@forinda/kickjs-cli 8.2.4 → 8.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{agent-docs-C6ZYsFJV.mjs → agent-docs-CpoUa3NG.mjs} +3 -3
- package/dist/{agent-docs-C6ZYsFJV.mjs.map → agent-docs-CpoUa3NG.mjs.map} +1 -1
- package/dist/{agent-docs-GCMhcDHy.mjs → agent-docs-VPtM_Kgj.mjs} +2 -2
- package/dist/{build-hdxD_kEK.mjs → build-BKNvIOBh.mjs} +3 -3
- package/dist/{build-hdxD_kEK.mjs.map → build-BKNvIOBh.mjs.map} +1 -1
- package/dist/{build-DTs2SHKS.mjs → build-BhoYGIVD.mjs} +2 -2
- package/dist/{builtins-Ci7vBC42.mjs → builtins-6FCYMic-.mjs} +34 -25
- package/dist/{builtins-BZGJgOyW.mjs → builtins-BvdsVFXh.mjs} +2 -2
- package/dist/cli.mjs +2 -2
- package/dist/{config-Bsokk8bV.mjs → config-3zv5pWqb.mjs} +2 -2
- package/dist/{config-Dgap2WmJ.mjs → config-LkaeajTr.mjs} +3 -3
- package/dist/config-LkaeajTr.mjs.map +1 -0
- package/dist/{doctor-Crq8eZsF.mjs → doctor-3-n9AElz.mjs} +4 -4
- package/dist/{doctor-Crq8eZsF.mjs.map → doctor-3-n9AElz.mjs.map} +1 -1
- package/dist/{fullstack-C7Q-BJcj.mjs → fullstack-0D2Dgia_.mjs} +14 -11
- package/dist/{fullstack-onQslndx.mjs → fullstack-D_OHhyZX.mjs} +15 -12
- package/dist/fullstack-D_OHhyZX.mjs.map +1 -0
- package/dist/index.d.mts +54 -0
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +2 -2
- package/dist/{plugin-BYqbu6uO.mjs → plugin-3V8ZP2h3.mjs} +2 -2
- package/dist/{plugin-BuSzbyf2.mjs → plugin-MfCs1kvG.mjs} +2 -2
- package/dist/{project-BnXVCMd6.mjs → project-D-8rOQYi.mjs} +36 -20
- package/dist/project-D-8rOQYi.mjs.map +1 -0
- package/dist/{project-4kpuS1ud.mjs → project-Evcbbdbq.mjs} +33 -17
- package/dist/{project-docs-Dn60gTjG.mjs → project-docs-B-qcYAX9.mjs} +1 -1
- package/dist/{project-docs-CDr1HNPD.mjs → project-docs-B6XKHBMO.mjs} +2 -2
- package/dist/{project-docs-CDr1HNPD.mjs.map → project-docs-B6XKHBMO.mjs.map} +1 -1
- package/dist/{project-root-B1lyUoe8.mjs → project-root-6mdsMXwA.mjs} +3 -3
- package/dist/{project-root-B1lyUoe8.mjs.map → project-root-6mdsMXwA.mjs.map} +1 -1
- package/dist/{project-root-B5MNmlIn.mjs → project-root-CxadsnDd.mjs} +2 -2
- package/dist/{prompts-8ssKQ4Kn.mjs → prompts-BtUBi1ob.mjs} +2 -2
- package/dist/{prompts-8ssKQ4Kn.mjs.map → prompts-BtUBi1ob.mjs.map} +1 -1
- package/dist/{rolldown-runtime-DtbiLYsN.mjs → rolldown-runtime-BeIFeoWC.mjs} +1 -1
- package/dist/{run-plugins-CxuPMW4H.mjs → run-plugins-lLfcDAbT.mjs} +77 -68
- package/dist/run-plugins-lLfcDAbT.mjs.map +1 -0
- package/dist/{typegen-ClJqftm9.mjs → typegen-DLdD6SMm.mjs} +4 -4
- package/dist/{typegen-Ca46MGcE.mjs → typegen-yk3CJH18.mjs} +5 -5
- package/dist/{typegen-Ca46MGcE.mjs.map → typegen-yk3CJH18.mjs.map} +1 -1
- package/dist/{types-CJlHwJb4.mjs → types-HQhLYWkB.mjs} +1 -1
- package/package.json +7 -7
- package/dist/config-Dgap2WmJ.mjs.map +0 -1
- package/dist/fullstack-onQslndx.mjs.map +0 -1
- package/dist/project-BnXVCMd6.mjs.map +0 -1
- package/dist/run-plugins-CxuPMW4H.mjs.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @forinda/kickjs-cli v8.
|
|
2
|
+
* @forinda/kickjs-cli v8.3.0
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Felix Orinda
|
|
5
5
|
*
|
|
@@ -8,5 +8,5 @@
|
|
|
8
8
|
*
|
|
9
9
|
* @license MIT
|
|
10
10
|
*/
|
|
11
|
-
import{t as e}from"./rolldown-runtime-
|
|
12
|
-
//# sourceMappingURL=agent-docs-
|
|
11
|
+
import{t as e}from"./rolldown-runtime-BeIFeoWC.mjs";import{a as t,i as n,l as r,n as i,r as a,t as o}from"./project-docs-B6XKHBMO.mjs";import{t as s}from"./prompts-BtUBi1ob.mjs";import{o as c}from"./config-LkaeajTr.mjs";import{join as l}from"node:path";import{existsSync as u,readFileSync as d}from"node:fs";var f=e({generateAgentDocs:()=>y});const p=`.agents`,m=new Set([`rest`,`minimal`,`fullstack`]);function h(e,t){if(t)return t;try{let t=JSON.parse(d(l(e,`package.json`),`utf-8`));if(t.name)return t.name.replace(/^@[^/]+\//,``)}catch{}return e.split(`/`).findLast(Boolean)??`app`}function g(e,t){if(t)return t;try{let t=JSON.parse(d(l(e,`package.json`),`utf-8`));if(t.packageManager)return t.packageManager.split(`@`)[0]}catch{}return`pnpm`}async function _(e){try{return(await c(e))?.modules?.style===`class`?`class`:`define`}catch{return`define`}}async function v(e,t){if(t)return t;try{let t=(await c(e))?.pattern;if(t&&m.has(t))return t}catch{}return`rest`}async function y(e){let c=e.only??`all`,d=h(e.outDir,e.name),f=g(e.outDir,e.pm),m=await v(e.outDir,e.template),y=await _(e.outDir),b=c===`agents`||c===`both`||c===`all`,x=c===`claude`||c===`both`||c===`all`,S=c===`skills`||c===`all`,C=c===`gemini`||c===`all`,w=c===`copilot`||c===`all`,T=[];if(b&&T.push({file:l(e.outDir,p,`AGENTS.md`),render:()=>o(d,m,f)}),x&&T.push({file:l(e.outDir,`CLAUDE.md`),render:()=>i(d,m,f)}),S)for(let n of t(d,m,f,y))T.push({file:l(e.outDir,p,`skills`,n.slug,`SKILL.md`),render:()=>n.content});C&&T.push({file:l(e.outDir,p,`GEMINI.md`),render:()=>n(d,m,f)}),w&&T.push({file:l(e.outDir,p,`COPILOT.md`),render:()=>a(d,m,f)});let E=[];for(let{file:t,render:n}of T){if(u(t)&&!e.force&&!await s({message:`${t.replace(e.outDir+`/`,``)} already exists. Overwrite?`,initialValue:!1})){console.log(` Skipped — existing ${t.replace(e.outDir+`/`,``)} preserved.`);continue}await r(t,n()),E.push(t)}return E}export{y as n,f as t};
|
|
12
|
+
//# sourceMappingURL=agent-docs-CpoUa3NG.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-docs-
|
|
1
|
+
{"version":3,"file":"agent-docs-CpoUa3NG.mjs","names":[],"sources":["../src/generators/agent-docs.ts"],"sourcesContent":["import { join } from 'node:path'\nimport { existsSync, readFileSync } from 'node:fs'\nimport { writeFileSafe } from '../utils/fs'\nimport { confirm } from '../utils/prompts'\nimport {\n generateClaude,\n generateAgents,\n generateKickJsSkillFiles,\n generateGemini,\n generateCopilot,\n} from './templates/project-docs'\nimport { loadKickConfig } from '../config'\nimport type { ModuleStyle } from './templates/types'\n\ntype ProjectTemplate = 'rest' | 'minimal' | 'fullstack'\n\n/**\n * Subdirectory (relative to the project root) where every shared\n * agent-context file lands. CLAUDE.md is the only exception — it stays\n * at the project root because Claude Code auto-loads CLAUDE.md from\n * there. CLAUDE.md is generated as a thin pointer that tells Claude\n * to read `.agents/AGENTS.md` first.\n *\n * Existing root-level AGENTS.md / kickjs-skills.md files (from older\n * scaffolds before this restructure) are left untouched — the\n * generator emits the new layout alongside them and leaves migration\n * to the adopter.\n */\nconst AGENTS_DIR = '.agents'\n\nexport interface GenerateAgentDocsOptions {\n outDir: string\n /** Override project name (defaults to package.json `name`). */\n name?: string\n /** Override package manager (defaults to package.json `packageManager` field, then 'pnpm'). */\n pm?: string\n /** Override template (defaults to kick.config.ts `pattern`, then 'rest'). */\n template?: ProjectTemplate\n /**\n * Which file(s) to (re)generate. All `.agents/`-bound files land in\n * the project's `.agents/` subdirectory; `claude` is the only file\n * that stays at the project root.\n *\n * - `agents` → `.agents/AGENTS.md`\n * - `claude` → `CLAUDE.md` (root; thin pointer to .agents/)\n * - `skills` → `.agents/skills/<slug>/SKILL.md` (one per skill)\n * - `gemini` → `.agents/GEMINI.md`\n * - `copilot` → `.agents/COPILOT.md`\n * - `both` → `.agents/AGENTS.md` + `CLAUDE.md` (legacy alias)\n * - `all` → every file above\n */\n only?: 'agents' | 'claude' | 'skills' | 'gemini' | 'copilot' | 'both' | 'all'\n /** Skip the overwrite prompt. */\n force?: boolean\n}\n\nconst VALID_TEMPLATES = new Set<ProjectTemplate>(['rest', 'minimal', 'fullstack'])\n\nfunction detectName(outDir: string, override?: string): string {\n if (override) return override\n try {\n const pkg = JSON.parse(readFileSync(join(outDir, 'package.json'), 'utf-8')) as { name?: string }\n if (pkg.name) return pkg.name.replace(/^@[^/]+\\//, '')\n } catch {\n // No package.json — fall back to folder name\n }\n return outDir.split('/').findLast(Boolean) ?? 'app'\n}\n\nfunction detectPm(outDir: string, override?: string): string {\n if (override) return override\n try {\n const pkg = JSON.parse(readFileSync(join(outDir, 'package.json'), 'utf-8')) as {\n packageManager?: string\n }\n if (pkg.packageManager) return pkg.packageManager.split('@')[0]\n } catch {\n // ignore\n }\n return 'pnpm'\n}\n\n/**\n * Module declaration style, so generated examples show the form this project\n * actually uses. A `class` module passed as `UserModule()` calls a class\n * without `new`; a `define` module passed bare is refused when it takes config.\n */\nasync function detectStyle(outDir: string): Promise<ModuleStyle> {\n try {\n const cfg = await loadKickConfig(outDir)\n return cfg?.modules?.style === 'class' ? 'class' : 'define'\n } catch {\n return 'define'\n }\n}\n\nasync function detectTemplate(\n outDir: string,\n override?: ProjectTemplate,\n): Promise<ProjectTemplate> {\n if (override) return override\n try {\n const cfg = await loadKickConfig(outDir)\n const pattern = cfg?.pattern as ProjectTemplate | undefined\n if (pattern && VALID_TEMPLATES.has(pattern)) return pattern\n } catch {\n // ignore\n }\n return 'rest'\n}\n\nexport async function generateAgentDocs(options: GenerateAgentDocsOptions): Promise<string[]> {\n const only = options.only ?? 'all'\n const name = detectName(options.outDir, options.name)\n const pm = detectPm(options.outDir, options.pm)\n const template = await detectTemplate(options.outDir, options.template)\n const style = await detectStyle(options.outDir)\n\n const wantsAgents = only === 'agents' || only === 'both' || only === 'all'\n const wantsClaude = only === 'claude' || only === 'both' || only === 'all'\n const wantsSkills = only === 'skills' || only === 'all'\n const wantsGemini = only === 'gemini' || only === 'all'\n const wantsCopilot = only === 'copilot' || only === 'all'\n\n // CLAUDE.md stays at the project root because Claude Code auto-loads\n // it from there. Every other shared-context file lands under\n // `.agents/` so the root stays uncluttered. `writeFileSafe` creates\n // parent directories automatically — no need to pre-mkdir.\n const targets: { file: string; render: () => string }[] = []\n if (wantsAgents) {\n targets.push({\n file: join(options.outDir, AGENTS_DIR, 'AGENTS.md'),\n render: () => generateAgents(name, template, pm),\n })\n }\n if (wantsClaude) {\n targets.push({\n file: join(options.outDir, 'CLAUDE.md'),\n render: () => generateClaude(name, template, pm),\n })\n }\n if (wantsSkills) {\n // Per-skill SKILL.md under `.agents/skills/<slug>/` so agents that\n // auto-discover skills (Claude Code, Copilot CLI plugins, Gemini's\n // activate_skill) pick each up by its frontmatter without needing\n // a separate index file.\n for (const skill of generateKickJsSkillFiles(name, template, pm, style)) {\n targets.push({\n file: join(options.outDir, AGENTS_DIR, 'skills', skill.slug, 'SKILL.md'),\n render: () => skill.content,\n })\n }\n }\n if (wantsGemini) {\n targets.push({\n file: join(options.outDir, AGENTS_DIR, 'GEMINI.md'),\n render: () => generateGemini(name, template, pm),\n })\n }\n if (wantsCopilot) {\n targets.push({\n file: join(options.outDir, AGENTS_DIR, 'COPILOT.md'),\n render: () => generateCopilot(name, template, pm),\n })\n }\n\n const written: string[] = []\n for (const { file, render } of targets) {\n if (existsSync(file) && !options.force) {\n const overwrite = await confirm({\n message: `${file.replace(options.outDir + '/', '')} already exists. Overwrite?`,\n initialValue: false,\n })\n if (!overwrite) {\n console.log(` Skipped — existing ${file.replace(options.outDir + '/', '')} preserved.`)\n continue\n }\n }\n await writeFileSafe(file, render())\n written.push(file)\n }\n return written\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @forinda/kickjs-cli v8.
|
|
2
|
+
* @forinda/kickjs-cli v8.3.0
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Felix Orinda
|
|
5
5
|
*
|
|
@@ -8,4 +8,4 @@
|
|
|
8
8
|
*
|
|
9
9
|
* @license MIT
|
|
10
10
|
*/
|
|
11
|
-
import{t as e}from"./rolldown-runtime-
|
|
11
|
+
import{t as e}from"./rolldown-runtime-BeIFeoWC.mjs";import{a as t}from"./config-3zv5pWqb.mjs";import{a as n,i as r,l as i,n as a,r as o,t as s}from"./project-docs-B-qcYAX9.mjs";import{existsSync as c,readFileSync as l}from"node:fs";import{join as u}from"node:path";import*as d from"@clack/prompts";import f from"picocolors";const p={GET:f.green,POST:f.cyan,PUT:f.yellow,PATCH:f.magenta,DELETE:f.red};function m(e){return(p[e]??f.dim)(e.padEnd(7))}function h(e){let t=`[${e}]`.padEnd(10);switch(e){case`CRITICAL`:return f.red(t);case`WARNING`:return f.yellow(t);case`INFO`:return f.blue(f.dim(t));default:return t}}f.green(`✓`),f.red(`✖`),f.yellow(`⚠`),f.blue(`ℹ`);function g(e){d.intro(f.bgCyan(f.black(` ${e} `)))}function _(e){d.outro(e)}function v(e){d.isCancel(e)&&(d.cancel(`Operation cancelled.`),process.exit(0))}async function y(e){let t=await d.text(e);return v(t),t}async function b(e){let t=await d.select(e);return v(t),t}async function x(e){let t=await d.multiselect(e);return v(t),t}async function S(e){let t=await d.confirm(e);return v(t),t}function C(){return d.spinner()}const w=d.log;var T=e({generateAgentDocs:()=>M});const E=`.agents`,D=new Set([`rest`,`minimal`,`fullstack`]);function O(e,t){if(t)return t;try{let t=JSON.parse(l(u(e,`package.json`),`utf-8`));if(t.name)return t.name.replace(/^@[^/]+\//,``)}catch{}return e.split(`/`).findLast(Boolean)??`app`}function k(e,t){if(t)return t;try{let t=JSON.parse(l(u(e,`package.json`),`utf-8`));if(t.packageManager)return t.packageManager.split(`@`)[0]}catch{}return`pnpm`}async function A(e){try{return(await t(e))?.modules?.style===`class`?`class`:`define`}catch{return`define`}}async function j(e,n){if(n)return n;try{let n=(await t(e))?.pattern;if(n&&D.has(n))return n}catch{}return`rest`}async function M(e){let t=e.only??`all`,l=O(e.outDir,e.name),d=k(e.outDir,e.pm),f=await j(e.outDir,e.template),p=await A(e.outDir),m=t===`agents`||t===`both`||t===`all`,h=t===`claude`||t===`both`||t===`all`,g=t===`skills`||t===`all`,_=t===`gemini`||t===`all`,v=t===`copilot`||t===`all`,y=[];if(m&&y.push({file:u(e.outDir,E,`AGENTS.md`),render:()=>s(l,f,d)}),h&&y.push({file:u(e.outDir,`CLAUDE.md`),render:()=>a(l,f,d)}),g)for(let t of n(l,f,d,p))y.push({file:u(e.outDir,E,`skills`,t.slug,`SKILL.md`),render:()=>t.content});_&&y.push({file:u(e.outDir,E,`GEMINI.md`),render:()=>r(l,f,d)}),v&&y.push({file:u(e.outDir,E,`COPILOT.md`),render:()=>o(l,f,d)});let b=[];for(let{file:t,render:n}of y){if(c(t)&&!e.force&&!await S({message:`${t.replace(e.outDir+`/`,``)} already exists. Overwrite?`,initialValue:!1})){console.log(` Skipped — existing ${t.replace(e.outDir+`/`,``)} preserved.`);continue}await i(t,n()),b.push(t)}return b}export{w as a,b as c,m as d,f,g as i,C as l,M as n,x as o,h as p,S as r,_ as s,T as t,y as u};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @forinda/kickjs-cli v8.
|
|
2
|
+
* @forinda/kickjs-cli v8.3.0
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Felix Orinda
|
|
5
5
|
*
|
|
@@ -8,6 +8,6 @@
|
|
|
8
8
|
*
|
|
9
9
|
* @license MIT
|
|
10
10
|
*/
|
|
11
|
-
import{t as e}from"./rolldown-runtime-
|
|
11
|
+
import{t as e}from"./rolldown-runtime-BeIFeoWC.mjs";import{dirname as t,isAbsolute as n,join as r,relative as i,resolve as a}from"node:path";import{cpSync as o,existsSync as s,mkdirSync as c,statSync as l,writeFileSync as u}from"node:fs";import{glob as d}from"glob";import{groupAssetKeys as f}from"@forinda/kickjs";var p=e({ASSET_MANIFEST_VERSION:()=>1,buildAssets:()=>m});async function m(e,t){let{cwd:n,silent:o=!1}=t,s=t.distDir??e?.build?.outDir??`dist`,l=e?.assetMap;if(!l||Object.keys(l).length===0)return null;let d=o?()=>{}:console.log,f=a(n,s);c(f,{recursive:!0});let p=[],m={};for(let[e,t]of Object.entries(l)){let r=await h(e,t,n,f);p.push(r.entrySummary),Object.assign(m,r.manifestSlice),d(` ✓ ${e}: ${r.entrySummary.filesCopied} file(s) → ${r.entrySummary.dest}`)}let g={version:1,entries:m},_=r(f,`.kickjs-assets.json`);return u(_,JSON.stringify(g,null,2)+`
|
|
12
12
|
`,`utf-8`),d(` ✓ wrote manifest → ${i(n,_)} (${Object.keys(m).length} entries)`),{manifestPath:_,entries:p,manifest:g}}async function h(e,n,l,u){let p=a(l,n.src),m=n.dest?a(l,n.dest):r(u,e);if(v(m,l))return console.warn(` ⚠ assetMap.${e}.dest ('${n.dest}') resolves outside the project root — skipping copy`),{entrySummary:{namespace:e,src:n.src,dest:i(l,m),filesCopied:0},manifestSlice:{}};if(!s(p)||!y(p))return{entrySummary:{namespace:e,src:n.src,dest:i(l,m),filesCopied:0},manifestSlice:{}};let h=n.glob??`**/*`,b=await d(h,{cwd:p,nodir:!0,dot:!1,posix:!0});c(m,{recursive:!0});let x={},S=[...b].toSorted(),{pairs:C,collisionGroupsResolved:w}=f(e,S,{strategy:n.keys??`auto`}),T=0;for(let{rel:e,key:n}of C){let i=r(p,e),a=r(m,e);x[n]=_(u,a),!g(i,a)&&(c(t(a),{recursive:!0}),o(i,a),T++)}return w>0&&console.log(` ℹ assetMap.${e}: auto-resolved ${w} 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:n.src,dest:i(l,m),filesCopied:T},manifestSlice:x}}function g(e,t){if(!s(t))return!1;try{let n=l(e),r=l(t);return r.size===n.size&&r.mtimeMs>=n.mtimeMs}catch{return!1}}function _(e,t){return i(e,t).split(/[\\/]/).filter(Boolean).join(`/`)}function v(e,t){let r=i(t,e);return r===``?!1:r.startsWith(`..`)||n(r)}function y(e){try{return l(e).isDirectory()}catch{return!1}}export{p as n,m as t};
|
|
13
|
-
//# sourceMappingURL=build-
|
|
13
|
+
//# sourceMappingURL=build-BKNvIOBh.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build-hdxD_kEK.mjs","names":[],"sources":["../src/asset-manager/build.ts"],"sourcesContent":["/**\n * Build pipeline for `assetMap` entries (asset-manager PR 2).\n *\n * For each entry, walks `src/<...>` matching the configured `glob`,\n * copies matches into `dest` (default `dist/<name>/`), then emits a\n * `dist/.kickjs-assets.json` manifest mapping logical\n * `<namespace>/<key>` keys to repo-relative paths inside `dist/`.\n *\n * Pure function on top of `node:fs` + `glob` — no shell, no side\n * effects beyond the configured directory writes. The build entry-\n * point in `commands/run.ts` calls `buildAssets` after the existing\n * `copyDirs` step.\n *\n * @module @forinda/kickjs-cli/asset-manager/build\n */\n\nimport { cpSync, existsSync, mkdirSync, statSync, writeFileSync } from 'node:fs'\nimport { dirname, isAbsolute, join, relative, resolve } from 'node:path'\nimport { glob } from 'glob'\nimport { groupAssetKeys } from '@forinda/kickjs'\nimport type { AssetMapEntry, KickConfig } from '../config'\n\n/** Wire-format version for `dist/.kickjs-assets.json`. Bump on shape change. */\nexport const ASSET_MANIFEST_VERSION = 1 as const\n\n/** On-disk manifest format (`dist/.kickjs-assets.json`). */\nexport interface AssetManifest {\n version: typeof ASSET_MANIFEST_VERSION\n /**\n * Logical key → manifest-relative path. Logical key is\n * `<namespace>/<key>` where `<key>` is the file path under `src`\n * with the extension stripped + path separators normalised.\n *\n * Path values are relative to the manifest file's directory so the\n * runtime can resolve them with a single `path.resolve(manifestDir,\n * entry)` regardless of where dist/ lives.\n */\n entries: Record<string, string>\n}\n\nexport interface BuildAssetsOptions {\n /** Project root — resolved for every relative path in the entry. */\n cwd: string\n /**\n * Output dir for the manifest + per-namespace asset copies. When\n * omitted, falls back to `config.build?.outDir` (resolved against\n * `cwd`), then to `dist/` under cwd. Adopters with a custom Vite\n * `build.outDir` should set `kick.config.ts.build.outDir` to match.\n */\n distDir?: string\n /** Suppress per-entry log lines. Default: false. */\n silent?: boolean\n}\n\n/** One entry in the per-build summary returned by `buildAssets`. */\nexport interface BuildAssetsEntryResult {\n namespace: string\n src: string\n dest: string\n /**\n * Number of files actually written this run. On an incremental\n * rebuild where nothing changed this is 0 even though the manifest\n * still lists every matched file.\n */\n filesCopied: number\n}\n\n/** Aggregated outcome of `buildAssets`. */\nexport interface BuildAssetsResult {\n manifestPath: string\n entries: BuildAssetsEntryResult[]\n /** `entries` merged into a single record — useful for tests + tooling. */\n manifest: AssetManifest\n}\n\n/**\n * Run the full asset build for a loaded config:\n *\n * 1. For each `assetMap` entry, glob → copy → manifest stub.\n * 2. Write `dist/.kickjs-assets.json`.\n *\n * Returns a summary including the manifest contents. No-op (and no\n * manifest written) when `assetMap` is empty / missing — the build\n * pipeline shouldn't litter `dist/` with empty manifests for\n * adopters who don't use the feature.\n */\nexport async function buildAssets(\n config: KickConfig | null,\n opts: BuildAssetsOptions,\n): Promise<BuildAssetsResult | null> {\n const { cwd, silent = false } = opts\n // Resolution order: explicit opts.distDir → config.build.outDir → 'dist'.\n // The CLI build command passes nothing explicit, so adopters control\n // the output via kick.config.ts.build.outDir alone.\n const distDir = opts.distDir ?? config?.build?.outDir ?? 'dist'\n const map = config?.assetMap\n if (!map || Object.keys(map).length === 0) return null\n\n const log = silent ? () => {} : console.log\n\n const distAbs = resolve(cwd, distDir)\n mkdirSync(distAbs, { recursive: true })\n\n const summary: BuildAssetsEntryResult[] = []\n const manifestEntries: Record<string, string> = {}\n\n for (const [namespace, entry] of Object.entries(map)) {\n const result = await processEntry(namespace, entry, cwd, distAbs)\n summary.push(result.entrySummary)\n Object.assign(manifestEntries, result.manifestSlice)\n log(\n ` ✓ ${namespace}: ${result.entrySummary.filesCopied} file(s) → ${result.entrySummary.dest}`,\n )\n }\n\n const manifest: AssetManifest = {\n version: ASSET_MANIFEST_VERSION,\n entries: manifestEntries,\n }\n const manifestPath = join(distAbs, '.kickjs-assets.json')\n writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + '\\n', 'utf-8')\n log(\n ` ✓ wrote manifest → ${relative(cwd, manifestPath)} (${Object.keys(manifestEntries).length} entries)`,\n )\n\n return { manifestPath, entries: summary, manifest }\n}\n\n/** Per-entry inner pipeline — extracted for unit-test reuse. */\nasync function processEntry(\n namespace: string,\n entry: AssetMapEntry,\n cwd: string,\n distAbs: string,\n): Promise<{\n entrySummary: BuildAssetsEntryResult\n manifestSlice: Record<string, string>\n}> {\n const srcAbs = resolve(cwd, entry.src)\n const destAbs = entry.dest ? resolve(cwd, entry.dest) : join(distAbs, namespace)\n\n // Defensive: refuse to write outside the project root (cwd) even\n // though validateAssetMap warned about it at config-load time. The\n // build step shouldn't trust upstream warnings — a typo like\n // `dest: '../../'` would otherwise sprinkle files outside the\n // workspace despite the warning being printed.\n if (escapesRoot(destAbs, cwd)) {\n console.warn(\n ` ⚠ assetMap.${namespace}.dest ('${entry.dest}') resolves outside the project root — skipping copy`,\n )\n return {\n entrySummary: { namespace, src: entry.src, dest: relative(cwd, destAbs), filesCopied: 0 },\n manifestSlice: {},\n }\n }\n\n // Treat src-not-a-directory the same as src-missing — `glob` would\n // throw if pointed at a file, surfacing as a generic build failure\n // instead of a clean 0-files entry. Matches the validator's warning\n // shape (already emitted at config-load time for the missing case).\n if (!existsSync(srcAbs) || !isDirectorySync(srcAbs)) {\n return {\n entrySummary: { namespace, src: entry.src, dest: relative(cwd, destAbs), filesCopied: 0 },\n manifestSlice: {},\n }\n }\n\n const pattern = entry.glob ?? '**/*'\n // `glob` returns paths relative to `cwd` when `cwd` is set —\n // exactly the slugs we want for the manifest keys.\n const matches = await glob(pattern, {\n cwd: srcAbs,\n nodir: true,\n dot: false,\n posix: true,\n })\n\n mkdirSync(destAbs, { recursive: true })\n\n const manifestSlice: Record<string, string> = {}\n // Sort the walk so the manifest is byte-stable across platforms.\n // The `groupAssetKeys` helper preserves input order, so a stable\n // sort here makes the resulting manifest stable too.\n const sorted = [...matches].toSorted()\n const { pairs, collisionGroupsResolved } = groupAssetKeys(namespace, sorted, {\n strategy: entry.keys ?? 'auto',\n })\n\n // Copy the files and write the keyed manifest slice. Both come from\n // the same `pairs` order so the on-disk layout matches the\n // manifest's iteration order — easier to grep in cold-start\n // debugging.\n //\n // Incremental: skip the copy when the destination is already\n // up-to-date (exists, same size, mtime ≥ source). `cpSync` stamps the\n // copy with the current time, so an unchanged source always satisfies\n // `dest.mtime ≥ src.mtime` on the next run — turning a re-build into a\n // pure stat sweep instead of re-copying every asset. The manifest\n // slice is written unconditionally so the manifest stays complete.\n let filesCopied = 0\n for (const { rel: relPath, key } of pairs) {\n const srcFile = join(srcAbs, relPath)\n const destFile = join(destAbs, relPath)\n manifestSlice[key] = toManifestRelative(distAbs, destFile)\n if (isUpToDate(srcFile, destFile)) continue\n mkdirSync(dirname(destFile), { recursive: true })\n cpSync(srcFile, destFile)\n filesCopied++\n }\n\n if (collisionGroupsResolved > 0) {\n console.log(\n ` ℹ assetMap.${namespace}: auto-resolved ${collisionGroupsResolved} basename collision(s) by keeping extensions ` +\n `(set 'keys: \"strip\"' to opt back into legacy last-write-wins behaviour, or 'keys: \"with-extension\"' to keep all keys verbose).`,\n )\n }\n\n return {\n entrySummary: {\n namespace,\n src: entry.src,\n dest: relative(cwd, destAbs),\n filesCopied,\n },\n manifestSlice,\n }\n}\n\n/**\n * Is `destFile` already a current copy of `srcFile`? True when the\n * destination exists with the same byte size and an mtime no older than\n * the source. Used to skip redundant copies on an incremental rebuild.\n */\nfunction isUpToDate(srcFile: string, destFile: string): boolean {\n if (!existsSync(destFile)) return false\n try {\n const s = statSync(srcFile)\n const d = statSync(destFile)\n return d.size === s.size && d.mtimeMs >= s.mtimeMs\n } catch {\n return false\n }\n}\n\n/**\n * Make `destFile` relative to the manifest's directory + force POSIX\n * separators so the manifest is byte-stable across platforms.\n */\nfunction toManifestRelative(manifestDir: string, destFile: string): string {\n const rel = relative(manifestDir, destFile)\n // path.relative returns OS-native separators; the manifest is JSON\n // and the runtime uses path.resolve which handles either, but a\n // forward-slash manifest is grep-friendly + diff-stable.\n return rel.split(/[\\\\/]/).filter(Boolean).join('/')\n}\n\n/**\n * Pure manifest writer — handy for tests that want to assert against\n * a hand-crafted manifest without exercising the full pipeline.\n */\nexport function writeAssetManifest(distDir: string, manifest: AssetManifest): string {\n const path = join(distDir, '.kickjs-assets.json')\n mkdirSync(distDir, { recursive: true })\n writeFileSync(path, JSON.stringify(manifest, null, 2) + '\\n', 'utf-8')\n return path\n}\n\n/**\n * Read + parse a manifest from disk. Returns `null` on missing or\n * malformed file rather than throwing — the runtime resolver wants\n * to fall through to dev-mode lookup in that case.\n */\nexport function readAssetManifest(distDir: string): AssetManifest | null {\n const path = join(distDir, '.kickjs-assets.json')\n if (!existsSync(path)) return null\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const fs = require('node:fs') as typeof import('node:fs')\n const raw = fs.readFileSync(path, 'utf-8')\n const parsed = JSON.parse(raw) as Partial<AssetManifest>\n if (parsed.version !== ASSET_MANIFEST_VERSION) return null\n if (!parsed.entries || typeof parsed.entries !== 'object') return null\n return parsed as AssetManifest\n } catch {\n return null\n }\n}\n\n/**\n * Project-root escape check that's safe across symlinks + drive letters.\n * `path.relative` returns `..` segments when the target sits above root,\n * and an absolute path when the two live on different roots (Windows).\n * `startsWith(root)` would miss both cases.\n */\nfunction escapesRoot(path: string, root: string): boolean {\n const rel = relative(root, path)\n if (rel === '') return false\n return rel.startsWith('..') || isAbsolute(rel)\n}\n\n/** Pure helper — `false` for missing, non-dir, or unreadable paths. */\nfunction isDirectorySync(path: string): boolean {\n try {\n return statSync(path).isDirectory()\n } catch {\n return false\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"build-BKNvIOBh.mjs","names":[],"sources":["../src/asset-manager/build.ts"],"sourcesContent":["/**\n * Build pipeline for `assetMap` entries (asset-manager PR 2).\n *\n * For each entry, walks `src/<...>` matching the configured `glob`,\n * copies matches into `dest` (default `dist/<name>/`), then emits a\n * `dist/.kickjs-assets.json` manifest mapping logical\n * `<namespace>/<key>` keys to repo-relative paths inside `dist/`.\n *\n * Pure function on top of `node:fs` + `glob` — no shell, no side\n * effects beyond the configured directory writes. The build entry-\n * point in `commands/run.ts` calls `buildAssets` after the existing\n * `copyDirs` step.\n *\n * @module @forinda/kickjs-cli/asset-manager/build\n */\n\nimport { cpSync, existsSync, mkdirSync, statSync, writeFileSync } from 'node:fs'\nimport { dirname, isAbsolute, join, relative, resolve } from 'node:path'\nimport { glob } from 'glob'\nimport { groupAssetKeys } from '@forinda/kickjs'\nimport type { AssetMapEntry, KickConfig } from '../config'\n\n/** Wire-format version for `dist/.kickjs-assets.json`. Bump on shape change. */\nexport const ASSET_MANIFEST_VERSION = 1 as const\n\n/** On-disk manifest format (`dist/.kickjs-assets.json`). */\nexport interface AssetManifest {\n version: typeof ASSET_MANIFEST_VERSION\n /**\n * Logical key → manifest-relative path. Logical key is\n * `<namespace>/<key>` where `<key>` is the file path under `src`\n * with the extension stripped + path separators normalised.\n *\n * Path values are relative to the manifest file's directory so the\n * runtime can resolve them with a single `path.resolve(manifestDir,\n * entry)` regardless of where dist/ lives.\n */\n entries: Record<string, string>\n}\n\nexport interface BuildAssetsOptions {\n /** Project root — resolved for every relative path in the entry. */\n cwd: string\n /**\n * Output dir for the manifest + per-namespace asset copies. When\n * omitted, falls back to `config.build?.outDir` (resolved against\n * `cwd`), then to `dist/` under cwd. Adopters with a custom Vite\n * `build.outDir` should set `kick.config.ts.build.outDir` to match.\n */\n distDir?: string\n /** Suppress per-entry log lines. Default: false. */\n silent?: boolean\n}\n\n/** One entry in the per-build summary returned by `buildAssets`. */\nexport interface BuildAssetsEntryResult {\n namespace: string\n src: string\n dest: string\n /**\n * Number of files actually written this run. On an incremental\n * rebuild where nothing changed this is 0 even though the manifest\n * still lists every matched file.\n */\n filesCopied: number\n}\n\n/** Aggregated outcome of `buildAssets`. */\nexport interface BuildAssetsResult {\n manifestPath: string\n entries: BuildAssetsEntryResult[]\n /** `entries` merged into a single record — useful for tests + tooling. */\n manifest: AssetManifest\n}\n\n/**\n * Run the full asset build for a loaded config:\n *\n * 1. For each `assetMap` entry, glob → copy → manifest stub.\n * 2. Write `dist/.kickjs-assets.json`.\n *\n * Returns a summary including the manifest contents. No-op (and no\n * manifest written) when `assetMap` is empty / missing — the build\n * pipeline shouldn't litter `dist/` with empty manifests for\n * adopters who don't use the feature.\n */\nexport async function buildAssets(\n config: KickConfig | null,\n opts: BuildAssetsOptions,\n): Promise<BuildAssetsResult | null> {\n const { cwd, silent = false } = opts\n // Resolution order: explicit opts.distDir → config.build.outDir → 'dist'.\n // The CLI build command passes nothing explicit, so adopters control\n // the output via kick.config.ts.build.outDir alone.\n const distDir = opts.distDir ?? config?.build?.outDir ?? 'dist'\n const map = config?.assetMap\n if (!map || Object.keys(map).length === 0) return null\n\n const log = silent ? () => {} : console.log\n\n const distAbs = resolve(cwd, distDir)\n mkdirSync(distAbs, { recursive: true })\n\n const summary: BuildAssetsEntryResult[] = []\n const manifestEntries: Record<string, string> = {}\n\n for (const [namespace, entry] of Object.entries(map)) {\n const result = await processEntry(namespace, entry, cwd, distAbs)\n summary.push(result.entrySummary)\n Object.assign(manifestEntries, result.manifestSlice)\n log(\n ` ✓ ${namespace}: ${result.entrySummary.filesCopied} file(s) → ${result.entrySummary.dest}`,\n )\n }\n\n const manifest: AssetManifest = {\n version: ASSET_MANIFEST_VERSION,\n entries: manifestEntries,\n }\n const manifestPath = join(distAbs, '.kickjs-assets.json')\n writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + '\\n', 'utf-8')\n log(\n ` ✓ wrote manifest → ${relative(cwd, manifestPath)} (${Object.keys(manifestEntries).length} entries)`,\n )\n\n return { manifestPath, entries: summary, manifest }\n}\n\n/** Per-entry inner pipeline — extracted for unit-test reuse. */\nasync function processEntry(\n namespace: string,\n entry: AssetMapEntry,\n cwd: string,\n distAbs: string,\n): Promise<{\n entrySummary: BuildAssetsEntryResult\n manifestSlice: Record<string, string>\n}> {\n const srcAbs = resolve(cwd, entry.src)\n const destAbs = entry.dest ? resolve(cwd, entry.dest) : join(distAbs, namespace)\n\n // Defensive: refuse to write outside the project root (cwd) even\n // though validateAssetMap warned about it at config-load time. The\n // build step shouldn't trust upstream warnings — a typo like\n // `dest: '../../'` would otherwise sprinkle files outside the\n // workspace despite the warning being printed.\n if (escapesRoot(destAbs, cwd)) {\n console.warn(\n ` ⚠ assetMap.${namespace}.dest ('${entry.dest}') resolves outside the project root — skipping copy`,\n )\n return {\n entrySummary: { namespace, src: entry.src, dest: relative(cwd, destAbs), filesCopied: 0 },\n manifestSlice: {},\n }\n }\n\n // Treat src-not-a-directory the same as src-missing — `glob` would\n // throw if pointed at a file, surfacing as a generic build failure\n // instead of a clean 0-files entry. Matches the validator's warning\n // shape (already emitted at config-load time for the missing case).\n if (!existsSync(srcAbs) || !isDirectorySync(srcAbs)) {\n return {\n entrySummary: { namespace, src: entry.src, dest: relative(cwd, destAbs), filesCopied: 0 },\n manifestSlice: {},\n }\n }\n\n const pattern = entry.glob ?? '**/*'\n // `glob` returns paths relative to `cwd` when `cwd` is set —\n // exactly the slugs we want for the manifest keys.\n const matches = await glob(pattern, {\n cwd: srcAbs,\n nodir: true,\n dot: false,\n posix: true,\n })\n\n mkdirSync(destAbs, { recursive: true })\n\n const manifestSlice: Record<string, string> = {}\n // Sort the walk so the manifest is byte-stable across platforms.\n // The `groupAssetKeys` helper preserves input order, so a stable\n // sort here makes the resulting manifest stable too.\n const sorted = [...matches].toSorted()\n const { pairs, collisionGroupsResolved } = groupAssetKeys(namespace, sorted, {\n strategy: entry.keys ?? 'auto',\n })\n\n // Copy the files and write the keyed manifest slice. Both come from\n // the same `pairs` order so the on-disk layout matches the\n // manifest's iteration order — easier to grep in cold-start\n // debugging.\n //\n // Incremental: skip the copy when the destination is already\n // up-to-date (exists, same size, mtime ≥ source). `cpSync` stamps the\n // copy with the current time, so an unchanged source always satisfies\n // `dest.mtime ≥ src.mtime` on the next run — turning a re-build into a\n // pure stat sweep instead of re-copying every asset. The manifest\n // slice is written unconditionally so the manifest stays complete.\n let filesCopied = 0\n for (const { rel: relPath, key } of pairs) {\n const srcFile = join(srcAbs, relPath)\n const destFile = join(destAbs, relPath)\n manifestSlice[key] = toManifestRelative(distAbs, destFile)\n if (isUpToDate(srcFile, destFile)) continue\n mkdirSync(dirname(destFile), { recursive: true })\n cpSync(srcFile, destFile)\n filesCopied++\n }\n\n if (collisionGroupsResolved > 0) {\n console.log(\n ` ℹ assetMap.${namespace}: auto-resolved ${collisionGroupsResolved} basename collision(s) by keeping extensions ` +\n `(set 'keys: \"strip\"' to opt back into legacy last-write-wins behaviour, or 'keys: \"with-extension\"' to keep all keys verbose).`,\n )\n }\n\n return {\n entrySummary: {\n namespace,\n src: entry.src,\n dest: relative(cwd, destAbs),\n filesCopied,\n },\n manifestSlice,\n }\n}\n\n/**\n * Is `destFile` already a current copy of `srcFile`? True when the\n * destination exists with the same byte size and an mtime no older than\n * the source. Used to skip redundant copies on an incremental rebuild.\n */\nfunction isUpToDate(srcFile: string, destFile: string): boolean {\n if (!existsSync(destFile)) return false\n try {\n const s = statSync(srcFile)\n const d = statSync(destFile)\n return d.size === s.size && d.mtimeMs >= s.mtimeMs\n } catch {\n return false\n }\n}\n\n/**\n * Make `destFile` relative to the manifest's directory + force POSIX\n * separators so the manifest is byte-stable across platforms.\n */\nfunction toManifestRelative(manifestDir: string, destFile: string): string {\n const rel = relative(manifestDir, destFile)\n // path.relative returns OS-native separators; the manifest is JSON\n // and the runtime uses path.resolve which handles either, but a\n // forward-slash manifest is grep-friendly + diff-stable.\n return rel.split(/[\\\\/]/).filter(Boolean).join('/')\n}\n\n/**\n * Pure manifest writer — handy for tests that want to assert against\n * a hand-crafted manifest without exercising the full pipeline.\n */\nexport function writeAssetManifest(distDir: string, manifest: AssetManifest): string {\n const path = join(distDir, '.kickjs-assets.json')\n mkdirSync(distDir, { recursive: true })\n writeFileSync(path, JSON.stringify(manifest, null, 2) + '\\n', 'utf-8')\n return path\n}\n\n/**\n * Read + parse a manifest from disk. Returns `null` on missing or\n * malformed file rather than throwing — the runtime resolver wants\n * to fall through to dev-mode lookup in that case.\n */\nexport function readAssetManifest(distDir: string): AssetManifest | null {\n const path = join(distDir, '.kickjs-assets.json')\n if (!existsSync(path)) return null\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const fs = require('node:fs') as typeof import('node:fs')\n const raw = fs.readFileSync(path, 'utf-8')\n const parsed = JSON.parse(raw) as Partial<AssetManifest>\n if (parsed.version !== ASSET_MANIFEST_VERSION) return null\n if (!parsed.entries || typeof parsed.entries !== 'object') return null\n return parsed as AssetManifest\n } catch {\n return null\n }\n}\n\n/**\n * Project-root escape check that's safe across symlinks + drive letters.\n * `path.relative` returns `..` segments when the target sits above root,\n * and an absolute path when the two live on different roots (Windows).\n * `startsWith(root)` would miss both cases.\n */\nfunction escapesRoot(path: string, root: string): boolean {\n const rel = relative(root, path)\n if (rel === '') return false\n return rel.startsWith('..') || isAbsolute(rel)\n}\n\n/** Pure helper — `false` for missing, non-dir, or unreadable paths. */\nfunction isDirectorySync(path: string): boolean {\n try {\n return statSync(path).isDirectory()\n } catch {\n return false\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @forinda/kickjs-cli v8.
|
|
2
|
+
* @forinda/kickjs-cli v8.3.0
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Felix Orinda
|
|
5
5
|
*
|
|
@@ -8,5 +8,5 @@
|
|
|
8
8
|
*
|
|
9
9
|
* @license MIT
|
|
10
10
|
*/
|
|
11
|
-
import{t as e}from"./rolldown-runtime-
|
|
11
|
+
import{t as e}from"./rolldown-runtime-BeIFeoWC.mjs";import{cpSync as t,existsSync as n,mkdirSync as r,statSync as i,writeFileSync as a}from"node:fs";import{dirname as o,isAbsolute as s,join as c,relative as l,resolve as u}from"node:path";import{glob as d}from"glob";import{groupAssetKeys as f}from"@forinda/kickjs";var p=e({ASSET_MANIFEST_VERSION:()=>1,buildAssets:()=>m});async function m(e,t){let{cwd:n,silent:i=!1}=t,o=t.distDir??e?.build?.outDir??`dist`,s=e?.assetMap;if(!s||Object.keys(s).length===0)return null;let d=i?()=>{}:console.log,f=u(n,o);r(f,{recursive:!0});let p=[],m={};for(let[e,t]of Object.entries(s)){let r=await h(e,t,n,f);p.push(r.entrySummary),Object.assign(m,r.manifestSlice),d(` ✓ ${e}: ${r.entrySummary.filesCopied} file(s) → ${r.entrySummary.dest}`)}let g={version:1,entries:m},_=c(f,`.kickjs-assets.json`);return a(_,JSON.stringify(g,null,2)+`
|
|
12
12
|
`,`utf-8`),d(` ✓ wrote manifest → ${l(n,_)} (${Object.keys(m).length} entries)`),{manifestPath:_,entries:p,manifest:g}}async function h(e,i,a,s){let p=u(a,i.src),m=i.dest?u(a,i.dest):c(s,e);if(v(m,a))return console.warn(` ⚠ assetMap.${e}.dest ('${i.dest}') resolves outside the project root — skipping copy`),{entrySummary:{namespace:e,src:i.src,dest:l(a,m),filesCopied:0},manifestSlice:{}};if(!n(p)||!y(p))return{entrySummary:{namespace:e,src:i.src,dest:l(a,m),filesCopied:0},manifestSlice:{}};let h=i.glob??`**/*`,b=await d(h,{cwd:p,nodir:!0,dot:!1,posix:!0});r(m,{recursive:!0});let x={},S=[...b].toSorted(),{pairs:C,collisionGroupsResolved:w}=f(e,S,{strategy:i.keys??`auto`}),T=0;for(let{rel:e,key:n}of C){let i=c(p,e),a=c(m,e);x[n]=_(s,a),!g(i,a)&&(r(o(a),{recursive:!0}),t(i,a),T++)}return w>0&&console.log(` ℹ assetMap.${e}: auto-resolved ${w} 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:i.src,dest:l(a,m),filesCopied:T},manifestSlice:x}}function g(e,t){if(!n(t))return!1;try{let n=i(e),r=i(t);return r.size===n.size&&r.mtimeMs>=n.mtimeMs}catch{return!1}}function _(e,t){return l(e,t).split(/[\\/]/).filter(Boolean).join(`/`)}function v(e,t){let n=l(t,e);return n===``?!1:n.startsWith(`..`)||s(n)}function y(e){try{return i(e).isDirectory()}catch{return!1}}export{p as n,m as t};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @forinda/kickjs-cli v8.
|
|
2
|
+
* @forinda/kickjs-cli v8.3.0
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Felix Orinda
|
|
5
5
|
*
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*
|
|
9
9
|
* @license MIT
|
|
10
10
|
*/
|
|
11
|
-
import{t as e}from"./rolldown-runtime-
|
|
11
|
+
import{t as e}from"./rolldown-runtime-BeIFeoWC.mjs";import{a as t,c as n,l as r,m as i,r as a,s as o,t as s,u as c}from"./project-Evcbbdbq.mjs";import{a as l,c as u,i as d,l as f,o as p,r as m,s as h}from"./config-3zv5pWqb.mjs";import{n as g,r as _}from"./plugin-MfCs1kvG.mjs";import{c as v,l as y,s as b}from"./project-docs-B-qcYAX9.mjs";import{a as x,c as S,d as ee,f as C,i as te,l as ne,n as re,o as ie,p as ae,r as w,s as T,u as oe}from"./agent-docs-VPtM_Kgj.mjs";import{t as E}from"./project-root-CxadsnDd.mjs";import{C as se,S as D,T as ce,_ as le,a as ue,b as de,c as fe,d as pe,f as me,g as he,h as ge,i as _e,l as ve,m as ye,o as be,p as xe,r as Se,s as Ce,t as we,u as Te,v as Ee,w as De,x as Oe,y as ke}from"./typegen-DLdD6SMm.mjs";import{t as Ae}from"./build-BhoYGIVD.mjs";import{createRequire as je}from"node:module";import{cpSync as Me,existsSync as O,mkdirSync as Ne,readFileSync as k,readdirSync as Pe,rmSync as Fe,statSync as Ie,writeFileSync as Le}from"node:fs";import A,{basename as Re,dirname as j,join as M,relative as N,resolve as P,sep as ze}from"node:path";import{fileURLToPath as Be,pathToFileURL as F}from"node:url";import{fork as Ve,spawn as He,spawnSync as Ue}from"node:child_process";import{copyFile as We,mkdir as Ge,readFile as I,readdir as Ke,rm as qe,stat as Je,writeFile as L}from"node:fs/promises";import"@forinda/kickjs-cli-kit";import Ye from"pluralize";import{parseSync as Xe}from"oxc-parser";import{arch as Ze,platform as Qe,release as $e}from"node:os";import{createHash as et}from"node:crypto";const tt=[{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 nt(e){e.command(`new [name]`).alias(`init`).description(`Create a new KickJS project (use "." for current directory)`).option(`-d, --directory <dir>`,`Target directory (defaults to project name)`).option(`--pm <manager>`,`Package manager: pnpm | npm | yarn | bun`).option(`--git`,`Initialize git repository`).option(`--no-git`,`Skip git initialization`).option(`--install`,`Install dependencies after scaffolding`).option(`--no-install`,`Skip dependency installation`).option(`-f, --force`,`Remove existing files without prompting`).option(`-t, --template <type>`,`Project template: rest | minimal | fullstack`).option(`--runtime <engine>`,`HTTP runtime: express | fastify | h3`).option(`-r, --repo <type>`,`Repository name (inmemory, or any DB name e.g. postgres)`).option(`-s, --schema <lib>`,`Schema library for env / DTOs: zod | valibot | yup (default: zod)`).option(`--packages <packages>`,`Comma-separated packages to include (e.g. swagger,ws,queue,devtools)`).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)=>{te(`KickJS — Create a new project`);let n=!!(t.yes||t.nonInteractive);e||=n?`my-api`:await oe({message:`Project name`,placeholder:`my-api`,defaultValue:`my-api`});let r;if(e===`.`?(r=P(`.`),e=Re(r)):r=P(t.directory||e),O(r)){let i=Pe(r);if(i.length>0){if(t.force)x.warn(`Clearing existing files in ${r}`);else if(n){x.warn(`Directory "${e}" is not empty. Pass --force to clear it.`),T(`Aborted.`);return}else{x.warn(`Directory "${e}" is not empty:`);let t=i.slice(0,5);for(let e of t)x.message(` - ${e}`);if(i.length>5&&x.message(` ... and ${i.length-5} more`),!await w({message:C.red(`Remove all existing files and proceed?`),initialValue:!1})){T(`Aborted.`);return}}for(let e of i)Fe(P(r,e),{recursive:!0,force:!0})}}let i=t.template;i||=n?`minimal`:await S({message:`Project template`,options:[{value:`rest`,label:`REST API`,hint:`Express + Swagger`},{value:`minimal`,label:`Minimal`,hint:`bare Express`},{value:`fullstack`,label:`Fullstack`,hint:`server + Vite React web, typed client`}]});let a=t.runtime;a||=n?`express`:await S({message:`HTTP runtime`,options:[{value:`express`,label:`Express`,hint:`default, zero-config`},{value:`fastify`,label:`Fastify`,hint:`fastify + @fastify/middie`},{value:`h3`,label:`h3`,hint:`Nitro / Nuxt engine`}]});let o=t.pm;o||=n?await c(void 0):await S({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?`inmemory`:await oe({message:`Repository name`,placeholder:`inmemory (or a DB name, e.g. postgres)`,defaultValue:`inmemory`}),f(l);let u=t.schema;u||=n?`zod`:await S({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)||(x.warn(`Unknown --schema "${u}", falling back to zod.`),u=`zod`);let d;if(t.packages!==void 0){let e=t.packages.trim().toLowerCase();d=e===``||e===`none`||e===`false`?[]:t.packages.split(`,`).map(e=>e.trim()).filter(Boolean)}else d=n?[]:await ie({message:`Select packages to include`,options:[...tt],required:!1});let p;p=t.git===void 0?n?!0:await w({message:`Initialize git repository?`,initialValue:!0}):t.git;let m;if(m=t.install===void 0?n?!0:await w({message:`Install dependencies?`,initialValue:!0}):t.install,i===`fullstack`){let{initFullstackProject:t}=await import(`./fullstack-0D2Dgia_.mjs`);await t({name:e,directory:r,packageManager:o,initGit:p,installDeps:m,schemaLib:u,runtime:a}),T(`Done! Next steps: ${C.cyan(`cd ${e} && ${o}${o===`pnpm`?` dev`:` run dev:server`}`)}`);return}await s({name:e,directory:r,packageManager:o,initGit:p,installDeps:m,template:i,defaultRepo:l,packages:d,schemaLib:u,runtime:a}),T(`Done! Next steps: ${C.cyan(`cd ${e} && ${o} dev`)}`)})}function R(e){return e.replace(/[-_\s]+(.)?/g,(e,t)=>t?t.toUpperCase():``).replace(/^(.)/,e=>e.toUpperCase())}function z(e){let t=R(e);return t.charAt(0).toLowerCase()+t.slice(1)}function B(e){return e.replace(/([a-z])([A-Z])/g,`$1-$2`).replace(/[\s_]+/g,`-`).toLowerCase()}function V(e){return Ye.plural(e)}function rt(e){return Ye.plural(e)}function it(e){return B(e).replace(/-/g,`_`)}function at(e){let t=e.cwd??process.cwd(),n=e.projectRoot??E(t),r=e.pluralize??!0,i=R(e.name),a=z(e.name),o=B(e.name),s=it(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=V(o);c.pluralKebab=e,c.pluralPascal=R(e),c.pluralCamel=z(e)}return c}function ot(e,t){return P(e.cwd,t)}async function st(e){return import(F(e).href)}const ct=new Map;async function lt(e){let t=ct.get(e);if(t)return t;let n=ut(e);return ct.set(e,n),n}async function ut(e){let t=P(e,`package.json`);if(!O(t))return{generators:[],loaded:[],failed:[]};let n=dt(JSON.parse(await I(t,`utf-8`))),r=je(P(e,`package.json`)),i=[],a=[],o=[];for(let e of n){let t;try{t=r.resolve(`${e}/package.json`)}catch{continue}let n;try{n=JSON.parse(await I(t,`utf-8`))}catch(t){o.push({source:e,reason:`failed to parse package.json: ${t}`});continue}if(!n.kickjs?.generators)continue;let s=n.kickjs.generators,c=P(j(t),s);if(!O(c)){o.push({source:e,reason:`kickjs.generators points to missing file: ${s}`});continue}let l;try{l=await st(c)}catch(t){o.push({source:e,reason:`failed to import manifest: ${t}`});continue}let u=l.default;if(!Array.isArray(u)){o.push({source:e,reason:`manifest's default export is not an array of GeneratorSpec`});continue}for(let t of u){if(!ft(t)){o.push({source:e,reason:`manifest entry is not a valid GeneratorSpec (missing name/files)`});continue}i.push({source:e,spec:t})}a.push(e)}return{generators:i,loaded:a,failed:o}}function dt(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 ft(e){if(!e||typeof e!=`object`)return!1;let t=e;return typeof t.name==`string`&&typeof t.files==`function`}async function pt(e,t=[]){let n=e.cwd??process.cwd(),r=t.find(t=>t.spec.name===e.generatorName);if(r)return gt(r.spec,r.source,e,n);let i=ht(await lt(n),e.generatorName);return i?gt(i.spec,i.source,e,n):null}async function mt(e,t=[]){let n=await lt(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 ht(e,t){return e.generators.find(e=>e.spec.name===t)}async function gt(e,t,n,r){let i=at({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=ot(i,e.path);await y(t,e.content),o.push(t)}return{files:o,source:t}}function H(e){return e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}const _t={inmemory:`in-memory`,drizzle:`Drizzle`,prisma:`Prisma`};function vt(e){return e.charAt(0).toUpperCase()+e.slice(1).replace(/-([a-z])/g,(e,t)=>t.toUpperCase())}function yt(e){return _t[e]??vt(e)}function bt(e){return`create${e}Repository`}function xt(e){return e??`define`}function St(e){let{pascal:t,kebab:n,plural:r=``,repo:i,style:a}=e,o=bt(t),s=xt(a),c=`/**
|
|
12
12
|
* ${t} Module
|
|
13
13
|
*
|
|
14
14
|
* REST module with a flat folder structure.
|
|
@@ -1290,7 +1290,7 @@ describe('${o}', () => {
|
|
|
1290
1290
|
Example: kick g scaffold Post title:string body:text:optional published:boolean:optional
|
|
1291
1291
|
Optional: append :optional (shell-safe, no quoting needed)
|
|
1292
1292
|
`),process.exit(1));let a=await l(process.cwd()),o=p(a),s=n.modulesDir??o.dir??`src/modules`,c=_n(t),f=u(a,process.cwd()),m=d(E()),h=await vn({name:e,fields:c,modulesDir:P(s),noEntity:n.entity===!1,noTests:n.tests===!1,pluralize:n.pluralize===!1?!1:o.pluralize??!0,tokenScope:f,swagger:m,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)`:``}`);q(h,i),await En(i)}),n.command(`config`).description(`Generate a kick.config.ts at the project root`).option(`--modules-dir <dir>`,`Modules directory path`,`src/modules`).option(`--repo <type>`,`Repository name: inmemory (default) or any DB name`,`inmemory`).option(`-f, --force`,`Overwrite existing kick.config.ts without prompting`).action(async(e,t)=>{let n=K(t);v(n),q(await nn({outDir:P(`.`),modulesDir:e.modulesDir,defaultRepo:e.repo,force:e.force}),n)}),n.command(`agents`).alias(`agent-docs`).alias(`ai-docs`).description(`Regenerate .agents/* + root CLAUDE.md (sync after framework upgrades)`).option(`--only <which>`,`Limit scope: agents | claude | skills | gemini | copilot | both (agents+claude) | all (default: all)`,`all`).option(`--name <name>`,`Project name (defaults to package.json name)`).option(`--pm <pm>`,`Package manager (defaults to package.json packageManager)`).option(`--template <template>`,`Template: rest | minimal | fullstack`).option(`-f, --force`,`Overwrite existing files without prompting`).action(async(e,t)=>{let n=K(t);v(n);let r=e.only??`all`;if(!Tn.includes(r)){console.error(` Invalid --only value: ${r}. Expected: ${Tn.join(` | `)}`),process.exitCode=1;return}q(await re({outDir:P(`.`),only:r,name:e.name,pm:e.pm,template:e.template,force:e.force}),n)});for(let e of t?.generators??[])Nn(n,e,t?.projectRoot)}function Nn(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=K(o);v(s);let c=await pt({generatorName:i.name,itemName:e??``,args:r??[],flags:a,cwd:process.cwd(),projectRoot:n},[t]);c&&q(c.files,s)})}const Pn=`/* AUTO-GENERATED by kick typegen — do not edit. Plugin: `;async function Fn(e){let t=A.resolve(e.cwd,`.kickjs/types`);e.check||await Ge(t,{recursive:!0});let n=new Map,r=e.scan??he,i=A.resolve(e.cwd,`.kickjs`,`cache`),a=e.scan?void 0:e.changedFiles,o={cwd:e.cwd,config:e.config,async importTs(e){return await import(F(e).href)},async writeFile(t,n){let r=A.resolve(e.cwd,t);await Ge(A.dirname(r),{recursive:!0}),await L(r,n,`utf8`)},getScanResult:e=>{let t=In(e),o=n.get(t);if(!o){let s={cacheDir:i,...e};o=a?le(s,a):r(s),n.set(t,o)}return o},log:console,watch:e.watch,check:e.check},s=[],c=[];for(let n of e.plugins){let r=n.outExtension??`.d.ts`,i=A.join(t,`${n.id.replace(/\//g,`__`)}${r}`),a;try{a=await n.generate(o)}catch(t){let r=t instanceof Error?t.message:String(t);if(e.check)throw Error(`kick typegen --check: ${n.id} failed to generate (${r})`,{cause:t});o.log.error(` ${n.id}: typegen failed (${r}) — keeping previous output`),s.push({id:n.id,status:`error`,outFile:i});continue}if(a===null){s.push({id:n.id,status:`skipped`});continue}let l=`${Pn}${n.id} */\n\n`+a+`
|
|
1293
|
-
`,u=``;if(O(i)&&(u=await I(i,`utf8`)),u===l){s.push({id:n.id,status:`unchanged`,outFile:i});continue}if(e.check){c.push({id:n.id,outFile:i}),s.push({id:n.id,status:`drifted`,outFile:i});continue}await L(i,l,`utf8`),s.push({id:n.id,status:`written`,outFile:i})}if(c.length>0)throw new wn(c);return s}function In(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 Ln(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 Rn=e({applyDisableFilter:()=>Ln,runAllPluginTypegens:()=>zn});async function zn(e){let t=[...
|
|
1293
|
+
`,u=``;if(O(i)&&(u=await I(i,`utf8`)),u===l){s.push({id:n.id,status:`unchanged`,outFile:i});continue}if(e.check){c.push({id:n.id,outFile:i}),s.push({id:n.id,status:`drifted`,outFile:i});continue}await L(i,l,`utf8`),s.push({id:n.id,status:`written`,outFile:i})}if(c.length>0)throw new wn(c);return s}function In(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 Ln(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 Rn=e({applyDisableFilter:()=>Ln,runAllPluginTypegens:()=>zn});async function zn(e){let t=[...oo,...e.config?.plugins??[]],{enabled:n,skipped:r,unknown:i}=Ln(g(t,e.config?.commands??[]).typegens,e.config?.typegen?.disable??[]);if(!e.silent&&r.length>0)for(let e of r)console.log(` ${e.id}: disabled (typegen.disable)`);if(!e.silent&&i.length>0&&console.warn(` kick typegen: disable list references unknown id(s): ${i.map(e=>`'${e}'`).join(`, `)}. Run \`kick typegen --list\` to see registered ids.`),n.length===0)return[];try{let t=await Fn({cwd:e.cwd,config:e.config??{},plugins:n,watch:e.watch,check:e.check,changedFiles:e.changedFiles});if(!e.silent&&Cn())for(let e of t)console.log(` ${e.id}: ${e.status}`);return t}catch(t){if(t instanceof wn||e.check)throw t;if(!e.silent){let e=t instanceof Error?t.message:String(t);console.warn(` kick typegen plugins: skipped (${e})`)}return[]}}function Bn(e){let t=new Map;return{report(n,r){let i=r instanceof Error?r.message:String(r);t.get(n)!==i&&(t.set(n,i),e(` kick typegen: ${n} pass failed (${i}) — types in .kickjs/types may be stale`))},clear(e){t.delete(e)}}}function Vn(e){let{cwd:t,config:n}=e,r=e.debounceMs??100,i=e.pipeline??{runTypegen:async e=>(await import(`./typegen-DLdD6SMm.mjs`).then(e=>e.n)).runTypegen(e),runAllPluginTypegens:async e=>(await Promise.resolve().then(()=>Rn)).runAllPluginTypegens(e),writeTypegenArtifacts:async(e,t,n)=>(await import(`./typegen-DLdD6SMm.mjs`).then(e=>e.n)).writeTypegenArtifacts(e,t,n),buildAssets:async(e,t)=>(await import(`./build-BhoYGIVD.mjs`).then(e=>e.n)).buildAssets(e,t)},a=n?.typegen?.schemaValidator??`zod`,o=n?.typegen?.envFile,s=A.resolve(t,n?.typegen?.outDir??`.kickjs/types`),c=n?.assetMap?Object.values(n.assetMap).map(e=>e?.src).filter(e=>typeof e==`string`&&e.length>0).map(e=>A.resolve(t,e)):[],l=!!n?.assetMap&&Object.keys(n.assetMap).length>0,u=e=>e.replaceAll(`\\`,`/`),d=c.map(u),f=e=>{let t=u(e);return d.some(e=>t===e||t.startsWith(`${e}/`))},p=Bn(e.emitWarning),m=null,h=!1,g=new Set,_=new Set,v=!1,y=!1;function b(r,c){i.runTypegen({cwd:t,silent:!0,allowDuplicates:!0,schemaValidator:a,envFile:o,srcDir:n?.typegen?.srcDir,outDir:n?.typegen?.outDir,assetMap:n?.assetMap,changedFiles:r,runPlugins:!1}).then(()=>p.clear(`scan`)).catch(e=>p.report(`scan`,e)),i.runAllPluginTypegens({cwd:t,config:n,silent:!0,changedFiles:r,watch:!0}).then(e=>i.writeTypegenArtifacts(s,e,!0)).then(()=>p.clear(`plugins`)).catch(e=>p.report(`plugins`,e)).finally(()=>e.onPassComplete?.()),c&&n&&i.buildAssets(n,{cwd:t,silent:!0}).catch(()=>{})}function x(){let e=v?void 0:{changed:[...g],removed:[..._]},t=y;g.clear(),_.clear(),v=!1,y=!1,b(e,t)}return{assetSrcRoots:c,handleWatchEvent(e,t){if(!h&&!u(t).includes(`/.kickjs/`)){if(e===`unlinkDir`)v=!0,l&&(y=!0);else{if(t.endsWith(`.d.ts`))return;let n=/\.(ts|tsx|mts|cts)$/.test(t),r=f(t);if(!n&&!r)return;r&&l&&(y=!0),n&&(e===`unlink`?(_.add(t),g.delete(t)):(g.add(t),_.delete(t)))}m&&clearTimeout(m),m=setTimeout(x,r)}},runOnce(){h||b(void 0,l)},dispose(){h=!0,m&&clearTimeout(m),m=null}}}function Hn(e){let t=M(e,`node_modules`,`.bin`),n=process.platform===`win32`;for(let e of[`vue-tsc`,`tsgo`,`tsc`]){let r=n?[`${e}.CMD`,`${e}.cmd`,`${e}.exe`]:[e];for(let i of r){let r=M(t,i);if(O(r))return{cmd:r,args:[`--noEmit`],shell:n,kind:e}}}return null}function Un(e){let t=e.spawnFn??He,n=null,r=0,i=!1;return{schedule(){if(i)return;let a=++r;n&&=(n.kill(),null);let o=Date.now(),s=t(e.bin.cmd,e.bin.args,{cwd:e.cwd,shell:e.bin.shell,stdio:[`ignore`,`pipe`,`pipe`]});n=s;let c=``;s.stdout?.on(`data`,e=>{c+=e.toString()}),s.stderr?.on(`data`,e=>{c+=e.toString()}),s.on(`error`,()=>{a===r&&(n=null)}),s.on(`close`,t=>{i||a!==r||(n=null,e.onResult({ok:t===0,output:c,durationMs:Date.now()-o,kind:e.bin.kind}))})},dispose(){i=!0,n&&=(n.kill(),null)}}}function Wn(e,t=12){let n=e.trim().split(/\r?\n/);return n.length<=t?n.join(`
|
|
1294
1294
|
`):`${n.slice(0,t).join(`
|
|
1295
1295
|
`)}\n… ${n.length-t} more line(s)`}function Gn(e){if(typeof e==`boolean`)return e;let t=process.env.KICKJS_WATCH_POLLING;return t===`1`||t===`true`}async function Kn(e,t=`127.0.0.1`){let n=await import(`node:inspector`);n.open(e,t,!1);let r=n.url();if(!r)throw Error(`inspector.open() reported no URL`);return r}async function qn(e,t,n={}){t&&(process.env.PORT=t);let r=Gn(n.polling),i=process.cwd(),a=await l(i),o=a?.typegen?.schemaValidator??`zod`,s=a?.typegen?.envFile;try{await we({cwd:i,allowDuplicates:!0,schemaValidator:o,envFile:s,srcDir:a?.typegen?.srcDir,outDir:a?.typegen?.outDir,assetMap:a?.assetMap,runPlugins:!1})}catch(e){console.warn(` kick typegen: skipped (${e?.message??e})`)}let c=P(i,a?.typegen?.outDir??`.kickjs/types`);try{let e=await zn({cwd:i,config:a});await _e(c,e,!1)}catch(e){console.warn(` kick typegen: plugin pass skipped (${e?.message??e})`)}let{createRequire:u}=await import(`node:module`),d=u(P(`package.json`)).resolve(`vite`),{createServer:f}=await import(F(d).href);globalThis.__kickjs_typegen_owner=`kick-dev`;let p=await f({configFile:P(`vite.config.ts`),server:{port:t?parseInt(t,10):void 0,...r?{watch:{usePolling:!0,interval:100}}:{}}}),m=n.typecheck??a?.dev?.typecheck??!1,h=null,g=!0;if(m){let e=Hn(i);e?h=Un({cwd:i,bin:e,onResult:e=>{p.hot.send({type:`custom`,event:`kickjs:typecheck`,data:{ok:e.ok,output:e.output,durationMs:e.durationMs}}),e.ok?g||(g=!0,console.log(` kick typecheck: clean again (${e.kind}, ${e.durationMs}ms)`)):(g=!1,console.warn(`\n kick typecheck (${e.kind}, ${e.durationMs}ms):`),console.warn(Wn(e.output).replace(/^/gm,` `)))}}):console.warn(` kick dev: --typecheck requested but neither tsgo (@typescript/native-preview) nor typescript is installed in this project — skipping type checks.`)}let _=Vn({cwd:i,config:a,emitWarning:e=>{console.warn(e),p.hot.send({type:`custom`,event:`kickjs:typegen-error`,data:{message:e,timestamp:Date.now()}})},onPassComplete:()=>h?.schedule()});p.watcher.on(`add`,e=>_.handleWatchEvent(`add`,e)),p.watcher.on(`unlink`,e=>_.handleWatchEvent(`unlink`,e)),p.watcher.on(`change`,e=>_.handleWatchEvent(`change`,e)),p.watcher.on(`unlinkDir`,e=>_.handleWatchEvent(`unlinkDir`,e)),_.assetSrcRoots.length>0&&p.watcher.add([..._.assetSrcRoots]),await p.listen(),p.printUrls(),console.log(`
|
|
1296
1296
|
KickJS dev server running (Vite + @forinda/kickjs-vite)
|
|
@@ -1307,7 +1307,7 @@ describe('${o}', () => {
|
|
|
1307
1307
|
`)}),e.command(`build:assets`).description(`Rebuild the .kickjs-assets.json manifest under the configured outDir (no JS rebuild)`).action(async()=>{let e=await l(process.cwd());if(!e?.assetMap||Object.keys(e.assetMap).length===0){console.log(` No assetMap entries — nothing to build.`);return}console.log(`
|
|
1308
1308
|
Building asset map...`);try{await Ae(e,{cwd:process.cwd()}),console.log(`
|
|
1309
1309
|
Asset build complete.
|
|
1310
|
-
`)}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)),
|
|
1310
|
+
`)}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)),i(e.entry,t)}),e.command(`typecheck`).description(`Type-check the project with its own tsgo/tsc`).option(`--cwd <dir>`,`Directory to type-check`,`.`).option(`--no-typegen`,`Skip refreshing .kickjs/types first`).action(async e=>{let t=P(process.cwd(),e.cwd??`.`);e.typegen!==!1&&await Jn(t);let n=Hn(t);if(!n){console.error(`
|
|
1311
1311
|
No type-checker found. Install one in this project:
|
|
1312
1312
|
pnpm add -D typescript (tsc)
|
|
1313
1313
|
pnpm add -D @typescript/native-preview (tsgo, faster)
|
|
@@ -1622,7 +1622,7 @@ server.on('exit', () => {
|
|
|
1622
1622
|
Cancelled.
|
|
1623
1623
|
`);return}await qe(c,{recursive:!0,force:!0}),console.log(` Deleted: ${c}`);let l=M(n,`index.ts`);if(await b(l)){let e=await I(l,`utf-8`),t=e,n=RegExp(`^import\\s*\\{\\s*${H(o)}Module\\s*\\}\\s*from\\s*['"][^'"]*${H(s)}(?:/[^'"]*)?['"].*\\n?`,`gm`);e=e.replace(n,``),e=Rr(e,o),e=e.replace(/\n{3,}/g,`
|
|
1624
1624
|
|
|
1625
|
-
`),e!==t&&(await L(l,e,`utf-8`),console.log(` Unregistered: ${o}Module from ${l}`))}console.log(`\n Module '${s}' removed.\n`)}function Br(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=await l(process.cwd()),r=p(n),i=t.modulesDir??r.dir??`src/modules`,a=t.pluralize===!1?!1:r.pluralize??!0;for(let n of e)await zr({name:n,modulesDir:P(i),force:t.force,pluralize:a})})}function Vr(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 Hr(e){if(e!==void 0)return e===`false`||e===`off`||e===`none`?!1:e}function Ur(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: exit non-zero if any generated file in .kickjs/types/ is out of date (routes, env, db, assets, adopter plugins) instead of writing it`).option(`--fix`,`Patch module import.meta.glob() calls to cover decorated classes that aren't loaded by any glob (orphans)`).option(`--list`,"List every registered typegen plugin id (use to populate `typegen.disable`)").option(`--no-cache`,`Disable the persistent scan cache; re-read + re-extract every file from cold`).action(async e=>{let t=E(process.cwd()),n=await l(t);if(e.list){let{mergeCliPlugins:e}=await import(`./plugin-
|
|
1625
|
+
`),e!==t&&(await L(l,e,`utf-8`),console.log(` Unregistered: ${o}Module from ${l}`))}console.log(`\n Module '${s}' removed.\n`)}function Br(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=await l(process.cwd()),r=p(n),i=t.modulesDir??r.dir??`src/modules`,a=t.pluralize===!1?!1:r.pluralize??!0;for(let n of e)await zr({name:n,modulesDir:P(i),force:t.force,pluralize:a})})}function Vr(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 Hr(e){if(e!==void 0)return e===`false`||e===`off`||e===`none`?!1:e}function Ur(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: exit non-zero if any generated file in .kickjs/types/ is out of date (routes, env, db, assets, adopter plugins) instead of writing it`).option(`--fix`,`Patch module import.meta.glob() calls to cover decorated classes that aren't loaded by any glob (orphans)`).option(`--list`,"List every registered typegen plugin id (use to populate `typegen.disable`)").option(`--no-cache`,`Disable the persistent scan cache; re-read + re-extract every file from cold`).action(async e=>{let t=E(process.cwd()),n=await l(t);if(e.list){let{mergeCliPlugins:e}=await import(`./plugin-MfCs1kvG.mjs`).then(e=>e.t),{builtinCliPlugins:t}=await Promise.resolve().then(()=>ao),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(`
|
|
1626
1626
|
Registered typegen plugins:
|
|
1627
1627
|
`);for(let e of r.typegens){let t=i.has(e.id)?` (disabled)`:``,n=`${e.id.replace(/\//g,`__`)}${e.outExtension??`.d.ts`}`;console.log(` ${e.id.padEnd(a+2)}→ .kickjs/types/${n}${t}`),console.log(` ${` `.repeat(a+2)} watches: ${e.inputs.join(`, `)||`(none)`}`)}console.log(`
|
|
1628
1628
|
Disable one in kick.config.ts:
|
|
@@ -1653,7 +1653,7 @@ holding the whole environment the suite should run against
|
|
|
1653
1653
|
(a var you leave out is then missing, not inherited), or set KICKJS_ENV_FILE=off
|
|
1654
1654
|
and supply env from the test runner.`}}const Ii=[()=>_i(),vi,yi,xi,Si,Ti,Ei,Di,Fi,Ai];async function Li(e,t={}){let n={cwd:e,pkg:li(M(e,`package.json`)),tsconfig:fi(e),runtime:t.runtime??`express`},r=[...Ii,...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 Ri(e){switch(e){case`pass`:return C.green(`✔`);case`warn`:return C.yellow(`⚠`);case`fail`:return C.red(`✖`)}}function zi(e){let t=Ri(e.status),n=e.message?` ${C.dim(`(${e.message})`)}`:``;return`${t} ${e.name}${n}`}function Bi(e){return e.split(`
|
|
1655
1655
|
`).map(e=>` ${C.dim(`→`)} ${e}`).join(`
|
|
1656
|
-
`)}function Vi(e){return e?.doctor?.checks??[]}function Hi(e){e.command(`doctor`).description(`Pre-flight checks for your KickJS project (dev environment health)`).action(async()=>{let e=process.cwd(),t=Vi(await l(e)),n=await
|
|
1656
|
+
`)}function Vi(e){return e?.doctor?.checks??[]}function Hi(e){e.command(`doctor`).description(`Pre-flight checks for your KickJS project (dev environment health)`).action(async()=>{let e=process.cwd(),t=Vi(await l(e)),n=await r(e);te(`KickJS Doctor`);let i=await Li(e,{extraChecks:t,runtime:n});for(let e of i)x.message(zi(e)),e.fix&&e.status!==`pass`&&x.message(Bi(e.fix));let a=i.filter(e=>e.status===`pass`).length,o=i.filter(e=>e.status===`warn`).length,s=i.filter(e=>e.status===`fail`).length,c=[C.green(`${a} passed`),o>0?C.yellow(`${o} warning${o===1?``:`s`}`):`${o} warnings`,s>0?C.red(`${s} error${s===1?``:`s`}`):`${s} errors`].join(`, `);s>0?(T(`${c} — fix the errors above before running the app`),process.exit(1)):T(o>0?`${c} — review the warnings`:C.green(`${c} — your environment looks good`))})}function Ui(e){return e.optsWithGlobals().dryRun??!1}function Wi(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.
|
|
1657
1657
|
Direction defaults to \`modules.style\` from kick.config (or "define").
|
|
1658
1658
|
--target define|class Override the migration direction.
|
|
1659
1659
|
--apply Apply the changes (default: dry-run preview).
|
|
@@ -1662,7 +1662,16 @@ and supply env from the test runner.`}}const Ii=[()=>_i(),vi,yi,xi,Si,Ti,Ei,Di,F
|
|
|
1662
1662
|
The regex-based rewrite handles the shapes our templates produce.
|
|
1663
1663
|
Hand-rolled modules with non-standard structures may be skipped.
|
|
1664
1664
|
Always commit before running with --apply.
|
|
1665
|
-
`),process.exit(1));let r=await l(process.cwd()),i=p(r),a=P(e.modulesDir??i.dir??`src/modules`),o;e.target===`define`||e.target===`class`?o=e.target:e.target===void 0?o=i.style??`define`:(console.error(`\n ${C.red(`Error:`)} --target must be 'define' or 'class' (got '${e.target}').\n`),process.exit(1));let s=C.dim(`→ ${o}`),c=n?C.dim(`(dry-run)`):C.bold(`(applying)`);console.log(`\n ${C.bold(`kick codemod modules`)} ${s} ${c}`),console.log(` modulesDir: ${C.dim(a)}\n`);let u=e.backup!==!1&&!n,d=await mn(a,{dryRun:n,target:o,backup:u});if(d.backupDir){let e=d.backupDir;console.log(` ${C.green(`✓`)} backup: ${C.dim(e)}\n ${C.dim(`(restore: rm -rf <modulesDir> && mv "<backup>" <modulesDir>)`)}\n`)}else!n&&e.backup===!1&&console.log(` ${C.dim(`(--no-backup — skipping snapshot)`)}\n`);let f=0,m=0;for(let e of d.files)if(e.status===`migrated`)f++,console.log(` ${C.green(`✓`)} ${e.path}`);else{m++;let t=C.dim(`(${e.reason??`skipped`})`);console.log(` ${C.dim(`-`)} ${e.path} ${t}`)}if(console.log(),d.indexStatus===`migrated`)console.log(` ${C.green(`✓`)} ${d.indexPath}`);else if(d.indexStatus===`skipped`){let e=C.dim(`(${d.indexReason??`skipped`})`);console.log(` ${C.dim(`-`)} ${d.indexPath} ${e}`)}else console.log(` ${C.dim(`-`)} ${d.indexPath} ${C.dim(`(not found)`)}`);let h=n?C.dim(` (dry-run — pass --apply to write)`):``;console.log(`\n ${C.bold(String(f))} migrated, ${C.bold(String(m))} skipped${h}\n`)})}
|
|
1665
|
+
`),process.exit(1));let r=await l(process.cwd()),i=p(r),a=P(e.modulesDir??i.dir??`src/modules`),o;e.target===`define`||e.target===`class`?o=e.target:e.target===void 0?o=i.style??`define`:(console.error(`\n ${C.red(`Error:`)} --target must be 'define' or 'class' (got '${e.target}').\n`),process.exit(1));let s=C.dim(`→ ${o}`),c=n?C.dim(`(dry-run)`):C.bold(`(applying)`);console.log(`\n ${C.bold(`kick codemod modules`)} ${s} ${c}`),console.log(` modulesDir: ${C.dim(a)}\n`);let u=e.backup!==!1&&!n,d=await mn(a,{dryRun:n,target:o,backup:u});if(d.backupDir){let e=d.backupDir;console.log(` ${C.green(`✓`)} backup: ${C.dim(e)}\n ${C.dim(`(restore: rm -rf <modulesDir> && mv "<backup>" <modulesDir>)`)}\n`)}else!n&&e.backup===!1&&console.log(` ${C.dim(`(--no-backup — skipping snapshot)`)}\n`);let f=0,m=0;for(let e of d.files)if(e.status===`migrated`)f++,console.log(` ${C.green(`✓`)} ${e.path}`);else{m++;let t=C.dim(`(${e.reason??`skipped`})`);console.log(` ${C.dim(`-`)} ${e.path} ${t}`)}if(console.log(),d.indexStatus===`migrated`)console.log(` ${C.green(`✓`)} ${d.indexPath}`);else if(d.indexStatus===`skipped`){let e=C.dim(`(${d.indexReason??`skipped`})`);console.log(` ${C.dim(`-`)} ${d.indexPath} ${e}`)}else console.log(` ${C.dim(`-`)} ${d.indexPath} ${C.dim(`(not found)`)}`);let h=n?C.dim(` (dry-run — pass --apply to write)`):``;console.log(`\n ${C.bold(String(f))} migrated, ${C.bold(String(m))} skipped${h}\n`)})}function Gi(e,t=O){let n=j(e);return(t(P(n,`pnpm-workspace.yaml`))||t(P(n,`package.json`)))&&t(P(n,`web`,`package.json`))?{staticDir:`../web/dist`,siteRoot:`..`,apiPath:`/api`}:{siteRoot:`.`,apiPath:``}}function Ki(e,t,n){let r=Gi(t,n),i=e?.staticDir===!1?void 0:e?.staticDir??r.staticDir;return{entry:e?.entry??`src/serverless.ts`,outDir:e?.outDir??`dist/serverless`,staticDir:i,siteRoot:e?.siteRoot??r.siteRoot,publishDir:e?.publishDir??`dist/public`,apiPath:e?.apiPath??r.apiPath,external:e?.external??[`valibot`,`yup`],vercelRuntime:e?.vercelRuntime??`nodejs22.x`}}function qi(e,t){return`import { handler } from '${e}'
|
|
1666
|
+
|
|
1667
|
+
export default (request) => handler.fetch(request)
|
|
1668
|
+
|
|
1669
|
+
export const config = {
|
|
1670
|
+
path: '${t}/*',
|
|
1671
|
+
}
|
|
1672
|
+
`}function Ji(e){return/^\s*publish\s*=\s*["']([^"']+)["']/m.exec(e)?.[1]?.replace(/^\.\//,``).replace(/\/+$/,``)}function Yi(e,t){let n=[{handle:`filesystem`},{src:`^${e}/(.*)$`,dest:`/api`}];return t&&n.push({src:`^/(.*)$`,dest:`/index.html`}),n}function Xi(e){let t=e=>{if(typeof e==`string`)return e;if(!e||typeof e!=`object`)return;let n=e;for(let e of[`import`,`module`,`node`,`default`]){let r=t(n[e]);if(r)return r}},n=e.exports;return t(typeof n==`string`||Array.isArray(n)?n:n?.[`.`]??n)??e.module??e.main}async function Zi(e,t){let{createRequire:n}=await import(`node:module`),r=n(P(e,`package.json`)),i;try{i=r.resolve(`${t}/package.json`)}catch{i=P(e,`node_modules`,t,`package.json`)}if(!O(i))throw Error(`${t} is not installed in this project. Run: pnpm add -D vite unplugin-swc @forinda/kickjs-vite`);let a=Xi(JSON.parse(k(i,`utf-8`)));if(!a)throw Error(`${t} has no importable entry point`);return import(F(P(j(i),a)).href)}async function Qi(e,t,n){let r=P(e,t.entry);if(!O(r))throw Error(`${t.entry} not found. The serverless entry exports \`handler = createHandler({ modules })\` — see the Serverless guide.`);let{build:i}=await Zi(e,`vite`),{default:a}=await Zi(e,`unplugin-swc`),{devtoolsFlagPlugin:o,devtoolsStripPlugin:s}=await Zi(e,`@forinda/kickjs-vite`);await i({configFile:!1,root:e,logLevel:`warn`,oxc:!1,plugins:[a.vite(),o(),s()],resolve:{alias:{"@":P(e,`src`)}},ssr:{noExternal:!0,target:`node`},build:{ssr:!0,target:`node20`,outDir:P(e,t.outDir),emptyOutDir:!0,minify:!1,rollupOptions:{input:r,external:t.external.filter(t=>!O(P(e,`node_modules`,t))),output:{format:`esm`,entryFileNames:`server.mjs`,codeSplitting:!1}}}});let c=P(e,t.outDir,`server.mjs`);return n(`bundled ${N(process.cwd(),c)}`),c}function $i(e,t){let n=t.projectRoot,r=()=>Ki(t.config?.deploy,n);e.command(`build:netlify`).description(`Bundle the serverless entry and write the Netlify function`).action(async()=>{let e=r(),i=await Qi(n,e,t.log),a=P(n,e.siteRoot),o=P(a,`.netlify/v1/functions`);Ne(o,{recursive:!0});let s=N(o,i).split(ze).join(`/`);Le(P(o,`api.mjs`),qi(s,e.apiPath)),t.log(`wrote ${N(process.cwd(),P(o,`api.mjs`))}`);let c=e.staticDir??e.publishDir;e.staticDir||(Ne(P(n,c),{recursive:!0}),t.log(`publish directory ready at ${N(process.cwd(),P(n,c))}`));let l=P(a,`netlify.toml`);if(O(l)){let e=Ji(k(l,`utf-8`)),r=N(a,P(n,c)).split(ze).join(`/`);e!==void 0&&e!==r&&t.log(`warning: netlify.toml publishes "${e}", but this build fills "${r}". Update netlify.toml, or set \`deploy.publishDir\` / \`deploy.staticDir\` to match.`)}}),e.command(`build:vercel`).description(`Bundle the serverless entry and write .vercel/output (Build Output API v3)`).action(async()=>{let e=r(),i=await Qi(n,e,t.log),a=P(n,e.siteRoot),o=e.staticDir?P(n,e.staticDir):void 0,s=P(a,`.vercel/output`),c=P(s,`functions/api.func`);if(Fe(s,{recursive:!0,force:!0}),Ne(c,{recursive:!0}),Me(i,P(c,`server.mjs`)),Le(P(c,`index.mjs`),`import { handler } from './server.mjs'
|
|
1673
|
+
export default handler.node
|
|
1674
|
+
`),Le(P(c,`.vc-config.json`),`${JSON.stringify({runtime:e.vercelRuntime,handler:`index.mjs`,launcherType:`Nodejs`,supportsResponseStreaming:!0},null,2)}\n`),o){if(!O(o))throw Error(`build:vercel: ${e.staticDir} does not exist — build the frontend first`);Me(o,P(s,`static`),{recursive:!0})}Le(P(s,`config.json`),`${JSON.stringify({version:3,routes:Yi(e.apiPath,!!o)},null,2)}\n`),t.log(`wrote ${N(process.cwd(),s)}`)})}const ea=()=>({id:`kick/assets`,inputs:[`kick.config.ts`,`kick.config.js`,`kick.config.mjs`],async generate(e){let t=A.resolve(e.cwd,`kick.config.ts`);if(!O(t))return null;let n=await l(e.cwd);if(!n?.assetMap)return null;let r=ue(n.assetMap,e.cwd);return r.count===0?null:be(r)}}),ta="/* 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 na(e,t,n,r={}){if(e.length===0)return`${ta}
|
|
1666
1675
|
// (no routes discovered yet — annotate a controller method with
|
|
1667
1676
|
// @Get/@Post/@Put/@Delete/@Patch and re-run \`kick typegen\`)
|
|
1668
1677
|
declare global {
|
|
@@ -1679,14 +1688,14 @@ declare global {
|
|
|
1679
1688
|
|
|
1680
1689
|
/** Empty until the first route exists — see kick typegen. */
|
|
1681
1690
|
export const kickRpc = {} as const
|
|
1682
|
-
`;let i=new Map;for(let t of e){let e=i.get(t.controller)??[];e.push(t),i.set(t.controller,e)}let a=new Map,o=new Map,s=e=>{let t=`${e.filePath}::${e.controller}`,n=o.get(t);return n||(n=`_C${o.size}`,o.set(t,n)),n},c=(e,i,o)=>{let s=
|
|
1691
|
+
`;let i=new Map;for(let t of e){let e=i.get(t.controller)??[];e.push(t),i.set(t.controller,e)}let a=new Map,o=new Map,s=e=>{let t=`${e.filePath}::${e.controller}`,n=o.get(t);return n||(n=`_C${o.size}`,o.set(t,n)),n},c=(e,i,o)=>{let s=oa(e,i.filePath,t,n,a);if(!s){if(e&&n!==!1){let t=o===`params`?`URL-pattern params`:o===`query`&&i.queryFilterable!==null?`the @ApiQueryParams-derived query shape`:`'unknown'`;r.onWarn?.(`route ${i.controller}.${i.method} (${i.httpMethod} ${i.path}): ${o} schema '${e.identifier}' could not be statically resolved — falling back to ${t}. Export the schema from the controller file or import it with a static specifier.`)}return null}return n===`kickjs-schema`?`import('@forinda/kickjs-schema').InferSchemaOutput<typeof ${s}>`:`import('zod').infer<typeof ${s}>`},l=[];for(let[e,t]of i){let n=[` interface ${e} {`];for(let e of t){let t=e.pathParams.length>0?`{ ${e.pathParams.map(e=>`${e}: string`).join(`; `)} }`:`{}`,r=c(e.bodySchema,e,`body`),i=c(e.querySchema,e,`query`),a=c(e.paramsSchema,e,`params`)??t,o=r??`unknown`,l=i??ia(e),u=c(e.responseSchema??null,e,`response`),d=s(e),f=u??`import('@forinda/kickjs').InferHandlerResponse<${d}['${e.method}']>`,p=aa(e);n.push(` /**`,` * ${e.httpMethod} ${e.path}`,...p.map(e=>` * ${e}`),` */`,` ${e.method}: {`,` params: ${a}`,` body: ${o}`,` query: ${l}`,` response: ${f}`,` contextKeys: ${ra(e)}`,` }`)}n.push(` }`),l.push(n.join(`
|
|
1683
1692
|
`))}let u=[],d=new Set,f=new Set;i.has(`Api`)&&r.onWarn?.(`controller class 'Api' collides with the reserved KickRoutes.Api client map — its interface declaration-merges into the flat route map. Rename the controller.`);for(let[e,t]of i)for(let n of t){let t=`${n.httpMethod} ${n.mountedPath??n.path}`;if(d.has(t)){r.onWarn?.(`duplicate route '${t}' (${e}.${n.method}) — two handlers claim the same verb+path at runtime. KickRoutes.Api keeps the first (scan order, which may not match runtime dispatch); resolve the conflict in the modules.`);continue}d.add(t),f.add(`${e}.${n.method}`),u.push(` '${t}': ${e}['${n.method}']`)}let p=[` interface Api {`,...u,` }`].join(`
|
|
1684
|
-
`);l.push(p);let m=[],h=new Set;for(let[e,t]of i){let n=
|
|
1693
|
+
`);l.push(p);let m=[],h=new Set;for(let[e,t]of i){let n=la(e);if(h.has(n)){r.onWarn?.(`RPC manifest: controller key '${n}' (from ${e}) collides with another controller — keeping the first; rename one class for distinct RPC namespaces.`);continue}h.add(n);let i=[];for(let n of t){if(!f.has(`${e}.${n.method}`))continue;let t=`${n.httpMethod} ${n.mountedPath??n.path}`;i.push(` ${n.method}: '${t}',`)}i.length>0&&m.push(` ${n}: {\n${i.join(`
|
|
1685
1694
|
`)}\n },`)}let g=[`/**`,` * Runtime route manifest for the tRPC-style sugar:`," * `createRpc(api, kickRpc)` from @forinda/kickjs-client.",` */`,`export const kickRpc = {`,...m,`} as const`].join(`
|
|
1686
|
-
`),_=[],v=new Map;for(let t of e)v.set(`${t.filePath}::${t.controller}`,t);for(let[e,n]of o){let r=v.get(e),i
|
|
1695
|
+
`),_=[],v=new Map;for(let t of e)v.set(`${t.filePath}::${t.controller}`,t);for(let[e,n]of o){let r=v.get(e),i=ca(``,r.filePath,t),a=r.controllerIsDefaultExport?`default as ${n}`:`${r.controller} as ${n}`;_.push(`import type { ${a} } from '${i}'`)}let y=_.length>0?_.join(`
|
|
1687
1696
|
`)+`
|
|
1688
|
-
`:``,b=
|
|
1689
|
-
`);return`${
|
|
1697
|
+
`:``,b=sa(a)+y,x=l.join(`
|
|
1698
|
+
`);return`${ta}${b}
|
|
1690
1699
|
declare global {
|
|
1691
1700
|
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
1692
1701
|
namespace KickRoutes {
|
|
@@ -1698,18 +1707,18 @@ ${x}
|
|
|
1698
1707
|
}
|
|
1699
1708
|
|
|
1700
1709
|
${g}
|
|
1701
|
-
`}function
|
|
1710
|
+
`}function ra(e){let t=e.contextKeys;return t==null?`string`:t.length===0?`never`:t.map(e=>JSON.stringify(e)).join(` | `)}function ia(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 aa(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 oa(e,t,n,r,i){if(!e||r===!1||e.source===null)return null;let a=ca(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 sa(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(`
|
|
1702
1711
|
`)+`
|
|
1703
|
-
`}function
|
|
1704
|
-
TypeScript 7 does not ship a compiler API, so the compatibility package is required.\n ${t}`):Error(`kick typegen: the client route map needs a TypeScript compiler API, and neither 'typescript' nor '${
|
|
1712
|
+
`}function ca(e,t,n){if(e===null)return`unknown`;let r=j(n);if(e===``){let e=N(r,t).split(ze).join(`/`);return e=e.replace(/\.(ts|tsx|mts|cts)$/i,``),e.startsWith(`.`)||(e=`./`+e),e}if(!e.startsWith(`.`)&&!e.startsWith(`/`))return e;let i=j(t),a=P(i,e),o=N(r,a).split(ze).join(`/`);return o=o.replace(/\.(ts|tsx|mts|cts)$/i,``),o.startsWith(`.`)||(o=`./`+o),o}function la(e){let t=e.endsWith(`Controller`)?e.slice(0,-10):e,n=t.length>0?t:e;return n.charAt(0).toLowerCase()+n.slice(1)}const ua=()=>({id:`kick/routes`,outExtension:`.ts`,inputs:[`src/**/*.controller.ts`,`src/**/*.module.ts`],async generate(e){let t=await e.getScanResult({root:da(e),cwd:e.cwd,envFile:fa(e)}),n=e.config?.typegen?.schemaValidator??`zod`,r=A.resolve(e.cwd,`.kickjs/types/kick__routes.ts`);return na(t.routes,r,n,{onWarn:t=>e.log.warn(t)})}});function da(e){return A.resolve(e.cwd,e.config?.typegen?.srcDir??`src`)}function fa(e){let t=e.config?.typegen?.envFile;if(t!==!1)return t}const pa=`@typescript/typescript6`;function ma(e){return typeof e?.createProgram==`function`}function ha(e){if(ma(e.typescript))return{api:e.typescript,source:`typescript`};if(ma(e.ts6))return{api:e.ts6,source:pa};let t=`Install it in the project:\n pnpm add -D ${pa}`;throw e.typescript?Error(`kick typegen: the client route map needs a TypeScript compiler API.
|
|
1713
|
+
TypeScript 7 does not ship a compiler API, so the compatibility package is required.\n ${t}`):Error(`kick typegen: the client route map needs a TypeScript compiler API, and neither 'typescript' nor '${pa}' resolved from this project.\n ${t}`)}async function ga(e){let t=je(M(e,`package.json`)),n=async e=>{try{return await import(F(t.resolve(e)).href)}catch{return null}},[r,i]=await Promise.all([n(`typescript`),n(pa)]);return ha({typescript:_a(r),ts6:_a(i)}).api}function _a(e){let t=e;return t?.default&&typeof t.default==`object`?t.default:e}const va=Symbol(`kick/client: expansion budget exhausted`);var ya=class{ts;checker;program;opts;get printFlags(){return this.ts.TypeFormatFlags.NoTruncation}hoistedByType=new Map;inProgress=new Map;jsonInProgress=new Set;nextName=0;blocks=[];maxDepth;truncations=0;budget;constructor(e,t,n,r={}){this.ts=e,this.checker=t,this.program=n,this.opts=r,this.maxDepth=r.maxDepth??12,this.budget=r.truncationBudget??1e3}hoisted(){return this.blocks}expand(e){this.truncations=0;try{return this.render(e,0)}catch(e){if(e!==va)throw e;return this.opts.onWarn?.(`expansion abandoned after ${this.budget} truncations — emitting 'unknown'. This usually means a recursive type. Declare a response schema on the route for an exact type.`),`unknown`}}render(e,t){let n=this.ts.TypeFlags;if(t>this.maxDepth){if(++this.truncations>this.budget)throw va;return this.opts.onWarn?.(`type nesting exceeded ${this.maxDepth} levels — emitting 'unknown'. Declare a response schema on the route for an exact type.`),`unknown`}if(e.flags&(n.String|n.Number|n.Boolean|n.BigInt|n.ESSymbol)||e.flags&(n.Any|n.Unknown|n.Never|n.Void|n.Undefined|n.Null)||e.isLiteral()||e.flags&n.BooleanLiteral)return this.checker.typeToString(e,void 0,this.printFlags);if(e.isUnion()){let n=e.types.filter(e=>!this.isCallable(e));return(n.length>0?n:e.types).map(e=>this.render(e,t+1)).join(` | `)}if(e.isIntersection())return e.types.map(e=>this.render(e,t+1)).join(` & `);if(this.isTuple(e))return this.renderTuple(e,t);let r=this.arrayElement(e);if(r){let e=this.render(r.element,t+1),n=/[|&]/.test(e)?`(${e})[]`:`${e}[]`;return r.readonly?`readonly ${n}`:n}let i=this.toJsonType(e);if(i){if(this.jsonInProgress.has(e))return this.opts.onWarn?.(`'${this.checker.typeToString(e,void 0,this.printFlags)}' has a cyclic toJSON() — emitting 'unknown', since it has no serializable form.`),`unknown`;this.jsonInProgress.add(e);try{return this.render(i,t)}finally{this.jsonInProgress.delete(e)}}return this.isLibType(e)?this.renderLibType(e,t):e.flags&n.Object?this.renderObject(e,t):(this.opts.onWarn?.(`could not expand type '${this.checker.typeToString(e)}' — emitting 'unknown'`),`unknown`)}renderObject(e,t){let n=this.hoistedByType.get(e);if(n)return n;if(this.isNamed(e)){let t=this.allocName();this.hoistedByType.set(e,t);let n=this.blocks.length;return this.blocks.push(``),this.blocks[n]=`interface ${t} {\n${this.members(e,0,` `)}\n}`,t}let r=this.inProgress.get(e);if(r)return r.name??=this.allocName();let i={name:null};this.inProgress.set(e,i);let a;try{a=this.members(e,t,``,`; `)}finally{this.inProgress.delete(e)}if(i.name){this.hoistedByType.set(e,i.name);let t=this.blocks.length;return this.blocks.push(``),this.blocks[t]=`interface ${i.name} {\n${this.members(e,0,` `)}\n}`,i.name}return a.length>0?`{ ${a} }`:`{}`}allocName(){return`__T${this.nextName++}`}members(e,t,n,r=`
|
|
1705
1714
|
`){let i=[];for(let r of this.checker.getIndexInfosOfType(e)){let e=this.checker.typeToString(r.keyType,void 0,this.printFlags);i.push(`${n}[key: ${e}]: ${this.render(r.type,t+1)}`)}for(let r of this.checker.getPropertiesOfType(e)){let e=this.typeOfProperty(r);if(this.isCallable(e)||r.getName().startsWith(`__@`))continue;let a=(r.flags&this.ts.SymbolFlags.Optional)!==0,o=this.renderPropertyType(e,a,r,t+1),s=this.isReadonlyProp(r)?`readonly `:``;i.push(`${n}${s}${this.propName(r.getName())}${a?`?`:``}: ${o}`)}return i.join(r===`
|
|
1706
1715
|
`?`
|
|
1707
|
-
`:r)}typeOfProperty(e){let t=this.checker;if(typeof t.getTypeOfSymbol==`function`)return t.getTypeOfSymbol(e);let n=e.valueDeclaration??e.declarations?.[0];return n?this.checker.getTypeOfSymbolAtLocation(e,n):this.checker.getDeclaredTypeOfSymbol(e)}renderPropertyType(e,t,n,r){if(!t||!e.isUnion()||this.declaresUndefined(n))return this.render(e,r);let i=e.types.filter(e=>!(e.flags&this.ts.TypeFlags.Undefined));return i.length===0?`undefined`:i.map(e=>this.render(e,r)).join(` | `)}isReadonlyProp(e){let t=e.valueDeclaration??e.declarations?.[0];return t?(this.ts.getCombinedModifierFlags(t)&this.ts.ModifierFlags.Readonly)!==0:!1}declaresUndefined(e){let t=e.valueDeclaration??e.declarations?.[0];if(!t||!(this.ts.isPropertySignature(t)||this.ts.isPropertyDeclaration(t))||!t.type)return!1;let n=this.checker.getTypeFromTypeNode(t.type);return(n.isUnion()?n.types:[n]).some(e=>(e.flags&this.ts.TypeFlags.Undefined)!==0)}renderTuple(e,t){let n=this.ts.ElementFlags,r=this.checker.getTypeArguments(e),i=e.target,a=i.elementFlags??[],o=r.map((e,r)=>{let i=a[r]??n.Required;return i&n.Optional?`${(e.isUnion()?e.types.filter(e=>!(e.flags&this.ts.TypeFlags.Undefined)):[e]).map(e=>this.render(e,t+1)).join(` | `)}?`:i&n.Rest?`...${this.render(e,t+1)}[]`:i&n.Variadic?`...${this.render(e,t+1)}`:this.render(e,t+1)});return`${i.readonly?`readonly `:``}[${o.join(`, `)}]`}propName(e){return/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(e)?e:JSON.stringify(e)}isLibType(e){let t=e.aliasSymbol?.declarations??e.getSymbol()?.declarations;return!t||t.length===0?!1:t.every(e=>this.program.isSourceFileDefaultLibrary(e.getSourceFile()))}renderLibType(e,t){let n=(e.aliasSymbol??e.getSymbol())?.getName(),r=e.aliasTypeArguments??this.typeArguments(e);return!n||r.length===0?this.checker.typeToString(e,void 0,this.printFlags):`${n}<${r.map(e=>this.render(e,t+1)).join(`, `)}>`}typeArguments(e){return!(e.flags&this.ts.TypeFlags.Object)||!(e.objectFlags&this.ts.ObjectFlags.Reference)?[]:this.checker.getTypeArguments(e)}toJsonType(e){if(!(e.flags&this.ts.TypeFlags.Object))return null;let t=this.checker.getPropertyOfType(e,`toJSON`);if(!t)return null;let[n]=this.checker.getSignaturesOfType(this.typeOfProperty(t),this.ts.SignatureKind.Call);if(!n)return null;let r=this.checker.getReturnTypeOfSignature(n);return r===e?null:r}isCallable(e){if(e.isUnion()){let t=e.types.filter(e=>!(e.flags&(this.ts.TypeFlags.Undefined|this.ts.TypeFlags.Null)));return t.length>0&&t.every(e=>this.isCallable(e))}return this.checker.getSignaturesOfType(e,this.ts.SignatureKind.Call).length>0||this.checker.getSignaturesOfType(e,this.ts.SignatureKind.Construct).length>0}isNamed(e){let t=e.getSymbol();if(!t)return!1;let n=t.getName();return n!==`__type`&&n!==`__object`&&n.length>0}isTuple(e){let t=this.ts.ObjectFlags;if(!(e.flags&this.ts.TypeFlags.Object)||!(e.objectFlags&t.Reference))return!1;let n=e.target;return!!(n&&n.objectFlags&t.Tuple)}arrayElement(e){let t=e.getSymbol()?.getName();if(t!==`Array`&&t!==`ReadonlyArray`)return null;let n=this.checker.getTypeArguments(e);return n.length===1?{element:n[0],readonly:t===`ReadonlyArray`}:null}};const
|
|
1708
|
-
`));for(let n of
|
|
1709
|
-
`);throw Error(`${n} has ${i.length} type error(s), so its route types cannot be resolved — every entry would come out as 'any'.\n${a}\n Usually this means dependencies are not installed or the server does not type-check.`)}function
|
|
1716
|
+
`:r)}typeOfProperty(e){let t=this.checker;if(typeof t.getTypeOfSymbol==`function`)return t.getTypeOfSymbol(e);let n=e.valueDeclaration??e.declarations?.[0];return n?this.checker.getTypeOfSymbolAtLocation(e,n):this.checker.getDeclaredTypeOfSymbol(e)}renderPropertyType(e,t,n,r){if(!t||!e.isUnion()||this.declaresUndefined(n))return this.render(e,r);let i=e.types.filter(e=>!(e.flags&this.ts.TypeFlags.Undefined));return i.length===0?`undefined`:i.map(e=>this.render(e,r)).join(` | `)}isReadonlyProp(e){let t=e.valueDeclaration??e.declarations?.[0];return t?(this.ts.getCombinedModifierFlags(t)&this.ts.ModifierFlags.Readonly)!==0:!1}declaresUndefined(e){let t=e.valueDeclaration??e.declarations?.[0];if(!t||!(this.ts.isPropertySignature(t)||this.ts.isPropertyDeclaration(t))||!t.type)return!1;let n=this.checker.getTypeFromTypeNode(t.type);return(n.isUnion()?n.types:[n]).some(e=>(e.flags&this.ts.TypeFlags.Undefined)!==0)}renderTuple(e,t){let n=this.ts.ElementFlags,r=this.checker.getTypeArguments(e),i=e.target,a=i.elementFlags??[],o=r.map((e,r)=>{let i=a[r]??n.Required;return i&n.Optional?`${(e.isUnion()?e.types.filter(e=>!(e.flags&this.ts.TypeFlags.Undefined)):[e]).map(e=>this.render(e,t+1)).join(` | `)}?`:i&n.Rest?`...${this.render(e,t+1)}[]`:i&n.Variadic?`...${this.render(e,t+1)}`:this.render(e,t+1)});return`${i.readonly?`readonly `:``}[${o.join(`, `)}]`}propName(e){return/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(e)?e:JSON.stringify(e)}isLibType(e){let t=e.aliasSymbol?.declarations??e.getSymbol()?.declarations;return!t||t.length===0?!1:t.every(e=>this.program.isSourceFileDefaultLibrary(e.getSourceFile()))}renderLibType(e,t){let n=(e.aliasSymbol??e.getSymbol())?.getName(),r=e.aliasTypeArguments??this.typeArguments(e);return!n||r.length===0?this.checker.typeToString(e,void 0,this.printFlags):`${n}<${r.map(e=>this.render(e,t+1)).join(`, `)}>`}typeArguments(e){return!(e.flags&this.ts.TypeFlags.Object)||!(e.objectFlags&this.ts.ObjectFlags.Reference)?[]:this.checker.getTypeArguments(e)}toJsonType(e){if(!(e.flags&this.ts.TypeFlags.Object))return null;let t=this.checker.getPropertyOfType(e,`toJSON`);if(!t)return null;let[n]=this.checker.getSignaturesOfType(this.typeOfProperty(t),this.ts.SignatureKind.Call);if(!n)return null;let r=this.checker.getReturnTypeOfSignature(n);return r===e?null:r}isCallable(e){if(e.isUnion()){let t=e.types.filter(e=>!(e.flags&(this.ts.TypeFlags.Undefined|this.ts.TypeFlags.Null)));return t.length>0&&t.every(e=>this.isCallable(e))}return this.checker.getSignaturesOfType(e,this.ts.SignatureKind.Call).length>0||this.checker.getSignaturesOfType(e,this.ts.SignatureKind.Construct).length>0}isNamed(e){let t=e.getSymbol();if(!t)return!1;let n=t.getName();return n!==`__type`&&n!==`__object`&&n.length>0}isTuple(e){let t=this.ts.ObjectFlags;if(!(e.flags&this.ts.TypeFlags.Object)||!(e.objectFlags&t.Reference))return!1;let n=e.target;return!!(n&&n.objectFlags&t.Tuple)}arrayElement(e){let t=e.getSymbol()?.getName();if(t!==`Array`&&t!==`ReadonlyArray`)return null;let n=this.checker.getTypeArguments(e);return n.length===1?{element:n[0],readonly:t===`ReadonlyArray`}:null}};const ba=[`pnpm-lock.yaml`,`package-lock.json`,`yarn.lock`,`bun.lock`,`bun.lockb`],xa=/(?:^|[\\/])(?:node_modules|\.kickjs)(?:[\\/]|$)/;function Sa(e){return et(`sha1`).update(e).digest(`hex`)}function Ca(e){let t=et(`sha1`);t.update(e.cliVersion),t.update(JSON.stringify(e.options??{})),t.update(e.keys.join(`
|
|
1717
|
+
`));for(let n of ba){let r=M(e.projectDir,n);if(O(r))try{t.update(k(r))}catch(e){throw Error(`kick/client: cannot read lockfile ${r}`,{cause:e})}}for(let n of e.fileNames.toSorted())if(!xa.test(n)){t.update(n);try{t.update(k(n))}catch(e){throw Error(`kick/client: cannot read project file ${n}`,{cause:e})}}return t.digest(`hex`)}async function wa(e){try{let t=await ga(e.compilerFrom??e.projectDir),n={...t.sys,onUnRecoverableConfigFileDiagnostic:()=>{}},r=t.getParsedCommandLineOfConfigFile(M(e.projectDir,`tsconfig.json`),{},n);return r?Ca({projectDir:e.projectDir,fileNames:r.fileNames,keys:e.keys,options:{...r.options,__kickMaxDepth:e.maxDepth??null},cliVersion:e.cliVersion}):null}catch{return null}}async function Ta(e){let t=await ga(e.compilerFrom??e.projectDir),n=M(j(e.routesFile),`__kick_client_probe__.ts`),r=Oa(e.routesFile,e.keys),i=ja(t,e.projectDir,n,r),a=i.getTypeChecker(),o=i.getSourceFile(n);if(!o)throw Error(`kick/client: could not add the resolution probe to the program. Check that ${e.routesFile} exists — run \`kick typegen\` first.`);Ea(t,i,e.routesFile);let s=ka(t,i,o,e.keys),c=null,l=new ya(t,a,i,{maxDepth:e.maxDepth,onWarn:t=>e.onWarn?.(c?`route '${c}': ${t}`:t)}),u=new Map;for(let[n,r]of e.keys.entries()){if(s.has(r)){e.onWarn?.(`route '${r}' is not present in KickRoutes.Api — skipped. Re-run \`kick typegen\` so the two maps agree.`);continue}let i=o.statements.find(e=>t.isTypeAliasDeclaration(e)&&e.name.text===Da(n));if(!i){e.onWarn?.(`route '${r}' could not be resolved — skipped.`);continue}let d=a.getTypeAtLocation(i.type);if(d.flags&t.TypeFlags.Any){e.onWarn?.(`route '${r}' resolved to 'any' — skipped rather than emitted, since an 'any' entry silently accepts every call. Check that the server type-checks.`);continue}c=r,u.set(r,l.expand(d)),c=null}return{entries:u,hoisted:l.hoisted()}}function Ea(e,t,n){let r=t.getSourceFile(n);if(!r)throw Error(`kick/client: ${n} is not in the TypeScript program. Run \`kick typegen\` first, and check that tsconfig.json includes .kickjs.`);let i=t.getSemanticDiagnostics(r);if(i.length===0)return;let a=i.slice(0,3).map(t=>` ${e.flattenDiagnosticMessageText(t.messageText,` `)}`).join(`
|
|
1718
|
+
`);throw Error(`${n} has ${i.length} type error(s), so its route types cannot be resolved — every entry would come out as 'any'.\n${a}\n Usually this means dependencies are not installed or the server does not type-check.`)}function Da(e){return`_K${e}`}function Oa(e,t){let n=`./`+Re(e).replace(/\.tsx?$/,``),r=t.map((e,t)=>`type ${Da(t)} = KickRoutes.Api[${JSON.stringify(e)}]`);return[`import ${JSON.stringify(n)}`,...r].join(`
|
|
1710
1719
|
`)+`
|
|
1711
|
-
`}function
|
|
1712
|
-
`))}},o=e.getParsedCommandLineOfConfigFile(i,{},a);if(!o)throw Error(`kick/client: could not read ${i}`);let s=e.createCompilerHost(o.options,!0),c=s.readFile.bind(s),l=s.getSourceFile.bind(s),u=s.fileExists.bind(s);return s.readFile=e=>e===n?r:c(e),s.fileExists=e=>e===n||u(e),s.getSourceFile=(t,i,a,o)=>t===n?e.createSourceFile(t,r,i,!0):l(t,i,a,o),e.createProgram({rootNames:[...
|
|
1720
|
+
`}function ka(e,t,n,r){let i=new Set,a=new Map;for(let t of n.statements)e.isTypeAliasDeclaration(t)&&a.set(t.name.text,t);for(let e of t.getSemanticDiagnostics(n))if(e.start!==void 0)for(let[t,o]of r.entries()){let r=a.get(Da(t));r&&e.start>=r.getStart(n)&&e.start<r.getEnd()&&i.add(o)}return i}function Aa(e,t){let n=e.filter(e=>/\.d\.(ts|mts|cts)$/.test(e)),r=[];try{r=Pe(t).filter(e=>e.endsWith(`.ts`)).map(e=>M(t,e))}catch{}return[...new Set([...n,...r])]}function ja(e,t,n,r){let i=M(t,`tsconfig.json`),a={...e.sys,onUnRecoverableConfigFileDiagnostic:t=>{throw Error(e.flattenDiagnosticMessageText(t.messageText,`
|
|
1721
|
+
`))}},o=e.getParsedCommandLineOfConfigFile(i,{},a);if(!o)throw Error(`kick/client: could not read ${i}`);let s=e.createCompilerHost(o.options,!0),c=s.readFile.bind(s),l=s.getSourceFile.bind(s),u=s.fileExists.bind(s);return s.readFile=e=>e===n?r:c(e),s.fileExists=e=>e===n||u(e),s.getSourceFile=(t,i,a,o)=>t===n?e.createSourceFile(t,r,i,!0):l(t,i,a,o),e.createProgram({rootNames:[...Aa(o.fileNames,j(n)),n],options:o.options,host:s})}const Ma=`/* eslint-disable */
|
|
1713
1722
|
// AUTO-GENERATED by \`kick typegen\`. DO NOT EDIT.
|
|
1714
1723
|
//
|
|
1715
1724
|
// Self-contained: this file has no imports, so a frontend consumes it without
|
|
@@ -1723,7 +1732,7 @@ ${g}
|
|
|
1723
1732
|
//
|
|
1724
1733
|
// Not refreshed by \`kick dev\` — resolving these types builds a full
|
|
1725
1734
|
// TypeScript program over the server. Re-run \`kick typegen\`.
|
|
1726
|
-
`;function
|
|
1735
|
+
`;function Na(e,t){let n=t.filter(t=>e.entries.has(t));if(n.length===0)return`${Ma}
|
|
1727
1736
|
// (no routes discovered yet — annotate a controller method with
|
|
1728
1737
|
// @Get/@Post/@Put/@Delete/@Patch and re-run \`kick typegen\`)
|
|
1729
1738
|
interface Api {}
|
|
@@ -1740,7 +1749,7 @@ export type { Api }
|
|
|
1740
1749
|
|
|
1741
1750
|
`)+`
|
|
1742
1751
|
|
|
1743
|
-
`:``,i=n.map(t=>` ${JSON.stringify(t)}: ${e.entries.get(t)}`);return`${
|
|
1752
|
+
`:``,i=n.map(t=>` ${JSON.stringify(t)}: ${e.entries.get(t)}`);return`${Ma}
|
|
1744
1753
|
${r}interface Api {
|
|
1745
1754
|
${i.join(`
|
|
1746
1755
|
`)}
|
|
@@ -1754,7 +1763,7 @@ declare global {
|
|
|
1754
1763
|
}
|
|
1755
1764
|
|
|
1756
1765
|
export type { Api }
|
|
1757
|
-
`}const
|
|
1766
|
+
`}const Pa=`kick/client`,Q=`.kickjs/types/kick__client.d.ts`,Fa=`.kickjs/cache/client-map.sha1`,Ia=(()=>{try{return je(import.meta.url)(`../../../package.json`).version??`0.0.0`}catch{return`0.0.0`}})();function La(e){try{if(!O(e))return null;let[t,n]=k(e,`utf-8`).trim().split(/\s+/);return t&&n?{inputs:t,output:n}:null}catch{return null}}function Ra(e){return`${Pn}${Pa} */\n\n${e}\n`}function za(e){try{return O(e)?k(e,`utf-8`):null}catch{return null}}async function Ba(e){let t=A.resolve(e.cwd,Q);if(!O(t))return!1;try{await qe(t,{force:!0})}catch(t){return e.log.warn(` kick/client: could not remove the stale ${Q} — treat it as out of date (${t instanceof Error?t.message:String(t)})`),!0}return e.log.warn(` kick/client: removed the previously generated ${Q} rather than leave a stale one — re-run \`kick typegen\` once the cause above is fixed.`),!0}function Va(e){let t=e?.typegen?.client;return typeof t==`object`?t.maxDepth:void 0}function Ha(e){let t=e.config?.typegen?.client;return typeof t==`boolean`?t:t&&typeof t==`object`?t.enabled!==!1:(O(A.resolve(e.cwd,Q))&&e.log.warn(` kick/client: ${Q} exists but typegen.client is not set, so it is NOT being refreshed.\n Add \`typegen: { client: true }\` to kick.config.ts to keep it current, or delete the file if nothing reads it.`),!1)}const Ua=()=>({id:Pa,outExtension:`.d.ts`,inputs:[`src/**/*.controller.ts`,`src/**/*.module.ts`],async generate(e){if(!Ha(e))return null;if(e.watch)return e.log.info?.(" kick/client: skipped under watch (builds a full TypeScript program). Run `kick typegen` to refresh the client route map."),null;let t=await e.getScanResult({root:A.resolve(e.cwd,e.config?.typegen?.srcDir??`src`),cwd:e.cwd}),n=[],r=new Set;for(let e of t.routes){let t=`${e.httpMethod} ${e.mountedPath??e.path}`;r.has(t)||(r.add(t),n.push(t))}let i=Va(e.config),a=await wa({projectDir:e.cwd,keys:n,maxDepth:i,cliVersion:Ia}),o=La(A.resolve(e.cwd,Fa)),s=za(A.resolve(e.cwd,Q));if(a&&o&&s!==null&&o.inputs===a&&o.output===Sa(s))return Cn()&&e.log.info?.(` kick/client: unchanged, keeping ${Q}`),null;try{let t=Na(await Ta({projectDir:e.cwd,routesFile:A.resolve(e.cwd,`.kickjs/types/kick__routes.ts`),keys:n,maxDepth:i,onWarn:t=>e.log.warn(t)}),n);return a&&!e.check&&await e.writeFile(Fa,`${a} ${Sa(Ra(t))}`),t}catch(t){let n=O(A.resolve(e.cwd,Q)),r=` kick/client: skipped — ${t instanceof Error?t.message:String(t)}`;return n?e.log.warn(r):Cn()&&e.log.info?.(r),n&&await Ba(e),null}}});function Wa(e,t,n=`zod`){if(!e)return null;let r=j(t),i=N(r,e.filePath).split(ze).join(`/`);return i=i.replace(/\.(ts|tsx|mts|cts)$/i,``),i.startsWith(`.`)||(i=`./`+i),`/* eslint-disable */
|
|
1758
1767
|
// AUTO-GENERATED by \`kick typegen\`. DO NOT EDIT.
|
|
1759
1768
|
// Re-run with \`kick typegen\` or rely on \`kick dev\` to refresh.
|
|
1760
1769
|
|
|
@@ -1792,5 +1801,5 @@ declare global {
|
|
|
1792
1801
|
}
|
|
1793
1802
|
|
|
1794
1803
|
export {}
|
|
1795
|
-
`}const
|
|
1796
|
-
`)}});var
|
|
1804
|
+
`}const Ga=()=>({id:`kick/env`,outExtension:`.ts`,inputs:[`src/env.ts`,`src/**/env.ts`,`src/**/*.env.ts`],async generate(e){let t=qa(e);if(t===!1)return null;let n=await e.getScanResult({root:Ka(e),cwd:e.cwd,envFile:t});if(!n.env)return null;let r=e.config?.typegen?.schemaValidator??`zod`,i=A.resolve(e.cwd,`.kickjs/types/kick__env.ts`);return Wa(n.env,i,r)}});function Ka(e){return A.resolve(e.cwd,e.config?.typegen?.srcDir??`src`)}function qa(e){return e.config?.typegen?.envFile}function Ja(e){return A.resolve(e.cwd,e.config?.typegen?.srcDir??`src`)}function Ya(e){let t=e.config?.typegen?.envFile;if(t!==!1)return t}function $(e){return{root:Ja(e),cwd:e.cwd,envFile:Ya(e)}}const Xa=()=>({id:`kick/registry`,inputs:[`src/**/*.ts`],async generate(e){let t=await e.getScanResult($(e)),n=A.resolve(e.cwd,`.kickjs/types/kick__registry.d.ts`),r=new Set(t.collisions.map(e=>e.className));return xe(t.classes,n,r)}}),Za=()=>({id:`kick/services`,inputs:[`src/**/*.ts`],async generate(e){let t=await e.getScanResult($(e)),n=new Set(t.collisions.map(e=>e.className)),r=ve(t.classes,t.tokens,t.injects,n);return ge(`ServiceToken`,r,"(no tokens discovered — declare with createToken<T>() or `kick g service <name>`)")}}),Qa=()=>({id:`kick/modules`,inputs:[`src/**/*.ts`],async generate(e){let t=await e.getScanResult($(e));return ge(`ModuleToken`,fe(t.classes),"(no @Module classes discovered — `kick g module <name>` to add one)")}}),$a=()=>({id:`kick/plugins`,inputs:[`src/**/*.ts`],async generate(e){let t=await e.getScanResult($(e));return me(t.pluginsAndAdapters)}}),eo=()=>({id:`kick/augmentations`,inputs:[`src/**/*.ts`],async generate(e){let t=await e.getScanResult($(e));return Te(t.augmentations)}}),to=()=>({id:`kick/context`,inputs:[`src/**/*.ts`],async generate(e){let t=await e.getScanResult($(e));return t.contextKeys.length===0?null:pe(t.contextKeys)}}),no=()=>({id:`kick/route-flags`,inputs:[`src/**/*.ts`],async generate(e){let t=await e.getScanResult($(e));return ye(t.routeFlags)}}),ro={fastify:{subpath:`@forinda/kickjs/fastify`,typeName:`FastifyRuntimeTypes`},h3:{subpath:`@forinda/kickjs/h3`,typeName:`H3RuntimeTypes`}},io=()=>({id:`kick/runtime`,outExtension:`.ts`,inputs:[`kick.config.ts`,`kick.config.js`,`kick.config.mjs`,`kick.config.json`],async generate(e){let t=e.config?.runtime;if(t!==`fastify`&&t!==`h3`)return null;let{subpath:n,typeName:r}=ro[t];return[`// Runtime escape-hatch types for the '${t}' engine (kick.config runtime).`,`declare module '@forinda/kickjs' {`,` interface KickRuntimeRegister {`,` runtime: import('${n}').${r}`,` }`,`}`,``,`export {}`,``].join(`
|
|
1805
|
+
`)}});var ao=e({builtinCliPlugins:()=>oo});const oo=[_({name:`kick/init`,register:nt}),_({name:`kick/generate`,register:Mn}),_({name:`kick/run`,register:Yn}),_({name:`kick/info`,register:er}),_({name:`kick/inspect`,register:ur}),_({name:`kick/add`,register:o}),_({name:`kick/list`,register:n}),_({name:`kick/explain`,register:yr}),_({name:`kick/mcp`,register:Ar}),_({name:`kick/tinker`,register:Pr}),_({name:`kick/remove`,register:Br}),_({name:`kick/typegen`,register:Ur}),_({name:`kick/check`,register:ci}),_({name:`kick/doctor`,register:Hi}),_({name:`kick/codemod`,register:Wi}),_({name:`kick/deploy`,register:$i}),_({name:`kick/registry`,typegens:[Xa()]}),_({name:`kick/services`,typegens:[Za()]}),_({name:`kick/modules`,typegens:[Qa()]}),_({name:`kick/plugins`,typegens:[$a()]}),_({name:`kick/augmentations`,typegens:[eo()]}),_({name:`kick/context`,typegens:[to()]}),_({name:`kick/route-flags`,typegens:[no()]}),_({name:`kick/assets`,typegens:[ea()]}),_({name:`kick/routes`,typegens:[ua()]}),_({name:`kick/client`,typegens:[Ua()]}),_({name:`kick/env`,typegens:[Ga()]}),_({name:`kick/runtime`,typegens:[io()]})];export{Rn as n,oo as t};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @forinda/kickjs-cli v8.
|
|
2
|
+
* @forinda/kickjs-cli v8.3.0
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Felix Orinda
|
|
5
5
|
*
|
|
@@ -8,4 +8,4 @@
|
|
|
8
8
|
*
|
|
9
9
|
* @license MIT
|
|
10
10
|
*/
|
|
11
|
-
import{t as e}from"./run-plugins-
|
|
11
|
+
import{t as e}from"./run-plugins-lLfcDAbT.mjs";export{e as builtinCliPlugins};
|