@forinda/kickjs-cli 5.9.1 → 5.10.1
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-CxuUgXF_.mjs → agent-docs-D1k73ywL.mjs} +3 -3
- package/dist/{agent-docs-CxuUgXF_.mjs.map → agent-docs-D1k73ywL.mjs.map} +1 -1
- package/dist/{builtins-yDCsD2ae.mjs → builtins-DsO7X7g9.mjs} +2 -2
- package/dist/cli.mjs +262 -164
- package/dist/{config-icjz-b4f.mjs → config-BnCPYsQu.mjs} +3 -3
- package/dist/config-BnCPYsQu.mjs.map +1 -0
- package/dist/{doctor-BrkA44Gz.mjs → doctor-Brw2ruus.mjs} +126 -30
- package/dist/doctor-Brw2ruus.mjs.map +1 -0
- package/dist/index.d.mts +11 -5
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +2 -2
- package/dist/{plugin-CdC5d4kw.mjs → plugin-0_cDz8hu.mjs} +3 -3
- package/dist/{plugin-CdC5d4kw.mjs.map → plugin-0_cDz8hu.mjs.map} +1 -1
- package/dist/{project-docs-LqGoslXZ.mjs → project-docs-Bh20nvAP.mjs} +2 -2
- package/dist/{project-docs-LqGoslXZ.mjs.map → project-docs-Bh20nvAP.mjs.map} +1 -1
- package/dist/{project-root-CM9jhMiW.mjs → project-root-B7_vpWeX.mjs} +3 -3
- package/dist/{project-root-CM9jhMiW.mjs.map → project-root-B7_vpWeX.mjs.map} +1 -1
- package/dist/{rolldown-runtime-My-8F9u3.mjs → rolldown-runtime-C3T7GIRR.mjs} +1 -1
- package/dist/{run-plugins-B3Ooiczg.mjs → run-plugins-w_kqfVLL.mjs} +14 -12
- package/dist/run-plugins-w_kqfVLL.mjs.map +1 -0
- package/dist/{typegen-Cd0w7Al-.mjs → typegen-CFtS0A1P.mjs} +5 -5
- package/dist/typegen-CFtS0A1P.mjs.map +1 -0
- package/dist/{types-Dry-y2AZ.mjs → types-CkZ7XoFJ.mjs} +2 -2
- package/dist/{types-Dry-y2AZ.mjs.map → types-CkZ7XoFJ.mjs.map} +1 -1
- package/package.json +10 -10
- package/dist/config-icjz-b4f.mjs.map +0 -1
- package/dist/doctor-BrkA44Gz.mjs.map +0 -1
- package/dist/run-plugins-B3Ooiczg.mjs.map +0 -1
- package/dist/typegen-Cd0w7Al-.mjs.map +0 -1
package/dist/cli.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @forinda/kickjs-cli v5.
|
|
2
|
+
* @forinda/kickjs-cli v5.10.1
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Felix Orinda
|
|
5
5
|
*
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*
|
|
9
9
|
* @license MIT
|
|
10
10
|
*/
|
|
11
|
-
import{createRequire as e}from"node:module";import{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 ee,execSync as S,fork as te,spawn as ne,spawnSync as re}from"node:child_process";import{access as ie,copyFile as ae,mkdir as oe,readFile as C,readdir as se,rm as ce,stat as le,unlink as ue,writeFile as w}from"node:fs/promises";import*as T from"@clack/prompts";import E from"picocolors";import de from"pluralize";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";import{detectCompositeReferences as ve,generate as ye,migrateDown as be,migrateLatest as xe,migrateRollback as Se,migrateStatus as Ce,migrateUp as we,renderSchemaSource as Te,resolveDbConfig as Ee}from"@forinda/kickjs-db";var De=Object.defineProperty,D=(e,t)=>{let n={};for(var r in e)De(n,r,{get:e[r],enumerable:!0});return t||De(n,Symbol.toStringTag,{value:`Module`}),n};function Oe(e,t,n){S(e,{cwd:t,stdio:`inherit`,env:n?{...process.env,...n}:process.env})}function ke(e,t,n){let r=re(process.execPath,[e],{cwd:n,stdio:`inherit`,env:{...process.env,...t}});r.status!==0&&process.exit(r.status??1)}function Ae(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}je(e,r)}}function je(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{Oe(r)}catch{console.error(` Command failed: ${t.name}`),process.exitCode=1;return}}})}var Me=D({BUILTIN_REPO_TYPES:()=>Pe,PACKAGE_MANAGERS:()=>Ne,defineConfig:()=>Fe,loadKickConfig:()=>k,resolveModuleConfig:()=>O,resolveTokenScope:()=>Ie,validateAssetMap:()=>ze});const Ne=[`pnpm`,`npm`,`yarn`,`bun`],Pe=[`drizzle`,`inmemory`,`prisma`];function Fe(e){return e}function Ie(e,t){if(e?.tokenScope&&typeof e.tokenScope==`string`&&e.tokenScope.length>0){let t=Le(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=Le(e?e[1]:t.name);if(n.length>0)return n}}}catch{}return`app`}function Le(e){return e.toLowerCase().replace(/[^a-z0-9-]/g,`-`).replace(/^-+|-+$/g,``).replace(/-{2,}/g,`-`)}function O(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`&&!Pe.includes(t.repo)&&console.warn(` Warning: modules.repo '${t.repo}' is not a built-in type (${Pe.join(`, `)}). It will generate a stub repository. Use { name: '${t.repo}' } to silence this warning.`),t}const Re=[`kick.config.ts`,`kick.config.js`,`kick.config.mjs`,`kick.config.json`];async function k(e){let{findProjectRoot:t}=await Promise.resolve().then(()=>
|
|
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 ee,execSync as S,fork as te,spawn as ne,spawnSync as re}from"node:child_process";import{access as ie,copyFile as ae,mkdir as oe,readFile as C,readdir as se,rm as ce,stat as le,unlink as ue,writeFile as w}from"node:fs/promises";import*as T from"@clack/prompts";import E from"picocolors";import de from"pluralize";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";import{detectCompositeReferences as ve,generate as ye,migrateDown as be,migrateLatest as xe,migrateRollback as Se,migrateStatus as Ce,migrateUp as we,renderSchemaSource as Te,resolveDbConfig as Ee}from"@forinda/kickjs-db";var De=Object.defineProperty,D=(e,t)=>{let n={};for(var r in e)De(n,r,{get:e[r],enumerable:!0});return t||De(n,Symbol.toStringTag,{value:`Module`}),n};function Oe(e,t,n){S(e,{cwd:t,stdio:`inherit`,env:n?{...process.env,...n}:process.env})}function ke(e,t,n){let r=re(process.execPath,[e],{cwd:n,stdio:`inherit`,env:{...process.env,...t}});r.status!==0&&process.exit(r.status??1)}function Ae(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}je(e,r)}}function je(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{Oe(r)}catch{console.error(` Command failed: ${t.name}`),process.exitCode=1;return}}})}var Me=D({BUILTIN_REPO_TYPES:()=>Pe,PACKAGE_MANAGERS:()=>Ne,defineConfig:()=>Fe,loadKickConfig:()=>k,resolveModuleConfig:()=>O,resolveTokenScope:()=>Ie,validateAssetMap:()=>ze});const Ne=[`pnpm`,`npm`,`yarn`,`bun`],Pe=[`drizzle`,`inmemory`,`prisma`];function Fe(e){return e}function Ie(e,t){if(e?.tokenScope&&typeof e.tokenScope==`string`&&e.tokenScope.length>0){let t=Le(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=Le(e?e[1]:t.name);if(n.length>0)return n}}}catch{}return`app`}function Le(e){return e.toLowerCase().replace(/[^a-z0-9-]/g,`-`).replace(/^-+|-+$/g,``).replace(/-{2,}/g,`-`)}function O(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`&&!Pe.includes(t.repo)&&console.warn(` Warning: modules.repo '${t.repo}' is not a built-in type (${Pe.join(`, `)}). It will generate a stub repository. Use { name: '${t.repo}' } to silence this warning.`),t}const Re=[`kick.config.ts`,`kick.config.js`,`kick.config.mjs`,`kick.config.json`];async function k(e){let{findProjectRoot:t}=await Promise.resolve().then(()=>Zt),n=t(e);for(let e of Re){let t=h(n,e);try{await ie(t)}catch{continue}if(e.endsWith(`.json`)){let e=await C(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=ze(e,n);for(let e of i)console.warn(` Warning: ${e}`);return 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=ze(i,n);for(let e of a)console.warn(` Warning: ${e}`);return i}catch(t){let n=t instanceof Error?t.message:String(t);console.warn(`Warning: Failed to load ${e}: ${n}`);continue}}return null}function ze(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&&Be(v(t,o.dest),i)&&n.push(`assetMap.${a}.dest ('${o.dest}') resolves outside the project root — refusing to copy`)}return n}function Be(e,t){let n=_(t,e);return n===``?!1:n.startsWith(`..`)||m(n)}function A(e){return e}var Ve=class extends Error{constructor(e,t,n){super(`Two plugins registered the same ${e} '${t}': ${n.join(`, `)}. Plugins must use unique ${e} names.`),this.name=`KickPluginConflictError`}};function He(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 Ve(`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 Ve(`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 Ve(`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 Ve(`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(()=>Zt),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 Ue=D({mergeCliPlugins:()=>He});let We=!1;function j(e){We=e}const Ge=new Set([`.ts`,`.tsx`,`.js`,`.jsx`,`.mjs`,`.cjs`,`.json`,`.md`]);async function M(e,t){We||(await oe(f(e),{recursive:!0}),await w(e,t,`utf-8`),Ge.has(p(e))&&await Je(e,t).catch(()=>{}))}let Ke;async function qe(t){if(Ke!==void 0)return Ke;try{Ke=await import(e(h(t,`package.json`)).resolve(`oxfmt`))}catch{Ke=null}return Ke}async function Je(e,t){let n=await qe(process.cwd());if(!n)return;let r=await Xe(e);if(r===null)return;let i=await n.format(e,t,r);i.code!==t&&await w(e,i.code,`utf-8`)}const Ye=new Map;async function Xe(e){let t=f(e),n=t;if(Ye.has(n))return Ye.get(n);for(;;){let e=h(t,`.oxfmtrc.json`);if(r(e))try{let t=await C(e,`utf-8`),r=JSON.parse(t);return delete r.$schema,delete r.ignorePatterns,Ye.set(n,r),r}catch{return Ye.set(n,null),null}let i=f(t);if(i===t)return Ye.set(n,null),null;t=i}}async function Ze(e){try{return await ie(e),!0}catch{return!1}}const Qe={swagger:`@forinda/kickjs-swagger`,ws:`@forinda/kickjs-ws`,queue:`@forinda/kickjs-queue`,devtools:`@forinda/kickjs-devtools`},$e={zod:{name:`zod`,range:`^4.3.6`},valibot:{name:`valibot`,range:`^1.4.1`},yup:{name:`yup`,range:`^1.7.1`}};function et(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 tt(e,t,n,r=[],i=`zod`){let a=$e[i],o={"@forinda/kickjs":et(n,`@forinda/kickjs`),"@forinda/kickjs-schema":et(n,`@forinda/kickjs-schema`),dotenv:`^17.3.1`,express:`^5.1.0`,"reflect-metadata":`^0.2.2`,[a.name]:a.range};for(let e of r){let t=Qe[e];t&&!o[t]&&(o[t]=et(n,t))}return JSON.stringify({name:e,version:`0.0.0`,type:`module`,scripts:{dev:`vite`,"dev:debug":`kick dev:debug`,build:`kick build`,start:`kick start`,test:`vitest run`,"test:watch":`vitest`,typecheck:`tsc --noEmit`,typegen:`kick typegen`,lint:`eslint src/`,format:`prettier --write src/`},dependencies:o,devDependencies:{"@forinda/kickjs-cli":et(n,`@forinda/kickjs-cli`),"@forinda/kickjs-vite":et(n,`@forinda/kickjs-vite`),"@swc/core":`^1.15.21`,"@types/express":`^5.0.6`,"@types/node":`^25.0.0`,"unplugin-swc":`^1.5.9`,vite:`^8.0.3`,vitest:`^4.1.2`,typescript:`^6.0.3`,prettier:`^3.8.1`}},null,2)}function nt(){return`import { defineConfig } from 'vite'
|
|
12
12
|
import { resolve } from 'node:path'
|
|
13
13
|
import swc from 'unplugin-swc'
|
|
14
14
|
import { kickjsVitePlugin, envWatchPlugin } from '@forinda/kickjs-vite'
|
|
@@ -38,7 +38,7 @@ export default defineConfig({
|
|
|
38
38
|
},
|
|
39
39
|
},
|
|
40
40
|
})
|
|
41
|
-
`}function
|
|
41
|
+
`}function rt(){return JSON.stringify({compilerOptions:{target:`ES2022`,module:`ESNext`,moduleResolution:`bundler`,lib:[`ES2022`],types:[`node`,`vite/client`],strict:!0,esModuleInterop:!0,skipLibCheck:!0,sourceMap:!0,declaration:!0,experimentalDecorators:!0,emitDecoratorMetadata:!0,outDir:`dist`,paths:{"@/*":[`./src/*`]}},include:[`src`,`.kickjs/types/**/*.d.ts`,`.kickjs/types/**/*.ts`]},null,2)}function it(){return JSON.stringify({semi:!1,singleQuote:!0,trailingComma:`all`,printWidth:100,tabWidth:2},null,2)}function at(){return`# https://editorconfig.org
|
|
42
42
|
root = true
|
|
43
43
|
|
|
44
44
|
[*]
|
|
@@ -51,14 +51,14 @@ insert_final_newline = true
|
|
|
51
51
|
|
|
52
52
|
[*.md]
|
|
53
53
|
trim_trailing_whitespace = false
|
|
54
|
-
`}function
|
|
54
|
+
`}function ot(){return`node_modules/
|
|
55
55
|
dist/
|
|
56
56
|
.env
|
|
57
57
|
coverage/
|
|
58
58
|
.DS_Store
|
|
59
59
|
*.tsbuildinfo
|
|
60
60
|
.kickjs/
|
|
61
|
-
`}function
|
|
61
|
+
`}function st(){return`# Auto-detect text files and normalise line endings to LF
|
|
62
62
|
* text=auto eol=lf
|
|
63
63
|
|
|
64
64
|
# Explicitly mark generated / binary files
|
|
@@ -76,11 +76,11 @@ coverage/
|
|
|
76
76
|
pnpm-lock.yaml -diff linguist-generated
|
|
77
77
|
yarn.lock -diff linguist-generated
|
|
78
78
|
package-lock.json -diff linguist-generated
|
|
79
|
-
`}function st(){return`PORT=3000
|
|
80
|
-
NODE_ENV=development
|
|
81
79
|
`}function ct(){return`PORT=3000
|
|
82
80
|
NODE_ENV=development
|
|
83
|
-
`}function lt(){return`
|
|
81
|
+
`}function lt(){return`PORT=3000
|
|
82
|
+
NODE_ENV=development
|
|
83
|
+
`}function ut(){return`import { defineConfig } from 'vitest/config'
|
|
84
84
|
import swc from 'unplugin-swc'
|
|
85
85
|
|
|
86
86
|
export default defineConfig({
|
|
@@ -91,7 +91,7 @@ export default defineConfig({
|
|
|
91
91
|
include: ['src/**/*.test.ts'],
|
|
92
92
|
},
|
|
93
93
|
})
|
|
94
|
-
`}function
|
|
94
|
+
`}function dt(e,t,n,r=[]){switch(t){case`cqrs`:{let t=[],i=[];return r.includes(`devtools`)&&(t.push(`import { DevToolsAdapter } from '@forinda/kickjs-devtools'`),i.push(` DevToolsAdapter(),`)),r.includes(`swagger`)&&(t.push(`import { SwaggerAdapter } from '@forinda/kickjs-swagger'`),i.push(` SwaggerAdapter({\n info: { title: '${e}', version: '${n}' },\n }),`)),`import 'reflect-metadata'
|
|
95
95
|
// Side-effect import — registers the extended env schema with kickjs
|
|
96
96
|
// **before** any controller / service / @Value gets resolved. Without
|
|
97
97
|
// this line ConfigService.get('YOUR_KEY') returns undefined because the
|
|
@@ -161,31 +161,124 @@ export const app = await bootstrap({
|
|
|
161
161
|
express.json(),
|
|
162
162
|
],
|
|
163
163
|
})
|
|
164
|
-
`}}}function
|
|
164
|
+
`}}}function ft(){return`import { defineModules } from '@forinda/kickjs'
|
|
165
165
|
import { HelloModule } from './hello/hello.module'
|
|
166
166
|
|
|
167
167
|
// Remove HelloModule and run: kick g module <name>
|
|
168
168
|
// \`defineModules()\` returns a chainable list — \`kick g module\` appends
|
|
169
169
|
// \`.mount(NewModule())\` to the chain on every generation.
|
|
170
170
|
export const modules = defineModules().mount(HelloModule())
|
|
171
|
-
`}function
|
|
171
|
+
`}function pt(e=`zod`){return e===`valibot`?`import { loadEnvFromSchema } from '@forinda/kickjs/config'
|
|
172
|
+
import { fromValibot } from '@forinda/kickjs-schema/valibot'
|
|
173
|
+
import * as v from 'valibot'
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Project environment schema (Valibot).
|
|
177
|
+
*
|
|
178
|
+
* \`fromValibot\` wraps the Valibot schema as a \`KickSchema\` so the
|
|
179
|
+
* env loader, validate middleware, and swagger spec generator all see
|
|
180
|
+
* the same shape. The default export is the contract \`kick typegen\`
|
|
181
|
+
* reads to populate \`KickEnv\` via \`InferSchemaOutput<typeof _envSchema>\`
|
|
182
|
+
* — that's what makes \`@Value('FOO')\` autocomplete and
|
|
183
|
+
* \`process.env.FOO\` typed.
|
|
184
|
+
*
|
|
185
|
+
* @example
|
|
186
|
+
* DATABASE_URL: v.pipe(v.string(), v.url()),
|
|
187
|
+
* JWT_SECRET: v.pipe(v.string(), v.minLength(32)),
|
|
188
|
+
* REDIS_URL: v.optional(v.pipe(v.string(), v.url())),
|
|
189
|
+
*/
|
|
190
|
+
const envSchema = fromValibot(
|
|
191
|
+
v.object({
|
|
192
|
+
PORT: v.optional(v.pipe(v.string(), v.transform(Number)), '3000'),
|
|
193
|
+
NODE_ENV: v.optional(v.picklist(['development', 'production', 'test']), 'development'),
|
|
194
|
+
LOG_LEVEL: v.optional(v.string(), 'info'),
|
|
195
|
+
// DATABASE_URL: v.pipe(v.string(), v.url()),
|
|
196
|
+
}),
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* IMPORTANT — side effect: register the schema with kickjs's env cache
|
|
201
|
+
* **at module-load time**. \`ConfigService\` and \`@Value()\` both consume
|
|
202
|
+
* this cache, and they will fall back to the base schema (or undefined)
|
|
203
|
+
* if no extended schema has been registered before they're resolved.
|
|
204
|
+
*
|
|
205
|
+
* As long as \`src/index.ts\` imports this file (\`import './config'\`) at
|
|
206
|
+
* the top — before \`bootstrap()\` runs — every controller and service
|
|
207
|
+
* in the app sees the typed extended values.
|
|
208
|
+
*/
|
|
209
|
+
export const env = loadEnvFromSchema(envSchema)
|
|
210
|
+
|
|
211
|
+
export default envSchema
|
|
212
|
+
`:e===`yup`?`import { loadEnvFromSchema } from '@forinda/kickjs/config'
|
|
213
|
+
import { fromYup } from '@forinda/kickjs-schema/yup'
|
|
214
|
+
import * as yup from 'yup'
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Project environment schema (Yup).
|
|
218
|
+
*
|
|
219
|
+
* \`fromYup\` wraps the Yup schema as a \`KickSchema\` so the env loader,
|
|
220
|
+
* validate middleware, and swagger spec generator all see the same
|
|
221
|
+
* shape. The default export is the contract \`kick typegen\` reads to
|
|
222
|
+
* populate \`KickEnv\` via \`InferSchemaOutput<typeof _envSchema>\`.
|
|
223
|
+
*
|
|
224
|
+
* Note: Yup's \`.url()\` defaults to http/https; database connection
|
|
225
|
+
* strings like \`postgres://\` use \`.matches(/^[a-z]+:\\/\\/.+/i)\` or
|
|
226
|
+
* a plain \`.string().required()\`.
|
|
227
|
+
*
|
|
228
|
+
* @example
|
|
229
|
+
* DATABASE_URL: yup.string().required(),
|
|
230
|
+
* JWT_SECRET: yup.string().min(32).required(),
|
|
231
|
+
* REDIS_URL: yup.string().url().optional(),
|
|
232
|
+
*/
|
|
233
|
+
const envSchema = fromYup(
|
|
234
|
+
yup.object({
|
|
235
|
+
PORT: yup.number().default(3000),
|
|
236
|
+
NODE_ENV: yup
|
|
237
|
+
.string()
|
|
238
|
+
.oneOf(['development', 'production', 'test'])
|
|
239
|
+
.default('development'),
|
|
240
|
+
LOG_LEVEL: yup.string().default('info'),
|
|
241
|
+
// DATABASE_URL: yup.string().required(),
|
|
242
|
+
}),
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* IMPORTANT — side effect: register the schema with kickjs's env cache
|
|
247
|
+
* **at module-load time**. \`ConfigService\` and \`@Value()\` both consume
|
|
248
|
+
* this cache, and they will fall back to the base schema (or undefined)
|
|
249
|
+
* if no extended schema has been registered before they're resolved.
|
|
250
|
+
*
|
|
251
|
+
* As long as \`src/index.ts\` imports this file (\`import './config'\`) at
|
|
252
|
+
* the top — before \`bootstrap()\` runs — every controller and service
|
|
253
|
+
* in the app sees the typed extended values.
|
|
254
|
+
*/
|
|
255
|
+
export const env = loadEnvFromSchema(envSchema)
|
|
256
|
+
|
|
257
|
+
export default envSchema
|
|
258
|
+
`:`import { loadEnvFromSchema } from '@forinda/kickjs/config'
|
|
259
|
+
import { fromZod } from '@forinda/kickjs-schema/zod'
|
|
172
260
|
import { z } from 'zod'
|
|
173
261
|
|
|
174
262
|
/**
|
|
175
|
-
* Project environment schema.
|
|
263
|
+
* Project environment schema (Zod).
|
|
176
264
|
*
|
|
177
|
-
*
|
|
178
|
-
*
|
|
179
|
-
*
|
|
180
|
-
*
|
|
265
|
+
* \`fromZod\` wraps the Zod schema as a \`KickSchema\` so the env loader,
|
|
266
|
+
* validate middleware, and swagger spec generator all see the same
|
|
267
|
+
* shape. The default export is the contract \`kick typegen\` reads to
|
|
268
|
+
* populate \`KickEnv\` via \`InferSchemaOutput<typeof _envSchema>\` —
|
|
269
|
+
* that's what makes \`@Value('FOO')\` autocomplete and
|
|
270
|
+
* \`process.env.FOO\` typed.
|
|
181
271
|
*
|
|
182
272
|
* @example
|
|
183
273
|
* DATABASE_URL: z.string().url(),
|
|
184
274
|
* JWT_SECRET: z.string().min(32),
|
|
185
275
|
* REDIS_URL: z.string().url().optional(),
|
|
186
276
|
*/
|
|
187
|
-
const envSchema =
|
|
188
|
-
|
|
277
|
+
const envSchema = fromZod(
|
|
278
|
+
z.object({
|
|
279
|
+
PORT: z.coerce.number().default(3000),
|
|
280
|
+
NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),
|
|
281
|
+
LOG_LEVEL: z.string().default('info'),
|
|
189
282
|
// DATABASE_URL: z.string().url(),
|
|
190
283
|
}),
|
|
191
284
|
)
|
|
@@ -196,14 +289,14 @@ const envSchema = defineEnv((base) =>
|
|
|
196
289
|
* this cache, and they will fall back to the base schema (or undefined)
|
|
197
290
|
* if no extended schema has been registered before they're resolved.
|
|
198
291
|
*
|
|
199
|
-
* As long as \`src/index.ts\` imports this file (\`import './
|
|
200
|
-
* top — before \`bootstrap()\` runs — every controller and service
|
|
201
|
-
* app sees the typed extended values.
|
|
292
|
+
* As long as \`src/index.ts\` imports this file (\`import './config'\`) at
|
|
293
|
+
* the top — before \`bootstrap()\` runs — every controller and service
|
|
294
|
+
* in the app sees the typed extended values.
|
|
202
295
|
*/
|
|
203
|
-
export const env =
|
|
296
|
+
export const env = loadEnvFromSchema(envSchema)
|
|
204
297
|
|
|
205
298
|
export default envSchema
|
|
206
|
-
`}function
|
|
299
|
+
`}function mt(){return`import { Service } from '@forinda/kickjs'
|
|
207
300
|
|
|
208
301
|
@Service()
|
|
209
302
|
export class HelloService {
|
|
@@ -215,7 +308,7 @@ export class HelloService {
|
|
|
215
308
|
return { status: 'ok', uptime: process.uptime() }
|
|
216
309
|
}
|
|
217
310
|
}
|
|
218
|
-
`}function
|
|
311
|
+
`}function ht(){return`import { Controller, Get, Autowired, type Ctx } from '@forinda/kickjs'
|
|
219
312
|
import { HelloService } from './hello.service'
|
|
220
313
|
|
|
221
314
|
// \`Ctx<KickRoutes.HelloController['<method>']>\` is generated by
|
|
@@ -237,7 +330,7 @@ export class HelloController {
|
|
|
237
330
|
ctx.json(this.helloService.healthCheck())
|
|
238
331
|
}
|
|
239
332
|
}
|
|
240
|
-
`}function
|
|
333
|
+
`}function gt(){return`import { defineModule } from '@forinda/kickjs'
|
|
241
334
|
import { HelloController } from './hello.controller'
|
|
242
335
|
|
|
243
336
|
export const HelloModule = defineModule({
|
|
@@ -258,7 +351,7 @@ export const HelloModule = defineModule({
|
|
|
258
351
|
},
|
|
259
352
|
}),
|
|
260
353
|
})
|
|
261
|
-
`}function
|
|
354
|
+
`}function _t(e,t=`inmemory`,n=`pnpm`){return`import { defineConfig } from '@forinda/kickjs-cli'
|
|
262
355
|
|
|
263
356
|
export default defineConfig({
|
|
264
357
|
pattern: '${e}',
|
|
@@ -273,9 +366,12 @@ export default defineConfig({
|
|
|
273
366
|
|
|
274
367
|
// \`kick typegen\` populates \`.kickjs/types/\` so \`Ctx<KickRoutes.X['method']>\`
|
|
275
368
|
// resolves to fully-typed params/body/query. Auto-runs on \`kick dev\`.
|
|
276
|
-
//
|
|
369
|
+
// \`'kickjs-schema'\` routes inference through \`InferSchemaOutput\` so the
|
|
370
|
+
// typegen works for any wrapped schema (Zod / Valibot / Yup). Switch
|
|
371
|
+
// to \`'zod'\` if you ship Zod schemas without \`fromZod()\` wrapping, or
|
|
372
|
+
// set \`schemaValidator: false\` to skip schema-driven body typing.
|
|
277
373
|
typegen: {
|
|
278
|
-
schemaValidator: '
|
|
374
|
+
schemaValidator: 'kickjs-schema',
|
|
279
375
|
},
|
|
280
376
|
|
|
281
377
|
commands: [
|
|
@@ -302,7 +398,7 @@ export default defineConfig({
|
|
|
302
398
|
},
|
|
303
399
|
],
|
|
304
400
|
})
|
|
305
|
-
`}function
|
|
401
|
+
`}function vt(e,t,n){let r={rest:`REST API`,ddd:`Domain-Driven Design`,cqrs:`CQRS + Event-Driven`,minimal:`Minimal`},i=[`@forinda/kickjs`,`@forinda/kickjs-vite`];return t!==`minimal`&&i.push(`@forinda/kickjs-swagger`,`@forinda/kickjs-devtools`),t===`cqrs`&&i.push(`@forinda/kickjs-queue`,`@forinda/kickjs-ws`),`# ${e}
|
|
306
402
|
|
|
307
403
|
A **${r[t]??`REST API`}** built with [KickJS](https://forinda.github.io/kick-js/) — a decorator-driven Node.js framework on Express 5 and TypeScript.
|
|
308
404
|
|
|
@@ -365,7 +461,7 @@ Copy \`.env.example\` to \`.env\` and configure:
|
|
|
365
461
|
|
|
366
462
|
- [KickJS Documentation](https://forinda.github.io/kick-js/)
|
|
367
463
|
- [CLI Reference](https://forinda.github.io/kick-js/api/cli.html)
|
|
368
|
-
`}function
|
|
464
|
+
`}function yt(e,t,n){return`# CLAUDE.md — ${e}
|
|
369
465
|
|
|
370
466
|
**Read \`./.agents/AGENTS.md\` first.** It is the canonical, multi-agent
|
|
371
467
|
reference for this project (Claude, Copilot, Codex, Gemini, etc.) —
|
|
@@ -439,7 +535,7 @@ When generating or modifying code in this project, stay aligned with the v4 conv
|
|
|
439
535
|
- **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.
|
|
440
536
|
|
|
441
537
|
For everything else (controllers, services, modules, RequestContext API, generators, CLI commands, package additions, env wiring, troubleshooting) → \`.agents/AGENTS.md\`.
|
|
442
|
-
`}function
|
|
538
|
+
`}function bt(e,t,n){return`# AGENTS.md — AI Agent Guide for ${e}
|
|
443
539
|
|
|
444
540
|
This guide is the **canonical, multi-agent reference** for this KickJS
|
|
445
541
|
application — Claude, Copilot, Codex, Gemini, etc. all read it first.
|
|
@@ -946,7 +1042,7 @@ ${t===`cqrs`?`### Background Jobs
|
|
|
946
1042
|
- [Decorators Guide](https://forinda.github.io/kick-js/guide/decorators.html)
|
|
947
1043
|
- [DI System](https://forinda.github.io/kick-js/guide/dependency-injection.html)
|
|
948
1044
|
- [Testing](https://forinda.github.io/kick-js/api/testing.html)
|
|
949
|
-
`}function
|
|
1045
|
+
`}function xt(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".
|
|
950
1046
|
|
|
951
1047
|
**Steps**:
|
|
952
1048
|
1. Run \`kick g module <name>\` (use plural form if the project pluralizes — check \`kick.config.ts\`).
|
|
@@ -1081,7 +1177,7 @@ description: ${e.description}
|
|
|
1081
1177
|
${r}
|
|
1082
1178
|
|
|
1083
1179
|
${e.body}
|
|
1084
|
-
`}))}function
|
|
1180
|
+
`}))}function St(e,t,n){return`# GEMINI.md — ${e}
|
|
1085
1181
|
|
|
1086
1182
|
**Read \`./AGENTS.md\` first.** It is the canonical, multi-agent
|
|
1087
1183
|
reference for this project — every convention, structure, decorator
|
|
@@ -1115,7 +1211,7 @@ without us copy-pasting.
|
|
|
1115
1211
|
\`kick g agents --only gemini -f\` regenerates this file from the
|
|
1116
1212
|
CLI template. Hand-edited content is overwritten — keep customisation
|
|
1117
1213
|
in \`.agents/GEMINI.local.md\`.
|
|
1118
|
-
`}function
|
|
1214
|
+
`}function Ct(e,t,n){return`# COPILOT.md — ${e}
|
|
1119
1215
|
|
|
1120
1216
|
**Read \`./AGENTS.md\` first.** It is the canonical, multi-agent
|
|
1121
1217
|
reference for this project — every convention, structure, decorator
|
|
@@ -1148,16 +1244,16 @@ Codex / Cursor / Gemini / Claude Code without copy-pasting.
|
|
|
1148
1244
|
\`kick g agents --only copilot -f\` regenerates this file from the
|
|
1149
1245
|
CLI template. Hand-edited content is overwritten — keep customisation
|
|
1150
1246
|
in \`.agents/COPILOT.local.md\`.
|
|
1151
|
-
`}const
|
|
1152
|
-
Dependencies installed successfully!`)}catch{console.log(`\n Warning: ${r} install failed. Run it manually.`)}}try{let{runTypegen:e}=await Promise.resolve().then(()=>
|
|
1153
|
-
Project scaffolded successfully!`),console.log();let
|
|
1247
|
+
`}const wt=f(b(import.meta.url)),Tt=JSON.parse(a(h(wt,`..`,`package.json`),`utf-8`)),Et=`^${Tt.version}`,Dt=[`@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 Ot(){let e=await Promise.all(Dt.map(async e=>{try{let t=ee(`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,Et]}));return Object.fromEntries(e)}async function kt(e){let{name:t,directory:n,packageManager:r=`pnpm`,template:i=`rest`,defaultRepo:a=`inmemory`,packages:o=[],schemaLib:s=`zod`}=e,c=n,l=e=>console.log(` ${e}`);console.log(`\n Creating KickJS project: ${t}\n`),l(`Resolving package versions...`);let u=await Ot();await M(h(c,`package.json`),tt(t,i,u,o,s)),await M(h(c,`vite.config.ts`),nt()),await M(h(c,`tsconfig.json`),rt()),await M(h(c,`.prettierrc`),it()),await M(h(c,`.editorconfig`),at()),await M(h(c,`.gitignore`),ot()),await M(h(c,`.gitattributes`),st()),await M(h(c,`.env`),ct()),await M(h(c,`.env.example`),lt()),await M(h(c,`src/config/index.ts`),pt(s)),await M(h(c,`src/index.ts`),dt(t,i,Tt.version,o)),await M(h(c,`src/modules/index.ts`),ft()),await M(h(c,`src/modules/hello/hello.service.ts`),mt()),await M(h(c,`src/modules/hello/hello.controller.ts`),ht()),await M(h(c,`src/modules/hello/hello.module.ts`),gt()),await M(h(c,`kick.config.ts`),_t(i,a,r)),await M(h(c,`vitest.config.ts`),ut()),await M(h(c,`README.md`),vt(t,i,r));let{generateAgentDocs:d}=await Promise.resolve().then(()=>vr);if(await d({outDir:c,name:t,pm:r,template:i,only:`all`,force:!0}),e.installDeps){console.log(`\n Installing dependencies with ${r}...\n`);try{S(`${r} install`,{cwd:c,stdio:`inherit`}),console.log(`
|
|
1248
|
+
Dependencies installed successfully!`)}catch{console.log(`\n Warning: ${r} install failed. Run it manually.`)}}try{let{runTypegen:e}=await Promise.resolve().then(()=>ua);await e({cwd:c,allowDuplicates:!0,silent:!0})}catch{}if(e.initGit)try{S(`git init`,{cwd:c,stdio:`pipe`}),S(`git branch -M main`,{cwd:c,stdio:`pipe`}),S(`git add -A`,{cwd:c,stdio:`pipe`}),S(`git commit -m "chore: initial commit from kick new"`,{cwd:c,stdio:`pipe`}),l(`Git repository initialized`)}catch{l(`Warning: git init failed (git may not be installed)`)}console.log(`
|
|
1249
|
+
Project scaffolded successfully!`),console.log();let f=c!==process.cwd();l(`Next steps:`),f&&l(` cd ${t}`),e.installDeps||l(` ${r} install`);let p={rest:`kick g module user`,ddd:`kick g module user --repo drizzle`,cqrs:`kick g module user --pattern cqrs`,minimal:`# add your routes to src/index.ts`};l(` ${p[i]??p.rest}`),l(` kick dev`),l(``),l(`Commands:`),l(` kick dev Start dev server with Vite HMR`),l(` kick build Production build via Vite`),l(` kick start Run production build`),l(``),l(`Generators:`),l(` kick g module <name> Full DDD module (controller, DTOs, use-cases, repo)`),l(` kick g scaffold <n> <f..> CRUD module from field definitions`),l(` kick g controller <name> Standalone controller`),l(` kick g service <name> @Service() class`),l(` kick g middleware <name> Express middleware`),l(` kick g guard <name> Route guard (auth, roles, etc.)`),l(` kick g adapter <name> AppAdapter with lifecycle hooks`),l(` kick g dto <name> Zod DTO schema`),i===`cqrs`&&l(` kick g job <name> Queue job processor`),l(` kick g config Generate kick.config.ts`),l(``),l(`Add packages:`),l(` kick add <pkg> Install a KickJS package + peers`),l(` kick add --list Show all available packages`),l(``),l(`Available: auth, swagger, drizzle, prisma, ws, queue, devtools, mcp, testing`),l(``)}const At={GET:E.green,POST:E.cyan,PUT:E.yellow,PATCH:E.magenta,DELETE:E.red};function jt(e){return(At[e]??E.dim)(e.padEnd(7))}function Mt(e){let t=`[${e}]`.padEnd(10);switch(e){case`CRITICAL`:return E.red(t);case`WARNING`:return E.yellow(t);case`INFO`:return E.blue(E.dim(t));default:return t}}E.green(`✓`),E.red(`✖`),E.yellow(`⚠`),E.blue(`ℹ`);function Nt(e){T.intro(E.bgCyan(E.black(` ${e} `)))}function N(e){T.outro(e)}function Pt(e){T.isCancel(e)&&(T.cancel(`Operation cancelled.`),process.exit(0))}async function Ft(e){let t=await T.text(e);return Pt(t),t}async function It(e){let t=await T.select(e);return Pt(t),t}async function Lt(e){let t=await T.multiselect(e);return Pt(t),t}async function P(e){let t=await T.confirm(e);return Pt(t),t}function Rt(){return T.spinner()}const F=T.log,zt={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},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`},"db-pg":{pkg:`@forinda/kickjs-db-pg`,peers:[`pg`],description:`kick/db PostgreSQL dialect + adapter (pgDialect, pgAdapter)`},drizzle:{pkg:`@forinda/kickjs-drizzle`,peers:[`drizzle-orm`],description:`Drizzle ORM adapter + query builder`},prisma:{pkg:`@forinda/kickjs-prisma`,peers:[`@prisma/client`],description:`Prisma adapter + query builder`},ws:{pkg:`@forinda/kickjs-ws`,peers:[`socket.io`],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}};function Bt(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 Vt(){return Bt(`pnpm-lock.yaml`)?`pnpm`:Bt(`yarn.lock`)?`yarn`:Bt(`bun.lockb`)||Bt(`bun.lock`)?`bun`:Bt(`package-lock.json`)?`npm`:null}function Ht(){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(Ne.includes(t))return t}}catch{}let n=f(e);if(n===e)return null;e=n}return null}async function Ut(e){if(e&&Ne.includes(e))return{pm:e,source:`flag`};let t=await k(process.cwd());if(t?.packageManager&&Ne.includes(t.packageManager))return{pm:t.packageManager,source:`config`};let n=Ht();if(n)return{pm:n,source:`package.json`};let r=Vt();return r?{pm:r,source:`lockfile`}:{pm:`npm`,source:`default`}}async function Wt(e){let{pm:t}=await Ut(e);return t}function Gt(e=!1){let t=Object.entries(zt),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(`, `)})`:``;return` ${r} ${t.description}${i}`};console.log(`
|
|
1154
1250
|
Core packages (always installed by \`kick new\`):
|
|
1155
1251
|
`);for(let e of r)console.log(a(e));if(e){console.log(`
|
|
1156
1252
|
Optional packages (add as needed):
|
|
1157
1253
|
`);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(`
|
|
1158
|
-
Usage: kick add auth drizzle swagger`),console.log(` kick add queue:bullmq`),console.log()}function
|
|
1254
|
+
Usage: kick add auth drizzle swagger`),console.log(` kick add queue:bullmq`),console.log()}function Kt(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=>{Gt(!!e.all)})}function qt(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){Gt(!!t.all);return}let{pm:n,source:r}=await Ut(t.pm);console.log(`\n Using ${n} (resolved from ${r})`);let i=t.dev,a=new Set,o=new Set,s=[];for(let t of e){let e=zt[t];if(!e){s.push(t);continue}let n=i||e.dev?o:a;n.add(e.pkg);for(let t of e.peers)n.add(t)}if(!(s.length>0&&(console.log(`\n Unknown packages: ${s.join(`, `)}`),console.log(` Run "kick add --list" to see available packages.
|
|
1159
1255
|
`),a.size===0&&o.size===0))){if(a.size>0){let e=Array.from(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{S(t,{stdio:`inherit`})}catch{console.log(`\n Installation failed. Run manually:\n ${t}\n`)}}if(o.size>0){let e=Array.from(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{S(t,{stdio:`inherit`})}catch{console.log(`\n Installation failed. Run manually:\n ${t}\n`)}}console.log(` Done!
|
|
1160
|
-
`)}})}const
|
|
1256
|
+
`)}})}const Jt=[{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 Yt(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 | ddd | cqrs | minimal`).option(`-r, --repo <type>`,`Default repository: prisma | drizzle | inmemory | custom`).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)=>{Nt(`KickJS — Create a new project`);let n=!!(t.yes||t.nonInteractive);e||=n?`my-api`:await Ft({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)F.warn(`Clearing existing files in ${i}`);else if(n){F.warn(`Directory "${e}" is not empty. Pass --force to clear it.`),N(`Aborted.`);return}else{F.warn(`Directory "${e}" is not empty:`);let t=r.slice(0,5);for(let e of t)F.message(` - ${e}`);if(r.length>5&&F.message(` ... and ${r.length-5} more`),!await P({message:E.red(`Remove all existing files and proceed?`),initialValue:!1})){N(`Aborted.`);return}}for(let e of r)s(v(i,e),{recursive:!0,force:!0})}}let a=t.template;a||=n?`minimal`:await It({message:`Project template`,options:[{value:`rest`,label:`REST API`,hint:`Express + Swagger`},{value:`ddd`,label:`DDD`,hint:`Domain-Driven Design modules`},{value:`cqrs`,label:`CQRS`,hint:`Commands, Queries, Events + WS/Queue`},{value:`minimal`,label:`Minimal`,hint:`bare Express`}]});let c=t.pm;c||=n?await Wt(void 0):await It({message:`Package manager`,options:[{value:`pnpm`,label:`pnpm`},{value:`npm`,label:`npm`},{value:`yarn`,label:`yarn`},{value:`bun`,label:`bun`}]});let l=t.repo;l||(n?l=`inmemory`:(l=await It({message:`Default repository/ORM`,options:[{value:`prisma`,label:`Prisma`},{value:`drizzle`,label:`Drizzle`},{value:`inmemory`,label:`In-Memory`},{value:`custom`,label:`Custom`,hint:`specify later`}]}),l===`custom`&&(l=await Ft({message:`Custom repository name`,defaultValue:`custom`}))));let u=t.schema;u||=n?`zod`:await It({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(u)||(F.warn(`Unknown --schema "${u}", falling back to zod.`),u=`zod`);let f;if(t.packages!==void 0){let e=t.packages.trim().toLowerCase();f=e===``||e===`none`||e===`false`?[]:t.packages.split(`,`).map(e=>e.trim()).filter(Boolean)}else f=n?[]:await Lt({message:`Select packages to include`,options:[...Jt],required:!1});let p;p=t.git===void 0?n?!0:await P({message:`Initialize git repository?`,initialValue:!0}):t.git;let m;m=t.install===void 0?n?!0:await P({message:`Install dependencies?`,initialValue:!0}):t.install,await kt({name:e,directory:i,packageManager:c,initGit:p,installDeps:m,template:a,defaultRepo:l,packages:f,schemaLib:u}),N(`Done! Next steps: ${E.cyan(`cd ${e} && ${c} dev`)}`)})}function I(e){return e.replace(/[-_\s]+(.)?/g,(e,t)=>t?t.toUpperCase():``).replace(/^(.)/,e=>e.toUpperCase())}function L(e){let t=I(e);return t.charAt(0).toLowerCase()+t.slice(1)}function R(e){return e.replace(/([a-z])([A-Z])/g,`$1-$2`).replace(/[\s_]+/g,`-`).toLowerCase()}function z(e){return de.plural(e)}function Xt(e){return de.plural(e)}var Zt=D({findProjectRoot:()=>$t});const Qt=[`kick.config.ts`,`kick.config.js`,`kick.config.mjs`,`kick.config.json`];function $t(e=process.cwd()){let t=v(e),{root:n}=g(t),i=null,a=t;for(;;){for(let e of Qt)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 en(e){return R(e).replace(/-/g,`_`)}function tn(e){let t=e.cwd??process.cwd(),n=e.projectRoot??$t(t),r=e.pluralize??!0,i=I(e.name),a=L(e.name),o=R(e.name),s=en(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=z(o);c.pluralKebab=e,c.pluralPascal=I(e),c.pluralCamel=L(e)}return c}function nn(e,t){return v(e.cwd,t)}async function rn(e){return import(x(e).href)}const an=new Map;async function on(e){let t=an.get(e);if(t)return t;let n=sn(e);return an.set(e,n),n}async function sn(t){let n=v(t,`package.json`);if(!r(n))return{generators:[],loaded:[],failed:[]};let i=cn(JSON.parse(await C(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 C(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 rn(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(!ln(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 cn(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 ln(e){if(!e||typeof e!=`object`)return!1;let t=e;return typeof t.name==`string`&&typeof t.files==`function`}async function un(e,t=[]){let n=e.cwd??process.cwd(),r=t.find(t=>t.spec.name===e.generatorName);if(r)return pn(r.spec,r.source,e,n);let i=fn(await on(n),e.generatorName);return i?pn(i.spec,i.source,e,n):null}async function dn(e,t=[]){let n=await on(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 fn(e,t){return e.generators.find(e=>e.spec.name===t)}async function pn(e,t,n,r){let i=tn({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=nn(i,e.path);await M(t,e.content),o.push(t)}return{files:o,source:t}}function B(e){return e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}const mn={inmemory:`in-memory`,drizzle:`Drizzle`,prisma:`Prisma`};function hn(e){return e.charAt(0).toUpperCase()+e.slice(1).replace(/-([a-z])/g,(e,t)=>t.toUpperCase())}function gn(e){return e.replace(/([a-z])([A-Z])/g,`$1-$2`).toLowerCase()}function _n(e){return mn[e]??hn(e)}function vn(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]??`${hn(n)}${e}Repository`,repoFile:i[n]??`${gn(n)}-${t}`}}function yn(e){return e??`define`}function bn(e){let{pascal:t,kebab:n,plural:r=``,repo:i,style:a}=e,{repoClass:o,repoFile:s}=vn(t,n,i),c=yn(a),l=`/**
|
|
1161
1257
|
* ${t} Module
|
|
1162
1258
|
*
|
|
1163
1259
|
* Self-contained feature module following Domain-Driven Design (DDD).
|
|
@@ -1167,7 +1263,7 @@ in \`.agents/COPILOT.local.md\`.
|
|
|
1167
1263
|
* presentation/ — HTTP controllers (entry points)
|
|
1168
1264
|
* application/ — Use cases (orchestration) and DTOs (validation)
|
|
1169
1265
|
* domain/ — Entities, value objects, repository interfaces, domain services
|
|
1170
|
-
* infrastructure/ — Repository implementations (currently ${
|
|
1266
|
+
* infrastructure/ — Repository implementations (currently ${_n(i)})
|
|
1171
1267
|
*/`,u=`import { ${t.toUpperCase()}_REPOSITORY } from './domain/repositories/${n}.repository'
|
|
1172
1268
|
import { ${o} } from './infrastructure/repositories/${s}.repository'
|
|
1173
1269
|
import { ${t}Controller } from './presentation/${n}.controller'
|
|
@@ -1201,7 +1297,7 @@ export class ${t}Module implements AppModule {
|
|
|
1201
1297
|
/**
|
|
1202
1298
|
* Register module dependencies in the DI container.
|
|
1203
1299
|
* Bind repository interface tokens to their implementations here.
|
|
1204
|
-
* Currently wired to ${
|
|
1300
|
+
* Currently wired to ${_n(i)}. To swap implementations, change the factory target.
|
|
1205
1301
|
*/
|
|
1206
1302
|
register(container: Container): void {
|
|
1207
1303
|
container.registerFactory(${t.toUpperCase()}_REPOSITORY, () =>
|
|
@@ -1227,7 +1323,7 @@ export const ${t}Module = defineModule({
|
|
|
1227
1323
|
/**
|
|
1228
1324
|
* Register module dependencies in the DI container.
|
|
1229
1325
|
* Bind repository interface tokens to their implementations here.
|
|
1230
|
-
* Currently wired to ${
|
|
1326
|
+
* Currently wired to ${_n(i)}. To swap implementations, change the factory target.
|
|
1231
1327
|
*/
|
|
1232
1328
|
register(container) {
|
|
1233
1329
|
container.registerFactory(${t.toUpperCase()}_REPOSITORY, () =>
|
|
@@ -1244,7 +1340,7 @@ ${d}
|
|
|
1244
1340
|
},
|
|
1245
1341
|
}),
|
|
1246
1342
|
})
|
|
1247
|
-
`}function
|
|
1343
|
+
`}function xn(e){let{pascal:t,kebab:n,plural:r=``,repo:i,style:a}=e,{repoClass:o,repoFile:s}=vn(t,n,i),c=yn(a),l=`/**
|
|
1248
1344
|
* ${t} Module
|
|
1249
1345
|
*
|
|
1250
1346
|
* REST module with a flat folder structure.
|
|
@@ -1316,7 +1412,7 @@ ${d}
|
|
|
1316
1412
|
},
|
|
1317
1413
|
}),
|
|
1318
1414
|
})
|
|
1319
|
-
`}function
|
|
1415
|
+
`}function Sn(e){let{pascal:t,kebab:n,plural:r=``,style:i}=e,a=yn(i),o=` /**
|
|
1320
1416
|
* Declare HTTP routes. Return value shape:
|
|
1321
1417
|
*
|
|
1322
1418
|
* - \`path\` — URL prefix for this route set.
|
|
@@ -1356,7 +1452,7 @@ ${o}
|
|
|
1356
1452
|
},
|
|
1357
1453
|
}),
|
|
1358
1454
|
})
|
|
1359
|
-
`}function
|
|
1455
|
+
`}function Cn(e){let{pascal:t,kebab:n,plural:r=``,pluralPascal:i=``}=e;return`import { Controller, Get, Post, Put, Delete, Autowired, ApiQueryParams, type Ctx } from '@forinda/kickjs'
|
|
1360
1456
|
import { ApiTags } from '@forinda/kickjs-swagger'
|
|
1361
1457
|
import { Create${t}UseCase } from '../application/use-cases/create-${n}.use-case'
|
|
1362
1458
|
import { Get${t}UseCase } from '../application/use-cases/get-${n}.use-case'
|
|
@@ -1419,7 +1515,7 @@ export class ${t}Controller {
|
|
|
1419
1515
|
ctx.noContent()
|
|
1420
1516
|
}
|
|
1421
1517
|
}
|
|
1422
|
-
`}function
|
|
1518
|
+
`}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'
|
|
1423
1519
|
import { ApiTags } from '@forinda/kickjs-swagger'
|
|
1424
1520
|
import { ${t}Service } from './${n}.service'
|
|
1425
1521
|
import { create${t}Schema } from './dtos/create-${n}.dto'
|
|
@@ -1474,14 +1570,14 @@ export class ${t}Controller {
|
|
|
1474
1570
|
ctx.noContent()
|
|
1475
1571
|
}
|
|
1476
1572
|
}
|
|
1477
|
-
`}function
|
|
1573
|
+
`}function Tn(e){let{pascal:t}=e;return`import type { QueryParamsConfig } from '@forinda/kickjs'
|
|
1478
1574
|
|
|
1479
1575
|
export const ${t.toUpperCase()}_QUERY_CONFIG: QueryParamsConfig = {
|
|
1480
1576
|
filterable: ['name'],
|
|
1481
1577
|
sortable: ['name', 'createdAt'],
|
|
1482
1578
|
searchable: ['name'],
|
|
1483
1579
|
}
|
|
1484
|
-
`}function
|
|
1580
|
+
`}function En(e){let{pascal:t}=e;return`import { z } from 'zod'
|
|
1485
1581
|
|
|
1486
1582
|
/**
|
|
1487
1583
|
* Create ${t} DTO — Zod schema for validating POST request bodies.
|
|
@@ -1497,20 +1593,20 @@ export const create${t}Schema = z.object({
|
|
|
1497
1593
|
})
|
|
1498
1594
|
|
|
1499
1595
|
export type Create${t}DTO = z.infer<typeof create${t}Schema>
|
|
1500
|
-
`}function
|
|
1596
|
+
`}function Dn(e){let{pascal:t}=e;return`import { z } from 'zod'
|
|
1501
1597
|
|
|
1502
1598
|
export const update${t}Schema = z.object({
|
|
1503
1599
|
name: z.string().min(1).max(200).optional(),
|
|
1504
1600
|
})
|
|
1505
1601
|
|
|
1506
1602
|
export type Update${t}DTO = z.infer<typeof update${t}Schema>
|
|
1507
|
-
`}function
|
|
1603
|
+
`}function On(e){let{pascal:t}=e;return`export interface ${t}ResponseDTO {
|
|
1508
1604
|
id: string
|
|
1509
1605
|
name: string
|
|
1510
1606
|
createdAt: string
|
|
1511
1607
|
updatedAt: string
|
|
1512
1608
|
}
|
|
1513
|
-
`}function
|
|
1609
|
+
`}function kn(e){let{pascal:t,kebab:n,plural:r=``,pluralPascal:i=``}=e;return[{file:`create-${n}.use-case.ts`,content:`/**
|
|
1514
1610
|
* Create ${t} Use Case
|
|
1515
1611
|
*
|
|
1516
1612
|
* Application layer — orchestrates a single business operation.
|
|
@@ -1588,7 +1684,7 @@ export class Delete${t}UseCase {
|
|
|
1588
1684
|
await this.repo.delete(id)
|
|
1589
1685
|
}
|
|
1590
1686
|
}
|
|
1591
|
-
`}]}function
|
|
1687
|
+
`}]}function An(e){let{pascal:t,kebab:n,dtoPrefix:r=`../../application/dtos`,tokenScope:i=`app`}=e;return`/**
|
|
1592
1688
|
* ${t} Repository Interface
|
|
1593
1689
|
*
|
|
1594
1690
|
* Defines the contract for data access.
|
|
@@ -1683,7 +1779,7 @@ export class InMemory${t}Repository implements I${t}Repository {
|
|
|
1683
1779
|
this.store.delete(id)
|
|
1684
1780
|
}
|
|
1685
1781
|
}
|
|
1686
|
-
`}function
|
|
1782
|
+
`}function jn(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`/**
|
|
1687
1783
|
* ${o} ${t} Repository
|
|
1688
1784
|
*
|
|
1689
1785
|
* Stub implementation for a custom '${r}' repository.
|
|
@@ -1752,7 +1848,7 @@ export class ${o}${t}Repository implements I${t}Repository {
|
|
|
1752
1848
|
this.store.delete(id)
|
|
1753
1849
|
}
|
|
1754
1850
|
}
|
|
1755
|
-
`}function
|
|
1851
|
+
`}function Mn(e){let{pascal:t,kebab:n}=e;return`/**
|
|
1756
1852
|
* ${t} Domain Service
|
|
1757
1853
|
*
|
|
1758
1854
|
* Domain layer — contains business rules that don't belong to a single entity.
|
|
@@ -1775,7 +1871,7 @@ export class ${t}DomainService {
|
|
|
1775
1871
|
}
|
|
1776
1872
|
}
|
|
1777
1873
|
}
|
|
1778
|
-
`}function
|
|
1874
|
+
`}function Nn(e){let{pascal:t,kebab:n}=e;return`/**
|
|
1779
1875
|
* ${t} Entity
|
|
1780
1876
|
*
|
|
1781
1877
|
* Domain layer — the core business object.
|
|
@@ -1844,7 +1940,7 @@ export class ${t} {
|
|
|
1844
1940
|
}
|
|
1845
1941
|
}
|
|
1846
1942
|
}
|
|
1847
|
-
`}function
|
|
1943
|
+
`}function Pn(e){let{pascal:t}=e;return`/**
|
|
1848
1944
|
* ${t} ID Value Object
|
|
1849
1945
|
*
|
|
1850
1946
|
* Domain layer — wraps a primitive ID with type safety and validation.
|
|
@@ -1878,7 +1974,7 @@ export class ${t}Id {
|
|
|
1878
1974
|
return this.value === other.value
|
|
1879
1975
|
}
|
|
1880
1976
|
}
|
|
1881
|
-
`}function
|
|
1977
|
+
`}function Fn(e){let{pascal:t,kebab:n,plural:r=``}=e;return`import { describe, it, expect, beforeEach } from 'vitest'
|
|
1882
1978
|
import { Container } from '@forinda/kickjs'
|
|
1883
1979
|
|
|
1884
1980
|
describe('${t}Controller', () => {
|
|
@@ -1930,7 +2026,7 @@ describe('${t}Controller', () => {
|
|
|
1930
2026
|
})
|
|
1931
2027
|
})
|
|
1932
2028
|
})
|
|
1933
|
-
`}function
|
|
2029
|
+
`}function In(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'
|
|
1934
2030
|
import { InMemory${t}Repository } from '${i}'
|
|
1935
2031
|
|
|
1936
2032
|
describe('InMemory${t}Repository', () => {
|
|
@@ -1992,7 +2088,7 @@ describe('InMemory${t}Repository', () => {
|
|
|
1992
2088
|
expect(found).toBeNull()
|
|
1993
2089
|
})
|
|
1994
2090
|
})
|
|
1995
|
-
`}function
|
|
2091
|
+
`}function Ln(e){let{pascal:t,kebab:n}=e;return`import { Service, Inject, HttpException } from '@forinda/kickjs'
|
|
1996
2092
|
import type { ParsedQuery } from '@forinda/kickjs'
|
|
1997
2093
|
import { ${t.toUpperCase()}_REPOSITORY, type I${t}Repository } from './${n}.repository'
|
|
1998
2094
|
import type { ${t}ResponseDTO } from './dtos/${n}-response.dto'
|
|
@@ -2029,14 +2125,14 @@ export class ${t}Service {
|
|
|
2029
2125
|
await this.repo.delete(id)
|
|
2030
2126
|
}
|
|
2031
2127
|
}
|
|
2032
|
-
`}function
|
|
2128
|
+
`}function Rn(e){let{pascal:t}=e;return`import type { QueryFieldConfig } from '@forinda/kickjs'
|
|
2033
2129
|
|
|
2034
2130
|
export const ${t.toUpperCase()}_QUERY_CONFIG: QueryFieldConfig = {
|
|
2035
2131
|
filterable: ['name'],
|
|
2036
2132
|
sortable: ['name', 'createdAt'],
|
|
2037
2133
|
searchable: ['name'],
|
|
2038
2134
|
}
|
|
2039
|
-
`}function
|
|
2135
|
+
`}function zn(e){let{pascal:t,kebab:n,plural:r=``,repo:i,style:a}=e,o={inmemory:`InMemory${t}Repository`,drizzle:`Drizzle${t}Repository`,prisma:`Prisma${t}Repository`},s={inmemory:`in-memory-${n}`,drizzle:`drizzle-${n}`,prisma:`prisma-${n}`},c=o[i]??o.inmemory,l=s[i]??s.inmemory,u=a??`define`,d=`/**
|
|
2040
2136
|
* ${t} Module — CQRS Pattern
|
|
2041
2137
|
*
|
|
2042
2138
|
* Separates read (queries) and write (commands) operations.
|
|
@@ -2115,7 +2211,7 @@ ${p}
|
|
|
2115
2211
|
},
|
|
2116
2212
|
}),
|
|
2117
2213
|
})
|
|
2118
|
-
`}function
|
|
2214
|
+
`}function Bn(e){let{pascal:t,kebab:n,plural:r=``,pluralPascal:i=``}=e;return`import { Controller, Get, Post, Put, Delete, Autowired, ApiQueryParams, type Ctx } from '@forinda/kickjs'
|
|
2119
2215
|
import { ApiTags } from '@forinda/kickjs-swagger'
|
|
2120
2216
|
import { Create${t}Command } from './commands/create-${n}.command'
|
|
2121
2217
|
import { Update${t}Command } from './commands/update-${n}.command'
|
|
@@ -2178,7 +2274,7 @@ export class ${t}Controller {
|
|
|
2178
2274
|
ctx.noContent()
|
|
2179
2275
|
}
|
|
2180
2276
|
}
|
|
2181
|
-
`}function
|
|
2277
|
+
`}function Vn(e){let{pascal:t,kebab:n}=e;return[{file:`create-${n}.command.ts`,content:`import { Service, Inject } from '@forinda/kickjs'
|
|
2182
2278
|
import { ${t.toUpperCase()}_REPOSITORY, type I${t}Repository } from '../${n}.repository'
|
|
2183
2279
|
import type { Create${t}DTO } from '../dtos/create-${n}.dto'
|
|
2184
2280
|
import type { ${t}ResponseDTO } from '../dtos/${n}-response.dto'
|
|
@@ -2232,7 +2328,7 @@ export class Delete${t}Command {
|
|
|
2232
2328
|
this.events.emit('${n}.deleted', { id })
|
|
2233
2329
|
}
|
|
2234
2330
|
}
|
|
2235
|
-
`}]}function
|
|
2331
|
+
`}]}function Hn(e){let{pascal:t,kebab:n,plural:r=``,pluralPascal:i=``}=e;return[{file:`get-${n}.query.ts`,content:`import { Service, Inject } from '@forinda/kickjs'
|
|
2236
2332
|
import { ${t.toUpperCase()}_REPOSITORY, type I${t}Repository } from '../${n}.repository'
|
|
2237
2333
|
import type { ${t}ResponseDTO } from '../dtos/${n}-response.dto'
|
|
2238
2334
|
|
|
@@ -2260,7 +2356,7 @@ export class List${i}Query {
|
|
|
2260
2356
|
return this.repo.findPaginated(parsed)
|
|
2261
2357
|
}
|
|
2262
2358
|
}
|
|
2263
|
-
`}]}function
|
|
2359
|
+
`}]}function Un(e){let{pascal:t,kebab:n}=e;return[{file:`${n}.events.ts`,content:`import { Service } from '@forinda/kickjs'
|
|
2264
2360
|
import { EventEmitter } from 'node:events'
|
|
2265
2361
|
import type { ${t}ResponseDTO } from '../dtos/${n}-response.dto'
|
|
2266
2362
|
|
|
@@ -2346,7 +2442,7 @@ export class On${t}ChangeHandler {
|
|
|
2346
2442
|
})
|
|
2347
2443
|
}
|
|
2348
2444
|
}
|
|
2349
|
-
`}]}function
|
|
2445
|
+
`}]}function Wn(e){let{pascal:t,kebab:n,repoPrefix:r=`../../domain/repositories`,dtoPrefix:i=`../../application/dtos`}=e;return`/**
|
|
2350
2446
|
* Drizzle ${t} Repository
|
|
2351
2447
|
*
|
|
2352
2448
|
* Implements the repository interface using Drizzle ORM.
|
|
@@ -2428,7 +2524,7 @@ export class Drizzle${t}Repository implements I${t}Repository {
|
|
|
2428
2524
|
throw new Error('Drizzle ${t} repository not yet implemented')
|
|
2429
2525
|
}
|
|
2430
2526
|
}
|
|
2431
|
-
`}function
|
|
2527
|
+
`}function Gn(e){let{pascal:t,kebab:n}=e;return`import type { DrizzleQueryParamsConfig } from '@forinda/kickjs-drizzle'
|
|
2432
2528
|
// TODO: Import your schema table and reference actual columns for type safety
|
|
2433
2529
|
// import { ${n}s } from '@/db/schema'
|
|
2434
2530
|
|
|
@@ -2446,7 +2542,7 @@ export const ${t.toUpperCase()}_QUERY_CONFIG: DrizzleQueryParamsConfig = {
|
|
|
2446
2542
|
// ${n}s.name,
|
|
2447
2543
|
],
|
|
2448
2544
|
}
|
|
2449
|
-
`}function
|
|
2545
|
+
`}function Kn(e){let{pascal:t,kebab:n,repoPrefix:r=`../../domain/repositories`,dtoPrefix:i=`../../application/dtos`}=e,a=n.replace(/-([a-z])/g,(e,t)=>t.toUpperCase());return`/**
|
|
2450
2546
|
* Prisma ${t} Repository
|
|
2451
2547
|
*
|
|
2452
2548
|
* Implements the repository interface using Prisma Client.
|
|
@@ -2504,7 +2600,7 @@ export class Prisma${t}Repository implements I${t}Repository {
|
|
|
2504
2600
|
await this.prisma.${a}.deleteMany({ where: { id } })
|
|
2505
2601
|
}
|
|
2506
2602
|
}
|
|
2507
|
-
`}async function
|
|
2603
|
+
`}async function qn(e){let{pascal:t,kebab:n,plural:r,style:i,write:a}=e;await a(`${n}.module.ts`,Sn({pascal:t,kebab:n,plural:r,style:i})),await a(`${n}.controller.ts`,`import { Controller, Get, type Ctx } from '@forinda/kickjs'
|
|
2508
2604
|
|
|
2509
2605
|
// \`Ctx<KickRoutes.${t}Controller['<method>']>\` is generated by
|
|
2510
2606
|
// \`kick typegen\` (auto-run on \`kick dev\`).
|
|
@@ -2516,7 +2612,7 @@ export class ${t}Controller {
|
|
|
2516
2612
|
ctx.json({ message: '${t} list' })
|
|
2517
2613
|
}
|
|
2518
2614
|
}
|
|
2519
|
-
`)}async function
|
|
2615
|
+
`)}async function Jn(e){let{pascal:t,kebab:n,plural:r,pluralPascal:i,repo:a,noTests:o,prismaClientPath:s,tokenScope:c,style:l,write:u}=e;await u(`${n}.module.ts`,xn({pascal:t,kebab:n,plural:r,repo:a,style:l})),await u(`${n}.constants.ts`,Rn({pascal:t,kebab:n})),await u(`${n}.controller.ts`,wn({pascal:t,kebab:n,plural:r,pluralPascal:i})),await u(`${n}.service.ts`,Ln({pascal:t,kebab:n})),await u(`dtos/create-${n}.dto.ts`,En({pascal:t,kebab:n})),await u(`dtos/update-${n}.dto.ts`,Dn({pascal:t,kebab:n})),await u(`dtos/${n}-response.dto.ts`,On({pascal:t,kebab:n})),await u(`${n}.repository.ts`,An({pascal:t,kebab:n,dtoPrefix:`./dtos`,tokenScope:c}));let d={inmemory:`in-memory-${n}`,drizzle:`drizzle-${n}`,prisma:`prisma-${n}`},f={inmemory:()=>V({pascal:t,kebab:n,repoPrefix:`.`,dtoPrefix:`./dtos`}),drizzle:()=>Wn({pascal:t,kebab:n,repoPrefix:`.`,dtoPrefix:`./dtos`}),prisma:()=>Kn({pascal:t,kebab:n,repoPrefix:`.`,dtoPrefix:`./dtos`,prismaClientPath:s})},p=d[a]??`${R(a)}-${n}`,m=f[a]??(()=>jn({pascal:t,kebab:n,repoType:a,repoPrefix:`.`,dtoPrefix:`./dtos`}));await u(`${p}.repository.ts`,m()),o||(a!==`inmemory`&&await u(`in-memory-${n}.repository.ts`,V({pascal:t,kebab:n,repoPrefix:`.`,dtoPrefix:`./dtos`})),await u(`__tests__/${n}.controller.test.ts`,Fn({pascal:t,kebab:n,plural:r})),await u(`__tests__/${n}.repository.test.ts`,In({pascal:t,kebab:n,plural:r,repoPrefix:`../${d.inmemory??`in-memory-${n}`}.repository`})))}async function Yn(e){let{pascal:t,kebab:n,plural:r,pluralPascal:i,repo:a,noTests:o,prismaClientPath:s,tokenScope:c,style:l,write:u}=e;await u(`${n}.module.ts`,zn({pascal:t,kebab:n,plural:r,repo:a,style:l})),await u(`${n}.constants.ts`,Rn({pascal:t,kebab:n})),await u(`${n}.controller.ts`,Bn({pascal:t,kebab:n,plural:r,pluralPascal:i})),await u(`dtos/create-${n}.dto.ts`,En({pascal:t,kebab:n})),await u(`dtos/update-${n}.dto.ts`,Dn({pascal:t,kebab:n})),await u(`dtos/${n}-response.dto.ts`,On({pascal:t,kebab:n}));let d=Vn({pascal:t,kebab:n});for(let e of d)await u(`commands/${e.file}`,e.content);let f=Hn({pascal:t,kebab:n,plural:r,pluralPascal:i});for(let e of f)await u(`queries/${e.file}`,e.content);let p=Un({pascal:t,kebab:n});for(let e of p)await u(`events/${e.file}`,e.content);await u(`${n}.repository.ts`,An({pascal:t,kebab:n,dtoPrefix:`./dtos`,tokenScope:c}));let m={inmemory:`in-memory-${n}`,drizzle:`drizzle-${n}`,prisma:`prisma-${n}`},h={inmemory:()=>V({pascal:t,kebab:n,repoPrefix:`.`,dtoPrefix:`./dtos`}),drizzle:()=>Wn({pascal:t,kebab:n,repoPrefix:`.`,dtoPrefix:`./dtos`}),prisma:()=>Kn({pascal:t,kebab:n,repoPrefix:`.`,dtoPrefix:`./dtos`,prismaClientPath:s})},g=m[a]??`${R(a)}-${n}`,_=h[a]??(()=>jn({pascal:t,kebab:n,repoType:a,repoPrefix:`.`,dtoPrefix:`./dtos`}));await u(`${g}.repository.ts`,_()),o||(a!==`inmemory`&&await u(`in-memory-${n}.repository.ts`,V({pascal:t,kebab:n,repoPrefix:`.`,dtoPrefix:`./dtos`})),await u(`__tests__/${n}.controller.test.ts`,Fn({pascal:t,kebab:n,plural:r})),await u(`__tests__/${n}.repository.test.ts`,In({pascal:t,kebab:n,plural:r,repoPrefix:`../${m.inmemory??`in-memory-${n}`}.repository`})))}async function Xn(e){let{pascal:t,kebab:n,plural:r,pluralPascal:i,repo:a,noEntity:o,noTests:s,prismaClientPath:c,tokenScope:l,style:u,write:d}=e;await d(`${n}.module.ts`,bn({pascal:t,kebab:n,plural:r,repo:a,style:u})),await d(`constants.ts`,a===`drizzle`?Gn({pascal:t,kebab:n}):Tn({pascal:t,kebab:n})),await d(`presentation/${n}.controller.ts`,Cn({pascal:t,kebab:n,plural:r,pluralPascal:i})),await d(`application/dtos/create-${n}.dto.ts`,En({pascal:t,kebab:n})),await d(`application/dtos/update-${n}.dto.ts`,Dn({pascal:t,kebab:n})),await d(`application/dtos/${n}-response.dto.ts`,On({pascal:t,kebab:n}));let f=kn({pascal:t,kebab:n,plural:r,pluralPascal:i});for(let e of f)await d(`application/use-cases/${e.file}`,e.content);await d(`domain/repositories/${n}.repository.ts`,An({pascal:t,kebab:n,tokenScope:l})),await d(`domain/services/${n}-domain.service.ts`,Mn({pascal:t,kebab:n}));let p={inmemory:`in-memory-${n}`,drizzle:`drizzle-${n}`,prisma:`prisma-${n}`},m={inmemory:()=>V({pascal:t,kebab:n}),drizzle:()=>Wn({pascal:t,kebab:n}),prisma:()=>Kn({pascal:t,kebab:n,prismaClientPath:c})},h=p[a]??`${R(a)}-${n}`,g=m[a]??(()=>jn({pascal:t,kebab:n,repoType:a}));await d(`infrastructure/repositories/${h}.repository.ts`,g()),o||(await d(`domain/entities/${n}.entity.ts`,Nn({pascal:t,kebab:n})),await d(`domain/value-objects/${n}-id.vo.ts`,Pn({pascal:t,kebab:n}))),s||(a!==`inmemory`&&await d(`infrastructure/repositories/in-memory-${n}.repository.ts`,V({pascal:t,kebab:n})),await d(`__tests__/${n}.controller.test.ts`,Fn({pascal:t,kebab:n,plural:r})),await d(`__tests__/${n}.repository.test.ts`,In({pascal:t,kebab:n,plural:r})))}function Zn(e){return e?typeof e==`string`?e:e.name:`inmemory`}async function Qn(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??`ddd`;e.minimal&&(l=`minimal`);let u=R(t),d=I(t),f=c?z(u):u,p=c?Xt(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 Ze(n)&&!await P({message:`File exists: ${E.dim(e)}. Overwrite?`,initialValue:!1})){F.warn(`Skipped: ${e}`);return}await M(n,t),g.push(n)},files:g};switch(l){case`minimal`:await qn(v);break;case`rest`:await Jn(v);break;case`cqrs`:await Yn(v);break;default:await Xn(v);break}return s||await $n(n,d,f,u,v.style),g}async function $n(e,t,n,r,i=`define`){let a=h(e,`index.ts`),o=await Ze(a),s=`./${n}/${r}.module`,c=i===`class`?`${t}Module`:`${t}Module()`;if(!o){await M(a,i===`class`?`import type { AppModuleEntry } from '@forinda/kickjs'
|
|
2520
2616
|
import { ${t}Module } from '${s}'
|
|
2521
2617
|
|
|
2522
2618
|
export const modules: AppModuleEntry[] = [${c}]
|
|
@@ -2527,8 +2623,8 @@ export const modules = defineModules().mount(${c})
|
|
|
2527
2623
|
`);return}let l=await C(a,`utf-8`),u=`import { ${t}Module } from '${s}'`,d=B(s);if(!RegExp(`^import\\s*\\{[^}]*\\b${B(t)}Module\\b[^}]*\\}\\s*from\\s*['"]${d}['"]`,`m`).test(l)){let e=l.lastIndexOf(`import `);if(e!==-1){let t=l.indexOf(`
|
|
2528
2624
|
`,e);l=l.slice(0,t+1)+u+`
|
|
2529
2625
|
`+l.slice(t+1)}else l=u+`
|
|
2530
|
-
`+l}let f=
|
|
2531
|
-
`;)t++;return t}if(n===`/*`){for(t+=2;t+1<e.length&&!(e[t]===`*`&&e[t+1]===`/`);)t++;return t+2}return t}function
|
|
2626
|
+
`+l}let f=tr(l);if(f){let e=l.slice(f.rhsStart,f.rhsEnd+1);RegExp(`\\b${B(t)}Module\\b`).test(e)||(l=er(l,c))}else l=er(l,c);await w(a,l,`utf-8`)}function er(e,t){let n=tr(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 tr(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=ir(e,n);return t===-1?null:{shape:`array`,rhsStart:n,rhsEnd:t}}if(e.slice(n,n+13)===`defineModules`){let t=nr(e,n);return t===-1?null:{shape:`chain`,rhsStart:n,rhsEnd:t-1,chainEnd:t}}return null}function nr(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=ar(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=ar(e,t);if(n===-1)break;i=n+1}return i}function rr(e,t){let n=e.slice(t,t+2);if(n===`//`){for(t+=2;t<e.length&&e[t]!==`
|
|
2627
|
+
`;)t++;return t}if(n===`/*`){for(t+=2;t+1<e.length&&!(e[t]===`*`&&e[t+1]===`/`);)t++;return t+2}return t}function ir(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=rr(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 ar(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=rr(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 or(e){let{name:t,outDir:n}=e,r=R(t),i=I(t),a=[],o=h(n,`${r}.adapter.ts`);return await M(o,`import {
|
|
2532
2628
|
defineAdapter,
|
|
2533
2629
|
type AdapterContext,
|
|
2534
2630
|
type AdapterMiddleware,
|
|
@@ -2697,7 +2793,7 @@ export const ${i}Adapter = defineAdapter<${i}AdapterConfig>({
|
|
|
2697
2793
|
}
|
|
2698
2794
|
},
|
|
2699
2795
|
})
|
|
2700
|
-
`),a.push(o),a}async function
|
|
2796
|
+
`),a.push(o),a}async function sr(e){let{name:t,outDir:n}=e,r=R(t),i=I(t),a=[],o=h(n,`${r}.plugin.ts`);return await M(o,`import {
|
|
2701
2797
|
definePlugin,
|
|
2702
2798
|
type AppAdapter,
|
|
2703
2799
|
type AppModuleEntry,
|
|
@@ -2841,7 +2937,7 @@ export const ${i}Plugin = definePlugin<${i}PluginConfig>({
|
|
|
2841
2937
|
},
|
|
2842
2938
|
}),
|
|
2843
2939
|
})
|
|
2844
|
-
`),a.push(o),a}const
|
|
2940
|
+
`),a.push(o),a}const cr={controller:`presentation`,service:`domain/services`,dto:`application/dtos`,guard:`presentation/guards`,middleware:`middleware`},lr={controller:``,service:``,dto:`dtos`,guard:`guards`,middleware:`middleware`},ur={controller:``,service:``,dto:`dtos`,guard:`guards`,middleware:`middleware`,command:`commands`,query:`queries`,event:`events`};function dr(e){let{type:t,outDir:n,moduleName:r,modulesDir:i=`src/modules`,defaultDir:a,pattern:o=`ddd`,shouldPluralize:s=!0}=e;if(n)return v(n);if(r){let e=o===`ddd`?cr:o===`cqrs`?ur:lr,n=R(r),a=s?z(n):n,c=e[t]??``,l=h(i,a);return v(c?h(l,c):l)}return v(a)}async function fr(e){let{name:t,moduleName:n,modulesDir:r,pattern:i}=e,a=dr({type:`middleware`,outDir:e.outDir,moduleName:n,modulesDir:r,defaultDir:`src/middleware`,pattern:i,shouldPluralize:e.pluralize??!0}),o=R(t),s=L(t),c=[],l=h(a,`${o}.middleware.ts`);return await M(l,`import type { Request, Response, NextFunction } from 'express'
|
|
2845
2941
|
|
|
2846
2942
|
export interface ${I(t)}Options {
|
|
2847
2943
|
// Add configuration options here. The factory below closes over the
|
|
@@ -2891,7 +2987,7 @@ export function ${s}(options: ${I(t)}Options = {}) {
|
|
|
2891
2987
|
next()
|
|
2892
2988
|
}
|
|
2893
2989
|
}
|
|
2894
|
-
`),c.push(l),c}async function
|
|
2990
|
+
`),c.push(l),c}async function pr(e){let{name:t,moduleName:n,modulesDir:r,pattern:i}=e,a=dr({type:`guard`,outDir:e.outDir,moduleName:n,modulesDir:r,defaultDir:`src/guards`,pattern:i,shouldPluralize:e.pluralize??!0}),o=R(t),s=L(t),c=I(t),l=[],u=h(a,`${o}.guard.ts`);return await M(u,`import { Container, HttpException } from '@forinda/kickjs'
|
|
2895
2991
|
import type { RequestContext } from '@forinda/kickjs'
|
|
2896
2992
|
|
|
2897
2993
|
/**
|
|
@@ -2927,7 +3023,7 @@ export async function ${s}Guard(ctx: RequestContext, next: () => void): Promise<
|
|
|
2927
3023
|
ctx.res.status(401).json({ message: 'Invalid or expired token' })
|
|
2928
3024
|
}
|
|
2929
3025
|
}
|
|
2930
|
-
`),l.push(u),l}async function
|
|
3026
|
+
`),l.push(u),l}async function mr(e){let{name:t,moduleName:n,modulesDir:r,pattern:i}=e,a=dr({type:`service`,outDir:e.outDir,moduleName:n,modulesDir:r,defaultDir:`src/services`,pattern:i,shouldPluralize:e.pluralize??!0}),o=R(t),s=I(t),c=[],l=h(a,`${o}.service.ts`);return await M(l,`import { Service } from '@forinda/kickjs'
|
|
2931
3027
|
|
|
2932
3028
|
@Service()
|
|
2933
3029
|
export class ${s}Service {
|
|
@@ -2936,7 +3032,7 @@ export class ${s}Service {
|
|
|
2936
3032
|
// @Inject(MY_REPO) private readonly repo: IMyRepository,
|
|
2937
3033
|
// ) {}
|
|
2938
3034
|
}
|
|
2939
|
-
`),c.push(l),c}async function
|
|
3035
|
+
`),c.push(l),c}async function hr(e){let{name:t,moduleName:n,modulesDir:r,pattern:i}=e,a=dr({type:`controller`,outDir:e.outDir,moduleName:n,modulesDir:r,defaultDir:`src/controllers`,pattern:i,shouldPluralize:e.pluralize??!0}),o=R(t),s=I(t),c=[],l=h(a,`${o}.controller.ts`);return await M(l,`import { Controller, Get, Post, type Ctx } from '@forinda/kickjs'
|
|
2940
3036
|
|
|
2941
3037
|
// \`Ctx<KickRoutes.${s}Controller['<method>']>\` is generated by
|
|
2942
3038
|
// \`kick typegen\` (auto-run on \`kick dev\`). After the first run, your IDE
|
|
@@ -2957,7 +3053,7 @@ export class ${s}Controller {
|
|
|
2957
3053
|
ctx.created({ message: '${s} created', data: ctx.body })
|
|
2958
3054
|
}
|
|
2959
3055
|
}
|
|
2960
|
-
`),c.push(l),c}async function
|
|
3056
|
+
`),c.push(l),c}async function gr(e){let{name:t,moduleName:n,modulesDir:r,pattern:i}=e,a=dr({type:`dto`,outDir:e.outDir,moduleName:n,modulesDir:r,defaultDir:`src/dtos`,pattern:i,shouldPluralize:e.pluralize??!0}),o=R(t),s=I(t),c=L(t),l=[],u=h(a,`${o}.dto.ts`);return await M(u,`import { z } from 'zod'
|
|
2961
3057
|
|
|
2962
3058
|
export const ${c}Schema = z.object({
|
|
2963
3059
|
// Define your schema fields here
|
|
@@ -2965,7 +3061,7 @@ export const ${c}Schema = z.object({
|
|
|
2965
3061
|
})
|
|
2966
3062
|
|
|
2967
3063
|
export type ${s}DTO = z.infer<typeof ${c}Schema>
|
|
2968
|
-
`),l.push(u),l}async function
|
|
3064
|
+
`),l.push(u),l}async function _r(e){let t=h(e.outDir,`kick.config.ts`),n=e.modulesDir??`src/modules`,i=e.defaultRepo??`inmemory`;return r(t)&&!e.force&&!await P({message:`kick.config.ts already exists. Overwrite?`,initialValue:!1})?(console.log(`
|
|
2969
3065
|
Skipped — existing kick.config.ts preserved.`),[]):(await M(t,`import { defineConfig } from '@forinda/kickjs-cli'
|
|
2970
3066
|
|
|
2971
3067
|
export default defineConfig({
|
|
@@ -3003,18 +3099,18 @@ export default defineConfig({
|
|
|
3003
3099
|
},
|
|
3004
3100
|
],
|
|
3005
3101
|
})
|
|
3006
|
-
`),[t])}var
|
|
3102
|
+
`),[t])}var vr=D({generateAgentDocs:()=>wr});const yr=`.agents`,br=new Set([`rest`,`ddd`,`cqrs`,`minimal`]);function xr(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 Sr(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 Cr(e,t){if(t)return t;try{let t=(await k(e))?.pattern;if(t&&br.has(t))return t}catch{}return`ddd`}async function wr(e){let t=e.only??`all`,n=xr(e.outDir,e.name),i=Sr(e.outDir,e.pm),a=await Cr(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,yr,`AGENTS.md`),render:()=>bt(n,a,i)}),s&&d.push({file:h(e.outDir,`CLAUDE.md`),render:()=>yt(n,a,i)}),c)for(let t of xt(n,a,i))d.push({file:h(e.outDir,yr,`skills`,t.slug,`SKILL.md`),render:()=>t.content});l&&d.push({file:h(e.outDir,yr,`GEMINI.md`),render:()=>St(n,a,i)}),u&&d.push({file:h(e.outDir,yr,`COPILOT.md`),render:()=>Ct(n,a,i)});let f=[];for(let{file:t,render:n}of d){if(r(t)&&!e.force&&!await P({message:`${t.replace(e.outDir+`/`,``)} already exists. Overwrite?`,initialValue:!1})){console.log(` Skipped — existing ${t.replace(e.outDir+`/`,``)} preserved.`);continue}await M(t,n()),f.push(t)}return f}function Tr(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 H(e,t){let n=t.exec(e);if(!n)return null;let r=n.index+n[0].length-1,i=Tr(e,r);return i===-1?null:e.slice(r+1,i)}function U(e,t,n){let r=` `.repeat(n);return e.split(`
|
|
3007
3103
|
`).map(e=>{if(e.trim()===``)return e;let n=RegExp(`^ {0,${t}}`);return r+e.replace(n,``)}).join(`
|
|
3008
|
-
`)}function
|
|
3104
|
+
`)}function Er(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 Dr(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 Or(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=Tr(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=H(o,/register\s*\(([^)]*)\)\s*:\s*void\s*\{/),u=H(o,/contributors\s*\(\s*\)\s*:\s*ContributorRegistrations\s*\{/),d=H(o,/routes\s*\(\s*\)\s*:\s*[A-Za-z|[\]\s]+\{/);if(!d)return{migrated:null,reason:`routes() method missing or signature unrecognized`};let f=Er(s),p=``;return l&&(p+=` register(container) {${U(l,4,6)} },\n\n`),u&&(p+=` contributors() {${U(u,4,6)} },\n\n`),p+=` routes() {${U(d,4,6)} },`,{migrated:`${f}${`export const ${r} = defineModule({
|
|
3009
3105
|
name: '${r}',
|
|
3010
3106
|
build: () => ({
|
|
3011
3107
|
${p}
|
|
3012
3108
|
}),
|
|
3013
|
-
})`}${c}`}}function
|
|
3014
|
-
`||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=
|
|
3109
|
+
})`}${c}`}}function kr(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=Tr(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]===`
|
|
3110
|
+
`||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=Tr(s,f);if(p===-1)return{migrated:null,reason:`unbalanced build() braces`};let m=s.slice(f+1,p),h=H(m,/register\s*\(([^)]*)\)\s*\{/),g=H(m,/contributors\s*\(\s*\)\s*\{/),_=H(m,/routes\s*\(\s*\)\s*\{/);if(!_)return{migrated:null,reason:`routes() method missing inside build()`};let v=Dr(c,{container:h!==null,appModule:!0,moduleRoutes:!0,contributorRegistrations:g!==null}),y=``;return h!==null&&(y+=` register(container: Container): void {${U(h,6,4)} }\n\n`),g!==null&&(y+=` contributors(): ContributorRegistrations {${U(g,6,4)} }\n\n`),y+=` routes(): ModuleRoutes {${U(_,6,4)} }`,{migrated:`${v}${`export class ${r} implements AppModule {
|
|
3015
3111
|
${y}
|
|
3016
3112
|
}
|
|
3017
|
-
`}${u}`}}function
|
|
3113
|
+
`}${u}`}}function Ar(e,t){return t===`class`?kr(e):Or(e)}function jr(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 Mr(e){let t=[];return await n(v(e),0),t;async function n(e,r){let i;try{i=await se(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 le(i)}catch{continue}o.isDirectory()?await n(i,r+1):(a.endsWith(`.module.ts`)||a===`index.ts`&&r===1)&&t.push(i)}}}async function Nr(e,t){let n=0;return await r(e,t),n;async function r(e,t){let i;try{i=await se(e)}catch{return}await oe(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 le(i)}catch{continue}s.isDirectory()?await r(i,o):(await ae(i,o),n++)}}}function Pr(e){return h(e,`.kickjs`,`codemod-backups`,`${new Date().toISOString().replaceAll(/[:.]/g,`-`)}-modules`)}async function Fr(e,t){let{dryRun:n=!1,cwd:r=process.cwd(),target:i}=t,a=t.backup??!n,o=await Mr(e),s=await C(h(e,`index.ts`),`utf-8`).then(()=>!0,()=>!1),c=null;a&&(o.length>0||s)&&(c=Pr(r),await Nr(e,c));let l=[];for(let e of o){let t=Ar(await C(e,`utf-8`),i);if(t.migrated==null){l.push({path:e,status:`skipped`,reason:t.reason});continue}n||await w(e,t.migrated,`utf-8`),l.push({path:e,status:`migrated`})}let u=h(e,`index.ts`),d=null;try{d=await C(u,`utf-8`)}catch{return{target:i,files:l,indexStatus:`not-found`,indexPath:u,backupDir:c}}let f=jr(d,i);return f.migrated==null?{target:i,files:l,indexStatus:`skipped`,indexPath:u,indexReason:f.reason,backupDir:c}:(n||await w(u,f.migrated,`utf-8`),{target:i,files:l,indexStatus:`migrated`,indexPath:u,backupDir:c})}async function Ir(e,t){let n=await Mr(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 C(e,`utf-8`);i.test(t)&&r.push(e)}return r}async function Lr(e){let{name:t,outDir:n}=e,r=I(t),i=R(t),a=L(t),o=e.queue??`${i}-queue`,s=[];return await(async(e,t)=>{let r=h(n,e);await M(r,t),s.push(r)})(`${i}.job.ts`,`import { Inject } from '@forinda/kickjs'
|
|
3018
3114
|
import { Job, Process, QUEUE_MANAGER, type QueueService } from '@forinda/kickjs-queue'
|
|
3019
3115
|
|
|
3020
3116
|
/**
|
|
@@ -3047,7 +3143,7 @@ export class ${r}Job {
|
|
|
3047
3143
|
// Handle high-priority variant of this job
|
|
3048
3144
|
}
|
|
3049
3145
|
}
|
|
3050
|
-
`),s}const
|
|
3146
|
+
`),s}const Rr={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 zr(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=Rr[a];if(!o){let e=[...Object.keys(Rr),`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 Br(e){let{name:t,fields:n,modulesDir:r,noEntity:i,noTests:a,repo:o=`inmemory`,tokenScope:s=`app`,style:c=`define`}=e,l=e.pluralize!==!1,u=R(t),d=I(t);L(t);let f=l?z(u):u,p=l?Xt(d):d,m=h(r,f),g=[],_=async(e,t)=>{let n=h(m,e);await M(n,t),g.push(n)};await _(`${u}.module.ts`,Jr(d,u,f,c)),await _(`constants.ts`,Wr(d,n)),await _(`presentation/${u}.controller.ts`,Yr(d,u,f,p)),await _(`application/dtos/create-${u}.dto.ts`,Vr(d,n)),await _(`application/dtos/update-${u}.dto.ts`,Hr(d,n)),await _(`application/dtos/${u}-response.dto.ts`,Ur(d,n));let v=Qr(d,u,f,p);for(let e of v)await _(`application/use-cases/${e.file}`,e.content);return await _(`domain/repositories/${u}.repository.ts`,Xr(d,u,s)),await _(`domain/services/${u}-domain.service.ts`,Zr(d,u)),o===`inmemory`&&await _(`infrastructure/repositories/in-memory-${u}.repository.ts`,Gr(d,u,n)),i||(await _(`domain/entities/${u}.entity.ts`,Kr(d,u,n)),await _(`domain/value-objects/${u}-id.vo.ts`,qr(d))),await $n(r,d,f,u,c),g}function Vr(e,t){return`import { z } from 'zod'
|
|
3051
3147
|
|
|
3052
3148
|
export const create${e}Schema = z.object({
|
|
3053
3149
|
${t.map(e=>{let t=e.zodType;return` ${e.name}: ${t}${e.optional?`.optional()`:``},`}).join(`
|
|
@@ -3055,7 +3151,7 @@ ${t.map(e=>{let t=e.zodType;return` ${e.name}: ${t}${e.optional?`.optional()`:`
|
|
|
3055
3151
|
})
|
|
3056
3152
|
|
|
3057
3153
|
export type Create${e}DTO = z.infer<typeof create${e}Schema>
|
|
3058
|
-
`}function
|
|
3154
|
+
`}function Hr(e,t){return`import { z } from 'zod'
|
|
3059
3155
|
|
|
3060
3156
|
export const update${e}Schema = z.object({
|
|
3061
3157
|
${t.map(e=>` ${e.name}: ${e.zodType}.optional(),`).join(`
|
|
@@ -3063,21 +3159,21 @@ ${t.map(e=>` ${e.name}: ${e.zodType}.optional(),`).join(`
|
|
|
3063
3159
|
})
|
|
3064
3160
|
|
|
3065
3161
|
export type Update${e}DTO = z.infer<typeof update${e}Schema>
|
|
3066
|
-
`}function
|
|
3162
|
+
`}function Ur(e,t){return`export interface ${e}ResponseDTO {
|
|
3067
3163
|
id: string
|
|
3068
3164
|
${t.map(e=>` ${e.name}${e.optional?`?`:``}: ${e.tsType}`).join(`
|
|
3069
3165
|
`)}
|
|
3070
3166
|
createdAt: string
|
|
3071
3167
|
updatedAt: string
|
|
3072
3168
|
}
|
|
3073
|
-
`}function
|
|
3169
|
+
`}function Wr(e,t){let n=t.filter(e=>e.tsType===`string`).map(e=>`'${e.name}'`);t.filter(e=>e.tsType===`number`).map(e=>`'${e.name}'`);let r=t.map(e=>`'${e.name}'`),i=[...r].join(`, `),a=[...r,`'createdAt'`,`'updatedAt'`].join(`, `),o=n.length>0?n.join(`, `):`'name'`;return`import type { ApiQueryParamsConfig } from '@forinda/kickjs'
|
|
3074
3170
|
|
|
3075
3171
|
export const ${e.toUpperCase()}_QUERY_CONFIG: ApiQueryParamsConfig = {
|
|
3076
3172
|
filterable: [${i}],
|
|
3077
3173
|
sortable: [${a}],
|
|
3078
3174
|
searchable: [${o}],
|
|
3079
3175
|
}
|
|
3080
|
-
`}function
|
|
3176
|
+
`}function Gr(e,t,n){return`import { randomUUID } from 'node:crypto'
|
|
3081
3177
|
import { Repository, HttpException } from '@forinda/kickjs'
|
|
3082
3178
|
import type { ParsedQuery } from '@forinda/kickjs'
|
|
3083
3179
|
import type { I${e}Repository } from '../../domain/repositories/${t}.repository'
|
|
@@ -3129,7 +3225,7 @@ ${n.map(e=>` ${e.name}: dto.${e.name},`).join(`
|
|
|
3129
3225
|
this.store.delete(id)
|
|
3130
3226
|
}
|
|
3131
3227
|
}
|
|
3132
|
-
`}function
|
|
3228
|
+
`}function Kr(e,t,n){return`import { ${e}Id } from '../value-objects/${t}-id.vo'
|
|
3133
3229
|
|
|
3134
3230
|
interface ${e}Props {
|
|
3135
3231
|
id: ${e}Id
|
|
@@ -3175,7 +3271,7 @@ ${n.map(e=>` ${e.name}: this.props.${e.name},`).join(`
|
|
|
3175
3271
|
}
|
|
3176
3272
|
}
|
|
3177
3273
|
}
|
|
3178
|
-
`}function
|
|
3274
|
+
`}function qr(e){return`import { randomUUID } from 'node:crypto'
|
|
3179
3275
|
|
|
3180
3276
|
export class ${e}Id {
|
|
3181
3277
|
private constructor(private readonly value: string) {}
|
|
@@ -3190,7 +3286,7 @@ export class ${e}Id {
|
|
|
3190
3286
|
toString(): string { return this.value }
|
|
3191
3287
|
equals(other: ${e}Id): boolean { return this.value === other.value }
|
|
3192
3288
|
}
|
|
3193
|
-
`}function
|
|
3289
|
+
`}function Jr(e,t,n,r=`define`){let i=`import { ${e}Controller } from './presentation/${t}.controller'
|
|
3194
3290
|
import { ${e.toUpperCase()}_REPOSITORY } from './domain/repositories/${t}.repository'
|
|
3195
3291
|
import { InMemory${e}Repository } from './infrastructure/repositories/in-memory-${t}.repository'
|
|
3196
3292
|
|
|
@@ -3263,7 +3359,7 @@ ${a}
|
|
|
3263
3359
|
},
|
|
3264
3360
|
}),
|
|
3265
3361
|
})
|
|
3266
|
-
`}function
|
|
3362
|
+
`}function Yr(e,t,n,r){return`import { Controller, Get, Post, Put, Delete, Autowired, ApiQueryParams, type Ctx } from '@forinda/kickjs'
|
|
3267
3363
|
import { ApiTags } from '@forinda/kickjs-swagger'
|
|
3268
3364
|
import { Create${e}UseCase } from '../application/use-cases/create-${t}.use-case'
|
|
3269
3365
|
import { Get${e}UseCase } from '../application/use-cases/get-${t}.use-case'
|
|
@@ -3326,7 +3422,7 @@ export class ${e}Controller {
|
|
|
3326
3422
|
ctx.noContent()
|
|
3327
3423
|
}
|
|
3328
3424
|
}
|
|
3329
|
-
`}function
|
|
3425
|
+
`}function Xr(e,t,n){return`import { createToken } from '@forinda/kickjs'
|
|
3330
3426
|
import type { ${e}ResponseDTO } from '../../application/dtos/${t}-response.dto'
|
|
3331
3427
|
import type { Create${e}DTO } from '../../application/dtos/create-${t}.dto'
|
|
3332
3428
|
import type { Update${e}DTO } from '../../application/dtos/update-${t}.dto'
|
|
@@ -3352,7 +3448,7 @@ export interface I${e}Repository {
|
|
|
3352
3448
|
* adopters must NOT use the reserved \`'kick/'\` namespace.
|
|
3353
3449
|
*/
|
|
3354
3450
|
export const ${e.toUpperCase()}_REPOSITORY = createToken<I${e}Repository>('${n}/${e}/repository')
|
|
3355
|
-
`}function
|
|
3451
|
+
`}function Zr(e,t){return`import { Service, Inject, HttpException } from '@forinda/kickjs'
|
|
3356
3452
|
import { ${e.toUpperCase()}_REPOSITORY, type I${e}Repository } from '../repositories/${t}.repository'
|
|
3357
3453
|
|
|
3358
3454
|
@Service()
|
|
@@ -3366,7 +3462,7 @@ export class ${e}DomainService {
|
|
|
3366
3462
|
if (!entity) throw HttpException.notFound('${e} not found')
|
|
3367
3463
|
}
|
|
3368
3464
|
}
|
|
3369
|
-
`}function
|
|
3465
|
+
`}function Qr(e,t,n,r){return[{file:`create-${t}.use-case.ts`,content:`import { Service, Inject } from '@forinda/kickjs'
|
|
3370
3466
|
import { ${e.toUpperCase()}_REPOSITORY, type I${e}Repository } from '../../domain/repositories/${t}.repository'
|
|
3371
3467
|
import type { Create${e}DTO } from '../dtos/create-${t}.dto'
|
|
3372
3468
|
|
|
@@ -3409,7 +3505,7 @@ export class Delete${e}UseCase {
|
|
|
3409
3505
|
constructor(@Inject(${e.toUpperCase()}_REPOSITORY) private repo: I${e}Repository) {}
|
|
3410
3506
|
async execute(id: string) { return this.repo.delete(id) }
|
|
3411
3507
|
}
|
|
3412
|
-
`}]}async function
|
|
3508
|
+
`}]}async function $r(e){let{name:t,moduleName:n,modulesDir:r}=e,i=e.pluralize??!0,a=R(t),o=I(t),s=[],c;if(e.outDir)c=v(e.outDir);else if(n){let e=R(n),t=i?z(e):e;c=v(h(r??`src/modules`,t,`__tests__`))}else c=v(`src/__tests__`);let l=h(c,`${a}.test.ts`);return await M(l,`import { describe, it, expect, beforeEach } from 'vitest'
|
|
3413
3509
|
import { Container } from '@forinda/kickjs'
|
|
3414
3510
|
|
|
3415
3511
|
describe('${o}', () => {
|
|
@@ -3432,9 +3528,9 @@ describe('${o}', () => {
|
|
|
3432
3528
|
expect(true).toBe(true)
|
|
3433
3529
|
})
|
|
3434
3530
|
})
|
|
3435
|
-
`),s.push(l),s}const
|
|
3436
|
-
`:t===`t`?` `:t===`r`?`\r`:t)}const
|
|
3437
|
-
`)}function
|
|
3531
|
+
`),s.push(l),s}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*createToken\s*(?:<[^>]*>)?\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g,oi=/createToken\s*(?:<[^>]*>)?\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g,si=/@Inject\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g,ci=/\b(defineAdapter|definePlugin)\s*(?:<[^>]*>)?\s*\(/g,li=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`),ui=/\bname\s*(?::\s*[^=]+)?=\s*['"`]([^'"`]+)['"`]/,di=/\bdefineAugmentation\s*\(\s*['"`]([^'"`]+)['"`]\s*(,\s*\{)?/g,fi=new RegExp(String.raw`@(${[`Get`,`Post`,`Put`,`Delete`,`Patch`].join(`|`)})\s*\(`,`g`);function pi(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 mi(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=pi(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 hi(e){return(e.match(/:([a-zA-Z_]\w*)/g)??[]).map(e=>e.slice(1))}function gi(e,t){let n=e.endsWith(`/`)?e.slice(0,-1):e;return!t||t===`/`?n||`/`:n+(t.startsWith(`/`)?t:`/`+t)||`/`}const _i=/\b(?:public\s+|private\s+|protected\s+)?routes\s*\([^)]*\)\s*(?::\s*[A-Za-z_][\w<>[\]\s,|]*\s*)?\{/g,vi=/\bpath\s*:\s*['"`]([^'"`]*)['"`]/g,yi=/\bcontroller\s*:\s*([A-Z]\w*)\b/g,bi=/\bimport\.meta\.glob\s*\(/g;function xi(e){let t=[];for(bi.lastIndex=0;bi.exec(e)!==null;){let n=bi.lastIndex-1,r=pi(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 Si(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 Ci(e,t){let n=e.startsWith(`./`)?e:`./`+e,r=!1;for(let e of t){let t=e.startsWith(`!`);Si(t?e.slice(1):e).test(n)&&(r=!t)}return r}function wi(e){let t=[];_i.lastIndex=0;let n;for(;(n=_i.exec(e))!==null;){let r=e.indexOf(`{`,n.index+n[0].length-1);if(r<0)continue;let i=Ii(e,r);if(i<0)continue;let a=e.slice(r+1,i),o=[];vi.lastIndex=0;let s;for(;(s=vi.exec(a))!==null;)o.push(s[1]??``);let c=[];yi.lastIndex=0;let l;for(;(l=yi.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 Ti(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 Ei(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 Di(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?Oi(n[1].trim(),t):null}return Oi(n[1].trim(),t)}function Oi(e,t){if(e.startsWith(`{`))return Ai(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 Ai(r[1])}return{filterable:[],sortable:[],searchable:[]}}function ki(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 Ai(e){return{filterable:ki(e,`filterable`),sortable:ki(e,`sortable`),searchable:ki(e,`searchable`)}}async function ji(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 ji(a,t)):o.isFile()&&n.some(e=>o.name.endsWith(e))&&i.push(a))}return i}function W(e,t){return _(t,e).split(y).join(`/`)}function Mi(e,t,n){let r=[],i=W(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})}return r}function Ni(e,t,n){let r=[],i=W(t,n),a=new Set;ai.lastIndex=0;let o;for(;(o=ai.exec(e))!==null;){let[e,n,s]=o;a.add(e),r.push({name:s,variable:n,filePath:t,relativePath:i})}for(oi.lastIndex=0;(o=oi.exec(e))!==null;)a.has(o[0])||r.push({name:o[1],variable:null,filePath:t,relativePath:i});return r}function Pi(e,t,n,r,i=new Map){let a=[];if(r.length===0)return a;let o=W(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);fi.lastIndex=0;let d;for(;(d=fi.exec(u))!==null;){let n=d[1],s=d.index,c=fi.lastIndex-1,l=pi(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=mi(u,l+1);if(!h)continue;let{methodName:g,endPos:_}=h;fi.lastIndex=_;let v=Di(u.slice(s,_),e),y=Ti(f,`body`),b=Ti(f,`query`),x=Ti(f,`params`),ee=i.get(r.className)??``,S=ee?gi(ee,m):m;a.push({controller:r.className,method:g,httpMethod:n.toUpperCase(),path:m,pathParams:hi(S),queryFilterable:v?.filterable??null,querySortable:v?.sortable??null,querySearchable:v?.searchable??null,bodySchema:y?{identifier:y,source:Ei(e,y)}:null,querySchema:b?{identifier:b,source:Ei(e,b)}:null,paramsSchema:x?{identifier:x,source:Ei(e,x)}:null,filePath:t,relativePath:o})}}return a}function Fi(e,t,n){let r=[],i=W(t,n);si.lastIndex=0;let a;for(;(a=si.exec(e))!==null;)r.push({name:a[1],filePath:t,relativePath:i});return r}function Ii(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 Li(e,t,n){let r=[],i=W(t,n),a=new Set;ci.lastIndex=0;let o;for(;(o=ci.exec(e))!==null;){let n=o[1],s=ci.lastIndex-1,c=pi(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}))}li.lastIndex=0;let s;for(;(s=li.exec(e))!==null;){let n=s.index,o=e.indexOf(`{`,n);if(o<0)continue;let c=Ii(e,o);if(c<0)continue;let l=e.slice(o+1,c),u=ui.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 Ri(e,t,n){let r=[],i=W(t,n);di.lastIndex=0;let a;for(;(a=di.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=Ii(e,t);if(n>=0){let r=e.slice(t+1,n);o=zi(r,`description`),s=zi(r,`example`)}}}r.push({name:n,description:o,example:s,filePath:t,relativePath:i})}return r}function zi(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`?`
|
|
3532
|
+
`:t===`t`?` `:t===`r`?`\r`:t)}const Bi=[`src/config/index.ts`,`src/config/env.ts`,`src/config.ts`,`src/env.ts`];async function Vi(e,t){let n=t===`src/env.ts`?Bi:[t];for(let t of n){let n=v(e,t),r;try{r=await C(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:W(n,e)}}return null}function Hi(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}async function Ui(e){let t=await ji(v(e.root),e),n=[],r=[],i=[],a=[],o=[],s=[],c=new Map;for(let r of t){let t;try{t=await C(r,`utf-8`)}catch{continue}c.set(r,t),n.push(...Mi(t,r,e.cwd)),i.push(...Ni(t,r,e.cwd)),a.push(...Fi(t,r,e.cwd)),o.push(...Li(t,r,e.cwd)),s.push(...Ri(t,r,e.cwd))}let l=new Map;for(let[,e]of c)for(let{controller:t,mountPath:n}of wi(e))l.has(t)||l.set(t,n);for(let[t,i]of c){let a=n.filter(e=>e.filePath===t);r.push(...Pi(i,t,e.cwd,a,l))}let u=[];for(let[e,t]of c){if(!/\.module\.[mc]?[tj]sx?$/.test(e))continue;let r=xi(t);if(r.length===0)continue;let i=e.replaceAll(y,`/`),a=i.slice(0,i.lastIndexOf(`/`));for(let t of n){if(t.decorator===`Module`)continue;let n=t.filePath.replaceAll(y,`/`);n.startsWith(a+`/`)&&n!==i&&(Ci(n.slice(a.length+1),r)||u.push({className:t.className,filePath:t.filePath,relativePath:t.relativePath,moduleFilePath:e,decorator:t.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));let d=Hi(n),f=await Vi(e.cwd,e.envFile??`src/env.ts`);return u.sort((e,t)=>e.relativePath.localeCompare(t.relativePath)||e.className.localeCompare(t.className)),{classes:n,routes:r,tokens:i,injects:a,collisions:d,env:f,pluginsAndAdapters:o,augmentations:s,orphanedClasses:u}}const G="/* 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",Wi=new Set([`Service`,`Repository`,`Injectable`,`Component`]);var Gi=class extends Error{collisions;constructor(e){super(Ki(e)),this.name=`TokenCollisionError`,this.collisions=e}};function Ki(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(`
|
|
3533
|
+
`)}function qi(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 Ji(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 Yi(e,t,n){let r=new Set,i=[];for(let a of e){if(!Wi.has(a.decorator))continue;let e=n.has(a.className)?Ji(a):a.className;if(r.has(e))continue;r.add(e);let o=qi(a.filePath,t),s=a.isDefault?`import('${o}').default`:`import('${o}').${a.className}`;i.push(` '${e}': ${s}`)}return`${G}
|
|
3438
3534
|
declare module '@forinda/kickjs' {
|
|
3439
3535
|
interface KickJsRegistry {
|
|
3440
3536
|
${i.length?i.join(`
|
|
@@ -3443,14 +3539,14 @@ ${i.length?i.join(`
|
|
|
3443
3539
|
}
|
|
3444
3540
|
|
|
3445
3541
|
export {}
|
|
3446
|
-
`}function
|
|
3542
|
+
`}function Xi(e,t,n){return t.length===0?`${G}
|
|
3447
3543
|
// ${n}
|
|
3448
3544
|
export type ${e} = never
|
|
3449
3545
|
`:`${G}
|
|
3450
3546
|
export type ${e} =
|
|
3451
3547
|
${[...new Set(t)].toSorted().map(e=>` | '${e}'`).join(`
|
|
3452
3548
|
`)}
|
|
3453
|
-
`}function
|
|
3549
|
+
`}function Zi(e,t){return`${G}
|
|
3454
3550
|
export type { ServiceToken } from './services'
|
|
3455
3551
|
export type { ModuleToken } from './modules'
|
|
3456
3552
|
|
|
@@ -3466,7 +3562,7 @@ import './plugins'
|
|
|
3466
3562
|
import './augmentations'
|
|
3467
3563
|
${t?`import './kick__assets'
|
|
3468
3564
|
`:``}${e?`import './kick__env'
|
|
3469
|
-
`:``}`}function
|
|
3565
|
+
`:``}`}function Qi(e){let t=new Map;for(let n of e)t.has(n.name)||t.set(n.name,n);return`${G}
|
|
3470
3566
|
declare module '@forinda/kickjs' {
|
|
3471
3567
|
/**
|
|
3472
3568
|
* Map of every plugin/adapter \`name\` discovered in the project. The
|
|
@@ -3481,7 +3577,7 @@ ${[...t.values()].toSorted((e,t)=>e.name.localeCompare(t.name)).map(e=>` '${e
|
|
|
3481
3577
|
}
|
|
3482
3578
|
|
|
3483
3579
|
export {}
|
|
3484
|
-
`}function
|
|
3580
|
+
`}function $i(e){if(e.length===0)return`${G}
|
|
3485
3581
|
// No augmentations discovered.
|
|
3486
3582
|
//
|
|
3487
3583
|
// Plugins advertise augmentable interfaces via:
|
|
@@ -3505,9 +3601,9 @@ export {}
|
|
|
3505
3601
|
${n.join(`
|
|
3506
3602
|
|
|
3507
3603
|
`)}
|
|
3508
|
-
`}async function
|
|
3604
|
+
`}async function ea(e){let{classes:t,routes:n=[],tokens:r=[],injects:i=[],collisions:a=[],env:o=null,pluginsAndAdapters:s=[],augmentations:c=[],assets:l={entries:[],count:0},outDir:u,allowDuplicates:d=!1,schemaValidator:p=!1}=e;if(a.length>0&&!d)throw new Gi(a);await oe(u,{recursive:!0});let m=h(u,`registry.d.ts`),g=h(u,`services.d.ts`),_=h(u,`modules.d.ts`),v=h(u,`plugins.d.ts`),y=h(u,`augmentations.d.ts`),b=h(u,`index.d.ts`),x=new Set(a.map(e=>e.className)),ee=Yi(t,m,x),S=t.filter(e=>Wi.has(e.decorator)).map(e=>x.has(e.className)?Ji(e):e.className),te=r.map(e=>e.name),ne=i.map(e=>e.name),re=[...S,...te,...ne],ie=t.filter(e=>e.decorator===`Module`).map(e=>e.className),ae=Xi(`ServiceToken`,re,"(no tokens discovered — declare with createToken<T>() or `kick g service <name>`)"),C=Xi(`ModuleToken`,ie,"(no @Module classes discovered — `kick g module <name>` to add one)"),se=Qi(s),ce=$i(c),le=Zi(o!==null,l.count>0);await w(m,ee,`utf-8`),await w(g,ae,`utf-8`),await w(_,C,`utf-8`),await w(v,se,`utf-8`),await w(y,ce,`utf-8`),await w(b,le,`utf-8`);let ue=[m,g,_,v,y,b];await w(h(f(u),`.gitignore`),`# Auto-generated by kick typegen
|
|
3509
3605
|
*
|
|
3510
|
-
`,`utf-8`);let T=new Set(s.map(e=>e.name)).size,E=new Set(c.map(e=>e.name)).size;return{registryEntries:S.length,serviceTokens:new Set(re).size,moduleTokens:ie.length,routeEntries:n.length,pluginEntries:T,augmentationEntries:E,assetEntries:l.count,envWritten:o!==null,written:ue,resolvedCollisions:a.length}}const
|
|
3606
|
+
`,`utf-8`);let T=new Set(s.map(e=>e.name)).size,E=new Set(c.map(e=>e.name)).size;return{registryEntries:S.length,serviceTokens:new Set(re).size,moduleTokens:ie.length,routeEntries:n.length,pluginEntries:T,augmentationEntries:E,assetEntries:l.count,envWritten:o!==null,written:ue,resolvedCollisions:a.length}}const ta=/^(kick\/)?([a-z][\w-]*\/[A-Z]\w*)(\/.+)?(:[a-z][\w-]+(:[a-z][\w-]+)*)?$/;function na(e){let t=[];for(let n of e){let e=n.name;e.startsWith(`kickjs.`)||ta.test(e)||t.push({token:e,variable:n.variable,filePath:n.relativePath,reason:"does not match `<scope>/<PascalKey>[/<suffix>][:<instance>]`",suggestion:ra(e)})}return t}function ra(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 ia(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(!la(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 aa(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}
|
|
3511
3607
|
declare module '@forinda/kickjs' {
|
|
3512
3608
|
/**
|
|
3513
3609
|
* Map of every typed asset discovered in the project's assetMap.
|
|
@@ -3518,7 +3614,7 @@ declare module '@forinda/kickjs' {
|
|
|
3518
3614
|
}
|
|
3519
3615
|
|
|
3520
3616
|
export {}
|
|
3521
|
-
`;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===
|
|
3617
|
+
`;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===oa){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]=oa)}return`${t}
|
|
3522
3618
|
declare module '@forinda/kickjs' {
|
|
3523
3619
|
/**
|
|
3524
3620
|
* Map of every typed asset discovered in the project's assetMap.
|
|
@@ -3527,30 +3623,30 @@ declare module '@forinda/kickjs' {
|
|
|
3527
3623
|
* prod → dist).
|
|
3528
3624
|
*/
|
|
3529
3625
|
interface KickAssets {
|
|
3530
|
-
${
|
|
3626
|
+
${sa(n,` `)}
|
|
3531
3627
|
}
|
|
3532
3628
|
}
|
|
3533
3629
|
|
|
3534
3630
|
export {}
|
|
3535
|
-
`}const
|
|
3536
|
-
`)}function
|
|
3631
|
+
`}const oa=Symbol(`asset-leaf`);function sa(e,t){let n=Object.keys(e).toSorted(),r=[];for(let i of n){let n=e[i],a=ca(i)?i:JSON.stringify(i);n===oa?r.push(`${t}${a}: () => string`):(r.push(`${t}${a}: {`),r.push(sa(n,`${t} `)),r.push(`${t}}`))}return r.join(`
|
|
3632
|
+
`)}function ca(e){return/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(e)}function la(e){try{return c(e).isDirectory()}catch{return!1}}var ua=D({runTypegen:()=>K,sweepStaleTypegen:()=>ma,watchTypegen:()=>fa});function da(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 K(e={}){let{cwd:t,srcDir:n,outDir:r,silent:i,allowDuplicates:a,schemaValidator:o,envFile:s}=da(e),c=Date.now(),l=await Ui({root:n,cwd:t,envFile:s===!1?void 0:s}),u=ia(e.assetMap,t),d=await ea({classes:l.classes,routes:l.routes,tokens:l.tokens,injects:l.injects,collisions:l.collisions,env:s===!1?null:l.env,pluginsAndAdapters:l.pluginsAndAdapters,augmentations:l.augmentations,assets:u,outDir:r,allowDuplicates:a,schemaValidator:o}),f=[];if(e.runPlugins!==!1)try{let{runAllPluginTypegens:e}=await Promise.resolve().then(()=>Ta),{loadKickConfig:n}=await Promise.resolve().then(()=>Me);f=await e({cwd:t,config:await n(t),silent:!0})}catch(e){if(!i){let t=e instanceof Error?e.message:String(e);console.warn(` kick typegen: plugin pipeline failed (${t}) — continuing`)}}e.runPlugins!==!1&&await ma(r,d.written,f,i);let p=na(l.tokens),m=Date.now()-c;if(!i){let e=r.replace(t+`/`,``),n=d.resolvedCollisions>0?`, ${d.resolvedCollisions} collisions namespaced`:``,i=d.envWritten?`, env typed`:``,a=d.pluginEntries>0?`, ${d.pluginEntries} plugins/adapters`:``,o=d.augmentationEntries>0?`, ${d.augmentationEntries} augmentations`:``,s=d.assetEntries>0?`, ${d.assetEntries} assets`:``;if(console.log(` kick typegen → ${d.serviceTokens} services, ${d.routeEntries} routes, ${d.moduleTokens} modules${a}${o}${s}${i}${n} → ${e} (${m}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}`)}}if(l.orphanedClasses.length>0){console.warn(` kick typegen: ${l.orphanedClasses.length} decorated class(es) not matched by any module's import.meta.glob():`);for(let e of l.orphanedClasses)console.warn(` @${e.decorator} ${e.className} (${e.relativePath})`),console.warn(` → not picked up by any glob in ${e.moduleFilePath}`)}}return{scan:l,result:d,tokenWarnings:p}}async function fa(e={}){let t=da(e),{srcDir:n,silent:r,cwd:i}=t,a={...t,allowDuplicates:!0,runPlugins:!1},o=process.env.KICKJS_WATCH_POLLING===`1`||process.env.KICKJS_WATCH_POLLING===`true`,[{runAllPluginTypegens:s},{loadKickConfig:c}]=await Promise.all([Promise.resolve().then(()=>Ta),Promise.resolve().then(()=>Me)]),l=await c(i),u=[],d=async()=>{try{u=(await K({...a})).result.written}catch(e){if(r)return;if(e instanceof Gi)console.error(`
|
|
3537
3633
|
`+e.message+`
|
|
3538
|
-
`);else{let t=e instanceof Error?e.message:String(e);console.error(` kick typegen failed: ${t}`)}}},f=async()=>{try{let e=await s({cwd:i,config:l,silent:!0});await
|
|
3634
|
+
`);else{let t=e instanceof Error?e.message:String(e);console.error(` kick typegen failed: ${t}`)}}},f=async()=>{try{let e=await s({cwd:i,config:l,silent:!0});await ma(t.outDir,u,e,!0)}catch{}};await d(),await f();let{watch:p}=await import(`node:fs`),m=null,h=e=>{e&&/\.(ts|tsx|mts|cts)$/.test(e)&&(e.includes(`.kickjs`)||e.endsWith(`.d.ts`)||(m&&clearTimeout(m),m=setTimeout(()=>{d().then(f)},100)))};if(o){r||console.log(` kick typegen: polling mode (KICKJS_WATCH_POLLING)`);let e=setInterval(()=>{pa({...a,silent:!0},!0)},2e3);return()=>clearInterval(e)}let g;try{g=p(n,{recursive:!0},(e,t)=>{h(t)})}catch(e){r||console.warn(` kick typegen: watch mode unavailable (${e?.message??e}). Falling back to polling.`);let t=setInterval(()=>{pa({...a,silent:!0},!0)},2e3);return()=>clearInterval(t)}return()=>{m&&clearTimeout(m),g.close()}}async function pa(e,t){try{await K(e)}catch(e){if(t)return;if(e instanceof Gi)console.error(`
|
|
3539
3635
|
`+e.message+`
|
|
3540
|
-
`);else{let t=e instanceof Error?e.message:String(e);console.error(` kick typegen failed: ${t}`)}}}async function
|
|
3541
|
-
(dry run — no files were written)`),console.log()}async function
|
|
3636
|
+
`);else{let t=e instanceof Error?e.message:String(e);console.error(` kick typegen failed: ${t}`)}}}async function ma(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 se(e)}catch{return[]}let o=[];for(let t of a){if(i.has(t))continue;let n=v(e,t);try{if(!(await le(n)).isFile())continue;await ue(n),o.push(t)}catch{}}return o.length>0&&!r&&console.log(` kick typegen: swept ${o.length} stale file(s): ${o.join(`, `)}`),o}const ha=[`agents`,`claude`,`skills`,`gemini`,`copilot`,`both`,`all`];function q(e){return e.parent?.opts()?.dryRun??!1}function J(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(`
|
|
3637
|
+
(dry run — no files were written)`),console.log()}async function ga(e){if(!e)try{let e=await k(process.cwd());await K({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 _a=[{name:`module <name>`,description:`Full DDD module (controller, DTOs, use-cases, 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:`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`}];async function va(){console.log(`
|
|
3542
3638
|
Built-in generators:
|
|
3543
|
-
`);let e=Math.max(...
|
|
3639
|
+
`);let e=Math.max(..._a.map(e=>e.name.length));for(let t of _a)console.log(` kick g ${t.name.padEnd(e+2)} ${t.description}`);let t=await k(process.cwd()),n=He(t?.plugins??[],t?.commands??[]),r=await dn(process.cwd(),n.generators);if(r.generators.length>0){console.log(`
|
|
3544
3640
|
Plugin generators:
|
|
3545
3641
|
`);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(`
|
|
3546
3642
|
Failed to load:
|
|
3547
|
-
`);for(let{source:e,reason:t}of r.failed)console.log(` ${e} — ${t}`)}console.log()}async function
|
|
3548
|
-
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=q(n);j(r);let i=await k(process.cwd()),a=O(i),o=a.dir??`src/modules`;J(await
|
|
3549
|
-
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=q(n);j(r);let i=await k(process.cwd()),a=O(i),o=a.dir??`src/modules`;J(await
|
|
3550
|
-
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=q(n);j(r);let i=await k(process.cwd()),a=O(i),o=a.dir??`src/modules`;J(await
|
|
3551
|
-
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=q(n);j(r);let i=await k(process.cwd()),a=O(i),o=a.dir??`src/modules`;J(await
|
|
3552
|
-
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=q(n);j(r);let i=await k(process.cwd()),a=O(i),o=a.dir??`src/modules`;J(await
|
|
3553
|
-
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=q(n);j(r);let i=O(await k(process.cwd())),a=i.dir??`src/modules`;J(await
|
|
3643
|
+
`);for(let{source:e,reason:t}of r.failed)console.log(` ${e} — ${t}`)}console.log()}async function ya(e,t,n){let r=await k(process.cwd()),i=O(r),a=t.modulesDir??i.dir??`src/modules`,o=t.repo??Zn(i.repo),s=t.pattern??r?.pattern??`ddd`,c=t.pluralize===!1?!1:i.pluralize??!0,l=Ie(r,process.cwd()),u=i.style??`define`;if(!n&&u===`define`){let e=await Ir(v(a),`define`);if(e.length>0){console.error(`\n ${E.red(`Error:`)} ${e.length} module file(s) still use the legacy \`class … implements AppModule\` shape.\n ${E.dim(`Project setting:`)} modules.style: 'define' (default)\n\n ${E.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 ${E.bold(`Pick one:`)}\n 1. Migrate everything to defineModule:\n ${E.dim(`$`)} kick codemod modules --experimental --apply\n 2. Keep the class form — pin it in kick.config.ts:\n ${E.dim(`// kick.config.ts`)}\n ${E.dim(`export default defineConfig({ modules: { style: 'class' } })`)}\n`),process.exit(1)}}let d=[];for(let r of e){let e=await Qn({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)}J(d,n),await ga(n)}function ba(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 implementation: inmemory | drizzle | prisma`).option(`--pattern <pattern>`,`Override project pattern: rest | ddd | cqrs | 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 va();return}if(!e||e.length===0){n.help();return}let a=q(i);j(a);let[o,s,...c]=e;if(o){let e=await k(process.cwd()),n=He(e?.plugins??[],e?.commands??[]),i=await un({generatorName:o,itemName:s??``,args:c,flags:r,cwd:process.cwd(),projectRoot:t?.projectRoot},n.generators);if(i){J(i.files,a);return}}await ya(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 implementation: inmemory | drizzle | prisma`).option(`--pattern <pattern>`,`Override project pattern: rest | ddd | cqrs | 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=q(n);j(r),await ya(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=q(n);j(r),J(await or({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=q(n);j(r),J(await sr({name:e,outDir:v(t.out)}),r)}),n.command(`middleware <name>`).description(`Generate an Express middleware function
|
|
3644
|
+
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=q(n);j(r);let i=await k(process.cwd()),a=O(i),o=a.dir??`src/modules`;J(await fr({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.)
|
|
3645
|
+
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=q(n);j(r);let i=await k(process.cwd()),a=O(i),o=a.dir??`src/modules`;J(await pr({name:e,outDir:t.out,moduleName:t.module,modulesDir:o,pattern:i?.pattern,pluralize:a.pluralize??!0}),r)}),n.command(`service <name>`).description(`Generate a @Service() class
|
|
3646
|
+
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=q(n);j(r);let i=await k(process.cwd()),a=O(i),o=a.dir??`src/modules`;J(await mr({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
|
|
3647
|
+
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=q(n);j(r);let i=await k(process.cwd()),a=O(i),o=a.dir??`src/modules`;J(await hr({name:e,outDir:t.out,moduleName:t.module,modulesDir:o,pattern:i?.pattern,pluralize:a.pluralize??!0}),r),await ga(r)}),n.command(`dto <name>`).description(`Generate a Zod DTO schema
|
|
3648
|
+
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=q(n);j(r);let i=await k(process.cwd()),a=O(i),o=a.dir??`src/modules`;J(await gr({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
|
|
3649
|
+
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=q(n);j(r);let i=O(await k(process.cwd())),a=i.dir??`src/modules`;J(await $r({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=q(n);j(r),J(await Lr({name:e,outDir:v(t.out),queue:t.queue}),r)}),n.command(`scaffold <name> [fields...]`).description(`Generate a full CRUD module from field definitions
|
|
3554
3650
|
Example: kick g scaffold Post title:string body:text:optional published:boolean:optional
|
|
3555
3651
|
Types: string, text, number, int, float, boolean, date, email, url, uuid, json, enum:a,b,c
|
|
3556
3652
|
Optional: append :optional (shell-safe): description:text:optional
|
|
@@ -3559,11 +3655,11 @@ export {}
|
|
|
3559
3655
|
Usage: kick g scaffold <name> <field:type> [field:type...]
|
|
3560
3656
|
Example: kick g scaffold Post title:string body:text:optional published:boolean:optional
|
|
3561
3657
|
Optional: append :optional (shell-safe, no quoting needed)
|
|
3562
|
-
`),process.exit(1));let a=await k(process.cwd()),o=O(a),s=n.modulesDir??o.dir??`src/modules`,c=
|
|
3563
|
-
`,d=``;if(r(c)&&(d=await C(c,`utf8`)),d===l){o.push({id:n.id,status:`unchanged`,outFile:c});continue}if(e.check)throw Error(`kick typegen --check: drift detected for ${n.id} (${c})`);await w(c,l,`utf8`),o.push({id:n.id,status:`written`,outFile:c})}return o}function
|
|
3564
|
-
`,`utf-8`),s(` ✓ wrote manifest → ${_(n,p)} (${Object.keys(d).length} entries)`),{manifestPath:p,entries:u,manifest:f}}async function
|
|
3658
|
+
`),process.exit(1));let a=await k(process.cwd()),o=O(a),s=n.modulesDir??o.dir??`src/modules`,c=zr(t),l=Ie(a,process.cwd()),u=a?.pattern??`ddd`;u!==`ddd`&&(console.error(`\n Error: 'kick g scaffold' currently only supports the DDD pattern.\n Detected project pattern: '${u}'.\n Workarounds:\n - Run 'kick g module ${e}' for the ${u} layout (no fields), then add fields manually.\n - Override the pattern for this scaffold by setting kick.config.ts pattern: 'ddd'.\n`),process.exit(1));let d=await Br({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)`:``}`);J(d,i),await ga(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>`,`Default repository type: inmemory | drizzle | prisma`,`inmemory`).option(`-f, --force`,`Overwrite existing kick.config.ts without prompting`).action(async(e,t)=>{let n=q(t);j(n),J(await _r({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 | ddd | cqrs | minimal`).option(`-f, --force`,`Overwrite existing files without prompting`).action(async(e,t)=>{let n=q(t);j(n);let r=e.only??`all`;if(!ha.includes(r)){console.error(` Invalid --only value: ${r}. Expected: ${ha.join(` | `)}`),process.exitCode=1;return}J(await wr({outDir:v(`.`),only:r,name:e.name,pm:e.pm,template:e.template,force:e.force}),n)});for(let e of t?.generators??[])xa(n,e,t?.projectRoot)}function xa(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=q(o);j(s);let c=await un({generatorName:i.name,itemName:e??``,args:r??[],flags:a,cwd:process.cwd(),projectRoot:n},[t]);c&&J(c.files,s)})}async function Sa(e){let t=u.resolve(e.cwd,`.kickjs/types`);await oe(t,{recursive:!0});let n=new Map,i=e.scan??Ui,a={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 oe(u.dirname(r),{recursive:!0}),await w(r,n,`utf8`)},getScanResult:e=>{let t=Ca(e),r=n.get(t);return r||(r=i(e),n.set(t,r)),r},log:console},o=[];for(let n of e.plugins){let i=await n.generate(a);if(i===null){o.push({id:n.id,status:`skipped`});continue}let s=n.outExtension??`.d.ts`,c=u.join(t,`${n.id.replace(/\//g,`__`)}${s}`),l=`/* AUTO-GENERATED by kick typegen — do not edit. Plugin: ${n.id} */\n\n`+i+`
|
|
3659
|
+
`,d=``;if(r(c)&&(d=await C(c,`utf8`)),d===l){o.push({id:n.id,status:`unchanged`,outFile:c});continue}if(e.check)throw Error(`kick typegen --check: drift detected for ${n.id} (${c})`);await w(c,l,`utf8`),o.push({id:n.id,status:`written`,outFile:c})}return o}function Ca(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 wa(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 Ta=D({applyDisableFilter:()=>wa,runAllPluginTypegens:()=>Ea});async function Ea(e){let{enabled:t,skipped:n,unknown:r}=wa(He([...js,...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 Sa({cwd:e.cwd,config:e.config??{},plugins:t,check:e.check});if(!e.silent)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[]}}async function Da(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 Oa(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)+`
|
|
3660
|
+
`,`utf-8`),s(` ✓ wrote manifest → ${_(n,p)} (${Object.keys(d).length} entries)`),{manifestPath:p,entries:u,manifest:f}}async function Oa(e,t,a,o){let s=v(a,t.src),c=t.dest?v(a,t.dest):h(o,e);if(Aa(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)||!ja(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`});for(let{rel:e,key:t}of d){let r=h(s,e),a=h(c,e);i(f(a),{recursive:!0}),n(r,a),u[t]=ka(o,a)}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:l.length},manifestSlice:u}}function ka(e,t){return _(e,t).split(/[\\/]/).filter(Boolean).join(`/`)}function Aa(e,t){let n=_(t,e);return n===``?!1:n.startsWith(`..`)||m(n)}function ja(e){try{return c(e).isDirectory()}catch{return!1}}function Ma(e){if(typeof e==`boolean`)return e;let t=process.env.KICKJS_WATCH_POLLING;return t===`1`||t===`true`}async function Na(e,t,n={}){t&&(process.env.PORT=t);let r=Ma(n.polling),i=process.cwd(),a=await k(i),o=a?.typegen?.schemaValidator??`zod`,s=a?.typegen?.envFile;try{await K({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})`)}await Ea({cwd:i,config:a});let{createRequire:c}=await import(`node:module`),{createServer:l}=await import(x(c(v(`package.json`)).resolve(`vite`)).href),u=await l({configFile:v(`vite.config.ts`),server:{port:t?parseInt(t,10):void 0,...r?{watch:{usePolling:!0,interval:100}}:{}}}),d=a?.assetMap?Object.values(a.assetMap).map(e=>e?.src).filter(e=>typeof e==`string`&&e.length>0).map(e=>v(i,e)):[],f=e=>d.some(t=>e===t||e.startsWith(`${t}/`)),p=null,m=e=>{if(e.includes(`.kickjs`)||e.endsWith(`.d.ts`))return;let t=/\.(ts|tsx|mts|cts)$/.test(e),n=f(e);!t&&!n||(p&&clearTimeout(p),p=setTimeout(()=>{K({cwd:i,silent:!0,allowDuplicates:!0,schemaValidator:o,envFile:s,srcDir:a?.typegen?.srcDir,outDir:a?.typegen?.outDir,assetMap:a?.assetMap,runPlugins:!1}).catch(()=>{}),Ea({cwd:i,config:a,silent:!0}).catch(()=>{})},100))};u.watcher.on(`add`,m),u.watcher.on(`unlink`,m),u.watcher.on(`change`,m),d.length>0&&u.watcher.add(d),await u.listen(),u.printUrls(),console.log(`
|
|
3565
3661
|
KickJS dev server running (Vite + @forinda/kickjs-vite)
|
|
3566
|
-
`);let h=async()=>{p&&clearTimeout(p),await u.close(),process.exit(0)};process.on(`SIGINT`,h),process.on(`SIGTERM`,h)}function
|
|
3662
|
+
`);let h=async()=>{p&&clearTimeout(p),await u.close(),process.exit(0)};process.on(`SIGINT`,h),process.on(`SIGTERM`,h)}function Pa(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)`).action(async e=>{try{await Na(e.entry,e.port,{polling:e.polling})}catch(e){e.code===`ERR_MODULE_NOT_FOUND`&&e.message?.includes(`vite`)?console.error(`
|
|
3567
3663
|
Error: vite is not installed.
|
|
3568
3664
|
Run: pnpm add -D vite unplugin-swc
|
|
3569
3665
|
`):console.error(`
|
|
@@ -3571,13 +3667,13 @@ export {}
|
|
|
3571
3667
|
Building for production...
|
|
3572
3668
|
`);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 k(process.cwd()),o=a?.copyDirs??[];if(o.length>0){console.log(`
|
|
3573
3669
|
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(`
|
|
3574
|
-
Building asset map...`);try{await
|
|
3670
|
+
Building asset map...`);try{await Da(a,{cwd:process.cwd()})}catch(e){console.error(` ✗ asset build failed: ${e instanceof Error?e.message:String(e)}`),process.exit(1)}}console.log(`
|
|
3575
3671
|
Build complete.
|
|
3576
3672
|
`)}),e.command(`build:assets`).description(`Rebuild the .kickjs-assets.json manifest under the configured outDir (no JS rebuild)`).action(async()=>{let e=await k(process.cwd());if(!e?.assetMap||Object.keys(e.assetMap).length===0){console.log(` No assetMap entries — nothing to build.`);return}console.log(`
|
|
3577
|
-
Building asset map...`);try{await
|
|
3673
|
+
Building asset map...`);try{await Da(e,{cwd:process.cwd()}),console.log(`
|
|
3578
3674
|
Asset build complete.
|
|
3579
|
-
`)}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)),ke(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
|
|
3580
|
-
Dev server (debug) failed:`,e.message??e),process.exit(1)}})}function
|
|
3675
|
+
`)}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)),ke(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 Na(e.entry,e.port)}catch(e){console.error(`
|
|
3676
|
+
Dev server (debug) failed:`,e.message??e),process.exit(1)}})}function Fa(e){e.command(`info`).description(`Print system and framework info`).action(()=>{console.log(`
|
|
3581
3677
|
KickJS CLI
|
|
3582
3678
|
|
|
3583
3679
|
System:
|
|
@@ -3588,7 +3684,7 @@ export {}
|
|
|
3588
3684
|
@forinda/kickjs workspace
|
|
3589
3685
|
@forinda/kickjs-vite workspace
|
|
3590
3686
|
@forinda/kickjs-cli workspace
|
|
3591
|
-
`)})}const{bold:Y,dim:X,green:
|
|
3687
|
+
`)})}const{bold:Y,dim:X,green:Ia,red:La,yellow:Ra,blue:za}=E;function Ba(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 Va(e){let t=await fetch(e,{signal:AbortSignal.timeout(5e3)});if(!t.ok)throw Error(`${t.status} ${t.statusText}`);return t.json()}async function Ha(e,t){try{return await Va(`${e}${t}`)}catch{return null}}async function Ua(e){let[t,n,r,i,a]=await Promise.all([Ha(e,`/health`),Ha(e,`/metrics`),Ha(e,`/routes`),Ha(e,`/container`),Ha(e,`/ws`)]);return{health:t,metrics:n,routes:r,container:i,ws:a}}function Wa(e,t){let{health:n,metrics:r,routes:i,container:a,ws:o}=t,s=X(`─`.repeat(60));if(console.log(),console.log(Y(` KickJS Inspector`)+X(` → ${e}`)),console.log(s),n){let e=n.status===`healthy`?Ia(`● healthy`):La(`● `+n.status);console.log(` ${Y(`Health:`)} ${e}`)}else console.log(` ${Y(`Health:`)} ${La(`● unreachable`)}`);if(r){let e=((r.errorRate??0)*100).toFixed(1),t=r.errorRate>.1?La:r.errorRate>0?Ra:Ia;console.log(` ${Y(`Uptime:`)} ${Ba(r.uptimeSeconds)}`),console.log(` ${Y(`Requests:`)} ${r.requests}`),console.log(` ${Y(`Errors:`)} ${r.serverErrors} server, ${r.clientErrors??0} client ${X(`(`)}${t(e+`%`)}${X(`)`)}`)}if(a&&console.log(` ${Y(`DI:`)} ${a.count} bindings`),o&&o.enabled&&console.log(` ${Y(`WS:`)} ${o.connections??0} connections, ${o.namespaces??0} namespaces`),i?.routes?.length){console.log(),console.log(Y(` Routes`)),console.log(s),console.log(` ${X(`METHOD`)} ${X(`PATH`.padEnd(36))} ${X(`CONTROLLER`)}`);for(let e of i.routes){let t=e.path.length>36?e.path.slice(0,33)+`...`:e.path.padEnd(36);console.log(` ${jt(e.method)} ${t} ${za(e.controller)}.${X(e.handler)}`)}}console.log(s),console.log()}function Ga(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 Ua(r);t.json?console.log(JSON.stringify(e,null,2)):Wa(n,e)}catch(e){t.json?console.log(JSON.stringify({error:String(e)})):(console.error(La(` ✖ Could not connect to ${n}`)),console.error(X(` ${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 Ka(e,t){let n=e.toLowerCase();return t.every(e=>n.includes(e.toLowerCase()))}function Z(e,t){let n=e.toLowerCase();return t.some(e=>n.includes(e.toLowerCase()))}const qa=[{match(e,t){let n=Ka(e,[`config`,`get`])&&Z(e,[`undefined`,`null`]),r=e.includes(`@Value`)&&Z(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
|
|
3592
3688
|
registers the env schema with kickjs at module-load time. Without it,
|
|
3593
3689
|
ConfigService falls back to the base schema (PORT/NODE_ENV/LOG_LEVEL only)
|
|
3594
3690
|
and every user-defined key reads as undefined. @Value() may *appear* to
|
|
@@ -3610,7 +3706,7 @@ describe('UserController', () => {
|
|
|
3610
3706
|
beforeEach(() => Container.reset())
|
|
3611
3707
|
|
|
3612
3708
|
it('does the thing', async () => { /* ... */ })
|
|
3613
|
-
})`,docs:`https://forinda.github.io/kick-js/guide/testing.html`}}:null}},{match(e,t){return e.includes(`@Module`)||
|
|
3709
|
+
})`,docs:`https://forinda.github.io/kick-js/guide/testing.html`}}:null}},{match(e,t){return e.includes(`@Module`)||Ka(e,[`Module`,`is not a function`])||Ka(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
|
|
3614
3710
|
pattern instead: a class implements AppModule and exposes routes() that
|
|
3615
3711
|
returns the controller wiring. This was a deliberate choice — modules
|
|
3616
3712
|
become explicit values rather than metadata, which makes them easier to
|
|
@@ -3662,24 +3758,24 @@ drop the entry.`,fix:`Open src/modules/index.ts and verify the module is in the
|
|
|
3662
3758
|
import { UserModule } from './users/user.module'
|
|
3663
3759
|
import { TaskModule } from './tasks/task.module' // ← was this missing?
|
|
3664
3760
|
|
|
3665
|
-
export const modules: AppModuleEntry[] = [UserModule(), TaskModule()]`,docs:`https://forinda.github.io/kick-js/guide/project-structure.html`}}:null}}];function
|
|
3761
|
+
export const modules: AppModuleEntry[] = [UserModule(), TaskModule()]`,docs:`https://forinda.github.io/kick-js/guide/project-structure.html`}}:null}}];function Ja(e,t){let n=null;for(let r of qa){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 Ya(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.
|
|
3666
3762
|
export OPENAI_API_KEY="sk-..."
|
|
3667
3763
|
|
|
3668
3764
|
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:
|
|
3669
3765
|
kick add ai
|
|
3670
3766
|
|
|
3671
3767
|
Or manually:
|
|
3672
|
-
pnpm add @forinda/kickjs-ai`}}let{OpenAIProvider:i}=r,a=new i({apiKey:n,defaultChatModel:e.model??`gpt-4o-mini`}),o=
|
|
3673
|
-
`)}function
|
|
3768
|
+
pnpm add @forinda/kickjs-ai`}}let{OpenAIProvider:i}=r,a=new i({apiKey:n,defaultChatModel:e.model??`gpt-4o-mini`}),o=Xa(e.cwd),s=`Error or stack trace:\n\n${e.input.trim()}`;try{let e=Za((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 Xa(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(`
|
|
3769
|
+
`)}function Za(e){let t=[e,Qa(e),$a(e)].filter(e=>e!==null);for(let e of t)try{let t=JSON.parse(e);if(eo(t))return t}catch{continue}return null}function Qa(e){let t=e.match(/```(?:json)?\s*\n([\s\S]*?)```/);return t?t[1]?.trim()??null:null}function $a(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 eo(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 to(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 io(e,t.message);(!n||n.trim().length===0)&&(process.stderr.write(`Error: no input provided.
|
|
3674
3770
|
|
|
3675
3771
|
Pass a message as a positional arg, --message flag, or pipe via stdin:
|
|
3676
3772
|
kick explain "config.get returned undefined"
|
|
3677
3773
|
pnpm test 2>&1 | kick explain
|
|
3678
|
-
`),process.exit(1));let r=
|
|
3679
|
-
`);return}if(i){
|
|
3680
|
-
`),process.exit(2)),
|
|
3681
|
-
`),process.exit(a.kind===`ok`?0:2)),
|
|
3682
|
-
`)}function
|
|
3774
|
+
`),process.exit(1));let r=oo(),i=Ja(n,r);if(t.json&&i){process.stdout.write(JSON.stringify({matched:!0,...i},null,2)+`
|
|
3775
|
+
`);return}if(i){so(n,i.diagnosis,i.confidence);return}t.ai||(t.json&&(process.stdout.write(JSON.stringify({matched:!1},null,2)+`
|
|
3776
|
+
`),process.exit(2)),co(n,!1),process.exit(2));let a=await Ya({input:n,model:t.model,cwd:r.cwd});t.json&&(process.stdout.write(JSON.stringify(no(a),null,2)+`
|
|
3777
|
+
`),process.exit(a.kind===`ok`?0:2)),ro(n,a),process.exit(a.kind===`ok`?0:2)})}function no(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 ro(e,t){if(t.kind===`ok`){so(e,t.diagnosis,-1,!0);return}if(t.kind===`unavailable`){process.stdout.write(`\n Explaining: ${uo(e.trim(),200)}\n\n`),process.stdout.write(` AI fallback unavailable: ${t.reason}\n\n`),process.stdout.write(`${lo(t.suggestion,` `)}\n\n`);return}process.stdout.write(`\n Explaining: ${uo(e.trim(),200)}\n\n`),process.stdout.write(` AI fallback error: ${t.message}\n\n`)}async function io(e,t){return e&&e.trim().length>0?e:t&&t.trim().length>0?t:process.stdin.isTTY?``:ao()}function ao(){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 oo(){let e=process.cwd();return{cwd:e,hasFile:t=>r(v(e,t))}}function so(e,t,n,r=!1){let i=uo(e.trim(),200),a=r?`AI-generated — verify before applying`:fo(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${lo(t.explanation,` `)}\n`),process.stdout.write(`\n Fix:\n${lo(t.fix,` `)}\n`),t.codeBefore&&process.stdout.write(`\n Before:\n${lo(t.codeBefore,` `)}\n`),t.codeAfter&&process.stdout.write(`\n After:\n${lo(t.codeAfter,` `)}\n`),t.docs&&process.stdout.write(`\n Docs: ${t.docs}\n`),process.stdout.write(`
|
|
3778
|
+
`)}function co(e,t){let n=uo(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.
|
|
3683
3779
|
When @forinda/kickjs-ai ships its provider implementations,
|
|
3684
3780
|
this command will call the configured LLM with the error +
|
|
3685
3781
|
project context and return a structured fix.
|
|
@@ -3696,12 +3792,12 @@ Pass a message as a positional arg, --message flag, or pipe via stdin:
|
|
|
3696
3792
|
3. File an issue with the error text:
|
|
3697
3793
|
https://github.com/forinda/kick-js/issues/new
|
|
3698
3794
|
|
|
3699
|
-
`)}function
|
|
3795
|
+
`)}function lo(e,t){return e.split(`
|
|
3700
3796
|
`).map(e=>`${t}${e}`).join(`
|
|
3701
|
-
`)}function
|
|
3702
|
-
`,`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
|
|
3797
|
+
`)}function uo(e,t){return e.length<=t?e:e.slice(0,t-1)+`…`}function fo(e){return e>=90?`high confidence`:e>=70?`good match`:e>=50?`medium confidence`:`low confidence — verify manually`}function po(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(mo),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(ho)}function mo(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=ne(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 ho(e){let t=process.cwd(),n=go(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)+`
|
|
3798
|
+
`,`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 go(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 _o(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=yo(t,`tsx`);i||(console.error(`
|
|
3703
3799
|
Error: tsx not found. Install it: pnpm add -D tsx
|
|
3704
|
-
`),process.exit(1));let a=
|
|
3800
|
+
`),process.exit(1));let a=vo(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=te(o,[],{cwd:t,execPath:i,stdio:`inherit`});await new Promise(t=>{e.on(`exit`,()=>t())})}finally{try{c(o)}catch{}}})}function vo(e,t){return`
|
|
3705
3801
|
import 'reflect-metadata'
|
|
3706
3802
|
|
|
3707
3803
|
// Prevent bootstrap() from starting the HTTP server
|
|
@@ -3755,40 +3851,40 @@ server.on('exit', () => {
|
|
|
3755
3851
|
console.log('\\n Goodbye!\\n')
|
|
3756
3852
|
process.exit(0)
|
|
3757
3853
|
})
|
|
3758
|
-
`}function
|
|
3854
|
+
`}function yo(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 bo(e,t){let n=RegExp(`^\\s*${B(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]!==`
|
|
3759
3855
|
`;)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]===`
|
|
3760
|
-
`);)t--;a=a.slice(0,t)+a.slice(s+1),r=!0,i=t;continue}i=s+1}return{content:a,changed:r}}function
|
|
3856
|
+
`);)t--;a=a.slice(0,t)+a.slice(s+1),r=!0,i=t;continue}i=s+1}return{content:a,changed:r}}function xo(e,t){let n=tr(e);if(!n)return e;let r=n.rhsStart,i=n.rhsEnd+1,a=e.slice(r,i);return a=bo(a,t).content,a=a.replace(RegExp(`\\s*,?\\s*${B(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 So(e){let{name:t,modulesDir:n,force:r}=e,i=e.pluralize!==!1,a=R(t),o=I(t),s=i?z(a):a,c=h(n,s);if(!await Ze(c)){console.log(`\n Module not found: ${c}\n`);return}if(!r&&!await P({message:E.red(`Delete module '${s}' at ${c}? This cannot be undone.`),initialValue:!1})){console.log(`
|
|
3761
3857
|
Cancelled.
|
|
3762
|
-
`);return}await ce(c,{recursive:!0,force:!0}),console.log(` Deleted: ${c}`);let l=h(n,`index.ts`);if(await Ze(l)){let e=await C(l,`utf-8`),t=e,n=RegExp(`^import\\s*\\{\\s*${B(o)}Module\\s*\\}\\s*from\\s*['"][^'"]*${B(s)}(?:/[^'"]*)?['"].*\\n?`,`gm`);e=e.replace(n,``),e=
|
|
3858
|
+
`);return}await ce(c,{recursive:!0,force:!0}),console.log(` Deleted: ${c}`);let l=h(n,`index.ts`);if(await Ze(l)){let e=await C(l,`utf-8`),t=e,n=RegExp(`^import\\s*\\{\\s*${B(o)}Module\\s*\\}\\s*from\\s*['"][^'"]*${B(s)}(?:/[^'"]*)?['"].*\\n?`,`gm`);e=e.replace(n,``),e=xo(e,o),e=e.replace(/\n{3,}/g,`
|
|
3763
3859
|
|
|
3764
|
-
`),e!==t&&(await w(l,e,`utf-8`),console.log(` Unregistered: ${o}Module from ${l}`))}console.log(`\n Module '${s}' removed.\n`)}function
|
|
3860
|
+
`),e!==t&&(await w(l,e,`utf-8`),console.log(` Unregistered: ${o}Module from ${l}`))}console.log(`\n Module '${s}' removed.\n`)}function Co(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=O(await k(process.cwd())),r=t.modulesDir??n.dir??`src/modules`,i=t.pluralize===!1?!1:n.pluralize??!0;for(let n of e)await So({name:n,modulesDir:v(r),force:t.force,pluralize:i})})}function wo(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 To(e){if(e!==void 0)return e===`false`||e===`off`||e===`none`?!1:e}function Eo(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(`--list`,"List every registered typegen plugin id (use to populate `typegen.disable`)").action(async e=>{let t=$t(process.cwd()),n=await k(t);if(e.list){let{mergeCliPlugins:e}=await Promise.resolve().then(()=>Ue),{builtinCliPlugins:t}=await Promise.resolve().then(()=>As),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(`
|
|
3765
3861
|
Registered typegen plugins:
|
|
3766
|
-
`);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=
|
|
3862
|
+
`);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=wo(e.schemaValidator)??n?.typegen?.schemaValidator??`zod`,i=To(e.envFile)??n?.typegen?.envFile,a={cwd:t,srcDir:e.src??n?.typegen?.srcDir,outDir:e.out??n?.typegen?.outDir,silent:e.silent,allowDuplicates:e.allowDuplicates,schemaValidator:r,envFile:i,assetMap:n?.assetMap,runPlugins:!1};try{if(e.watch){let t=await fa(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{let{result:r}=await K(a),i=await Ea({cwd:t,config:n??null,silent:e.silent,check:e.check});e.check&&i.some(e=>e.status===`written`)&&process.exit(1),e.check||await ma(v(t,e.out??n?.typegen?.outDir??`.kickjs/types`),r.written,i,e.silent??!1)}}catch(e){e instanceof Gi?console.error(`
|
|
3767
3863
|
`+e.message+`
|
|
3768
|
-
`):e instanceof Error?console.error(`\n kick typegen failed: ${e.message}`):console.error(`\n kick typegen failed: ${JSON.stringify(e)}`),process.exit(1)}})}function
|
|
3864
|
+
`):e instanceof Error?console.error(`\n kick typegen failed: ${e.message}`):console.error(`\n kick typegen failed: ${JSON.stringify(e)}`),process.exit(1)}})}function Do(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(...Do(n))}else r.isFile()&&/\.tsx?$/.test(r.name)&&!r.name.endsWith(`.d.ts`)&&t.push(n)}return t}function Oo(e){try{return a(e,`utf-8`)}catch{return``}}const ko=new Set([`secret`,`changeme`,`password`,`test`,`default`,``]);function Ao(e,t){let n=Oo(h(e,`.env`));if(n){let e=n.match(/^JWT_SECRET\s*=\s*['"]?([^'"\n]*)['"]?/m);if(e){let t=e[1].trim();if(ko.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 jo(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 Mo(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 No(){return process.env.NODE_ENV===`production`?null:{severity:`WARNING`,message:`NODE_ENV is '${process.env.NODE_ENV??`undefined`}', not 'production'`}}function Po(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 Fo(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 Io(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 Lo(e){let t=Do(h(e,`src`)).map(e=>Oo(e)),n=[],r=Ao(e,t);r&&n.push(r);let i=jo(t);i&&n.push(i);let a=Mo(t);a&&n.push(a);let o=No();o&&n.push(o);let s=Po(t);return s&&n.push(s),n.push(Fo(t)),n.push(Io(t)),n}function Ro(e){e.command(`check`).description(`Audit project for common issues`).option(`--deploy`,`Run production readiness checks`).action(e=>{if(!e.deploy){console.log(`
|
|
3769
3865
|
Usage: kick check --deploy
|
|
3770
3866
|
|
|
3771
3867
|
Available checks:
|
|
3772
3868
|
--deploy Audit for production readiness (security, config, best practices)
|
|
3773
|
-
`);return}let t=process.cwd();
|
|
3774
|
-
Install a supported version via nvm / fnm / volta.`}:{name:`Node version`,status:`pass`,message:e}}function
|
|
3869
|
+
`);return}let t=process.cwd();Nt(`KickJS Deploy Check`);let n=Rt();n.start(`Scanning project...`);let r=Lo(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)F.message(`${Mt(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?E.red(`${a} critical`):`${a} critical`,o>0?E.yellow(`${o} ${c}`):`${o} ${c}`,`${s} info`].join(`, `);a>0?(N(E.red(`${l} — fix critical issues before deploying`)),process.exit(1)):N(E.green(`${l} — looking good!`))})}function zo(e){try{return JSON.parse(a(e,`utf-8`))}catch{return null}}function Bo(e){try{return a(e,`utf-8`)}catch{return null}}function Vo(e){let t=Bo(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=Ho(e,r.extends);if(t){let e=zo(t)??{};r.compilerOptions={...e.compilerOptions,...r.compilerOptions}}}return r}function Ho(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 Uo(e){return e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}function Wo(){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.
|
|
3870
|
+
Install a supported version via nvm / fnm / volta.`}:{name:`Node version`,status:`pass`,message:e}}function Go(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 Ko(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}function qo(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.
|
|
3775
3871
|
Install it: pnpm add reflect-metadata
|
|
3776
3872
|
Then import it at the top of src/index.ts:
|
|
3777
3873
|
|
|
3778
3874
|
import 'reflect-metadata'
|
|
3779
|
-
// ... rest of bootstrap`}}function
|
|
3875
|
+
// ... rest of bootstrap`}}function Jo(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 Yo(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(Bo(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=Bo(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+)?['"]${Uo(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 Xo(e,t=Zo){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 Zo=2e3;function Qo(e){let t=h(e.cwd,`.kickjs`,`types`);if(!r(t))return null;let n=Xo(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 $o=[()=>Wo(),Go,Ko,qo,Jo,Yo,Qo];async function es(e,t={}){let n={cwd:e,pkg:zo(h(e,`package.json`)),tsconfig:Vo(e)},r=[...$o,...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 ts(e){switch(e){case`pass`:return E.green(`✔`);case`warn`:return E.yellow(`⚠`);case`fail`:return E.red(`✖`)}}function ns(e){let t=ts(e.status),n=e.message?` ${E.dim(`(${e.message})`)}`:``;return`${t} ${e.name}${n}`}function rs(e){return e.split(`
|
|
3780
3876
|
`).map(e=>` ${E.dim(`→`)} ${e}`).join(`
|
|
3781
|
-
`)}function
|
|
3877
|
+
`)}function is(e){return e?.doctor?.checks??[]}function as(e){e.command(`doctor`).description(`Pre-flight checks for your KickJS project (dev environment health)`).action(async()=>{let e=process.cwd(),t=is(await k(e));Nt(`KickJS Doctor`);let n=await es(e,{extraChecks:t});for(let e of n)F.message(ns(e)),e.fix&&e.status!==`pass`&&F.message(rs(e.fix));let r=n.filter(e=>e.status===`pass`).length,i=n.filter(e=>e.status===`warn`).length,a=n.filter(e=>e.status===`fail`).length,o=[E.green(`${r} passed`),i>0?E.yellow(`${i} warning${i===1?``:`s`}`):`${i} warnings`,a>0?E.red(`${a} error${a===1?``:`s`}`):`${a} errors`].join(`, `);a>0?(N(`${o} — fix the errors above before running the app`),process.exit(1)):N(i>0?`${o} — review the warnings`:E.green(`${o} — your environment looks good`))})}async function Q(e){return Ee({configPath:u.resolve(process.cwd(),e.config)})}async function $(e){if(e.adapter){let t=await e.adapter();return{adapter:t,cleanup:async()=>t.close()}}if(!e.connectionString)throw Error(`kickjs-db: no adapter resolved — set db.connectionString (or DATABASE_URL) in kick.config.ts, or supply db.adapter() factory`);let t=e.dialect??`postgres`;if(t!==`postgres`)throw Error(`kickjs-db: built-in CLI adapter only supports postgres in M1 (dialect=${t}); use db.adapter() factory for other dialects`);let[{pgAdapter:n},r]=await Promise.all([import(`@forinda/kickjs-db-pg`),import(`pg`)]),i=new r.default.Pool({connectionString:e.connectionString}),a=n({pool:i});return{adapter:a,cleanup:async()=>{await a.close(),await i.end()}}}async function os(e){if(e.adapter||(e.dialect??`postgres`)!==`postgres`||!e.connectionString)return null;let t=new(await(import(`pg`))).default.Pool({connectionString:e.connectionString});return{runner:t,cleanup:async()=>{await t.end()}}}function ss(e){if(e.length===0){console.log(`No migrations.`);return}console.table(e.map(e=>({id:e.id,state:e.state,batch:e.batch??`-`,reviewed:e.reviewed,applied:e.appliedAt??`-`})))}function cs(e){let t=e.command(`db`).description(`Database commands (kickjs-db)`);t.command(`generate <name>`).description(`Generate a new migration from schema diff`).option(`-c, --config <path>`,`Path to kick.config.ts`,`kick.config.ts`).option(`-e, --empty`,`Skip schema diff and create an empty migration shell (data migration, seed, freeform SQL)`).action(async(e,t)=>{let n=process.cwd(),r=await Q(t),i=await os(r),a=i?e=>ve(i.runner,e):void 0;try{let i=await ye({name:e,config:r,cwd:n,empty:t.empty,detectCompositeRefs:a});if(i.status===`no-changes`){console.log(`No schema changes detected.`);return}if(i.empty){console.log(`Created empty migration ${i.migrationDir} (author up.sql + down.sql).`);return}let o=i.changeCount===1?``:`s`;console.log(`Created migration ${i.migrationDir} (${i.changeCount} change${o}).`)}finally{await i?.cleanup()}});let n=t.command(`migrate`).description(`Migration runner subcommands`);n.command(`latest`).description(`Apply all pending migrations in a new batch`).option(`-c, --config <path>`,`Path to kick.config.ts`,`kick.config.ts`).option(`--confirm-enum-drop`,"Allow migrations carrying the `-- KICK ENUM REMOVE` header to apply",!1).action(async e=>{let t=await Q(e),{adapter:n,cleanup:r}=await $(t);try{let r=await xe({adapter:n,migrationsDir:t.migrationsDir,confirmEnumDrop:e.confirmEnumDrop});r.applied.length===0?console.log(`No pending migrations.`):console.log(`Applied batch ${r.batch}: ${r.applied.join(`, `)}`)}finally{await r()}}),n.command(`up`).description(`Apply the next single pending migration`).option(`-c, --config <path>`,`Path to kick.config.ts`,`kick.config.ts`).option(`--confirm-enum-drop`,"Allow migrations carrying the `-- KICK ENUM REMOVE` header to apply",!1).action(async e=>{let t=await Q(e),{adapter:n,cleanup:r}=await $(t);try{let r=await we({adapter:n,migrationsDir:t.migrationsDir,confirmEnumDrop:e.confirmEnumDrop});r.applied.length===0?console.log(`No pending migrations.`):console.log(`Applied ${r.applied[0]} (batch ${r.batch})`)}finally{await r()}}),n.command(`down`).description(`Reverse the most recent applied migration`).option(`-c, --config <path>`,`Path to kick.config.ts`,`kick.config.ts`).action(async e=>{let t=await Q(e),{adapter:n,cleanup:r}=await $(t);try{let e=await be({adapter:n,migrationsDir:t.migrationsDir});e.reversed?console.log(`Reversed ${e.reversed}.`):console.log(`Nothing to reverse.`)}finally{await r()}}),n.command(`rollback`).description(`Reverse the entire last batch as a single unit`).option(`-c, --config <path>`,`Path to kick.config.ts`,`kick.config.ts`).action(async e=>{let t=await Q(e),{adapter:n,cleanup:r}=await $(t);try{let e=await Se({adapter:n,migrationsDir:t.migrationsDir});e.reversed.length===0?console.log(`Nothing to roll back.`):console.log(`Rolled back batch ${e.batch}: ${e.reversed.join(`, `)}`)}finally{await r()}}),n.command(`status`).description(`Print applied + pending migrations`).option(`-c, --config <path>`,`Path to kick.config.ts`,`kick.config.ts`).action(async e=>{let t=await Q(e),{adapter:n,cleanup:r}=await $(t);try{ss(await Ce({adapter:n,migrationsDir:t.migrationsDir}))}finally{await r()}}),t.command(`introspect`).description(`Generate a TypeScript schema file from a live database`).option(`-c, --config <path>`,`Path to kick.config.ts`,`kick.config.ts`).option(`--out <path>`,`Output file (defaults to db.schemaPath from config)`).option(`--json`,`Print the raw SchemaSnapshot JSON to stdout instead of writing TS source`).action(async e=>{let t=await Q(e),{adapter:n,cleanup:r}=await $(t);try{let r=await n.introspect();if(e.json){console.log(JSON.stringify(r,null,2));return}let i=e.out??t.schemaPath;await w(i,Te(r),`utf8`);let a=Object.keys(r.tables).length;console.log(`Wrote ${i} (${a} table${a===1?``:`s`}).`)}finally{await r()}})}function ls(e){return e.optsWithGlobals().dryRun??!1}function us(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.
|
|
3782
3878
|
Direction defaults to \`modules.style\` from kick.config (or "define").
|
|
3783
3879
|
--target define|class Override the migration direction.
|
|
3784
3880
|
--apply Apply the changes (default: dry-run preview).
|
|
3785
|
-
--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=
|
|
3881
|
+
--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=ls(t)||!e.apply;j(n),e.experimental||(console.error(`
|
|
3786
3882
|
`+E.red(`Error:`)+` kick codemod modules is experimental — pass --experimental to acknowledge.
|
|
3787
3883
|
The regex-based rewrite handles the shapes our templates produce.
|
|
3788
3884
|
Hand-rolled modules with non-standard structures may be skipped.
|
|
3789
3885
|
Always commit before running with --apply.
|
|
3790
|
-
`),process.exit(1));let r=O(await k(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 ${E.red(`Error:`)} --target must be 'define' or 'class' (got '${e.target}').\n`),process.exit(1));let o=E.dim(`→ ${a}`),s=n?E.dim(`(dry-run)`):E.bold(`(applying)`);console.log(`\n ${E.bold(`kick codemod modules`)} ${o} ${s}`),console.log(` modulesDir: ${E.dim(i)}\n`);let c=e.backup!==!1&&!n,l=await
|
|
3791
|
-
`)}});function
|
|
3886
|
+
`),process.exit(1));let r=O(await k(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 ${E.red(`Error:`)} --target must be 'define' or 'class' (got '${e.target}').\n`),process.exit(1));let o=E.dim(`→ ${a}`),s=n?E.dim(`(dry-run)`):E.bold(`(applying)`);console.log(`\n ${E.bold(`kick codemod modules`)} ${o} ${s}`),console.log(` modulesDir: ${E.dim(i)}\n`);let c=e.backup!==!1&&!n,l=await Fr(i,{dryRun:n,target:a,backup:c});if(l.backupDir){let e=l.backupDir;console.log(` ${E.green(`✓`)} backup: ${E.dim(e)}\n ${E.dim(`(restore: rm -rf <modulesDir> && mv "<backup>" <modulesDir>)`)}\n`)}else !n&&e.backup===!1&&console.log(` ${E.dim(`(--no-backup — skipping snapshot)`)}\n`);let u=0,d=0;for(let e of l.files)if(e.status===`migrated`)u++,console.log(` ${E.green(`✓`)} ${e.path}`);else{d++;let t=E.dim(`(${e.reason??`skipped`})`);console.log(` ${E.dim(`-`)} ${e.path} ${t}`)}if(console.log(),l.indexStatus===`migrated`)console.log(` ${E.green(`✓`)} ${l.indexPath}`);else if(l.indexStatus===`skipped`){let e=E.dim(`(${l.indexReason??`skipped`})`);console.log(` ${E.dim(`-`)} ${l.indexPath} ${e}`)}else console.log(` ${E.dim(`-`)} ${l.indexPath} ${E.dim(`(not found)`)}`);let f=n?E.dim(` (dry-run — pass --apply to write)`):``;console.log(`\n ${E.bold(String(u))} migrated, ${E.bold(String(d))} skipped${f}\n`)})}const ds=[`src/db/schema.ts`,`src/db/schema/index.ts`,`src/db/schema`],fs=()=>({id:`kick/db`,inputs:[`src/db/schema.ts`,`src/db/schema/**/*.ts`],async generate(e){let t=ps(e.cwd);if(!t)return null;let n=u.resolve(e.cwd,`.kickjs/types`);return[`import type { SchemaToTypes, SchemaToRelationsRegister, KickDbClient } from '@forinda/kickjs-db'`,`import type * as appSchema from '${ms(u.relative(n,t)).replace(/\.ts$/,``).replace(/\/index$/,``)}'`,``,`declare global {`,` interface KickDbSchema extends SchemaToTypes<typeof appSchema> {}`,`}`,``,`declare module '@forinda/kickjs-db' {`,` interface KickDbRegister {`,` db: KickDbClient<KickDbSchema>`,` }`,``,` interface KickDbRelationsRegister {`,` db: SchemaToRelationsRegister<typeof appSchema>`,` }`,`}`].join(`
|
|
3887
|
+
`)}});function ps(e){for(let t of ds){let n=u.resolve(e,t);if(t.endsWith(`.ts`)){if(r(n))return n}else{let e=u.join(n,`index.ts`);if(r(e))return e}}return null}function ms(e){return e.replace(/\\/g,`/`)}const hs=()=>({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 k(e.cwd);if(!t?.assetMap)return null;let n=ia(t.assetMap,e.cwd);return n.count===0?null:aa(n)}}),gs="/* 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 _s(e,t,n){if(e.length===0)return`${gs}
|
|
3792
3888
|
// (no routes discovered yet — annotate a controller method with
|
|
3793
3889
|
// @Get/@Post/@Put/@Delete/@Patch and re-run \`kick typegen\`)
|
|
3794
3890
|
declare global {
|
|
@@ -3797,8 +3893,8 @@ declare global {
|
|
|
3797
3893
|
}
|
|
3798
3894
|
|
|
3799
3895
|
export {}
|
|
3800
|
-
`;let r=new Map;for(let t of e){let e=r.get(t.controller)??[];e.push(t),r.set(t.controller,e)}let i=new Map,a=(e,r)=>{let a=
|
|
3801
|
-
`))}return`${
|
|
3896
|
+
`;let r=new Map;for(let t of e){let e=r.get(t.controller)??[];e.push(t),r.set(t.controller,e)}let i=new Map,a=(e,r)=>{let a=bs(e,r,t,n,i);return a?n===`kickjs-schema`?`import('@forinda/kickjs-schema').InferSchemaOutput<typeof ${a}>`:`import('zod').infer<typeof ${a}>`:null},o=[];for(let[e,t]of r){let n=[` interface ${e} {`];for(let e of t){let t=e.pathParams.length>0?`{ ${e.pathParams.map(e=>`${e}: string`).join(`; `)} }`:`{}`,r=a(e.bodySchema,e.filePath),i=a(e.querySchema,e.filePath),o=a(e.paramsSchema,e.filePath)??t,s=r??`unknown`,c=i??vs(e),l=ys(e);n.push(` /**`,` * ${e.httpMethod} ${e.path}`,...l.map(e=>` * ${e}`),` */`,` ${e.method}: {`,` params: ${o}`,` body: ${s}`,` query: ${c}`,` response: unknown`,` }`)}n.push(` }`),o.push(n.join(`
|
|
3897
|
+
`))}return`${gs}${xs(i)}
|
|
3802
3898
|
declare global {
|
|
3803
3899
|
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
3804
3900
|
namespace KickRoutes {
|
|
@@ -3808,21 +3904,23 @@ ${o.join(`
|
|
|
3808
3904
|
}
|
|
3809
3905
|
|
|
3810
3906
|
export {}
|
|
3811
|
-
`}function
|
|
3907
|
+
`}function vs(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 ys(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 bs(e,t,n,r,i){if(!e||r===!1||e.source===null)return null;let a=Ss(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 xs(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(`
|
|
3812
3908
|
`)+`
|
|
3813
|
-
`}function
|
|
3909
|
+
`}function Ss(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 Cs=()=>({id:`kick/routes`,outExtension:`.ts`,inputs:[`src/**/*.controller.ts`,`src/**/*.module.ts`],async generate(e){let t=await e.getScanResult({root:ws(e),cwd:e.cwd,envFile:Ts(e)}),n=e.config?.typegen?.schemaValidator??`zod`,r=u.resolve(e.cwd,`.kickjs/types/kick__routes.ts`);return _s(t.routes,r,n)}});function ws(e){return u.resolve(e.cwd,e.config?.typegen?.srcDir??`src`)}function Ts(e){let t=e.config?.typegen?.envFile;if(t!==!1)return t}function Es(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 */
|
|
3814
3910
|
// AUTO-GENERATED by \`kick typegen\`. DO NOT EDIT.
|
|
3815
3911
|
// Re-run with \`kick typegen\` or rely on \`kick dev\` to refresh.
|
|
3816
3912
|
|
|
3817
3913
|
// Importing the schema as a type lets us infer its shape without
|
|
3818
3914
|
// pulling in any runtime code. \`Awaited<>\` strips an accidental
|
|
3819
3915
|
// Promise wrap on dynamic-imported defaults.
|
|
3820
|
-
import type _envSchema from '${
|
|
3916
|
+
import type _envSchema from '${r}'
|
|
3821
3917
|
|
|
3822
|
-
|
|
3918
|
+
${n===`kickjs-schema`?`type _Raw = import('@forinda/kickjs-schema').InferSchemaOutput<typeof _envSchema>
|
|
3919
|
+
type _Resolved = { [K in keyof _Raw]: _Raw[K] }
|
|
3920
|
+
`:``}// Local type alias — interfaces can only \`extend\` an identifier,
|
|
3823
3921
|
// not an inline import expression, so we resolve the schema's
|
|
3824
3922
|
// inferred shape into a named type first.
|
|
3825
|
-
type _KickEnvShape = import('zod').infer<typeof _envSchema
|
|
3923
|
+
type _KickEnvShape = ${n===`kickjs-schema`?`_Resolved`:`import('zod').infer<typeof _envSchema>`}
|
|
3826
3924
|
|
|
3827
3925
|
declare global {
|
|
3828
3926
|
/**
|
|
@@ -3846,4 +3944,4 @@ declare global {
|
|
|
3846
3944
|
}
|
|
3847
3945
|
|
|
3848
3946
|
export {}
|
|
3849
|
-
`}const
|
|
3947
|
+
`}const Ds=()=>({id:`kick/env`,outExtension:`.ts`,inputs:[`src/env.ts`,`src/**/env.ts`,`src/**/*.env.ts`],async generate(e){let t=ks(e);if(t===!1)return null;let n=await e.getScanResult({root:Os(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 Es(n.env,i,r)}});function Os(e){return u.resolve(e.cwd,e.config?.typegen?.srcDir??`src`)}function ks(e){return e.config?.typegen?.envFile}var As=D({builtinCliPlugins:()=>js});const js=[A({name:`kick/init`,register:Yt}),A({name:`kick/generate`,register:ba}),A({name:`kick/run`,register:Pa}),A({name:`kick/info`,register:Fa}),A({name:`kick/inspect`,register:Ga}),A({name:`kick/add`,register:qt}),A({name:`kick/list`,register:Kt}),A({name:`kick/explain`,register:to}),A({name:`kick/mcp`,register:po}),A({name:`kick/tinker`,register:_o}),A({name:`kick/remove`,register:Co}),A({name:`kick/typegen`,register:Eo}),A({name:`kick/check`,register:Ro}),A({name:`kick/doctor`,register:as}),A({name:`kick/db`,register:cs,typegens:[fs()]}),A({name:`kick/codemod`,register:us}),A({name:`kick/assets`,typegens:[hs()]}),A({name:`kick/routes`,typegens:[Cs()]}),A({name:`kick/env`,typegens:[Ds()]})],Ms=f(b(import.meta.url)),Ns=JSON.parse(a(h(Ms,`..`,`package.json`),`utf-8`));async function Ps(){let e=new t;e.name(`kick`).description(`KickJS — A production-grade, decorator-driven Node.js framework`).version(Ns.version);let n=$t(process.cwd()),r=n,i=await k(r)??{},a=He([...js,...i.plugins??[]],i.commands??[]);await a.register(e,{cwd:r,projectRoot:n,config:i,log:e=>console.log(e)}),Ae(e,{...i,commands:a.commands}),e.showHelpAfterError(),await e.parseAsync(process.argv)}Ps().catch(e=>{console.error(e instanceof Error?e.message:e),process.exitCode=1});export{};
|