@forinda/kickjs-cli 8.10.2 → 8.12.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-As_KjQBC.mjs → agent-docs-CuD2-X3w.mjs} +30 -26
- package/dist/{agent-docs-ZgfnGL-j.mjs → agent-docs-ykxoPqXX.mjs} +23 -19
- package/dist/agent-docs-ykxoPqXX.mjs.map +1 -0
- package/dist/{build-BfC9Kkt-.mjs → build-C-AsmCh1.mjs} +2 -2
- package/dist/{build-BuBCsnzr.mjs → build-DQnV0GCD.mjs} +3 -3
- package/dist/{build-BuBCsnzr.mjs.map → build-DQnV0GCD.mjs.map} +1 -1
- package/dist/{builtins-DXASTS7y.mjs → builtins-BsYCQU80.mjs} +2 -2
- package/dist/{builtins-397XZB9_.mjs → builtins-Cjp9FT1m.mjs} +392 -185
- package/dist/cli.mjs +2 -2
- package/dist/config-DMFwBdWg.mjs +12 -0
- package/dist/config-DbnBakh8.mjs +13 -0
- package/dist/config-DbnBakh8.mjs.map +1 -0
- package/dist/{doctor-DGWvBOvj.mjs → doctor-rEbeoAoO.mjs} +282 -75
- package/dist/doctor-rEbeoAoO.mjs.map +1 -0
- package/dist/{fullstack-x16HfCRz.mjs → fullstack-DdSScENL.mjs} +7 -7
- package/dist/{fullstack-BqYdhTDI.mjs → fullstack-XhuwRQEb.mjs} +8 -8
- package/dist/{fullstack-BqYdhTDI.mjs.map → fullstack-XhuwRQEb.mjs.map} +1 -1
- package/dist/index.d.mts +29 -7
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +2 -2
- package/dist/package-manager-C8ekNwsa.mjs +11 -0
- package/dist/package-manager-DvXi-NGm.mjs +12 -0
- package/dist/package-manager-DvXi-NGm.mjs.map +1 -0
- package/dist/{plugin-HazJu53p.mjs → plugin--9hxxgsD.mjs} +2 -2
- package/dist/{plugin-Dh0LYWl5.mjs → plugin-CvlUt9NG.mjs} +2 -2
- package/dist/project-BN1DnrN3.mjs +134 -0
- package/dist/project-BN1DnrN3.mjs.map +1 -0
- package/dist/project-DBmrFgdd.mjs +133 -0
- package/dist/{project-root-DGKTJDH3.mjs → project-root-BXmtd-te.mjs} +2 -2
- package/dist/{project-root-DlgCWwc_.mjs → project-root-FMt83NHV.mjs} +3 -3
- package/dist/{project-root-DlgCWwc_.mjs.map → project-root-FMt83NHV.mjs.map} +1 -1
- package/dist/{prompts-D4nwf5mP.mjs → prompts-DJBDNwHt.mjs} +2 -2
- package/dist/{prompts-D4nwf5mP.mjs.map → prompts-DJBDNwHt.mjs.map} +1 -1
- package/dist/{rolldown-runtime-7c5UUG6D.mjs → rolldown-runtime-C4d34LEE.mjs} +1 -1
- package/dist/{run-plugins-Dx-QENlm.mjs → run-plugins-9tjbMqS6.mjs} +87 -87
- package/dist/run-plugins-9tjbMqS6.mjs.map +1 -0
- package/dist/typegen-AGdhxyRc.mjs +107 -0
- package/dist/typegen-AGdhxyRc.mjs.map +1 -0
- package/dist/typegen-Lf0UPhdl.mjs +106 -0
- package/dist/{types-CtrnAiNl.mjs → types-B5dY2mTz.mjs} +1 -1
- package/package.json +3 -3
- package/templates/base/files/README.md +2 -2
- package/templates/base/files/kick.config.ts +1 -1
- package/templates/base/files/src/modules/hello/hello.controller.ts +0 -5
- package/templates/base/files/src/modules/hello/hello.service.ts +0 -4
- package/templates/base/files/tsconfig.json +3 -1
- package/templates/feature-devtools/feature.json +2 -6
- package/templates/feature-devtools/files/src/devtools.d.ts +3 -0
- package/templates/feature-queue/feature.json +39 -3
- package/templates/feature-queue/files/_dot_env.example.append +4 -2
- package/templates/feature-queue/files/src/adapters/queue.ts +16 -0
- package/templates/feature-storage/feature.json +1 -1
- package/templates/schema-valibot/files/src/config/index.ts +5 -2
- package/templates/schema-yup/files/src/config/index.ts +5 -2
- package/templates/schema-zod/files/src/config/index.ts +5 -2
- package/templates/template-inertia/feature.json +9 -1
- package/templates/template-inertia/files/_dot_env.append +2 -0
- package/templates/template-inertia/files/_dot_env.example.append +6 -2
- package/templates/template-inertia/files/_dot_env.test.append +1 -0
- package/templates/template-inertia/files/_dot_env.test.example.append +1 -0
- package/templates/template-inertia/files/src/client/Layout.tsx +2 -0
- package/templates/template-inertia/files/src/client/Seo.tsx +35 -0
- package/templates/template-inertia/files/src/index.ts +11 -5
- package/templates/template-inertia/files/src/modules/index.ts +2 -1
- package/templates/template-inertia/files/src/modules/pages/pages.controller.ts +18 -6
- package/templates/template-inertia/files/src/modules/pages/pages.test.ts +34 -0
- package/templates/template-inertia/files/src/modules/seo/seo.controller.ts +19 -0
- package/templates/template-inertia/files/src/modules/seo/seo.module.ts +12 -0
- package/templates/template-inertia/files/tsconfig.json +3 -1
- package/templates/template-inertia/files/vite.config.ts +3 -2
- package/templates/web-kick/files/web/_dot_oxfmtrc.json +9 -0
- package/templates/web-kick/files/web/src/App.tsx +1 -7
- package/dist/agent-docs-ZgfnGL-j.mjs.map +0 -1
- package/dist/config-Ck9aQVpE.mjs +0 -12
- package/dist/config-CsOfUFfq.mjs +0 -13
- package/dist/config-CsOfUFfq.mjs.map +0 -1
- package/dist/doctor-DGWvBOvj.mjs.map +0 -1
- package/dist/package-manager--IUl91nq.mjs +0 -11
- package/dist/package-manager-DBmD5nSr.mjs +0 -12
- package/dist/package-manager-DBmD5nSr.mjs.map +0 -1
- package/dist/project-C98JovY4.mjs +0 -115
- package/dist/project-C98JovY4.mjs.map +0 -1
- package/dist/project-TbTVQCnh.mjs +0 -114
- package/dist/run-plugins-Dx-QENlm.mjs.map +0 -1
- package/dist/typegen-DJQ6WBwr.mjs +0 -106
- package/dist/typegen-DSaawXaQ.mjs +0 -107
- package/dist/typegen-DSaawXaQ.mjs.map +0 -1
- package/templates/feature-queue/files/_dot_env.append +0 -2
- package/templates/template-inertia/files/public/robots.txt +0 -4
- /package/templates/feature-storage/files/src/{storage.ts → adapters/storage.ts} +0 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @forinda/kickjs-cli v8.12.0
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) Felix Orinda
|
|
5
|
+
*
|
|
6
|
+
* This source code is licensed under the MIT license found in the
|
|
7
|
+
* LICENSE file in the root directory of this source tree.
|
|
8
|
+
*
|
|
9
|
+
* @license MIT
|
|
10
|
+
*/
|
|
11
|
+
import{t as e}from"./rolldown-runtime-C4d34LEE.mjs";import{statSync as t}from"node:fs";import{basename as n,dirname as r,join as i,relative as a,resolve as o,sep as s}from"node:path";import{mkdir as c,readFile as l,readdir as u,stat as d,unlink as f,writeFile as p}from"node:fs/promises";import{parseSync as m}from"oxc-parser";import{globSync as h}from"glob";import{groupAssetKeys as g}from"@forinda/kickjs";const _=[`classes`,`tokens`,`injects`,`pluginsAndAdapters`,`contextKeys`,`routeFlags`,`routes`,`moduleMounts`,`globPatterns`];function v(e){if(!e||typeof e!=`object`)return!1;let t=e;return _.every(e=>Array.isArray(t[e]))}var y=class e{path;prev;next=/* @__PURE__ */ new Map;nextSig=/* @__PURE__ */ new Map;constructor(e,t){this.path=e,this.prev=t}static async load(t){let n=i(t,`scan.json`),r=/* @__PURE__ */ new Map;try{let e=await l(n,`utf-8`),t=JSON.parse(e);if(t.version===3&&t.files)for(let[e,n]of Object.entries(t.files))n&&typeof n.sig==`string`&&v(n.extract)&&r.set(e,n)}catch{}return new e(n,r)}static async signature(e){try{let t=await d(e);return`${t.mtimeMs}:${t.size}`}catch{return null}}get(e,t){let n=this.prev.get(e);return n&&n.sig===t?n.extract:null}set(e,t,n){this.next.set(e,n),this.nextSig.set(e,t)}cachedFiles(){return[...this.prev.keys()]}peek(e){return this.prev.get(e)?.extract??null}carry(e){let t=this.prev.get(e);return t?(this.next.set(e,t.extract),this.nextSig.set(e,t.sig),!0):!1}async save(){let e={};for(let[t,n]of this.next){let r=this.nextSig.get(t);r&&(e[t]={sig:r,extract:n})}let t={version:3,files:e};try{await c(r(this.path),{recursive:!0}),await p(this.path,JSON.stringify(t),`utf-8`)}catch{}}};let b=null;function ee(){return b??=new Set(L),b}const x=/* @__PURE__ */ new Set([`Get`,`Post`,`Put`,`Delete`,`Patch`]);function S(e){return typeof e==`object`&&!!e&&typeof e.type==`string`}function C(e,t){if(Array.isArray(e))for(let n of e)C(n,t);else if(S(e)){t(e);for(let n of Object.keys(e)){if(n===`type`)continue;let r=e[n];typeof r==`object`&&r&&C(r,t)}}}function w(e){if(!S(e))return null;if(e.type===`Literal`&&typeof e.value==`string`)return e.value;if(e.type===`TemplateLiteral`){let t=e.quasis,n=e.expressions;if(t?.length===1&&(n?.length??0)===0){let e=t[0].value?.cooked;return typeof e==`string`?e:null}}return null}function T(e){return S(e)&&e.type===`Identifier`?e.name:null}function E(e){return T(e.callee)}function D(e,t){if(!e||e.type!==`ObjectExpression`)return null;for(let n of e.properties??[]){if(n.type!==`Property`)continue;let e=n.key;if((T(e)??(e.type===`Literal`?String(e.value):w(e)))===t)return n.value}return null}function O(e){let t=e.arguments?.[0];return S(t)&&t.type===`ObjectExpression`?t:null}function k(e,t){let n=D(e,t);if(!S(n)||n.type!==`ArrayExpression`)return[];let r=[];for(let e of n.elements??[]){let t=w(e);t!==null&&r.push(t)}return r}function te(e,t){return a(t,e).split(s).join(`/`)}function ne(e){return(e.match(/:([a-zA-Z_]\w*)/g)??[]).map(e=>e.slice(1))}function re(e,t){for(let n of e.implements??[]){let e=n.expression??n;if(T(e)===t)return!0;if(e.type===`TSQualifiedName`||e.type===`MemberExpression`){let n=e.right??e.property;if(n&&T(n)===t)return!0}}return!1}function A(e){return e.decorators??[]}function j(e){let t=e.expression;if(!S(t)||t.type!==`CallExpression`)return null;let n=E(t);return n?{name:n,call:t}:null}function ie(e){let t=/* @__PURE__ */ new Map,n=/* @__PURE__ */ new Set,r=/* @__PURE__ */ new Set;for(let i of e.body??[]){if(i.type===`ExportNamedDeclaration`&&!i.source)for(let e of i.specifiers??[]){let t=T(e.local);t&&t===T(e.exported)&&r.add(t)}if(i.type===`ImportDeclaration`){let e=w(i.source)??``;for(let n of i.specifiers??[]){let r=T(n.local);r&&t.set(r,{source:e})}continue}let e=i.type===`VariableDeclaration`?i:i.type===`ExportNamedDeclaration`&&S(i.declaration)?i.declaration:null;if(S(e)&&e.type===`VariableDeclaration`)for(let t of e.declarations??[]){let a=T(t.id);a&&n.add(a),a&&i!==e&&r.add(a)}}return{imports:t,topLevelConsts:n,exported:r}}function M(e,t){let n=t.imports.get(e);return n?{identifier:e,source:n.source}:t.topLevelConsts.has(e)?t.exported.has(e)?{identifier:e,source:``}:{identifier:e,source:null,unexported:!0}:{identifier:e,source:null}}function ae(e,t){let n=[];for(let r of e){let e=j(r),i=e?e.name:T(r.expression);if(!i||x.has(i))continue;let a=t.imports.get(i);n.push({identifier:i,source:a?a.source:t.topLevelConsts.has(i)?``:null})}return n}const N=/* @__PURE__ */ new Set([`bootstrap`,`createWebApp`,`Application`]);function oe(e,t){if(!N.has(e))return!1;let n=t.imports.get(e)?.source;return n===`@forinda/kickjs`||(n?.startsWith(`@forinda/kickjs/`)??!1)}function se(e,t){let n={refs:[],resolved:!1},r=P(e);if(!r||r.type!==`ArrayExpression`)return n;let i=[];for(let e of r.elements??[]){if(!S(e)||e.type!==`MemberExpression`||T(e.property)!==`registration`)return n;let r=e.object,a=T(r);if(!a&&S(r)&&r.type===`CallExpression`){let e=r.callee;S(e)&&e.type===`MemberExpression`&&T(e.property)===`with`&&(a=T(e.object))}if(!a)return n;let o=t.imports.get(a);i.push({identifier:a,source:o?o.source:t.topLevelConsts.has(a)?``:null})}return{refs:i,resolved:!0}}function P(e){let t=e.value??e;if(!S(t))return null;if(t.type===`ArrayExpression`)return t;let n=t.body;if(!S(n))return null;if(n.type!==`BlockStatement`)return n;let r=(n.body??[]).filter(e=>e.type===`ReturnStatement`);if(r.length!==1)return null;let i=r[0].argument;return S(i)?i:null}function F(e,t,n){let r=T(D(e,t));return r?M(r,n):null}function ce(e,t){for(let n of e){let e=j(n);if(!e||e.name!==`ApiQueryParams`)continue;let r=e.call.arguments?.[0],i=null;if(S(r)&&r.type===`ObjectExpression`)i=r;else{let e=T(r);if(e){let n=t.get(e);n&&n.type===`ObjectExpression`&&(i=n)}}return{filterable:k(i,`filterable`),sortable:k(i,`sortable`),searchable:k(i,`searchable`)}}return null}function I(e,t,n){let r;try{let n=m(t,e);if(n.errors.length>0)return null;r=n.program}catch{return null}let i=te(t,n),a=ie(r),o=[],s=[],c=[],l=[],u=[],d=[],f=/* @__PURE__ */ new Set,p=[],h=[],g=[],_=/* @__PURE__ */ new Set,v=/* @__PURE__ */ new Set,y=/* @__PURE__ */ new Map;C(r,e=>{if(e.type!==`VariableDeclarator`)return;let t=T(e.id),n=e.init;t&&S(n)&&y.set(n,t)});let b=/* @__PURE__ */ new Set,k=/* @__PURE__ */ new Map;for(let e of r.body??[]){let t=e.type===`VariableDeclaration`?e:e.type===`ExportNamedDeclaration`&&S(e.declaration)?e.declaration:null;if(S(t)&&t.type===`VariableDeclaration`)for(let e of t.declarations??[]){let t=T(e.id);t&&S(e.init)&&k.set(t,e.init)}}let M=[];for(let e of r.body??[])if(e.type===`ExportNamedDeclaration`&&S(e.declaration)){let t=e.declaration;t.type===`ClassDeclaration`&&M.push({cls:t,isDefault:!1})}else if(e.type===`ExportDefaultDeclaration`&&S(e.declaration)){let t=e.declaration;t.type===`ClassDeclaration`&&M.push({cls:t,isDefault:!0})}for(let{cls:e,isDefault:n}of M){let r=T(e.id);if(!r)continue;let a=null;for(let t of A(e)){let e=j(t);if(e&&ee().has(e.name)){a=e.name;break}}a?o.push({className:r,decorator:a,filePath:t,relativePath:i,isDefault:n}):re(e,`AppModule`)&&o.push({className:r,decorator:`Module`,filePath:t,relativePath:i,isDefault:n})}for(let e of r.body??[]){if(e.type!==`ExportNamedDeclaration`||!S(e.declaration))continue;let n=e.declaration;if(n.type===`VariableDeclaration`)for(let e of n.declarations??[]){let n=T(e.id),r=e.init;n&&S(r)&&r.type===`CallExpression`&&E(r)===`defineModule`&&(o.some(e=>e.className===n)||o.push({className:n,decorator:`Module`,filePath:t,relativePath:i,isDefault:!1}))}}C(r,n=>{if(n.type===`VariableDeclarator`){let e=n.init;if(S(e)&&e.type===`CallExpression`&&E(e)===`createToken`){let r=w(e.arguments?.[0]);r!==null&&(b.add(e),s.push({name:r,variable:T(n.id),filePath:t,relativePath:i}))}return}if(n.type!==`CallExpression`){if(n.type===`Decorator`){let e=j(n);if(e?.name===`Inject`){let n=w(e.call.arguments?.[0]);n!==null&&c.push({name:n,filePath:t,relativePath:i})}}return}let r=n.callee,a=E(n);if(a===`createToken`&&!b.has(n)){let e=w(n.arguments?.[0]);e!==null&&s.push({name:e,variable:null,filePath:t,relativePath:i})}else if(a===`defineAdapter`||a===`definePlugin`){let e=w(D(O(n),`name`));if(e!==null){let n=a===`definePlugin`?`plugin`:`adapter`,r=`${a}::${e}::${t}`;_.has(r)||(_.add(r),l.push({kind:n,name:e,filePath:t,relativePath:i}))}}else if(a===`defineRouteFlag`){let r=w(n.arguments?.[0]);if(r!==null&&!f.has(r)){f.add(r);let a=n.typeArguments,o=a?e.slice(a.start,a.end):null;d.push({name:r,valueType:o?o.slice(1,-1).trim():null,filePath:t,relativePath:i})}}else if(a===`defineContextDecorator`||a===`defineHttpContextDecorator`){let e=w(D(O(n),`key`));e!==null&&!v.has(e)&&(v.add(e),u.push({key:e,exportName:y.get(n)??null,filePath:t,relativePath:i}))}else if(S(r)&&r.type===`CallExpression`){let e=r.callee;if(S(e)&&e.type===`MemberExpression`&&T(e.property)===`withParams`){let r=T(e.object);if(r===`defineContextDecorator`||r===`defineHttpContextDecorator`){let e=w(D(O(n),`key`));e!==null&&!v.has(e)&&(v.add(e),u.push({key:e,exportName:y.get(n)??null,filePath:t,relativePath:i}))}}}else if(S(r)&&r.type===`MemberExpression`&&T(r.property)===`glob`){let e=r.object;S(e)&&e.type===`MetaProperty`&&C(n.arguments,e=>{let t=w(e);t!==null&&g.push(t)})}});let N=[];C(r,e=>{if(e.type===`ClassDeclaration`||e.type===`ClassExpression`){let t=T(e.id);t&&N.push({cls:e,className:t})}});for(let{cls:e,className:n}of N){let r=o.find(e=>e.className===n),s=e.body?.body;if(re(e,`AppAdapter`))for(let e of s??[]){if(e.type!==`PropertyDefinition`||T(e.key)!==`name`)continue;let n=w(e.value);if(n===null)continue;let r=`class::${n}::${t}`;_.has(r)||(_.add(r),l.push({kind:`adapter`,name:n,filePath:t,relativePath:i}));break}for(let o of s??[]){if(o.type!==`MethodDefinition`)continue;let s=T(o.key);if(!s)continue;if(s===`routes`){le(o.value,h);continue}if(!r)continue;let c=A(o),l=ce(c,k),u=[...ae(A(e),a),...ae(c,a)];for(let e of c){let o=j(e);if(!o||!x.has(o.name))continue;let c=o.call.arguments??[],d=w(c[0]),f=d&&d.length>0?d:`/`,m=S(c[1])&&c[1].type===`ObjectExpression`?c[1]:null;p.push({controller:n,method:s,httpMethod:o.name.toUpperCase(),path:f,pathParams:ne(f),queryFilterable:l?.filterable??null,querySortable:l?.sortable??null,querySearchable:l?.searchable??null,bodySchema:F(m,`body`,a),querySchema:F(m,`query`,a),paramsSchema:F(m,`params`,a),responseSchema:F(m,`response`,a),filePath:t,relativePath:i,controllerIsDefaultExport:r.isDefault,appliedDecorators:u,mountedPath:f})}}}C(r,e=>{if(e.type!==`Property`||T(e.key)!==`routes`)return;let t=e.value;S(t)&&(t.type===`FunctionExpression`||t.type===`ArrowFunctionExpression`)&&le(t,h)});let P=/* @__PURE__ */ new Set,I=/* @__PURE__ */ new Set;C(r,e=>{let t=e.type===`Property`&&T(e.key)===`contributors`,n=e.type===`MethodDefinition`&&T(e.key)===`contributors`;(t||n)&&I.add(e)});let L=e=>e.properties??e.body?.body??[];C(r,e=>{if(e.type!==`ObjectExpression`&&e.type!==`ClassDeclaration`)return;let t=L(e);if(t.map(e=>T(e.key)).includes(`routes`))for(let e of t)T(e.key)===`contributors`&&P.add(e)});let R=/* @__PURE__ */ new Set;C(r,e=>{let t=e.type===`CallExpression`?E(e):e.type===`NewExpression`?T(e.callee):null;if(t===null||!oe(t,a))return;let n=O(e);if(n)for(let e of n.properties??[])e.type===`Property`&&T(e.key)===`contributors`&&R.add(e)});let z=e=>{if(e.size===0)return null;let n=[],r=!0;for(let t of e){let e=se(t,a);e.resolved||(r=!1),n.push(...e.refs)}return{refs:n,resolved:r,filePath:t}},B=z(P),V=z(R);return{classes:o,tokens:s,injects:c,pluginsAndAdapters:l,contextKeys:u,routeFlags:d,routes:p,moduleMounts:h,globPatterns:/\.module\.[mc]?[tj]sx?$/.test(t)?g:[],moduleContributors:B,appContributors:V,hasNonDecoratorContributors:I.size>P.size+R.size}}function le(e,t){let n=[],r=[];C(e.body,e=>{if(e.type!==`Property`)return;let t=T(e.key);if(t===`path`){let t=w(e.value);t!==null&&n.push(t)}else if(t===`controller`){let t=T(e.value);t&&/^[A-Z]/.test(t)&&r.push(t)}});let i=Math.min(n.length,r.length);for(let e=0;e<i;e++)t.push({controller:r[e],mountPath:n[e]})}const L=[`Service`,`Controller`,`Repository`,`Injectable`,`Component`,`Module`],R=[`.ts`,`.tsx`,`.mts`,`.cts`],z=[`node_modules`,`.kickjs`,`dist`,`build`,`.test.`,`.spec.`,`.d.ts`],B=new RegExp(String.raw`@(${L.join(`|`)})\s*\([^)]*\)`+String.raw`(?:\s*@[A-Z]\w*(?:\s*\([^)]*\))?)*`+String.raw`\s*export\s+(default\s+)?(?:abstract\s+)?class\s+(\w+)`,`g`),V=new RegExp(String.raw`export\s+(default\s+)?(?:abstract\s+)?class\s+(\w+)`+String.raw`(?:\s+extends\s+\w+(?:<[^>]*>)?)?`+String.raw`\s+implements\s+[^{]*\bAppModule\b`,`g`),ue=/export\s+const\s+(\w+)\s*(?::\s*[^=]+)?=\s*defineModule\s*(?:<[^>]*>)?\s*\(/g,de=/(?:export\s+)?const\s+(\w+)\s*(?::\s*[^=]+)?=\s*createToken\s*(?:<[^>]*>)?\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g,fe=/createToken\s*(?:<[^>]*>)?\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g,pe=/@Inject\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g,H=/\b(defineAdapter|definePlugin)\s*(?:<[^>]*>)?\s*\(/g,U=/(?:(?:export\s+)?(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*(?::[^=]+)?=\s*)?\b(?:defineContextDecorator|defineHttpContextDecorator)\s*(?:\.withParams\s*<(?:[^<>]|<[^<>]*>)*>\s*\(\s*\))?\s*(?:<(?:[^<>]|<[^<>]*>)*>)?\s*\(/g,me=new RegExp(String.raw`export\s+(?:default\s+)?(?:abstract\s+)?class\s+(\w+)`+String.raw`(?:\s+extends\s+\w+(?:<[^>]*>)?)?`+String.raw`\s+implements\s+[^{]*\bAppAdapter\b`,`g`),he=/\bname\s*(?::\s*[^=]+)?=\s*['"`]([^'"`]+)['"`]/,W=new RegExp(String.raw`@(${[`Get`,`Post`,`Put`,`Delete`,`Patch`].join(`|`)})\s*\(`,`g`);function G(e,t){let n=1;for(let r=t+1;r<e.length;r++){let t=e[r];if(t===`(`)n++;else if(t===`)`&&(n--,n===0))return r}return-1}function ge(e,t){let n=t;for(;n<e.length;){for(;n<e.length&&/\s/.test(e[n]);)n++;if(e[n]!==`@`)break;let t=e.slice(n).match(/^@([A-Z]\w*)/);if(!t)break;for(n+=t[0].length;n<e.length&&/\s/.test(e[n]);)n++;if(e[n]===`(`){let t=G(e,n);if(t<0)return null;n=t+1}}for(;n<e.length&&/\s/.test(e[n]);)n++;for(let t of[`public`,`private`,`protected`])if(e.slice(n,n+t.length)===t&&/\s/.test(e.charAt(n+t.length))){for(n+=t.length;n<e.length&&/\s/.test(e[n]);)n++;break}if(e.slice(n,n+5)===`async`&&/\s/.test(e.charAt(n+5)))for(n+=5;n<e.length&&/\s/.test(e[n]);)n++;let r=e.slice(n).match(/^([a-zA-Z_]\w*)\s*\(/);return r?{methodName:r[1],endPos:n+r[0].length}:null}function _e(e){return(e.match(/:([a-zA-Z_]\w*)/g)??[]).map(e=>e.slice(1))}function ve(e,t){let n=e.endsWith(`/`)?e.slice(0,-1):e;return!t||t===`/`?n||`/`:n+(t.startsWith(`/`)?t:`/`+t)||`/`}const ye=/\b(?:public\s+|private\s+|protected\s+)?routes\s*\([^)]*\)\s*(?::\s*[A-Za-z_][\w<>[\]\s,|]*\s*)?\{/g,be=/\bpath\s*:\s*['"`]([^'"`]*)['"`]/g,xe=/\bcontroller\s*:\s*([A-Z]\w*)\b/g,K=/\bimport\.meta\.glob\s*\(/g;function Se(e){let t=[];for(K.lastIndex=0;K.exec(e)!==null;){let n=K.lastIndex-1,r=G(e,n);if(r<0)continue;let i=e.slice(n+1,r),a=/['"`]([^'"`]+)['"`]/g,o;for(;(o=a.exec(i))!==null;)t.push(o[1])}return t}function Ce(e){let t=e.replace(/[.+^$()|[\]\\]/g,`\\$&`).replace(/\?/g,`.`).replace(/\*\*\//g,`___DOUBLESTAR_SLASH___`).replace(/\*\*/g,`___DOUBLESTAR___`).replace(/\*/g,`[^/]*`).replace(/___DOUBLESTAR_SLASH___/g,`(?:.+/)?`).replace(/___DOUBLESTAR___/g,`.*`);return RegExp(`^`+t+`$`)}function we(e,t){let n=e.startsWith(`./`)?e:`./`+e,r=!1;for(let e of t){let t=e.startsWith(`!`);Ce(t?e.slice(1):e).test(n)&&(r=!t)}return r}function Te(e){let t=[];ye.lastIndex=0;let n;for(;(n=ye.exec(e))!==null;){let r=e.indexOf(`{`,n.index+n[0].length-1);if(r<0)continue;let i=Ie(e,r);if(i<0)continue;let a=e.slice(r+1,i),o=[];be.lastIndex=0;let s;for(;(s=be.exec(a))!==null;)o.push(s[1]??``);let c=[];xe.lastIndex=0;let l;for(;(l=xe.exec(a))!==null;)c.push(l[1]);let u=Math.min(o.length,c.length);for(let e=0;e<u;e++)t.push({controller:c[e],mountPath:o[e]})}return t}function q(e,t){let n=new RegExp(String.raw`\b${t}\s*:\s*([A-Za-z_$][\w$]*)`,`g`).exec(e);return n?n[1]:null}function J(e,t){let n=Ee(e,t);return n===null?new RegExp(String.raw`(?:^|\n)\s*const\s+${t}\b`).test(e)?{identifier:t,source:null,unexported:!0}:{identifier:t,source:null}:{identifier:t,source:n}}function Ee(e,t){let n=new RegExp(String.raw`import\s*(?:type\s+)?\{[^}]*\b${t}\b[^}]*\}\s*from\s*['"\`]([^'"\`]+)['"\`]`).exec(e);if(n)return n[1];let r=new RegExp(String.raw`import\s+(?:type\s+)?${t}\s+from\s*['"\`]([^'"\`]+)['"\`]`).exec(e);if(r)return r[1];let i=new RegExp(String.raw`import\s*\*\s*as\s+${t}\s+from\s*['"\`]([^'"\`]+)['"\`]`).exec(e);return i?i[1]:new RegExp(String.raw`(?:^|\n)\s*export\s+const\s+${t}\b|export\s*\{[^}]*(?<!\bas\s+)\b${t}\b(?!\s+as\b)[^}]*\}(?!\s*from)`).test(e)?``:null}function De(e,t){let n=/@ApiQueryParams\s*\(\s*([\s\S]*?)\s*\)\s*$/.exec(e);if(!n){let n=/@ApiQueryParams\s*\(([\s\S]*?)\)/.exec(e);return n?Oe(n[1].trim(),t):null}return Oe(n[1].trim(),t)}function Oe(e,t){if(e.startsWith(`{`))return Ae(e);let n=/^([A-Za-z_]\w*)/.exec(e);if(n){let e=n[1],r=new RegExp(String.raw`const\s+${e}\s*(?::\s*[^=]+)?=\s*(\{[\s\S]*?\n\})`,`m`).exec(t);if(r)return Ae(r[1])}return{filterable:[],sortable:[],searchable:[]}}function ke(e,t){let n=new RegExp(String.raw`${t}\s*:\s*\[([\s\S]*?)\]`).exec(e);return n?Array.from(n[1].matchAll(/['"`]([^'"`]+)['"`]/g)).map(e=>e[1]):[]}function Ae(e){return{filterable:ke(e,`filterable`),sortable:ke(e,`sortable`),searchable:ke(e,`searchable`)}}async function je(e,t){let n=t.extensions??R,r=t.exclude??z,o=[],s;try{s=await u(e,{withFileTypes:!0,encoding:`utf-8`})}catch{return o}for(let c of s){let s=i(e,c.name),l=a(t.cwd,s);r.some(e=>l.includes(e))||(c.isDirectory()?o.push(...await je(s,t)):c.isFile()&&n.some(e=>c.name.endsWith(e))&&o.push(s))}return o}function Y(e,t){return a(t,e).split(s).join(`/`)}function Me(e,t,n){let r=[],i=Y(t,n);B.lastIndex=0;let a;for(;(a=B.exec(e))!==null;){let[,e,n,o]=a;r.push({className:o,decorator:e,filePath:t,relativePath:i,isDefault:!!n})}V.lastIndex=0;let o;for(;(o=V.exec(e))!==null;){let[,e,n]=o;r.some(e=>e.className===n&&e.filePath===t)||r.push({className:n,decorator:`Module`,filePath:t,relativePath:i,isDefault:!!e})}ue.lastIndex=0;let s;for(;(s=ue.exec(e))!==null;){let[,e]=s;r.some(n=>n.className===e&&n.filePath===t)||r.push({className:e,decorator:`Module`,filePath:t,relativePath:i,isDefault:!1})}return r}function Ne(e,t,n){let r=[],i=Y(t,n),a=/* @__PURE__ */ new Set;de.lastIndex=0;let o;for(;(o=de.exec(e))!==null;){let[e,n,s]=o;a.add(e),r.push({name:s,variable:n,filePath:t,relativePath:i})}for(fe.lastIndex=0;(o=fe.exec(e))!==null;)a.has(o[0])||r.push({name:o[1],variable:null,filePath:t,relativePath:i});return r}function Pe(e,t,n,r,i=/* @__PURE__ */ new Map){let a=[];if(r.length===0)return a;let o=Y(t,n),s=[];for(let t of r){let n=new RegExp(String.raw`class\s+${t.className}\b`).exec(e);n?.index!==void 0&&s.push({cls:t,start:n.index})}s.sort((e,t)=>e.start-t.start);for(let n=0;n<s.length;n++){let{cls:r,start:c}=s[n],l=n+1<s.length?s[n+1].start:e.length,u=e.slice(c,l);W.lastIndex=0;let d;for(;(d=W.exec(u))!==null;){let n=d[1],s=d.index,c=W.lastIndex-1,l=G(u,c);if(l<0)continue;let f=u.slice(c+1,l),p=f.match(/^\s*['"`]([^'"`]*)['"`]/),m=p&&p[1].length>0?p[1]:`/`,h=ge(u,l+1);if(!h)continue;let{methodName:g,endPos:_}=h;W.lastIndex=_;let v=De(u.slice(s,_),e),y=q(f,`body`),b=q(f,`query`),ee=q(f,`params`),x=q(f,`response`),S=i.get(r.className)??``,C=S?ve(S,m):m;a.push({controller:r.className,method:g,httpMethod:n.toUpperCase(),path:m,pathParams:_e(C),queryFilterable:v?.filterable??null,querySortable:v?.sortable??null,querySearchable:v?.searchable??null,bodySchema:y?J(e,y):null,querySchema:b?J(e,b):null,paramsSchema:ee?J(e,ee):null,responseSchema:x?J(e,x):null,filePath:t,relativePath:o,controllerIsDefaultExport:r.isDefault,mountedPath:C})}}return a}function Fe(e,t,n){let r=[],i=Y(t,n);pe.lastIndex=0;let a;for(;(a=pe.exec(e))!==null;)r.push({name:a[1],filePath:t,relativePath:i});return r}function Ie(e,t){let n=1;for(let r=t+1;r<e.length;r++){let t=e[r];if(t===`{`)n++;else if(t===`}`&&(n--,n===0))return r}return-1}function Le(e,t,n){let r=[],i=Y(t,n),a=/* @__PURE__ */ new Set;H.lastIndex=0;let o;for(;(o=H.exec(e))!==null;){let n=o[1],s=H.lastIndex-1,c=G(e,s);if(c<0)continue;let l=e.slice(s+1,c),u=/\bname\s*:\s*['"`]([^'"`]+)['"`]/.exec(l);if(!u)continue;let d=u[1],f=`${n}::${d}::${t}`;a.has(f)||(a.add(f),r.push({kind:n===`definePlugin`?`plugin`:`adapter`,name:d,filePath:t,relativePath:i}))}me.lastIndex=0;let s;for(;(s=me.exec(e))!==null;){let n=s.index,o=e.indexOf(`{`,n);if(o<0)continue;let c=Ie(e,o);if(c<0)continue;let l=e.slice(o+1,c),u=he.exec(l);if(!u)continue;let d=u[1],f=`class::${d}::${t}`;a.has(f)||(a.add(f),r.push({kind:`adapter`,name:d,filePath:t,relativePath:i}))}return r}function Re(e,t,n){let r=[],i=Y(t,n),a=/* @__PURE__ */ new Set;U.lastIndex=0;let o;for(;(o=U.exec(e))!==null;){let n=U.lastIndex-1,s=G(e,n);if(s<0)continue;let c=e.slice(n+1,s),l=/\bkey\s*:\s*['"`]([^'"`]+)['"`]/.exec(c);if(!l)continue;let u=l[1];a.has(u)||(a.add(u),r.push({key:u,exportName:o[1]??null,filePath:t,relativePath:i}))}return r}const ze=[`src/config/index.ts`,`src/config/env.ts`,`src/config.ts`,`src/env.ts`];async function Be(e,t){let n=t===`src/env.ts`?ze:[t];for(let t of n){let n=o(e,t),r;try{r=await l(n,`utf-8`)}catch{continue}if((/\bdefineEnv\s*\(/.test(r)||/\bfrom(Zod|Valibot|Yup)\s*\(/.test(r))&&/export\s+default\b/.test(r)&&!/export\s+default\s+loadEnvFromSchema\s*\(/.test(r))return{filePath:n,relativePath:Y(n,e)}}return null}function Ve(e){let t=/* @__PURE__ */ new Map;for(let n of e){let e=t.get(n.className)??[];e.push(n),t.set(n.className,e)}let n=[];for(let[e,r]of t)new Set(r.map(e=>e.filePath)).size>1&&n.push({className:e,classes:r});return n.sort((e,t)=>e.className.localeCompare(t.className)),n}const He=/* @__PURE__ */ new Set([`Controller`,`Service`,`Repository`,`Injectable`,`Component`,`Module`,`Middleware`,`ApiQueryParams`,`Public`,`Roles`,`Cron`,`Cacheable`,`CacheEvict`,`FileUpload`,`Asset`,`Builder`,`PostConstruct`,`PreDestroy`,`Value`,`Inject`,`Autowired`]);function X(e){return e.split(s).join(`/`).replace(/\.[mc]?[tj]sx?$/,``)}function Ue(e,t,n){let i=X(n);if(t===``)return i===X(e);if(t.startsWith(`.`)){let n=X(o(r(e),t));return i===n||i===`${n}/index`}let a=t.replace(/^[@~#]\//,``);if(a===t&&t.startsWith(`@`))return!1;let s=X(a);return i===s||i.endsWith(`/${s}`)}function We(e){let t=/* @__PURE__ */ new Map,n=/* @__PURE__ */ new Map;for(let t of e)if(t)for(let{controller:e}of t.moduleMounts)n.set(e,(n.get(e)??0)+1);for(let r of e)if(r?.moduleContributors)for(let{controller:e}of r.moduleMounts){if((n.get(e)??0)>1){t.set(e,`ambiguous`);continue}let i=t.get(e);t.set(e,i===void 0?r.moduleContributors:`ambiguous`)}return t}function Ge(e,t,n,r=/* @__PURE__ */ new Map,i=[]){if(n){for(let t of e)t.contextKeys=null;return}let a=/* @__PURE__ */ new Map;for(let e of t){if(!e.exportName)continue;let t=a.get(e.exportName);t?t.push(e):a.set(e.exportName,[e])}for(let t of e){let e=t.appliedDecorators;if(!e){t.contextKeys=null;continue}let n=/* @__PURE__ */ new Set,o=!0,s=(e,t)=>{if(t.source===null)return null;let n=(a.get(t.identifier)??[]).filter(n=>Ue(e,t.source,n.filePath));return n.length===1?n[0].key:null};for(let r of e){if(He.has(r.identifier))continue;let e=s(t.filePath,r);if(e===null){o=!1;break}n.add(e)}if(o)for(let e of i){if(!e.resolved){o=!1;break}for(let t of e.refs){let r=s(e.filePath,t);if(r===null){o=!1;break}n.add(r)}if(!o)break}if(o){let e=r.get(t.controller);if(e===`ambiguous`)o=!1;else if(e){if(!e.resolved)o=!1;else for(let t of e.refs){let r=s(e.filePath,t);if(r===null){o=!1;break}n.add(r)}}}t.contextKeys=o?[...n].toSorted():null}}const Ke=/\bcontributors\s*(?::|\()/;function qe(e,t,n){return I(e,t,n)||{...Je(e,t,n),hasNonDecoratorContributors:Ke.test(e)}}function Je(e,t,n){let r=Me(e,t,n);return{classes:r,tokens:Ne(e,t,n),injects:Fe(e,t,n),pluginsAndAdapters:Le(e,t,n),routeFlags:[],contextKeys:Re(e,t,n),routes:Pe(e,t,n,r,/* @__PURE__ */ new Map),moduleMounts:Te(e),globPatterns:/\.module\.[mc]?[tj]sx?$/.test(t)?Se(e):[],hasNonDecoratorContributors:!1}}async function Ye(e,t,n){let r=n?await y.signature(e):null;if(n&&r){let t=n.get(e,r);if(t)return n.set(e,r,t),t}let i;try{i=await l(e,`utf-8`)}catch{return null}let a=qe(i,e,t);return n&&r&&n.set(e,r,a),a}async function Xe(e,t,n){let r=[],i=0,a=Array.from({length:Math.min(t,e.length)},async()=>{for(;;){let t=i++;if(t>=e.length)return;r[t]=await n(e[t],t)}});return await Promise.all(a),r}async function Z(e){let t=(await je(o(e.root),e)).toSorted(),n=e.cacheDir?await y.load(e.cacheDir):null,r=$e(t,await Xe(t,16,t=>Ye(t,e.cwd,n))),i=await Be(e.cwd,e.envFile??`src/env.ts`);return n&&await n.save(),{...r,env:i}}function Ze(e,t,n){let r=n.extensions??R,i=n.exclude??z;if(!e.startsWith(t+s)&&e!==t||!r.some(t=>e.endsWith(t)))return!1;let o=a(n.cwd,e);return!i.some(e=>o.includes(e))}async function Qe(e,t){if(!e.cacheDir)return Z(e);let n=o(e.root),r=await y.load(e.cacheDir),i=r.cachedFiles();if(i.length===0)return Z(e);let a=new Set(t.removed.map(t=>o(e.cwd,t))),s=t.changed.map(t=>o(e.cwd,t)).filter(t=>!a.has(t)&&Ze(t,n,e)),c=new Set(s),u=new Set(i);for(let e of c)u.add(e);for(let e of a)u.delete(e);let d=/* @__PURE__ */ new Map;await Xe(s,16,async t=>{if(!u.has(t))return;let n=await y.signature(t),i;try{i=await l(t,`utf-8`)}catch{u.delete(t);return}let a=qe(i,t,e.cwd);d.set(t,a),n&&r.set(t,n,a)});let f=[...u].toSorted(),p=$e(f,f.map(e=>d.get(e)||(r.carry(e),r.peek(e)))),m=await Be(e.cwd,e.envFile??`src/env.ts`);return await r.save(),{...p,env:m}}function $e(e,t){let n=[],r=[],i=[],a=[],o=[],c=[],l=[],u=/* @__PURE__ */ new Map;for(let e of t)if(e)for(let{controller:t,mountPath:n}of e.moduleMounts)u.has(t)||u.set(t,n);let d=/* @__PURE__ */ new Map;for(let s=0;s<e.length;s++){let f=t[s];if(f){n.push(...f.classes),i.push(...f.tokens),a.push(...f.injects),o.push(...f.pluginsAndAdapters),c.push(...f.contextKeys),l.push(...f.routeFlags),f.globPatterns.length>0&&d.set(e[s],f.globPatterns);for(let e of f.routes){let t=u.get(e.controller);if(t){let n=ve(t,e.path);r.push({...e,pathParams:_e(n),mountedPath:n})}else r.push({...e,mountedPath:e.mountedPath??e.path})}}}Ge(r,c,t.some(e=>e?.hasNonDecoratorContributors===!0),We(t),t.flatMap(e=>e?.appContributors?[e.appContributors]:[]));let f=[];for(let[e,t]of d){if(!/\.module\.[mc]?[tj]sx?$/.test(e)||t.length===0)continue;let r=e.replaceAll(s,`/`),i=r.slice(0,r.lastIndexOf(`/`));for(let a of n){if(a.decorator===`Module`)continue;let n=a.filePath.replaceAll(s,`/`);n.startsWith(i+`/`)&&n!==r&&(we(n.slice(i.length+1),t)||f.push({className:a.className,filePath:a.filePath,relativePath:a.relativePath,moduleFilePath:e,decorator:a.decorator}))}}n.sort((e,t)=>e.className===t.className?e.relativePath.localeCompare(t.relativePath):e.className.localeCompare(t.className)),i.sort((e,t)=>e.name.localeCompare(t.name)||e.relativePath.localeCompare(t.relativePath)),a.sort((e,t)=>e.name.localeCompare(t.name)||e.relativePath.localeCompare(t.relativePath)),r.sort((e,t)=>e.controller.localeCompare(t.controller)||e.method.localeCompare(t.method)),o.sort((e,t)=>e.name.localeCompare(t.name)||e.relativePath.localeCompare(t.relativePath)),c.sort((e,t)=>e.key.localeCompare(t.key)||e.relativePath.localeCompare(t.relativePath));let p=Ve(n);return f.sort((e,t)=>e.relativePath.localeCompare(t.relativePath)||e.className.localeCompare(t.className)),{classes:n,routes:r,tokens:i,injects:a,collisions:p,pluginsAndAdapters:o,contextKeys:c,routeFlags:l,orphanedClasses:f}}function et(e){let t=e.lastIndexOf(`.`);return t<=0?{stem:e,ext:``}:{stem:e.slice(0,t),ext:e.slice(t+1)}}function tt(e){let t=e.replaceAll(`\\`,`/`),{stem:n,ext:r}=et(t.slice(t.lastIndexOf(`/`)+1)),i=r||`ts`,a=n.lastIndexOf(`.`);return a>0?`./**/*.${n.slice(a+1)}.${i}`:`./**/*.${i}`}function nt(e){let t=/* @__PURE__ */ new Set;for(let n of e)t.add(tt(n.relativePath));return[...t].toSorted()}function rt(e,t){let n=0,r=null;for(let i=t;i<e.length;i++){let t=e[i];if(r){if(t===`\\`){i++;continue}t===r&&(r=null)}else if(t===`'`||t===`"`||t==="`")r=t;else if(t===`(`)n++;else if(t===`)`&&(n--,n===0))return i}return-1}function it(e,t,n,r){let i=null;for(let a=n;a<r;a++){let n=e[a];if(i){if(n===`\\`){a++;continue}n===i&&(i=null)}else if(n===`'`||n===`"`||n==="`")i=n;else if(n===t)return a}return-1}function at(e,t){let n=0,r=null;for(let i=t;i<e.length;i++){let t=e[i];if(r){if(t===`\\`){i++;continue}t===r&&(r=null)}else if(t===`'`||t===`"`||t==="`")r=t;else if(t===`[`)n++;else if(t===`]`&&(n--,n===0))return i}return-1}function ot(e){let t=/\bimport\.meta\.glob\s*\(/g,n=[],r;for(;(r=t.exec(e))!==null;){let t=e.indexOf(`(`,r.index);if(t<0)continue;let i=rt(e,t);i<0||n.push({start:r.index,open:t,close:i})}return n}function st(e,t){let n=ot(e);if(n.length===0)return null;let r=n.find(t=>/\beager\s*:\s*true\b/.test(e.slice(t.open,t.close+1)))??n[0],i=e.slice(r.start,r.close+1),a=new Set(Se(i).map(e=>e.startsWith(`!`)?e.slice(1):e)),o=t.filter(e=>!a.has(e));if(o.length===0)return null;let s=o.map(e=>`'${e}'`).join(`, `),c=it(e,`[`,r.open,r.close);if(c>=0){let t=at(e,c);if(t<0||t>r.close)return null;let n=e.slice(0,t);return n+(/[[,]\s*$/.test(n)?``:`, `)+s+e.slice(t)}let l=/(['"`])((?:\\.|(?!\1).)*)\1/,u=e.slice(r.open+1,r.close),d=l.exec(u);if(!d)return null;let f=r.open+1+d.index,p=f+d[0].length;return e.slice(0,f)+`[${d[0]}, ${s}]`+e.slice(p)}const Q="/* 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",ct=/* @__PURE__ */ new Set([`Service`,`Repository`,`Injectable`,`Component`]);var lt=class extends Error{collisions;constructor(e){super(ut(e)),this.name=`TokenCollisionError`,this.collisions=e}};function ut(e){let t=[`kick typegen: token collision detected`];for(let n of e){t.push(``),t.push(` ${n.classes.length} classes named '${n.className}':`);for(let e of n.classes)t.push(` - ${e.relativePath}`)}return t.push(``),t.push(`Resolutions:`),t.push(` (a) Rename one of the classes`),t.push(` (b) Use createToken<T>('namespaced/Name') and import the token explicitly — see @forinda/kickjs`),t.push(` (c) Pass --allow-duplicates to namespace the registry keys automatically`),t.push(` (e.g. 'modules/users/UserService' instead of 'UserService')`),t.join(`
|
|
12
|
+
`)}function dt(e,t){let n=r(t),i=a(n,e).split(s).join(`/`);return i=i.replace(/\.(ts|tsx|mts|cts)$/i,``),i.startsWith(`.`)||(i=`./`+i),i}function ft(e){let t=e.relativePath.replace(/^src\//,``).replace(/\.(ts|tsx|mts|cts)$/i,``).split(`/`);t.pop();let n=t.join(`/`);return n?`${n}/${e.className}`:e.className}function pt(e,t,n){let r=/* @__PURE__ */ new Set,i=[];for(let a of e){if(!ct.has(a.decorator))continue;let e=n.has(a.className)?ft(a):a.className;if(r.has(e))continue;r.add(e);let o=dt(a.filePath,t),s=a.isDefault?`import('${o}').default`:`import('${o}').${a.className}`;i.push(` '${e}': ${s}`)}let a=i.length?i.join(`
|
|
13
|
+
`):" // (no services discovered yet — run `kick g service <name>` to add one)";return`${Q}
|
|
14
|
+
declare module '@forinda/kickjs' {
|
|
15
|
+
interface KickJsRegistry {
|
|
16
|
+
${a}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export {}
|
|
21
|
+
`}function mt(e){return/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(e)}function ht(e){let t=[...new Set(e.map(e=>e.key))].toSorted().map(e=>` ${mt(e)?e:JSON.stringify(e)}: true`).join(`
|
|
22
|
+
`);return`${Q}
|
|
23
|
+
declare module '@forinda/kickjs' {
|
|
24
|
+
/**
|
|
25
|
+
* Key-only registry of every context key produced by a
|
|
26
|
+
* \`defineContextDecorator\` / \`defineHttpContextDecorator\` in the
|
|
27
|
+
* project. Feeds \`dependsOn\` typo-checking. Value types live in
|
|
28
|
+
* \`ContextMeta\`; this only records that the key exists.
|
|
29
|
+
*/
|
|
30
|
+
interface ContextKeys {
|
|
31
|
+
${t}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export {}
|
|
36
|
+
`}function gt(e,t,n){if(t.length===0)return`${Q}
|
|
37
|
+
// ${n}
|
|
38
|
+
export type ${e} = never
|
|
39
|
+
`;let r=[...new Set(t)].toSorted();return`${Q}
|
|
40
|
+
export type ${e} =
|
|
41
|
+
${r.map(e=>` | '${e}'`).join(`
|
|
42
|
+
`)}
|
|
43
|
+
`}function _t(e,t,n,r){return[...e.filter(e=>ct.has(e.decorator)).map(e=>r.has(e.className)?ft(e):e.className),...t.map(e=>e.name),...n.map(e=>e.name)]}function vt(e){return e.filter(e=>e.decorator===`Module`).map(e=>e.className)}const yt=/* @__PURE__ */ new Set(/* @__PURE__ */ `string.number.boolean.bigint.symbol.object.unknown.any.never.void.null.undefined.true.false.Array.ReadonlyArray.Record.Partial.Required.Readonly.Pick.Omit.Date.RegExp.Map.Set.ReadonlyMap.ReadonlySet.Promise.Error.URL.Uint8Array.ArrayBuffer`.split(`.`));function bt(e){return(e.replace(/'[^']*'|"[^"]*"|`[^`]*`/g,``).replace(/[A-Za-z_$][A-Za-z0-9_$]*\s*\??\s*:/g,`:`).match(/[A-Za-z_$][A-Za-z0-9_$]*/g)??[]).every(e=>yt.has(e))}const xt=e=>{let t=e??`true`,n=[];return t.replace(/'[^']*'|"[^"]*"|`[^`]*`/g,e=>(n.push(e),`@@kicklit${n.length-1}@@`)).replace(/\s+/g,``).replace(/@@kicklit(\d+)@@/g,(e,t)=>n[Number(t)])};function St(e){let t=/* @__PURE__ */ new Map;for(let n of e){let e=t.get(n.name);if(!e)t.set(n.name,n);else if(xt(e.valueType)!==xt(n.valueType))throw Error(`Route flag '${n.name}' is declared with two different value types:\n ${e.relativePath}: ${e.valueType??`true`}\n ${n.relativePath}: ${n.valueType??`true`}\nDeclare the flag once and import it, or give the two flags different names.`)}let n=[...t.values()].toSorted((e,t)=>e.name.localeCompare(t.name)).map(e=>{let t=JSON.stringify(e.name);return e.valueType===null?` ${t}: true`:bt(e.valueType)?` ${t}: ${e.valueType}`:` // '${e.valueType.replace(/\s+/g,` `).trim()}' is declared in ${e.relativePath}, not in scope here.\n // Inline the type at the defineRouteFlag call, or declare this flag by hand.\n ${t}: unknown`}).join(`
|
|
44
|
+
`);return`${Q}
|
|
45
|
+
declare module '@forinda/kickjs' {
|
|
46
|
+
/**
|
|
47
|
+
* Every route flag declared in this project, from its \`defineRouteFlag\`
|
|
48
|
+
* call site. A bare flag carries \`true\`; one declared with an explicit
|
|
49
|
+
* value type carries that type.
|
|
50
|
+
*
|
|
51
|
+
* The \`keyof\` narrows every flag name in the codebase — \`skipWhen\`,
|
|
52
|
+
* \`onlyWhen\`, \`exemptWhen\`, \`flags.has()\` — so a typo is a compile
|
|
53
|
+
* error rather than a flag that silently never matches.
|
|
54
|
+
*/
|
|
55
|
+
interface KickRouteFlags {
|
|
56
|
+
${n||" // (no route flags discovered yet — `defineRouteFlag(...)` calls feed this)"}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export {}
|
|
61
|
+
`}function Ct(e){let t=/* @__PURE__ */ new Map;for(let n of e)t.has(n.name)||t.set(n.name,n);let n=[...t.values()].toSorted((e,t)=>e.name.localeCompare(t.name)).map(e=>` '${e.name}': '${e.kind}'`).join(`
|
|
62
|
+
`);return`${Q}
|
|
63
|
+
declare module '@forinda/kickjs' {
|
|
64
|
+
/**
|
|
65
|
+
* Map of every plugin/adapter \`name\` discovered in the project. The
|
|
66
|
+
* value type is the kind tag (\`'plugin'\` or \`'adapter'\`); the
|
|
67
|
+
* \`keyof\` of this interface narrows \`dependsOn\` so misspelled deps
|
|
68
|
+
* become compile errors instead of boot-time \`MissingMountDepError\`.
|
|
69
|
+
*/
|
|
70
|
+
interface KickJsPluginRegistry {
|
|
71
|
+
${n||" // (no plugins/adapters discovered yet — `defineAdapter`/`definePlugin` calls feed this)"}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export {}
|
|
76
|
+
`}const wt=/^[a-z][a-z\d_-]*(\/[A-Za-z][\w-]*)+(:[a-z][\w-]+)*$/;function Tt(e){let t=[];for(let n of e){let e=n.name;e.startsWith(`kickjs.`)||wt.test(e)||t.push({token:e,variable:n.variable,filePath:n.relativePath,reason:"does not match `<scope>/<area>/<key>[:<instance>]`",suggestion:Et(e)})}return t}function Et(e){if(/^[A-Za-z]\w*$/.test(e))return`'<scope>/<area>/${e}' (e.g. 'app/${e}')`;if(e.includes(`.`))return`'${e.toLowerCase().split(`.`).join(`/`)}' — slashes, not dots`}function Dt(e,t){if(!e)return{entries:[],count:0};let n=/* @__PURE__ */ new Map;for(let[r,i]of Object.entries(e)){if(!i||typeof i.src!=`string`)continue;let e=o(t,i.src);if(!Mt(e))continue;let a=h(i.glob??`**/*`,{cwd:e,nodir:!0,dot:!1,posix:!0});a.sort();let{pairs:s}=g(r,a,{strategy:i.keys??`auto`});for(let{key:e}of s){let t=e.slice(r.length+1);n.set(e,{namespace:r,key:t})}}return{entries:[...n.values()],count:n.size}}function Ot(e){let t="/* eslint-disable */\n// AUTO-GENERATED by `kick typegen`. DO NOT EDIT.\n// Re-run with `kick typegen` or rely on `kick dev` to refresh.\n";if(e.entries.length===0)return`${t}
|
|
77
|
+
declare module '@forinda/kickjs' {
|
|
78
|
+
/**
|
|
79
|
+
* Map of every typed asset discovered in the project's assetMap.
|
|
80
|
+
* (No assetMap entries discovered yet — declare with
|
|
81
|
+
* \`assetMap: { name: { src: 'src/...' } }\` in kick.config.ts.)
|
|
82
|
+
*/
|
|
83
|
+
interface KickAssets {}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export {}
|
|
87
|
+
`;let n={};for(let t of e.entries){let e=`${t.namespace}/${t.key}`.split(`/`),r=n;for(let t=0;t<e.length-1;t++){let n=e[t],i=r[n];if(i===kt){let e={};r[n]=e,r=e}else i||(r[n]={}),r=r[n]}let i=e[e.length-1];typeof r[i]!=`object`&&(r[i]=kt)}return`${t}
|
|
88
|
+
declare module '@forinda/kickjs' {
|
|
89
|
+
/**
|
|
90
|
+
* Map of every typed asset discovered in the project's assetMap.
|
|
91
|
+
* Each leaf is a \`() => string\` thunk that returns the resolved
|
|
92
|
+
* absolute path for the file in the current run mode (dev → src,
|
|
93
|
+
* prod → dist).
|
|
94
|
+
*/
|
|
95
|
+
interface KickAssets {
|
|
96
|
+
${At(n,` `)}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export {}
|
|
101
|
+
`}const kt=Symbol(`asset-leaf`);function At(e,t){let n=Object.keys(e).toSorted(),r=[];for(let i of n){let n=e[i],a=jt(i)?i:JSON.stringify(i);n===kt?r.push(`${t}${a}: () => string`):(r.push(`${t}${a}: {`),r.push(At(n,`${t} `)),r.push(`${t}}`))}return r.join(`
|
|
102
|
+
`)}function jt(e){return/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(e)}function Mt(e){try{return t(e).isDirectory()}catch{return!1}}var Nt=/* @__PURE__ */ e({runTypegen:()=>Ft,sweepStaleTypegen:()=>zt,watchTypegen:()=>Rt,writeTypegenArtifacts:()=>$});function Pt(e){let t=e.cwd??process.cwd();return{cwd:t,srcDir:o(t,e.srcDir??`src`),outDir:o(t,e.outDir??`.kickjs/types`),silent:e.silent??!1,allowDuplicates:e.allowDuplicates??!1,schemaValidator:e.schemaValidator??!1,envFile:e.envFile??`src/env.ts`}}async function Ft(e={}){let{cwd:t,srcDir:n,outDir:r,silent:i,allowDuplicates:a,envFile:s}=Pt(e),c=Date.now(),l={root:n,cwd:t,cacheDir:e.noCache?void 0:o(t,`.kickjs`,`cache`),envFile:s===!1?void 0:s},u=e.changedFiles?await Qe(l,e.changedFiles):await Z(l);if(u.collisions.length>0&&!a)throw new lt(u.collisions);let d=Dt(e.assetMap,t),f=[],p=[];if(e.runPlugins!==!1){try{let{runAllPluginTypegens:n}=await import(`./builtins-Cjp9FT1m.mjs`).then(e=>e.n),{loadKickConfig:r}=await import(`./config-DMFwBdWg.mjs`).then(e=>e.n);f=await n({cwd:t,config:await r(t),silent:!0,changedFiles:e.changedFiles})}catch(e){if(!i){let t=e instanceof Error?e.message:String(e);console.warn(` kick typegen: plugin pipeline failed (${t}) — continuing`)}}p.push(...await $(r,f,i))}let m=Tt(u.tokens),h=Lt(u,d.count,p),g=Date.now()-c;if(!i){let e=r.replace(t+`/`,``),n=h.resolvedCollisions>0?`, ${h.resolvedCollisions} collisions namespaced`:``,i=h.envWritten?`, env typed`:``,a=h.pluginEntries>0?`, ${h.pluginEntries} plugins/adapters`:``,o=h.assetEntries>0?`, ${h.assetEntries} assets`:``;if(console.log(` kick typegen → ${h.serviceTokens} services, ${h.routeEntries} routes, ${h.moduleTokens} modules${a}${o}${i}${n} → ${e} (${g}ms)`),m.length>0){console.warn(` kick typegen: ${m.length} token(s) don't match the <scope>/<area>/<key> convention:`);for(let e of m){let t=e.variable?` [${e.variable}]`:``;console.warn(` '${e.token}' (${e.filePath})${t} — ${e.reason}`),e.suggestion&&console.warn(` → suggestion: ${e.suggestion}`)}}}return u.orphanedClasses.length>0&&await It(u.orphanedClasses,{fix:e.fix??!1,silent:i}),{scan:u,result:h,tokenWarnings:m}}async function It(e,{fix:t,silent:n}){let r=/* @__PURE__ */ new Map;for(let t of e){let e=r.get(t.moduleFilePath)??[];e.push(t),r.set(t.moduleFilePath,e)}if(t){let e=0,t=[];for(let[i,a]of r){let r=nt(a);try{let a=await l(i,`utf-8`),o=st(a,r);o&&o!==a?(await p(i,o),e++,n||console.log(` kick typegen --fix: patched ${i}\n + ${r.join(`, `)}`)):t.push(i)}catch{t.push(i)}}if(!n&&(e>0&&console.log(` kick typegen --fix: updated ${e} module glob(s) — re-run typegen to pick up the now-loaded classes.`),t.length>0)){console.warn(` kick typegen --fix: could not auto-patch ${t.length} module(s) (no import.meta.glob() call found) — add the patterns by hand:`);for(let e of t){let t=r.get(e)??[];console.warn(` ${e}: ${nt(t).join(`, `)}`)}}}else if(!n){console.warn(` kick typegen: ${e.length} decorated class(es) not matched by any module's import.meta.glob():`);for(let[e,t]of r){for(let e of t)console.warn(` @${e.decorator} ${e.className} (${e.relativePath})`);let n=nt(t);console.warn(` → add to import.meta.glob([...]) in ${e}:`),console.warn(` ${n.map(e=>`'${e}'`).join(`, `)}`)}console.warn(" → or run `kick typegen --fix` to apply these automatically.")}}function Lt(e,t,n){let r=new Set(e.collisions.map(e=>e.className)),i=e.classes.filter(e=>ct.has(e.decorator)),a=_t(e.classes,e.tokens,e.injects,r);return{registryEntries:i.length,serviceTokens:new Set(a).size,moduleTokens:vt(e.classes).length,routeEntries:e.routes.length,pluginEntries:new Set(e.pluginsAndAdapters.map(e=>e.name)).size,assetEntries:t,envWritten:e.env!==null,written:n,resolvedCollisions:e.collisions.length}}async function $(e,t,n){await c(e,{recursive:!0}),await p(i(r(e),`.gitignore`),`# Auto-generated by kick typegen
|
|
103
|
+
*
|
|
104
|
+
`,`utf-8`);let a=t.filter(e=>e.outFile).map(e=>e.outFile);return await zt(e,a,t,n),a}async function Rt(e={}){let t=Pt(e),{srcDir:n,silent:r,cwd:i}=t,a={...t,allowDuplicates:!0,runPlugins:!1,noCache:e.noCache},o=process.env.KICKJS_WATCH_POLLING===`1`||process.env.KICKJS_WATCH_POLLING===`true`,[{runAllPluginTypegens:s},{loadKickConfig:c}]=await Promise.all([import(`./builtins-Cjp9FT1m.mjs`).then(e=>e.n),import(`./config-DMFwBdWg.mjs`).then(e=>e.n)]),l=await c(i),u=async()=>{try{await Ft({...a})}catch(e){if(r)return;if(e instanceof lt)console.error(`
|
|
105
|
+
`+e.message+`
|
|
106
|
+
`);else{let t=e instanceof Error?e.message:String(e);console.error(` kick typegen failed: ${t}`)}}},d=async()=>{try{let e=await s({cwd:i,config:l,silent:!0,watch:!0});await $(t.outDir,e,!0)}catch{}};await u(),await d();let{watch:f}=await import(`node:fs`),p=null,m=e=>{e&&/\.(ts|tsx|mts|cts)$/.test(e)&&(e.includes(`.kickjs`)||e.endsWith(`.d.ts`)||(p&&clearTimeout(p),p=setTimeout(()=>{u().then(d)},100)))};if(o){r||console.log(` kick typegen: polling mode (KICKJS_WATCH_POLLING)`);let e=setInterval(()=>{u().then(d)},2e3);return()=>clearInterval(e)}let h;try{h=f(n,{recursive:!0},(e,t)=>{m(t)})}catch(e){r||console.warn(` kick typegen: watch mode unavailable (${e?.message??e}). Falling back to polling.`);let t=setInterval(()=>{u().then(d)},2e3);return()=>clearInterval(t)}return()=>{p&&clearTimeout(p),h.close()}}async function zt(e,t,r,i){let a=/* @__PURE__ */ new Set;for(let e of t)a.add(n(e));for(let e of r)e.outFile&&a.add(n(e.outFile));let s;try{s=await u(e)}catch{return[]}let c=[];for(let t of s){if(!Bt.has(t)||a.has(t))continue;let n=o(e,t);try{if(!(await d(n)).isFile())continue;await f(n),c.push(t)}catch{}}return c.length>0&&!i&&console.log(` kick typegen: swept ${c.length} stale file(s): ${c.join(`, `)}`),c}const Bt=/* @__PURE__ */ new Set([`assets.d.ts`,`env.ts`,`routes.ts`,`registry.d.ts`,`services.d.ts`,`modules.d.ts`,`plugins.d.ts`,`augmentations.d.ts`,`index.d.ts`,`kick__augmentations.d.ts`]);export{w as C,S,j as _,Dt as a,D as b,vt as c,Ct as d,pt as f,Qe as g,Z as h,$ as i,_t as l,gt as m,Nt as n,Ot as o,St as p,Rt as r,lt as s,Ft as t,ht as u,A as v,C as w,T as x,O as y};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forinda/kickjs-cli",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.12.0",
|
|
4
4
|
"description": "CLI for KickJS — project scaffolding, DDD module generation, dev/build/start",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"kickjs",
|
|
@@ -41,9 +41,9 @@
|
|
|
41
41
|
"oxfmt": "^0.72.0",
|
|
42
42
|
"picocolors": "^1.1.1",
|
|
43
43
|
"pluralize": "^8.0.0",
|
|
44
|
+
"@forinda/kickjs": "10.5.0",
|
|
44
45
|
"@forinda/kickjs-cli-kit": "0.1.3",
|
|
45
|
-
"@forinda/kickjs": "
|
|
46
|
-
"@forinda/kickjs-db": "8.7.0"
|
|
46
|
+
"@forinda/kickjs-db": "8.8.0"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"@swc/core": "^1.16.13",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# {{name}}
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Built from the **{{templateLabel}}** template of [KickJS](https://kickjs.app/) — a decorator-driven Node.js framework for TypeScript that runs on Express, Fastify, or h3 (swap the engine in one line).
|
|
4
4
|
|
|
5
5
|
## Getting Started
|
|
6
6
|
|
|
@@ -17,7 +17,7 @@ A **{{templateLabel}}** built with [KickJS](https://kickjs.app/) — a decorator
|
|
|
17
17
|
| `{{runBuild}}` | Production build |
|
|
18
18
|
| `{{runStart}}` | Run production build |
|
|
19
19
|
| `{{runTest}}` | Run tests with Vitest |
|
|
20
|
-
| `{{kick}} g module <name>` | Generate a
|
|
20
|
+
| `{{kick}} g module <name>` | Generate a module |
|
|
21
21
|
| `{{kick}} g scaffold <name> <fields...>` | Generate CRUD from field definitions |
|
|
22
22
|
| `{{kick}} add <package>` | Add a KickJS package |
|
|
23
23
|
|
|
@@ -18,9 +18,4 @@ export class HelloController {
|
|
|
18
18
|
index(_ctx: Ctx<KickRoutes.HelloController['index']>) {
|
|
19
19
|
return this.helloService.greet('World')
|
|
20
20
|
}
|
|
21
|
-
|
|
22
|
-
@Get('/health')
|
|
23
|
-
health(_ctx: Ctx<KickRoutes.HelloController['health']>) {
|
|
24
|
-
return this.helloService.healthCheck()
|
|
25
|
-
}
|
|
26
21
|
}
|
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
"esModuleInterop": true,
|
|
10
10
|
"skipLibCheck": true,
|
|
11
11
|
"sourceMap": true,
|
|
12
|
+
"noEmit": true,
|
|
13
|
+
"allowImportingTsExtensions": true,
|
|
12
14
|
"experimentalDecorators": true,
|
|
13
15
|
"emitDecoratorMetadata": true,
|
|
14
16
|
"outDir": "dist",
|
|
@@ -16,5 +18,5 @@
|
|
|
16
18
|
"@/*": ["./src/*"]
|
|
17
19
|
}
|
|
18
20
|
},
|
|
19
|
-
"include": ["src", "db", ".kickjs/types/**/*.d.ts", ".kickjs/types/**/*.ts"]
|
|
21
|
+
"include": ["src", "db", "*.config.ts", ".kickjs/types/**/*.d.ts", ".kickjs/types/**/*.ts"]
|
|
20
22
|
}
|
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
{
|
|
2
|
-
"
|
|
2
|
+
"devDependencies": ["@forinda/kickjs-devtools"],
|
|
3
3
|
"integrations": [
|
|
4
4
|
{
|
|
5
|
-
"import": {
|
|
6
|
-
"from": "@forinda/kickjs-devtools",
|
|
7
|
-
"names": ["DevToolsAdapter"]
|
|
8
|
-
},
|
|
9
5
|
"slot": "adapter",
|
|
10
|
-
"code": "DevToolsAdapter()"
|
|
6
|
+
"code": "// DevTools at /_debug under `kick dev` only. `kick build` compiles this\n// branch out, so the package never reaches the production bundle\n// (guide/devtools, \"Stripping DevTools from production bundles\").\n...(__KICKJS_DEVTOOLS__\n ? [(await import('@forinda/kickjs-devtools')).DevToolsAdapter()]\n : [])"
|
|
11
7
|
}
|
|
12
8
|
]
|
|
13
9
|
}
|
|
@@ -6,11 +6,47 @@
|
|
|
6
6
|
"integrations": [
|
|
7
7
|
{
|
|
8
8
|
"import": {
|
|
9
|
-
"from": "
|
|
10
|
-
"names": ["
|
|
9
|
+
"from": "./adapters/queue",
|
|
10
|
+
"names": ["queueAdapter"]
|
|
11
11
|
},
|
|
12
12
|
"slot": "adapter",
|
|
13
|
-
"code": "// BullMQ over Redis
|
|
13
|
+
"code": "// BullMQ over Redis (REDIS_* in src/config).\nqueueAdapter()"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"slot": "env-zod",
|
|
17
|
+
"code": "REDIS_HOST: z.string().default('127.0.0.1')"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"slot": "env-zod",
|
|
21
|
+
"code": "REDIS_PORT: z.coerce.number().default(6379)"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"slot": "env-zod",
|
|
25
|
+
"code": "// No default: a local Redis needs none, a real one needs its own.\nREDIS_PASSWORD: z.string().optional()"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"slot": "env-valibot",
|
|
29
|
+
"code": "REDIS_HOST: v.optional(v.string(), '127.0.0.1')"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"slot": "env-valibot",
|
|
33
|
+
"code": "REDIS_PORT: v.optional(v.pipe(v.string(), v.transform(Number)), '6379')"
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"slot": "env-valibot",
|
|
37
|
+
"code": "// No default: a local Redis needs none, a real one needs its own.\nREDIS_PASSWORD: v.optional(v.string())"
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"slot": "env-yup",
|
|
41
|
+
"code": "REDIS_HOST: yup.string().default('127.0.0.1')"
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"slot": "env-yup",
|
|
45
|
+
"code": "REDIS_PORT: yup.number().default(6379)"
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"slot": "env-yup",
|
|
49
|
+
"code": "// No default: a local Redis needs none, a real one needs its own.\nREDIS_PASSWORD: yup.string().optional()"
|
|
14
50
|
}
|
|
15
51
|
]
|
|
16
52
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { getEnv } from '@forinda/kickjs'
|
|
2
|
+
import { QueueAdapter } from '@forinda/kickjs-queue'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* BullMQ over Redis, at REDIS_HOST / REDIS_PORT (REDIS_PASSWORD when the
|
|
6
|
+
* server needs one) — declared in src/config. Nothing connects until a @Job
|
|
7
|
+
* class or a queue is used, so the app boots without Redis running.
|
|
8
|
+
*/
|
|
9
|
+
export const queueAdapter = () =>
|
|
10
|
+
QueueAdapter({
|
|
11
|
+
redis: {
|
|
12
|
+
host: getEnv('REDIS_HOST'),
|
|
13
|
+
port: getEnv('REDIS_PORT'),
|
|
14
|
+
password: getEnv('REDIS_PASSWORD'),
|
|
15
|
+
},
|
|
16
|
+
})
|
|
@@ -23,6 +23,7 @@ const envSchema = fromValibot(
|
|
|
23
23
|
NODE_ENV: v.optional(v.picklist(['development', 'production', 'test']), 'development'),
|
|
24
24
|
LOG_LEVEL: v.optional(v.string(), 'info'),
|
|
25
25
|
// DATABASE_URL: v.pipe(v.string(), v.url()),
|
|
26
|
+
// @kick:env-valibot
|
|
26
27
|
}),
|
|
27
28
|
)
|
|
28
29
|
|
|
@@ -34,8 +35,10 @@ const envSchema = fromValibot(
|
|
|
34
35
|
*
|
|
35
36
|
* As long as `src/index.ts` imports this file (`import './config'`) at
|
|
36
37
|
* the top — before `bootstrap()` runs — every controller and service
|
|
37
|
-
* in the app sees the typed extended values.
|
|
38
|
+
* in the app sees the typed extended values. Read them with
|
|
39
|
+
* `getEnv('KEY')` from `@forinda/kickjs`, `ConfigService`, or `@Value()`;
|
|
40
|
+
* this file exports no parsed env object.
|
|
38
41
|
*/
|
|
39
|
-
|
|
42
|
+
loadEnvFromSchema(envSchema)
|
|
40
43
|
|
|
41
44
|
export default envSchema
|
|
@@ -25,6 +25,7 @@ const envSchema = fromYup(
|
|
|
25
25
|
NODE_ENV: yup.string().oneOf(['development', 'production', 'test']).default('development'),
|
|
26
26
|
LOG_LEVEL: yup.string().default('info'),
|
|
27
27
|
// DATABASE_URL: yup.string().required(),
|
|
28
|
+
// @kick:env-yup
|
|
28
29
|
}),
|
|
29
30
|
)
|
|
30
31
|
|
|
@@ -36,8 +37,10 @@ const envSchema = fromYup(
|
|
|
36
37
|
*
|
|
37
38
|
* As long as `src/index.ts` imports this file (`import './config'`) at
|
|
38
39
|
* the top — before `bootstrap()` runs — every controller and service
|
|
39
|
-
* in the app sees the typed extended values.
|
|
40
|
+
* in the app sees the typed extended values. Read them with
|
|
41
|
+
* `getEnv('KEY')` from `@forinda/kickjs`, `ConfigService`, or `@Value()`;
|
|
42
|
+
* this file exports no parsed env object.
|
|
40
43
|
*/
|
|
41
|
-
|
|
44
|
+
loadEnvFromSchema(envSchema)
|
|
42
45
|
|
|
43
46
|
export default envSchema
|
|
@@ -23,6 +23,7 @@ const envSchema = fromZod(
|
|
|
23
23
|
NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),
|
|
24
24
|
LOG_LEVEL: z.string().default('info'),
|
|
25
25
|
// DATABASE_URL: z.url(),
|
|
26
|
+
// @kick:env-zod
|
|
26
27
|
}),
|
|
27
28
|
)
|
|
28
29
|
|
|
@@ -34,8 +35,10 @@ const envSchema = fromZod(
|
|
|
34
35
|
*
|
|
35
36
|
* As long as `src/index.ts` imports this file (`import './config'`) at
|
|
36
37
|
* the top — before `bootstrap()` runs — every controller and service
|
|
37
|
-
* in the app sees the typed extended values.
|
|
38
|
+
* in the app sees the typed extended values. Read them with
|
|
39
|
+
* `getEnv('KEY')` from `@forinda/kickjs`, `ConfigService`, or `@Value()`;
|
|
40
|
+
* this file exports no parsed env object.
|
|
38
41
|
*/
|
|
39
|
-
|
|
42
|
+
loadEnvFromSchema(envSchema)
|
|
40
43
|
|
|
41
44
|
export default envSchema
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
{
|
|
17
17
|
"import": {
|
|
18
18
|
"from": "@forinda/kickjs",
|
|
19
|
-
"names": ["bootstrap", "requestId", "session"]
|
|
19
|
+
"names": ["bootstrap", "getEnv", "requestId", "session"]
|
|
20
20
|
}
|
|
21
21
|
},
|
|
22
22
|
{
|
|
@@ -24,6 +24,14 @@
|
|
|
24
24
|
"from": "@forinda/kickjs-inertia",
|
|
25
25
|
"names": ["InertiaAdapter", "inertiaErrorHandler", "inertiaNotFound"]
|
|
26
26
|
}
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"slot": "env-zod",
|
|
30
|
+
"code": "// Signs the session cookie. The public dev-only default is accepted only when\n// NODE_ENV is 'development' (kick dev) or 'test' (vitest); anywhere else,\n// including an unset NODE_ENV, a real secret is required.\nSESSION_SECRET: z\n .string()\n .min(32)\n .default('dev-only-session-secret-not-for-production')\n // `: boolean` \u2014 inferring it would make this schema's type depend on\n // process.env, whose type `kick typegen` derives from this schema.\n .refine(\n (s): boolean =>\n ['development', 'test'].includes(process.env.NODE_ENV ?? '') ||\n !s.startsWith('dev-only-'),\n { error: 'set SESSION_SECRET \u2014 the dev-only default is public' },\n )"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"slot": "env-zod",
|
|
34
|
+
"code": "// The site's public URL \u2014 canonical links, the sitemap and social-card images\n// are built from it, never from the request's Host header. The localhost\n// default is accepted only when NODE_ENV is 'development' or 'test'; anywhere\n// else, including an unset NODE_ENV, APP_URL must be set.\nAPP_URL: z\n .url()\n .default('http://localhost:3000')\n .refine(\n (): boolean =>\n ['development', 'test'].includes(process.env.NODE_ENV ?? '') ||\n process.env.APP_URL !== undefined,\n { error: 'set APP_URL to the public URL of the site' },\n )"
|
|
27
35
|
}
|
|
28
36
|
]
|
|
29
37
|
}
|
|
@@ -1,2 +1,6 @@
|
|
|
1
|
-
# Signs the session cookie — at least 32 random characters.
|
|
2
|
-
|
|
1
|
+
# Signs the session cookie — at least 32 random characters. Required everywhere
|
|
2
|
+
# except NODE_ENV=development or test, which fall back to a fixed dev-only value.
|
|
3
|
+
# SESSION_SECRET=
|
|
4
|
+
# The site's public URL, e.g. https://example.com. Required everywhere except
|
|
5
|
+
# NODE_ENV=development or test, which fall back to http://localhost:3000.
|
|
6
|
+
# APP_URL=
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Link, usePage } from '@inertiajs/react'
|
|
2
2
|
import type { ReactNode } from 'react'
|
|
3
|
+
import { Seo } from '@/client/Seo'
|
|
3
4
|
|
|
4
5
|
export function Layout({ children }: { children: ReactNode }) {
|
|
5
6
|
const page = usePage<{ appName: string }>()
|
|
@@ -8,6 +9,7 @@ export function Layout({ children }: { children: ReactNode }) {
|
|
|
8
9
|
<main
|
|
9
10
|
style={{ fontFamily: 'system-ui', maxWidth: 640, margin: '2rem auto', padding: '0 1rem' }}
|
|
10
11
|
>
|
|
12
|
+
<Seo />
|
|
11
13
|
<nav style={{ display: 'flex', gap: 12 }}>
|
|
12
14
|
<strong>{page.props.appName}</strong>
|
|
13
15
|
<Link href="/">Home</Link>
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Head, usePage } from '@inertiajs/react'
|
|
2
|
+
import type { PageMeta } from '@forinda/kickjs-inertia'
|
|
3
|
+
|
|
4
|
+
// Renders the meta a controller passes to inertia(..., { meta }), merged with
|
|
5
|
+
// the InertiaAdapter `meta` defaults — on the server (SSR) and again on every
|
|
6
|
+
// client-side visit, so the browser's title and tags follow the page. The
|
|
7
|
+
// head-keys match the tags the adapter writes, so each tag is replaced, not
|
|
8
|
+
// duplicated.
|
|
9
|
+
export function Seo() {
|
|
10
|
+
const meta = (usePage() as { meta?: PageMeta }).meta
|
|
11
|
+
if (!meta) return null
|
|
12
|
+
return (
|
|
13
|
+
<Head title={meta.title}>
|
|
14
|
+
{meta.description && (
|
|
15
|
+
<meta head-key="description" name="description" content={meta.description} />
|
|
16
|
+
)}
|
|
17
|
+
{meta.robots && <meta head-key="robots" name="robots" content={meta.robots} />}
|
|
18
|
+
{meta.canonical && <link head-key="canonical" rel="canonical" href={meta.canonical} />}
|
|
19
|
+
{Object.entries(meta.og ?? {}).map(([key, value]) => (
|
|
20
|
+
<meta key={key} head-key={`og:${key}`} property={`og:${key}`} content={value} />
|
|
21
|
+
))}
|
|
22
|
+
{Object.entries(meta.twitter ?? {}).map(([key, value]) => (
|
|
23
|
+
<meta key={key} head-key={`twitter:${key}`} name={`twitter:${key}`} content={value} />
|
|
24
|
+
))}
|
|
25
|
+
{meta.jsonLd && (
|
|
26
|
+
<script
|
|
27
|
+
head-key="json-ld"
|
|
28
|
+
type="application/ld+json"
|
|
29
|
+
// `<` escaped, so a value can't close the script tag.
|
|
30
|
+
dangerouslySetInnerHTML={{ __html: JSON.stringify(meta.jsonLd).replace(/</g, '\\u003c') }}
|
|
31
|
+
/>
|
|
32
|
+
)}
|
|
33
|
+
</Head>
|
|
34
|
+
)
|
|
35
|
+
}
|
|
@@ -7,9 +7,6 @@ import './config'
|
|
|
7
7
|
// @kick:imports
|
|
8
8
|
import { modules } from './modules'
|
|
9
9
|
|
|
10
|
-
const sessionSecret = process.env.SESSION_SECRET
|
|
11
|
-
if (!sessionSecret) throw new Error('SESSION_SECRET is not set — see .env.example')
|
|
12
|
-
|
|
13
10
|
// Export the app for the Vite plugin (dev mode)
|
|
14
11
|
export const app = await bootstrap({
|
|
15
12
|
modules,
|
|
@@ -20,14 +17,23 @@ export const app = await bootstrap({
|
|
|
20
17
|
// Carries validation errors and flash messages to the next page. Kept in
|
|
21
18
|
// an encrypted cookie, so it works on any number of instances — several
|
|
22
19
|
// containers, or Netlify / Vercel functions — with nothing shared.
|
|
23
|
-
session({ secret:
|
|
20
|
+
session({ secret: getEnv('SESSION_SECRET'), store: 'cookie' }),
|
|
24
21
|
],
|
|
25
22
|
adapters: [
|
|
26
23
|
InertiaAdapter({
|
|
27
24
|
title: '{{name}}',
|
|
28
25
|
entry: 'src/client/main.tsx',
|
|
29
|
-
// On every page. Per-page titles and meta: Inertia's <Head> component.
|
|
30
26
|
head: '<link rel="icon" href="/favicon.svg" type="image/svg+xml" />',
|
|
27
|
+
// Canonical URLs and absolute image URLs start here — not at the Host header.
|
|
28
|
+
baseUrl: getEnv('APP_URL'),
|
|
29
|
+
// Every page's meta starts from these; a controller adds its own with
|
|
30
|
+
// inertia(component, props, { meta }), and src/client/Seo.tsx keeps the
|
|
31
|
+
// browser's <head> in sync on client-side visits.
|
|
32
|
+
meta: {
|
|
33
|
+
titleTemplate: '%s · {{name}}',
|
|
34
|
+
description: '{{name}}, built with KickJS and Inertia.',
|
|
35
|
+
og: { site_name: '{{name}}', type: 'website' },
|
|
36
|
+
},
|
|
31
37
|
// Props every page receives.
|
|
32
38
|
share: () => ({ appName: '{{name}}' }),
|
|
33
39
|
ssr: { entry: 'src/client/ssr.tsx' },
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { defineModules } from '@forinda/kickjs'
|
|
2
2
|
import { HelloModule } from './hello/hello.module'
|
|
3
3
|
import { PagesModule } from './pages/pages.module'
|
|
4
|
+
import { SeoModule } from './seo/seo.module'
|
|
4
5
|
|
|
5
6
|
// Every module the app mounts. `kick g module <name>` appends a `.mount(...)`
|
|
6
7
|
// line here; `kick rm module <name>` takes one out.
|
|
7
|
-
export const modules = defineModules().mount(HelloModule()).mount(PagesModule())
|
|
8
|
+
export const modules = defineModules().mount(HelloModule()).mount(PagesModule()).mount(SeoModule())
|