@ooneex/cli 1.10.1 → 1.11.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/index.js +218 -187
- package/dist/index.js.map +21 -21
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,38 +1,38 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
// @bun
|
|
3
|
-
var Sa=Object.create;var{getPrototypeOf:Na,defineProperty:
|
|
4
|
-
`),d=a.length;if(d>0&&a.includes("unstyle"))a=[...new Set(["unstyle",...a])].reverse();while(d-- >0)n=s(e.styles[a[d]],n,l);return n},
|
|
5
|
-
`+s,width:
|
|
6
|
-
`)o.name="enter";else if(e==="\t")o.name="tab";else if(e==="\b"||e==="\x7F"||e==="\x1B\x7F"||e==="\x1B\b")o.name="backspace",o.meta=e.charAt(0)==="\x1B";else if(e==="\x1B"||e==="\x1B\x1B")o.name="escape",o.meta=e.length===2;else if(e===" "||e==="\x1B ")o.name="space",o.meta=e.length===2;else if(e<="\x1A")o.name=String.fromCharCode(e.charCodeAt(0)+97-1),o.ctrl=!0;else if(e.length===1&&e>="0"&&e<="9")o.name="number";else if(e.length===1&&e>="a"&&e<="z")o.name=e;else if(e.length===1&&e>="A"&&e<="Z")o.name=e.toLowerCase(),o.shift=!0;else if(s=Sn.exec(e))o.meta=!0,o.shift=/^[A-Z]$/.test(s[1]);else if(s=Nn.exec(e)){let r=[...e];if(r[0]==="\x1B"&&r[1]==="\x1B")o.option=!0;let i=[s[1],s[2],s[4],s[6]].filter(Boolean).join(""),a=(s[3]||s[5]||1)-1;o.ctrl=!!(a&4),o.meta=!!(a&10),o.shift=!!(a&1),o.code=i,o.name=Rn[i],o.shift=Cn(i)||o.shift,o.ctrl=Mn(i)||o.ctrl}return o};Pe.listen=(e={},t)=>{let{stdin:s}=e;if(!s||s!==process.stdin&&!s.isTTY)throw Error("Invalid stream passed");let o=ms.createInterface({terminal:!0,input:s});ms.emitKeypressEvents(s,o);let r=new Tn((n,l)=>t(n,Pe(n,l),o)),i=s.isRaw;if(s.isTTY)s.setRawMode(!0);return s.on("keypress",r.enqueue),o.resume(),()=>{if(s.isTTY)s.setRawMode(i);s.removeListener("keypress",r.enqueue),r.destroy(),o.pause(),o.close()}};Pe.action=(e,t,s)=>{let o={...An,...s};if(t.ctrl)return t.action=o.ctrl[t.name],t;if(t.option&&o.option)return t.action=o.option[t.name],t;if(t.shift)return t.action=o.shift[t.name],t;return t.action=o.keys[t.name],t};us.exports=Pe});var fs=E((Mm,hs)=>{hs.exports=(e)=>{e.timers=e.timers||{};let t=e.options.timers;if(!t)return;for(let s of Object.keys(t)){let o=t[s];if(typeof o==="number")o={interval:o};_n(e,s,o)}};function _n(e,t,s={}){let o=e.timers[t]={name:t,start:Date.now(),ms:0,tick:0},r=s.interval||120;o.frames=s.frames||[],o.loading=!0;let i=setInterval(()=>{o.ms=Date.now()-o.start,o.tick++,e.render()},r);return o.stop=()=>{o.loading=!1,clearInterval(i)},Reflect.defineProperty(o,"interval",{value:i}),e.once("close",()=>o.stop()),o.stop}});var bs=E((_m,gs)=>{var{define:Bn,width:In}=M();class ys{constructor(e){let t=e.options;Bn(this,"_prompt",e),this.type=e.type,this.name=e.name,this.message="",this.header="",this.footer="",this.error="",this.hint="",this.input="",this.cursor=0,this.index=0,this.lines=0,this.tick=0,this.prompt="",this.buffer="",this.width=In(t.stdout||process.stdout),Object.assign(this,t),this.name=this.name||this.message,this.message=this.message||this.name,this.symbols=e.symbols,this.styles=e.styles,this.required=new Set,this.cancelled=!1,this.submitted=!1}clone(){let e={...this};return e.status=this.status,e.buffer=Buffer.from(e.buffer),delete e.clone,e}set color(e){this._color=e}get color(){let e=this.prompt.styles;if(this.cancelled)return e.cancelled;if(this.submitted)return e.submitted;let t=this._color||e[this.status];return typeof t==="function"?t:e.pending}set loading(e){this._loading=e}get loading(){if(typeof this._loading==="boolean")return this._loading;if(this.loadingChoices)return"choices";return!1}get status(){if(this.cancelled)return"cancelled";if(this.submitted)return"submitted";return"pending"}}gs.exports=ys});var ws=E((Bm,xs)=>{var ut=M(),R=Ie(),ht={default:R.noop,noop:R.noop,set inverse(e){this._inverse=e},get inverse(){return this._inverse||ut.inverse(this.primary)},set complement(e){this._complement=e},get complement(){return this._complement||ut.complement(this.primary)},primary:R.cyan,success:R.green,danger:R.magenta,strong:R.bold,warning:R.yellow,muted:R.dim,disabled:R.gray,dark:R.dim.gray,underline:R.underline,set info(e){this._info=e},get info(){return this._info||this.primary},set em(e){this._em=e},get em(){return this._em||this.primary.underline},set heading(e){this._heading=e},get heading(){return this._heading||this.muted.underline},set pending(e){this._pending=e},get pending(){return this._pending||this.primary},set submitted(e){this._submitted=e},get submitted(){return this._submitted||this.success},set cancelled(e){this._cancelled=e},get cancelled(){return this._cancelled||this.danger},set typing(e){this._typing=e},get typing(){return this._typing||this.dim},set placeholder(e){this._placeholder=e},get placeholder(){return this._placeholder||this.primary.dim},set highlight(e){this._highlight=e},get highlight(){return this._highlight||this.inverse}};ht.merge=(e={})=>{if(e.styles&&typeof e.styles.enabled==="boolean")R.enabled=e.styles.enabled;if(e.styles&&typeof e.styles.visible==="boolean")R.visible=e.styles.visible;let t=ut.merge({},ht,e.styles);delete t.merge;for(let s of Object.keys(R))if(!hasOwnProperty.call(t,s))Reflect.defineProperty(t,s,{get:()=>R[s]});for(let s of Object.keys(R.styles))if(!hasOwnProperty.call(t,s))Reflect.defineProperty(t,s,{get:()=>R[s]});return t};xs.exports=ht});var vs=E((Im,Es)=>{var ft=process.platform==="win32",K=Ie(),On=M(),yt={...K.symbols,upDownDoubleArrow:"\u21D5",upDownDoubleArrow2:"\u2B0D",upDownArrow:"\u2195",asterisk:"*",asterism:"\u2042",bulletWhite:"\u25E6",electricArrow:"\u2301",ellipsisLarge:"\u22EF",ellipsisSmall:"\u2026",fullBlock:"\u2588",identicalTo:"\u2261",indicator:K.symbols.check,leftAngle:"\u2039",mark:"\u203B",minus:"\u2212",multiplication:"\xD7",obelus:"\xF7",percent:"%",pilcrow:"\xB6",pilcrow2:"\u2761",pencilUpRight:"\u2710",pencilDownRight:"\u270E",pencilRight:"\u270F",plus:"+",plusMinus:"\xB1",pointRight:"\u261E",rightAngle:"\u203A",section:"\xA7",hexagon:{off:"\u2B21",on:"\u2B22",disabled:"\u2B22"},ballot:{on:"\u2611",off:"\u2610",disabled:"\u2612"},stars:{on:"\u2605",off:"\u2606",disabled:"\u2606"},folder:{on:"\u25BC",off:"\u25B6",disabled:"\u25B6"},prefix:{pending:K.symbols.question,submitted:K.symbols.check,cancelled:K.symbols.cross},separator:{pending:K.symbols.pointerSmall,submitted:K.symbols.middot,cancelled:K.symbols.middot},radio:{off:ft?"( )":"\u25EF",on:ft?"(*)":"\u25C9",disabled:ft?"(|)":"\u24BE"},numbers:["\u24EA","\u2460","\u2461","\u2462","\u2463","\u2464","\u2465","\u2466","\u2467","\u2468","\u2469","\u246A","\u246B","\u246C","\u246D","\u246E","\u246F","\u2470","\u2471","\u2472","\u2473","\u3251","\u3252","\u3253","\u3254","\u3255","\u3256","\u3257","\u3258","\u3259","\u325A","\u325B","\u325C","\u325D","\u325E","\u325F","\u32B1","\u32B2","\u32B3","\u32B4","\u32B5","\u32B6","\u32B7","\u32B8","\u32B9","\u32BA","\u32BB","\u32BC","\u32BD","\u32BE","\u32BF"]};yt.merge=(e)=>{let t=On.merge({},K.symbols,yt,e.symbols);return delete t.merge,t};Es.exports=yt});var Ts=E((Om,As)=>{var Dn=ws(),Pn=vs(),Ln=M();As.exports=(e)=>{e.options=Ln.merge({},e.options.theme,e.options),e.symbols=Pn.merge(e.options),e.styles=Dn.merge(e.options)}});var Cs=E((Ns,Rs)=>{var Ss=process.env.TERM_PROGRAM==="Apple_Terminal",kn=se(),gt=M(),L=Rs.exports=Ns,bt=!1,oe=L.code={bell:"\x07",beep:"\x07",beginning:"\x1B[G",down:"\x1B[J",esc:"\x1B[",getPosition:"\x1B[6n",hide:"\x1B[?25l",line:"\x1B[2K",lineEnd:"\x1B[K",lineStart:"\x1B[1K",restorePosition:"\x1B["+(Ss?"8":"u"),savePosition:"\x1B["+(Ss?"7":"s"),screen:"\x1B[2J",show:"\x1B[?25h",up:"\x1B[1J"},de=L.cursor={get hidden(){return bt},hide(){return bt=!0,oe.hide},show(){return bt=!1,oe.show},forward:(e=1)=>`\x1B[${e}C`,backward:(e=1)=>`\x1B[${e}D`,nextLine:(e=1)=>"\x1B[E".repeat(e),prevLine:(e=1)=>"\x1B[F".repeat(e),up:(e=1)=>e?`\x1B[${e}A`:"",down:(e=1)=>e?`\x1B[${e}B`:"",right:(e=1)=>e?`\x1B[${e}C`:"",left:(e=1)=>e?`\x1B[${e}D`:"",to(e,t){return t?`\x1B[${t+1};${e+1}H`:`\x1B[${e+1}G`},move(e=0,t=0){let s="";return s+=e<0?de.left(-e):e>0?de.right(e):"",s+=t<0?de.up(-t):t>0?de.down(t):"",s},strLen(e){var t=0,s=e.length,o=-1;for(var r=0;r<s;r++)if(o=e.charCodeAt(r),o>=0&&o<=128)t+=1;else t+=2;return t},restore(e={}){let{after:t,cursor:s,initial:o,input:r,prompt:i,size:a,value:n}=e;if(o=gt.isPrimitive(o)?String(o):"",r=gt.isPrimitive(r)?String(r):"",n=gt.isPrimitive(n)?String(n):"",a){let l=L.cursor.up(a)+L.cursor.to(this.strLen(i)),d=r.length-s;if(d>0)l+=L.cursor.left(d);return l}if(n||t){let l=!r&&!!o?-this.strLen(o):-this.strLen(r)+s;if(t)l-=this.strLen(t);if(r===""&&o&&!i.includes(o))l+=this.strLen(o);return L.cursor.move(l)}}},xt=L.erase={screen:oe.screen,up:oe.up,down:oe.down,line:oe.line,lineEnd:oe.lineEnd,lineStart:oe.lineStart,lines(e){let t="";for(let s=0;s<e;s++)t+=L.erase.line+(s<e-1?L.cursor.up(1):"");if(e)t+=L.code.beginning;return t}};L.clear=(e="",t=process.stdout.columns)=>{if(!t)return xt.line+de.to(0);let s=(i)=>[...kn(i)].length,o=e.split(/\r?\n/),r=0;for(let i of o)r+=1+Math.floor(Math.max(s(i)-1,0)/t);return(xt.line+de.prevLine()).repeat(r-1)+xt.line+de.to(0)}});var fe=E((Dm,_s)=>{var Un=ve("events"),Ms=se(),wt=mt(),Gn=fs(),$n=bs(),qn=Ts(),B=M(),pe=Cs();class Et extends Un{constructor(e={}){super();this.name=e.name,this.type=e.type,this.options=e,qn(this),Gn(this),this.state=new $n(this),this.initial=[e.initial,e.default].find((t)=>t!=null),this.stdout=e.stdout||process.stdout,this.stdin=e.stdin||process.stdin,this.scale=e.scale||1,this.term=this.options.term||process.env.TERM_PROGRAM,this.margin=Fn(this.options.margin),this.setMaxListeners(0),Wn(this)}async keypress(e,t={}){this.keypressed=!0;let s=wt.action(e,wt(e,t),this.options.actions);this.state.keypress=s,this.emit("keypress",e,s),this.emit("state",this.state.clone());let o=this.options[s.action]||this[s.action]||this.dispatch;if(typeof o==="function")return await o.call(this,e,s);this.alert()}alert(){if(delete this.state.alert,this.options.show===!1)this.emit("alert");else this.stdout.write(pe.code.beep)}cursorHide(){this.stdout.write(pe.cursor.hide());let e=B.onExit(()=>this.cursorShow());this.on("close",()=>{this.cursorShow(),e()})}cursorShow(){this.stdout.write(pe.cursor.show())}write(e){if(!e)return;if(this.stdout&&this.state.show!==!1)this.stdout.write(e);this.state.buffer+=e}clear(e=0){let t=this.state.buffer;if(this.state.buffer="",!t&&!e||this.options.show===!1)return;this.stdout.write(pe.cursor.down(e)+pe.clear(t,this.width))}restore(){if(this.state.closed||this.options.show===!1)return;let{prompt:e,after:t,rest:s}=this.sections(),{cursor:o,initial:r="",input:i="",value:a=""}=this,n=this.state.size=s.length,l={after:t,cursor:o,initial:r,input:i,prompt:e,size:n,value:a},d=pe.cursor.restore(l);if(d)this.stdout.write(d)}sections(){let{buffer:e,input:t,prompt:s}=this.state;s=Ms(s);let o=Ms(e),r=o.indexOf(s),i=o.slice(0,r),n=o.slice(r).split(`
|
|
7
|
-
`),l=n[0],d=n[n.length-1],
|
|
3
|
+
var Sa=Object.create;var{getPrototypeOf:Na,defineProperty:Ht,getOwnPropertyNames:Ra}=Object;var Ca=Object.prototype.hasOwnProperty;function Ma(e){return this[e]}var _a,Ba,te=(e,t,s)=>{var r=e!=null&&typeof e==="object";if(r){var o=t?_a??=new WeakMap:Ba??=new WeakMap,i=o.get(e);if(i)return i}s=e!=null?Sa(Na(e)):{};let a=t||!e||!e.__esModule?Ht(s,"default",{value:e,enumerable:!0}):s;for(let n of Ra(e))if(!Ca.call(a,n))Ht(a,n,{get:Ma.bind(e,n),enumerable:!0});if(r)o.set(e,a);return a};var v=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var w=function(e,t,s,r){var o=arguments.length,i=o<3?t:r===null?r=Object.getOwnPropertyDescriptor(t,s):r,a;if(typeof Reflect==="object"&&typeof Reflect.decorate==="function")i=Reflect.decorate(e,t,s,r);else for(var n=e.length-1;n>=0;n--)if(a=e[n])i=(o<3?a(i):o>3?a(t,s,i):a(t,s))||i;return o>3&&i&&Object.defineProperty(t,s,i),i};var Ae=import.meta.require;var jt=v((Em,Te)=>{var Ga=typeof process<"u"&&process.env.TERM_PROGRAM==="Hyper",$a=typeof process<"u"&&process.platform==="win32",Qt=typeof process<"u"&&process.platform==="linux",ct={ballotDisabled:"\u2612",ballotOff:"\u2610",ballotOn:"\u2611",bullet:"\u2022",bulletWhite:"\u25E6",fullBlock:"\u2588",heart:"\u2764",identicalTo:"\u2261",line:"\u2500",mark:"\u203B",middot:"\xB7",minus:"\uFF0D",multiplication:"\xD7",obelus:"\xF7",pencilDownRight:"\u270E",pencilRight:"\u270F",pencilUpRight:"\u2710",percent:"%",pilcrow2:"\u2761",pilcrow:"\xB6",plusMinus:"\xB1",question:"?",section:"\xA7",starsOff:"\u2606",starsOn:"\u2605",upDownArrow:"\u2195"},Zt=Object.assign({},ct,{check:"\u221A",cross:"\xD7",ellipsisLarge:"...",ellipsis:"...",info:"i",questionSmall:"?",pointer:">",pointerSmall:"\xBB",radioOff:"( )",radioOn:"(*)",warning:"\u203C"}),Xt=Object.assign({},ct,{ballotCross:"\u2718",check:"\u2714",cross:"\u2716",ellipsisLarge:"\u22EF",ellipsis:"\u2026",info:"\u2139",questionFull:"\uFF1F",questionSmall:"\uFE56",pointer:Qt?"\u25B8":"\u276F",pointerSmall:Qt?"\u2023":"\u203A",radioOff:"\u25EF",radioOn:"\u25C9",warning:"\u26A0"});Te.exports=$a&&!Ga?Zt:Xt;Reflect.defineProperty(Te.exports,"common",{enumerable:!1,value:ct});Reflect.defineProperty(Te.exports,"windows",{enumerable:!1,value:Zt});Reflect.defineProperty(Te.exports,"other",{enumerable:!1,value:Xt})});var Ie=v((vm,pt)=>{var qa=(e)=>e!==null&&typeof e==="object"&&!Array.isArray(e),Wa=/[\u001b\u009b][[\]#;?()]*(?:(?:(?:[^\W_]*;?[^\W_]*)\u0007)|(?:(?:[0-9]{1,4}(;[0-9]{0,4})*)?[~0-9=<>cf-nqrtyA-PRZ]))/g,Fa=()=>{if(typeof process<"u")return process.env.FORCE_COLOR!=="0";return!1},Jt=()=>{let e={enabled:Fa(),visible:!0,styles:{},keys:{}},t=(i)=>{let a=i.open=`\x1B[${i.codes[0]}m`,n=i.close=`\x1B[${i.codes[1]}m`,l=i.regex=new RegExp(`\\u001b\\[${i.codes[1]}m`,"g");return i.wrap=(d,u)=>{if(d.includes(n))d=d.replace(l,n+a);let h=a+d+n;return u?h.replace(/\r*\n/g,`${n}$&${a}`):h},i},s=(i,a,n)=>{return typeof i==="function"?i(a):i.wrap(a,n)},r=(i,a)=>{if(i===""||i==null)return"";if(e.enabled===!1)return i;if(e.visible===!1)return"";let n=""+i,l=n.includes(`
|
|
4
|
+
`),d=a.length;if(d>0&&a.includes("unstyle"))a=[...new Set(["unstyle",...a])].reverse();while(d-- >0)n=s(e.styles[a[d]],n,l);return n},o=(i,a,n)=>{e.styles[i]=t({name:i,codes:a}),(e.keys[n]||(e.keys[n]=[])).push(i),Reflect.defineProperty(e,i,{configurable:!0,enumerable:!0,set(d){e.alias(i,d)},get(){let d=(u)=>r(u,d.stack);return Reflect.setPrototypeOf(d,e),d.stack=this.stack?this.stack.concat(i):[i],d}})};return o("reset",[0,0],"modifier"),o("bold",[1,22],"modifier"),o("dim",[2,22],"modifier"),o("italic",[3,23],"modifier"),o("underline",[4,24],"modifier"),o("inverse",[7,27],"modifier"),o("hidden",[8,28],"modifier"),o("strikethrough",[9,29],"modifier"),o("black",[30,39],"color"),o("red",[31,39],"color"),o("green",[32,39],"color"),o("yellow",[33,39],"color"),o("blue",[34,39],"color"),o("magenta",[35,39],"color"),o("cyan",[36,39],"color"),o("white",[37,39],"color"),o("gray",[90,39],"color"),o("grey",[90,39],"color"),o("bgBlack",[40,49],"bg"),o("bgRed",[41,49],"bg"),o("bgGreen",[42,49],"bg"),o("bgYellow",[43,49],"bg"),o("bgBlue",[44,49],"bg"),o("bgMagenta",[45,49],"bg"),o("bgCyan",[46,49],"bg"),o("bgWhite",[47,49],"bg"),o("blackBright",[90,39],"bright"),o("redBright",[91,39],"bright"),o("greenBright",[92,39],"bright"),o("yellowBright",[93,39],"bright"),o("blueBright",[94,39],"bright"),o("magentaBright",[95,39],"bright"),o("cyanBright",[96,39],"bright"),o("whiteBright",[97,39],"bright"),o("bgBlackBright",[100,49],"bgBright"),o("bgRedBright",[101,49],"bgBright"),o("bgGreenBright",[102,49],"bgBright"),o("bgYellowBright",[103,49],"bgBright"),o("bgBlueBright",[104,49],"bgBright"),o("bgMagentaBright",[105,49],"bgBright"),o("bgCyanBright",[106,49],"bgBright"),o("bgWhiteBright",[107,49],"bgBright"),e.ansiRegex=Wa,e.hasColor=e.hasAnsi=(i)=>{return e.ansiRegex.lastIndex=0,typeof i==="string"&&i!==""&&e.ansiRegex.test(i)},e.alias=(i,a)=>{let n=typeof a==="string"?e[a]:a;if(typeof n!=="function")throw TypeError("Expected alias to be the name of an existing color (string) or a function");if(!n.stack)Reflect.defineProperty(n,"name",{value:i}),e.styles[i]=n,n.stack=[i];Reflect.defineProperty(e,i,{configurable:!0,enumerable:!0,set(l){e.alias(i,l)},get(){let l=(d)=>r(d,l.stack);return Reflect.setPrototypeOf(l,e),l.stack=this.stack?this.stack.concat(n.stack):n.stack,l}})},e.theme=(i)=>{if(!qa(i))throw TypeError("Expected theme to be an object");for(let a of Object.keys(i))e.alias(a,i[a]);return e},e.alias("unstyle",(i)=>{if(typeof i==="string"&&i!=="")return e.ansiRegex.lastIndex=0,i.replace(e.ansiRegex,"");return""}),e.alias("noop",(i)=>i),e.none=e.clear=e.noop,e.stripColor=e.unstyle,e.symbols=jt(),e.define=o,e};pt.exports=Jt();pt.exports.create=Jt});var _=v((Ha)=>{var Ka=Object.prototype.toString,P=Ie(),es=!1,Se=new Set,ts={yellow:"blue",cyan:"red",green:"magenta",black:"white",blue:"yellow",red:"cyan",magenta:"green",white:"black"};Ha.longest=(e,t)=>{return e.reduce((s,r)=>Math.max(s,t?r[t].length:r.length),0)};Ha.hasColor=(e)=>!!e&&P.hasColor(e);var Oe=Ha.isObject=(e)=>{return e!==null&&typeof e==="object"&&!Array.isArray(e)};Ha.nativeType=(e)=>{return Ka.call(e).slice(8,-1).toLowerCase().replace(/\s/g,"")};Ha.isAsyncFn=(e)=>{return Ha.nativeType(e)==="asyncfunction"};Ha.isPrimitive=(e)=>{return e!=null&&typeof e!=="object"&&typeof e!=="function"};Ha.resolve=(e,t,...s)=>{if(typeof t==="function")return t.call(e,...s);return t};Ha.scrollDown=(e=[])=>[...e.slice(1),e[0]];Ha.scrollUp=(e=[])=>[e.pop(),...e];Ha.reorder=(e=[])=>{let t=e.slice();return t.sort((s,r)=>{if(s.index>r.index)return 1;if(s.index<r.index)return-1;return 0}),t};Ha.swap=(e,t,s)=>{let r=e.length,o=s===r?0:s<0?r-1:s,i=e[t];e[t]=e[o],e[o]=i};Ha.width=(e,t=80)=>{let s=e&&e.columns?e.columns:t;if(e&&typeof e.getWindowSize==="function")s=e.getWindowSize()[0];if(process.platform==="win32")return s-1;return s};Ha.height=(e,t=20)=>{let s=e&&e.rows?e.rows:t;if(e&&typeof e.getWindowSize==="function")s=e.getWindowSize()[1];return s};Ha.wordWrap=(e,t={})=>{if(!e)return e;if(typeof t==="number")t={width:t};let{indent:s="",newline:r=`
|
|
5
|
+
`+s,width:o=80}=t,i=(r+s).match(/[^\S\n]/g)||[];o-=i.length;let a=`.{1,${o}}([\\s\\u200B]+|$)|[^\\s\\u200B]+?([\\s\\u200B]+|$)`,n=e.trim(),l=new RegExp(a,"g"),d=n.match(l)||[];if(d=d.map((u)=>u.replace(/\n$/,"")),t.padEnd)d=d.map((u)=>u.padEnd(o," "));if(t.padStart)d=d.map((u)=>u.padStart(o," "));return s+d.join(r)};Ha.unmute=(e)=>{let t=e.stack.find((r)=>P.keys.color.includes(r));if(t)return P[t];if(e.stack.find((r)=>r.slice(2)==="bg"))return P[t.slice(2)];return(r)=>r};Ha.pascal=(e)=>e?e[0].toUpperCase()+e.slice(1):"";Ha.inverse=(e)=>{if(!e||!e.stack)return e;let t=e.stack.find((r)=>P.keys.color.includes(r));if(t){let r=P["bg"+Ha.pascal(t)];return r?r.black:e}let s=e.stack.find((r)=>r.slice(0,2)==="bg");if(s)return P[s.slice(2).toLowerCase()]||e;return P.none};Ha.complement=(e)=>{if(!e||!e.stack)return e;let t=e.stack.find((r)=>P.keys.color.includes(r)),s=e.stack.find((r)=>r.slice(0,2)==="bg");if(t&&!s)return P[ts[t]||t];if(s){let r=s.slice(2).toLowerCase(),o=ts[r];if(!o)return e;return P["bg"+Ha.pascal(o)]||e}return P.none};Ha.meridiem=(e)=>{let t=e.getHours(),s=e.getMinutes(),r=t>=12?"pm":"am";t=t%12;let o=t===0?12:t,i=s<10?"0"+s:s;return o+":"+i+" "+r};Ha.set=(e={},t="",s)=>{return t.split(".").reduce((r,o,i,a)=>{let n=a.length-1>i?r[o]||{}:s;if(!Ha.isObject(n)&&i<a.length-1)n={};return r[o]=n},e)};Ha.get=(e={},t="",s)=>{let r=e[t]==null?t.split(".").reduce((o,i)=>o&&o[i],e):e[t];return r==null?s:r};Ha.mixin=(e,t)=>{if(!Oe(e))return t;if(!Oe(t))return e;for(let s of Object.keys(t)){let r=Object.getOwnPropertyDescriptor(t,s);if(hasOwnProperty.call(r,"value"))if(hasOwnProperty.call(e,s)&&Oe(r.value)){let o=Object.getOwnPropertyDescriptor(e,s);if(Oe(o.value)&&o.value!==r.value)e[s]=Ha.merge({},e[s],t[s]);else Reflect.defineProperty(e,s,r)}else Reflect.defineProperty(e,s,r);else Reflect.defineProperty(e,s,r)}return e};Ha.merge=(...e)=>{let t={};for(let s of e)Ha.mixin(t,s);return t};Ha.mixinEmitter=(e,t)=>{let s=t.constructor.prototype;for(let r of Object.keys(s)){let o=s[r];if(typeof o==="function")Ha.define(e,r,o.bind(t));else Ha.define(e,r,o)}};var De=(e,t)=>{if(es)return;if(es=!0,Se.forEach((s)=>s()),e===!0)process.exit(128+t)},ss=De.bind(null,!0,15),rs=De.bind(null,!0,2);Ha.onExit=(e)=>{if(Se.size===0)process.once("SIGTERM",ss),process.once("SIGINT",rs),process.once("exit",De);return Se.add(e),()=>{if(Se.delete(e),Se.size===0)process.off("SIGTERM",ss),process.off("SIGINT",rs),process.off("exit",De)}};Ha.define=(e,t,s)=>{Reflect.defineProperty(e,t,{value:s})};Ha.defineExport=(e,t,s)=>{let r;Reflect.defineProperty(e,t,{enumerable:!0,configurable:!0,set(o){r=o},get(){return r?r():s()}})}});var ls=v((Tm,ns)=>{ns.exports=({onlyFirst:e=!1}={})=>{let t=["[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)","(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))"].join("|");return new RegExp(t,e?void 0:"g")}});var se=v((Sm,ds)=>{var yn=ls();ds.exports=(e)=>typeof e==="string"?e.replace(yn(),""):e});var cs=v((gn)=>{gn.ctrl={a:"first",b:"backward",c:"cancel",d:"deleteForward",e:"last",f:"forward",g:"reset",i:"tab",k:"cutForward",l:"reset",n:"newItem",m:"cancel",j:"submit",p:"search",r:"remove",s:"save",u:"undo",w:"cutLeft",x:"toggleCursor",v:"paste"};gn.shift={up:"shiftUp",down:"shiftDown",left:"shiftLeft",right:"shiftRight",tab:"prev"};gn.fn={up:"pageUp",down:"pageDown",left:"pageLeft",right:"pageRight",delete:"deleteForward"};gn.option={b:"backward",f:"forward",d:"cutRight",left:"cutLeft",up:"altUp",down:"altDown"};gn.keys={pageup:"pageUp",pagedown:"pageDown",home:"home",end:"end",cancel:"cancel",delete:"deleteForward",backspace:"delete",down:"down",enter:"submit",escape:"cancel",left:"left",space:"space",number:"number",return:"submit",right:"right",tab:"next",up:"up"}});var ms=v((Rm,ps)=>{ps.exports=class{_queue=[];_executing=!1;_jobRunner=null;constructor(t){this._jobRunner=t}enqueue=(...t)=>{this._queue.push(t),this._dequeue()};destroy(){this._queue.length=0,this._jobRunner=null}_dequeue(){if(this._executing||!this._queue.length)return;this._executing=!0,this._jobRunner(...this._queue.shift()),setTimeout(()=>{this._executing=!1,this._dequeue()})}}});var ut=v((Cm,hs)=>{var us=Ae("readline"),An=cs(),Tn=ms(),Sn=/^(?:\x1b)([a-zA-Z0-9])$/,Nn=/^(?:\x1b+)(O|N|\[|\[\[)(?:(\d+)(?:;(\d+))?([~^$])|(?:1;)?(\d+)?([a-zA-Z]))/,Rn={OP:"f1",OQ:"f2",OR:"f3",OS:"f4","[11~":"f1","[12~":"f2","[13~":"f3","[14~":"f4","[[A":"f1","[[B":"f2","[[C":"f3","[[D":"f4","[[E":"f5","[15~":"f5","[17~":"f6","[18~":"f7","[19~":"f8","[20~":"f9","[21~":"f10","[23~":"f11","[24~":"f12","[A":"up","[B":"down","[C":"right","[D":"left","[E":"clear","[F":"end","[H":"home",OA:"up",OB:"down",OC:"right",OD:"left",OE:"clear",OF:"end",OH:"home","[1~":"home","[2~":"insert","[3~":"delete","[4~":"end","[5~":"pageup","[6~":"pagedown","[[5~":"pageup","[[6~":"pagedown","[7~":"home","[8~":"end","[a":"up","[b":"down","[c":"right","[d":"left","[e":"clear","[2$":"insert","[3$":"delete","[5$":"pageup","[6$":"pagedown","[7$":"home","[8$":"end",Oa:"up",Ob:"down",Oc:"right",Od:"left",Oe:"clear","[2^":"insert","[3^":"delete","[5^":"pageup","[6^":"pagedown","[7^":"home","[8^":"end","[Z":"tab"};function Cn(e){return["[a","[b","[c","[d","[e","[2$","[3$","[5$","[6$","[7$","[8$","[Z"].includes(e)}function Mn(e){return["Oa","Ob","Oc","Od","Oe","[2^","[3^","[5^","[6^","[7^","[8^"].includes(e)}var Pe=(e="",t={})=>{let s,r={name:t.name,ctrl:!1,meta:!1,shift:!1,option:!1,sequence:e,raw:e,...t};if(Buffer.isBuffer(e))if(e[0]>127&&e[1]===void 0)e[0]-=128,e="\x1B"+String(e);else e=String(e);else if(e!==void 0&&typeof e!=="string")e=String(e);else if(!e)e=r.sequence||"";if(r.sequence=r.sequence||e||r.name,e==="\r")r.raw=void 0,r.name="return";else if(e===`
|
|
6
|
+
`)r.name="enter";else if(e==="\t")r.name="tab";else if(e==="\b"||e==="\x7F"||e==="\x1B\x7F"||e==="\x1B\b")r.name="backspace",r.meta=e.charAt(0)==="\x1B";else if(e==="\x1B"||e==="\x1B\x1B")r.name="escape",r.meta=e.length===2;else if(e===" "||e==="\x1B ")r.name="space",r.meta=e.length===2;else if(e<="\x1A")r.name=String.fromCharCode(e.charCodeAt(0)+97-1),r.ctrl=!0;else if(e.length===1&&e>="0"&&e<="9")r.name="number";else if(e.length===1&&e>="a"&&e<="z")r.name=e;else if(e.length===1&&e>="A"&&e<="Z")r.name=e.toLowerCase(),r.shift=!0;else if(s=Sn.exec(e))r.meta=!0,r.shift=/^[A-Z]$/.test(s[1]);else if(s=Nn.exec(e)){let o=[...e];if(o[0]==="\x1B"&&o[1]==="\x1B")r.option=!0;let i=[s[1],s[2],s[4],s[6]].filter(Boolean).join(""),a=(s[3]||s[5]||1)-1;r.ctrl=!!(a&4),r.meta=!!(a&10),r.shift=!!(a&1),r.code=i,r.name=Rn[i],r.shift=Cn(i)||r.shift,r.ctrl=Mn(i)||r.ctrl}return r};Pe.listen=(e={},t)=>{let{stdin:s}=e;if(!s||s!==process.stdin&&!s.isTTY)throw Error("Invalid stream passed");let r=us.createInterface({terminal:!0,input:s});us.emitKeypressEvents(s,r);let o=new Tn((n,l)=>t(n,Pe(n,l),r)),i=s.isRaw;if(s.isTTY)s.setRawMode(!0);return s.on("keypress",o.enqueue),r.resume(),()=>{if(s.isTTY)s.setRawMode(i);s.removeListener("keypress",o.enqueue),o.destroy(),r.pause(),r.close()}};Pe.action=(e,t,s)=>{let r={...An,...s};if(t.ctrl)return t.action=r.ctrl[t.name],t;if(t.option&&r.option)return t.action=r.option[t.name],t;if(t.shift)return t.action=r.shift[t.name],t;return t.action=r.keys[t.name],t};hs.exports=Pe});var ys=v((Mm,fs)=>{fs.exports=(e)=>{e.timers=e.timers||{};let t=e.options.timers;if(!t)return;for(let s of Object.keys(t)){let r=t[s];if(typeof r==="number")r={interval:r};_n(e,s,r)}};function _n(e,t,s={}){let r=e.timers[t]={name:t,start:Date.now(),ms:0,tick:0},o=s.interval||120;r.frames=s.frames||[],r.loading=!0;let i=setInterval(()=>{r.ms=Date.now()-r.start,r.tick++,e.render()},o);return r.stop=()=>{r.loading=!1,clearInterval(i)},Reflect.defineProperty(r,"interval",{value:i}),e.once("close",()=>r.stop()),r.stop}});var xs=v((_m,bs)=>{var{define:Bn,width:In}=_();class gs{constructor(e){let t=e.options;Bn(this,"_prompt",e),this.type=e.type,this.name=e.name,this.message="",this.header="",this.footer="",this.error="",this.hint="",this.input="",this.cursor=0,this.index=0,this.lines=0,this.tick=0,this.prompt="",this.buffer="",this.width=In(t.stdout||process.stdout),Object.assign(this,t),this.name=this.name||this.message,this.message=this.message||this.name,this.symbols=e.symbols,this.styles=e.styles,this.required=new Set,this.cancelled=!1,this.submitted=!1}clone(){let e={...this};return e.status=this.status,e.buffer=Buffer.from(e.buffer),delete e.clone,e}set color(e){this._color=e}get color(){let e=this.prompt.styles;if(this.cancelled)return e.cancelled;if(this.submitted)return e.submitted;let t=this._color||e[this.status];return typeof t==="function"?t:e.pending}set loading(e){this._loading=e}get loading(){if(typeof this._loading==="boolean")return this._loading;if(this.loadingChoices)return"choices";return!1}get status(){if(this.cancelled)return"cancelled";if(this.submitted)return"submitted";return"pending"}}bs.exports=gs});var Es=v((Bm,ws)=>{var ht=_(),C=Ie(),ft={default:C.noop,noop:C.noop,set inverse(e){this._inverse=e},get inverse(){return this._inverse||ht.inverse(this.primary)},set complement(e){this._complement=e},get complement(){return this._complement||ht.complement(this.primary)},primary:C.cyan,success:C.green,danger:C.magenta,strong:C.bold,warning:C.yellow,muted:C.dim,disabled:C.gray,dark:C.dim.gray,underline:C.underline,set info(e){this._info=e},get info(){return this._info||this.primary},set em(e){this._em=e},get em(){return this._em||this.primary.underline},set heading(e){this._heading=e},get heading(){return this._heading||this.muted.underline},set pending(e){this._pending=e},get pending(){return this._pending||this.primary},set submitted(e){this._submitted=e},get submitted(){return this._submitted||this.success},set cancelled(e){this._cancelled=e},get cancelled(){return this._cancelled||this.danger},set typing(e){this._typing=e},get typing(){return this._typing||this.dim},set placeholder(e){this._placeholder=e},get placeholder(){return this._placeholder||this.primary.dim},set highlight(e){this._highlight=e},get highlight(){return this._highlight||this.inverse}};ft.merge=(e={})=>{if(e.styles&&typeof e.styles.enabled==="boolean")C.enabled=e.styles.enabled;if(e.styles&&typeof e.styles.visible==="boolean")C.visible=e.styles.visible;let t=ht.merge({},ft,e.styles);delete t.merge;for(let s of Object.keys(C))if(!hasOwnProperty.call(t,s))Reflect.defineProperty(t,s,{get:()=>C[s]});for(let s of Object.keys(C.styles))if(!hasOwnProperty.call(t,s))Reflect.defineProperty(t,s,{get:()=>C[s]});return t};ws.exports=ft});var As=v((Im,vs)=>{var yt=process.platform==="win32",ee=Ie(),On=_(),gt={...ee.symbols,upDownDoubleArrow:"\u21D5",upDownDoubleArrow2:"\u2B0D",upDownArrow:"\u2195",asterisk:"*",asterism:"\u2042",bulletWhite:"\u25E6",electricArrow:"\u2301",ellipsisLarge:"\u22EF",ellipsisSmall:"\u2026",fullBlock:"\u2588",identicalTo:"\u2261",indicator:ee.symbols.check,leftAngle:"\u2039",mark:"\u203B",minus:"\u2212",multiplication:"\xD7",obelus:"\xF7",percent:"%",pilcrow:"\xB6",pilcrow2:"\u2761",pencilUpRight:"\u2710",pencilDownRight:"\u270E",pencilRight:"\u270F",plus:"+",plusMinus:"\xB1",pointRight:"\u261E",rightAngle:"\u203A",section:"\xA7",hexagon:{off:"\u2B21",on:"\u2B22",disabled:"\u2B22"},ballot:{on:"\u2611",off:"\u2610",disabled:"\u2612"},stars:{on:"\u2605",off:"\u2606",disabled:"\u2606"},folder:{on:"\u25BC",off:"\u25B6",disabled:"\u25B6"},prefix:{pending:ee.symbols.question,submitted:ee.symbols.check,cancelled:ee.symbols.cross},separator:{pending:ee.symbols.pointerSmall,submitted:ee.symbols.middot,cancelled:ee.symbols.middot},radio:{off:yt?"( )":"\u25EF",on:yt?"(*)":"\u25C9",disabled:yt?"(|)":"\u24BE"},numbers:["\u24EA","\u2460","\u2461","\u2462","\u2463","\u2464","\u2465","\u2466","\u2467","\u2468","\u2469","\u246A","\u246B","\u246C","\u246D","\u246E","\u246F","\u2470","\u2471","\u2472","\u2473","\u3251","\u3252","\u3253","\u3254","\u3255","\u3256","\u3257","\u3258","\u3259","\u325A","\u325B","\u325C","\u325D","\u325E","\u325F","\u32B1","\u32B2","\u32B3","\u32B4","\u32B5","\u32B6","\u32B7","\u32B8","\u32B9","\u32BA","\u32BB","\u32BC","\u32BD","\u32BE","\u32BF"]};gt.merge=(e)=>{let t=On.merge({},ee.symbols,gt,e.symbols);return delete t.merge,t};vs.exports=gt});var Ss=v((Om,Ts)=>{var Dn=Es(),Pn=As(),kn=_();Ts.exports=(e)=>{e.options=kn.merge({},e.options.theme,e.options),e.symbols=Pn.merge(e.options),e.styles=Dn.merge(e.options)}});var Ms=v((Rs,Cs)=>{var Ns=process.env.TERM_PROGRAM==="Apple_Terminal",Ln=se(),bt=_(),k=Cs.exports=Rs,xt=!1,re=k.code={bell:"\x07",beep:"\x07",beginning:"\x1B[G",down:"\x1B[J",esc:"\x1B[",getPosition:"\x1B[6n",hide:"\x1B[?25l",line:"\x1B[2K",lineEnd:"\x1B[K",lineStart:"\x1B[1K",restorePosition:"\x1B["+(Ns?"8":"u"),savePosition:"\x1B["+(Ns?"7":"s"),screen:"\x1B[2J",show:"\x1B[?25h",up:"\x1B[1J"},de=k.cursor={get hidden(){return xt},hide(){return xt=!0,re.hide},show(){return xt=!1,re.show},forward:(e=1)=>`\x1B[${e}C`,backward:(e=1)=>`\x1B[${e}D`,nextLine:(e=1)=>"\x1B[E".repeat(e),prevLine:(e=1)=>"\x1B[F".repeat(e),up:(e=1)=>e?`\x1B[${e}A`:"",down:(e=1)=>e?`\x1B[${e}B`:"",right:(e=1)=>e?`\x1B[${e}C`:"",left:(e=1)=>e?`\x1B[${e}D`:"",to(e,t){return t?`\x1B[${t+1};${e+1}H`:`\x1B[${e+1}G`},move(e=0,t=0){let s="";return s+=e<0?de.left(-e):e>0?de.right(e):"",s+=t<0?de.up(-t):t>0?de.down(t):"",s},strLen(e){var t=0,s=e.length,r=-1;for(var o=0;o<s;o++)if(r=e.charCodeAt(o),r>=0&&r<=128)t+=1;else t+=2;return t},restore(e={}){let{after:t,cursor:s,initial:r,input:o,prompt:i,size:a,value:n}=e;if(r=bt.isPrimitive(r)?String(r):"",o=bt.isPrimitive(o)?String(o):"",n=bt.isPrimitive(n)?String(n):"",a){let l=k.cursor.up(a)+k.cursor.to(this.strLen(i)),d=o.length-s;if(d>0)l+=k.cursor.left(d);return l}if(n||t){let l=!o&&!!r?-this.strLen(r):-this.strLen(o)+s;if(t)l-=this.strLen(t);if(o===""&&r&&!i.includes(r))l+=this.strLen(r);return k.cursor.move(l)}}},wt=k.erase={screen:re.screen,up:re.up,down:re.down,line:re.line,lineEnd:re.lineEnd,lineStart:re.lineStart,lines(e){let t="";for(let s=0;s<e;s++)t+=k.erase.line+(s<e-1?k.cursor.up(1):"");if(e)t+=k.code.beginning;return t}};k.clear=(e="",t=process.stdout.columns)=>{if(!t)return wt.line+de.to(0);let s=(i)=>[...Ln(i)].length,r=e.split(/\r?\n/),o=0;for(let i of r)o+=1+Math.floor(Math.max(s(i)-1,0)/t);return(wt.line+de.prevLine()).repeat(o-1)+wt.line+de.to(0)}});var fe=v((Dm,Bs)=>{var Un=Ae("events"),_s=se(),Et=ut(),Gn=ys(),$n=xs(),qn=Ss(),I=_(),ce=Ms();class vt extends Un{constructor(e={}){super();this.name=e.name,this.type=e.type,this.options=e,qn(this),Gn(this),this.state=new $n(this),this.initial=[e.initial,e.default].find((t)=>t!=null),this.stdout=e.stdout||process.stdout,this.stdin=e.stdin||process.stdin,this.scale=e.scale||1,this.term=this.options.term||process.env.TERM_PROGRAM,this.margin=Fn(this.options.margin),this.setMaxListeners(0),Wn(this)}async keypress(e,t={}){this.keypressed=!0;let s=Et.action(e,Et(e,t),this.options.actions);this.state.keypress=s,this.emit("keypress",e,s),this.emit("state",this.state.clone());let r=this.options[s.action]||this[s.action]||this.dispatch;if(typeof r==="function")return await r.call(this,e,s);this.alert()}alert(){if(delete this.state.alert,this.options.show===!1)this.emit("alert");else this.stdout.write(ce.code.beep)}cursorHide(){this.stdout.write(ce.cursor.hide());let e=I.onExit(()=>this.cursorShow());this.on("close",()=>{this.cursorShow(),e()})}cursorShow(){this.stdout.write(ce.cursor.show())}write(e){if(!e)return;if(this.stdout&&this.state.show!==!1)this.stdout.write(e);this.state.buffer+=e}clear(e=0){let t=this.state.buffer;if(this.state.buffer="",!t&&!e||this.options.show===!1)return;this.stdout.write(ce.cursor.down(e)+ce.clear(t,this.width))}restore(){if(this.state.closed||this.options.show===!1)return;let{prompt:e,after:t,rest:s}=this.sections(),{cursor:r,initial:o="",input:i="",value:a=""}=this,n=this.state.size=s.length,l={after:t,cursor:r,initial:o,input:i,prompt:e,size:n,value:a},d=ce.cursor.restore(l);if(d)this.stdout.write(d)}sections(){let{buffer:e,input:t,prompt:s}=this.state;s=_s(s);let r=_s(e),o=r.indexOf(s),i=r.slice(0,o),n=r.slice(o).split(`
|
|
7
|
+
`),l=n[0],d=n[n.length-1],h=(s+(t?" "+t:"")).length,m=h<l.length?l.slice(h+1):"";return{header:i,prompt:l,after:m,rest:n.slice(1),last:d}}async submit(){if(this.state.submitted=!0,this.state.validating=!0,this.options.onSubmit)await this.options.onSubmit.call(this,this.name,this.value,this);let e=this.state.error||await this.validate(this.value,this.state);if(e!==!0){let t=`
|
|
8
8
|
`+this.symbols.pointer+" ";if(typeof e==="string")t+=e.trim();else t+="Invalid input";this.state.error=`
|
|
9
|
-
`+this.styles.danger(t),this.state.submitted=!1,await this.render(),await this.alert(),this.state.validating=!1,this.state.error=void 0;return}this.state.validating=!1,await this.render(),await this.close(),this.value=await this.result(this.value),this.emit("submit",this.value)}async cancel(e){if(this.state.cancelled=this.state.submitted=!0,await this.render(),await this.close(),typeof this.options.onCancel==="function")await this.options.onCancel.call(this,this.name,this.value,this);this.emit("cancel",await this.error(e))}async close(){this.state.closed=!0;try{let e=this.sections(),t=Math.ceil(e.prompt.length/this.width);if(e.rest)this.write(
|
|
10
|
-
`.repeat(t))}catch(e){}this.emit("close")}start(){if(!this.stop&&this.options.show!==!1)this.stop=
|
|
11
|
-
`:" ",o=[];for(let r=0;r<4;r++){let i=s(r);if(t[r])o.push(i.repeat(t[r]));else o.push("")}return o}_s.exports=Et});var Os=E((Pm,Is)=>{var Kn=M(),Bs={default(e,t){return t},checkbox(e,t){throw Error("checkbox role is not implemented yet")},editable(e,t){throw Error("editable role is not implemented yet")},expandable(e,t){throw Error("expandable role is not implemented yet")},heading(e,t){return t.disabled="",t.indicator=[t.indicator," "].find((s)=>s!=null),t.message=t.message||"",t},input(e,t){throw Error("input role is not implemented yet")},option(e,t){return Bs.default(e,t)},radio(e,t){throw Error("radio role is not implemented yet")},separator(e,t){return t.disabled="",t.indicator=[t.indicator," "].find((s)=>s!=null),t.message=t.message||e.symbols.line.repeat(5),t},spacer(e,t){return t}};Is.exports=(e,t={})=>{let s=Kn.merge({},Bs,t.roles);return s[e]||s.default}});var Se=E((Lm,ks)=>{var Hn=se(),Vn=fe(),zn=Os(),Le=M(),{reorder:vt,scrollUp:Yn,scrollDown:Qn,isObject:Ds,swap:Zn}=Le;class Ls extends Vn{constructor(e){super(e);this.cursorHide(),this.maxSelected=e.maxSelected||1/0,this.multiple=e.multiple||!1,this.initial=e.initial||0,this.delay=e.delay||0,this.longest=0,this.num=""}async initialize(){if(typeof this.options.initial==="function")this.initial=await this.options.initial.call(this);await this.reset(!0),await super.initialize()}async reset(){let{choices:e,initial:t,autofocus:s,suggest:o}=this.options;if(this.state._choices=[],this.state.choices=[],this.choices=await Promise.all(await this.toChoices(e)),this.choices.forEach((r)=>r.enabled=!1),typeof o!=="function"&&this.selectable.length===0)throw Error("At least one choice must be selectable");if(Ds(t))t=Object.keys(t);if(Array.isArray(t)){if(s!=null)this.index=this.findIndex(s);t.forEach((r)=>this.enable(this.find(r))),await this.render()}else{if(s!=null)t=s;if(typeof t==="string")t=this.findIndex(t);if(typeof t==="number"&&t>-1)this.index=Math.max(0,Math.min(t,this.choices.length)),this.enable(this.find(this.index))}if(this.isDisabled(this.focused))await this.down()}async toChoices(e,t){this.state.loadingChoices=!0;let s=[],o=0,r=async(i,a)=>{if(typeof i==="function")i=await i.call(this);if(i instanceof Promise)i=await i;for(let n=0;n<i.length;n++){let l=i[n]=await this.toChoice(i[n],o++,a);if(s.push(l),l.choices)await r(l.choices,l)}return s};return r(e,t).then((i)=>{return this.state.loadingChoices=!1,i})}async toChoice(e,t,s){if(typeof e==="function")e=await e.call(this,this);if(e instanceof Promise)e=await e;if(typeof e==="string")e={name:e};if(e.normalized)return e;e.normalized=!0;let o=e.value;if(e=zn(e.role,this.options)(this,e),typeof e.disabled==="string"&&!e.hint)e.hint=e.disabled,e.disabled=!0;if(e.disabled===!0&&e.hint==null)e.hint="(disabled)";if(e.index!=null)return e;if(e.name=e.name||e.key||e.title||e.value||e.message,e.message=e.message||e.name||"",e.value=[e.value,e.name].find(this.isValue.bind(this)),e.input="",e.index=t,e.cursor=0,Le.define(e,"parent",s),e.level=s?s.level+1:1,e.indent==null)e.indent=s?s.indent+" ":e.indent||"";if(e.path=s?s.path+"."+e.name:e.name,e.enabled=!!(this.multiple&&!this.isDisabled(e)&&(e.enabled||this.isSelected(e))),!this.isDisabled(e))this.longest=Math.max(this.longest,Hn(e.message).length);let i={...e};if(e.reset=(a=i.input,n=i.value)=>{for(let l of Object.keys(i))e[l]=i[l];e.input=a,e.value=n},o==null&&typeof e.initial==="function")e.input=await e.initial.call(this,this.state,e,t);return e}async onChoice(e,t){if(this.emit("choice",e,t,this),typeof e.onChoice==="function")await e.onChoice.call(this,this.state,e,t)}async addChoice(e,t,s){let o=await this.toChoice(e,t,s);return this.choices.push(o),this.index=this.choices.length-1,this.limit=this.choices.length,o}async newItem(e,t,s){let o={name:"New choice name?",editable:!0,newChoice:!0,...e},r=await this.addChoice(o,t,s);return r.updateChoice=()=>{delete r.newChoice,r.name=r.message=r.input,r.input="",r.cursor=0},this.render()}indent(e){if(e.indent==null)return e.level>1?" ".repeat(e.level-1):"";return e.indent}dispatch(e,t){if(this.multiple&&this[t.name])return this[t.name]();this.alert()}focus(e,t){if(typeof t!=="boolean")t=e.enabled;if(t&&!e.enabled&&this.selected.length>=this.maxSelected)return this.alert();return this.index=e.index,e.enabled=t&&!this.isDisabled(e),e}space(){if(!this.multiple)return this.alert();if(!this.focused)return;return this.toggle(this.focused),this.render()}a(){if(this.maxSelected<this.choices.length)return this.alert();let e=this.selectable.every((t)=>t.enabled);return this.choices.forEach((t)=>t.enabled=!e),this.render()}i(){if(this.choices.length-this.selected.length>this.maxSelected)return this.alert();return this.choices.forEach((e)=>e.enabled=!e.enabled),this.render()}g(){if(!this.choices.some((t)=>!!t.parent))return this.a();let e=this.focused;return this.toggle(e.parent&&!e.choices?e.parent:e),this.render()}toggle(e,t){if(!e.enabled&&this.selected.length>=this.maxSelected)return this.alert();if(typeof t!=="boolean")t=!e.enabled;if(e.enabled=t,e.choices)e.choices.forEach((o)=>this.toggle(o,t));let s=e.parent;while(s){let o=s.choices.filter((r)=>this.isDisabled(r));s.enabled=o.every((r)=>r.enabled===!0),s=s.parent}return Ps(this,this.choices),this.emit("toggle",e,this),e}enable(e){if(this.selected.length>=this.maxSelected)return this.alert();return e.enabled=!this.isDisabled(e),e.choices&&e.choices.forEach(this.enable.bind(this)),e}disable(e){return e.enabled=!1,e.choices&&e.choices.forEach(this.disable.bind(this)),e}number(e){this.num+=e;let t=(s)=>{let o=Number(s);if(o>this.choices.length-1)return this.alert();let r=this.focused,i=this.choices.find((a)=>o===a.index);if(!i.enabled&&this.selected.length>=this.maxSelected)return this.alert();if(this.visible.indexOf(i)===-1){let a=vt(this.choices),n=a.indexOf(i);if(r.index>n){let l=a.slice(n,n+this.limit),d=a.filter((c)=>!l.includes(c));this.choices=l.concat(d)}else{let l=n-this.limit+1;this.choices=a.slice(l).concat(a.slice(0,l))}}return this.index=this.choices.indexOf(i),this.toggle(this.focused),this.render()};return clearTimeout(this.numberTimeout),new Promise((s)=>{let o=this.choices.length,r=this.num,i=(a=!1,n)=>{if(clearTimeout(this.numberTimeout),a)n=t(r);this.num="",s(n)};if(r==="0"||r.length===1&&Number(r+"0")>o)return i(!0);if(Number(r)>o)return i(!1,this.alert());this.numberTimeout=setTimeout(()=>i(!0),this.delay)})}home(){return this.choices=vt(this.choices),this.index=0,this.render()}end(){let e=this.choices.length-this.limit,t=vt(this.choices);return this.choices=t.slice(e).concat(t.slice(0,e)),this.index=this.limit-1,this.render()}first(){return this.index=0,this.render()}last(){return this.index=this.visible.length-1,this.render()}prev(){if(this.visible.length<=1)return this.alert();return this.up()}next(){if(this.visible.length<=1)return this.alert();return this.down()}right(){if(this.cursor>=this.input.length)return this.alert();return this.cursor++,this.render()}left(){if(this.cursor<=0)return this.alert();return this.cursor--,this.render()}up(){let e=this.choices.length,t=this.visible.length,s=this.index;if(this.options.scroll===!1&&s===0)return this.alert();if(e>t&&s===0)return this.scrollUp();if(this.index=(s-1%e+e)%e,this.isDisabled()&&!this.allChoicesAreDisabled())return this.up();return this.render()}down(){let e=this.choices.length,t=this.visible.length,s=this.index;if(this.options.scroll===!1&&s===t-1)return this.alert();if(e>t&&s===t-1)return this.scrollDown();if(this.index=(s+1)%e,this.isDisabled()&&!this.allChoicesAreDisabled())return this.down();return this.render()}scrollUp(e=0){if(this.choices=Yn(this.choices),this.index=e,this.isDisabled())return this.up();return this.render()}scrollDown(e=this.visible.length-1){if(this.choices=Qn(this.choices),this.index=e,this.isDisabled())return this.down();return this.render()}async shiftUp(){if(this.options.sort===!0){this.sorting=!0,this.swap(this.index-1),await this.up(),this.sorting=!1;return}return this.scrollUp(this.index)}async shiftDown(){if(this.options.sort===!0){this.sorting=!0,this.swap(this.index+1),await this.down(),this.sorting=!1;return}return this.scrollDown(this.index)}pageUp(){if(this.visible.length<=1)return this.alert();if(this.limit=Math.max(this.limit-1,0),this.index=Math.min(this.limit-1,this.index),this._limit=this.limit,this.isDisabled())return this.up();return this.render()}pageDown(){if(this.visible.length>=this.choices.length)return this.alert();if(this.index=Math.max(0,this.index),this.limit=Math.min(this.limit+1,this.choices.length),this._limit=this.limit,this.isDisabled())return this.down();return this.render()}swap(e){Zn(this.choices,this.index,e)}allChoicesAreDisabled(e=this.choices){return e.every((t)=>this.isDisabled(t))}isDisabled(e=this.focused){if(e&&["disabled","collapsed","hidden","completing","readonly"].some((s)=>e[s]===!0))return!0;return e&&e.role==="heading"}isEnabled(e=this.focused){if(Array.isArray(e))return e.every((t)=>this.isEnabled(t));if(e.choices){let t=e.choices.filter((s)=>!this.isDisabled(s));return e.enabled&&t.every((s)=>this.isEnabled(s))}return e.enabled&&!this.isDisabled(e)}isChoice(e,t){return e.name===t||e.index===Number(t)}isSelected(e){if(Array.isArray(this.initial))return this.initial.some((t)=>this.isChoice(e,t));return this.isChoice(e,this.initial)}map(e=[],t="value"){return[].concat(e||[]).reduce((s,o)=>{return s[o]=this.find(o,t),s},{})}filter(e,t){let o=typeof e==="function"?e:(a,n)=>[a.name,n].includes(e),i=(this.options.multiple?this.state._choices:this.choices).filter(o);if(t)return i.map((a)=>a[t]);return i}find(e,t){if(Ds(e))return t?e[t]:e;let o=typeof e==="function"?e:(i,a)=>[i.name,a].includes(e),r=this.choices.find(o);if(r)return t?r[t]:r}findIndex(e){return this.choices.indexOf(this.find(e))}async submit(){let e=this.focused;if(!e)return this.alert();if(e.newChoice){if(!e.input)return this.alert();return e.updateChoice(),this.render()}if(this.choices.some((i)=>i.newChoice))return this.alert();let{reorder:t,sort:s}=this.options,o=this.multiple===!0,r=this.selected;if(r===void 0)return this.alert();if(Array.isArray(r)&&t!==!1&&s!==!0)r=Le.reorder(r);return this.value=o?r.map((i)=>i.name):r.name,super.submit()}set choices(e=[]){this.state._choices=this.state._choices||[],this.state.choices=e;for(let t of e)if(!this.state._choices.some((s)=>s.name===t.name))this.state._choices.push(t);if(!this._initial&&this.options.initial){this._initial=!0;let t=this.initial;if(typeof t==="string"||typeof t==="number"){let s=this.find(t);if(s)this.initial=s.index,this.focus(s,!0)}}}get choices(){return Ps(this,this.state.choices||[])}set visible(e){this.state.visible=e}get visible(){return(this.state.visible||this.choices).slice(0,this.limit)}set limit(e){this.state.limit=e}get limit(){let{state:e,options:t,choices:s}=this,o=e.limit||this._limit||t.limit||s.length;return Math.min(o,this.height)}set value(e){super.value=e}get value(){if(typeof super.value!=="string"&&super.value===this.initial)return this.input;return super.value}set index(e){this.state.index=e}get index(){return Math.max(0,this.state?this.state.index:0)}get enabled(){return this.filter(this.isEnabled.bind(this))}get focused(){let e=this.choices[this.index];if(e&&this.state.submitted&&this.multiple!==!0)e.enabled=!0;return e}get selectable(){return this.choices.filter((e)=>!this.isDisabled(e))}get selected(){return this.multiple?this.enabled:this.focused}}function Ps(e,t){if(t instanceof Promise)return t;if(typeof t==="function"){if(Le.isAsyncFn(t))return t;t=t.call(e,e)}for(let s of t){if(Array.isArray(s.choices)){let o=s.choices.filter((r)=>!e.isDisabled(r));s.enabled=o.every((r)=>r.enabled===!0)}if(e.isDisabled(s)===!0)delete s.enabled}return t}ks.exports=Ls});var re=E((km,Gs)=>{var Xn=Se(),At=M();class Us extends Xn{constructor(e){super(e);this.emptyError=this.options.emptyError||"No items were selected"}async dispatch(e,t){if(this.multiple)return this[t.name]?await this[t.name](e,t):await super.dispatch(e,t);this.alert()}separator(){if(this.options.separator)return super.separator();let e=this.styles.muted(this.symbols.ellipsis);return this.state.submitted?super.separator():e}pointer(e,t){return!this.multiple||this.options.pointer?super.pointer(e,t):""}indicator(e,t){return this.multiple?super.indicator(e,t):""}choiceMessage(e,t){let s=this.resolve(e.message,this.state,e,t);if(e.role==="heading"&&!At.hasColor(s))s=this.styles.strong(s);return this.resolve(s,this.state,e,t)}choiceSeparator(){return":"}async renderChoice(e,t){await this.onChoice(e,t);let s=this.index===t,o=await this.pointer(e,t),r=await this.indicator(e,t)+(e.pad||""),i=await this.resolve(e.hint,this.state,e,t);if(i&&!At.hasColor(i))i=this.styles.muted(i);let a=this.indent(e),n=await this.choiceMessage(e,t),l=()=>[this.margin[3],a+o+r,n,this.margin[1],i].filter(Boolean).join(" ");if(e.role==="heading")return l();if(e.disabled){if(!At.hasColor(n))n=this.styles.disabled(n);return l()}if(s)n=this.styles.em(n);return l()}async renderChoices(){if(this.state.loading==="choices")return this.styles.warning("Loading choices");if(this.state.submitted)return"";let e=this.visible.map(async(r,i)=>await this.renderChoice(r,i)),t=await Promise.all(e);if(!t.length)t.push(this.styles.danger("No matching choices"));let s=this.margin[0]+t.join(`
|
|
12
|
-
`),
|
|
13
|
-
`)}format(){if(!this.state.submitted||this.state.cancelled)return"";if(Array.isArray(this.selected))return this.selected.map((e)=>this.styles.primary(e.name)).join(", ");return this.styles.primary(this.selected.name)}async render(){let{submitted:e,size:t}=this.state,s="",
|
|
14
|
-
`)),this.write(this.margin[2]),this.restore()}}
|
|
15
|
-
`)),this.restore()}set value(e){super.value=e}get value(){return this.cast(super.value)}}Js.exports=
|
|
16
|
-
`,t)}return super.keypress(e,t)}moveCursor(e){this.cursor+=e}reset(){return this.input=this.value="",this.cursor=0,this.render()}dispatch(e,t){if(!e||t.ctrl||t.code)return this.alert();this.append(e)}append(e){let{cursor:t,input:s}=this.state;this.input=`${s}`.slice(0,t)+e+`${s}`.slice(t),this.moveCursor(String(e).length),this.render()}insert(e){this.append(e)}delete(){let{cursor:e,input:t}=this.state;if(e<=0)return this.alert();this.input=`${t}`.slice(0,e-1)+`${t}`.slice(e),this.moveCursor(-1),this.render()}deleteForward(){let{cursor:e,input:t}=this.state;if(t[e]===void 0)return this.alert();this.input=`${t}`.slice(0,e)+`${t}`.slice(e+1),this.render()}cutForward(){let e=this.cursor;if(this.input.length<=e)return this.alert();this.state.clipboard.push(this.input.slice(e)),this.input=this.input.slice(0,e),this.render()}cutLeft(){let e=this.cursor;if(e===0)return this.alert();let t=this.input.slice(0,e),s=this.input.slice(e),
|
|
17
|
-
`)),this.restore()}}
|
|
18
|
-
`;let t=e.startNumber||1;if(typeof this.scale==="number")this.scaleKey=!1,this.scale=Array(this.scale).fill(0).map((s,
|
|
19
|
-
`)}renderScaleHeading(e){let t=this.scale.map((n)=>n.name);if(typeof this.options.renderScaleHeading==="function")t=this.options.renderScaleHeading.call(this,e);let s=this.scaleLength-t.join("").length,
|
|
20
|
-
`).map((
|
|
21
|
-
`)].filter(Boolean)}async renderChoices(){if(this.state.submitted)return"";this.tableize();let e=this.visible.map(async(o
|
|
22
|
-
`)}async render(){let{submitted:e,size:t}=this.state,s=await this.prefix(),
|
|
23
|
-
`)),!this.state.submitted)this.write(this.margin[2]);this.restore()}submit(){this.value={};for(let e of this.choices)this.value[e.name]=e.scaleIndex;return this.base.submit.call(this)}}
|
|
24
|
-
`){
|
|
25
|
-
`).map((
|
|
26
|
-
`),
|
|
27
|
-
`].find((
|
|
9
|
+
`+this.styles.danger(t),this.state.submitted=!1,await this.render(),await this.alert(),this.state.validating=!1,this.state.error=void 0;return}this.state.validating=!1,await this.render(),await this.close(),this.value=await this.result(this.value),this.emit("submit",this.value)}async cancel(e){if(this.state.cancelled=this.state.submitted=!0,await this.render(),await this.close(),typeof this.options.onCancel==="function")await this.options.onCancel.call(this,this.name,this.value,this);this.emit("cancel",await this.error(e))}async close(){this.state.closed=!0;try{let e=this.sections(),t=Math.ceil(e.prompt.length/this.width);if(e.rest)this.write(ce.cursor.down(e.rest.length));this.write(`
|
|
10
|
+
`.repeat(t))}catch(e){}this.emit("close")}start(){if(!this.stop&&this.options.show!==!1)this.stop=Et.listen(this,this.keypress.bind(this)),this.once("close",this.stop),this.emit("start",this)}async skip(){if(this.skipped=this.options.skip===!0,typeof this.options.skip==="function")this.skipped=await this.options.skip.call(this,this.name,this.value);return this.skipped}async initialize(){let{format:e,options:t,result:s}=this;if(this.format=()=>e.call(this,this.value),this.result=()=>s.call(this,this.value),typeof t.initial==="function")this.initial=await t.initial.call(this,this);if(typeof t.onRun==="function")await t.onRun.call(this,this);if(typeof t.onSubmit==="function"){let r=t.onSubmit.bind(this),o=this.submit.bind(this);delete this.options.onSubmit,this.submit=async()=>{return await r(this.name,this.value,this),o()}}await this.start(),await this.render()}render(){throw Error("expected prompt to have a custom render method")}run(){return new Promise(async(e,t)=>{if(this.once("submit",e),this.once("cancel",t),await this.skip())return this.render=()=>{},this.submit();await this.initialize(),this.emit("run")})}async element(e,t,s){let{options:r,state:o,symbols:i,timers:a}=this,n=a&&a[e];o.timer=n;let l=r[e]||o[e]||i[e],d=t&&t[e]!=null?t[e]:await l;if(d==="")return d;let u=await this.resolve(d,o,t,s);if(!u&&t&&t[e])return this.resolve(l,o,t,s);return u}async prefix(){let e=await this.element("prefix")||this.symbols,t=this.timers&&this.timers.prefix,s=this.state;if(s.timer=t,I.isObject(e))e=e[s.status]||e.pending;if(!I.hasColor(e))return(this.styles[s.status]||this.styles.pending)(e);return e}async message(){let e=await this.element("message");if(!I.hasColor(e))return this.styles.strong(e);return e}async separator(){let e=await this.element("separator")||this.symbols,t=this.timers&&this.timers.separator,s=this.state;s.timer=t;let r=e[s.status]||e.pending||s.separator,o=await this.resolve(r,s);if(I.isObject(o))o=o[s.status]||o.pending;if(!I.hasColor(o))return this.styles.muted(o);return o}async pointer(e,t){let s=await this.element("pointer",e,t);if(typeof s==="string"&&I.hasColor(s))return s;if(s){let r=this.styles,o=this.index===t,i=o?r.primary:(l)=>l,a=await this.resolve(s[o?"on":"off"]||s,this.state),n=!I.hasColor(a)?i(a):a;return o?n:" ".repeat(a.length)}}async indicator(e,t){let s=await this.element("indicator",e,t);if(typeof s==="string"&&I.hasColor(s))return s;if(s){let r=this.styles,o=e.enabled===!0,i=o?r.success:r.dark,a=s[o?"on":"off"]||s;return!I.hasColor(a)?i(a):a}return""}body(){return null}footer(){if(this.state.status==="pending")return this.element("footer")}header(){if(this.state.status==="pending")return this.element("header")}async hint(){if(this.state.status==="pending"&&!this.isValue(this.state.input)){let e=await this.element("hint");if(!I.hasColor(e))return this.styles.muted(e);return e}}error(e){return!this.state.submitted?e||this.state.error:""}format(e){return e}result(e){return e}validate(e){if(this.options.required===!0)return this.isValue(e);return!0}isValue(e){return e!=null&&e!==""}resolve(e,...t){return I.resolve(this,e,...t)}get base(){return vt.prototype}get style(){return this.styles[this.state.status]}get height(){return this.options.rows||I.height(this.stdout,25)}get width(){return this.options.columns||I.width(this.stdout,80)}get size(){return{width:this.width,height:this.height}}set cursor(e){this.state.cursor=e}get cursor(){return this.state.cursor}set input(e){this.state.input=e}get input(){return this.state.input}set value(e){this.state.value=e}get value(){let{input:e,value:t}=this.state,s=[t,e].find(this.isValue.bind(this));return this.isValue(s)?s:this.initial}static get prompt(){return(e)=>new this(e).run()}}function Wn(e){let t=(o)=>{return e[o]===void 0||typeof e[o]==="function"},s=["actions","choices","initial","margin","roles","styles","symbols","theme","timers","value"],r=["body","footer","error","header","hint","indicator","message","prefix","separator","skip"];for(let o of Object.keys(e.options)){if(s.includes(o))continue;if(/^on[A-Z]/.test(o))continue;let i=e.options[o];if(typeof i==="function"&&t(o)){if(!r.includes(o))e[o]=i.bind(e)}else if(typeof e[o]!=="function")e[o]=i}}function Fn(e){if(typeof e==="number")e=[e,e,e,e];let t=[].concat(e||[]),s=(o)=>o%2===0?`
|
|
11
|
+
`:" ",r=[];for(let o=0;o<4;o++){let i=s(o);if(t[o])r.push(i.repeat(t[o]));else r.push("")}return r}Bs.exports=vt});var Ds=v((Pm,Os)=>{var Kn=_(),Is={default(e,t){return t},checkbox(e,t){throw Error("checkbox role is not implemented yet")},editable(e,t){throw Error("editable role is not implemented yet")},expandable(e,t){throw Error("expandable role is not implemented yet")},heading(e,t){return t.disabled="",t.indicator=[t.indicator," "].find((s)=>s!=null),t.message=t.message||"",t},input(e,t){throw Error("input role is not implemented yet")},option(e,t){return Is.default(e,t)},radio(e,t){throw Error("radio role is not implemented yet")},separator(e,t){return t.disabled="",t.indicator=[t.indicator," "].find((s)=>s!=null),t.message=t.message||e.symbols.line.repeat(5),t},spacer(e,t){return t}};Os.exports=(e,t={})=>{let s=Kn.merge({},Is,t.roles);return s[e]||s.default}});var Ne=v((km,Us)=>{var Hn=se(),Vn=fe(),zn=Ds(),ke=_(),{reorder:At,scrollUp:Yn,scrollDown:Qn,isObject:Ps,swap:Zn}=ke;class Ls extends Vn{constructor(e){super(e);this.cursorHide(),this.maxSelected=e.maxSelected||1/0,this.multiple=e.multiple||!1,this.initial=e.initial||0,this.delay=e.delay||0,this.longest=0,this.num=""}async initialize(){if(typeof this.options.initial==="function")this.initial=await this.options.initial.call(this);await this.reset(!0),await super.initialize()}async reset(){let{choices:e,initial:t,autofocus:s,suggest:r}=this.options;if(this.state._choices=[],this.state.choices=[],this.choices=await Promise.all(await this.toChoices(e)),this.choices.forEach((o)=>o.enabled=!1),typeof r!=="function"&&this.selectable.length===0)throw Error("At least one choice must be selectable");if(Ps(t))t=Object.keys(t);if(Array.isArray(t)){if(s!=null)this.index=this.findIndex(s);t.forEach((o)=>this.enable(this.find(o))),await this.render()}else{if(s!=null)t=s;if(typeof t==="string")t=this.findIndex(t);if(typeof t==="number"&&t>-1)this.index=Math.max(0,Math.min(t,this.choices.length)),this.enable(this.find(this.index))}if(this.isDisabled(this.focused))await this.down()}async toChoices(e,t){this.state.loadingChoices=!0;let s=[],r=0,o=async(i,a)=>{if(typeof i==="function")i=await i.call(this);if(i instanceof Promise)i=await i;for(let n=0;n<i.length;n++){let l=i[n]=await this.toChoice(i[n],r++,a);if(s.push(l),l.choices)await o(l.choices,l)}return s};return o(e,t).then((i)=>{return this.state.loadingChoices=!1,i})}async toChoice(e,t,s){if(typeof e==="function")e=await e.call(this,this);if(e instanceof Promise)e=await e;if(typeof e==="string")e={name:e};if(e.normalized)return e;e.normalized=!0;let r=e.value;if(e=zn(e.role,this.options)(this,e),typeof e.disabled==="string"&&!e.hint)e.hint=e.disabled,e.disabled=!0;if(e.disabled===!0&&e.hint==null)e.hint="(disabled)";if(e.index!=null)return e;if(e.name=e.name||e.key||e.title||e.value||e.message,e.message=e.message||e.name||"",e.value=[e.value,e.name].find(this.isValue.bind(this)),e.input="",e.index=t,e.cursor=0,ke.define(e,"parent",s),e.level=s?s.level+1:1,e.indent==null)e.indent=s?s.indent+" ":e.indent||"";if(e.path=s?s.path+"."+e.name:e.name,e.enabled=!!(this.multiple&&!this.isDisabled(e)&&(e.enabled||this.isSelected(e))),!this.isDisabled(e))this.longest=Math.max(this.longest,Hn(e.message).length);let i={...e};if(e.reset=(a=i.input,n=i.value)=>{for(let l of Object.keys(i))e[l]=i[l];e.input=a,e.value=n},r==null&&typeof e.initial==="function")e.input=await e.initial.call(this,this.state,e,t);return e}async onChoice(e,t){if(this.emit("choice",e,t,this),typeof e.onChoice==="function")await e.onChoice.call(this,this.state,e,t)}async addChoice(e,t,s){let r=await this.toChoice(e,t,s);return this.choices.push(r),this.index=this.choices.length-1,this.limit=this.choices.length,r}async newItem(e,t,s){let r={name:"New choice name?",editable:!0,newChoice:!0,...e},o=await this.addChoice(r,t,s);return o.updateChoice=()=>{delete o.newChoice,o.name=o.message=o.input,o.input="",o.cursor=0},this.render()}indent(e){if(e.indent==null)return e.level>1?" ".repeat(e.level-1):"";return e.indent}dispatch(e,t){if(this.multiple&&this[t.name])return this[t.name]();this.alert()}focus(e,t){if(typeof t!=="boolean")t=e.enabled;if(t&&!e.enabled&&this.selected.length>=this.maxSelected)return this.alert();return this.index=e.index,e.enabled=t&&!this.isDisabled(e),e}space(){if(!this.multiple)return this.alert();if(!this.focused)return;return this.toggle(this.focused),this.render()}a(){if(this.maxSelected<this.choices.length)return this.alert();let e=this.selectable.every((t)=>t.enabled);return this.choices.forEach((t)=>t.enabled=!e),this.render()}i(){if(this.choices.length-this.selected.length>this.maxSelected)return this.alert();return this.choices.forEach((e)=>e.enabled=!e.enabled),this.render()}g(){if(!this.choices.some((t)=>!!t.parent))return this.a();let e=this.focused;return this.toggle(e.parent&&!e.choices?e.parent:e),this.render()}toggle(e,t){if(!e.enabled&&this.selected.length>=this.maxSelected)return this.alert();if(typeof t!=="boolean")t=!e.enabled;if(e.enabled=t,e.choices)e.choices.forEach((r)=>this.toggle(r,t));let s=e.parent;while(s){let r=s.choices.filter((o)=>this.isDisabled(o));s.enabled=r.every((o)=>o.enabled===!0),s=s.parent}return ks(this,this.choices),this.emit("toggle",e,this),e}enable(e){if(this.selected.length>=this.maxSelected)return this.alert();return e.enabled=!this.isDisabled(e),e.choices&&e.choices.forEach(this.enable.bind(this)),e}disable(e){return e.enabled=!1,e.choices&&e.choices.forEach(this.disable.bind(this)),e}number(e){this.num+=e;let t=(s)=>{let r=Number(s);if(r>this.choices.length-1)return this.alert();let o=this.focused,i=this.choices.find((a)=>r===a.index);if(!i.enabled&&this.selected.length>=this.maxSelected)return this.alert();if(this.visible.indexOf(i)===-1){let a=At(this.choices),n=a.indexOf(i);if(o.index>n){let l=a.slice(n,n+this.limit),d=a.filter((u)=>!l.includes(u));this.choices=l.concat(d)}else{let l=n-this.limit+1;this.choices=a.slice(l).concat(a.slice(0,l))}}return this.index=this.choices.indexOf(i),this.toggle(this.focused),this.render()};return clearTimeout(this.numberTimeout),new Promise((s)=>{let r=this.choices.length,o=this.num,i=(a=!1,n)=>{if(clearTimeout(this.numberTimeout),a)n=t(o);this.num="",s(n)};if(o==="0"||o.length===1&&Number(o+"0")>r)return i(!0);if(Number(o)>r)return i(!1,this.alert());this.numberTimeout=setTimeout(()=>i(!0),this.delay)})}home(){return this.choices=At(this.choices),this.index=0,this.render()}end(){let e=this.choices.length-this.limit,t=At(this.choices);return this.choices=t.slice(e).concat(t.slice(0,e)),this.index=this.limit-1,this.render()}first(){return this.index=0,this.render()}last(){return this.index=this.visible.length-1,this.render()}prev(){if(this.visible.length<=1)return this.alert();return this.up()}next(){if(this.visible.length<=1)return this.alert();return this.down()}right(){if(this.cursor>=this.input.length)return this.alert();return this.cursor++,this.render()}left(){if(this.cursor<=0)return this.alert();return this.cursor--,this.render()}up(){let e=this.choices.length,t=this.visible.length,s=this.index;if(this.options.scroll===!1&&s===0)return this.alert();if(e>t&&s===0)return this.scrollUp();if(this.index=(s-1%e+e)%e,this.isDisabled()&&!this.allChoicesAreDisabled())return this.up();return this.render()}down(){let e=this.choices.length,t=this.visible.length,s=this.index;if(this.options.scroll===!1&&s===t-1)return this.alert();if(e>t&&s===t-1)return this.scrollDown();if(this.index=(s+1)%e,this.isDisabled()&&!this.allChoicesAreDisabled())return this.down();return this.render()}scrollUp(e=0){if(this.choices=Yn(this.choices),this.index=e,this.isDisabled())return this.up();return this.render()}scrollDown(e=this.visible.length-1){if(this.choices=Qn(this.choices),this.index=e,this.isDisabled())return this.down();return this.render()}async shiftUp(){if(this.options.sort===!0){this.sorting=!0,this.swap(this.index-1),await this.up(),this.sorting=!1;return}return this.scrollUp(this.index)}async shiftDown(){if(this.options.sort===!0){this.sorting=!0,this.swap(this.index+1),await this.down(),this.sorting=!1;return}return this.scrollDown(this.index)}pageUp(){if(this.visible.length<=1)return this.alert();if(this.limit=Math.max(this.limit-1,0),this.index=Math.min(this.limit-1,this.index),this._limit=this.limit,this.isDisabled())return this.up();return this.render()}pageDown(){if(this.visible.length>=this.choices.length)return this.alert();if(this.index=Math.max(0,this.index),this.limit=Math.min(this.limit+1,this.choices.length),this._limit=this.limit,this.isDisabled())return this.down();return this.render()}swap(e){Zn(this.choices,this.index,e)}allChoicesAreDisabled(e=this.choices){return e.every((t)=>this.isDisabled(t))}isDisabled(e=this.focused){if(e&&["disabled","collapsed","hidden","completing","readonly"].some((s)=>e[s]===!0))return!0;return e&&e.role==="heading"}isEnabled(e=this.focused){if(Array.isArray(e))return e.every((t)=>this.isEnabled(t));if(e.choices){let t=e.choices.filter((s)=>!this.isDisabled(s));return e.enabled&&t.every((s)=>this.isEnabled(s))}return e.enabled&&!this.isDisabled(e)}isChoice(e,t){return e.name===t||e.index===Number(t)}isSelected(e){if(Array.isArray(this.initial))return this.initial.some((t)=>this.isChoice(e,t));return this.isChoice(e,this.initial)}map(e=[],t="value"){return[].concat(e||[]).reduce((s,r)=>{return s[r]=this.find(r,t),s},{})}filter(e,t){let r=typeof e==="function"?e:(a,n)=>[a.name,n].includes(e),i=(this.options.multiple?this.state._choices:this.choices).filter(r);if(t)return i.map((a)=>a[t]);return i}find(e,t){if(Ps(e))return t?e[t]:e;let r=typeof e==="function"?e:(i,a)=>[i.name,a].includes(e),o=this.choices.find(r);if(o)return t?o[t]:o}findIndex(e){return this.choices.indexOf(this.find(e))}async submit(){let e=this.focused;if(!e)return this.alert();if(e.newChoice){if(!e.input)return this.alert();return e.updateChoice(),this.render()}if(this.choices.some((i)=>i.newChoice))return this.alert();let{reorder:t,sort:s}=this.options,r=this.multiple===!0,o=this.selected;if(o===void 0)return this.alert();if(Array.isArray(o)&&t!==!1&&s!==!0)o=ke.reorder(o);return this.value=r?o.map((i)=>i.name):o.name,super.submit()}set choices(e=[]){this.state._choices=this.state._choices||[],this.state.choices=e;for(let t of e)if(!this.state._choices.some((s)=>s.name===t.name))this.state._choices.push(t);if(!this._initial&&this.options.initial){this._initial=!0;let t=this.initial;if(typeof t==="string"||typeof t==="number"){let s=this.find(t);if(s)this.initial=s.index,this.focus(s,!0)}}}get choices(){return ks(this,this.state.choices||[])}set visible(e){this.state.visible=e}get visible(){return(this.state.visible||this.choices).slice(0,this.limit)}set limit(e){this.state.limit=e}get limit(){let{state:e,options:t,choices:s}=this,r=e.limit||this._limit||t.limit||s.length;return Math.min(r,this.height)}set value(e){super.value=e}get value(){if(typeof super.value!=="string"&&super.value===this.initial)return this.input;return super.value}set index(e){this.state.index=e}get index(){return Math.max(0,this.state?this.state.index:0)}get enabled(){return this.filter(this.isEnabled.bind(this))}get focused(){let e=this.choices[this.index];if(e&&this.state.submitted&&this.multiple!==!0)e.enabled=!0;return e}get selectable(){return this.choices.filter((e)=>!this.isDisabled(e))}get selected(){return this.multiple?this.enabled:this.focused}}function ks(e,t){if(t instanceof Promise)return t;if(typeof t==="function"){if(ke.isAsyncFn(t))return t;t=t.call(e,e)}for(let s of t){if(Array.isArray(s.choices)){let r=s.choices.filter((o)=>!e.isDisabled(o));s.enabled=r.every((o)=>o.enabled===!0)}if(e.isDisabled(s)===!0)delete s.enabled}return t}Us.exports=Ls});var oe=v((Lm,$s)=>{var Xn=Ne(),Tt=_();class Gs extends Xn{constructor(e){super(e);this.emptyError=this.options.emptyError||"No items were selected"}async dispatch(e,t){if(this.multiple)return this[t.name]?await this[t.name](e,t):await super.dispatch(e,t);this.alert()}separator(){if(this.options.separator)return super.separator();let e=this.styles.muted(this.symbols.ellipsis);return this.state.submitted?super.separator():e}pointer(e,t){return!this.multiple||this.options.pointer?super.pointer(e,t):""}indicator(e,t){return this.multiple?super.indicator(e,t):""}choiceMessage(e,t){let s=this.resolve(e.message,this.state,e,t);if(e.role==="heading"&&!Tt.hasColor(s))s=this.styles.strong(s);return this.resolve(s,this.state,e,t)}choiceSeparator(){return":"}async renderChoice(e,t){await this.onChoice(e,t);let s=this.index===t,r=await this.pointer(e,t),o=await this.indicator(e,t)+(e.pad||""),i=await this.resolve(e.hint,this.state,e,t);if(i&&!Tt.hasColor(i))i=this.styles.muted(i);let a=this.indent(e),n=await this.choiceMessage(e,t),l=()=>[this.margin[3],a+r+o,n,this.margin[1],i].filter(Boolean).join(" ");if(e.role==="heading")return l();if(e.disabled){if(!Tt.hasColor(n))n=this.styles.disabled(n);return l()}if(s)n=this.styles.em(n);return l()}async renderChoices(){if(this.state.loading==="choices")return this.styles.warning("Loading choices");if(this.state.submitted)return"";let e=this.visible.map(async(o,i)=>await this.renderChoice(o,i)),t=await Promise.all(e);if(!t.length)t.push(this.styles.danger("No matching choices"));let s=this.margin[0]+t.join(`
|
|
12
|
+
`),r;if(this.options.choicesHeader)r=await this.resolve(this.options.choicesHeader,this.state);return[r,s].filter(Boolean).join(`
|
|
13
|
+
`)}format(){if(!this.state.submitted||this.state.cancelled)return"";if(Array.isArray(this.selected))return this.selected.map((e)=>this.styles.primary(e.name)).join(", ");return this.styles.primary(this.selected.name)}async render(){let{submitted:e,size:t}=this.state,s="",r=await this.header(),o=await this.prefix(),i=await this.separator(),a=await this.message();if(this.options.promptLine!==!1)s=[o,a,i,""].join(" "),this.state.prompt=s;let n=await this.format(),l=await this.error()||await this.hint(),d=await this.renderChoices(),u=await this.footer();if(n)s+=n;if(l&&!s.includes(l))s+=" "+l;if(e&&!n&&!d.trim()&&this.multiple&&this.emptyError!=null)s+=this.styles.danger(this.emptyError);this.clear(t),this.write([r,s,d,u].filter(Boolean).join(`
|
|
14
|
+
`)),this.write(this.margin[2]),this.restore()}}$s.exports=Gs});var Fs=v((Um,Ws)=>{var jn=oe(),Jn=(e,t)=>{let s=e?new RegExp(e,"ig"):/$^/;return(r)=>{return e?r.replace(s,(o)=>t(o)):r}};class qs extends jn{constructor(e){super(e);this.cursorShow()}moveCursor(e){this.state.cursor+=e}dispatch(e){return this.append(e)}space(e){return this.options.multiple?super.space(e):this.append(e)}append(e){let{cursor:t,input:s}=this.state;return this.input=s.slice(0,t)+e+s.slice(t),this.moveCursor(1),this.complete()}delete(){let{cursor:e,input:t}=this.state;if(!t)return this.alert();return this.input=t.slice(0,e-1)+t.slice(e),this.moveCursor(-1),this.complete()}deleteForward(){let{cursor:e,input:t}=this.state;if(t[e]===void 0)return this.alert();return this.input=`${t}`.slice(0,e)+`${t}`.slice(e+1),this.complete()}number(e){return this.append(e)}async complete(){this.completing=!0,this.choices=await this.suggest(this.input,this.state._choices),this.state.limit=void 0,this.index=Math.min(Math.max(this.visible.length-1,0),this.index),await this.render(),this.completing=!1}suggest(e=this.input,t=this.state._choices){if(typeof this.options.suggest==="function")return this.options.suggest.call(this,e,t);let s=e.toLowerCase();return t.filter((r)=>r.message.toLowerCase().includes(s))}pointer(){return""}format(){if(!this.focused)return this.input;if(this.options.multiple&&this.state.submitted)return this.selected.map((e)=>this.styles.primary(e.message)).join(", ");if(this.state.submitted){let e=this.value=this.input=this.focused.value;return this.styles.primary(e)}return this.input}async render(){if(this.state.status!=="pending")return super.render();let e=this.options.highlight||this.styles.complement,t=(o,i)=>{if(!o)return o;if(e.stack)return e(o);return e.call(this,o)},s=Jn(this.input,t),r=this.choices;this.choices=r.map((o)=>({...o,message:s(o.message)})),await super.render(),this.choices=r}submit(){if(this.options.multiple)this.value=this.selected.map((e)=>e.name);return super.submit()}}Ws.exports=qs});var Nt=v((Gm,Ks)=>{var St=_();Ks.exports=(e,t={})=>{e.cursorHide();let{input:s="",initial:r="",pos:o,showCursor:i=!0,color:a}=t,n=a||e.styles.placeholder,l=St.inverse(e.styles.primary),d=(f)=>l(e.styles.black(f)),u=s,h=" ",m=d(h);if(e.blink&&e.blink.off===!0)d=(f)=>f,m="";if(i&&o===0&&r===""&&s==="")return d(h);if(i&&o===0&&(s===r||s===""))return d(r[0])+n(r.slice(1));r=St.isPrimitive(r)?`${r}`:"",s=St.isPrimitive(s)?`${s}`:"";let c=r&&r.startsWith(s)&&r!==s,p=c?d(r[s.length]):m;if(o!==s.length&&i===!0)u=s.slice(0,o)+d(s[o])+s.slice(o+1),p="";if(i===!1)p="";if(c){let f=e.styles.unstyle(u+p);return u+p+n(r.slice(f.length))}return u+p}});var Le=v(($m,Vs)=>{var el=se(),tl=oe(),sl=Nt();class Hs extends tl{constructor(e){super({...e,multiple:!0});this.type="form",this.initial=this.options.initial,this.align=[this.options.align,"right"].find((t)=>t!=null),this.emptyError="",this.values={}}async reset(e){if(await super.reset(),e===!0)this._index=this.index;return this.index=this._index,this.values={},this.choices.forEach((t)=>t.reset&&t.reset()),this.render()}dispatch(e){return!!e&&this.append(e)}append(e){let t=this.focused;if(!t)return this.alert();let{cursor:s,input:r}=t;return t.value=t.input=r.slice(0,s)+e+r.slice(s),t.cursor++,this.render()}delete(){let e=this.focused;if(!e||e.cursor<=0)return this.alert();let{cursor:t,input:s}=e;return e.value=e.input=s.slice(0,t-1)+s.slice(t),e.cursor--,this.render()}deleteForward(){let e=this.focused;if(!e)return this.alert();let{cursor:t,input:s}=e;if(s[t]===void 0)return this.alert();let r=`${s}`.slice(0,t)+`${s}`.slice(t+1);return e.value=e.input=r,this.render()}right(){let e=this.focused;if(!e)return this.alert();if(e.cursor>=e.input.length)return this.alert();return e.cursor++,this.render()}left(){let e=this.focused;if(!e)return this.alert();if(e.cursor<=0)return this.alert();return e.cursor--,this.render()}space(e,t){return this.dispatch(e,t)}number(e,t){return this.dispatch(e,t)}next(){let e=this.focused;if(!e)return this.alert();let{initial:t,input:s}=e;if(t&&t.startsWith(s)&&s!==t)return e.value=e.input=t,e.cursor=e.value.length,this.render();return super.next()}prev(){let e=this.focused;if(!e)return this.alert();if(e.cursor===0)return super.prev();return e.value=e.input="",e.cursor=0,this.render()}separator(){return""}format(e){return!this.state.submitted?super.format(e):""}pointer(){return""}indicator(e){return e.input?"\u29BF":"\u2299"}async choiceSeparator(e,t){let s=await this.resolve(e.separator,this.state,e,t)||":";return s?" "+this.styles.disabled(s):""}async renderChoice(e,t){await this.onChoice(e,t);let{state:s,styles:r}=this,{cursor:o,initial:i="",name:a,input:n=""}=e,{muted:l,submitted:d,primary:u,danger:h}=r,m=this.index===t,c=e.validate||(()=>!0),p=await this.choiceSeparator(e,t),f=e.message;if(this.align==="right")f=f.padStart(this.longest+1," ");if(this.align==="left")f=f.padEnd(this.longest+1," ");let y=this.values[a]=n||i,g=n?"success":"dark";if(await c.call(e,y,this.state)!==!0)g="danger";let b=r[g],x=b(await this.indicator(e,t))+(e.pad||""),T=this.indent(e),S=()=>[T,x,f+p,n].filter(Boolean).join(" ");if(s.submitted)return f=el(f),n=d(n),S();if(e.format)n=await e.format.call(this,n,e,t);else{let B=this.styles.muted;n=sl(this,{input:n,initial:i,pos:o,showCursor:m,color:B})}if(!this.isValue(n))n=this.styles.muted(this.symbols.ellipsis);if(e.result)this.values[a]=await e.result.call(this,y,e,t);if(m)f=u(f);if(e.error)n+=(n?" ":"")+h(e.error.trim());else if(e.hint)n+=(n?" ":"")+l(e.hint.trim());return S()}async submit(){return this.value=this.values,super.base.submit.call(this)}}Vs.exports=Hs});var Rt=v((qm,Ys)=>{var rl=Le(),ol=()=>{throw Error("expected prompt to have a custom authenticate method")},zs=(e=ol)=>{class t extends rl{constructor(s){super(s)}async submit(){this.value=await e.call(this,this.values,this.state),super.base.submit.call(this)}static create(s){return zs(s)}}return t};Ys.exports=zs()});var Xs=v((Wm,Zs)=>{var il=Rt();function al(e,t){if(e.username===this.options.username&&e.password===this.options.password)return!0;return!1}var Qs=(e=al)=>{let t=[{name:"username",message:"username"},{name:"password",message:"password",format(r){if(this.options.showPassword)return r;return(this.state.submitted?this.styles.primary:this.styles.muted)(this.symbols.asterisk.repeat(r.length))}}];class s extends il.create(e){constructor(r){super({...r,choices:t})}static create(r){return Qs(r)}}return s};Zs.exports=Qs()});var Ue=v((Fm,Js)=>{var nl=fe(),{isPrimitive:ll,hasColor:dl}=_();class js extends nl{constructor(e){super(e);this.cursorHide()}async initialize(){let e=await this.resolve(this.initial,this.state);this.input=await this.cast(e),await super.initialize()}dispatch(e){if(!this.isValue(e))return this.alert();return this.input=e,this.submit()}format(e){let{styles:t,state:s}=this;return!s.submitted?t.primary(e):t.success(e)}cast(e){return this.isTrue(e)}isTrue(e){return/^[ty1]/i.test(e)}isFalse(e){return/^[fn0]/i.test(e)}isValue(e){return ll(e)&&(this.isTrue(e)||this.isFalse(e))}async hint(){if(this.state.status==="pending"){let e=await this.element("hint");if(!dl(e))return this.styles.muted(e);return e}}async render(){let{input:e,size:t}=this.state,s=await this.prefix(),r=await this.separator(),o=await this.message(),i=this.styles.muted(this.default),a=[s,o,i,r].filter(Boolean).join(" ");this.state.prompt=a;let n=await this.header(),l=this.value=this.cast(e),d=await this.format(l),u=await this.error()||await this.hint(),h=await this.footer();if(u&&!a.includes(u))d+=" "+u;a+=" "+d,this.clear(t),this.write([n,a,h].filter(Boolean).join(`
|
|
15
|
+
`)),this.restore()}set value(e){super.value=e}get value(){return this.cast(super.value)}}Js.exports=js});var sr=v((Km,tr)=>{var cl=Ue();class er extends cl{constructor(e){super(e);this.default=this.options.default||(this.initial?"(Y/n)":"(y/N)")}}tr.exports=er});var ir=v((Hm,or)=>{var pl=oe(),ml=Le(),ye=ml.prototype;class rr extends pl{constructor(e){super({...e,multiple:!0});this.align=[this.options.align,"left"].find((t)=>t!=null),this.emptyError="",this.values={}}dispatch(e,t){let s=this.focused,r=s.parent||{};if(!s.editable&&!r.editable){if(e==="a"||e==="i")return super[e]()}return ye.dispatch.call(this,e,t)}append(e,t){return ye.append.call(this,e,t)}delete(e,t){return ye.delete.call(this,e,t)}space(e){return this.focused.editable?this.append(e):super.space()}number(e){return this.focused.editable?this.append(e):super.number(e)}next(){return this.focused.editable?ye.next.call(this):super.next()}prev(){return this.focused.editable?ye.prev.call(this):super.prev()}async indicator(e,t){let s=e.indicator||"",r=e.editable?s:super.indicator(e,t);return await this.resolve(r,this.state,e,t)||""}indent(e){return e.role==="heading"?"":e.editable?" ":" "}async renderChoice(e,t){if(e.indent="",e.editable)return ye.renderChoice.call(this,e,t);return super.renderChoice(e,t)}error(){return""}footer(){return this.state.error}async validate(){let e=!0;for(let t of this.choices){if(typeof t.validate!=="function")continue;if(t.role==="heading")continue;let s=t.parent?this.value[t.parent.name]:this.value;if(t.editable)s=t.value===t.name?t.initial||"":t.value;else if(!this.isDisabled(t))s=t.enabled===!0;if(e=await t.validate(s,this.state),e!==!0)break}if(e!==!0)this.state.error=typeof e==="string"?e:"Invalid Input";return e}submit(){if(this.focused.newChoice===!0)return super.submit();if(this.choices.some((e)=>e.newChoice))return this.alert();this.value={};for(let e of this.choices){let t=e.parent?this.value[e.parent.name]:this.value;if(e.role==="heading"){this.value[e.name]={};continue}if(e.editable)t[e.name]=e.value===e.name?e.initial||"":e.value;else if(!this.isDisabled(e))t[e.name]=e.enabled===!0}return this.base.submit.call(this)}}or.exports=rr});var pe=v((Vm,nr)=>{var ul=fe(),hl=ut(),fl=Nt(),{isPrimitive:yl}=_();class ar extends ul{constructor(e){super(e);if(this.initial=yl(this.initial)?String(this.initial):"",this.initial)this.cursorHide();this.state.prevCursor=0,this.state.clipboard=[],this.keypressTimeout=this.options.keypressTimeout!==void 0?this.options.keypressTimeout:null}async keypress(e,t=e?hl(e,{}):{}){let s=Date.now(),r=s-this.lastKeypress;this.lastKeypress=s;let o=t.name==="return"||t.name==="enter",i=this.state.prevKeypress,a;if(this.state.prevKeypress=t,this.keypressTimeout!=null&&o){if(r<this.keypressTimeout)return this.submit();this.state.multilineBuffer=this.state.multilineBuffer||"",this.state.multilineBuffer+=e,a=!0,i=null}if(a||this.options.multiline&&o){if(!i||i.name!=="return")return this.append(`
|
|
16
|
+
`,t)}return super.keypress(e,t)}moveCursor(e){this.cursor+=e}reset(){return this.input=this.value="",this.cursor=0,this.render()}dispatch(e,t){if(!e||t.ctrl||t.code)return this.alert();this.append(e)}append(e){let{cursor:t,input:s}=this.state;this.input=`${s}`.slice(0,t)+e+`${s}`.slice(t),this.moveCursor(String(e).length),this.render()}insert(e){this.append(e)}delete(){let{cursor:e,input:t}=this.state;if(e<=0)return this.alert();this.input=`${t}`.slice(0,e-1)+`${t}`.slice(e),this.moveCursor(-1),this.render()}deleteForward(){let{cursor:e,input:t}=this.state;if(t[e]===void 0)return this.alert();this.input=`${t}`.slice(0,e)+`${t}`.slice(e+1),this.render()}cutForward(){let e=this.cursor;if(this.input.length<=e)return this.alert();this.state.clipboard.push(this.input.slice(e)),this.input=this.input.slice(0,e),this.render()}cutLeft(){let e=this.cursor;if(e===0)return this.alert();let t=this.input.slice(0,e),s=this.input.slice(e),r=t.split(" ");this.state.clipboard.push(r.pop()),this.input=r.join(" "),this.cursor=this.input.length,this.input+=s,this.render()}paste(){if(!this.state.clipboard.length)return this.alert();this.insert(this.state.clipboard.pop()),this.render()}toggleCursor(){if(this.state.prevCursor)this.cursor=this.state.prevCursor,this.state.prevCursor=0;else this.state.prevCursor=this.cursor,this.cursor=0;this.render()}first(){this.cursor=0,this.render()}last(){this.cursor=this.input.length-1,this.render()}next(){let e=this.initial!=null?String(this.initial):"";if(!e||!e.startsWith(this.input))return this.alert();this.input=this.initial,this.cursor=this.initial.length,this.render()}prev(){if(!this.input)return this.alert();this.reset()}backward(){return this.left()}forward(){return this.right()}right(){if(this.cursor>=this.input.length)return this.alert();return this.moveCursor(1),this.render()}left(){if(this.cursor<=0)return this.alert();return this.moveCursor(-1),this.render()}isValue(e){return!!e}async format(e=this.value){let t=await this.resolve(this.initial,this.state);if(!this.state.submitted)return fl(this,{input:e,initial:t,pos:this.cursor});return this.styles.submitted(e||t)}async render(){let e=this.state.size,t=await this.prefix(),s=await this.separator(),r=await this.message(),o=[t,r,s].filter(Boolean).join(" ");this.state.prompt=o;let i=await this.header(),a=await this.format(),n=await this.error()||await this.hint(),l=await this.footer();if(n&&!a.includes(n))a+=" "+n;o+=" "+a,this.clear(e),this.write([i,o,l].filter(Boolean).join(`
|
|
17
|
+
`)),this.restore()}}nr.exports=ar});var dr=v((zm,lr)=>{var gl=(e)=>e.filter((t,s)=>e.lastIndexOf(t)===s),Ge=(e)=>gl(e).filter(Boolean);lr.exports=(e,t={},s="")=>{let{past:r=[],present:o=""}=t,i,a;switch(e){case"prev":case"undo":return i=r.slice(0,r.length-1),a=r[r.length-1]||"",{past:Ge([s,...i]),present:a};case"next":case"redo":return i=r.slice(1),a=r[0]||"",{past:Ge([...i,s]),present:a};case"save":return{past:Ge([...r,s]),present:""};case"remove":if(a=Ge(r.filter((n)=>n!==s)),o="",a.length)o=a.pop();return{past:a,present:o};default:throw Error(`Invalid action: "${e}"`)}}});var Ct=v((Ym,mr)=>{var bl=pe(),cr=dr();class pr extends bl{constructor(e){super(e);let t=this.options.history;if(t&&t.store){let s=t.values||this.initial;this.autosave=!!t.autosave,this.store=t.store,this.data=this.store.get("values")||{past:[],present:s},this.initial=this.data.present||this.data.past[this.data.past.length-1]}}completion(e){if(!this.store)return this.alert();if(this.data=cr(e,this.data,this.input),!this.data.present)return this.alert();return this.input=this.data.present,this.cursor=this.input.length,this.render()}altUp(){return this.completion("prev")}altDown(){return this.completion("next")}prev(){return this.save(),super.prev()}save(){if(!this.store)return;this.data=cr("save",this.data,this.input),this.store.set("values",this.data)}submit(){if(this.store&&this.autosave===!0)this.save();return super.submit()}}mr.exports=pr});var fr=v((Qm,hr)=>{var xl=pe();class ur extends xl{format(){return""}}hr.exports=ur});var br=v((Zm,gr)=>{var wl=pe();class yr extends wl{constructor(e={}){super(e);this.sep=this.options.separator||/, */,this.initial=e.initial||""}split(e=this.value){return e?String(e).split(this.sep):[]}format(){let e=this.state.submitted?this.styles.primary:(t)=>t;return this.list.map(e).join(", ")}async submit(e){let t=this.state.error||await this.validate(this.list,this.state);if(t!==!0)return this.state.error=t,super.submit();return this.value=this.list,super.submit()}get list(){return this.split()}}gr.exports=yr});var Er=v((Xm,wr)=>{var El=oe();class xr extends El{constructor(e){super({...e,multiple:!0})}}wr.exports=xr});var Mt=v((jm,Ar)=>{var vl=pe();class vr extends vl{constructor(e={}){super({style:"number",...e});this.min=this.isValue(e.min)?this.toNumber(e.min):-1/0,this.max=this.isValue(e.max)?this.toNumber(e.max):1/0,this.delay=e.delay!=null?e.delay:1000,this.float=e.float!==!1,this.round=e.round===!0||e.float===!1,this.major=e.major||10,this.minor=e.minor||1,this.initial=e.initial!=null?e.initial:"",this.input=String(this.initial),this.cursor=this.input.length,this.cursorShow()}append(e){if(!/[-+.]/.test(e)||e==="."&&this.input.includes("."))return this.alert("invalid number");return super.append(e)}number(e){return super.append(e)}next(){if(this.input&&this.input!==this.initial)return this.alert();if(!this.isValue(this.initial))return this.alert();return this.input=this.initial,this.cursor=String(this.initial).length,this.render()}up(e){let t=e||this.minor,s=this.toNumber(this.input);if(s>this.max+t)return this.alert();return this.input=`${s+t}`,this.render()}down(e){let t=e||this.minor,s=this.toNumber(this.input);if(s<this.min-t)return this.alert();return this.input=`${s-t}`,this.render()}shiftDown(){return this.down(this.major)}shiftUp(){return this.up(this.major)}format(e=this.input){if(typeof this.options.format==="function")return this.options.format.call(this,e);return this.styles.info(e)}toNumber(e=""){return this.float?+e:Math.round(+e)}isValue(e){return/^[-+]?[0-9]+((\.)|(\.[0-9]+))?$/.test(e)}submit(){let e=[this.input,this.initial].find((t)=>this.isValue(t));return this.value=this.toNumber(e||0),super.submit()}}Ar.exports=vr});var Nr=v((Jm,Sr)=>{var Al=pe();class Tr extends Al{constructor(e){super(e);this.cursorShow()}format(e=this.input){if(!this.keypressed)return"";return(this.state.submitted?this.styles.primary:this.styles.muted)(this.symbols.asterisk.repeat(e.length))}}Sr.exports=Tr});var _r=v((eu,Mr)=>{var Tl=se(),Sl=Ne(),Rr=_();class Cr extends Sl{constructor(e={}){super(e);this.widths=[].concat(e.messageWidth||50),this.align=[].concat(e.align||"left"),this.linebreak=e.linebreak||!1,this.edgeLength=e.edgeLength||3,this.newline=e.newline||`
|
|
18
|
+
`;let t=e.startNumber||1;if(typeof this.scale==="number")this.scaleKey=!1,this.scale=Array(this.scale).fill(0).map((s,r)=>({name:r+t}))}async reset(){return this.tableized=!1,await super.reset(),this.render()}tableize(){if(this.tableized===!0)return;this.tableized=!0;let e=0;for(let t of this.choices){e=Math.max(e,t.message.length),t.scaleIndex=t.initial||2,t.scale=[];for(let s=0;s<this.scale.length;s++)t.scale.push({index:s})}this.widths[0]=Math.min(this.widths[0],e+3)}async dispatch(e,t){if(this.multiple)return this[t.name]?await this[t.name](e,t):await super.dispatch(e,t);this.alert()}heading(e,t,s){return this.styles.strong(e)}separator(){return this.styles.muted(this.symbols.ellipsis)}right(){let e=this.focused;if(e.scaleIndex>=this.scale.length-1)return this.alert();return e.scaleIndex++,this.render()}left(){let e=this.focused;if(e.scaleIndex<=0)return this.alert();return e.scaleIndex--,this.render()}indent(){return""}format(){if(this.state.submitted)return this.choices.map((t)=>this.styles.info(t.index)).join(", ");return""}pointer(){return""}renderScaleKey(){if(this.scaleKey===!1)return"";if(this.state.submitted)return"";return["",...this.scale.map((s)=>` ${s.name} - ${s.message}`)].map((s)=>this.styles.muted(s)).join(`
|
|
19
|
+
`)}renderScaleHeading(e){let t=this.scale.map((n)=>n.name);if(typeof this.options.renderScaleHeading==="function")t=this.options.renderScaleHeading.call(this,e);let s=this.scaleLength-t.join("").length,r=Math.round(s/(t.length-1)),i=t.map((n)=>this.styles.strong(n)).join(" ".repeat(r)),a=" ".repeat(this.widths[0]);return this.margin[3]+a+this.margin[1]+i}scaleIndicator(e,t,s){if(typeof this.options.scaleIndicator==="function")return this.options.scaleIndicator.call(this,e,t,s);let r=e.scaleIndex===t.index;if(t.disabled)return this.styles.hint(this.symbols.radio.disabled);if(r)return this.styles.success(this.symbols.radio.on);return this.symbols.radio.off}renderScale(e,t){let s=e.scale.map((o)=>this.scaleIndicator(e,o,t)),r=this.term==="Hyper"?"":" ";return s.join(r+this.symbols.line.repeat(this.edgeLength))}async renderChoice(e,t){await this.onChoice(e,t);let s=this.index===t,r=await this.pointer(e,t),o=await e.hint;if(o&&!Rr.hasColor(o))o=this.styles.muted(o);let i=(c)=>this.margin[3]+c.replace(/\s+$/,"").padEnd(this.widths[0]," "),a=this.newline,n=this.indent(e),l=await this.resolve(e.message,this.state,e,t),d=await this.renderScale(e,t),u=this.margin[1]+this.margin[3];this.scaleLength=Tl(d).length,this.widths[0]=Math.min(this.widths[0],this.width-this.scaleLength-u.length);let m=Rr.wordWrap(l,{width:this.widths[0],newline:a}).split(`
|
|
20
|
+
`).map((c)=>i(c)+this.margin[1]);if(s)d=this.styles.info(d),m=m.map((c)=>this.styles.info(c));if(m[0]+=d,this.linebreak)m.push("");return[n+r,m.join(`
|
|
21
|
+
`)].filter(Boolean)}async renderChoices(){if(this.state.submitted)return"";this.tableize();let e=this.visible.map(async(r,o)=>await this.renderChoice(r,o)),t=await Promise.all(e),s=await this.renderScaleHeading();return this.margin[0]+[s,...t.map((r)=>r.join(" "))].join(`
|
|
22
|
+
`)}async render(){let{submitted:e,size:t}=this.state,s=await this.prefix(),r=await this.separator(),o=await this.message(),i="";if(this.options.promptLine!==!1)i=[s,o,r,""].join(" "),this.state.prompt=i;let a=await this.header(),n=await this.format(),l=await this.renderScaleKey(),d=await this.error()||await this.hint(),u=await this.renderChoices(),h=await this.footer(),m=this.emptyError;if(n)i+=n;if(d&&!i.includes(d))i+=" "+d;if(e&&!n&&!u.trim()&&this.multiple&&m!=null)i+=this.styles.danger(m);if(this.clear(t),this.write([a,i,l,u,h].filter(Boolean).join(`
|
|
23
|
+
`)),!this.state.submitted)this.write(this.margin[2]);this.restore()}submit(){this.value={};for(let e of this.choices)this.value[e.name]=e.scaleIndex;return this.base.submit.call(this)}}Mr.exports=Cr});var Dr=v((tu,Or)=>{var Br=se(),Nl=(e="")=>{return typeof e==="string"?e.replace(/^['"]|['"]$/g,""):""};class Ir{constructor(e){this.name=e.key,this.field=e.field||{},this.value=Nl(e.initial||this.field.initial||""),this.message=e.message||this.name,this.cursor=0,this.input="",this.lines=[]}}var Rl=async(e={},t={},s=(r)=>r)=>{let r=new Set,o=e.fields||[],i=e.template,a=[],n=[],l=[],d=1;if(typeof i==="function")i=await i();let u=-1,h=()=>i[++u],m=()=>i[u+1],c=(p)=>{p.line=d,a.push(p)};c({type:"bos",value:""});while(u<i.length-1){let p=h();if(/^[^\S\n ]$/.test(p)){c({type:"text",value:p});continue}if(p===`
|
|
24
|
+
`){c({type:"newline",value:p}),d++;continue}if(p==="\\"){p+=h(),c({type:"text",value:p});continue}if((p==="$"||p==="#"||p==="{")&&m()==="{"){let y=h();p+=y;let g={type:"template",open:p,inner:"",close:"",value:p},b;while(b=h()){if(b==="}"){if(m()==="}")b+=h();g.value+=b,g.close=b;break}if(b===":")g.initial="",g.key=g.inner;else if(g.initial!==void 0)g.initial+=b;g.value+=b,g.inner+=b}if(g.template=g.open+(g.initial||g.inner)+g.close,g.key=g.key||g.inner,hasOwnProperty.call(t,g.key))g.initial=t[g.key];g=s(g),c(g),l.push(g.key),r.add(g.key);let x=n.find((T)=>T.name===g.key);if(g.field=o.find((T)=>T.name===g.key),!x)x=new Ir(g),n.push(x);x.lines.push(g.line-1);continue}let f=a[a.length-1];if(f.type==="text"&&f.line===d)f.value+=p;else c({type:"text",value:p})}return c({type:"eos",value:""}),{input:i,tabstops:a,unique:r,keys:l,items:n}};Or.exports=async(e)=>{let t=e.options,s=new Set(t.required===!0?[]:t.required||[]),r={...t.values,...t.initial},{tabstops:o,items:i,keys:a}=await Rl(t,r),n=_t("result",e,t),l=_t("format",e,t),d=_t("validate",e,t,!0),u=e.isValue.bind(e);return async(h={},m=!1)=>{let c=0;h.required=s,h.items=i,h.keys=a,h.output="";let p=async(b,x,T,S)=>{let B=await d(b,x,T,S);if(B===!1)return"Invalid field "+T.name;return B};for(let b of o){let{value:x,key:T}=b;if(b.type!=="template"){if(x)h.output+=x;continue}if(b.type==="template"){let S=i.find((he)=>he.name===T);if(t.required===!0)h.required.add(S.name);let B=[S.input,h.values[S.value],S.value,x].find(u),ve=(S.field||{}).message||b.inner;if(m){let he=await p(h.values[T],h,S,c);if(he&&typeof he==="string"||he===!1){h.invalid.set(T,he);continue}h.invalid.delete(T);let Ta=await n(h.values[T],h,S,c);h.output+=Br(Ta);continue}S.placeholder=!1;let Aa=x;if(x=await l(x,h,S,c),B!==x)h.values[T]=B,x=e.styles.typing(B),h.missing.delete(ve);else if(h.values[T]=void 0,B=`<${ve}>`,x=e.styles.primary(B),S.placeholder=!0,h.required.has(T))h.missing.add(ve);if(h.missing.has(ve)&&h.validating)x=e.styles.warning(B);if(h.invalid.has(T)&&h.validating)x=e.styles.danger(B);if(c===h.index)if(Aa!==x)x=e.styles.underline(x);else x=e.styles.heading(Br(x));c++}if(x)h.output+=x}let f=h.output.split(`
|
|
25
|
+
`).map((b)=>" "+b),y=i.length,g=0;for(let b of i){if(h.invalid.has(b.name))b.lines.forEach((x)=>{if(f[x][0]!==" ")return;f[x]=h.styles.danger(h.symbols.bullet)+f[x].slice(1)});if(e.isValue(h.values[b.name]))g++}return h.completed=(g/y*100).toFixed(0),h.output=f.join(`
|
|
26
|
+
`),h.output}};function _t(e,t,s,r){return(o,i,a,n)=>{if(typeof a.field[e]==="function")return a.field[e].call(t,o,i,a,n);return[r,o].find((l)=>t.isValue(l))}}});var Lr=v((su,kr)=>{var Cl=se(),Ml=Dr(),_l=fe();class Pr extends _l{constructor(e){super(e);this.cursorHide(),this.reset(!0)}async initialize(){this.interpolate=await Ml(this),await super.initialize()}async reset(e){if(this.state.keys=[],this.state.invalid=new Map,this.state.missing=new Set,this.state.completed=0,this.state.values={},e!==!0)await this.initialize(),await this.render()}moveCursor(e){let t=this.getItem();this.cursor+=e,t.cursor+=e}dispatch(e,t){if(!t.code&&!t.ctrl&&e!=null&&this.getItem()){this.append(e,t);return}this.alert()}append(e,t){let s=this.getItem(),r=s.input.slice(0,this.cursor),o=s.input.slice(this.cursor);this.input=s.input=`${r}${e}${o}`,this.moveCursor(1),this.render()}delete(){let e=this.getItem();if(this.cursor<=0||!e.input)return this.alert();let t=e.input.slice(this.cursor),s=e.input.slice(0,this.cursor-1);this.input=e.input=`${s}${t}`,this.moveCursor(-1),this.render()}increment(e){return e>=this.state.keys.length-1?0:e+1}decrement(e){return e<=0?this.state.keys.length-1:e-1}first(){this.state.index=0,this.render()}last(){this.state.index=this.state.keys.length-1,this.render()}right(){if(this.cursor>=this.input.length)return this.alert();this.moveCursor(1),this.render()}left(){if(this.cursor<=0)return this.alert();this.moveCursor(-1),this.render()}prev(){this.state.index=this.decrement(this.state.index),this.getItem(),this.render()}next(){this.state.index=this.increment(this.state.index),this.getItem(),this.render()}up(){this.prev()}down(){this.next()}format(e){let t=this.state.completed<100?this.styles.warning:this.styles.success;if(this.state.submitted===!0&&this.state.completed!==100)t=this.styles.danger;return t(`${this.state.completed}% completed`)}async render(){let{index:e,keys:t=[],submitted:s,size:r}=this.state,o=[this.options.newline,`
|
|
27
|
+
`].find((g)=>g!=null),i=await this.prefix(),a=await this.separator(),n=await this.message(),l=[i,n,a].filter(Boolean).join(" ");this.state.prompt=l;let d=await this.header(),u=await this.error()||"",h=await this.hint()||"",m=s?"":await this.interpolate(this.state),c=this.state.key=t[e]||"",p=await this.format(c),f=await this.footer();if(p)l+=" "+p;if(h&&!p&&this.state.completed===0)l+=" "+h;this.clear(r);let y=[d,l,m,f,u.trim()];this.write(y.filter(Boolean).join(o)),this.restore()}getItem(e){let{items:t,keys:s,index:r}=this.state,o=t.find((i)=>i.name===s[r]);if(o&&o.input!=null)this.input=o.input,this.cursor=o.cursor;return o}async submit(){if(typeof this.interpolate!=="function")await this.initialize();await this.interpolate(this.state,!0);let{invalid:e,missing:t,output:s,values:r}=this.state;if(e.size){let a="";for(let[n,l]of e)a+=`Invalid ${n}: ${l}
|
|
28
28
|
`;return this.state.error=a,super.submit()}if(t.size)return this.state.error="Required: "+[...t.keys()].join(", "),super.submit();let i=Cl(s).split(`
|
|
29
29
|
`).map((a)=>a.slice(1)).join(`
|
|
30
|
-
`);return this.value={values:
|
|
31
|
-
`)}}async toChoices(...e){if(this.createdScales)return!1;this.createdScales=!0;let t=await super.toChoices(...e);for(let s of t)s.scale=Ol(5,this.options),s.scaleIdx=2;return t}dispatch(){this.alert()}space(){let e=this.focused,t=e.scale[e.scaleIdx],s=t.selected;return e.scale.forEach((
|
|
32
|
-
`);if(s)
|
|
33
|
-
`)}format(){if(this.state.submitted)return this.choices.map((t)=>this.styles.info(t.scaleIdx)).join(", ");return""}async render(){let{submitted:e,size:t}=this.state,s=await this.prefix(),
|
|
34
|
-
`)),this.restore()}submit(){this.value={};for(let e of this.choices)this.value[e.name]=e.scaleIdx;return this.base.submit.call(this)}}function Ol(e,t={}){if(Array.isArray(t.scale))return t.scale.map((
|
|
35
|
-
`)),this.write(this.margin[2]),this.restore()}}Ho.exports=Ko});var Qo=E((au,Yo)=>{var Pl=re();class zo extends Pl{constructor(e){super(e);if(typeof this.options.correctChoice!=="number"||this.options.correctChoice<0)throw Error("Please specify the index of the correct answer from the list of choices")}async toChoices(e,t){let s=await super.toChoices(e,t);if(s.length<2)throw Error("Please give at least two choices to the user");if(this.options.correctChoice>s.length)throw Error("Please specify the index of the correct answer from the list of choices");return s}check(e){return e.index===this.options.correctChoice}async result(e){return{selectedAnswer:e,correctAnswer:this.options.choices[this.options.correctChoice].value,correct:await this.check(this.state)}}}Yo.exports=zo});var Xo=E((_t)=>{var Zo=M(),S=(e,t)=>{Zo.defineExport(_t,e,t),Zo.defineExport(_t,e.toLowerCase(),t)};S("AutoComplete",()=>Ws());S("BasicAuth",()=>Zs());S("Confirm",()=>to());S("Editable",()=>ro());S("Form",()=>ke());S("Input",()=>Rt());S("Invisible",()=>fo());S("List",()=>bo());S("MultiSelect",()=>Eo());S("Numeral",()=>Ct());S("Password",()=>No());S("Scale",()=>_o());S("Select",()=>re());S("Snippet",()=>ko());S("Sort",()=>$o());S("Survey",()=>Fo());S("Text",()=>Rt());S("Toggle",()=>Vo());S("Quiz",()=>Qo())});var jo=E((lu,Jo)=>{Jo.exports={ArrayPrompt:Se(),AuthPrompt:Nt(),BooleanPrompt:Ue(),NumberPrompt:Ct(),StringPrompt:ce()}});var ae=E((du,tr)=>{var er=ve("assert"),It=ve("events"),ie=M();class k extends It{constructor(e,t){super();this.options=ie.merge({},e),this.answers={...t}}register(e,t){if(ie.isObject(e)){for(let o of Object.keys(e))this.register(o,e[o]);return this}er.equal(typeof t,"function","expected a function");let s=e.toLowerCase();if(t.prototype instanceof this.Prompt)this.prompts[s]=t;else this.prompts[s]=t(this.Prompt,this);return this}async prompt(e=[]){for(let t of[].concat(e))try{if(typeof t==="function")t=await t.call(this);await this.ask(ie.merge({},this.options,t))}catch(s){return Promise.reject(s)}return this.answers}async ask(e){if(typeof e==="function")e=await e.call(this);let t=ie.merge({},this.options,e),{type:s,name:o}=e,{set:r,get:i}=ie;if(typeof s==="function")s=await s.call(this,e,this.answers);if(!s)return this.answers[o];if(s==="number")s="numeral";er(this.prompts[s],`Prompt "${s}" is not registered`);let a=new this.prompts[s](t),n=i(this.answers,o);if(a.state.answers=this.answers,a.enquirer=this,o)a.on("submit",(d)=>{this.emit("answer",o,d,a),r(this.answers,o,d)});let l=a.emit.bind(a);if(a.emit=(...d)=>{return this.emit.call(this,...d),l(...d)},this.emit("prompt",a,this),t.autofill&&n!=null){if(a.value=a.input=n,t.autofill==="show")await a.submit()}else n=a.value=await a.run();return n}use(e){return e.call(this,this),this}set Prompt(e){this._Prompt=e}get Prompt(){return this._Prompt||this.constructor.Prompt}get prompts(){return this.constructor.prompts}static set Prompt(e){this._Prompt=e}static get Prompt(){return this._Prompt||fe()}static get prompts(){return Xo()}static get types(){return jo()}static get prompt(){let e=(t,...s)=>{let o=new this(...s),r=o.emit.bind(o);return o.emit=(...i)=>{return e.emit(...i),r(...i)},o.prompt(t)};return ie.mixinEmitter(e,new It),e}}ie.mixinEmitter(k,new It);var Bt=k.prompts;for(let e of Object.keys(Bt)){let t=e.toLowerCase(),s=(o)=>new Bt[e](o).run();if(k.prompt[t]=s,k[t]=s,!k[e])Reflect.defineProperty(k,e,{get:()=>Bt[e]})}var Ne=(e)=>{ie.defineExport(k,e,()=>k.types[e])};Ne("ArrayPrompt");Ne("AuthPrompt");Ne("BooleanPrompt");Ne("NumberPrompt");Ne("StringPrompt");tr.exports=k});var Oi=E((Ut,Gt)=>{(function(e,t){if(typeof Ut==="object"&&typeof Gt==="object")Gt.exports=t();else if(typeof define==="function"&&define.amd)define(function(){return t()});else e.pluralize=t()})(Ut,function(){var e=[],t=[],s={},o={},r={};function i(p){if(typeof p==="string")return new RegExp("^"+p+"$","i");return p}function a(p,h){if(p===h)return h;if(p===p.toLowerCase())return h.toLowerCase();if(p===p.toUpperCase())return h.toUpperCase();if(p[0]===p[0].toUpperCase())return h.charAt(0).toUpperCase()+h.substr(1).toLowerCase();return h.toLowerCase()}function n(p,h){return p.replace(/\$(\d{1,2})/g,function(f,g){return h[g]||""})}function l(p,h){return p.replace(h[0],function(f,g){var y=n(h[1],arguments);if(f==="")return a(p[g-1],y);return a(f,y)})}function d(p,h,f){if(!p.length||s.hasOwnProperty(p))return h;var g=f.length;while(g--){var y=f[g];if(y[0].test(h))return l(h,y)}return h}function c(p,h,f){return function(g){var y=g.toLowerCase();if(h.hasOwnProperty(y))return a(g,y);if(p.hasOwnProperty(y))return a(g,p[y]);return d(y,g,f)}}function u(p,h,f,g){return function(y){var w=y.toLowerCase();if(h.hasOwnProperty(w))return!0;if(p.hasOwnProperty(w))return!1;return d(w,w,f)===w}}function m(p,h,f){var g=h===1?m.singular(p):m.plural(p);return(f?h+" ":"")+g}return m.plural=c(r,o,e),m.isPlural=u(r,o,e),m.singular=c(o,r,t),m.isSingular=u(o,r,t),m.addPluralRule=function(p,h){e.push([i(p),h])},m.addSingularRule=function(p,h){t.push([i(p),h])},m.addUncountableRule=function(p){if(typeof p==="string"){s[p.toLowerCase()]=!0;return}m.addPluralRule(p,"$0"),m.addSingularRule(p,"$0")},m.addIrregularRule=function(p,h){h=h.toLowerCase(),p=p.toLowerCase(),r[p]=h,o[h]=p},[["I","we"],["me","us"],["he","they"],["she","they"],["them","them"],["myself","ourselves"],["yourself","yourselves"],["itself","themselves"],["herself","themselves"],["himself","themselves"],["themself","themselves"],["is","are"],["was","were"],["has","have"],["this","these"],["that","those"],["echo","echoes"],["dingo","dingoes"],["volcano","volcanoes"],["tornado","tornadoes"],["torpedo","torpedoes"],["genus","genera"],["viscus","viscera"],["stigma","stigmata"],["stoma","stomata"],["dogma","dogmata"],["lemma","lemmata"],["schema","schemata"],["anathema","anathemata"],["ox","oxen"],["axe","axes"],["die","dice"],["yes","yeses"],["foot","feet"],["eave","eaves"],["goose","geese"],["tooth","teeth"],["quiz","quizzes"],["human","humans"],["proof","proofs"],["carve","carves"],["valve","valves"],["looey","looies"],["thief","thieves"],["groove","grooves"],["pickaxe","pickaxes"],["passerby","passersby"]].forEach(function(p){return m.addIrregularRule(p[0],p[1])}),[[/s?$/i,"s"],[/[^\u0000-\u007F]$/i,"$0"],[/([^aeiou]ese)$/i,"$1"],[/(ax|test)is$/i,"$1es"],[/(alias|[^aou]us|t[lm]as|gas|ris)$/i,"$1es"],[/(e[mn]u)s?$/i,"$1s"],[/([^l]ias|[aeiou]las|[ejzr]as|[iu]am)$/i,"$1"],[/(alumn|syllab|vir|radi|nucle|fung|cact|stimul|termin|bacill|foc|uter|loc|strat)(?:us|i)$/i,"$1i"],[/(alumn|alg|vertebr)(?:a|ae)$/i,"$1ae"],[/(seraph|cherub)(?:im)?$/i,"$1im"],[/(her|at|gr)o$/i,"$1oes"],[/(agend|addend|millenni|dat|extrem|bacteri|desiderat|strat|candelabr|errat|ov|symposi|curricul|automat|quor)(?:a|um)$/i,"$1a"],[/(apheli|hyperbat|periheli|asyndet|noumen|phenomen|criteri|organ|prolegomen|hedr|automat)(?:a|on)$/i,"$1a"],[/sis$/i,"ses"],[/(?:(kni|wi|li)fe|(ar|l|ea|eo|oa|hoo)f)$/i,"$1$2ves"],[/([^aeiouy]|qu)y$/i,"$1ies"],[/([^ch][ieo][ln])ey$/i,"$1ies"],[/(x|ch|ss|sh|zz)$/i,"$1es"],[/(matr|cod|mur|sil|vert|ind|append)(?:ix|ex)$/i,"$1ices"],[/\b((?:tit)?m|l)(?:ice|ouse)$/i,"$1ice"],[/(pe)(?:rson|ople)$/i,"$1ople"],[/(child)(?:ren)?$/i,"$1ren"],[/eaux$/i,"$0"],[/m[ae]n$/i,"men"],["thou","you"]].forEach(function(p){return m.addPluralRule(p[0],p[1])}),[[/s$/i,""],[/(ss)$/i,"$1"],[/(wi|kni|(?:after|half|high|low|mid|non|night|[^\w]|^)li)ves$/i,"$1fe"],[/(ar|(?:wo|[ae])l|[eo][ao])ves$/i,"$1f"],[/ies$/i,"y"],[/\b([pl]|zomb|(?:neck|cross)?t|coll|faer|food|gen|goon|group|lass|talk|goal|cut)ies$/i,"$1ie"],[/\b(mon|smil)ies$/i,"$1ey"],[/\b((?:tit)?m|l)ice$/i,"$1ouse"],[/(seraph|cherub)im$/i,"$1"],[/(x|ch|ss|sh|zz|tto|go|cho|alias|[^aou]us|t[lm]as|gas|(?:her|at|gr)o|[aeiou]ris)(?:es)?$/i,"$1"],[/(analy|diagno|parenthe|progno|synop|the|empha|cri|ne)(?:sis|ses)$/i,"$1sis"],[/(movie|twelve|abuse|e[mn]u)s$/i,"$1"],[/(test)(?:is|es)$/i,"$1is"],[/(alumn|syllab|vir|radi|nucle|fung|cact|stimul|termin|bacill|foc|uter|loc|strat)(?:us|i)$/i,"$1us"],[/(agend|addend|millenni|dat|extrem|bacteri|desiderat|strat|candelabr|errat|ov|symposi|curricul|quor)a$/i,"$1um"],[/(apheli|hyperbat|periheli|asyndet|noumen|phenomen|criteri|organ|prolegomen|hedr|automat)a$/i,"$1on"],[/(alumn|alg|vertebr)ae$/i,"$1a"],[/(cod|mur|sil|vert|ind)ices$/i,"$1ex"],[/(matr|append)ices$/i,"$1ix"],[/(pe)(rson|ople)$/i,"$1rson"],[/(child)ren$/i,"$1"],[/(eau)x?$/i,"$1"],[/men$/i,"man"]].forEach(function(p){return m.addSingularRule(p[0],p[1])}),["adulthood","advice","agenda","aid","aircraft","alcohol","ammo","analytics","anime","athletics","audio","bison","blood","bream","buffalo","butter","carp","cash","chassis","chess","clothing","cod","commerce","cooperation","corps","debris","diabetes","digestion","elk","energy","equipment","excretion","expertise","firmware","flounder","fun","gallows","garbage","graffiti","hardware","headquarters","health","herpes","highjinks","homework","housework","information","jeans","justice","kudos","labour","literature","machinery","mackerel","mail","media","mews","moose","music","mud","manga","news","only","personnel","pike","plankton","pliers","police","pollution","premises","rain","research","rice","salmon","scissors","series","sewage","shambles","shrimp","software","species","staff","swine","tennis","traffic","transportation","trout","tuna","wealth","welfare","whiting","wildebeest","wildlife","you",/pok[e\u00E9]mon$/i,/[^aeiou]ese$/i,/deer$/i,/fish$/i,/measles$/i,/o[iu]s$/i,/pox$/i,/sheep$/i].forEach(m.addUncountableRule),m})});import{parseArgs as jc}from"util";import{Exception as xa}from"@ooneex/exception";import{TerminalLogger as em}from"@ooneex/logger";import{container as Ia}from"@ooneex/container";var _e=[];var Ht=(e)=>{let t=null;return _e.find((s)=>{return t=Ia.get(s),t.getName()===e}),t};import{homedir as ka}from"os";import{join as lt}from"path";import{TerminalLogger as Ua}from"@ooneex/logger";import{container as Oa,EContainerScope as Da}from"@ooneex/container";var x={command:(e=Da.Singleton)=>{return(t)=>{Oa.add(t,e),_e.push(t)}}};var Vt=`#compdef oo ooneex
|
|
30
|
+
`);return this.value={values:r,result:i},super.submit()}}kr.exports=Pr});var $r=v((ru,Gr)=>{var Bl=oe();class Ur extends Bl{constructor(e){super({...e,reorder:!1,sort:!0,multiple:!0});this.state.hint=[this.options.hint,"(Use <shift>+<up/down> to sort)"].find(this.isValue.bind(this))}indicator(){return""}async renderChoice(e,t){let s=await super.renderChoice(e,t),r=this.symbols.identicalTo+" ",o=this.index===t&&this.sorting?this.styles.muted(r):" ";if(this.options.drag===!1)o="";if(this.options.numbered===!0)return o+`${t+1} - `+s;return o+s}get selected(){return this.choices}submit(){return this.value=this.choices.map((e)=>e.value),super.submit()}}Gr.exports=Ur});var Fr=v((ou,Wr)=>{var Il=Ne();class qr extends Il{constructor(e={}){super(e);if(this.emptyError=e.emptyError||"No items were selected",this.term=process.env.TERM_PROGRAM,!this.options.header){let t=["","4 - Strongly Agree","3 - Agree","2 - Neutral","1 - Disagree","0 - Strongly Disagree",""];t=t.map((s)=>this.styles.muted(s)),this.state.header=t.join(`
|
|
31
|
+
`)}}async toChoices(...e){if(this.createdScales)return!1;this.createdScales=!0;let t=await super.toChoices(...e);for(let s of t)s.scale=Ol(5,this.options),s.scaleIdx=2;return t}dispatch(){this.alert()}space(){let e=this.focused,t=e.scale[e.scaleIdx],s=t.selected;return e.scale.forEach((r)=>r.selected=!1),t.selected=!s,this.render()}indicator(){return""}pointer(){return""}separator(){return this.styles.muted(this.symbols.ellipsis)}right(){let e=this.focused;if(e.scaleIdx>=e.scale.length-1)return this.alert();return e.scaleIdx++,this.render()}left(){let e=this.focused;if(e.scaleIdx<=0)return this.alert();return e.scaleIdx--,this.render()}indent(){return" "}async renderChoice(e,t){await this.onChoice(e,t);let s=this.index===t,r=this.term==="Hyper",o=!r?8:9,i=!r?" ":"",a=this.symbols.line.repeat(o),n=" ".repeat(o+(r?0:1)),l=(b)=>(b?this.styles.success("\u25C9"):"\u25EF")+i,d=t+1+".",u=s?this.styles.heading:this.styles.noop,h=await this.resolve(e.message,this.state,e,t),m=this.indent(e),c=m+e.scale.map((b,x)=>l(x===e.scaleIdx)).join(a),p=(b)=>b===e.scaleIdx?u(b):b,f=m+e.scale.map((b,x)=>p(x)).join(n),y=()=>[d,h].filter(Boolean).join(" "),g=()=>[y(),c,f," "].filter(Boolean).join(`
|
|
32
|
+
`);if(s)c=this.styles.cyan(c),f=this.styles.cyan(f);return g()}async renderChoices(){if(this.state.submitted)return"";let e=this.visible.map(async(s,r)=>await this.renderChoice(s,r)),t=await Promise.all(e);if(!t.length)t.push(this.styles.danger("No matching choices"));return t.join(`
|
|
33
|
+
`)}format(){if(this.state.submitted)return this.choices.map((t)=>this.styles.info(t.scaleIdx)).join(", ");return""}async render(){let{submitted:e,size:t}=this.state,s=await this.prefix(),r=await this.separator(),o=await this.message(),i=[s,o,r].filter(Boolean).join(" ");this.state.prompt=i;let a=await this.header(),n=await this.format(),l=await this.error()||await this.hint(),d=await this.renderChoices(),u=await this.footer();if(n||!l)i+=" "+n;if(l&&!i.includes(l))i+=" "+l;if(e&&!n&&!d&&this.multiple&&this.type!=="form")i+=this.styles.danger(this.emptyError);this.clear(t),this.write([i,a,d,u].filter(Boolean).join(`
|
|
34
|
+
`)),this.restore()}submit(){this.value={};for(let e of this.choices)this.value[e.name]=e.scaleIdx;return this.base.submit.call(this)}}function Ol(e,t={}){if(Array.isArray(t.scale))return t.scale.map((r)=>({...r}));let s=[];for(let r=1;r<e+1;r++)s.push({i:r,selected:!1});return s}Wr.exports=qr});var Vr=v((iu,Hr)=>{var Dl=Ue();class Kr extends Dl{async initialize(){await super.initialize(),this.value=this.initial=this.resolve(this.options.initial),this.disabled=this.options.disabled||"no",this.enabled=this.options.enabled||"yes",await this.render()}reset(){this.value=this.initial,this.render()}delete(){this.alert()}toggle(){this.value=!this.value,this.render()}enable(){if(this.value===!0)return this.alert();this.value=!0,this.render()}disable(){if(this.value===!1)return this.alert();this.value=!1,this.render()}up(){this.toggle()}down(){this.toggle()}right(){this.toggle()}left(){this.toggle()}next(){this.toggle()}prev(){this.toggle()}dispatch(e="",t){switch(e.toLowerCase()){case" ":return this.toggle();case"1":case"y":case"t":return this.enable();case"0":case"n":case"f":return this.disable();default:return this.alert()}}format(){let e=(s)=>this.styles.primary.underline(s);return[this.value?this.disabled:e(this.disabled),this.value?e(this.enabled):this.enabled].join(this.styles.muted(" / "))}async render(){let{size:e}=this.state,t=await this.header(),s=await this.prefix(),r=await this.separator(),o=await this.message(),i=await this.format(),a=await this.error()||await this.hint(),n=await this.footer(),l=[s,o,r,i].join(" ");if(this.state.prompt=l,a&&!l.includes(a))l+=" "+a;this.clear(e),this.write([t,l,n].filter(Boolean).join(`
|
|
35
|
+
`)),this.write(this.margin[2]),this.restore()}}Hr.exports=Kr});var Qr=v((au,Yr)=>{var Pl=oe();class zr extends Pl{constructor(e){super(e);if(typeof this.options.correctChoice!=="number"||this.options.correctChoice<0)throw Error("Please specify the index of the correct answer from the list of choices")}async toChoices(e,t){let s=await super.toChoices(e,t);if(s.length<2)throw Error("Please give at least two choices to the user");if(this.options.correctChoice>s.length)throw Error("Please specify the index of the correct answer from the list of choices");return s}check(e){return e.index===this.options.correctChoice}async result(e){return{selectedAnswer:e,correctAnswer:this.options.choices[this.options.correctChoice].value,correct:await this.check(this.state)}}}Yr.exports=zr});var Xr=v((Bt)=>{var Zr=_(),N=(e,t)=>{Zr.defineExport(Bt,e,t),Zr.defineExport(Bt,e.toLowerCase(),t)};N("AutoComplete",()=>Fs());N("BasicAuth",()=>Xs());N("Confirm",()=>sr());N("Editable",()=>ir());N("Form",()=>Le());N("Input",()=>Ct());N("Invisible",()=>fr());N("List",()=>br());N("MultiSelect",()=>Er());N("Numeral",()=>Mt());N("Password",()=>Nr());N("Scale",()=>_r());N("Select",()=>oe());N("Snippet",()=>Lr());N("Sort",()=>$r());N("Survey",()=>Fr());N("Text",()=>Ct());N("Toggle",()=>Vr());N("Quiz",()=>Qr())});var Jr=v((lu,jr)=>{jr.exports={ArrayPrompt:Ne(),AuthPrompt:Rt(),BooleanPrompt:Ue(),NumberPrompt:Mt(),StringPrompt:pe()}});var ae=v((du,to)=>{var eo=Ae("assert"),Ot=Ae("events"),ie=_();class q extends Ot{constructor(e,t){super();this.options=ie.merge({},e),this.answers={...t}}register(e,t){if(ie.isObject(e)){for(let r of Object.keys(e))this.register(r,e[r]);return this}eo.equal(typeof t,"function","expected a function");let s=e.toLowerCase();if(t.prototype instanceof this.Prompt)this.prompts[s]=t;else this.prompts[s]=t(this.Prompt,this);return this}async prompt(e=[]){for(let t of[].concat(e))try{if(typeof t==="function")t=await t.call(this);await this.ask(ie.merge({},this.options,t))}catch(s){return Promise.reject(s)}return this.answers}async ask(e){if(typeof e==="function")e=await e.call(this);let t=ie.merge({},this.options,e),{type:s,name:r}=e,{set:o,get:i}=ie;if(typeof s==="function")s=await s.call(this,e,this.answers);if(!s)return this.answers[r];if(s==="number")s="numeral";eo(this.prompts[s],`Prompt "${s}" is not registered`);let a=new this.prompts[s](t),n=i(this.answers,r);if(a.state.answers=this.answers,a.enquirer=this,r)a.on("submit",(d)=>{this.emit("answer",r,d,a),o(this.answers,r,d)});let l=a.emit.bind(a);if(a.emit=(...d)=>{return this.emit.call(this,...d),l(...d)},this.emit("prompt",a,this),t.autofill&&n!=null){if(a.value=a.input=n,t.autofill==="show")await a.submit()}else n=a.value=await a.run();return n}use(e){return e.call(this,this),this}set Prompt(e){this._Prompt=e}get Prompt(){return this._Prompt||this.constructor.Prompt}get prompts(){return this.constructor.prompts}static set Prompt(e){this._Prompt=e}static get Prompt(){return this._Prompt||fe()}static get prompts(){return Xr()}static get types(){return Jr()}static get prompt(){let e=(t,...s)=>{let r=new this(...s),o=r.emit.bind(r);return r.emit=(...i)=>{return e.emit(...i),o(...i)},r.prompt(t)};return ie.mixinEmitter(e,new Ot),e}}ie.mixinEmitter(q,new Ot);var It=q.prompts;for(let e of Object.keys(It)){let t=e.toLowerCase(),s=(r)=>new It[e](r).run();if(q.prompt[t]=s,q[t]=s,!q[e])Reflect.defineProperty(q,e,{get:()=>It[e]})}var Re=(e)=>{ie.defineExport(q,e,()=>q.types[e])};Re("ArrayPrompt");Re("AuthPrompt");Re("BooleanPrompt");Re("NumberPrompt");Re("StringPrompt");to.exports=q});var Di=v((Gt,$t)=>{(function(e,t){if(typeof Gt==="object"&&typeof $t==="object")$t.exports=t();else if(typeof define==="function"&&define.amd)define(function(){return t()});else e.pluralize=t()})(Gt,function(){var e=[],t=[],s={},r={},o={};function i(c){if(typeof c==="string")return new RegExp("^"+c+"$","i");return c}function a(c,p){if(c===p)return p;if(c===c.toLowerCase())return p.toLowerCase();if(c===c.toUpperCase())return p.toUpperCase();if(c[0]===c[0].toUpperCase())return p.charAt(0).toUpperCase()+p.substr(1).toLowerCase();return p.toLowerCase()}function n(c,p){return c.replace(/\$(\d{1,2})/g,function(f,y){return p[y]||""})}function l(c,p){return c.replace(p[0],function(f,y){var g=n(p[1],arguments);if(f==="")return a(c[y-1],g);return a(f,g)})}function d(c,p,f){if(!c.length||s.hasOwnProperty(c))return p;var y=f.length;while(y--){var g=f[y];if(g[0].test(p))return l(p,g)}return p}function u(c,p,f){return function(y){var g=y.toLowerCase();if(p.hasOwnProperty(g))return a(y,g);if(c.hasOwnProperty(g))return a(y,c[g]);return d(g,y,f)}}function h(c,p,f,y){return function(g){var b=g.toLowerCase();if(p.hasOwnProperty(b))return!0;if(c.hasOwnProperty(b))return!1;return d(b,b,f)===b}}function m(c,p,f){var y=p===1?m.singular(c):m.plural(c);return(f?p+" ":"")+y}return m.plural=u(o,r,e),m.isPlural=h(o,r,e),m.singular=u(r,o,t),m.isSingular=h(r,o,t),m.addPluralRule=function(c,p){e.push([i(c),p])},m.addSingularRule=function(c,p){t.push([i(c),p])},m.addUncountableRule=function(c){if(typeof c==="string"){s[c.toLowerCase()]=!0;return}m.addPluralRule(c,"$0"),m.addSingularRule(c,"$0")},m.addIrregularRule=function(c,p){p=p.toLowerCase(),c=c.toLowerCase(),o[c]=p,r[p]=c},[["I","we"],["me","us"],["he","they"],["she","they"],["them","them"],["myself","ourselves"],["yourself","yourselves"],["itself","themselves"],["herself","themselves"],["himself","themselves"],["themself","themselves"],["is","are"],["was","were"],["has","have"],["this","these"],["that","those"],["echo","echoes"],["dingo","dingoes"],["volcano","volcanoes"],["tornado","tornadoes"],["torpedo","torpedoes"],["genus","genera"],["viscus","viscera"],["stigma","stigmata"],["stoma","stomata"],["dogma","dogmata"],["lemma","lemmata"],["schema","schemata"],["anathema","anathemata"],["ox","oxen"],["axe","axes"],["die","dice"],["yes","yeses"],["foot","feet"],["eave","eaves"],["goose","geese"],["tooth","teeth"],["quiz","quizzes"],["human","humans"],["proof","proofs"],["carve","carves"],["valve","valves"],["looey","looies"],["thief","thieves"],["groove","grooves"],["pickaxe","pickaxes"],["passerby","passersby"]].forEach(function(c){return m.addIrregularRule(c[0],c[1])}),[[/s?$/i,"s"],[/[^\u0000-\u007F]$/i,"$0"],[/([^aeiou]ese)$/i,"$1"],[/(ax|test)is$/i,"$1es"],[/(alias|[^aou]us|t[lm]as|gas|ris)$/i,"$1es"],[/(e[mn]u)s?$/i,"$1s"],[/([^l]ias|[aeiou]las|[ejzr]as|[iu]am)$/i,"$1"],[/(alumn|syllab|vir|radi|nucle|fung|cact|stimul|termin|bacill|foc|uter|loc|strat)(?:us|i)$/i,"$1i"],[/(alumn|alg|vertebr)(?:a|ae)$/i,"$1ae"],[/(seraph|cherub)(?:im)?$/i,"$1im"],[/(her|at|gr)o$/i,"$1oes"],[/(agend|addend|millenni|dat|extrem|bacteri|desiderat|strat|candelabr|errat|ov|symposi|curricul|automat|quor)(?:a|um)$/i,"$1a"],[/(apheli|hyperbat|periheli|asyndet|noumen|phenomen|criteri|organ|prolegomen|hedr|automat)(?:a|on)$/i,"$1a"],[/sis$/i,"ses"],[/(?:(kni|wi|li)fe|(ar|l|ea|eo|oa|hoo)f)$/i,"$1$2ves"],[/([^aeiouy]|qu)y$/i,"$1ies"],[/([^ch][ieo][ln])ey$/i,"$1ies"],[/(x|ch|ss|sh|zz)$/i,"$1es"],[/(matr|cod|mur|sil|vert|ind|append)(?:ix|ex)$/i,"$1ices"],[/\b((?:tit)?m|l)(?:ice|ouse)$/i,"$1ice"],[/(pe)(?:rson|ople)$/i,"$1ople"],[/(child)(?:ren)?$/i,"$1ren"],[/eaux$/i,"$0"],[/m[ae]n$/i,"men"],["thou","you"]].forEach(function(c){return m.addPluralRule(c[0],c[1])}),[[/s$/i,""],[/(ss)$/i,"$1"],[/(wi|kni|(?:after|half|high|low|mid|non|night|[^\w]|^)li)ves$/i,"$1fe"],[/(ar|(?:wo|[ae])l|[eo][ao])ves$/i,"$1f"],[/ies$/i,"y"],[/\b([pl]|zomb|(?:neck|cross)?t|coll|faer|food|gen|goon|group|lass|talk|goal|cut)ies$/i,"$1ie"],[/\b(mon|smil)ies$/i,"$1ey"],[/\b((?:tit)?m|l)ice$/i,"$1ouse"],[/(seraph|cherub)im$/i,"$1"],[/(x|ch|ss|sh|zz|tto|go|cho|alias|[^aou]us|t[lm]as|gas|(?:her|at|gr)o|[aeiou]ris)(?:es)?$/i,"$1"],[/(analy|diagno|parenthe|progno|synop|the|empha|cri|ne)(?:sis|ses)$/i,"$1sis"],[/(movie|twelve|abuse|e[mn]u)s$/i,"$1"],[/(test)(?:is|es)$/i,"$1is"],[/(alumn|syllab|vir|radi|nucle|fung|cact|stimul|termin|bacill|foc|uter|loc|strat)(?:us|i)$/i,"$1us"],[/(agend|addend|millenni|dat|extrem|bacteri|desiderat|strat|candelabr|errat|ov|symposi|curricul|quor)a$/i,"$1um"],[/(apheli|hyperbat|periheli|asyndet|noumen|phenomen|criteri|organ|prolegomen|hedr|automat)a$/i,"$1on"],[/(alumn|alg|vertebr)ae$/i,"$1a"],[/(cod|mur|sil|vert|ind)ices$/i,"$1ex"],[/(matr|append)ices$/i,"$1ix"],[/(pe)(rson|ople)$/i,"$1rson"],[/(child)ren$/i,"$1"],[/(eau)x?$/i,"$1"],[/men$/i,"man"]].forEach(function(c){return m.addSingularRule(c[0],c[1])}),["adulthood","advice","agenda","aid","aircraft","alcohol","ammo","analytics","anime","athletics","audio","bison","blood","bream","buffalo","butter","carp","cash","chassis","chess","clothing","cod","commerce","cooperation","corps","debris","diabetes","digestion","elk","energy","equipment","excretion","expertise","firmware","flounder","fun","gallows","garbage","graffiti","hardware","headquarters","health","herpes","highjinks","homework","housework","information","jeans","justice","kudos","labour","literature","machinery","mackerel","mail","media","mews","moose","music","mud","manga","news","only","personnel","pike","plankton","pliers","police","pollution","premises","rain","research","rice","salmon","scissors","series","sewage","shambles","shrimp","software","species","staff","swine","tennis","traffic","transportation","trout","tuna","wealth","welfare","whiting","wildebeest","wildlife","you",/pok[e\u00E9]mon$/i,/[^aeiou]ese$/i,/deer$/i,/fish$/i,/measles$/i,/o[iu]s$/i,/pox$/i,/sheep$/i].forEach(m.addUncountableRule),m})});import{parseArgs as Jp}from"util";import{Exception as wa}from"@ooneex/exception";import{TerminalLogger as em}from"@ooneex/logger";import{container as Ia}from"@ooneex/container";var _e=[];var Vt=(e)=>{let t=null;return _e.find((s)=>{return t=Ia.get(s),t.getName()===e}),t};import{homedir as La}from"os";import{join as dt}from"path";import{TerminalLogger as Ua}from"@ooneex/logger";import{container as Oa,EContainerScope as Da}from"@ooneex/container";var E={command:(e=Da.Singleton)=>{return(t)=>{Oa.add(t,e),_e.push(t)}}};var zt=`#compdef oo ooneex
|
|
36
36
|
|
|
37
37
|
_oo_modules() {
|
|
38
38
|
local -a modules
|
|
@@ -66,6 +66,19 @@ _oo() {
|
|
|
66
66
|
'make\\:release:Release packages with version bump, changelog, and git tag'
|
|
67
67
|
'make\\:repository:Generate a new repository class'
|
|
68
68
|
'make\\:resource\\:book:Generate book resource (entity, migration, repository)'
|
|
69
|
+
'make\\:resource\\:calendar-event:Generate calendar event resource (entity, migration, repository)'
|
|
70
|
+
'make\\:resource\\:category:Generate category resource (entity, migration, repository)'
|
|
71
|
+
'make\\:resource\\:color:Generate color resource (entity, migration, repository)'
|
|
72
|
+
'make\\:resource\\:discount:Generate discount resource (entity, migration, repository)'
|
|
73
|
+
'make\\:resource\\:folder:Generate folder resource (entity, migration, repository)'
|
|
74
|
+
'make\\:resource\\:image:Generate image resource (entity, migration, repository)'
|
|
75
|
+
'make\\:resource\\:note:Generate note resource (entity, migration, repository)'
|
|
76
|
+
'make\\:resource\\:status:Generate status resource (entity, migration, repository)'
|
|
77
|
+
'make\\:resource\\:tag:Generate tag resource (entity, migration, repository)'
|
|
78
|
+
'make\\:resource\\:task:Generate task resource (entity, migration, repository)'
|
|
79
|
+
'make\\:resource\\:topic:Generate topic resource (entity, migration, repository)'
|
|
80
|
+
'make\\:resource\\:user:Generate user resource (entity, migration, repository)'
|
|
81
|
+
'make\\:resource\\:video:Generate video resource (entity, migration, repository)'
|
|
69
82
|
'make\\:seed:Generate a new seed file'
|
|
70
83
|
'make\\:service:Generate a new service class'
|
|
71
84
|
'make\\:storage:Generate a new storage class'
|
|
@@ -138,7 +151,7 @@ _oo() {
|
|
|
138
151
|
'--name=[Name of the resource]:name' \\
|
|
139
152
|
'--module=[Module name]:module:_oo_modules'
|
|
140
153
|
;;
|
|
141
|
-
make:release|make:resource:book|make:claude:skill|completion:zsh)
|
|
154
|
+
make:release|make:resource:book|make:resource:calendar-event|make:resource:category|make:resource:color|make:resource:discount|make:resource:folder|make:resource:image|make:resource:note|make:resource:status|make:resource:tag|make:resource:task|make:resource:topic|make:resource:user|make:resource:video|make:claude:skill|completion:zsh)
|
|
142
155
|
;;
|
|
143
156
|
esac
|
|
144
157
|
;;
|
|
@@ -146,7 +159,7 @@ _oo() {
|
|
|
146
159
|
}
|
|
147
160
|
|
|
148
161
|
_oo "$@"
|
|
149
|
-
`;var
|
|
162
|
+
`;var Yt=`#compdef oo ooneex
|
|
150
163
|
|
|
151
164
|
_ooneex_modules() {
|
|
152
165
|
local -a modules
|
|
@@ -180,6 +193,19 @@ _ooneex() {
|
|
|
180
193
|
'make\\:release:Release packages with version bump, changelog, and git tag'
|
|
181
194
|
'make\\:repository:Generate a new repository class'
|
|
182
195
|
'make\\:resource\\:book:Generate book resource (entity, migration, repository)'
|
|
196
|
+
'make\\:resource\\:calendar-event:Generate calendar event resource (entity, migration, repository)'
|
|
197
|
+
'make\\:resource\\:category:Generate category resource (entity, migration, repository)'
|
|
198
|
+
'make\\:resource\\:color:Generate color resource (entity, migration, repository)'
|
|
199
|
+
'make\\:resource\\:discount:Generate discount resource (entity, migration, repository)'
|
|
200
|
+
'make\\:resource\\:folder:Generate folder resource (entity, migration, repository)'
|
|
201
|
+
'make\\:resource\\:image:Generate image resource (entity, migration, repository)'
|
|
202
|
+
'make\\:resource\\:note:Generate note resource (entity, migration, repository)'
|
|
203
|
+
'make\\:resource\\:status:Generate status resource (entity, migration, repository)'
|
|
204
|
+
'make\\:resource\\:tag:Generate tag resource (entity, migration, repository)'
|
|
205
|
+
'make\\:resource\\:task:Generate task resource (entity, migration, repository)'
|
|
206
|
+
'make\\:resource\\:topic:Generate topic resource (entity, migration, repository)'
|
|
207
|
+
'make\\:resource\\:user:Generate user resource (entity, migration, repository)'
|
|
208
|
+
'make\\:resource\\:video:Generate video resource (entity, migration, repository)'
|
|
183
209
|
'make\\:seed:Generate a new seed file'
|
|
184
210
|
'make\\:service:Generate a new service class'
|
|
185
211
|
'make\\:storage:Generate a new storage class'
|
|
@@ -252,7 +278,7 @@ _ooneex() {
|
|
|
252
278
|
'--name=[Name of the resource]:name' \\
|
|
253
279
|
'--module=[Module name]:module:_ooneex_modules'
|
|
254
280
|
;;
|
|
255
|
-
make:release|make:resource:book|make:claude:skill|completion:zsh)
|
|
281
|
+
make:release|make:resource:book|make:resource:calendar-event|make:resource:category|make:resource:color|make:resource:discount|make:resource:folder|make:resource:image|make:resource:note|make:resource:status|make:resource:tag|make:resource:task|make:resource:topic|make:resource:user|make:resource:video|make:claude:skill|completion:zsh)
|
|
256
282
|
;;
|
|
257
283
|
esac
|
|
258
284
|
;;
|
|
@@ -260,9 +286,9 @@ _ooneex() {
|
|
|
260
286
|
}
|
|
261
287
|
|
|
262
288
|
_ooneex "$@"
|
|
263
|
-
`;class Be{getName(){return"completion:zsh"}getDescription(){return"Install Zsh completion for oo command"}async run(){let e=
|
|
289
|
+
`;class Be{getName(){return"completion:zsh"}getDescription(){return"Install Zsh completion for oo command"}async run(){let e=dt(La(),".zsh"),t=dt(e,"_oo");await Bun.write(t,zt);let s=dt(e,"_ooneex");await Bun.write(s,Yt);let r=new Ua;r.success(`${t} created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),r.success(`${s} created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),r.info(`Add the following to your .zshrc if not already present:
|
|
264
290
|
fpath=(~/.zsh $fpath)
|
|
265
|
-
autoload -Uz compinit && compinit`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0})}}Be=
|
|
291
|
+
autoload -Uz compinit && compinit`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0})}}Be=w([E.command()],Be);import{join as W}from"path";import{TerminalLogger as Wl}from"@ooneex/logger";import{toPascalCase as Fl}from"@ooneex/utils";var so=te(ae(),1);import{Assert as kl,Validation as Ll}from"@ooneex/validation";var Ul=1,Gl=/^[a-zA-Z][a-zA-Z0-9-]*$/;class Ce extends Ll{getConstraint(){return kl(`string >= ${Ul}`)}getErrorMessage(){return"Name must start with a letter and contain only letters, numbers, and hyphens"}validate(e,t){let s=super.validate(e,t);if(!s.isValid)return s;let r=e;if(!Gl.test(r))return{isValid:!1,message:this.getErrorMessage()||"Invalid name format"};return{isValid:!0}}}var A=async(e)=>{return(await so.prompt({type:"input",name:"name",message:e.message,validate:(s)=>{let o=new Ce().validate(s);if(!o.isValid)return o.message||"Controller name is invalid";return!0}})).name};var ro=`import { describe, expect, test } from "bun:test";
|
|
266
292
|
import { {{NAME}}Ai } from "@/ai/{{NAME}}Ai";
|
|
267
293
|
|
|
268
294
|
describe("{{NAME}}Ai", () => {
|
|
@@ -280,7 +306,7 @@ describe("{{NAME}}Ai", () => {
|
|
|
280
306
|
expect(typeof {{NAME}}Ai.prototype.runStream).toBe("function");
|
|
281
307
|
});
|
|
282
308
|
});
|
|
283
|
-
`;var
|
|
309
|
+
`;var oo=`import { decorator, type IAiChat, OpenAi, type OpenAiConfigType } from "@ooneex/ai";
|
|
284
310
|
import { inject } from "@ooneex/container";
|
|
285
311
|
|
|
286
312
|
@decorator.ai()
|
|
@@ -298,7 +324,7 @@ export class {{NAME}}Ai implements IAiChat<OpenAiConfigType> {
|
|
|
298
324
|
yield* this.ai.runStream(prompt || "My prompt", config);
|
|
299
325
|
}
|
|
300
326
|
}
|
|
301
|
-
`;class $e{getName(){return"make:ai"}getDescription(){return"Generate a new AI class"}async run(e){let{name:t,module:s}=e;if(!t)t=await A({message:"Enter name"});t=Fl(t).replace(/Ai$/,"");let
|
|
327
|
+
`;class $e{getName(){return"make:ai"}getDescription(){return"Generate a new AI class"}async run(e){let{name:t,module:s}=e;if(!t)t=await A({message:"Enter name"});t=Fl(t).replace(/Ai$/,"");let r=oo.replace(/{{NAME}}/g,t),o=s?W("modules",s):".",i=W(o,"src","ai"),a=W(process.cwd(),i),n=W(a,`${t}Ai.ts`);await Bun.write(n,r);let l=ro.replace(/{{NAME}}/g,t),d=W(o,"tests","ai"),u=W(process.cwd(),d),h=W(u,`${t}Ai.spec.ts`);await Bun.write(h,l);let m=new Wl;m.success(`${W(i,t)}Ai.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),m.success(`${W(d,t)}Ai.spec.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0});let c=W(process.cwd(),"package.json"),p=await Bun.file(c).json(),f=p.dependencies??{},y=p.devDependencies??{};if(!f["@ooneex/ai"]&&!y["@ooneex/ai"])await Bun.spawn(["bun","add","@ooneex/ai"],{cwd:process.cwd(),stdout:"ignore",stderr:"inherit"}).exited}}$e=w([E.command()],$e);import{join as F}from"path";import{TerminalLogger as Vl}from"@ooneex/logger";import{toPascalCase as zl}from"@ooneex/utils";var io=`import { describe, expect, test } from "bun:test";
|
|
302
328
|
import { {{NAME}}Analytics } from "@/analytics/{{NAME}}Analytics";
|
|
303
329
|
|
|
304
330
|
describe("{{NAME}}Analytics", () => {
|
|
@@ -311,7 +337,7 @@ describe("{{NAME}}Analytics", () => {
|
|
|
311
337
|
expect(typeof {{NAME}}Analytics.prototype.capture).toBe("function");
|
|
312
338
|
});
|
|
313
339
|
});
|
|
314
|
-
`;var
|
|
340
|
+
`;var ao=`import { decorator } from "@ooneex/analytics";
|
|
315
341
|
import type { IAnalytics } from "@ooneex/analytics";
|
|
316
342
|
|
|
317
343
|
type CaptureOptionsType = Record<string, unknown>;
|
|
@@ -322,7 +348,7 @@ export class {{NAME}}Analytics<T extends CaptureOptionsType = CaptureOptionsType
|
|
|
322
348
|
// console.log("Analytics captured:", options);
|
|
323
349
|
}
|
|
324
350
|
}
|
|
325
|
-
`;class qe{getName(){return"make:analytics"}getDescription(){return"Generate a new analytics class"}async run(e){let{name:t,module:s}=e;if(!t)t=await A({message:"Enter analytics name"});t=zl(t).replace(/Analytics$/,"");let
|
|
351
|
+
`;class qe{getName(){return"make:analytics"}getDescription(){return"Generate a new analytics class"}async run(e){let{name:t,module:s}=e;if(!t)t=await A({message:"Enter analytics name"});t=zl(t).replace(/Analytics$/,"");let r=ao.replace(/{{NAME}}/g,t),o=s?F("modules",s):".",i=F(o,"src","analytics"),a=F(process.cwd(),i),n=F(a,`${t}Analytics.ts`);await Bun.write(n,r);let l=io.replace(/{{NAME}}/g,t),d=F(o,"tests","analytics"),u=F(process.cwd(),d),h=F(u,`${t}Analytics.spec.ts`);await Bun.write(h,l);let m=new Vl;m.success(`${F(i,t)}Analytics.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),m.success(`${F(d,t)}Analytics.spec.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0});let c=F(process.cwd(),"package.json"),p=await Bun.file(c).json(),f=p.dependencies??{},y=p.devDependencies??{};if(!f["@ooneex/analytics"]&&!y["@ooneex/analytics"])await Bun.spawn(["bun","add","@ooneex/analytics"],{cwd:process.cwd(),stdout:"ignore",stderr:"inherit"}).exited}}qe=w([E.command()],qe);import{join as R}from"path";import{TerminalLogger as Od}from"@ooneex/logger";import{toKebabCase as Dd,toSnakeCase as Pd}from"@ooneex/utils";var no=te(ae(),1);var lo=async(e)=>{let t=new Ce;return(await no.prompt({type:"input",name:"destination",message:e.message,initial:e.initial||".",validate:(r)=>{let o=t.validate(r);if(!o.isValid)return o.message||"Invalid destination";return!0}})).destination};var co=`import { RuleConfigSeverity, type UserConfig } from "@commitlint/types";
|
|
326
352
|
|
|
327
353
|
const Configuration: UserConfig = {
|
|
328
354
|
extends: ["@commitlint/config-conventional"],
|
|
@@ -462,7 +488,7 @@ const Configuration: UserConfig = {
|
|
|
462
488
|
};
|
|
463
489
|
|
|
464
490
|
export default Configuration;
|
|
465
|
-
`;var
|
|
491
|
+
`;var po=`# Logs
|
|
466
492
|
logs
|
|
467
493
|
*.log
|
|
468
494
|
npm-debug.log*
|
|
@@ -612,7 +638,7 @@ vite.config.ts.timestamp-*
|
|
|
612
638
|
|
|
613
639
|
# Application
|
|
614
640
|
var/
|
|
615
|
-
`;var
|
|
641
|
+
`;var mo=`import { inject } from "@ooneex/container";
|
|
616
642
|
import { AppEnv } from "@ooneex/app-env";
|
|
617
643
|
import { DataSource } from "typeorm";
|
|
618
644
|
import { TypeormDatabase, DatabaseException, decorator } from "@ooneex/database";
|
|
@@ -646,7 +672,7 @@ export class AppDatabase extends TypeormDatabase {
|
|
|
646
672
|
return this.source;
|
|
647
673
|
}
|
|
648
674
|
}
|
|
649
|
-
`;var
|
|
675
|
+
`;var uo=`{
|
|
650
676
|
"$schema": "./node_modules/@biomejs/biome/configuration_schema.json",
|
|
651
677
|
"vcs": {
|
|
652
678
|
"enabled": true,
|
|
@@ -725,7 +751,7 @@ export class AppDatabase extends TypeormDatabase {
|
|
|
725
751
|
}
|
|
726
752
|
}
|
|
727
753
|
}
|
|
728
|
-
`;var
|
|
754
|
+
`;var ho=`[test]
|
|
729
755
|
coverage = true
|
|
730
756
|
|
|
731
757
|
[workspace]
|
|
@@ -756,7 +782,7 @@ buildDependencies = [
|
|
|
756
782
|
"@swc/core",
|
|
757
783
|
"nx",
|
|
758
784
|
]
|
|
759
|
-
`;var
|
|
785
|
+
`;var fo=`# use the official Bun image
|
|
760
786
|
# see all versions at https://hub.docker.com/r/oven/bun/tags
|
|
761
787
|
FROM oven/bun:1 AS base
|
|
762
788
|
WORKDIR /{{NAME}}
|
|
@@ -803,7 +829,7 @@ COPY --from=prerelease /{{NAME}}/dist .
|
|
|
803
829
|
USER bun
|
|
804
830
|
EXPOSE 3000/tcp
|
|
805
831
|
ENTRYPOINT [ "bun", "run", "index.js" ]
|
|
806
|
-
`;var
|
|
832
|
+
`;var yo=`services:
|
|
807
833
|
# PostgreSQL - Primary relational database
|
|
808
834
|
# Docs: https://www.postgresql.org/docs/
|
|
809
835
|
# Connection: postgresql://ooneex:ooneex@localhost:5432/ooneex
|
|
@@ -837,7 +863,7 @@ ENTRYPOINT [ "bun", "run", "index.js" ]
|
|
|
837
863
|
volumes:
|
|
838
864
|
{{NAME}}_db_data:
|
|
839
865
|
{{NAME}}_redis_data:
|
|
840
|
-
`;var
|
|
866
|
+
`;var Dt=`# =============================================================================
|
|
841
867
|
# App
|
|
842
868
|
# =============================================================================
|
|
843
869
|
|
|
@@ -1038,7 +1064,7 @@ SYSTEM_USERS=
|
|
|
1038
1064
|
SUPER_ADMIN_USERS=
|
|
1039
1065
|
# Comma-separated admin user emails
|
|
1040
1066
|
ADMIN_USERS=
|
|
1041
|
-
`;var
|
|
1067
|
+
`;var go=`import { PostHogAnalytics } from "@ooneex/analytics";
|
|
1042
1068
|
import { App } from "@ooneex/app";
|
|
1043
1069
|
import { RedisCache } from "@ooneex/cache";
|
|
1044
1070
|
import { LogtailLogger, ExceptionLogger, TerminalLogger } from "@ooneex/logger";
|
|
@@ -1050,8 +1076,12 @@ import { AppModule } from "./AppModule";
|
|
|
1050
1076
|
import { AppDatabase } from "./databases/AppDatabase";
|
|
1051
1077
|
|
|
1052
1078
|
const app = new App({
|
|
1053
|
-
|
|
1054
|
-
|
|
1079
|
+
routing: {
|
|
1080
|
+
prefix: "api",
|
|
1081
|
+
},
|
|
1082
|
+
check: {
|
|
1083
|
+
health: "/api/v1/healthcheck",
|
|
1084
|
+
},
|
|
1055
1085
|
loggers: [LogtailLogger, TerminalLogger],
|
|
1056
1086
|
onException: ExceptionLogger,
|
|
1057
1087
|
analytics: PostHogAnalytics,
|
|
@@ -1067,7 +1097,7 @@ const app = new App({
|
|
|
1067
1097
|
});
|
|
1068
1098
|
|
|
1069
1099
|
await app.run();
|
|
1070
|
-
`;var
|
|
1100
|
+
`;var bo=`{
|
|
1071
1101
|
"$schema": "./node_modules/nx/schemas/nx-schema.json",
|
|
1072
1102
|
"targetDefaults": {
|
|
1073
1103
|
"build": {
|
|
@@ -1097,7 +1127,7 @@ await app.run();
|
|
|
1097
1127
|
],
|
|
1098
1128
|
"packageManager": "bun"
|
|
1099
1129
|
}
|
|
1100
|
-
`;var
|
|
1130
|
+
`;var xo=`{
|
|
1101
1131
|
"name": "{{NAME}}",
|
|
1102
1132
|
"scripts": {
|
|
1103
1133
|
"dev": "bun run --filter app dev",
|
|
@@ -1120,7 +1150,7 @@ await app.run();
|
|
|
1120
1150
|
]
|
|
1121
1151
|
}
|
|
1122
1152
|
}
|
|
1123
|
-
`;var
|
|
1153
|
+
`;var wo=`# {{NAME}}
|
|
1124
1154
|
|
|
1125
1155
|
A modular, enterprise-grade backend framework built with TypeScript and Bun, powered by the **@ooneex** ecosystem.
|
|
1126
1156
|
|
|
@@ -1276,7 +1306,7 @@ This creates \`.claude/skills/\` in your project with skill guides for each \`ma
|
|
|
1276
1306
|
## License
|
|
1277
1307
|
|
|
1278
1308
|
Proprietary - All rights reserved.
|
|
1279
|
-
`;var
|
|
1309
|
+
`;var Eo=`{
|
|
1280
1310
|
"compilerOptions": {
|
|
1281
1311
|
"jsx": "react-jsx",
|
|
1282
1312
|
"lib": ["ES2022", "DOM"],
|
|
@@ -1305,7 +1335,7 @@ Proprietary - All rights reserved.
|
|
|
1305
1335
|
},
|
|
1306
1336
|
"exclude": ["node_modules", ".github", ".husky", ".nx", ".zed", ".vscode"]
|
|
1307
1337
|
}
|
|
1308
|
-
`;var
|
|
1338
|
+
`;var vo=`{
|
|
1309
1339
|
"formatter": "language_server",
|
|
1310
1340
|
"format_on_save": "on",
|
|
1311
1341
|
"languages": {
|
|
@@ -1407,7 +1437,7 @@ Proprietary - All rights reserved.
|
|
|
1407
1437
|
}
|
|
1408
1438
|
}
|
|
1409
1439
|
}
|
|
1410
|
-
`;import{basename as vd,join as
|
|
1440
|
+
`;import{basename as vd,join as L}from"path";import{TerminalLogger as Ad}from"@ooneex/logger";import{toKebabCase as Td,toPascalCase as We,trim as Sd}from"@ooneex/utils";var Ao=te(ae(),1),ge=async(e)=>{return(await Ao.prompt({type:"confirm",name:"confirm",message:e.message})).confirm};var Me=["GET","POST","PUT","DELETE","PATCH","OPTIONS","HEAD"];var To=te(ae(),1);import{Assert as ld,Validation as dd}from"@ooneex/validation";class Pt extends dd{getConstraint(){return ld("string >= 3")}getErrorMessage(){return`Route method must be one of: ${Me.join(", ")}`}validate(e,t){let s=super.validate(e,t);if(!s.isValid)return s;let r=e;if(r.trim()!==r)return{isValid:!1,message:this.getErrorMessage()||"Invalid route method format"};let o=r.toUpperCase();if(!Me.includes(o))return{isValid:!1,message:this.getErrorMessage()||"Invalid route method"};return{isValid:!0}}}var So=async(e)=>{return(await To.prompt({type:"select",name:"method",message:e.message,initial:e.initial??0,choices:Me.map((s)=>s),validate:(s)=>{let o=new Pt().validate(s);if(!o.isValid)return o.message||"Route method is invalid";return!0}})).method};var No=te(ae(),1);import{Assert as cd,Validation as pd}from"@ooneex/validation";var md=/^[a-zA-Z0-9]+\.[a-zA-Z0-9]+\.[a-zA-Z0-9]+$/;class kt extends pd{getConstraint(){return cd("string >= 7")}getErrorMessage(){return"Route name must follow format: namespace.resource.action (e.g., 'api.users.list')"}validate(e,t){let s=super.validate(e,t);if(!s.isValid)return s;let r=e;if(r.trim()!==r)return{isValid:!1,message:this.getErrorMessage()||"Invalid route name format"};if(!md.test(r))return{isValid:!1,message:this.getErrorMessage()||"Invalid route name format"};let o=r.split(".");if(o.length!==3)return{isValid:!1,message:this.getErrorMessage()||"Invalid route name format"};let[i,a,n]=o;if(!i||!a||!n)return{isValid:!1,message:this.getErrorMessage()||"Invalid route name format"};return{isValid:!0}}}var Ro=async(e)=>{return(await No.prompt({type:"input",name:"routeName",message:e.message,validate:(s)=>{let o=new kt().validate(s);if(!o.isValid)return o.message||"Route name is invalid";return!0}})).routeName};var Co=te(ae(),1);import{Assert as ud,Validation as hd}from"@ooneex/validation";var fd=1,yd=/^\/[\w\-/:]*$/,gd=/^[a-zA-Z0-9\-_]+$/,bd=/^:[a-zA-Z][a-zA-Z0-9]*$/;class Lt extends hd{getConstraint(){return ud(`string >= ${fd}`)}getErrorMessage(){return"Route path must start with '/' and contain only valid segments (e.g., '/users', '/api/users/:id')"}validate(e,t){let s=super.validate(e,t);if(!s.isValid)return s;let r=e;if(r.trim()!==r)return{isValid:!1,message:this.getErrorMessage()||"Invalid route path format"};if(!r.startsWith("/"))return{isValid:!1,message:"Route path must start with '/'"};if(r.length>1&&r.endsWith("/"))return{isValid:!1,message:"Route path cannot end with '/' (except for root path)"};if(!yd.test(r))return{isValid:!1,message:this.getErrorMessage()||"Invalid route path format"};if(r==="/")return{isValid:!0};let o=r.slice(1).split("/");for(let i of o){if(!i)return{isValid:!1,message:"Route path cannot contain empty segments (double slashes)"};if(i.startsWith(":")){if(!bd.test(i))return{isValid:!1,message:`Invalid parameter segment '${i}'. Parameters must follow format ':paramName' with alphanumeric characters only`}}else if(!gd.test(i))return{isValid:!1,message:`Invalid path segment '${i}'. Segments must contain only letters, numbers, hyphens, and underscores`}}return{isValid:!0}}}var Mo=async(e)=>{return(await Co.prompt({type:"input",name:"path",message:e.message,initial:e.initial??"/",validate:(s)=>{let o=new Lt().validate(s);if(!o.isValid)return o.message||"Route path is invalid";return!0}})).path};var _o=`import type { ContextType } from "@ooneex/socket";
|
|
1411
1441
|
import { ERole } from "@ooneex/role";
|
|
1412
1442
|
import { Route } from "@ooneex/routing";
|
|
1413
1443
|
import { Assert } from "@ooneex/validation";
|
|
@@ -1454,7 +1484,7 @@ export class {{NAME}}Controller {
|
|
|
1454
1484
|
});
|
|
1455
1485
|
}
|
|
1456
1486
|
}
|
|
1457
|
-
`;var
|
|
1487
|
+
`;var Bo=`import { describe, expect, test } from "bun:test";
|
|
1458
1488
|
import { {{NAME}}Controller } from "@/controllers/{{NAME}}Controller";
|
|
1459
1489
|
|
|
1460
1490
|
describe("{{NAME}}Controller", () => {
|
|
@@ -1467,7 +1497,7 @@ describe("{{NAME}}Controller", () => {
|
|
|
1467
1497
|
expect(typeof {{NAME}}Controller.prototype.index).toBe("function");
|
|
1468
1498
|
});
|
|
1469
1499
|
});
|
|
1470
|
-
`;var
|
|
1500
|
+
`;var Io=`import type { ContextType } from "@ooneex/controller";
|
|
1471
1501
|
import { ERole } from "@ooneex/role";
|
|
1472
1502
|
import { Route } from "@ooneex/routing";
|
|
1473
1503
|
import { Assert } from "@ooneex/validation";
|
|
@@ -1514,9 +1544,9 @@ export class {{NAME}}Controller {
|
|
|
1514
1544
|
});
|
|
1515
1545
|
}
|
|
1516
1546
|
}
|
|
1517
|
-
`;class ne{getName(){return"make:controller"}getDescription(){return"Generate a new controller class"}async addToModule(e,t){let s=await Bun.file(e).text(),
|
|
1547
|
+
`;class ne{getName(){return"make:controller"}getDescription(){return"Generate a new controller class"}async addToModule(e,t){let s=await Bun.file(e).text(),r=`${t}Controller`,o=`import { ${r} } from "./controllers/${r}";
|
|
1518
1548
|
`,i=s.lastIndexOf("import "),a=s.indexOf(`
|
|
1519
|
-
`,i);s=`${s.slice(0,a+1)}${
|
|
1549
|
+
`,i);s=`${s.slice(0,a+1)}${o}${s.slice(a+1)}`;let n=/(controllers:\s*\[)([^\]]*)/s,l=s.match(n);if(l){let d=l[2]?.trim(),u=d?`${d}, ${r}`:r;s=s.replace(n,`$1${u}`)}await Bun.write(e,s)}async run(e){let{name:t,module:s,isSocket:r}=e;if(!t)t=await A({message:"Enter controller name"});if(r===void 0)r=await ge({message:"Is this a socket controller?"});t=We(t).replace(/Controller$/,"");let{route:o={}}=e,a=(r?_o:Io).replaceAll("{{NAME}}",t);if(!o.name)o.name=await Ro({message:"Enter route name (e.g., api.user.create)"});let n=We(o.name);if(a=a.replaceAll("{{ROUTE_NAME}}",o.name).replaceAll("{{TYPE_NAME}}",n),!o.path)o.path=await Mo({message:"Enter route path",initial:"/"});let l=`/${Td(Sd(o.path,"/"))}`;if(a=a.replaceAll("{{ROUTE_PATH}}",l),!r&&!o.method)o.method=await So({message:"Enter route method"});if(!r&&o.method)a=a.replaceAll("{{ROUTE_METHOD}}",o.method.toLowerCase());let d=s?L("modules",s):".",u=L(d,"src","controllers"),h=L(process.cwd(),u),m=L(h,`${t}Controller.ts`);await Bun.write(m,a);let c=Bo.replace(/{{NAME}}/g,t),p=L(d,"tests","controllers"),f=L(process.cwd(),p),y=L(f,`${t}Controller.spec.ts`);await Bun.write(y,c);let g=s?We(s):We(vd(process.cwd())),b=L(process.cwd(),d,"src",`${g}Module.ts`);if(await Bun.file(b).exists())await this.addToModule(b,t);let x=new Ad;x.success(`${L(u,t)}Controller.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),x.success(`${L(p,t)}Controller.spec.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0});let T=L(process.cwd(),"package.json"),S=await Bun.file(T).json(),B=S.dependencies??{},lt=S.devDependencies??{};if(!B["@ooneex/controller"]&&!lt["@ooneex/controller"])await Bun.spawn(["bun","add","@ooneex/controller"],{cwd:process.cwd(),stdout:"ignore",stderr:"inherit"}).exited}}ne=w([E.command()],ne);import{join as D}from"path";import{TerminalLogger as _d}from"@ooneex/logger";import{toKebabCase as Bd,toPascalCase as Id}from"@ooneex/utils";var Oo=`import type { ModuleType } from "@ooneex/module";
|
|
1520
1550
|
|
|
1521
1551
|
export const {{NAME}}Module: ModuleType = {
|
|
1522
1552
|
controllers: [],
|
|
@@ -1525,7 +1555,7 @@ export const {{NAME}}Module: ModuleType = {
|
|
|
1525
1555
|
cronJobs: [],
|
|
1526
1556
|
events: [],
|
|
1527
1557
|
};
|
|
1528
|
-
`;var
|
|
1558
|
+
`;var Do=`{
|
|
1529
1559
|
"name": "@module/{{NAME}}",
|
|
1530
1560
|
"description": "",
|
|
1531
1561
|
"version": "0.0.1",
|
|
@@ -1534,7 +1564,7 @@ export const {{NAME}}Module: ModuleType = {
|
|
|
1534
1564
|
"lint": "tsgo --noEmit && bunx biome lint"
|
|
1535
1565
|
}
|
|
1536
1566
|
}
|
|
1537
|
-
`;var
|
|
1567
|
+
`;var Po=`import { describe, expect, test } from "bun:test";
|
|
1538
1568
|
import { {{NAME}}Module } from "@/{{NAME}}Module";
|
|
1539
1569
|
|
|
1540
1570
|
describe("{{NAME}}Module", () => {
|
|
@@ -1558,7 +1588,7 @@ describe("{{NAME}}Module", () => {
|
|
|
1558
1588
|
expect(Array.isArray({{NAME}}Module.events)).toBe(true);
|
|
1559
1589
|
});
|
|
1560
1590
|
});
|
|
1561
|
-
`;var
|
|
1591
|
+
`;var ko=`{
|
|
1562
1592
|
"extends": "../../tsconfig.json",
|
|
1563
1593
|
"compilerOptions": {
|
|
1564
1594
|
"types": ["@types/bun"],
|
|
@@ -1566,16 +1596,16 @@ describe("{{NAME}}Module", () => {
|
|
|
1566
1596
|
"@/*": ["./src/*"]
|
|
1567
1597
|
}
|
|
1568
1598
|
},
|
|
1569
|
-
"include": ["src/**/*.ts", "src/**/*.tsx", "tests/**/*.ts", "tests/**/*.tsx"],
|
|
1599
|
+
"include": ["src/**/*.ts", "src/**/*.tsx", "tests/**/*.ts", "tests/**/*.tsx", "bin/**/*.ts"],
|
|
1570
1600
|
"exclude": ["node_modules", "dist"]
|
|
1571
1601
|
}
|
|
1572
|
-
`;class le{getName(){return"make:module"}getDescription(){return"Generate a new module"}async addToAppModule(e,t,s){let
|
|
1573
|
-
`,n=
|
|
1574
|
-
`,n);
|
|
1602
|
+
`;class le{getName(){return"make:module"}getDescription(){return"Generate a new module"}async addToAppModule(e,t,s){let r=await Bun.file(e).text(),o=`${t}Module`,i=`@${s}/${o}`,a=`import { ${o} } from "${i}";
|
|
1603
|
+
`,n=r.lastIndexOf("import "),l=r.indexOf(`
|
|
1604
|
+
`,n);r=`${r.slice(0,l+1)}${a}${r.slice(l+1)}`;let d=["controllers","entities","middlewares","cronJobs","events"];for(let u of d){let h=new RegExp(`(${u}:\\s*\\[)([^\\]]*)`,"s"),m=r.match(h);if(m){let c=m[2]?.trim(),p=`...${o}.${u}`,f=c?`${c}, ${p}`:p;r=r.replace(h,`$1${f}`)}}await Bun.write(e,r)}async addModuleScope(e,t){let s=await Bun.file(e).text(),r=/("scope-enum":\s*\[\s*RuleConfigSeverity\.Error,\s*"always",\s*\[)([\s\S]*?)(\])/,o=s.match(r);if(o){let i=o[2]?.trim()??"",a=`"${t}"`;if(!i.includes(a)){let n=i?`${i}
|
|
1575
1605
|
${a},`:`
|
|
1576
|
-
${a},`;s=s.replace(
|
|
1577
|
-
$3`),await Bun.write(e,s)}}}async addPathAlias(e,t){let s=await Bun.file(e).text(),
|
|
1578
|
-
`)}async run(e){let{cwd:t=process.cwd(),silent:s=!1,skipMigrations:
|
|
1606
|
+
${a},`;s=s.replace(r,`$1${n}
|
|
1607
|
+
$3`),await Bun.write(e,s)}}}async addPathAlias(e,t){let s=await Bun.file(e).text(),r=JSON.parse(s);r.compilerOptions??={},r.compilerOptions.paths??={},r.compilerOptions.paths[`@${t}/*`]=[`../${t}/src/*`],await Bun.write(e,`${JSON.stringify(r,null,2)}
|
|
1608
|
+
`)}async run(e){let{cwd:t=process.cwd(),silent:s=!1,skipMigrations:r=!1,skipSeeds:o=!1}=e,{name:i}=e;if(!i)i=await A({message:"Enter module name"});let a=Id(i).replace(/Module$/,""),n=Bd(a),l=D(t,"modules",n),d=D(l,"src"),u=D(l,"tests"),h=Oo.replace(/{{NAME}}/g,a),m=Do.replace(/{{NAME}}/g,n),c=Po.replace(/{{NAME}}/g,a);if(await Bun.write(D(d,`${a}Module.ts`),h),!r)await Bun.write(D(d,"migrations","migrations.ts"),"");if(!o)await Bun.write(D(d,"seeds","seeds.ts"),"");if(await Bun.write(D(l,"package.json"),m),await Bun.write(D(l,"tsconfig.json"),ko),await Bun.write(D(u,`${a}Module.spec.ts`),c),n!=="app"){let x=D(t,"modules","app","src","AppModule.ts");if(await Bun.file(x).exists())await this.addToAppModule(x,a,n);let T=D(t,"modules","app","tsconfig.json");if(await Bun.file(T).exists())await this.addPathAlias(T,n)}let p=D(t,".commitlintrc.ts");if(await Bun.file(p).exists())await this.addModuleScope(p,n);if(!s)new _d().success(`modules/${n} created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0});let f=D(process.cwd(),"package.json"),y=await Bun.file(f).json(),g=y.dependencies??{},b=y.devDependencies??{};if(!g["@ooneex/module"]&&!b["@ooneex/module"])await Bun.spawn(["bun","add","@ooneex/module"],{cwd:process.cwd(),stdout:"ignore",stderr:"inherit"}).exited}}le=w([E.command()],le);class Fe{getName(){return"make:app"}getDescription(){return"Generate a new application"}async run(e){let{name:t,destination:s}=e;if(!t)t=await A({message:"Enter application name"});let r=Dd(t);if(!s)s=await lo({message:"Enter destination path",initial:r});let o=xo.replace(/{{NAME}}/g,r);await Bun.write(R(s,".commitlintrc.ts"),co),await Bun.write(R(s,".gitignore"),po),await Bun.write(R(s,"biome.jsonc"),uo),await Bun.write(R(s,"bunfig.toml"),ho),await Bun.write(R(s,"nx.json"),bo),await Bun.write(R(s,"package.json"),o),await Bun.write(R(s,"README.md"),wo.replace(/{{NAME}}/g,r)),await Bun.write(R(s,"tsconfig.json"),Eo),await Bun.write(R(s,".zed","settings.json"),vo),await new le().run({name:"app",cwd:s,silent:!0,skipMigrations:!0,skipSeeds:!0});let a=R(s,"modules","app","package.json"),n=await Bun.file(a).json();n.scripts.dev="docker compose up -d && bun --hot run ./src/index.ts",n.scripts.build="bun build ./src/index.ts --outdir ./dist --target bun",await Bun.write(a,JSON.stringify(n,null,2));let l=Dt.replace(/^DATABASE_URL=/m,'DATABASE_URL="postgresql://ooneex:ooneex@localhost:5432/ooneex"').replace(/^CACHE_REDIS_URL=/m,'CACHE_REDIS_URL="redis://localhost:6379"').replace(/^PUBSUB_REDIS_URL=/m,'PUBSUB_REDIS_URL="redis://localhost:6379"').replace(/^RATE_LIMIT_REDIS_URL=/m,'RATE_LIMIT_REDIS_URL="redis://localhost:6379"').replace(/^DATABASE_REDIS_URL=/m,'DATABASE_REDIS_URL="redis://localhost:6379"');await Bun.write(R(s,"modules","app",".env"),l),await Bun.write(R(s,"modules","app",".env.example"),Dt),await Bun.write(R(s,"modules","app","src","databases","AppDatabase.ts"),mo),await Bun.write(R(s,"modules","app","src","index.ts"),go);let d=Pd(t),u=yo.replace(/{{NAME}}/g,d);await Bun.write(R(s,"modules","app","docker-compose.yml"),u);let h=fo.replace(/{{NAME}}/g,d);await Bun.write(R(s,"modules","app","Dockerfile"),h),await Bun.write(R(s,"modules","app","var",".gitkeep"),""),await new ne().run({name:"HealthCheck",isSocket:!1,module:"app",route:{name:"api.health.check",path:"/healthcheck",method:"GET"}}),await Bun.spawn(["git","init"],{cwd:s,stdout:"ignore",stderr:"inherit"}).exited,await Bun.spawn(["bun","add","@ooneex/analytics","@ooneex/app","@ooneex/app-env","@ooneex/auth","@ooneex/cache","@ooneex/container","@ooneex/database","@ooneex/logger","@ooneex/mailer","@ooneex/middleware","@ooneex/module","@ooneex/rate-limit","@ooneex/role","@ooneex/routing","@ooneex/storage","@ooneex/translation","@ooneex/types","@ooneex/user","@ooneex/utils","@ooneex/validation","@ooneex/controller","pg","react","react-dom","apache-arrow","reflect-metadata","typeorm"],{cwd:s,stdout:"ignore",stderr:"inherit"}).exited,await Bun.spawn(["bun","add","-D","@biomejs/biome","@commitlint/cli","@commitlint/config-conventional","@commitlint/prompt-cli","@commitlint/types","@nx/js","@nx/workspace","@swc-node/register","@swc/core","@swc/helpers","@types/bun","@types/node","@types/react","@types/react-dom","@typescript/native-preview","husky","lint-staged","nx","typescript","undici-types"],{cwd:s,stdout:"ignore",stderr:"inherit"}).exited,await Bun.spawn(["bunx","husky","init"],{cwd:s,stdout:"ignore",stderr:"inherit"}).exited,await Bun.write(R(s,".husky","pre-commit"),"lint-staged"),await Bun.write(R(s,".husky","commit-msg"),'bunx commitlint --edit "$1"'),new Od().success(`${r} created successfully at ${s}`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0})}}Fe=w([E.command()],Fe);import{join as K}from"path";import{TerminalLogger as Ud}from"@ooneex/logger";import{toPascalCase as Gd}from"@ooneex/utils";var Lo=`import { describe, expect, test } from "bun:test";
|
|
1579
1609
|
import { {{NAME}}Cache } from "@/cache/{{NAME}}Cache";
|
|
1580
1610
|
|
|
1581
1611
|
describe("{{NAME}}Cache", () => {
|
|
@@ -1603,7 +1633,7 @@ describe("{{NAME}}Cache", () => {
|
|
|
1603
1633
|
expect(typeof {{NAME}}Cache.prototype.has).toBe("function");
|
|
1604
1634
|
});
|
|
1605
1635
|
});
|
|
1606
|
-
`;var
|
|
1636
|
+
`;var Uo=`import { CacheException, decorator } from "@ooneex/cache";
|
|
1607
1637
|
import type { ICache } from "@ooneex/cache";
|
|
1608
1638
|
|
|
1609
1639
|
@decorator.cache()
|
|
@@ -1624,7 +1654,7 @@ export class {{NAME}}Cache implements ICache {
|
|
|
1624
1654
|
throw new CacheException(\`Failed to check if key "\${key}" exists: Not implemented\`);
|
|
1625
1655
|
}
|
|
1626
1656
|
}
|
|
1627
|
-
`;class Ke{getName(){return"make:cache"}getDescription(){return"Generate a new cache class"}async run(e){let{name:t,module:s}=e;if(!t)t=await A({message:"Enter cache name"});t=Gd(t).replace(/Cache$/,"");let
|
|
1657
|
+
`;class Ke{getName(){return"make:cache"}getDescription(){return"Generate a new cache class"}async run(e){let{name:t,module:s}=e;if(!t)t=await A({message:"Enter cache name"});t=Gd(t).replace(/Cache$/,"");let r=Uo.replace(/{{NAME}}/g,t),o=s?K("modules",s):".",i=K(o,"src","cache"),a=K(process.cwd(),i),n=K(a,`${t}Cache.ts`);await Bun.write(n,r);let l=Lo.replace(/{{NAME}}/g,t),d=K(o,"tests","cache"),u=K(process.cwd(),d),h=K(u,`${t}Cache.spec.ts`);await Bun.write(h,l);let m=new Ud;m.success(`${K(i,t)}Cache.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),m.success(`${K(d,t)}Cache.spec.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0});let c=K(process.cwd(),"package.json"),p=await Bun.file(c).json(),f=p.dependencies??{},y=p.devDependencies??{};if(!f["@ooneex/cache"]&&!y["@ooneex/cache"])await Bun.spawn(["bun","add","@ooneex/cache"],{cwd:process.cwd(),stdout:"ignore",stderr:"inherit"}).exited}}Ke=w([E.command()],Ke);import{join as He}from"path";import{TerminalLogger as ac}from"@ooneex/logger";var Go=`---
|
|
1628
1658
|
name: commit
|
|
1629
1659
|
description: Create commit messages grouped by module. Analyzes git changes, groups files under modules/ by module name, and creates separate commits following commitlint conventions. Uses common scope for non-module changes.
|
|
1630
1660
|
---
|
|
@@ -1817,7 +1847,7 @@ Use \`refactor\` for file reorganization:
|
|
|
1817
1847
|
git add modules/product/
|
|
1818
1848
|
git commit -m "refactor(product): Reorganize service file structure"
|
|
1819
1849
|
\`\`\`
|
|
1820
|
-
`;var Gr="---\nname: make:ai\ndescription: Generate a new AI class with its test file, then complete the generated code. Use when creating a new AI chat class that uses OpenAI via the @ooneex/ai package.\n---\n\n# Make AI Class\n\nGenerate a new AI class and its test file using the `make:ai` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the AI class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:ai --name <name> --module <module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/ai/<Name>Ai.ts` - The AI class file (or `modules/<module>/src/ai/<Name>Ai.ts` with `--module`)\n- `tests/ai/<Name>Ai.spec.ts` - The test file (or `modules/<module>/tests/ai/<Name>Ai.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the AI class\n\nEdit `src/ai/<Name>Ai.ts` to complete the implementation:\n\n- Update the prompt in the `run` method from `\"My prompt\"` to a meaningful prompt based on the class purpose\n- Update the prompt in the `runStream` method from `\"My prompt\"` to a meaningful prompt based on the class purpose\n- Add any additional configuration or methods relevant to the AI class purpose\n- Ensure proper typing for the `run<T>()` generic return type\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { decorator, type IAiChat, OpenAi, type OpenAiConfigType } from \"@ooneex/ai\";\nimport { inject } from \"@ooneex/container\";\n\n@decorator.ai()\nexport class <Name>Ai implements IAiChat<OpenAiConfigType> {\n constructor(@inject(OpenAi) private readonly ai: OpenAi) {}\n\n public async run<T>(prompt?: string, config?: Omit<OpenAiConfigType, \"prompt\">): Promise<T> {\n return this.ai.run<T>(prompt || \"My prompt\", config);\n }\n\n public async *runStream(\n prompt?: string,\n config?: Omit<OpenAiConfigType, \"prompt\" | \"output\">,\n ): AsyncGenerator<string, void, unknown> {\n yield* this.ai.runStream(prompt || \"My prompt\", config);\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/ai/<Name>Ai.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep the existing scaffolded tests (class name, run method, runStream method)\n- Add tests relevant to the specific AI class behavior\n\nThe generated test structure follows this pattern:\n\n```typescript\nimport { describe, expect, test } from \"bun:test\";\nimport { <Name>Ai } from \"@/ai/<Name>Ai\";\n\ndescribe(\"<Name>Ai\", () => {\n test(\"should have class name ending with 'Ai'\", () => {\n expect(<Name>Ai.name.endsWith(\"Ai\")).toBe(true);\n });\n\n test(\"should have 'run' method\", () => {\n expect(<Name>Ai.prototype.run).toBeDefined();\n expect(typeof <Name>Ai.prototype.run).toBe(\"function\");\n });\n\n test(\"should have 'runStream' method\", () => {\n expect(<Name>Ai.prototype.runStream).toBeDefined();\n expect(typeof <Name>Ai.prototype.runStream).toBe(\"function\");\n });\n});\n```\n\n### 5. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/ai/<Name>Ai.ts tests/ai/<Name>Ai.spec.ts\n```\n";var $r="---\nname: make:analytics\ndescription: Generate a new analytics class with its test file, then complete the generated code. Use when creating a new analytics tracking class that uses the @ooneex/analytics package.\n---\n\n# Make Analytics Class\n\nGenerate a new analytics class and its test file using the `make:analytics` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the analytics class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:analytics --name <name> --module <module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/analytics/<Name>Analytics.ts` - The analytics class file (or `modules/<module>/src/analytics/<Name>Analytics.ts` with `--module`)\n- `tests/analytics/<Name>Analytics.spec.ts` - The test file (or `modules/<module>/tests/analytics/<Name>Analytics.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the analytics class\n\nEdit `src/analytics/<Name>Analytics.ts` to complete the implementation:\n\n- Implement the `capture` method with actual analytics tracking logic\n- Define a proper type for `CaptureOptionsType` instead of `Record<string, unknown>` based on the analytics purpose\n- Add any additional methods or properties relevant to the analytics class purpose\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { decorator } from \"@ooneex/analytics\";\nimport type { IAnalytics } from \"@ooneex/analytics\";\n\ntype CaptureOptionsType = Record<string, unknown>;\n\n@decorator.analytics()\nexport class <Name>Analytics<T extends CaptureOptionsType = CaptureOptionsType> implements IAnalytics<T> {\n public capture(options: T): void {\n // console.log(\"Analytics captured:\", options);\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/analytics/<Name>Analytics.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep the existing scaffolded tests (class name, capture method)\n- Add tests relevant to the specific analytics class behavior\n\nThe generated test structure follows this pattern:\n\n```typescript\nimport { describe, expect, test } from \"bun:test\";\nimport { <Name>Analytics } from \"@/analytics/<Name>Analytics\";\n\ndescribe(\"<Name>Analytics\", () => {\n test(\"should have class name ending with 'Analytics'\", () => {\n expect(<Name>Analytics.name.endsWith(\"Analytics\")).toBe(true);\n });\n\n test(\"should have 'capture' method\", () => {\n expect(<Name>Analytics.prototype.capture).toBeDefined();\n expect(typeof <Name>Analytics.prototype.capture).toBe(\"function\");\n });\n});\n```\n\n### 5. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/analytics/<Name>Analytics.ts tests/analytics/<Name>Analytics.spec.ts\n```\n";var qr="---\nname: make:cache\ndescription: Generate a new cache adapter class with its test file, then complete the generated code. Use when creating a new cache adapter that implements the ICache interface from @ooneex/cache.\n---\n\n# Make Cache Class\n\nGenerate a new cache class and its test file using the `make:cache` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the cache class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:cache --name <name> --module <module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/cache/<Name>Cache.ts` - The cache class file (or `modules/<module>/src/cache/<Name>Cache.ts` with `--module`)\n- `tests/cache/<Name>Cache.spec.ts` - The test file (or `modules/<module>/tests/cache/<Name>Cache.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the cache class\n\nEdit `src/cache/<Name>Cache.ts` to complete the implementation:\n\n- Implement the `get` method to retrieve cached values by key\n- Implement the `set` method to store values with optional TTL\n- Implement the `delete` method to remove cached entries\n- Implement the `has` method to check key existence\n- Replace the `CacheException` throws with actual cache logic\n- Inject any required dependencies (e.g., Redis client) via the constructor\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { CacheException, decorator } from \"@ooneex/cache\";\nimport type { ICache } from \"@ooneex/cache\";\n\n@decorator.cache()\nexport class <Name>Cache implements ICache {\n public async get<T = unknown>(key: string): Promise<T | undefined> {\n throw new CacheException(`Failed to get key \"${key}\": Not implemented`);\n }\n\n public async set<T = unknown>(key: string, value: T, ttl?: number): Promise<void> {\n throw new CacheException(`Failed to set key \"${key}\": Not implemented`);\n }\n\n public async delete(key: string): Promise<boolean> {\n throw new CacheException(`Failed to delete key \"${key}\": Not implemented`);\n }\n\n public async has(key: string): Promise<boolean> {\n throw new CacheException(`Failed to check if key \"${key}\" exists: Not implemented`);\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/cache/<Name>Cache.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep the existing scaffolded tests (class name, get, set, delete, has methods)\n- Add tests relevant to the specific cache class behavior\n\nThe generated test structure follows this pattern:\n\n```typescript\nimport { describe, expect, test } from \"bun:test\";\nimport { <Name>Cache } from \"@/cache/<Name>Cache\";\n\ndescribe(\"<Name>Cache\", () => {\n test(\"should have class name ending with 'Cache'\", () => {\n expect(<Name>Cache.name.endsWith(\"Cache\")).toBe(true);\n });\n\n test(\"should have 'get' method\", () => {\n expect(<Name>Cache.prototype.get).toBeDefined();\n expect(typeof <Name>Cache.prototype.get).toBe(\"function\");\n });\n\n test(\"should have 'set' method\", () => {\n expect(<Name>Cache.prototype.set).toBeDefined();\n expect(typeof <Name>Cache.prototype.set).toBe(\"function\");\n });\n\n test(\"should have 'delete' method\", () => {\n expect(<Name>Cache.prototype.delete).toBeDefined();\n expect(typeof <Name>Cache.prototype.delete).toBe(\"function\");\n });\n\n test(\"should have 'has' method\", () => {\n expect(<Name>Cache.prototype.has).toBeDefined();\n expect(typeof <Name>Cache.prototype.has).toBe(\"function\");\n });\n});\n```\n\n### 5. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/cache/<Name>Cache.ts tests/cache/<Name>Cache.spec.ts\n```\n";var Wr="---\nname: make:controller\ndescription: Generate a new controller class with route type and test file, then complete the generated code. Use when creating a new HTTP or WebSocket controller with routing, validation, and role-based access.\n---\n\n# Make Controller Class\n\nGenerate a new controller class, its route type, and test file using the `make:controller` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the controller class and related files:\n\n```bash\nbunx @ooneex/cli@latest make:controller --name <name> --module <module> --is-socket <true|false> --route.name <route.name> --route.path <route.path> --route.method <route.method>\n```\n\nWhere:\n- `<name>` is the controller name provided by the user\n- `--module` is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root\n- `--is-socket` determines HTTP vs WebSocket controller (defaults to `false`)\n- `--route.name` is the route name using dot notation: `<resource>.<action>` (e.g., `user.create`, `book.list`, `flashcard.delete`)\n- `--route.path` is the route path (e.g., `/api/users`)\n- `--route.method` is the HTTP method (e.g., `get`, `post`, `put`, `patch`, `delete`) \u2014 only for HTTP controllers\n\nThe command will generate (paths prefixed with `modules/<module>/` when `--module` is provided):\n- `src/controllers/<Name>Controller.ts` - The controller class file\n- `src/types/routes/<route.name>.ts` - The route type file (will be moved into the controller file \u2014 see step 3)\n- `tests/controllers/<Name>Controller.spec.ts` - The test file\n\n### 2. Read the generated files\n\nRead all three generated files to understand the scaffolded code.\n\n### 3. Complete the route type\n\n**IMPORTANT: Keep the route type inside the controller file**, not in a separate type file. Define the type directly in `src/controllers/<Name>Controller.ts` above the class definition. Delete the generated `src/types/routes/<route.name>.ts` file if it was created.\n\n**Remove unnecessary `params`, `payload`, and `queries` \u2014 only include what the route actually needs:**\n\n- **`params`** \u2014 Include only when the route path contains dynamic segments (e.g., `/api/users/:id`). Remove entirely for routes with no URL parameters (e.g., `/api/users`).\n- **`payload`** \u2014 Include only for methods that accept a request body (`post`, `put`, `patch`). Remove entirely for `get` and `delete` routes.\n- **`queries`** \u2014 Include only when the route supports query string filtering, pagination, or sorting (e.g., list/search endpoints). Remove entirely when not needed.\n- **`response`** \u2014 Always include.\n\nThe route type structure follows this pattern (remove unused sections):\n\n```typescript\n// Example: GET /api/users (list) \u2014 no params, no payload, has queries\ntype <TypeName>RouteType = {\n queries: {\n\n },\n response: {\n\n },\n};\n\n// Example: POST /api/users (create) \u2014 no params, has payload, no queries\ntype <TypeName>RouteType = {\n payload: {\n\n },\n response: {\n\n },\n};\n\n// Example: GET /api/users/:id (detail) \u2014 has params, no payload, no queries\ntype <TypeName>RouteType = {\n params: {\n\n },\n response: {\n\n },\n};\n\n// Example: PUT /api/users/:id (update) \u2014 has params, has payload, no queries\ntype <TypeName>RouteType = {\n params: {\n\n },\n payload: {\n\n },\n response: {\n\n },\n};\n```\n\n### 4. Complete the controller class\n\nEdit `src/controllers/<Name>Controller.ts` to complete the implementation:\n\n- Set appropriate `roles` for access control\n- Add a meaningful `description` for the route that explains what the endpoint does (e.g., `\"Create a new user account\"`, `\"List all books with pagination\"`)\n- **Keep the controller thin** \u2014 do NOT put business logic in the controller. Put all logic in the corresponding service and inject the service into the controller via the constructor. The controller's `index` method should only delegate to the service.\n- **Remove unnecessary `params`, `payload`, and `queries`** from both the route type and the `@Route` decorator \u2014 only include what the route actually needs (see step 3 rules).\n\n**Add or remove `params`, `payload`, and `queries` in the `@Route` decorator to match the route type (step 3):**\n\n- **`params`** \u2014 Include with `Assert()` validators only when the route has URL parameters. Remove the `params` key entirely otherwise.\n- **`payload`** \u2014 Include with `Assert({...})` only for `post`, `put`, `patch` methods. Remove the `payload` key entirely for `get` and `delete`.\n- **`queries`** \u2014 Include with `Assert({...})` only when query parameters are expected. Remove the `queries` key entirely otherwise.\n- **`response`** \u2014 Always include with `Assert({...})`.\n\n**HTTP controller** generated structure (remove `params`, `payload`, `queries` as needed \u2014 see rules above):\n\n```typescript\nimport type { ContextType } from \"@ooneex/controller\";\nimport { ERole } from \"@ooneex/role\";\nimport { Route } from \"@ooneex/routing\";\nimport { Assert } from \"@ooneex/validation\";\n\ntype <TypeName>RouteType = {\n // Only include params, payload, queries as needed (see step 3)\n response: {\n\n },\n};\n\n@Route.<method>(\"<route.path>\", {\n name: \"<route.name>\",\n version: 1,\n description: \"\",\n // Only include params, payload, queries as needed (see step 3)\n response: Assert({\n\n }),\n roles: [ERole.USER],\n})\nexport class <Name>Controller {\n public async index(context: ContextType<<TypeName>RouteType>) {\n return context.response.json({\n\n });\n }\n}\n```\n\n**Socket controller** generated structure (remove `params`, `payload`, `queries` as needed \u2014 see rules above):\n\n```typescript\nimport type { ContextType } from \"@ooneex/socket\";\nimport { ERole } from \"@ooneex/role\";\nimport { Route } from \"@ooneex/routing\";\nimport { Assert } from \"@ooneex/validation\";\n\ntype <TypeName>RouteType = {\n // Only include params, payload, queries as needed (see step 3)\n response: {\n\n },\n};\n\n@Route.socket(\"<route.path>\", {\n name: \"<route.name>\",\n version: 1,\n description: \"\",\n // Only include params, payload, queries as needed (see step 3)\n response: Assert({\n\n }),\n roles: [ERole.USER],\n})\nexport class <Name>Controller {\n public async index(context: ContextType<<TypeName>RouteType>) {\n return context.response.json({\n\n });\n }\n}\n```\n\n### 5. Complete the test file\n\nEdit `tests/controllers/<Name>Controller.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep the existing scaffolded tests (class name, index method)\n- Add tests relevant to the specific controller behavior\n\nThe generated test structure follows this pattern:\n\n```typescript\nimport { describe, expect, test } from \"bun:test\";\nimport { <Name>Controller } from \"@/controllers/<Name>Controller\";\n\ndescribe(\"<Name>Controller\", () => {\n test(\"should have class name ending with 'Controller'\", () => {\n expect(<Name>Controller.name.endsWith(\"Controller\")).toBe(true);\n });\n\n test(\"should have 'index' method\", () => {\n expect(<Name>Controller.prototype.index).toBeDefined();\n expect(typeof <Name>Controller.prototype.index).toBe(\"function\");\n });\n});\n```\n\n### 6. Register the controller in the module\n\nAdd the new controller to the module's `controllers` array in `src/<PascalModuleName>Module.ts` (e.g., `src/BookModule.ts` for the `book` module):\n\n```typescript\nimport type { ModuleType } from \"@ooneex/module\";\nimport { <Name>Controller } from \"./controllers/<Name>Controller\";\n\nexport const <PascalModuleName>Module: ModuleType = {\n controllers: [<Name>Controller],\n entities: [],\n permissions: [],\n middlewares: [],\n cronJobs: [],\n events: [],\n};\n```\n\nThe module file uses PascalCase naming: `<PascalModuleName>Module.ts` with export `<PascalModuleName>Module`.\n\nIf the module already has other controllers registered, append the new controller to the existing `controllers` array and add the import alongside existing imports.\n\n### 7. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/controllers/<Name>Controller.ts tests/controllers/<Name>Controller.spec.ts\n```\n\n### 8. Create the service\n\nAfter the controller is created, generate a service class for the controller's business logic using the `make:service` skill:\n\n```\n/make:service --name <Name>\n```\n\nWhere `<Name>` matches the controller name (e.g., if the controller is `CreateUserController`, the service is `CreateUserService`).\n\n### 9. Create the pubsub event\n\nAfter the service is created, generate a pubsub event class for the controller's domain events using the `make:pubsub` skill:\n\n```\n/make:pubsub --name <Name> --channel <resource>.<action>\n```\n\nWhere:\n- `<Name>` matches the controller name (e.g., if the controller is `CreateUserController`, the event is `CreateUserEvent`)\n- `<resource>.<action>` follows the same dot notation as the route name (e.g., `user.create`, `book.delete`)\n\nOnce the event is created:\n- Inject the **service** into the **event** via the constructor, and call the service's `execute` method from the event's `handler` method.\n- Inject the **event** into the **controller** via the constructor, and publish the event from the controller's `index` method.\n";var Fr="---\nname: make:cron\ndescription: Generate a new cron job class with its test file, then complete the generated code. Use when creating a new scheduled task that extends the Cron base class from @ooneex/cron.\n---\n\n# Make Cron Class\n\nGenerate a new cron class and its test file using the `make:cron` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the cron class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:cron --name <name> --module <module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/cron/<Name>Cron.ts` - The cron class file (or `modules/<module>/src/cron/<Name>Cron.ts` with `--module`)\n- `tests/cron/<Name>Cron.spec.ts` - The test file (or `modules/<module>/tests/cron/<Name>Cron.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the cron class\n\nEdit `src/cron/<Name>Cron.ts` to complete the implementation:\n\n- Set the appropriate cron schedule in `getTime()` (e.g., `\"every 5 minutes\"`, `\"every 1 hours\"`, `\"every 30 seconds\"`)\n- Set the timezone in `getTimeZone()` if needed, or keep `null` for server timezone\n- Implement the `handler()` method with the actual cron job logic\n- Inject any required dependencies via the constructor\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport type { TimeZoneType } from \"@ooneex/country\";\nimport type { CronTimeType } from \"@ooneex/cron\";\nimport { Cron, decorator } from \"@ooneex/cron\";\n\n@decorator.cron()\nexport class <Name>Cron extends Cron {\n public getTime(): CronTimeType {\n // Examples: \"every 5 minutes\", \"every 1 hours\", \"every 30 seconds\"\n return \"every 1 hours\";\n }\n\n public getTimeZone(): TimeZoneType | null {\n // Return null to use server timezone, or specify a timezone like \"Europe/Paris\"\n return null;\n }\n\n public async handler(): Promise<void> {\n // Implement your cron handler logic here\n // console.log(\"<Name>Cron handler executed\");\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/cron/<Name>Cron.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep the existing scaffolded tests (class name, getTime, getTimeZone, handler methods)\n- Add tests relevant to the specific cron class behavior\n\nThe generated test structure follows this pattern:\n\n```typescript\nimport { describe, expect, test } from \"bun:test\";\nimport { <Name>Cron } from \"@/cron/<Name>Cron\";\n\ndescribe(\"<Name>Cron\", () => {\n test(\"should have class name ending with 'Cron'\", () => {\n expect(<Name>Cron.name.endsWith(\"Cron\")).toBe(true);\n });\n\n test(\"should have 'getTime' method\", () => {\n expect(<Name>Cron.prototype.getTime).toBeDefined();\n expect(typeof <Name>Cron.prototype.getTime).toBe(\"function\");\n });\n\n test(\"should have 'getTimeZone' method\", () => {\n expect(<Name>Cron.prototype.getTimeZone).toBeDefined();\n expect(typeof <Name>Cron.prototype.getTimeZone).toBe(\"function\");\n });\n\n test(\"should have 'handler' method\", () => {\n expect(<Name>Cron.prototype.handler).toBeDefined();\n expect(typeof <Name>Cron.prototype.handler).toBe(\"function\");\n });\n});\n```\n\n### 5. Register the cron job in the module\n\nAdd the new cron job to the module's `cronJobs` array in `src/<PascalModuleName>Module.ts` (e.g., `src/BookModule.ts` for the `book` module):\n\n```typescript\nimport type { ModuleType } from \"@ooneex/module\";\nimport { <Name>Cron } from \"./cron/<Name>Cron\";\n\nexport const <PascalModuleName>Module: ModuleType = {\n controllers: [],\n entities: [],\n permissions: [],\n middlewares: [],\n cronJobs: [<Name>Cron],\n events: [],\n};\n```\n\nThe module file uses PascalCase naming: `<PascalModuleName>Module.ts` with export `<PascalModuleName>Module`.\n\nIf the module already has other cron jobs registered, append the new cron job to the existing `cronJobs` array and add the import alongside existing imports.\n\n### 6. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/cron/<Name>Cron.ts tests/cron/<Name>Cron.spec.ts\n```\n";var Kr="---\nname: make:database\ndescription: Generate a new database class with its test file, then complete the generated code. Use when creating a new database adapter that extends TypeormDatabase from @ooneex/database.\n---\n\n# Make Database Class\n\nGenerate a new database class and its test file using the `make:database` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the database class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:database --name <name> --module <module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/databases/<Name>Database.ts` - The database class file (or `modules/<module>/src/databases/<Name>Database.ts` with `--module`)\n- `tests/databases/<Name>Database.spec.ts` - The test file (or `modules/<module>/tests/databases/<Name>Database.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the database class\n\nEdit `src/databases/<Name>Database.ts` to complete the implementation:\n\n- Add entity imports and register them in the `entities` array\n- Adjust the database path if needed (default is `\"var/db\"`)\n- Configure DataSource options as appropriate (type, synchronize, etc.)\n- Inject any required dependencies via the constructor\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { DataSource } from \"typeorm\";\nimport { TypeormDatabase, DatabaseException, decorator } from \"@ooneex/database\";\n\n@decorator.database()\nexport class <Name>Database extends TypeormDatabase {\n public getSource(database?: string): DataSource {\n database = database || \"var/db\";\n\n this.source = new DataSource({\n synchronize: false,\n entities: [\n // TODO: Load your entities here\n ],\n enableWAL: true,\n busyErrorRetry: 2000,\n busyTimeout: 30_000,\n database,\n type: \"sqlite\",\n });\n\n return this.source;\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/databases/<Name>Database.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep the existing scaffolded tests (class name, getSource method)\n- Add tests relevant to the specific database class behavior\n\nThe generated test structure follows this pattern:\n\n```typescript\nimport { describe, expect, test } from \"bun:test\";\nimport { <Name>Database } from \"@/databases/<Name>Database\";\n\ndescribe(\"<Name>Database\", () => {\n test(\"should have class name ending with 'Database'\", () => {\n expect(<Name>Database.name.endsWith(\"Database\")).toBe(true);\n });\n\n test(\"should have 'getSource' method\", () => {\n expect(<Name>Database.prototype.getSource).toBeDefined();\n expect(typeof <Name>Database.prototype.getSource).toBe(\"function\");\n });\n});\n```\n\n### 5. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/databases/<Name>Database.ts tests/databases/<Name>Database.spec.ts\n```\n";var Hr="---\nname: make:entity\ndescription: Generate a new TypeORM entity class with its test file, then complete the generated code. Use when creating a new database entity with columns, relations, and table mapping.\n---\n\n# Make Entity Class\n\nGenerate a new entity class and its test file using the `make:entity` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the entity class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:entity --name <name> --module <module> --table-name <table_name>\n```\n\nWhere `<name>` is the name provided by the user. The `--table-name` option is optional \u2014 if omitted, it defaults to the snake_case pluralized form of the name (e.g., `UserProfile` becomes `user_profiles`). The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/entities/<Name>Entity.ts` - The entity class file (or `modules/<module>/src/entities/<Name>Entity.ts` with `--module`)\n- `tests/entities/<Name>Entity.spec.ts` - The test file (or `modules/<module>/tests/entities/<Name>Entity.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the entity class\n\nEdit `src/entities/<Name>Entity.ts` to complete the implementation:\n\n- Add entity-specific columns with appropriate TypeORM decorators (`@Column`)\n- Add relations if needed (`@ManyToOne`, `@OneToMany`, `@ManyToMany`, etc.)\n- Remove any scaffolded columns that are not relevant to the entity\n- Adjust column types, lengths, and constraints as needed\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport type { LocaleType } from \"@ooneex/translation\";\nimport { random } from \"@ooneex/utils\";\nimport { Column, CreateDateColumn, DeleteDateColumn, PrimaryColumn, UpdateDateColumn } from \"typeorm\";\n\n@Entity({\n name: \"<table_name>\",\n})\nexport class <Name>Entity extends BaseEntity {\n @PrimaryColumn({ name: \"id\", type: \"varchar\", length: 25 })\n id: string = random.nanoid(25);\n\n @Column({\n name: \"is_locked\",\n type: \"boolean\",\n default: false,\n nullable: true,\n })\n isLocked?: boolean;\n\n @Column({ name: \"locked_at\", type: \"timestamptz\", nullable: true })\n lockedAt?: Date;\n\n @Column({\n name: \"is_blocked\",\n type: \"boolean\",\n default: false,\n nullable: true,\n })\n isBlocked?: boolean;\n\n @Column({ name: \"blocked_at\", type: \"timestamptz\", nullable: true })\n blockedAt?: Date;\n\n @Column({ name: \"block_reason\", type: \"text\", nullable: true })\n blockReason?: string;\n\n @Column({ name: \"is_public\", type: \"boolean\", default: true, nullable: true })\n isPublic?: boolean;\n\n @Column({ name: \"lang\", type: \"varchar\", length: 10, nullable: true })\n lang?: LocaleType;\n\n @CreateDateColumn({ name: \"created_at\" })\n createdAt?: Date;\n\n @UpdateDateColumn({ name: \"updated_at\" })\n updatedAt?: Date;\n\n @DeleteDateColumn({ name: \"deleted_at\" })\n deletedAt?: Date;\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/entities/<Name>Entity.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep the existing scaffolded tests (class name, id, default columns)\n- Add tests for any new entity-specific columns and relations\n- Update tests if scaffolded columns were removed\n\nThe generated test structure follows this pattern:\n\n```typescript\nimport { describe, expect, test } from \"bun:test\";\nimport { <Name>Entity } from \"@/entities/<Name>Entity\";\n\ndescribe(\"<Name>Entity\", () => {\n test(\"should have class name ending with 'Entity'\", () => {\n expect(<Name>Entity.name.endsWith(\"Entity\")).toBe(true);\n });\n\n test(\"should have 'id' property with default nanoid\", () => {\n const entity = new <Name>Entity();\n expect(entity.id).toBeDefined();\n expect(typeof entity.id).toBe(\"string\");\n expect(entity.id.length).toBe(25);\n });\n\n test(\"should have 'isLocked' property\", () => {\n const entity = new <Name>Entity();\n expect(\"isLocked\" in entity).toBe(true);\n });\n\n // ... additional property tests\n});\n```\n\n### 5. Register the entity in the module\n\nAdd the new entity to the module's `entities` array in `src/<PascalModuleName>Module.ts` (e.g., `src/BookModule.ts` for the `book` module):\n\n```typescript\nimport type { ModuleType } from \"@ooneex/module\";\nimport { <Name>Entity } from \"./entities/<Name>Entity\";\n\nexport const <PascalModuleName>Module: ModuleType = {\n controllers: [],\n entities: [<Name>Entity],\n permissions: [],\n middlewares: [],\n cronJobs: [],\n events: [],\n};\n```\n\nThe module file uses PascalCase naming: `<PascalModuleName>Module.ts` with export `<PascalModuleName>Module`.\n\nIf the module already has other entities registered, append the new entity to the existing `entities` array and add the import alongside existing imports.\n\n### 6. Create a migration for the entity\n\nAfter creating or updating an entity, generate a migration to apply the corresponding schema changes to the database.\n\nRun the generator:\n\n```bash\nbunx @ooneex/cli@latest make:migration\n```\n\nThen read the generated migration file in `src/migrations/` and complete it:\n\n- In the `up` method, write the SQL to create the table (or alter it if updating an existing entity). Include all columns, types, constraints, defaults, and indexes matching the entity definition.\n- In the `down` method, write the reverse SQL to undo the changes (e.g., `DROP TABLE` or `ALTER TABLE DROP COLUMN`).\n- If the migration depends on another migration (e.g., a foreign key referencing another table), add that migration class to the `getDependencies()` return array.\n\nExample `up` method for a new entity:\n\n```typescript\npublic async up(tx: TransactionSQL): Promise<void> {\n await tx`\n CREATE TABLE IF NOT EXISTS <table_name> (\n id VARCHAR(25) PRIMARY KEY,\n is_locked BOOLEAN DEFAULT false,\n locked_at TIMESTAMPTZ,\n is_blocked BOOLEAN DEFAULT false,\n blocked_at TIMESTAMPTZ,\n block_reason TEXT,\n is_public BOOLEAN DEFAULT true,\n lang VARCHAR(10),\n created_at TIMESTAMPTZ DEFAULT NOW(),\n updated_at TIMESTAMPTZ DEFAULT NOW(),\n deleted_at TIMESTAMPTZ\n )\n `;\n}\n```\n\n### 7. Create a repository for the entity\n\nAfter creating the entity, generate a repository to handle database operations for it.\n\nRun the generator:\n\n```bash\nbunx @ooneex/cli@latest make:repository --name <name>\n```\n\nWhere `<name>` is the same name used for the entity. The command will generate:\n- `src/repositories/<Name>Repository.ts` - The repository class\n- `tests/repositories/<Name>Repository.spec.ts` - The test file\n\nThen read the generated files and complete the repository implementation:\n\n- Adjust search fields in the `find()` method to match the entity's searchable columns\n- Customize relations loading in `findOne`/`findOneBy` if the entity has relations\n- Add any domain-specific methods relevant to the entity\n- Remove methods that don't apply to the entity\n- Update tests to match the final repository methods\n\n### 8. Lint and format\n\nRun linting and formatting on all generated files:\n\n```bash\nbunx biome check --fix src/entities/<Name>Entity.ts tests/entities/<Name>Entity.spec.ts src/repositories/<Name>Repository.ts tests/repositories/<Name>Repository.spec.ts src/migrations/\n```\n";var Vr="---\nname: make:logger\ndescription: Generate a new logger class with its test file, then complete the generated code. Use when creating a new logger that implements the ILogger interface from @ooneex/logger.\n---\n\n# Make Logger Class\n\nGenerate a new logger class and its test file using the `make:logger` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the logger class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:logger --name <name> --module <module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/loggers/<Name>Logger.ts` - The logger class file (or `modules/<module>/src/loggers/<Name>Logger.ts` with `--module`)\n- `tests/loggers/<Name>Logger.spec.ts` - The test file (or `modules/<module>/tests/loggers/<Name>Logger.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the logger class\n\nEdit `src/loggers/<Name>Logger.ts` to complete the implementation:\n\n- Implement the `init()` method to set up the logger (e.g., open file handles, configure transports)\n- Implement `log`, `debug`, `info`, `success`, `warn`, and `error` methods with actual logging logic\n- Inject any required dependencies via the constructor\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport type { IException } from \"@ooneex/exception\";\nimport type { ILogger } from \"@ooneex/logger\";\nimport type { ScalarType } from \"@ooneex/types\";\nimport { decorator } from \"@ooneex/logger\";\n\n@decorator.logger()\nexport class <Name>Logger implements ILogger {\n public async init(): Promise<void> {\n // Initialize your logger here\n }\n\n public log(message: string, data?: Record<string, ScalarType>): void {\n // Handle general logging\n }\n\n public debug(message: string, data?: Record<string, ScalarType>): void {\n // Handle debug logging\n }\n\n public info(message: string, data?: Record<string, ScalarType>): void {\n // Handle info logging\n }\n\n public success(message: string, data?: Record<string, ScalarType>): void {\n // Handle success logging\n }\n\n public warn(message: string, data?: Record<string, ScalarType>): void {\n // Handle warning logging\n }\n\n public error(message: string | IException, data?: Record<string, ScalarType>): void {\n // Handle error logging\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/loggers/<Name>Logger.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep the existing scaffolded tests (class name, init, log, debug, info, success, warn, error methods)\n- Add tests relevant to the specific logger class behavior\n\nThe generated test structure follows this pattern:\n\n```typescript\nimport { describe, expect, test } from \"bun:test\";\nimport { <Name>Logger } from \"@/loggers/<Name>Logger\";\n\ndescribe(\"<Name>Logger\", () => {\n test(\"should have class name ending with 'Logger'\", () => {\n expect(<Name>Logger.name.endsWith(\"Logger\")).toBe(true);\n });\n\n test(\"should have 'init' method\", () => {\n expect(<Name>Logger.prototype.init).toBeDefined();\n expect(typeof <Name>Logger.prototype.init).toBe(\"function\");\n });\n\n test(\"should have 'log' method\", () => {\n expect(<Name>Logger.prototype.log).toBeDefined();\n expect(typeof <Name>Logger.prototype.log).toBe(\"function\");\n });\n\n test(\"should have 'debug' method\", () => {\n expect(<Name>Logger.prototype.debug).toBeDefined();\n expect(typeof <Name>Logger.prototype.debug).toBe(\"function\");\n });\n\n test(\"should have 'info' method\", () => {\n expect(<Name>Logger.prototype.info).toBeDefined();\n expect(typeof <Name>Logger.prototype.info).toBe(\"function\");\n });\n\n test(\"should have 'success' method\", () => {\n expect(<Name>Logger.prototype.success).toBeDefined();\n expect(typeof <Name>Logger.prototype.success).toBe(\"function\");\n });\n\n test(\"should have 'warn' method\", () => {\n expect(<Name>Logger.prototype.warn).toBeDefined();\n expect(typeof <Name>Logger.prototype.warn).toBe(\"function\");\n });\n\n test(\"should have 'error' method\", () => {\n expect(<Name>Logger.prototype.error).toBeDefined();\n expect(typeof <Name>Logger.prototype.error).toBe(\"function\");\n });\n});\n```\n\n### 5. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/loggers/<Name>Logger.ts tests/loggers/<Name>Logger.spec.ts\n```\n";var zr="---\nname: make:mailer\ndescription: Generate a new mailer class with its template and test files, then complete the generated code. Use when creating a new email sender with JSX template using @ooneex/mailer.\n---\n\n# Make Mailer Class\n\nGenerate a new mailer class, its JSX template, and test files using the `make:mailer` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the mailer class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:mailer --name <name> --module <module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate (paths prefixed with `modules/<module>/` when `--module` is provided):\n- `src/mailers/<Name>Mailer.ts` - The mailer class file\n- `src/mailers/<Name>MailerTemplate.tsx` - The JSX email template\n- `tests/mailers/<Name>Mailer.spec.ts` - The mailer test file\n- `tests/mailers/<Name>MailerTemplate.spec.ts` - The template test file\n\n### 2. Read the generated files\n\nRead all four generated files to understand the scaffolded code.\n\n### 3. Complete the mailer class\n\nEdit `src/mailers/<Name>Mailer.ts` to complete the implementation:\n\n- Adjust the `send` method config type if additional parameters are needed\n- Add any pre-send logic (validation, data transformation, etc.)\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { inject } from \"@ooneex/container\";\nimport type { IMailer } from \"@ooneex/mailer\";\nimport { type <Name>MailerPropsType, <Name>MailerTemplate } from \"./<Name>MailerTemplate\";\n\nexport class <Name>Mailer implements IMailer {\n constructor(\n @inject(\"mailer\")\n private readonly mailer: IMailer,\n ) {}\n\n public send = async (config: {\n to: string[];\n subject: string;\n from?: { name: string; address: string };\n data?: <Name>MailerPropsType;\n }): Promise<void> => {\n const { data, ...rest } = config;\n\n await this.mailer.send({\n ...rest,\n content: <Name>MailerTemplate(data),\n });\n };\n}\n```\n\n### 4. Complete the mailer template\n\nEdit `src/mailers/<Name>MailerTemplate.tsx` to complete the implementation:\n\n- Update `<Name>MailerPropsType` with the actual props needed for the email\n- Build the email body using `MailerLayout` components (Header, Body, Footer)\n- Add email content, styling, and dynamic data rendering\n\nThe generated template structure follows this pattern:\n\n```tsx\nimport { MailerLayout } from \"@ooneex/mailer\";\n\nexport type <Name>MailerPropsType = {\n link: string;\n};\n\nexport const <Name>MailerTemplate = (props?: <Name>MailerPropsType) => (\n <MailerLayout>\n <MailerLayout.Header />\n <MailerLayout.Body>\n <a href={props?.link}>Login</a>\n </MailerLayout.Body>\n <MailerLayout.Footer />\n </MailerLayout>\n);\n```\n\n### 5. Complete the test files\n\nEdit `tests/mailers/<Name>Mailer.spec.ts` and `tests/mailers/<Name>MailerTemplate.spec.ts` to add meaningful tests beyond the scaffolded ones.\n\n### 6. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/mailers/<Name>Mailer.ts src/mailers/<Name>MailerTemplate.tsx tests/mailers/<Name>Mailer.spec.ts tests/mailers/<Name>MailerTemplate.spec.ts\n```\n";var Yr="---\nname: make:middleware\ndescription: Generate a new middleware class with its test file, then complete the generated code. Use when creating a new HTTP or WebSocket middleware that implements IMiddleware from @ooneex/middleware.\n---\n\n# Make Middleware Class\n\nGenerate a new middleware class and its test file using the `make:middleware` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the middleware class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:middleware --name <name> --module <module> --is-socket <true|false>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The `--is-socket` option determines whether to generate an HTTP middleware or a WebSocket middleware (defaults to `false` if omitted). The command will generate:\n- `src/middlewares/<Name>Middleware.ts` - The middleware class file (or `modules/<module>/src/middlewares/<Name>Middleware.ts` with `--module`)\n- `tests/middlewares/<Name>Middleware.spec.ts` - The test file (or `modules/<module>/tests/middlewares/<Name>Middleware.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the middleware class\n\nEdit `src/middlewares/<Name>Middleware.ts` to complete the implementation:\n\n- Implement the `handler` method with actual middleware logic\n- Add request/response transformations, authentication checks, logging, etc.\n- Inject any required dependencies via the constructor\n\n**HTTP middleware** generated structure:\n\n```typescript\nimport type { ContextType } from \"@ooneex/controller\";\nimport { decorator, type IMiddleware } from \"@ooneex/middleware\";\n\n@decorator.middleware()\nexport class <Name>Middleware implements IMiddleware {\n public async handler(context: ContextType): Promise<ContextType> {\n // Example: Add custom header\n // context.response.header(\"X-Custom-Header\", \"value\");\n\n return context\n }\n}\n```\n\n**Socket middleware** generated structure:\n\n```typescript\nimport type { ContextType } from \"@ooneex/socket\";\nimport { decorator, type IMiddleware } from \"@ooneex/middleware\";\n\n@decorator.middleware()\nexport class <Name>Middleware implements IMiddleware {\n public async handler(context: ContextType): Promise<ContextType> {\n // Example: Add custom header\n // context.response.header(\"X-Custom-Header\", \"value\");\n\n return context\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/middlewares/<Name>Middleware.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep the existing scaffolded tests (class name, handler method)\n- Add tests relevant to the specific middleware behavior\n\nThe generated test structure follows this pattern:\n\n```typescript\nimport { describe, expect, test } from \"bun:test\";\nimport { <Name>Middleware } from \"@/middlewares/<Name>Middleware\";\n\ndescribe(\"<Name>Middleware\", () => {\n test(\"should have class name ending with 'Middleware'\", () => {\n expect(<Name>Middleware.name.endsWith(\"Middleware\")).toBe(true);\n });\n\n test(\"should have 'handler' method\", () => {\n expect(<Name>Middleware.prototype.handler).toBeDefined();\n expect(typeof <Name>Middleware.prototype.handler).toBe(\"function\");\n });\n});\n```\n\n### 5. Register the middleware in the module\n\nAdd the new middleware to the module's `middlewares` array in `src/<PascalModuleName>Module.ts` (e.g., `src/BookModule.ts` for the `book` module):\n\n```typescript\nimport type { ModuleType } from \"@ooneex/module\";\nimport { <Name>Middleware } from \"./middlewares/<Name>Middleware\";\n\nexport const <PascalModuleName>Module: ModuleType = {\n controllers: [],\n entities: [],\n permissions: [],\n middlewares: [<Name>Middleware],\n cronJobs: [],\n events: [],\n};\n```\n\nThe module file uses PascalCase naming: `<PascalModuleName>Module.ts` with export `<PascalModuleName>Module`.\n\nIf the module already has other middlewares registered, append the new middleware to the existing `middlewares` array and add the import alongside existing imports.\n\n### 6. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/middlewares/<Name>Middleware.ts tests/middlewares/<Name>Middleware.spec.ts\n```\n";var Qr="---\nname: make:migration\ndescription: Generate a new database migration file, then complete the generated code. Use when creating a new database migration for schema changes using @ooneex/migrations.\n---\n\n# Make Migration\n\nGenerate a new migration file using the `make:migration` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the migration file:\n\n```bash\nbunx @ooneex/cli@latest make:migration --module <module>\n```\n\nThe `--module` option is optional \u2014 if provided, the migration file is generated under `modules/<module>/src/migrations/` instead of `src/migrations/`. The command will:\n- Generate a timestamped migration file in `src/migrations/` (or `modules/<module>/src/migrations/` with `--module`)\n- Add a `migration:up` script to `package.json` if not already present\n\n### 2. Read the generated file\n\nRead the generated migration file in `src/migrations/` to understand the scaffolded code.\n\n### 3. Complete the migration\n\nEdit the generated migration file to implement:\n\n- The `up` method with the schema changes (create tables, add columns, create indexes, etc.)\n- The `down` method with the reverse operations to undo the migration\n\n### 4. Lint and format\n\nRun linting and formatting on the generated file:\n\n```bash\nbunx biome check --fix src/migrations/\n```\n";var Zr="---\nname: make:permission\ndescription: Generate a new permission class with its test file, then complete the generated code. Use when creating a new permission that extends Permission from @ooneex/permission.\n---\n\n# Make Permission Class\n\nGenerate a new permission class and its test file using the `make:permission` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the permission class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:permission --name <name> --module <module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/permissions/<Name>Permission.ts` - The permission class file (or `modules/<module>/src/permissions/<Name>Permission.ts` with `--module`)\n- `tests/permissions/<Name>Permission.spec.ts` - The test file (or `modules/<module>/tests/permissions/<Name>Permission.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the permission class\n\nEdit `src/permissions/<Name>Permission.ts` to complete the implementation:\n\n- Implement the `allow()` method with permission rules using `this.ability.can()`\n- Implement the `setUserPermissions()` method with role-based permission logic\n- Define which actions (read, create, update, delete, manage) are allowed on which entities\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { decorator, Permission } from \"@ooneex/permission\";\nimport type { IUser } from \"@ooneex/user\";\n\n@decorator.permission()\nexport class <Name>Permission extends Permission {\n public allow(): this {\n // Example: Add permissions using this.ability.can()\n // this.ability.can(\"read\", \"YourEntity\");\n // this.ability.can([\"read\", \"update\"], \"YourEntity\", { userId: user.id });\n\n return this;\n }\n\n public setUserPermissions(user: IUser | null): this {\n if (!user) {\n return this;\n }\n\n // Example: Grant full access to admins\n // const { roles } = user;\n // if (roles.includes(ERole.ADMIN)) {\n // this.ability.can(\"manage\", \"all\");\n // return this;\n // }\n\n // Example: Grant specific permissions based on roles\n // for (const role of roles) {\n // if (role === ERole.USER) {\n // this.ability.can([\"read\", \"update\"], \"YourEntity\", { userId: user.id });\n // }\n //\n // if (role === ERole.GUEST) {\n // this.ability.can(\"read\", \"YourEntity\", { public: true });\n // }\n // }\n\n return this;\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/permissions/<Name>Permission.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep the existing scaffolded tests (class name, extends Permission, allow, setUserPermissions methods)\n- Add tests relevant to the specific permission rules\n\nThe generated test structure follows this pattern:\n\n```typescript\nimport { describe, expect, test } from \"bun:test\";\nimport { Permission } from \"@ooneex/permission\";\nimport { <Name>Permission } from \"@/permissions/<Name>Permission\";\n\ndescribe(\"<Name>Permission\", () => {\n test(\"should have class name ending with 'Permission'\", () => {\n expect(<Name>Permission.name.endsWith(\"Permission\")).toBe(true);\n });\n\n test(\"should extend Permission\", () => {\n const permission = new <Name>Permission();\n expect(permission).toBeInstanceOf(Permission);\n });\n\n test(\"should have 'allow' method\", () => {\n expect(<Name>Permission.prototype.allow).toBeDefined();\n expect(typeof <Name>Permission.prototype.allow).toBe(\"function\");\n });\n\n test(\"should have 'setUserPermissions' method\", () => {\n expect(<Name>Permission.prototype.setUserPermissions).toBeDefined();\n expect(typeof <Name>Permission.prototype.setUserPermissions).toBe(\"function\");\n });\n});\n```\n\n### 5. Register the permission in the module\n\nAdd the new permission to the module's `permissions` array in `src/<PascalModuleName>Module.ts` (e.g., `src/BookModule.ts` for the `book` module):\n\n```typescript\nimport type { ModuleType } from \"@ooneex/module\";\nimport { <Name>Permission } from \"./permissions/<Name>Permission\";\n\nexport const <PascalModuleName>Module: ModuleType = {\n controllers: [],\n entities: [],\n permissions: [<Name>Permission],\n middlewares: [],\n cronJobs: [],\n events: [],\n};\n```\n\nThe module file uses PascalCase naming: `<PascalModuleName>Module.ts` with export `<PascalModuleName>Module`.\n\nIf the module already has other permissions registered, append the new permission to the existing `permissions` array and add the import alongside existing imports.\n\n### 6. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/permissions/<Name>Permission.ts tests/permissions/<Name>Permission.spec.ts\n```\n";var Xr="---\nname: make:pubsub\ndescription: Generate a new PubSub event class with its test file, then complete the generated code. Use when creating a new publish/subscribe event that extends PubSub from @ooneex/pub-sub.\n---\n\n# Make PubSub Event Class\n\nGenerate a new PubSub event class and its test file using the `make:pubsub` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the PubSub event class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:pubsub --name <name> --module <module> --channel <channel>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The `--channel` option is optional \u2014 if omitted, it defaults to the kebab-case form of the name (e.g., `UserCreated` becomes `user-created`). The command will generate:\n- `src/events/<Name>Event.ts` - The event class file (or `modules/<module>/src/events/<Name>Event.ts` with `--module`)\n- `tests/events/<Name>Event.spec.ts` - The test file (or `modules/<module>/tests/events/<Name>Event.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the PubSub event class\n\nEdit `src/events/<Name>Event.ts` to complete the implementation:\n\n- Define a proper data type instead of `Record<string, ScalarType>` for the event payload\n- Implement the `handler()` method with actual event handling logic\n- Set the appropriate channel name in `getChannel()`\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { inject } from \"@ooneex/container\";\nimport type { ScalarType } from \"@ooneex/types\";\nimport { decorator, PubSub, RedisPubSub } from \"@ooneex/pub-sub\";\n\n@decorator.pubSub()\nexport class <Name>Event<Data extends Record<string, ScalarType> = Record<string, ScalarType>> extends PubSub<Data> {\n constructor(\n @inject(RedisPubSub)\n client: RedisPubSub<Data>,\n ) {\n super(client);\n }\n\n public getChannel(): string {\n return \"<channel>\";\n }\n\n public async handler(context: { data: Data; channel: string }): Promise<void> {\n console.log(context);\n // TODO: Implement handler logic here\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/events/<Name>Event.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep the existing scaffolded tests (class name, getChannel, handler, publish, subscribe, unsubscribe, unsubscribeAll methods)\n- Add tests relevant to the specific event behavior\n\nThe generated test structure follows this pattern:\n\n```typescript\nimport { describe, expect, test } from \"bun:test\";\nimport { <Name>PubSub } from \"@/pubsub/<Name>PubSub\";\n\ndescribe(\"<Name>PubSub\", () => {\n test(\"should have class name ending with 'PubSub'\", () => {\n expect(<Name>PubSub.name.endsWith(\"PubSub\")).toBe(true);\n });\n\n test(\"should have 'getChannel' method\", () => {\n expect(<Name>PubSub.prototype.getChannel).toBeDefined();\n expect(typeof <Name>PubSub.prototype.getChannel).toBe(\"function\");\n });\n\n test(\"should have 'handler' method\", () => {\n expect(<Name>PubSub.prototype.handler).toBeDefined();\n expect(typeof <Name>PubSub.prototype.handler).toBe(\"function\");\n });\n\n test(\"should have 'publish' method\", () => {\n expect(<Name>PubSub.prototype.publish).toBeDefined();\n expect(typeof <Name>PubSub.prototype.publish).toBe(\"function\");\n });\n\n test(\"should have 'subscribe' method\", () => {\n expect(<Name>PubSub.prototype.subscribe).toBeDefined();\n expect(typeof <Name>PubSub.prototype.subscribe).toBe(\"function\");\n });\n\n test(\"should have 'unsubscribe' method\", () => {\n expect(<Name>PubSub.prototype.unsubscribe).toBeDefined();\n expect(typeof <Name>PubSub.prototype.unsubscribe).toBe(\"function\");\n });\n\n test(\"should have 'unsubscribeAll' method\", () => {\n expect(<Name>PubSub.prototype.unsubscribeAll).toBeDefined();\n expect(typeof <Name>PubSub.prototype.unsubscribeAll).toBe(\"function\");\n });\n});\n```\n\n### 5. Register the event in the module\n\nAdd the new event to the module's `events` array in `src/<PascalModuleName>Module.ts` (e.g., `src/BookModule.ts` for the `book` module):\n\n```typescript\nimport type { ModuleType } from \"@ooneex/module\";\nimport { <Name>Event } from \"./events/<Name>Event\";\n\nexport const <PascalModuleName>Module: ModuleType = {\n controllers: [],\n entities: [],\n permissions: [],\n middlewares: [],\n cronJobs: [],\n events: [<Name>Event],\n};\n```\n\nThe module file uses PascalCase naming: `<PascalModuleName>Module.ts` with export `<PascalModuleName>Module`.\n\nIf the module already has other events registered, append the new event to the existing `events` array and add the import alongside existing imports.\n\n### 6. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/events/<Name>Event.ts tests/events/<Name>Event.spec.ts\n```\n";var Jr="---\nname: make:repository\ndescription: Generate a new repository class with its test file, then complete the generated code. Use when creating a new TypeORM repository for database operations on an entity.\n---\n\n# Make Repository Class\n\nGenerate a new repository class and its test file using the `make:repository` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the repository class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:repository --name <name> --module <module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/repositories/<Name>Repository.ts` - The repository class file (or `modules/<module>/src/repositories/<Name>Repository.ts` with `--module`)\n- `tests/repositories/<Name>Repository.spec.ts` - The test file (or `modules/<module>/tests/repositories/<Name>Repository.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the repository class\n\nEdit `src/repositories/<Name>Repository.ts` to complete the implementation:\n\n- Verify the entity import path matches the actual entity location\n- Adjust the `find` method's search fields (default searches `name` with `ILike`)\n- Customize relations loading in `findOne`/`findOneBy` if needed\n\n#### Adding methods\n\nLook at the entity's fields, relations, and business context to determine if custom domain-specific methods are needed. For example:\n- A `SessionRepository` might need `revokeSession(sessionId: string)` and `revokeAllUserSessions(userId: string)`\n- A `NotificationRepository` might need `markAsRead(id: string)` and `markAllAsRead(userId: string)`\n- Entities with status fields may need methods like `archive(id: string)` or `activate(id: string)`\n\nRead related entities, services, or actions in the module to understand what operations the repository should support, then add the appropriate methods.\n\n#### Removing methods\n\nRemove scaffolded methods that don't make sense for the entity's context:\n- Remove `createMany`/`updateMany` if the entity is always managed individually (e.g., user profiles, settings)\n- Remove `delete` if the entity uses soft deletes only (use a custom `softDelete` or `archive` method instead)\n- Remove `find` if the entity is only ever accessed by ID or specific criteria (e.g., singleton config entities)\n- Remove `count` if there's no use case for counting records of this entity\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { inject } from \"@ooneex/container\";\nimport type { ITypeormDatabase } from \"@ooneex/database\";\nimport { decorator } from \"@ooneex/repository\";\nimport type { FilterResultType } from \"@ooneex/types\";\nimport type { FindManyOptions, FindOptionsWhere, Repository, SaveOptions, UpdateResult } from \"typeorm\";\nimport { ILike } from \"typeorm\";\nimport { <Name>Entity } from \"../entities/<Name>Entity\";\n\n@decorator.repository()\nexport class <Name>Repository {\n constructor(\n @inject(\"database\")\n private readonly database: ITypeormDatabase,\n ) {}\n\n public async open(): Promise<Repository<<Name>Entity>> {\n return await this.database.open(<Name>Entity);\n }\n\n public async close(): Promise<void> {\n await this.database.close();\n }\n\n public async find(\n criteria: FindManyOptions<<Name>Entity> & { page?: number; limit?: number; q?: string },\n ): Promise<FilterResultType<<Name>Entity>> {\n // ... pagination and search logic\n }\n\n public async findOne(id: string): Promise<<Name>Entity | null> { ... }\n public async findOneBy(criteria: FindOptionsWhere<<Name>Entity>): Promise<<Name>Entity | null> { ... }\n public async create(entity: <Name>Entity, options?: SaveOptions): Promise<<Name>Entity> { ... }\n public async createMany(entities: <Name>Entity[], options?: SaveOptions): Promise<<Name>Entity[]> { ... }\n public async update(entity: <Name>Entity, options?: SaveOptions): Promise<<Name>Entity> { ... }\n public async updateMany(entities: <Name>Entity[], options?: SaveOptions): Promise<<Name>Entity[]> { ... }\n public async delete(criteria: FindOptionsWhere<<Name>Entity> | FindOptionsWhere<<Name>Entity>[]): Promise<UpdateResult> { ... }\n public async count(criteria?: FindOptionsWhere<<Name>Entity> | FindOptionsWhere<<Name>Entity>[]): Promise<number> { ... }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/repositories/<Name>Repository.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep scaffolded tests for methods that remain in the repository (remove tests for methods that were removed)\n- Add tests for any custom domain-specific methods added to the repository\n- Add tests relevant to the specific repository behavior\n\n### 5. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/repositories/<Name>Repository.ts tests/repositories/<Name>Repository.spec.ts\n```\n";var jr="---\nname: make:seed\ndescription: Generate a new database seed file, then complete the generated code. Use when creating seed data for populating the database using @ooneex/seeds.\n---\n\n# Make Seed\n\nGenerate a new seed file using the `make:seed` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the seed file:\n\n```bash\nbunx @ooneex/cli@latest make:seed --name <name> --module <module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, the seed file is generated under `modules/<module>/src/seeds/` instead of `src/seeds/`. The command will:\n- Generate a seed file in `src/seeds/` (or `modules/<module>/src/seeds/` with `--module`)\n- Add a `seed:run` script to `package.json` if not already present\n\n### 2. Read the generated file\n\nRead the generated seed file in `src/seeds/` to understand the scaffolded code.\n\n### 3. Complete the seed\n\nEdit the generated seed file to implement:\n\n- Import the relevant entity classes\n- Create seed data with hardcoded nanoid values for `id` fields (generate via `bun -e \"import { random } from '@ooneex/utils'; console.log(random.nanoid())\"`)\n- Do NOT use sequential IDs like `\"item-1\"`, `\"item-2\"`\n- Ensure the same entity uses the same ID everywhere it appears\n\n### 4. Lint and format\n\nRun linting and formatting on the generated file:\n\n```bash\nbunx biome check --fix src/seeds/\n```\n";var ei="---\nname: make:service\ndescription: Generate a new service class with its test file, then complete the generated code. Use when creating a new business logic service that implements IService from @ooneex/service.\n---\n\n# Make Service Class\n\nGenerate a new service class and its test file using the `make:service` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the service class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:service --name <name> --module <module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/services/<Name>Service.ts` - The service class file (or `modules/<module>/src/services/<Name>Service.ts` with `--module`)\n- `tests/services/<Name>Service.spec.ts` - The test file (or `modules/<module>/tests/services/<Name>Service.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the service class\n\nEdit `src/services/<Name>Service.ts` to complete the implementation:\n\n- Define a proper type for `ServiceDataType` instead of `Record<string, unknown>`\n- Implement the `execute()` method with actual business logic\n- Inject any required dependencies (repositories, other services, etc.) via the constructor\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { decorator } from \"@ooneex/service\";\nimport type { IService } from \"@ooneex/service\";\n\ntype ServiceDataType = Record<string, unknown>;\n\n@decorator.service()\nexport class <Name>Service<T extends ServiceDataType = ServiceDataType> implements IService<T> {\n public async execute(data?: T): Promise<void> {\n // TODO: Implement service logic\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/services/<Name>Service.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep the existing scaffolded tests (class name, execute method)\n- Add tests relevant to the specific service behavior\n\nThe generated test structure follows this pattern:\n\n```typescript\nimport { describe, expect, test } from \"bun:test\";\nimport { <Name>Service } from \"@/services/<Name>Service\";\n\ndescribe(\"<Name>Service\", () => {\n test(\"should have class name ending with 'Service'\", () => {\n expect(<Name>Service.name.endsWith(\"Service\")).toBe(true);\n });\n\n test(\"should have 'execute' method\", () => {\n expect(<Name>Service.prototype.execute).toBeDefined();\n expect(typeof <Name>Service.prototype.execute).toBe(\"function\");\n });\n});\n```\n\n### 5. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/services/<Name>Service.ts tests/services/<Name>Service.spec.ts\n```\n";var ti="---\nname: make:storage\ndescription: Generate a new storage class with its test file, then complete the generated code. Use when creating a new S3-compatible storage adapter that extends Storage from @ooneex/storage.\n---\n\n# Make Storage Class\n\nGenerate a new storage class and its test file using the `make:storage` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the storage class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:storage --name <name> --module <module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/storage/<Name>Storage.ts` - The storage class file (or `modules/<module>/src/storage/<Name>Storage.ts` with `--module`)\n- `tests/storage/<Name>Storage.spec.ts` - The test file (or `modules/<module>/tests/storage/<Name>Storage.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the storage class\n\nEdit `src/storage/<Name>Storage.ts` to complete the implementation:\n\n- Set the `bucket` property to the appropriate bucket name\n- Verify the environment variable names match the project configuration (`STORAGE_<NAME_UPPER>_ACCESS_KEY`, `STORAGE_<NAME_UPPER>_SECRET_KEY`, `STORAGE_<NAME_UPPER>_ENDPOINT`, `STORAGE_<NAME_UPPER>_REGION`)\n- Add any additional storage-specific methods if needed\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { Storage, decorator, StorageException } from \"@ooneex/storage\";\nimport type { S3Options } from \"bun\";\n\n@decorator.storage()\nexport class <Name>Storage extends Storage {\n protected bucket: string;\n private readonly accessKey: string;\n private readonly secretKey: string;\n private readonly endpoint: string;\n private readonly region: string;\n\n constructor(options?: {\n accessKey?: string;\n secretKey?: string;\n endpoint?: string;\n region?: string;\n }) {\n super();\n\n const accessKey = options?.accessKey || Bun.env.STORAGE_<NAME_UPPER>_ACCESS_KEY;\n const secretKey = options?.secretKey || Bun.env.STORAGE_<NAME_UPPER>_SECRET_KEY;\n const endpoint = options?.endpoint || Bun.env.STORAGE_<NAME_UPPER>_ENDPOINT;\n\n // ... validation throws StorageException if missing ...\n\n this.accessKey = accessKey;\n this.secretKey = secretKey;\n this.endpoint = endpoint;\n this.region = options?.region || Bun.env.STORAGE_<NAME_UPPER>_REGION || \"auto\";\n }\n\n public getOptions(): S3Options {\n return {\n accessKeyId: this.accessKey,\n secretAccessKey: this.secretKey,\n endpoint: this.endpoint,\n bucket: this.bucket,\n region: this.region,\n };\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/storage/<Name>Storage.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep the existing scaffolded tests (class name, bucket field, getOptions method)\n- Add tests relevant to the specific storage class behavior\n\nThe generated test structure follows this pattern:\n\n```typescript\nimport { describe, expect, test } from \"bun:test\";\nimport { <Name>StorageAdapter } from \"@/storage/<Name>StorageAdapter\";\n\ndescribe(\"<Name>StorageAdapter\", () => {\n test(\"should have class name ending with 'StorageAdapter'\", () => {\n expect(<Name>StorageAdapter.name.endsWith(\"StorageAdapter\")).toBe(true);\n });\n\n test(\"should have 'bucket' field\", () => {\n expect(\"bucket\" in <Name>StorageAdapter.prototype || \"bucket\" in Object.getOwnPropertyNames(<Name>StorageAdapter.prototype)).toBe(true);\n });\n\n test(\"should have 'getOptions' method\", () => {\n expect(<Name>StorageAdapter.prototype.getOptions).toBeDefined();\n expect(typeof <Name>StorageAdapter.prototype.getOptions).toBe(\"function\");\n });\n});\n```\n\n### 5. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/storage/<Name>Storage.ts tests/storage/<Name>Storage.spec.ts\n```\n";var si="---\nname: make:vector-database\ndescription: Generate a new vector database class with its test file, then complete the generated code. Use when creating a new vector database that extends VectorDatabase from @ooneex/rag.\n---\n\n# Make Vector Database Class\n\nGenerate a new vector database class and its test file using the `make:vector-database` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the vector database class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:vector-database --name <name> --module <module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/databases/<Name>VectorDatabase.ts` - The vector database class file (or `modules/<module>/src/databases/<Name>VectorDatabase.ts` with `--module`)\n- `tests/databases/<Name>VectorDatabase.spec.ts` - The test file (or `modules/<module>/tests/databases/<Name>VectorDatabase.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the vector database class\n\nEdit `src/databases/<Name>VectorDatabase.ts` to complete the implementation:\n\n- Set the `getDatabaseUri()` return value to the actual LanceDB database path\n- Configure the embedding provider and model in `getEmbeddingModel()`\n- Define the custom data fields in `DataType` and map them in `getSchema()`\n- Import the appropriate Apache Arrow types for your schema fields\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { VectorDatabase, decorator } from \"@ooneex/rag\";\nimport type { EmbeddingModelType, EmbeddingProviderType, FieldValueType } from \"@ooneex/rag\";\nimport { Utf8 } from \"apache-arrow\";\n\ntype DataType = {\n name: string;\n};\n\n@decorator.vectorDatabase()\nexport class <Name>VectorDatabase extends VectorDatabase<DataType> {\n public getDatabaseUri(): string {\n return \"\";\n }\n\n public getEmbeddingModel(): { provider: EmbeddingProviderType; model: EmbeddingModelType[\"model\"] } {\n return { provider: \"openai\", model: \"text-embedding-ada-002\" };\n }\n\n public getSchema(): { [K in keyof DataType]: FieldValueType } {\n return {\n name: new Utf8(),\n };\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/databases/<Name>VectorDatabase.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep the existing scaffolded tests (class name, getDatabaseUri, getEmbeddingModel, getSchema methods)\n- Add tests relevant to the specific vector database class behavior\n\nThe generated test structure follows this pattern:\n\n```typescript\nimport { describe, expect, test } from \"bun:test\";\nimport { <Name>VectorDatabase } from \"@/databases/<Name>VectorDatabase\";\n\ndescribe(\"<Name>VectorDatabase\", () => {\n test(\"should have class name ending with 'VectorDatabase'\", () => {\n expect(<Name>VectorDatabase.name.endsWith(\"VectorDatabase\")).toBe(true);\n });\n\n test(\"should have 'getDatabaseUri' method\", () => {\n expect(<Name>VectorDatabase.prototype.getDatabaseUri).toBeDefined();\n expect(typeof <Name>VectorDatabase.prototype.getDatabaseUri).toBe(\"function\");\n });\n\n test(\"should have 'getEmbeddingModel' method\", () => {\n expect(<Name>VectorDatabase.prototype.getEmbeddingModel).toBeDefined();\n expect(typeof <Name>VectorDatabase.prototype.getEmbeddingModel).toBe(\"function\");\n });\n\n test(\"should have 'getSchema' method\", () => {\n expect(<Name>VectorDatabase.prototype.getSchema).toBeDefined();\n expect(typeof <Name>VectorDatabase.prototype.getSchema).toBe(\"function\");\n });\n});\n```\n\n### 5. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/databases/<Name>VectorDatabase.ts tests/databases/<Name>VectorDatabase.spec.ts\n```\n";var oi="---\nname: optimize\ndescription: Optimize a module's codebase for quality, performance, and clean conventions. Enforces arrow functions (except class methods), type/interface naming, removes duplication, and ensures only important tests remain.\n---\n\n# Optimize Codebase\n\nOptimize a module's codebase for quality, performance, and clean conventions.\n\n## Coding Conventions\n\nApply these conventions across all files in the target module:\n\n- **Arrow functions everywhere** \u2014 use arrow functions for all function expressions, callbacks, standalone functions, and variable declarations. The ONLY exception is class methods, which must use regular method syntax.\n- **Type naming** \u2014 all type aliases must end with the `Type` suffix (e.g., `UserDataType`, `ConfigOptionsType`). Rename any that don't comply.\n- **Interface naming** \u2014 all interface names must start with the `I` prefix (e.g., `IUser`, `IService`, `IRepository`). Rename any that don't comply.\n- **No definite assignment assertions** \u2014 never use `!` on class properties (e.g., `email!: string`). Use a default value or make the property optional (`?`) instead.\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`).\n- For Entity class, if property is optional, add `null` to its type.\n\n## Steps\n\n### 1. Identify the target\n\nDetermine the module to optimize. If the user specifies a module name, work in `modules/<module>/`. If no module is specified, ask the user which module to optimize.\n\n### 2. Read and analyze the module\n\nRead all source files (`src/**/*.ts`) and test files (`tests/**/*.ts`) in the target module. Build a full picture of:\n\n- All types, interfaces, classes, and functions\n- Dependencies between files\n- Existing test coverage\n\n### 3. Enforce naming conventions\n\nScan every file and fix:\n\n- **Types not ending with `Type`** \u2014 rename the type and update all references across the module\n- **Interfaces not starting with `I`** \u2014 rename the interface and update all references across the module\n- **Non-arrow functions** \u2014 convert all function expressions, callbacks, and standalone functions to arrow functions. Do NOT convert class methods.\n- **Missing visibility modifiers** \u2014 add explicit `public`, `private`, or `protected` to all class methods and properties\n\n### 4. Remove code duplication\n\nIdentify duplicated or near-duplicated code within the module:\n\n- Extract shared logic into well-named helper arrow functions or base classes\n- Consolidate repeated type definitions\n- Merge similar utility functions\n- Remove dead code (unused imports, unreachable branches, unused variables)\n\n### 5. Optimize for performance\n\nReview and improve:\n\n- Replace inefficient loops or repeated iterations with single-pass approaches where possible\n- Use `Map`/`Set` instead of arrays for lookups when appropriate\n- Avoid unnecessary object spreads or deep clones\n- Prefer early returns to reduce nesting\n- Remove unnecessary `async`/`await` where a direct return suffices\n- Eliminate redundant null/undefined checks when the type system already guarantees the value\n\n### 6. Optimize tests\n\nReview all test files and restructure:\n\n- **Remove trivial tests** \u2014 delete tests that only check obvious things (e.g., \"class name ends with X\", \"method exists\") unless they serve as smoke tests for generated code\n- **Keep and improve important tests** \u2014 focus on tests that verify actual business logic, edge cases, error handling, and integration behavior\n- **Write fewer but more meaningful tests** \u2014 each test should validate a real scenario or invariant, not just existence checks\n- **Consolidate redundant test cases** \u2014 merge tests that cover the same code path with slightly different inputs into parameterized patterns\n- **Ensure critical paths are covered** \u2014 every public method with logic should have at least one test covering its happy path and one covering its error/edge case\n\n### 7. Final cleanup\n\n- Remove all unused imports\n- Remove empty files or files with no exports\n- Ensure consistent formatting\n\n### 8. Lint and format\n\nRun linting and formatting on all modified files:\n\n```bash\nbunx biome check --fix <list of modified files>\n```\n\n### 9. Run tests\n\nRun the module's tests to verify nothing is broken:\n\n```bash\nbun test <module test directory>\n```\n\nIf any test fails, fix the issue and re-run until all tests pass.\n";var np={"make.ai":Gr,"make.analytics":$r,"make.cache":qr,"make.controller":Wr,"make.cron":Fr,"make.database":Kr,"make.entity":Hr,"make.logger":Vr,"make.mailer":zr,"make.middleware":Yr,"make.migration":Qr,"make.permission":Zr,"make.pubsub":Xr,"make.repository":Jr,"make.seed":jr,"make.service":ei,"make.storage":ti,"make.vector-database":si,commit:Ur,optimize:oi};class Ve{getName(){return"make:claude:skill"}getDescription(){return"Generate Claude skills from templates"}async run(){let e=He(".claude","skills"),t=He(process.cwd(),e),s=new ap;for(let[o,r]of Object.entries(np)){let i=o.replace(/\./g,"-"),a=He(t,i,"SKILL.md");await Bun.write(a,r),s.success(`${He(e,i,"SKILL.md")} created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0})}}}Ve=b([x.command()],Ve);import{basename as pp,join as G}from"path";import{TerminalLogger as cp}from"@ooneex/logger";import{toPascalCase as kt}from"@ooneex/utils";var ri=`import { describe, expect, test } from "bun:test";
|
|
1850
|
+
`;var $o="---\nname: make:ai\ndescription: Generate a new AI class with its test file, then complete the generated code. Use when creating a new AI chat class that uses OpenAI via the @ooneex/ai package.\n---\n\n# Make AI Class\n\nGenerate a new AI class and its test file using the `make:ai` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the AI class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:ai --name <name> --module <module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/ai/<Name>Ai.ts` - The AI class file (or `modules/<module>/src/ai/<Name>Ai.ts` with `--module`)\n- `tests/ai/<Name>Ai.spec.ts` - The test file (or `modules/<module>/tests/ai/<Name>Ai.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the AI class\n\nEdit `src/ai/<Name>Ai.ts` to complete the implementation:\n\n- Update the prompt in the `run` method from `\"My prompt\"` to a meaningful prompt based on the class purpose\n- Update the prompt in the `runStream` method from `\"My prompt\"` to a meaningful prompt based on the class purpose\n- Add any additional configuration or methods relevant to the AI class purpose\n- Ensure proper typing for the `run<T>()` generic return type\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { decorator, type IAiChat, OpenAi, type OpenAiConfigType } from \"@ooneex/ai\";\nimport { inject } from \"@ooneex/container\";\n\n@decorator.ai()\nexport class <Name>Ai implements IAiChat<OpenAiConfigType> {\n constructor(@inject(OpenAi) private readonly ai: OpenAi) {}\n\n public async run<T>(prompt?: string, config?: Omit<OpenAiConfigType, \"prompt\">): Promise<T> {\n return this.ai.run<T>(prompt || \"My prompt\", config);\n }\n\n public async *runStream(\n prompt?: string,\n config?: Omit<OpenAiConfigType, \"prompt\" | \"output\">,\n ): AsyncGenerator<string, void, unknown> {\n yield* this.ai.runStream(prompt || \"My prompt\", config);\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/ai/<Name>Ai.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep the existing scaffolded tests (class name, run method, runStream method)\n- Add tests relevant to the specific AI class behavior\n\nThe generated test structure follows this pattern:\n\n```typescript\nimport { describe, expect, test } from \"bun:test\";\nimport { <Name>Ai } from \"@/ai/<Name>Ai\";\n\ndescribe(\"<Name>Ai\", () => {\n test(\"should have class name ending with 'Ai'\", () => {\n expect(<Name>Ai.name.endsWith(\"Ai\")).toBe(true);\n });\n\n test(\"should have 'run' method\", () => {\n expect(<Name>Ai.prototype.run).toBeDefined();\n expect(typeof <Name>Ai.prototype.run).toBe(\"function\");\n });\n\n test(\"should have 'runStream' method\", () => {\n expect(<Name>Ai.prototype.runStream).toBeDefined();\n expect(typeof <Name>Ai.prototype.runStream).toBe(\"function\");\n });\n});\n```\n\n### 5. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/ai/<Name>Ai.ts tests/ai/<Name>Ai.spec.ts\n```\n";var qo="---\nname: make:analytics\ndescription: Generate a new analytics class with its test file, then complete the generated code. Use when creating a new analytics tracking class that uses the @ooneex/analytics package.\n---\n\n# Make Analytics Class\n\nGenerate a new analytics class and its test file using the `make:analytics` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the analytics class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:analytics --name <name> --module <module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/analytics/<Name>Analytics.ts` - The analytics class file (or `modules/<module>/src/analytics/<Name>Analytics.ts` with `--module`)\n- `tests/analytics/<Name>Analytics.spec.ts` - The test file (or `modules/<module>/tests/analytics/<Name>Analytics.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the analytics class\n\nEdit `src/analytics/<Name>Analytics.ts` to complete the implementation:\n\n- Implement the `capture` method with actual analytics tracking logic\n- Define a proper type for `CaptureOptionsType` instead of `Record<string, unknown>` based on the analytics purpose\n- Add any additional methods or properties relevant to the analytics class purpose\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { decorator } from \"@ooneex/analytics\";\nimport type { IAnalytics } from \"@ooneex/analytics\";\n\ntype CaptureOptionsType = Record<string, unknown>;\n\n@decorator.analytics()\nexport class <Name>Analytics<T extends CaptureOptionsType = CaptureOptionsType> implements IAnalytics<T> {\n public capture(options: T): void {\n // console.log(\"Analytics captured:\", options);\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/analytics/<Name>Analytics.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep the existing scaffolded tests (class name, capture method)\n- Add tests relevant to the specific analytics class behavior\n\nThe generated test structure follows this pattern:\n\n```typescript\nimport { describe, expect, test } from \"bun:test\";\nimport { <Name>Analytics } from \"@/analytics/<Name>Analytics\";\n\ndescribe(\"<Name>Analytics\", () => {\n test(\"should have class name ending with 'Analytics'\", () => {\n expect(<Name>Analytics.name.endsWith(\"Analytics\")).toBe(true);\n });\n\n test(\"should have 'capture' method\", () => {\n expect(<Name>Analytics.prototype.capture).toBeDefined();\n expect(typeof <Name>Analytics.prototype.capture).toBe(\"function\");\n });\n});\n```\n\n### 5. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/analytics/<Name>Analytics.ts tests/analytics/<Name>Analytics.spec.ts\n```\n";var Wo="---\nname: make:cache\ndescription: Generate a new cache adapter class with its test file, then complete the generated code. Use when creating a new cache adapter that implements the ICache interface from @ooneex/cache.\n---\n\n# Make Cache Class\n\nGenerate a new cache class and its test file using the `make:cache` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the cache class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:cache --name <name> --module <module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/cache/<Name>Cache.ts` - The cache class file (or `modules/<module>/src/cache/<Name>Cache.ts` with `--module`)\n- `tests/cache/<Name>Cache.spec.ts` - The test file (or `modules/<module>/tests/cache/<Name>Cache.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the cache class\n\nEdit `src/cache/<Name>Cache.ts` to complete the implementation:\n\n- Implement the `get` method to retrieve cached values by key\n- Implement the `set` method to store values with optional TTL\n- Implement the `delete` method to remove cached entries\n- Implement the `has` method to check key existence\n- Replace the `CacheException` throws with actual cache logic\n- Inject any required dependencies (e.g., Redis client) via the constructor\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { CacheException, decorator } from \"@ooneex/cache\";\nimport type { ICache } from \"@ooneex/cache\";\n\n@decorator.cache()\nexport class <Name>Cache implements ICache {\n public async get<T = unknown>(key: string): Promise<T | undefined> {\n throw new CacheException(`Failed to get key \"${key}\": Not implemented`);\n }\n\n public async set<T = unknown>(key: string, value: T, ttl?: number): Promise<void> {\n throw new CacheException(`Failed to set key \"${key}\": Not implemented`);\n }\n\n public async delete(key: string): Promise<boolean> {\n throw new CacheException(`Failed to delete key \"${key}\": Not implemented`);\n }\n\n public async has(key: string): Promise<boolean> {\n throw new CacheException(`Failed to check if key \"${key}\" exists: Not implemented`);\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/cache/<Name>Cache.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep the existing scaffolded tests (class name, get, set, delete, has methods)\n- Add tests relevant to the specific cache class behavior\n\nThe generated test structure follows this pattern:\n\n```typescript\nimport { describe, expect, test } from \"bun:test\";\nimport { <Name>Cache } from \"@/cache/<Name>Cache\";\n\ndescribe(\"<Name>Cache\", () => {\n test(\"should have class name ending with 'Cache'\", () => {\n expect(<Name>Cache.name.endsWith(\"Cache\")).toBe(true);\n });\n\n test(\"should have 'get' method\", () => {\n expect(<Name>Cache.prototype.get).toBeDefined();\n expect(typeof <Name>Cache.prototype.get).toBe(\"function\");\n });\n\n test(\"should have 'set' method\", () => {\n expect(<Name>Cache.prototype.set).toBeDefined();\n expect(typeof <Name>Cache.prototype.set).toBe(\"function\");\n });\n\n test(\"should have 'delete' method\", () => {\n expect(<Name>Cache.prototype.delete).toBeDefined();\n expect(typeof <Name>Cache.prototype.delete).toBe(\"function\");\n });\n\n test(\"should have 'has' method\", () => {\n expect(<Name>Cache.prototype.has).toBeDefined();\n expect(typeof <Name>Cache.prototype.has).toBe(\"function\");\n });\n});\n```\n\n### 5. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/cache/<Name>Cache.ts tests/cache/<Name>Cache.spec.ts\n```\n";var Fo="---\nname: make:controller\ndescription: Generate a new controller class with route type and test file, then complete the generated code. Use when creating a new HTTP or WebSocket controller with routing, validation, and role-based access.\n---\n\n# Make Controller Class\n\nGenerate a new controller class, its route type, and test file using the `make:controller` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the controller class and related files:\n\n```bash\nbunx @ooneex/cli@latest make:controller --name <name> --module <module> --is-socket <true|false> --route.name <route.name> --route.path <route.path> --route.method <route.method>\n```\n\nWhere:\n- `<name>` is the controller name provided by the user\n- `--module` is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root\n- `--is-socket` determines HTTP vs WebSocket controller (defaults to `false`)\n- `--route.name` is the route name using dot notation: `<resource>.<action>` (e.g., `user.create`, `book.list`, `flashcard.delete`)\n- `--route.path` is the route path (e.g., `/api/users`)\n- `--route.method` is the HTTP method (e.g., `get`, `post`, `put`, `patch`, `delete`) \u2014 only for HTTP controllers\n\nThe command will generate (paths prefixed with `modules/<module>/` when `--module` is provided):\n- `src/controllers/<Name>Controller.ts` - The controller class file\n- `src/types/routes/<route.name>.ts` - The route type file (will be moved into the controller file \u2014 see step 3)\n- `tests/controllers/<Name>Controller.spec.ts` - The test file\n\n### 2. Read the generated files\n\nRead all three generated files to understand the scaffolded code.\n\n### 3. Complete the route type\n\n**IMPORTANT: Keep the route type inside the controller file**, not in a separate type file. Define the type directly in `src/controllers/<Name>Controller.ts` above the class definition. Delete the generated `src/types/routes/<route.name>.ts` file if it was created.\n\n**Remove unnecessary `params`, `payload`, and `queries` \u2014 only include what the route actually needs:**\n\n- **`params`** \u2014 Include only when the route path contains dynamic segments (e.g., `/api/users/:id`). Remove entirely for routes with no URL parameters (e.g., `/api/users`).\n- **`payload`** \u2014 Include only for methods that accept a request body (`post`, `put`, `patch`). Remove entirely for `get` and `delete` routes.\n- **`queries`** \u2014 Include only when the route supports query string filtering, pagination, or sorting (e.g., list/search endpoints). Remove entirely when not needed.\n- **`response`** \u2014 Always include.\n\nThe route type structure follows this pattern (remove unused sections):\n\n```typescript\n// Example: GET /api/users (list) \u2014 no params, no payload, has queries\ntype <TypeName>RouteType = {\n queries: {\n\n },\n response: {\n\n },\n};\n\n// Example: POST /api/users (create) \u2014 no params, has payload, no queries\ntype <TypeName>RouteType = {\n payload: {\n\n },\n response: {\n\n },\n};\n\n// Example: GET /api/users/:id (detail) \u2014 has params, no payload, no queries\ntype <TypeName>RouteType = {\n params: {\n\n },\n response: {\n\n },\n};\n\n// Example: PUT /api/users/:id (update) \u2014 has params, has payload, no queries\ntype <TypeName>RouteType = {\n params: {\n\n },\n payload: {\n\n },\n response: {\n\n },\n};\n```\n\n### 4. Complete the controller class\n\nEdit `src/controllers/<Name>Controller.ts` to complete the implementation:\n\n- Set appropriate `roles` for access control\n- Add a meaningful `description` for the route that explains what the endpoint does (e.g., `\"Create a new user account\"`, `\"List all books with pagination\"`)\n- **Keep the controller thin** \u2014 do NOT put business logic in the controller. Put all logic in the corresponding service and inject the service into the controller via the constructor. The controller's `index` method should only delegate to the service.\n- **Remove unnecessary `params`, `payload`, and `queries`** from both the route type and the `@Route` decorator \u2014 only include what the route actually needs (see step 3 rules).\n\n**Add or remove `params`, `payload`, and `queries` in the `@Route` decorator to match the route type (step 3):**\n\n- **`params`** \u2014 Include with `Assert()` validators only when the route has URL parameters. Remove the `params` key entirely otherwise.\n- **`payload`** \u2014 Include with `Assert({...})` only for `post`, `put`, `patch` methods. Remove the `payload` key entirely for `get` and `delete`.\n- **`queries`** \u2014 Include with `Assert({...})` only when query parameters are expected. Remove the `queries` key entirely otherwise.\n- **`response`** \u2014 Always include with `Assert({...})`.\n\n**HTTP controller** generated structure (remove `params`, `payload`, `queries` as needed \u2014 see rules above):\n\n```typescript\nimport type { ContextType } from \"@ooneex/controller\";\nimport { ERole } from \"@ooneex/role\";\nimport { Route } from \"@ooneex/routing\";\nimport { Assert } from \"@ooneex/validation\";\n\ntype <TypeName>RouteType = {\n // Only include params, payload, queries as needed (see step 3)\n response: {\n\n },\n};\n\n@Route.<method>(\"<route.path>\", {\n name: \"<route.name>\",\n version: 1,\n description: \"\",\n // Only include params, payload, queries as needed (see step 3)\n response: Assert({\n\n }),\n roles: [ERole.USER],\n})\nexport class <Name>Controller {\n public async index(context: ContextType<<TypeName>RouteType>) {\n return context.response.json({\n\n });\n }\n}\n```\n\n**Socket controller** generated structure (remove `params`, `payload`, `queries` as needed \u2014 see rules above):\n\n```typescript\nimport type { ContextType } from \"@ooneex/socket\";\nimport { ERole } from \"@ooneex/role\";\nimport { Route } from \"@ooneex/routing\";\nimport { Assert } from \"@ooneex/validation\";\n\ntype <TypeName>RouteType = {\n // Only include params, payload, queries as needed (see step 3)\n response: {\n\n },\n};\n\n@Route.socket(\"<route.path>\", {\n name: \"<route.name>\",\n version: 1,\n description: \"\",\n // Only include params, payload, queries as needed (see step 3)\n response: Assert({\n\n }),\n roles: [ERole.USER],\n})\nexport class <Name>Controller {\n public async index(context: ContextType<<TypeName>RouteType>) {\n return context.response.json({\n\n });\n }\n}\n```\n\n### 5. Complete the test file\n\nEdit `tests/controllers/<Name>Controller.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep the existing scaffolded tests (class name, index method)\n- Add tests relevant to the specific controller behavior\n\nThe generated test structure follows this pattern:\n\n```typescript\nimport { describe, expect, test } from \"bun:test\";\nimport { <Name>Controller } from \"@/controllers/<Name>Controller\";\n\ndescribe(\"<Name>Controller\", () => {\n test(\"should have class name ending with 'Controller'\", () => {\n expect(<Name>Controller.name.endsWith(\"Controller\")).toBe(true);\n });\n\n test(\"should have 'index' method\", () => {\n expect(<Name>Controller.prototype.index).toBeDefined();\n expect(typeof <Name>Controller.prototype.index).toBe(\"function\");\n });\n});\n```\n\n### 6. Register the controller in the module\n\nAdd the new controller to the module's `controllers` array in `src/<PascalModuleName>Module.ts` (e.g., `src/BookModule.ts` for the `book` module):\n\n```typescript\nimport type { ModuleType } from \"@ooneex/module\";\nimport { <Name>Controller } from \"./controllers/<Name>Controller\";\n\nexport const <PascalModuleName>Module: ModuleType = {\n controllers: [<Name>Controller],\n entities: [],\n permissions: [],\n middlewares: [],\n cronJobs: [],\n events: [],\n};\n```\n\nThe module file uses PascalCase naming: `<PascalModuleName>Module.ts` with export `<PascalModuleName>Module`.\n\nIf the module already has other controllers registered, append the new controller to the existing `controllers` array and add the import alongside existing imports.\n\n### 7. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/controllers/<Name>Controller.ts tests/controllers/<Name>Controller.spec.ts\n```\n\n### 8. Create the service\n\nAfter the controller is created, generate a service class for the controller's business logic using the `make:service` skill:\n\n```\n/make:service --name <Name>\n```\n\nWhere `<Name>` matches the controller name (e.g., if the controller is `CreateUserController`, the service is `CreateUserService`).\n\n### 9. Create the pubsub event\n\nAfter the service is created, generate a pubsub event class for the controller's domain events using the `make:pubsub` skill:\n\n```\n/make:pubsub --name <Name> --channel <resource>.<action>\n```\n\nWhere:\n- `<Name>` matches the controller name (e.g., if the controller is `CreateUserController`, the event is `CreateUserEvent`)\n- `<resource>.<action>` follows the same dot notation as the route name (e.g., `user.create`, `book.delete`)\n\nOnce the event is created:\n- Inject the **service** into the **event** via the constructor, and call the service's `execute` method from the event's `handler` method.\n- Inject the **event** into the **controller** via the constructor, and publish the event from the controller's `index` method.\n";var Ko="---\nname: make:cron\ndescription: Generate a new cron job class with its test file, then complete the generated code. Use when creating a new scheduled task that extends the Cron base class from @ooneex/cron.\n---\n\n# Make Cron Class\n\nGenerate a new cron class and its test file using the `make:cron` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the cron class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:cron --name <name> --module <module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/cron/<Name>Cron.ts` - The cron class file (or `modules/<module>/src/cron/<Name>Cron.ts` with `--module`)\n- `tests/cron/<Name>Cron.spec.ts` - The test file (or `modules/<module>/tests/cron/<Name>Cron.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the cron class\n\nEdit `src/cron/<Name>Cron.ts` to complete the implementation:\n\n- Set the appropriate cron schedule in `getTime()` (e.g., `\"every 5 minutes\"`, `\"every 1 hours\"`, `\"every 30 seconds\"`)\n- Set the timezone in `getTimeZone()` if needed, or keep `null` for server timezone\n- Implement the `handler()` method with the actual cron job logic\n- Inject any required dependencies via the constructor\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport type { TimeZoneType } from \"@ooneex/country\";\nimport type { CronTimeType } from \"@ooneex/cron\";\nimport { Cron, decorator } from \"@ooneex/cron\";\n\n@decorator.cron()\nexport class <Name>Cron extends Cron {\n public getTime(): CronTimeType {\n // Examples: \"every 5 minutes\", \"every 1 hours\", \"every 30 seconds\"\n return \"every 1 hours\";\n }\n\n public getTimeZone(): TimeZoneType | null {\n // Return null to use server timezone, or specify a timezone like \"Europe/Paris\"\n return null;\n }\n\n public async handler(): Promise<void> {\n // Implement your cron handler logic here\n // console.log(\"<Name>Cron handler executed\");\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/cron/<Name>Cron.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep the existing scaffolded tests (class name, getTime, getTimeZone, handler methods)\n- Add tests relevant to the specific cron class behavior\n\nThe generated test structure follows this pattern:\n\n```typescript\nimport { describe, expect, test } from \"bun:test\";\nimport { <Name>Cron } from \"@/cron/<Name>Cron\";\n\ndescribe(\"<Name>Cron\", () => {\n test(\"should have class name ending with 'Cron'\", () => {\n expect(<Name>Cron.name.endsWith(\"Cron\")).toBe(true);\n });\n\n test(\"should have 'getTime' method\", () => {\n expect(<Name>Cron.prototype.getTime).toBeDefined();\n expect(typeof <Name>Cron.prototype.getTime).toBe(\"function\");\n });\n\n test(\"should have 'getTimeZone' method\", () => {\n expect(<Name>Cron.prototype.getTimeZone).toBeDefined();\n expect(typeof <Name>Cron.prototype.getTimeZone).toBe(\"function\");\n });\n\n test(\"should have 'handler' method\", () => {\n expect(<Name>Cron.prototype.handler).toBeDefined();\n expect(typeof <Name>Cron.prototype.handler).toBe(\"function\");\n });\n});\n```\n\n### 5. Register the cron job in the module\n\nAdd the new cron job to the module's `cronJobs` array in `src/<PascalModuleName>Module.ts` (e.g., `src/BookModule.ts` for the `book` module):\n\n```typescript\nimport type { ModuleType } from \"@ooneex/module\";\nimport { <Name>Cron } from \"./cron/<Name>Cron\";\n\nexport const <PascalModuleName>Module: ModuleType = {\n controllers: [],\n entities: [],\n permissions: [],\n middlewares: [],\n cronJobs: [<Name>Cron],\n events: [],\n};\n```\n\nThe module file uses PascalCase naming: `<PascalModuleName>Module.ts` with export `<PascalModuleName>Module`.\n\nIf the module already has other cron jobs registered, append the new cron job to the existing `cronJobs` array and add the import alongside existing imports.\n\n### 6. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/cron/<Name>Cron.ts tests/cron/<Name>Cron.spec.ts\n```\n";var Ho="---\nname: make:database\ndescription: Generate a new database class with its test file, then complete the generated code. Use when creating a new database adapter that extends TypeormDatabase from @ooneex/database.\n---\n\n# Make Database Class\n\nGenerate a new database class and its test file using the `make:database` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the database class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:database --name <name> --module <module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/databases/<Name>Database.ts` - The database class file (or `modules/<module>/src/databases/<Name>Database.ts` with `--module`)\n- `tests/databases/<Name>Database.spec.ts` - The test file (or `modules/<module>/tests/databases/<Name>Database.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the database class\n\nEdit `src/databases/<Name>Database.ts` to complete the implementation:\n\n- Add entity imports and register them in the `entities` array\n- Adjust the database path if needed (default is `\"var/db\"`)\n- Configure DataSource options as appropriate (type, synchronize, etc.)\n- Inject any required dependencies via the constructor\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { DataSource } from \"typeorm\";\nimport { TypeormDatabase, DatabaseException, decorator } from \"@ooneex/database\";\n\n@decorator.database()\nexport class <Name>Database extends TypeormDatabase {\n public getSource(database?: string): DataSource {\n database = database || \"var/db\";\n\n this.source = new DataSource({\n synchronize: false,\n entities: [\n // TODO: Load your entities here\n ],\n enableWAL: true,\n busyErrorRetry: 2000,\n busyTimeout: 30_000,\n database,\n type: \"sqlite\",\n });\n\n return this.source;\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/databases/<Name>Database.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep the existing scaffolded tests (class name, getSource method)\n- Add tests relevant to the specific database class behavior\n\nThe generated test structure follows this pattern:\n\n```typescript\nimport { describe, expect, test } from \"bun:test\";\nimport { <Name>Database } from \"@/databases/<Name>Database\";\n\ndescribe(\"<Name>Database\", () => {\n test(\"should have class name ending with 'Database'\", () => {\n expect(<Name>Database.name.endsWith(\"Database\")).toBe(true);\n });\n\n test(\"should have 'getSource' method\", () => {\n expect(<Name>Database.prototype.getSource).toBeDefined();\n expect(typeof <Name>Database.prototype.getSource).toBe(\"function\");\n });\n});\n```\n\n### 5. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/databases/<Name>Database.ts tests/databases/<Name>Database.spec.ts\n```\n";var Vo="---\nname: make:entity\ndescription: Generate a new TypeORM entity class with its test file, then complete the generated code. Use when creating a new database entity with columns, relations, and table mapping.\n---\n\n# Make Entity Class\n\nGenerate a new entity class and its test file using the `make:entity` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the entity class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:entity --name <name> --module <module> --table-name <table_name>\n```\n\nWhere `<name>` is the name provided by the user. The `--table-name` option is optional \u2014 if omitted, it defaults to the snake_case pluralized form of the name (e.g., `UserProfile` becomes `user_profiles`). The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/entities/<Name>Entity.ts` - The entity class file (or `modules/<module>/src/entities/<Name>Entity.ts` with `--module`)\n- `tests/entities/<Name>Entity.spec.ts` - The test file (or `modules/<module>/tests/entities/<Name>Entity.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the entity class\n\nEdit `src/entities/<Name>Entity.ts` to complete the implementation:\n\n- Add entity-specific columns with appropriate TypeORM decorators (`@Column`)\n- Add relations if needed (`@ManyToOne`, `@OneToMany`, `@ManyToMany`, etc.)\n- Remove any scaffolded columns that are not relevant to the entity\n- Adjust column types, lengths, and constraints as needed\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport type { LocaleType } from \"@ooneex/translation\";\nimport { random } from \"@ooneex/utils\";\nimport { Column, CreateDateColumn, DeleteDateColumn, PrimaryColumn, UpdateDateColumn } from \"typeorm\";\n\n@Entity({\n name: \"<table_name>\",\n})\nexport class <Name>Entity extends BaseEntity {\n @PrimaryColumn({ name: \"id\", type: \"varchar\", length: 25 })\n id: string = random.nanoid(25);\n\n @Column({\n name: \"is_locked\",\n type: \"boolean\",\n default: false,\n nullable: true,\n })\n isLocked?: boolean;\n\n @Column({ name: \"locked_at\", type: \"timestamptz\", nullable: true })\n lockedAt?: Date;\n\n @Column({\n name: \"is_blocked\",\n type: \"boolean\",\n default: false,\n nullable: true,\n })\n isBlocked?: boolean;\n\n @Column({ name: \"blocked_at\", type: \"timestamptz\", nullable: true })\n blockedAt?: Date;\n\n @Column({ name: \"block_reason\", type: \"text\", nullable: true })\n blockReason?: string;\n\n @Column({ name: \"is_public\", type: \"boolean\", default: true, nullable: true })\n isPublic?: boolean;\n\n @Column({ name: \"lang\", type: \"varchar\", length: 10, nullable: true })\n lang?: LocaleType;\n\n @CreateDateColumn({ name: \"created_at\" })\n createdAt?: Date;\n\n @UpdateDateColumn({ name: \"updated_at\" })\n updatedAt?: Date;\n\n @DeleteDateColumn({ name: \"deleted_at\" })\n deletedAt?: Date;\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/entities/<Name>Entity.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep the existing scaffolded tests (class name, id, default columns)\n- Add tests for any new entity-specific columns and relations\n- Update tests if scaffolded columns were removed\n\nThe generated test structure follows this pattern:\n\n```typescript\nimport { describe, expect, test } from \"bun:test\";\nimport { <Name>Entity } from \"@/entities/<Name>Entity\";\n\ndescribe(\"<Name>Entity\", () => {\n test(\"should have class name ending with 'Entity'\", () => {\n expect(<Name>Entity.name.endsWith(\"Entity\")).toBe(true);\n });\n\n test(\"should have 'id' property with default nanoid\", () => {\n const entity = new <Name>Entity();\n expect(entity.id).toBeDefined();\n expect(typeof entity.id).toBe(\"string\");\n expect(entity.id.length).toBe(25);\n });\n\n test(\"should have 'isLocked' property\", () => {\n const entity = new <Name>Entity();\n expect(\"isLocked\" in entity).toBe(true);\n });\n\n // ... additional property tests\n});\n```\n\n### 5. Register the entity in the module\n\nAdd the new entity to the module's `entities` array in `src/<PascalModuleName>Module.ts` (e.g., `src/BookModule.ts` for the `book` module):\n\n```typescript\nimport type { ModuleType } from \"@ooneex/module\";\nimport { <Name>Entity } from \"./entities/<Name>Entity\";\n\nexport const <PascalModuleName>Module: ModuleType = {\n controllers: [],\n entities: [<Name>Entity],\n permissions: [],\n middlewares: [],\n cronJobs: [],\n events: [],\n};\n```\n\nThe module file uses PascalCase naming: `<PascalModuleName>Module.ts` with export `<PascalModuleName>Module`.\n\nIf the module already has other entities registered, append the new entity to the existing `entities` array and add the import alongside existing imports.\n\n### 6. Create a migration for the entity\n\nAfter creating or updating an entity, generate a migration to apply the corresponding schema changes to the database.\n\nRun the generator:\n\n```bash\nbunx @ooneex/cli@latest make:migration\n```\n\nThen read the generated migration file in `src/migrations/` and complete it:\n\n- In the `up` method, write the SQL to create the table (or alter it if updating an existing entity). Include all columns, types, constraints, defaults, and indexes matching the entity definition.\n- In the `down` method, write the reverse SQL to undo the changes (e.g., `DROP TABLE` or `ALTER TABLE DROP COLUMN`).\n- If the migration depends on another migration (e.g., a foreign key referencing another table), add that migration class to the `getDependencies()` return array.\n\nExample `up` method for a new entity:\n\n```typescript\npublic async up(tx: TransactionSQL): Promise<void> {\n await tx`\n CREATE TABLE IF NOT EXISTS <table_name> (\n id VARCHAR(25) PRIMARY KEY,\n is_locked BOOLEAN DEFAULT false,\n locked_at TIMESTAMPTZ,\n is_blocked BOOLEAN DEFAULT false,\n blocked_at TIMESTAMPTZ,\n block_reason TEXT,\n is_public BOOLEAN DEFAULT true,\n lang VARCHAR(10),\n created_at TIMESTAMPTZ DEFAULT NOW(),\n updated_at TIMESTAMPTZ DEFAULT NOW(),\n deleted_at TIMESTAMPTZ\n )\n `;\n}\n```\n\n### 7. Create a repository for the entity\n\nAfter creating the entity, generate a repository to handle database operations for it.\n\nRun the generator:\n\n```bash\nbunx @ooneex/cli@latest make:repository --name <name>\n```\n\nWhere `<name>` is the same name used for the entity. The command will generate:\n- `src/repositories/<Name>Repository.ts` - The repository class\n- `tests/repositories/<Name>Repository.spec.ts` - The test file\n\nThen read the generated files and complete the repository implementation:\n\n- Adjust search fields in the `find()` method to match the entity's searchable columns\n- Customize relations loading in `findOne`/`findOneBy` if the entity has relations\n- Add any domain-specific methods relevant to the entity\n- Remove methods that don't apply to the entity\n- Update tests to match the final repository methods\n\n### 8. Lint and format\n\nRun linting and formatting on all generated files:\n\n```bash\nbunx biome check --fix src/entities/<Name>Entity.ts tests/entities/<Name>Entity.spec.ts src/repositories/<Name>Repository.ts tests/repositories/<Name>Repository.spec.ts src/migrations/\n```\n";var zo="---\nname: make:logger\ndescription: Generate a new logger class with its test file, then complete the generated code. Use when creating a new logger that implements the ILogger interface from @ooneex/logger.\n---\n\n# Make Logger Class\n\nGenerate a new logger class and its test file using the `make:logger` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the logger class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:logger --name <name> --module <module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/loggers/<Name>Logger.ts` - The logger class file (or `modules/<module>/src/loggers/<Name>Logger.ts` with `--module`)\n- `tests/loggers/<Name>Logger.spec.ts` - The test file (or `modules/<module>/tests/loggers/<Name>Logger.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the logger class\n\nEdit `src/loggers/<Name>Logger.ts` to complete the implementation:\n\n- Implement the `init()` method to set up the logger (e.g., open file handles, configure transports)\n- Implement `log`, `debug`, `info`, `success`, `warn`, and `error` methods with actual logging logic\n- Inject any required dependencies via the constructor\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport type { IException } from \"@ooneex/exception\";\nimport type { ILogger } from \"@ooneex/logger\";\nimport type { ScalarType } from \"@ooneex/types\";\nimport { decorator } from \"@ooneex/logger\";\n\n@decorator.logger()\nexport class <Name>Logger implements ILogger {\n public async init(): Promise<void> {\n // Initialize your logger here\n }\n\n public log(message: string, data?: Record<string, ScalarType>): void {\n // Handle general logging\n }\n\n public debug(message: string, data?: Record<string, ScalarType>): void {\n // Handle debug logging\n }\n\n public info(message: string, data?: Record<string, ScalarType>): void {\n // Handle info logging\n }\n\n public success(message: string, data?: Record<string, ScalarType>): void {\n // Handle success logging\n }\n\n public warn(message: string, data?: Record<string, ScalarType>): void {\n // Handle warning logging\n }\n\n public error(message: string | IException, data?: Record<string, ScalarType>): void {\n // Handle error logging\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/loggers/<Name>Logger.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep the existing scaffolded tests (class name, init, log, debug, info, success, warn, error methods)\n- Add tests relevant to the specific logger class behavior\n\nThe generated test structure follows this pattern:\n\n```typescript\nimport { describe, expect, test } from \"bun:test\";\nimport { <Name>Logger } from \"@/loggers/<Name>Logger\";\n\ndescribe(\"<Name>Logger\", () => {\n test(\"should have class name ending with 'Logger'\", () => {\n expect(<Name>Logger.name.endsWith(\"Logger\")).toBe(true);\n });\n\n test(\"should have 'init' method\", () => {\n expect(<Name>Logger.prototype.init).toBeDefined();\n expect(typeof <Name>Logger.prototype.init).toBe(\"function\");\n });\n\n test(\"should have 'log' method\", () => {\n expect(<Name>Logger.prototype.log).toBeDefined();\n expect(typeof <Name>Logger.prototype.log).toBe(\"function\");\n });\n\n test(\"should have 'debug' method\", () => {\n expect(<Name>Logger.prototype.debug).toBeDefined();\n expect(typeof <Name>Logger.prototype.debug).toBe(\"function\");\n });\n\n test(\"should have 'info' method\", () => {\n expect(<Name>Logger.prototype.info).toBeDefined();\n expect(typeof <Name>Logger.prototype.info).toBe(\"function\");\n });\n\n test(\"should have 'success' method\", () => {\n expect(<Name>Logger.prototype.success).toBeDefined();\n expect(typeof <Name>Logger.prototype.success).toBe(\"function\");\n });\n\n test(\"should have 'warn' method\", () => {\n expect(<Name>Logger.prototype.warn).toBeDefined();\n expect(typeof <Name>Logger.prototype.warn).toBe(\"function\");\n });\n\n test(\"should have 'error' method\", () => {\n expect(<Name>Logger.prototype.error).toBeDefined();\n expect(typeof <Name>Logger.prototype.error).toBe(\"function\");\n });\n});\n```\n\n### 5. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/loggers/<Name>Logger.ts tests/loggers/<Name>Logger.spec.ts\n```\n";var Yo="---\nname: make:mailer\ndescription: Generate a new mailer class with its template and test files, then complete the generated code. Use when creating a new email sender with JSX template using @ooneex/mailer.\n---\n\n# Make Mailer Class\n\nGenerate a new mailer class, its JSX template, and test files using the `make:mailer` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the mailer class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:mailer --name <name> --module <module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate (paths prefixed with `modules/<module>/` when `--module` is provided):\n- `src/mailers/<Name>Mailer.ts` - The mailer class file\n- `src/mailers/<Name>MailerTemplate.tsx` - The JSX email template\n- `tests/mailers/<Name>Mailer.spec.ts` - The mailer test file\n- `tests/mailers/<Name>MailerTemplate.spec.ts` - The template test file\n\n### 2. Read the generated files\n\nRead all four generated files to understand the scaffolded code.\n\n### 3. Complete the mailer class\n\nEdit `src/mailers/<Name>Mailer.ts` to complete the implementation:\n\n- Adjust the `send` method config type if additional parameters are needed\n- Add any pre-send logic (validation, data transformation, etc.)\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { inject } from \"@ooneex/container\";\nimport type { IMailer } from \"@ooneex/mailer\";\nimport { type <Name>MailerPropsType, <Name>MailerTemplate } from \"./<Name>MailerTemplate\";\n\nexport class <Name>Mailer implements IMailer {\n constructor(\n @inject(\"mailer\")\n private readonly mailer: IMailer,\n ) {}\n\n public send = async (config: {\n to: string[];\n subject: string;\n from?: { name: string; address: string };\n data?: <Name>MailerPropsType;\n }): Promise<void> => {\n const { data, ...rest } = config;\n\n await this.mailer.send({\n ...rest,\n content: <Name>MailerTemplate(data),\n });\n };\n}\n```\n\n### 4. Complete the mailer template\n\nEdit `src/mailers/<Name>MailerTemplate.tsx` to complete the implementation:\n\n- Update `<Name>MailerPropsType` with the actual props needed for the email\n- Build the email body using `MailerLayout` components (Header, Body, Footer)\n- Add email content, styling, and dynamic data rendering\n\nThe generated template structure follows this pattern:\n\n```tsx\nimport { MailerLayout } from \"@ooneex/mailer\";\n\nexport type <Name>MailerPropsType = {\n link: string;\n};\n\nexport const <Name>MailerTemplate = (props?: <Name>MailerPropsType) => (\n <MailerLayout>\n <MailerLayout.Header />\n <MailerLayout.Body>\n <a href={props?.link}>Login</a>\n </MailerLayout.Body>\n <MailerLayout.Footer />\n </MailerLayout>\n);\n```\n\n### 5. Complete the test files\n\nEdit `tests/mailers/<Name>Mailer.spec.ts` and `tests/mailers/<Name>MailerTemplate.spec.ts` to add meaningful tests beyond the scaffolded ones.\n\n### 6. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/mailers/<Name>Mailer.ts src/mailers/<Name>MailerTemplate.tsx tests/mailers/<Name>Mailer.spec.ts tests/mailers/<Name>MailerTemplate.spec.ts\n```\n";var Qo="---\nname: make:middleware\ndescription: Generate a new middleware class with its test file, then complete the generated code. Use when creating a new HTTP or WebSocket middleware that implements IMiddleware from @ooneex/middleware.\n---\n\n# Make Middleware Class\n\nGenerate a new middleware class and its test file using the `make:middleware` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the middleware class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:middleware --name <name> --module <module> --is-socket <true|false>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The `--is-socket` option determines whether to generate an HTTP middleware or a WebSocket middleware (defaults to `false` if omitted). The command will generate:\n- `src/middlewares/<Name>Middleware.ts` - The middleware class file (or `modules/<module>/src/middlewares/<Name>Middleware.ts` with `--module`)\n- `tests/middlewares/<Name>Middleware.spec.ts` - The test file (or `modules/<module>/tests/middlewares/<Name>Middleware.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the middleware class\n\nEdit `src/middlewares/<Name>Middleware.ts` to complete the implementation:\n\n- Implement the `handler` method with actual middleware logic\n- Add request/response transformations, authentication checks, logging, etc.\n- Inject any required dependencies via the constructor\n\n**HTTP middleware** generated structure:\n\n```typescript\nimport type { ContextType } from \"@ooneex/controller\";\nimport { decorator, type IMiddleware } from \"@ooneex/middleware\";\n\n@decorator.middleware()\nexport class <Name>Middleware implements IMiddleware {\n public async handler(context: ContextType): Promise<ContextType> {\n // Example: Add custom header\n // context.response.header(\"X-Custom-Header\", \"value\");\n\n return context\n }\n}\n```\n\n**Socket middleware** generated structure:\n\n```typescript\nimport type { ContextType } from \"@ooneex/socket\";\nimport { decorator, type IMiddleware } from \"@ooneex/middleware\";\n\n@decorator.middleware()\nexport class <Name>Middleware implements IMiddleware {\n public async handler(context: ContextType): Promise<ContextType> {\n // Example: Add custom header\n // context.response.header(\"X-Custom-Header\", \"value\");\n\n return context\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/middlewares/<Name>Middleware.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep the existing scaffolded tests (class name, handler method)\n- Add tests relevant to the specific middleware behavior\n\nThe generated test structure follows this pattern:\n\n```typescript\nimport { describe, expect, test } from \"bun:test\";\nimport { <Name>Middleware } from \"@/middlewares/<Name>Middleware\";\n\ndescribe(\"<Name>Middleware\", () => {\n test(\"should have class name ending with 'Middleware'\", () => {\n expect(<Name>Middleware.name.endsWith(\"Middleware\")).toBe(true);\n });\n\n test(\"should have 'handler' method\", () => {\n expect(<Name>Middleware.prototype.handler).toBeDefined();\n expect(typeof <Name>Middleware.prototype.handler).toBe(\"function\");\n });\n});\n```\n\n### 5. Register the middleware in the module\n\nAdd the new middleware to the module's `middlewares` array in `src/<PascalModuleName>Module.ts` (e.g., `src/BookModule.ts` for the `book` module):\n\n```typescript\nimport type { ModuleType } from \"@ooneex/module\";\nimport { <Name>Middleware } from \"./middlewares/<Name>Middleware\";\n\nexport const <PascalModuleName>Module: ModuleType = {\n controllers: [],\n entities: [],\n permissions: [],\n middlewares: [<Name>Middleware],\n cronJobs: [],\n events: [],\n};\n```\n\nThe module file uses PascalCase naming: `<PascalModuleName>Module.ts` with export `<PascalModuleName>Module`.\n\nIf the module already has other middlewares registered, append the new middleware to the existing `middlewares` array and add the import alongside existing imports.\n\n### 6. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/middlewares/<Name>Middleware.ts tests/middlewares/<Name>Middleware.spec.ts\n```\n";var Zo="---\nname: make:migration\ndescription: Generate a new database migration file, then complete the generated code. Use when creating a new database migration for schema changes using @ooneex/migrations.\n---\n\n# Make Migration\n\nGenerate a new migration file using the `make:migration` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the migration file:\n\n```bash\nbunx @ooneex/cli@latest make:migration --module <module>\n```\n\nThe `--module` option is optional \u2014 if provided, the migration file is generated under `modules/<module>/src/migrations/` instead of `src/migrations/`. The command will:\n- Generate a timestamped migration file in `src/migrations/` (or `modules/<module>/src/migrations/` with `--module`)\n- Add a `migration:up` script to `package.json` if not already present\n\n### 2. Read the generated file\n\nRead the generated migration file in `src/migrations/` to understand the scaffolded code.\n\n### 3. Complete the migration\n\nEdit the generated migration file to implement:\n\n- The `up` method with the schema changes (create tables, add columns, create indexes, etc.)\n- The `down` method with the reverse operations to undo the migration\n\n### 4. Lint and format\n\nRun linting and formatting on the generated file:\n\n```bash\nbunx biome check --fix src/migrations/\n```\n";var Xo="---\nname: make:permission\ndescription: Generate a new permission class with its test file, then complete the generated code. Use when creating a new permission that extends Permission from @ooneex/permission.\n---\n\n# Make Permission Class\n\nGenerate a new permission class and its test file using the `make:permission` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the permission class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:permission --name <name> --module <module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/permissions/<Name>Permission.ts` - The permission class file (or `modules/<module>/src/permissions/<Name>Permission.ts` with `--module`)\n- `tests/permissions/<Name>Permission.spec.ts` - The test file (or `modules/<module>/tests/permissions/<Name>Permission.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the permission class\n\nEdit `src/permissions/<Name>Permission.ts` to complete the implementation:\n\n- Implement the `allow()` method with permission rules using `this.ability.can()`\n- Implement the `setUserPermissions()` method with role-based permission logic\n- Define which actions (read, create, update, delete, manage) are allowed on which entities\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { decorator, Permission } from \"@ooneex/permission\";\nimport type { IUser } from \"@ooneex/user\";\n\n@decorator.permission()\nexport class <Name>Permission extends Permission {\n public allow(): this {\n // Example: Add permissions using this.ability.can()\n // this.ability.can(\"read\", \"YourEntity\");\n // this.ability.can([\"read\", \"update\"], \"YourEntity\", { userId: user.id });\n\n return this;\n }\n\n public setUserPermissions(user: IUser | null): this {\n if (!user) {\n return this;\n }\n\n // Example: Grant full access to admins\n // const { roles } = user;\n // if (roles.includes(ERole.ADMIN)) {\n // this.ability.can(\"manage\", \"all\");\n // return this;\n // }\n\n // Example: Grant specific permissions based on roles\n // for (const role of roles) {\n // if (role === ERole.USER) {\n // this.ability.can([\"read\", \"update\"], \"YourEntity\", { userId: user.id });\n // }\n //\n // if (role === ERole.GUEST) {\n // this.ability.can(\"read\", \"YourEntity\", { public: true });\n // }\n // }\n\n return this;\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/permissions/<Name>Permission.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep the existing scaffolded tests (class name, extends Permission, allow, setUserPermissions methods)\n- Add tests relevant to the specific permission rules\n\nThe generated test structure follows this pattern:\n\n```typescript\nimport { describe, expect, test } from \"bun:test\";\nimport { Permission } from \"@ooneex/permission\";\nimport { <Name>Permission } from \"@/permissions/<Name>Permission\";\n\ndescribe(\"<Name>Permission\", () => {\n test(\"should have class name ending with 'Permission'\", () => {\n expect(<Name>Permission.name.endsWith(\"Permission\")).toBe(true);\n });\n\n test(\"should extend Permission\", () => {\n const permission = new <Name>Permission();\n expect(permission).toBeInstanceOf(Permission);\n });\n\n test(\"should have 'allow' method\", () => {\n expect(<Name>Permission.prototype.allow).toBeDefined();\n expect(typeof <Name>Permission.prototype.allow).toBe(\"function\");\n });\n\n test(\"should have 'setUserPermissions' method\", () => {\n expect(<Name>Permission.prototype.setUserPermissions).toBeDefined();\n expect(typeof <Name>Permission.prototype.setUserPermissions).toBe(\"function\");\n });\n});\n```\n\n### 5. Register the permission in the module\n\nAdd the new permission to the module's `permissions` array in `src/<PascalModuleName>Module.ts` (e.g., `src/BookModule.ts` for the `book` module):\n\n```typescript\nimport type { ModuleType } from \"@ooneex/module\";\nimport { <Name>Permission } from \"./permissions/<Name>Permission\";\n\nexport const <PascalModuleName>Module: ModuleType = {\n controllers: [],\n entities: [],\n permissions: [<Name>Permission],\n middlewares: [],\n cronJobs: [],\n events: [],\n};\n```\n\nThe module file uses PascalCase naming: `<PascalModuleName>Module.ts` with export `<PascalModuleName>Module`.\n\nIf the module already has other permissions registered, append the new permission to the existing `permissions` array and add the import alongside existing imports.\n\n### 6. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/permissions/<Name>Permission.ts tests/permissions/<Name>Permission.spec.ts\n```\n";var jo="---\nname: make:pubsub\ndescription: Generate a new PubSub event class with its test file, then complete the generated code. Use when creating a new publish/subscribe event that extends PubSub from @ooneex/pub-sub.\n---\n\n# Make PubSub Event Class\n\nGenerate a new PubSub event class and its test file using the `make:pubsub` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the PubSub event class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:pubsub --name <name> --module <module> --channel <channel>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The `--channel` option is optional \u2014 if omitted, it defaults to the kebab-case form of the name (e.g., `UserCreated` becomes `user-created`). The command will generate:\n- `src/events/<Name>Event.ts` - The event class file (or `modules/<module>/src/events/<Name>Event.ts` with `--module`)\n- `tests/events/<Name>Event.spec.ts` - The test file (or `modules/<module>/tests/events/<Name>Event.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the PubSub event class\n\nEdit `src/events/<Name>Event.ts` to complete the implementation:\n\n- Define a proper data type instead of `Record<string, ScalarType>` for the event payload\n- Implement the `handler()` method with actual event handling logic\n- Set the appropriate channel name in `getChannel()`\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { inject } from \"@ooneex/container\";\nimport type { ScalarType } from \"@ooneex/types\";\nimport { decorator, PubSub, RedisPubSub } from \"@ooneex/pub-sub\";\n\n@decorator.pubSub()\nexport class <Name>Event<Data extends Record<string, ScalarType> = Record<string, ScalarType>> extends PubSub<Data> {\n constructor(\n @inject(RedisPubSub)\n client: RedisPubSub<Data>,\n ) {\n super(client);\n }\n\n public getChannel(): string {\n return \"<channel>\";\n }\n\n public async handler(context: { data: Data; channel: string }): Promise<void> {\n console.log(context);\n // TODO: Implement handler logic here\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/events/<Name>Event.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep the existing scaffolded tests (class name, getChannel, handler, publish, subscribe, unsubscribe, unsubscribeAll methods)\n- Add tests relevant to the specific event behavior\n\nThe generated test structure follows this pattern:\n\n```typescript\nimport { describe, expect, test } from \"bun:test\";\nimport { <Name>PubSub } from \"@/pubsub/<Name>PubSub\";\n\ndescribe(\"<Name>PubSub\", () => {\n test(\"should have class name ending with 'PubSub'\", () => {\n expect(<Name>PubSub.name.endsWith(\"PubSub\")).toBe(true);\n });\n\n test(\"should have 'getChannel' method\", () => {\n expect(<Name>PubSub.prototype.getChannel).toBeDefined();\n expect(typeof <Name>PubSub.prototype.getChannel).toBe(\"function\");\n });\n\n test(\"should have 'handler' method\", () => {\n expect(<Name>PubSub.prototype.handler).toBeDefined();\n expect(typeof <Name>PubSub.prototype.handler).toBe(\"function\");\n });\n\n test(\"should have 'publish' method\", () => {\n expect(<Name>PubSub.prototype.publish).toBeDefined();\n expect(typeof <Name>PubSub.prototype.publish).toBe(\"function\");\n });\n\n test(\"should have 'subscribe' method\", () => {\n expect(<Name>PubSub.prototype.subscribe).toBeDefined();\n expect(typeof <Name>PubSub.prototype.subscribe).toBe(\"function\");\n });\n\n test(\"should have 'unsubscribe' method\", () => {\n expect(<Name>PubSub.prototype.unsubscribe).toBeDefined();\n expect(typeof <Name>PubSub.prototype.unsubscribe).toBe(\"function\");\n });\n\n test(\"should have 'unsubscribeAll' method\", () => {\n expect(<Name>PubSub.prototype.unsubscribeAll).toBeDefined();\n expect(typeof <Name>PubSub.prototype.unsubscribeAll).toBe(\"function\");\n });\n});\n```\n\n### 5. Register the event in the module\n\nAdd the new event to the module's `events` array in `src/<PascalModuleName>Module.ts` (e.g., `src/BookModule.ts` for the `book` module):\n\n```typescript\nimport type { ModuleType } from \"@ooneex/module\";\nimport { <Name>Event } from \"./events/<Name>Event\";\n\nexport const <PascalModuleName>Module: ModuleType = {\n controllers: [],\n entities: [],\n permissions: [],\n middlewares: [],\n cronJobs: [],\n events: [<Name>Event],\n};\n```\n\nThe module file uses PascalCase naming: `<PascalModuleName>Module.ts` with export `<PascalModuleName>Module`.\n\nIf the module already has other events registered, append the new event to the existing `events` array and add the import alongside existing imports.\n\n### 6. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/events/<Name>Event.ts tests/events/<Name>Event.spec.ts\n```\n";var Jo="---\nname: make:repository\ndescription: Generate a new repository class with its test file, then complete the generated code. Use when creating a new TypeORM repository for database operations on an entity.\n---\n\n# Make Repository Class\n\nGenerate a new repository class and its test file using the `make:repository` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the repository class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:repository --name <name> --module <module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/repositories/<Name>Repository.ts` - The repository class file (or `modules/<module>/src/repositories/<Name>Repository.ts` with `--module`)\n- `tests/repositories/<Name>Repository.spec.ts` - The test file (or `modules/<module>/tests/repositories/<Name>Repository.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the repository class\n\nEdit `src/repositories/<Name>Repository.ts` to complete the implementation:\n\n- Verify the entity import path matches the actual entity location\n- Adjust the `find` method's search fields (default searches `name` with `ILike`)\n- Customize relations loading in `findOne`/`findOneBy` if needed\n\n#### Adding methods\n\nLook at the entity's fields, relations, and business context to determine if custom domain-specific methods are needed. For example:\n- A `SessionRepository` might need `revokeSession(sessionId: string)` and `revokeAllUserSessions(userId: string)`\n- A `NotificationRepository` might need `markAsRead(id: string)` and `markAllAsRead(userId: string)`\n- Entities with status fields may need methods like `archive(id: string)` or `activate(id: string)`\n\nRead related entities, services, or actions in the module to understand what operations the repository should support, then add the appropriate methods.\n\n#### Removing methods\n\nRemove scaffolded methods that don't make sense for the entity's context:\n- Remove `createMany`/`updateMany` if the entity is always managed individually (e.g., user profiles, settings)\n- Remove `delete` if the entity uses soft deletes only (use a custom `softDelete` or `archive` method instead)\n- Remove `find` if the entity is only ever accessed by ID or specific criteria (e.g., singleton config entities)\n- Remove `count` if there's no use case for counting records of this entity\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { inject } from \"@ooneex/container\";\nimport type { ITypeormDatabase } from \"@ooneex/database\";\nimport { decorator } from \"@ooneex/repository\";\nimport type { FilterResultType } from \"@ooneex/types\";\nimport type { FindManyOptions, FindOptionsWhere, Repository, SaveOptions, UpdateResult } from \"typeorm\";\nimport { ILike } from \"typeorm\";\nimport { <Name>Entity } from \"../entities/<Name>Entity\";\n\n@decorator.repository()\nexport class <Name>Repository {\n constructor(\n @inject(\"database\")\n private readonly database: ITypeormDatabase,\n ) {}\n\n public async open(): Promise<Repository<<Name>Entity>> {\n return await this.database.open(<Name>Entity);\n }\n\n public async close(): Promise<void> {\n await this.database.close();\n }\n\n public async find(\n criteria: FindManyOptions<<Name>Entity> & { page?: number; limit?: number; q?: string },\n ): Promise<FilterResultType<<Name>Entity>> {\n // ... pagination and search logic\n }\n\n public async findOne(id: string): Promise<<Name>Entity | null> { ... }\n public async findOneBy(criteria: FindOptionsWhere<<Name>Entity>): Promise<<Name>Entity | null> { ... }\n public async create(entity: <Name>Entity, options?: SaveOptions): Promise<<Name>Entity> { ... }\n public async createMany(entities: <Name>Entity[], options?: SaveOptions): Promise<<Name>Entity[]> { ... }\n public async update(entity: <Name>Entity, options?: SaveOptions): Promise<<Name>Entity> { ... }\n public async updateMany(entities: <Name>Entity[], options?: SaveOptions): Promise<<Name>Entity[]> { ... }\n public async delete(criteria: FindOptionsWhere<<Name>Entity> | FindOptionsWhere<<Name>Entity>[]): Promise<UpdateResult> { ... }\n public async count(criteria?: FindOptionsWhere<<Name>Entity> | FindOptionsWhere<<Name>Entity>[]): Promise<number> { ... }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/repositories/<Name>Repository.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep scaffolded tests for methods that remain in the repository (remove tests for methods that were removed)\n- Add tests for any custom domain-specific methods added to the repository\n- Add tests relevant to the specific repository behavior\n\n### 5. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/repositories/<Name>Repository.ts tests/repositories/<Name>Repository.spec.ts\n```\n";var ei="---\nname: make:seed\ndescription: Generate a new database seed file, then complete the generated code. Use when creating seed data for populating the database using @ooneex/seeds.\n---\n\n# Make Seed\n\nGenerate a new seed file using the `make:seed` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the seed file:\n\n```bash\nbunx @ooneex/cli@latest make:seed --name <name> --module <module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, the seed file is generated under `modules/<module>/src/seeds/` instead of `src/seeds/`. The command will:\n- Generate a seed file in `src/seeds/` (or `modules/<module>/src/seeds/` with `--module`)\n- Add a `seed:run` script to `package.json` if not already present\n\n### 2. Read the generated file\n\nRead the generated seed file in `src/seeds/` to understand the scaffolded code.\n\n### 3. Complete the seed\n\nEdit the generated seed file to implement:\n\n- Import the relevant entity classes\n- Create seed data with hardcoded nanoid values for `id` fields (generate via `bun -e \"import { random } from '@ooneex/utils'; console.log(random.nanoid())\"`)\n- Do NOT use sequential IDs like `\"item-1\"`, `\"item-2\"`\n- Ensure the same entity uses the same ID everywhere it appears\n\n### 4. Lint and format\n\nRun linting and formatting on the generated file:\n\n```bash\nbunx biome check --fix src/seeds/\n```\n";var ti="---\nname: make:service\ndescription: Generate a new service class with its test file, then complete the generated code. Use when creating a new business logic service that implements IService from @ooneex/service.\n---\n\n# Make Service Class\n\nGenerate a new service class and its test file using the `make:service` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the service class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:service --name <name> --module <module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/services/<Name>Service.ts` - The service class file (or `modules/<module>/src/services/<Name>Service.ts` with `--module`)\n- `tests/services/<Name>Service.spec.ts` - The test file (or `modules/<module>/tests/services/<Name>Service.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the service class\n\nEdit `src/services/<Name>Service.ts` to complete the implementation:\n\n- Define a proper type for `ServiceDataType` instead of `Record<string, unknown>`\n- Implement the `execute()` method with actual business logic\n- Inject any required dependencies (repositories, other services, etc.) via the constructor\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { decorator } from \"@ooneex/service\";\nimport type { IService } from \"@ooneex/service\";\n\ntype ServiceDataType = Record<string, unknown>;\n\n@decorator.service()\nexport class <Name>Service implements IService {\n public async execute(data?: ServiceDataType): Promise<void> {\n // TODO: Implement service logic\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/services/<Name>Service.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep the existing scaffolded tests (class name, execute method)\n- Add tests relevant to the specific service behavior\n\nThe generated test structure follows this pattern:\n\n```typescript\nimport { describe, expect, test } from \"bun:test\";\nimport { <Name>Service } from \"@/services/<Name>Service\";\n\ndescribe(\"<Name>Service\", () => {\n test(\"should have class name ending with 'Service'\", () => {\n expect(<Name>Service.name.endsWith(\"Service\")).toBe(true);\n });\n\n test(\"should have 'execute' method\", () => {\n expect(<Name>Service.prototype.execute).toBeDefined();\n expect(typeof <Name>Service.prototype.execute).toBe(\"function\");\n });\n});\n```\n\n### 5. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/services/<Name>Service.ts tests/services/<Name>Service.spec.ts\n```\n";var si="---\nname: make:storage\ndescription: Generate a new storage class with its test file, then complete the generated code. Use when creating a new S3-compatible storage adapter that extends Storage from @ooneex/storage.\n---\n\n# Make Storage Class\n\nGenerate a new storage class and its test file using the `make:storage` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the storage class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:storage --name <name> --module <module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/storage/<Name>Storage.ts` - The storage class file (or `modules/<module>/src/storage/<Name>Storage.ts` with `--module`)\n- `tests/storage/<Name>Storage.spec.ts` - The test file (or `modules/<module>/tests/storage/<Name>Storage.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the storage class\n\nEdit `src/storage/<Name>Storage.ts` to complete the implementation:\n\n- Set the `bucket` property to the appropriate bucket name\n- Verify the environment variable names match the project configuration (`STORAGE_<NAME_UPPER>_ACCESS_KEY`, `STORAGE_<NAME_UPPER>_SECRET_KEY`, `STORAGE_<NAME_UPPER>_ENDPOINT`, `STORAGE_<NAME_UPPER>_REGION`)\n- Add any additional storage-specific methods if needed\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { Storage, decorator, StorageException } from \"@ooneex/storage\";\nimport type { S3Options } from \"bun\";\n\n@decorator.storage()\nexport class <Name>Storage extends Storage {\n protected bucket: string;\n private readonly accessKey: string;\n private readonly secretKey: string;\n private readonly endpoint: string;\n private readonly region: string;\n\n constructor(options?: {\n accessKey?: string;\n secretKey?: string;\n endpoint?: string;\n region?: string;\n }) {\n super();\n\n const accessKey = options?.accessKey || Bun.env.STORAGE_<NAME_UPPER>_ACCESS_KEY;\n const secretKey = options?.secretKey || Bun.env.STORAGE_<NAME_UPPER>_SECRET_KEY;\n const endpoint = options?.endpoint || Bun.env.STORAGE_<NAME_UPPER>_ENDPOINT;\n\n // ... validation throws StorageException if missing ...\n\n this.accessKey = accessKey;\n this.secretKey = secretKey;\n this.endpoint = endpoint;\n this.region = options?.region || Bun.env.STORAGE_<NAME_UPPER>_REGION || \"auto\";\n }\n\n public getOptions(): S3Options {\n return {\n accessKeyId: this.accessKey,\n secretAccessKey: this.secretKey,\n endpoint: this.endpoint,\n bucket: this.bucket,\n region: this.region,\n };\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/storage/<Name>Storage.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep the existing scaffolded tests (class name, bucket field, getOptions method)\n- Add tests relevant to the specific storage class behavior\n\nThe generated test structure follows this pattern:\n\n```typescript\nimport { describe, expect, test } from \"bun:test\";\nimport { <Name>StorageAdapter } from \"@/storage/<Name>StorageAdapter\";\n\ndescribe(\"<Name>StorageAdapter\", () => {\n test(\"should have class name ending with 'StorageAdapter'\", () => {\n expect(<Name>StorageAdapter.name.endsWith(\"StorageAdapter\")).toBe(true);\n });\n\n test(\"should have 'bucket' field\", () => {\n expect(\"bucket\" in <Name>StorageAdapter.prototype || \"bucket\" in Object.getOwnPropertyNames(<Name>StorageAdapter.prototype)).toBe(true);\n });\n\n test(\"should have 'getOptions' method\", () => {\n expect(<Name>StorageAdapter.prototype.getOptions).toBeDefined();\n expect(typeof <Name>StorageAdapter.prototype.getOptions).toBe(\"function\");\n });\n});\n```\n\n### 5. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/storage/<Name>Storage.ts tests/storage/<Name>Storage.spec.ts\n```\n";var ri="---\nname: make:vector-database\ndescription: Generate a new vector database class with its test file, then complete the generated code. Use when creating a new vector database that extends VectorDatabase from @ooneex/rag.\n---\n\n# Make Vector Database Class\n\nGenerate a new vector database class and its test file using the `make:vector-database` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the vector database class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:vector-database --name <name> --module <module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/databases/<Name>VectorDatabase.ts` - The vector database class file (or `modules/<module>/src/databases/<Name>VectorDatabase.ts` with `--module`)\n- `tests/databases/<Name>VectorDatabase.spec.ts` - The test file (or `modules/<module>/tests/databases/<Name>VectorDatabase.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the vector database class\n\nEdit `src/databases/<Name>VectorDatabase.ts` to complete the implementation:\n\n- Set the `getDatabaseUri()` return value to the actual LanceDB database path\n- Configure the embedding provider and model in `getEmbeddingModel()`\n- Define the custom data fields in `DataType` and map them in `getSchema()`\n- Import the appropriate Apache Arrow types for your schema fields\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { VectorDatabase, decorator } from \"@ooneex/rag\";\nimport type { EmbeddingModelType, EmbeddingProviderType, FieldValueType } from \"@ooneex/rag\";\nimport { Utf8 } from \"apache-arrow\";\n\ntype DataType = {\n name: string;\n};\n\n@decorator.vectorDatabase()\nexport class <Name>VectorDatabase extends VectorDatabase<DataType> {\n public getDatabaseUri(): string {\n return \"\";\n }\n\n public getEmbeddingModel(): { provider: EmbeddingProviderType; model: EmbeddingModelType[\"model\"] } {\n return { provider: \"openai\", model: \"text-embedding-ada-002\" };\n }\n\n public getSchema(): { [K in keyof DataType]: FieldValueType } {\n return {\n name: new Utf8(),\n };\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/databases/<Name>VectorDatabase.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep the existing scaffolded tests (class name, getDatabaseUri, getEmbeddingModel, getSchema methods)\n- Add tests relevant to the specific vector database class behavior\n\nThe generated test structure follows this pattern:\n\n```typescript\nimport { describe, expect, test } from \"bun:test\";\nimport { <Name>VectorDatabase } from \"@/databases/<Name>VectorDatabase\";\n\ndescribe(\"<Name>VectorDatabase\", () => {\n test(\"should have class name ending with 'VectorDatabase'\", () => {\n expect(<Name>VectorDatabase.name.endsWith(\"VectorDatabase\")).toBe(true);\n });\n\n test(\"should have 'getDatabaseUri' method\", () => {\n expect(<Name>VectorDatabase.prototype.getDatabaseUri).toBeDefined();\n expect(typeof <Name>VectorDatabase.prototype.getDatabaseUri).toBe(\"function\");\n });\n\n test(\"should have 'getEmbeddingModel' method\", () => {\n expect(<Name>VectorDatabase.prototype.getEmbeddingModel).toBeDefined();\n expect(typeof <Name>VectorDatabase.prototype.getEmbeddingModel).toBe(\"function\");\n });\n\n test(\"should have 'getSchema' method\", () => {\n expect(<Name>VectorDatabase.prototype.getSchema).toBeDefined();\n expect(typeof <Name>VectorDatabase.prototype.getSchema).toBe(\"function\");\n });\n});\n```\n\n### 5. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/databases/<Name>VectorDatabase.ts tests/databases/<Name>VectorDatabase.spec.ts\n```\n";var oi="---\nname: optimize\ndescription: Optimize a module's codebase for quality, performance, and clean conventions. Enforces arrow functions (except class methods), type/interface naming, removes duplication, and ensures only important tests remain.\n---\n\n# Optimize Codebase\n\nOptimize a module's codebase for quality, performance, and clean conventions.\n\n## Coding Conventions\n\nApply these conventions across all files in the target module:\n\n- **Arrow functions everywhere** \u2014 use arrow functions for all function expressions, callbacks, standalone functions, and variable declarations. The ONLY exception is class methods, which must use regular method syntax.\n- **Type naming** \u2014 all type aliases must end with the `Type` suffix (e.g., `UserDataType`, `ConfigOptionsType`). Rename any that don't comply.\n- **Interface naming** \u2014 all interface names must start with the `I` prefix (e.g., `IUser`, `IService`, `IRepository`). Rename any that don't comply.\n- **No definite assignment assertions** \u2014 never use `!` on class properties (e.g., `email!: string`). Use a default value or make the property optional (`?`) instead.\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`).\n- For Entity class, if property is optional, add `null` to its type.\n\n## Steps\n\n### 1. Identify the target\n\nDetermine the module to optimize. If the user specifies a module name, work in `modules/<module>/`. If no module is specified, ask the user which module to optimize.\n\n### 2. Read and analyze the module\n\nRead all source files (`src/**/*.ts`) and test files (`tests/**/*.ts`) in the target module. Build a full picture of:\n\n- All types, interfaces, classes, and functions\n- Dependencies between files\n- Existing test coverage\n\n### 3. Enforce naming conventions\n\nScan every file and fix:\n\n- **Types not ending with `Type`** \u2014 rename the type and update all references across the module\n- **Interfaces not starting with `I`** \u2014 rename the interface and update all references across the module\n- **Non-arrow functions** \u2014 convert all function expressions, callbacks, and standalone functions to arrow functions. Do NOT convert class methods.\n- **Missing visibility modifiers** \u2014 add explicit `public`, `private`, or `protected` to all class methods and properties\n\n### 4. Remove code duplication\n\nIdentify duplicated or near-duplicated code within the module:\n\n- Extract shared logic into well-named helper arrow functions or base classes\n- Consolidate repeated type definitions\n- Merge similar utility functions\n- Remove dead code (unused imports, unreachable branches, unused variables)\n\n### 5. Optimize for performance\n\nReview and improve:\n\n- Replace inefficient loops or repeated iterations with single-pass approaches where possible\n- Use `Map`/`Set` instead of arrays for lookups when appropriate\n- Avoid unnecessary object spreads or deep clones\n- Prefer early returns to reduce nesting\n- Remove unnecessary `async`/`await` where a direct return suffices\n- Eliminate redundant null/undefined checks when the type system already guarantees the value\n\n### 6. Optimize tests\n\nReview all test files and restructure:\n\n- **Remove trivial tests** \u2014 delete tests that only check obvious things (e.g., \"class name ends with X\", \"method exists\") unless they serve as smoke tests for generated code\n- **Keep and improve important tests** \u2014 focus on tests that verify actual business logic, edge cases, error handling, and integration behavior\n- **Write fewer but more meaningful tests** \u2014 each test should validate a real scenario or invariant, not just existence checks\n- **Consolidate redundant test cases** \u2014 merge tests that cover the same code path with slightly different inputs into parameterized patterns\n- **Ensure critical paths are covered** \u2014 every public method with logic should have at least one test covering its happy path and one covering its error/edge case\n\n### 7. Final cleanup\n\n- Remove all unused imports\n- Remove empty files or files with no exports\n- Ensure consistent formatting\n\n### 8. Lint and format\n\nRun linting and formatting on all modified files:\n\n```bash\nbunx biome check --fix <list of modified files>\n```\n\n### 9. Run tests\n\nRun the module's tests to verify nothing is broken:\n\n```bash\nbun test <module test directory>\n```\n\nIf any test fails, fix the issue and re-run until all tests pass.\n";var nc={"make.ai":$o,"make.analytics":qo,"make.cache":Wo,"make.controller":Fo,"make.cron":Ko,"make.database":Ho,"make.entity":Vo,"make.logger":zo,"make.mailer":Yo,"make.middleware":Qo,"make.migration":Zo,"make.permission":Xo,"make.pubsub":jo,"make.repository":Jo,"make.seed":ei,"make.service":ti,"make.storage":si,"make.vector-database":ri,commit:Go,optimize:oi};class Ve{getName(){return"make:claude:skill"}getDescription(){return"Generate Claude skills from templates"}async run(){let e=He(".claude","skills"),t=He(process.cwd(),e),s=new ac;for(let[r,o]of Object.entries(nc)){let i=r.replace(/\./g,"-"),a=He(t,i,"SKILL.md");await Bun.write(a,o),s.success(`${He(e,i,"SKILL.md")} created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0})}}}Ve=w([E.command()],Ve);import{basename as cc,join as U}from"path";import{TerminalLogger as pc}from"@ooneex/logger";import{toPascalCase as Ut}from"@ooneex/utils";var ii=`import { describe, expect, test } from "bun:test";
|
|
1821
1851
|
import { {{NAME}}Cron } from "@/cron/{{NAME}}Cron";
|
|
1822
1852
|
|
|
1823
1853
|
describe("{{NAME}}Cron", () => {
|
|
@@ -1840,7 +1870,7 @@ describe("{{NAME}}Cron", () => {
|
|
|
1840
1870
|
expect(typeof {{NAME}}Cron.prototype.handler).toBe("function");
|
|
1841
1871
|
});
|
|
1842
1872
|
});
|
|
1843
|
-
`;var
|
|
1873
|
+
`;var ai=`import type { TimeZoneType } from "@ooneex/country";
|
|
1844
1874
|
import type { CronTimeType } from "@ooneex/cron";
|
|
1845
1875
|
import { Cron, decorator } from "@ooneex/cron";
|
|
1846
1876
|
|
|
@@ -1861,9 +1891,9 @@ export class {{NAME}}Cron extends Cron {
|
|
|
1861
1891
|
// console.log("{{NAME}}Cron handler executed");
|
|
1862
1892
|
}
|
|
1863
1893
|
}
|
|
1864
|
-
`;class ze{getName(){return"make:cron"}getDescription(){return"Generate a new cron class"}async addToModule(e,t){let s=await Bun.file(e).text(),
|
|
1894
|
+
`;class ze{getName(){return"make:cron"}getDescription(){return"Generate a new cron class"}async addToModule(e,t){let s=await Bun.file(e).text(),r=`${t}Cron`,o=`import { ${r} } from "./cron/${r}";
|
|
1865
1895
|
`,i=s.lastIndexOf("import "),a=s.indexOf(`
|
|
1866
|
-
`,i);s=`${s.slice(0,a+1)}${
|
|
1896
|
+
`,i);s=`${s.slice(0,a+1)}${o}${s.slice(a+1)}`;let n=/(cronJobs:\s*\[)([^\]]*)/s,l=s.match(n);if(l){let d=l[2]?.trim(),u=d?`${d}, ${r}`:r;s=s.replace(n,`$1${u}`)}await Bun.write(e,s)}async run(e){let{name:t,module:s}=e;if(!t)t=await A({message:"Enter cron name"});t=Ut(t).replace(/Cron$/,"");let r=ai.replace(/{{NAME}}/g,t),o=s?U("modules",s):".",i=U(o,"src","cron"),a=U(process.cwd(),i),n=U(a,`${t}Cron.ts`);await Bun.write(n,r);let l=ii.replace(/{{NAME}}/g,t),d=U(o,"tests","cron"),u=U(process.cwd(),d),h=U(u,`${t}Cron.spec.ts`);await Bun.write(h,l);let m=s?Ut(s):Ut(cc(process.cwd())),c=U(process.cwd(),o,"src",`${m}Module.ts`);if(await Bun.file(c).exists())await this.addToModule(c,t);let p=new pc;p.success(`${U(i,t)}Cron.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),p.success(`${U(d,t)}Cron.spec.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0});let f=U(process.cwd(),"package.json"),y=await Bun.file(f).json(),g=y.dependencies??{},b=y.devDependencies??{};if(!g["@ooneex/cron"]&&!b["@ooneex/cron"])await Bun.spawn(["bun","add","@ooneex/cron"],{cwd:process.cwd(),stdout:"ignore",stderr:"inherit"}).exited}}ze=w([E.command()],ze);import{join as H}from"path";import{TerminalLogger as hc}from"@ooneex/logger";import{toPascalCase as fc}from"@ooneex/utils";var ni=`import { describe, expect, test } from "bun:test";
|
|
1867
1897
|
import { {{NAME}}Database } from "@/databases/{{NAME}}Database";
|
|
1868
1898
|
|
|
1869
1899
|
describe("{{NAME}}Database", () => {
|
|
@@ -1876,7 +1906,7 @@ describe("{{NAME}}Database", () => {
|
|
|
1876
1906
|
expect(typeof {{NAME}}Database.prototype.getSource).toBe("function");
|
|
1877
1907
|
});
|
|
1878
1908
|
});
|
|
1879
|
-
`;var
|
|
1909
|
+
`;var li=`import { DataSource } from "typeorm";
|
|
1880
1910
|
import { TypeormDatabase, DatabaseException, decorator } from "@ooneex/database";
|
|
1881
1911
|
|
|
1882
1912
|
@decorator.database()
|
|
@@ -1899,7 +1929,7 @@ export class {{NAME}}Database extends TypeormDatabase {
|
|
|
1899
1929
|
return this.source;
|
|
1900
1930
|
}
|
|
1901
1931
|
}
|
|
1902
|
-
`;class Ye{getName(){return"make:database"}getDescription(){return"Generate a new database class"}async run(e){let{name:t,module:s}=e;if(!t)t=await A({message:"Enter database name"});t=
|
|
1932
|
+
`;class Ye{getName(){return"make:database"}getDescription(){return"Generate a new database class"}async run(e){let{name:t,module:s}=e;if(!t)t=await A({message:"Enter database name"});t=fc(t).replace(/DatabaseAdapter$/,"").replace(/Database$/,"");let r=li.replace(/{{NAME}}/g,t),o=s?H("modules",s):".",i=H(o,"src","databases"),a=H(process.cwd(),i),n=H(a,`${t}Database.ts`);await Bun.write(n,r);let l=ni.replace(/{{NAME}}/g,t),d=H(o,"tests","databases"),u=H(process.cwd(),d),h=H(u,`${t}Database.spec.ts`);await Bun.write(h,l);let m=new hc;m.success(`${H(i,t)}Database.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),m.success(`${H(d,t)}Database.spec.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0});let c=H(process.cwd(),"package.json"),p=await Bun.file(c).json(),f=p.dependencies??{},y=p.devDependencies??{};if(!f["@ooneex/database"]&&!y["@ooneex/database"])await Bun.spawn(["bun","add","@ooneex/database"],{cwd:process.cwd(),stdout:"ignore",stderr:"inherit"}).exited}}Ye=w([E.command()],Ye);import{join as Ii}from"path";import{TerminalLogger as Pc}from"@ooneex/logger";var{YAML:Oi}=globalThis.Bun;var ci=te(ae(),1),di=["clickhouse","elasticsearch","grafana","jaeger","keycloak","libretranslate","maildev","memcached","minio","mongodb","mysql","nats","postgres","prometheus","rabbitmq","redis","temporal","vault"],pi=async(e)=>{return(await ci.prompt({type:"autocomplete",name:"service",message:e.message,initial:e.initial,choices:di.map((s)=>s),validate:(s)=>{if(!di.includes(s))return"Docker service is invalid";return!0}})).service};var mi=`services:
|
|
1903
1933
|
# ClickHouse - Column-oriented OLAP database for analytics
|
|
1904
1934
|
# Docs: https://clickhouse.com/docs
|
|
1905
1935
|
# HTTP API: http://localhost:8123
|
|
@@ -1920,7 +1950,7 @@ export class {{NAME}}Database extends TypeormDatabase {
|
|
|
1920
1950
|
|
|
1921
1951
|
volumes:
|
|
1922
1952
|
clickhouse_data:
|
|
1923
|
-
`;var
|
|
1953
|
+
`;var ui=`services:
|
|
1924
1954
|
# Elasticsearch - Full-text search and analytics engine
|
|
1925
1955
|
# Docs: https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html
|
|
1926
1956
|
# HTTP API: http://localhost:9200
|
|
@@ -1941,7 +1971,7 @@ volumes:
|
|
|
1941
1971
|
|
|
1942
1972
|
volumes:
|
|
1943
1973
|
elasticsearch_data:
|
|
1944
|
-
`;var
|
|
1974
|
+
`;var hi=`services:
|
|
1945
1975
|
# Grafana - Metrics visualization and dashboards
|
|
1946
1976
|
# Docs: https://grafana.com/docs/grafana/latest/
|
|
1947
1977
|
# Web UI: http://localhost:3000 (ooneex/ooneex)
|
|
@@ -1959,7 +1989,7 @@ volumes:
|
|
|
1959
1989
|
|
|
1960
1990
|
volumes:
|
|
1961
1991
|
grafana_data:
|
|
1962
|
-
`;var
|
|
1992
|
+
`;var fi=`services:
|
|
1963
1993
|
# Jaeger - Distributed tracing system
|
|
1964
1994
|
# Docs: https://www.jaegertracing.io/docs/
|
|
1965
1995
|
# Web UI: http://localhost:16686
|
|
@@ -1973,7 +2003,7 @@ volumes:
|
|
|
1973
2003
|
- "16686:16686"
|
|
1974
2004
|
- "6831:6831/udp"
|
|
1975
2005
|
- "14268:14268"
|
|
1976
|
-
`;var
|
|
2006
|
+
`;var yi=`services:
|
|
1977
2007
|
# Keycloak - Identity and access management
|
|
1978
2008
|
# Docs: https://www.keycloak.org/documentation
|
|
1979
2009
|
# Admin Console: http://localhost:8080 (ooneex/ooneex)
|
|
@@ -1987,7 +2017,7 @@ volumes:
|
|
|
1987
2017
|
- KEYCLOAK_ADMIN=ooneex
|
|
1988
2018
|
- KEYCLOAK_ADMIN_PASSWORD=ooneex
|
|
1989
2019
|
command: start-dev
|
|
1990
|
-
`;var
|
|
2020
|
+
`;var gi=`services:
|
|
1991
2021
|
# LibreTranslate - Self-hosted machine translation API
|
|
1992
2022
|
# Docs: https://libretranslate.com/docs/
|
|
1993
2023
|
# API: http://localhost:4000
|
|
@@ -2014,7 +2044,7 @@ volumes:
|
|
|
2014
2044
|
|
|
2015
2045
|
volumes:
|
|
2016
2046
|
libretranslate_models:
|
|
2017
|
-
`;var
|
|
2047
|
+
`;var bi=`services:
|
|
2018
2048
|
# MailDev - Email testing tool with web UI
|
|
2019
2049
|
# Docs: https://github.com/maildev/maildev
|
|
2020
2050
|
# Web UI: http://localhost:1080
|
|
@@ -2025,7 +2055,7 @@ volumes:
|
|
|
2025
2055
|
ports:
|
|
2026
2056
|
- "1080:1080"
|
|
2027
2057
|
- "1025:1025"
|
|
2028
|
-
`;var
|
|
2058
|
+
`;var xi=`services:
|
|
2029
2059
|
# Memcached - Distributed memory caching system
|
|
2030
2060
|
# Docs: https://memcached.org/
|
|
2031
2061
|
# Connection: localhost:11211
|
|
@@ -2035,7 +2065,7 @@ volumes:
|
|
|
2035
2065
|
restart: "on-failure"
|
|
2036
2066
|
ports:
|
|
2037
2067
|
- "11211:11211"
|
|
2038
|
-
`;var
|
|
2068
|
+
`;var wi=`services:
|
|
2039
2069
|
# MinIO - S3-compatible object storage
|
|
2040
2070
|
# Docs: https://min.io/docs/minio/container/index.html
|
|
2041
2071
|
# API: http://localhost:9000
|
|
@@ -2056,7 +2086,7 @@ volumes:
|
|
|
2056
2086
|
|
|
2057
2087
|
volumes:
|
|
2058
2088
|
minio_data:
|
|
2059
|
-
`;var
|
|
2089
|
+
`;var Ei=`services:
|
|
2060
2090
|
# MongoDB - NoSQL document database
|
|
2061
2091
|
# Docs: https://www.mongodb.com/docs/
|
|
2062
2092
|
# Connection: mongodb://ooneex:ooneex@localhost:27017/ooneex
|
|
@@ -2075,7 +2105,7 @@ volumes:
|
|
|
2075
2105
|
|
|
2076
2106
|
volumes:
|
|
2077
2107
|
mongodb_data:
|
|
2078
|
-
`;var
|
|
2108
|
+
`;var vi=`services:
|
|
2079
2109
|
# MySQL - Alternative relational database
|
|
2080
2110
|
# Docs: https://dev.mysql.com/doc/
|
|
2081
2111
|
# Connection: mysql://ooneex:ooneex@localhost:3306/ooneex
|
|
@@ -2095,7 +2125,7 @@ volumes:
|
|
|
2095
2125
|
|
|
2096
2126
|
volumes:
|
|
2097
2127
|
mysql_db:
|
|
2098
|
-
`;var
|
|
2128
|
+
`;var Ai=`services:
|
|
2099
2129
|
# NATS - High-performance messaging system with JetStream
|
|
2100
2130
|
# Docs: https://docs.nats.io/
|
|
2101
2131
|
# Client: localhost:4222
|
|
@@ -2108,7 +2138,7 @@ volumes:
|
|
|
2108
2138
|
- "4222:4222"
|
|
2109
2139
|
- "8222:8222"
|
|
2110
2140
|
command: "--jetstream --http_port 8222"
|
|
2111
|
-
`;var
|
|
2141
|
+
`;var Ti=`services:
|
|
2112
2142
|
# Jade - FastAPI REST API to fetch YouTube metadata and download videos or audio via Dockerized microservice.
|
|
2113
2143
|
# API: http://localhost:8000
|
|
2114
2144
|
# Docs: http://localhost:8000/docs
|
|
@@ -2126,7 +2156,7 @@ volumes:
|
|
|
2126
2156
|
|
|
2127
2157
|
volumes:
|
|
2128
2158
|
jade_data:
|
|
2129
|
-
`;var
|
|
2159
|
+
`;var Si=`services:
|
|
2130
2160
|
# PostgreSQL - Primary relational database
|
|
2131
2161
|
# Docs: https://www.postgresql.org/docs/
|
|
2132
2162
|
# Connection: postgresql://ooneex:ooneex@localhost:5432/ooneex
|
|
@@ -2147,7 +2177,7 @@ volumes:
|
|
|
2147
2177
|
|
|
2148
2178
|
volumes:
|
|
2149
2179
|
postgres_db:
|
|
2150
|
-
`;var
|
|
2180
|
+
`;var Ni=`services:
|
|
2151
2181
|
# Prometheus - Metrics collection and monitoring
|
|
2152
2182
|
# Docs: https://prometheus.io/docs/
|
|
2153
2183
|
# Web UI: http://localhost:9090
|
|
@@ -2162,7 +2192,7 @@ volumes:
|
|
|
2162
2192
|
|
|
2163
2193
|
volumes:
|
|
2164
2194
|
prometheus_data:
|
|
2165
|
-
`;var
|
|
2195
|
+
`;var Ri=`services:
|
|
2166
2196
|
# RabbitMQ - Message broker for async processing
|
|
2167
2197
|
# Docs: https://www.rabbitmq.com/docs
|
|
2168
2198
|
# AMQP: amqp://ooneex:ooneex@localhost:5672/ooneex
|
|
@@ -2184,7 +2214,7 @@ volumes:
|
|
|
2184
2214
|
|
|
2185
2215
|
volumes:
|
|
2186
2216
|
rabbitmq_data:
|
|
2187
|
-
`;var
|
|
2217
|
+
`;var Ci=`services:
|
|
2188
2218
|
# Redis - In-memory data store for caching and sessions
|
|
2189
2219
|
# Docs: https://redis.io/docs/
|
|
2190
2220
|
# Connection: redis://localhost:6379
|
|
@@ -2199,7 +2229,7 @@ volumes:
|
|
|
2199
2229
|
|
|
2200
2230
|
volumes:
|
|
2201
2231
|
redis_data:
|
|
2202
|
-
`;var
|
|
2232
|
+
`;var Mi=`services:
|
|
2203
2233
|
# Temporal - Workflow orchestration engine
|
|
2204
2234
|
# Docs: https://docs.temporal.io/
|
|
2205
2235
|
# gRPC: localhost:7233
|
|
@@ -2216,7 +2246,7 @@ volumes:
|
|
|
2216
2246
|
- POSTGRES_USER=ooneex
|
|
2217
2247
|
- POSTGRES_PWD=ooneex
|
|
2218
2248
|
- POSTGRES_SEEDS=postgres
|
|
2219
|
-
`;var
|
|
2249
|
+
`;var _i=`services:
|
|
2220
2250
|
# Vault - Secrets management and encryption
|
|
2221
2251
|
# Docs: https://developer.hashicorp.com/vault/docs
|
|
2222
2252
|
# Web UI: http://localhost:8200 (token: ooneex)
|
|
@@ -2231,20 +2261,20 @@ volumes:
|
|
|
2231
2261
|
- VAULT_DEV_LISTEN_ADDRESS=0.0.0.0:8200
|
|
2232
2262
|
cap_add:
|
|
2233
2263
|
- IPC_LOCK
|
|
2234
|
-
`;var
|
|
2235
|
-
`),s=[],
|
|
2236
|
-
`)}function
|
|
2237
|
-
volumes:`),
|
|
2238
|
-
networks:`),f=-1;if(
|
|
2239
|
-
${
|
|
2240
|
-
${
|
|
2241
|
-
volumes:`)){let
|
|
2242
|
-
volumes:`),
|
|
2243
|
-
${
|
|
2264
|
+
`;var Bi={clickhouse:mi,elasticsearch:ui,grafana:hi,"ooneex-jade":Ti,jaeger:fi,keycloak:yi,libretranslate:gi,maildev:bi,memcached:xi,minio:wi,mongodb:Ei,mysql:vi,nats:Ai,postgres:Si,prometheus:Ni,rabbitmq:Ri,redis:Ci,temporal:Mi,vault:_i};function kc(e){let t=e.split(`
|
|
2265
|
+
`),s=[],r=!1;for(let o of t){if(o.startsWith("services:")){r=!0;continue}if(r){if(o.startsWith("volumes:")||o.startsWith("networks:"))break;s.push(o)}}return s.join(`
|
|
2266
|
+
`)}function Lc(e){let t=Oi.parse(e);return t.volumes?Object.keys(t.volumes):[]}class Qe{getName(){return"make:docker"}getDescription(){return"Add a docker service to docker-compose.yml"}async run(e){let{name:t}=e;if(!t)t=await pi({message:"Select docker service"});let s=Bi[t],r=Ii(process.cwd(),"docker-compose.yml"),o=new Pc,i=Bun.file(r);if(await i.exists()){let l=await i.text(),d=Oi.parse(l);if(d.services&&t in d.services){o.warn(`Service "${t}" already exists in docker-compose.yml`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0});return}let u=kc(s),h=Lc(s),m=l,c=m.indexOf(`
|
|
2267
|
+
volumes:`),p=m.indexOf(`
|
|
2268
|
+
networks:`),f=-1;if(c!==-1&&p!==-1)f=Math.min(c,p);else if(c!==-1)f=c;else if(p!==-1)f=p;if(f!==-1)m=`${m.slice(0,f)}
|
|
2269
|
+
${u}${m.slice(f)}`;else m=`${m.trimEnd()}
|
|
2270
|
+
${u}`;for(let y of h)if(!m.includes(` ${y}:`))if(m.includes(`
|
|
2271
|
+
volumes:`)){let g=m.indexOf(`
|
|
2272
|
+
volumes:`),b=m.slice(g+9);m=`${m.slice(0,g+9)}
|
|
2273
|
+
${y}:${b}`}else m=`${m.trimEnd()}
|
|
2244
2274
|
|
|
2245
2275
|
volumes:
|
|
2246
|
-
${
|
|
2247
|
-
`;await Bun.write(
|
|
2276
|
+
${y}:
|
|
2277
|
+
`;await Bun.write(r,m)}else await Bun.write(r,s);let a=Ii(process.cwd(),"package.json"),n=Bun.file(a);if(await n.exists()){let l=await n.json();l.scripts=l.scripts||{},l.scripts.docker="docker compose up -d",await Bun.write(a,JSON.stringify(l,null,2))}o.success(`Service "${t}" added to docker-compose.yml`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),o.info("Run 'bun run docker' to start docker containers",void 0,{showTimestamp:!1,showArrow:!0,showLevel:!1})}}Qe=w([E.command()],Qe);var Li=te(Di(),1);import{basename as $c,join as V}from"path";import{TerminalLogger as qc}from"@ooneex/logger";import{toPascalCase as qt,toSnakeCase as Wc}from"@ooneex/utils";var Pi=`import { describe, expect, test } from "bun:test";
|
|
2248
2278
|
import { {{NAME}}Entity } from "@/entities/{{NAME}}Entity";
|
|
2249
2279
|
|
|
2250
2280
|
describe("{{NAME}}Entity", () => {
|
|
@@ -2309,7 +2339,7 @@ describe("{{NAME}}Entity", () => {
|
|
|
2309
2339
|
expect("deletedAt" in entity).toBe(true);
|
|
2310
2340
|
});
|
|
2311
2341
|
});
|
|
2312
|
-
`;var
|
|
2342
|
+
`;var ki=`import type { LocaleType } from "@ooneex/translation";
|
|
2313
2343
|
import { random } from "@ooneex/utils";
|
|
2314
2344
|
import { Column, CreateDateColumn, DeleteDateColumn, Entity, PrimaryColumn, UpdateDateColumn } from "typeorm";
|
|
2315
2345
|
|
|
@@ -2360,9 +2390,9 @@ export class {{NAME}}Entity {
|
|
|
2360
2390
|
@DeleteDateColumn({ name: "deleted_at" })
|
|
2361
2391
|
deletedAt?: Date;
|
|
2362
2392
|
}
|
|
2363
|
-
`;class be{getName(){return"make:entity"}getDescription(){return"Generate a new entity class"}async addToModule(e,t){let s=await Bun.file(e).text(),
|
|
2393
|
+
`;class be{getName(){return"make:entity"}getDescription(){return"Generate a new entity class"}async addToModule(e,t){let s=await Bun.file(e).text(),r=`${t}Entity`,o=`import { ${r} } from "./entities/${r}";
|
|
2364
2394
|
`,i=s.lastIndexOf("import "),a=s.indexOf(`
|
|
2365
|
-
`,i);s=`${s.slice(0,a+1)}${
|
|
2395
|
+
`,i);s=`${s.slice(0,a+1)}${o}${s.slice(a+1)}`;let n=/(entities:\s*\[)([^\]]*)/s,l=s.match(n);if(l){let d=l[2]?.trim(),u=d?`${d}, ${r}`:r;s=s.replace(n,`$1${u}`)}await Bun.write(e,s)}async run(e){let{name:t,module:s,tableName:r}=e;if(!t)t=await A({message:"Enter entity name"});if(t=qt(t).replace(/Entity$/,""),!r)r=Wc(Li.default(t));let o=ki.replace(/{{NAME}}/g,t).replace(/{{TABLE_NAME}}/g,r),i=s?V("modules",s):".",a=V(i,"src","entities"),n=V(process.cwd(),a),l=V(n,`${t}Entity.ts`);await Bun.write(l,o);let d=Pi.replace(/{{NAME}}/g,t),u=V(i,"tests","entities"),h=V(process.cwd(),u),m=V(h,`${t}Entity.spec.ts`);await Bun.write(m,d);let c=s?qt(s):qt($c(process.cwd())),p=V(process.cwd(),i,"src",`${c}Module.ts`);if(await Bun.file(p).exists())await this.addToModule(p,t);let f=new qc;f.success(`${V(a,t)}Entity.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),f.success(`${V(u,t)}Entity.spec.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0})}}be=w([E.command()],be);import{join as z}from"path";import{TerminalLogger as Hc}from"@ooneex/logger";import{toPascalCase as Vc}from"@ooneex/utils";var Ui=`import { describe, expect, test } from "bun:test";
|
|
2366
2396
|
import { {{NAME}}Logger } from "@/loggers/{{NAME}}Logger";
|
|
2367
2397
|
|
|
2368
2398
|
describe("{{NAME}}Logger", () => {
|
|
@@ -2405,7 +2435,7 @@ describe("{{NAME}}Logger", () => {
|
|
|
2405
2435
|
expect(typeof {{NAME}}Logger.prototype.error).toBe("function");
|
|
2406
2436
|
});
|
|
2407
2437
|
});
|
|
2408
|
-
`;var
|
|
2438
|
+
`;var Gi=`import type { IException } from "@ooneex/exception";
|
|
2409
2439
|
import type { ILogger } from "@ooneex/logger";
|
|
2410
2440
|
import type { ScalarType } from "@ooneex/types";
|
|
2411
2441
|
import { decorator } from "@ooneex/logger";
|
|
@@ -2440,7 +2470,7 @@ export class {{NAME}}Logger implements ILogger {
|
|
|
2440
2470
|
// Handle error logging
|
|
2441
2471
|
}
|
|
2442
2472
|
}
|
|
2443
|
-
`;class Ze{getName(){return"make:logger"}getDescription(){return"Generate a new logger class"}async run(e){let{name:t,module:s}=e;if(!t)t=await A({message:"Enter logger name"});t=
|
|
2473
|
+
`;class Ze{getName(){return"make:logger"}getDescription(){return"Generate a new logger class"}async run(e){let{name:t,module:s}=e;if(!t)t=await A({message:"Enter logger name"});t=Vc(t).replace(/Logger$/,"");let r=Gi.replace(/{{NAME}}/g,t),o=s?z("modules",s):".",i=z(o,"src","loggers"),a=z(process.cwd(),i),n=z(a,`${t}Logger.ts`);await Bun.write(n,r);let l=Ui.replace(/{{NAME}}/g,t),d=z(o,"tests","loggers"),u=z(process.cwd(),d),h=z(u,`${t}Logger.spec.ts`);await Bun.write(h,l);let m=new Hc;m.success(`${z(i,t)}Logger.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),m.success(`${z(d,t)}Logger.spec.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0});let c=z(process.cwd(),"package.json"),p=await Bun.file(c).json(),f=p.dependencies??{},y=p.devDependencies??{};if(!f["@ooneex/logger"]&&!y["@ooneex/logger"])await Bun.spawn(["bun","add","@ooneex/logger"],{cwd:process.cwd(),stdout:"ignore",stderr:"inherit"}).exited}}Ze=w([E.command()],Ze);import{join as O}from"path";import{TerminalLogger as Xc}from"@ooneex/logger";import{toPascalCase as jc}from"@ooneex/utils";var $i=`import { describe, expect, test } from "bun:test";
|
|
2444
2474
|
import { {{NAME}}Mailer } from "@/mailers/{{NAME}}Mailer";
|
|
2445
2475
|
|
|
2446
2476
|
describe("{{NAME}}Mailer", () => {
|
|
@@ -2453,7 +2483,7 @@ describe("{{NAME}}Mailer", () => {
|
|
|
2453
2483
|
expect(typeof {{NAME}}Mailer.prototype.send).toBe("function");
|
|
2454
2484
|
});
|
|
2455
2485
|
});
|
|
2456
|
-
`;var
|
|
2486
|
+
`;var qi=`import { inject } from "@ooneex/container";
|
|
2457
2487
|
import type { IMailer } from "@ooneex/mailer";
|
|
2458
2488
|
import { type {{NAME}}MailerPropsType, {{NAME}}MailerTemplate } from "./{{NAME}}MailerTemplate";
|
|
2459
2489
|
|
|
@@ -2477,7 +2507,7 @@ export class {{NAME}}Mailer implements IMailer {
|
|
|
2477
2507
|
});
|
|
2478
2508
|
}
|
|
2479
2509
|
}
|
|
2480
|
-
`;var
|
|
2510
|
+
`;var Wi=`import { describe, expect, test } from "bun:test";
|
|
2481
2511
|
import { {{NAME}}MailerTemplate } from "@/mailers/{{NAME}}MailerTemplate";
|
|
2482
2512
|
|
|
2483
2513
|
describe("{{NAME}}MailerTemplate", () => {
|
|
@@ -2489,7 +2519,7 @@ describe("{{NAME}}MailerTemplate", () => {
|
|
|
2489
2519
|
expect(typeof {{NAME}}MailerTemplate).toBe("function");
|
|
2490
2520
|
});
|
|
2491
2521
|
});
|
|
2492
|
-
`;var
|
|
2522
|
+
`;var Fi=`import { MailerLayout } from "@ooneex/mailer";
|
|
2493
2523
|
|
|
2494
2524
|
export type {{NAME}}MailerPropsType = {
|
|
2495
2525
|
link: string;
|
|
@@ -2504,7 +2534,7 @@ export const {{NAME}}MailerTemplate = (props?: {{NAME}}MailerPropsType) => (
|
|
|
2504
2534
|
<MailerLayout.Footer />
|
|
2505
2535
|
</MailerLayout>
|
|
2506
2536
|
);
|
|
2507
|
-
`;class Xe{getName(){return"make:mailer"}getDescription(){return"Generate a new mailer class"}async run(e){let{name:t,module:s}=e;if(!t)t=await A({message:"Enter mailer name"});t=
|
|
2537
|
+
`;class Xe{getName(){return"make:mailer"}getDescription(){return"Generate a new mailer class"}async run(e){let{name:t,module:s}=e;if(!t)t=await A({message:"Enter mailer name"});t=jc(t).replace(/Mailer$/,"");let r=qi.replace(/{{NAME}}/g,t),o=Fi.replace(/{{NAME}}/g,t),i=s?O("modules",s):".",a=O(i,"src","mailers"),n=O(process.cwd(),a),l=O(n,`${t}Mailer.ts`),d=O(n,`${t}MailerTemplate.tsx`);await Bun.write(l,r),await Bun.write(d,o);let u=$i.replace(/{{NAME}}/g,t),h=Wi.replace(/{{NAME}}/g,t),m=O(i,"tests","mailers"),c=O(process.cwd(),m),p=O(c,`${t}Mailer.spec.ts`),f=O(c,`${t}MailerTemplate.spec.ts`);await Bun.write(p,u),await Bun.write(f,h);let y=new Xc;y.success(`${O(a,t)}Mailer.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),y.success(`${O(a,t)}MailerTemplate.tsx created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),y.success(`${O(m,t)}Mailer.spec.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),y.success(`${O(m,t)}MailerTemplate.spec.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0});let g=O(process.cwd(),"package.json"),b=await Bun.file(g).json(),x=b.dependencies??{},T=b.devDependencies??{};if(!x["@ooneex/mailer"]&&!T["@ooneex/mailer"])await Bun.spawn(["bun","add","@ooneex/mailer"],{cwd:process.cwd(),stdout:"ignore",stderr:"inherit"}).exited}}Xe=w([E.command()],Xe);import{basename as sp,join as G}from"path";import{TerminalLogger as rp}from"@ooneex/logger";import{toPascalCase as Wt}from"@ooneex/utils";var Ki=`import type { ContextType } from "@ooneex/socket";
|
|
2508
2538
|
import { decorator, type IMiddleware } from "@ooneex/middleware";
|
|
2509
2539
|
|
|
2510
2540
|
@decorator.middleware()
|
|
@@ -2516,7 +2546,7 @@ export class {{NAME}}Middleware implements IMiddleware {
|
|
|
2516
2546
|
return context
|
|
2517
2547
|
}
|
|
2518
2548
|
}
|
|
2519
|
-
`;var
|
|
2549
|
+
`;var Hi=`import { describe, expect, test } from "bun:test";
|
|
2520
2550
|
import { {{NAME}}Middleware } from "@/middlewares/{{NAME}}Middleware";
|
|
2521
2551
|
|
|
2522
2552
|
describe("{{NAME}}Middleware", () => {
|
|
@@ -2529,7 +2559,7 @@ describe("{{NAME}}Middleware", () => {
|
|
|
2529
2559
|
expect(typeof {{NAME}}Middleware.prototype.handler).toBe("function");
|
|
2530
2560
|
});
|
|
2531
2561
|
});
|
|
2532
|
-
`;var
|
|
2562
|
+
`;var Vi=`import type { ContextType } from "@ooneex/controller";
|
|
2533
2563
|
import { decorator, type IMiddleware } from "@ooneex/middleware";
|
|
2534
2564
|
|
|
2535
2565
|
@decorator.middleware()
|
|
@@ -2541,9 +2571,9 @@ export class {{NAME}}Middleware implements IMiddleware {
|
|
|
2541
2571
|
return context
|
|
2542
2572
|
}
|
|
2543
2573
|
}
|
|
2544
|
-
`;class
|
|
2574
|
+
`;class je{getName(){return"make:middleware"}getDescription(){return"Generate a new middleware class"}async addToModule(e,t){let s=await Bun.file(e).text(),r=`${t}Middleware`,o=`import { ${r} } from "./middlewares/${r}";
|
|
2545
2575
|
`,i=s.lastIndexOf("import "),a=s.indexOf(`
|
|
2546
|
-
`,i);s=`${s.slice(0,a+1)}${
|
|
2576
|
+
`,i);s=`${s.slice(0,a+1)}${o}${s.slice(a+1)}`;let n=/(middlewares:\s*\[)([^\]]*)/s,l=s.match(n);if(l){let d=l[2]?.trim(),u=d?`${d}, ${r}`:r;s=s.replace(n,`$1${u}`)}await Bun.write(e,s)}async run(e){let{name:t,module:s,isSocket:r}=e;if(!t)t=await A({message:"Enter middleware name"});if(r===void 0)r=await ge({message:"Is this a socket middleware?"});t=Wt(t).replace(/Middleware$/,"");let i=(r?Ki:Vi).replace(/{{NAME}}/g,t),a=s?G("modules",s):".",n=G(a,"src","middlewares"),l=G(process.cwd(),n),d=G(l,`${t}Middleware.ts`);await Bun.write(d,i);let u=Hi.replace(/{{NAME}}/g,t),h=G(a,"tests","middlewares"),m=G(process.cwd(),h),c=G(m,`${t}Middleware.spec.ts`);await Bun.write(c,u);let p=s?Wt(s):Wt(sp(process.cwd())),f=G(process.cwd(),a,"src",`${p}Module.ts`);if(await Bun.file(f).exists())await this.addToModule(f,t);let y=new rp;y.success(`${G(n,t)}Middleware.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),y.success(`${G(h,t)}Middleware.spec.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0});let g=G(process.cwd(),"package.json"),b=await Bun.file(g).json(),x=b.dependencies??{},T=b.devDependencies??{};if(!x["@ooneex/middleware"]&&!T["@ooneex/middleware"])await Bun.spawn(["bun","add","@ooneex/middleware"],{cwd:process.cwd(),stdout:"ignore",stderr:"inherit"}).exited}}je=w([E.command()],je);import{join as Je}from"path";import{TerminalLogger as ip}from"@ooneex/logger";import{migrationCreate as ap}from"@ooneex/migrations";var zi=`#!/usr/bin/env bun
|
|
2547
2577
|
|
|
2548
2578
|
import { migrationUp } from "@ooneex/migrations";
|
|
2549
2579
|
import "@/migrations/migrations";
|
|
@@ -2552,7 +2582,7 @@ await migrationUp({
|
|
|
2552
2582
|
databaseUrl: Bun.env.DATABASE_URL,
|
|
2553
2583
|
tableName: "migrations",
|
|
2554
2584
|
});
|
|
2555
|
-
`;class xe{getName(){return"make:migration"}getDescription(){return"Generate a new migration file"}async run(e){let{module:t}=e,s=t?
|
|
2585
|
+
`;class xe{getName(){return"make:migration"}getDescription(){return"Generate a new migration file"}async run(e){let{module:t}=e,s=t?Je("modules",t):".",r=await ap({dir:Je(s,"src/migrations")}),o=Je(process.cwd(),s,"bin","migration","up.ts");if(!await Bun.file(o).exists())await Bun.write(o,zi);let a=Je(process.cwd(),"package.json"),n=Bun.file(a);if(await n.exists()){let m=await n.json();m.scripts=m.scripts||{},m.scripts["migration:up"]="bun ./bin/migration/up.ts",await Bun.write(a,JSON.stringify(m,null,2))}let l=new ip;l.success(`${r} created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),l.info("Run 'bun run migration:up' to execute migrations",void 0,{showTimestamp:!1,showArrow:!0,showLevel:!1});let d=await Bun.file(a).json(),u=d.dependencies??{},h=d.devDependencies??{};if(!u["@ooneex/migrations"]&&!h["@ooneex/migrations"])await Bun.spawn(["bun","add","--dev","@ooneex/migrations"],{cwd:process.cwd(),stdout:"ignore",stderr:"inherit"}).exited}}xe=w([E.command()],xe);import{join as Y}from"path";import{TerminalLogger as dp}from"@ooneex/logger";import{toPascalCase as cp}from"@ooneex/utils";var Yi=`import { describe, expect, test } from "bun:test";
|
|
2556
2586
|
import { Permission } from "@ooneex/permission";
|
|
2557
2587
|
import { {{NAME}}Permission } from "@/permissions/{{NAME}}Permission";
|
|
2558
2588
|
|
|
@@ -2577,7 +2607,7 @@ describe("{{NAME}}Permission", () => {
|
|
|
2577
2607
|
});
|
|
2578
2608
|
|
|
2579
2609
|
});
|
|
2580
|
-
`;var
|
|
2610
|
+
`;var Qi=`import { decorator, Permission } from "@ooneex/permission";
|
|
2581
2611
|
import type { IUser } from "@ooneex/user";
|
|
2582
2612
|
|
|
2583
2613
|
@decorator.permission()
|
|
@@ -2616,7 +2646,7 @@ export class {{NAME}}Permission extends Permission {
|
|
|
2616
2646
|
return this;
|
|
2617
2647
|
}
|
|
2618
2648
|
}
|
|
2619
|
-
`;class et{getName(){return"make:permission"}getDescription(){return"Generate a new permission class"}async run(e){let{name:t,module:s}=e;if(!t)t=await A({message:"Enter permission name"});t=
|
|
2649
|
+
`;class et{getName(){return"make:permission"}getDescription(){return"Generate a new permission class"}async run(e){let{name:t,module:s}=e;if(!t)t=await A({message:"Enter permission name"});t=cp(t).replace(/Permission$/,"");let r=Qi.replace(/{{NAME}}/g,t),o=s?Y("modules",s):".",i=Y(o,"src","permissions"),a=Y(process.cwd(),i),n=Y(a,`${t}Permission.ts`);await Bun.write(n,r);let l=Yi.replace(/{{NAME}}/g,t),d=Y(o,"tests","permissions"),u=Y(process.cwd(),d),h=Y(u,`${t}Permission.spec.ts`);await Bun.write(h,l);let m=new dp;m.success(`${Y(i,t)}Permission.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),m.success(`${Y(d,t)}Permission.spec.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0});let c=Y(process.cwd(),"package.json"),p=await Bun.file(c).json(),f=p.dependencies??{},y=p.devDependencies??{};if(!f["@ooneex/permission"]&&!y["@ooneex/permission"])await Bun.spawn(["bun","add","@ooneex/permission"],{cwd:process.cwd(),stdout:"ignore",stderr:"inherit"}).exited}}et=w([E.command()],et);import{basename as up,join as $}from"path";import{TerminalLogger as hp}from"@ooneex/logger";import{toKebabCase as fp,toPascalCase as Ft}from"@ooneex/utils";var Zi=`import { describe, expect, test } from "bun:test";
|
|
2620
2650
|
import { {{NAME}}PubSub } from "@/pubsub/{{NAME}}PubSub";
|
|
2621
2651
|
|
|
2622
2652
|
describe("{{NAME}}PubSub", () => {
|
|
@@ -2654,7 +2684,7 @@ describe("{{NAME}}PubSub", () => {
|
|
|
2654
2684
|
expect(typeof {{NAME}}PubSub.prototype.unsubscribeAll).toBe("function");
|
|
2655
2685
|
});
|
|
2656
2686
|
});
|
|
2657
|
-
`;var
|
|
2687
|
+
`;var Xi=`import { inject } from "@ooneex/container";
|
|
2658
2688
|
import type { ScalarType } from "@ooneex/types";
|
|
2659
2689
|
import { decorator, PubSub, RedisPubSub } from "@ooneex/pub-sub";
|
|
2660
2690
|
|
|
@@ -2676,27 +2706,27 @@ export class {{NAME}}Event<Data extends Record<string, ScalarType> = Record<stri
|
|
|
2676
2706
|
// TODO: Implement handler logic here
|
|
2677
2707
|
}
|
|
2678
2708
|
}
|
|
2679
|
-
`;class tt{getName(){return"make:pubsub"}getDescription(){return"Generate a new PubSub event class"}async addToModule(e,t){let s=await Bun.file(e).text(),
|
|
2709
|
+
`;class tt{getName(){return"make:pubsub"}getDescription(){return"Generate a new PubSub event class"}async addToModule(e,t){let s=await Bun.file(e).text(),r=`${t}Event`,o=`import { ${r} } from "./events/${r}";
|
|
2680
2710
|
`,i=s.lastIndexOf("import "),a=s.indexOf(`
|
|
2681
|
-
`,i);s=`${s.slice(0,a+1)}${
|
|
2682
|
-
`),await this.updateChangelog(n,
|
|
2683
|
-
`,void 0,{showArrow:!1,showTimestamp:!1,showLevel:!1,useSymbol:!1});return}if(e.success(`${
|
|
2684
|
-
`)[0]??null}catch{return null}}async getCommitsSinceTag(e,t){let s=e?`${e}..HEAD`:"HEAD",
|
|
2685
|
-
`)){let[d,
|
|
2686
|
-
`;for(let
|
|
2687
|
-
### ${
|
|
2688
|
-
|
|
2689
|
-
`;for(let
|
|
2690
|
-
`}}let
|
|
2691
|
-
${
|
|
2692
|
-
${m.slice(
|
|
2693
|
-
${m.slice(f.index)}`;else
|
|
2694
|
-
|
|
2695
|
-
${
|
|
2696
|
-
`}else
|
|
2697
|
-
|
|
2698
|
-
${
|
|
2699
|
-
`;await Bun.write(
|
|
2711
|
+
`,i);s=`${s.slice(0,a+1)}${o}${s.slice(a+1)}`;let n=/(events:\s*\[)([^\]]*)/s,l=s.match(n);if(l){let d=l[2]?.trim(),u=d?`${d}, ${r}`:r;s=s.replace(n,`$1${u}`)}await Bun.write(e,s)}async run(e){let{name:t,module:s,channel:r}=e;if(!t)t=await A({message:"Enter name"});if(t=Ft(t).replace(/PubSub$/,""),!r)r=fp(t);let o=Xi.replace(/{{NAME}}/g,t).replace(/{{CHANNEL}}/g,r),i=s?$("modules",s):".",a=$(i,"src","events"),n=$(process.cwd(),a),l=$(n,`${t}Event.ts`);await Bun.write(l,o);let d=Zi.replace(/{{NAME}}/g,t),u=$(i,"tests","events"),h=$(process.cwd(),u),m=$(h,`${t}Event.spec.ts`);await Bun.write(m,d);let c=s?Ft(s):Ft(up(process.cwd())),p=$(process.cwd(),i,"src",`${c}Module.ts`);if(await Bun.file(p).exists())await this.addToModule(p,t);let f=new hp;f.success(`${$(a,t)}Event.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),f.success(`${$(u,t)}Event.spec.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0});let y=$(process.cwd(),"package.json"),g=await Bun.file(y).json(),b=g.dependencies??{},x=g.devDependencies??{};if(!b["@ooneex/pub-sub"]&&!x["@ooneex/pub-sub"])await Bun.spawn(["bun","add","@ooneex/pub-sub"],{cwd:process.cwd(),stdout:"ignore",stderr:"inherit"}).exited}}tt=w([E.command()],tt);import{readdir as yp}from"fs/promises";import{join as me}from"path";import{TerminalLogger as gp}from"@ooneex/logger";var{$:ue}=globalThis.Bun;var bp={feat:"Added",fix:"Fixed",refactor:"Changed",perf:"Changed",style:"Changed",docs:"Changed",build:"Changed",ci:"Changed",chore:"Changed",revert:"Removed"};class st{getName(){return"make:release"}getDescription(){return"Release packages with version bump, changelog, and git tag"}async run(){let e=new gp,t=process.cwd(),s=[];for(let{name:a,type:n}of[{name:"packages",type:"package"},{name:"modules",type:"module"}])try{let l=await yp(me(t,a),{withFileTypes:!0});s.push(...l.filter((d)=>d.isDirectory()).map((d)=>({base:me(a,d.name),type:n})))}catch{}let r={showTimestamp:!1,showArrow:!1,useSymbol:!0};if(s.length===0){e.error("No packages or modules found",void 0,r);return}let o=0;for(let a of s){let n=me(t,a.base),l=me(n,"package.json"),d=Bun.file(l);if(!await d.exists())continue;let u=await d.json(),h=await this.getLastTag(u.name),m=await this.getCommitsSinceTag(h,a.base);if(m.length===0)continue;let c=this.determineBumpType(m),p=this.bumpVersion(u.version,c);u.version=p;let f=`${u.name}@${p}`;await Bun.write(l,`${JSON.stringify(u,null,2)}
|
|
2712
|
+
`),await this.updateChangelog(n,p,f,m),await this.gitAdd(me(a.base,"package.json"),me(a.base,"CHANGELOG.md")),await this.gitCommit(`chore(release): ${u.name}@${p}`),await this.gitTag(f,`chore(release): ${u.name}@${p}`),e.success(`${u.name}@${p} released (${c} bump, ${m.length} commit(s))`,void 0,r),o++}if(o===0){e.info(`No packages have unreleased commits
|
|
2713
|
+
`,void 0,{showArrow:!1,showTimestamp:!1,showLevel:!1,useSymbol:!1});return}if(e.success(`${o} package(s) released`,void 0,r),await ge({message:"Push commits and tags to remote?"}))try{await ue`git push && git push --tags`,e.success("Pushed commits and tags to remote",void 0,r)}catch{e.error("Failed to push to remote",void 0,r)}}async getLastTag(e){try{let s=(await ue`git --no-pager tag --list "${e}@*" --sort=-v:refname`.quiet()).text().trim();if(!s)return null;return s.split(`
|
|
2714
|
+
`)[0]??null}catch{return null}}async getCommitsSinceTag(e,t){let s=e?`${e}..HEAD`:"HEAD",r="%H|%an|%s";try{let i=(await ue`git --no-pager log ${s} --format=${"%H|%an|%s"} -- ${t}`.quiet()).text().trim();if(!i)return[];let a=[],n=/^([a-z]+)\(([^)]+)\):\s*(.+)$/;for(let l of i.split(`
|
|
2715
|
+
`)){let[d,u,...h]=l.split("|"),m=h.join("|");if(!d||!u||!m)continue;let c=m.match(n);if(c){let[,p,f,y]=c;if(p&&f&&y)a.push({hash:d.substring(0,8),type:p,scope:f,subject:y,author:u})}}return a}catch{return[]}}determineBumpType(e){for(let t of e)if(t.type==="feat")return"minor";return"patch"}bumpVersion(e,t){let s=e.split(".").map(Number),[r=0,o=0,i=0]=s;if(t==="minor")return`${r}.${o+1}.0`;return`${r}.${o}.${i+1}`}async getRepoUrl(){try{return(await ue`git --no-pager remote get-url origin`.quiet()).text().trim().replace(/\.git$/,"").replace(/^git@([^:]+):/,"https://$1/")}catch{return null}}async updateChangelog(e,t,s,r){let o=me(e,"CHANGELOG.md"),i=new Date().toISOString().split("T")[0],a=await this.getRepoUrl(),n=new Map;for(let p of r){let f=bp[p.type]??"Changed",y=n.get(f)??[];y.push(p),n.set(f,y)}let l=["Added","Changed","Deprecated","Removed","Fixed","Security"],u=`## ${a?`[${t}](${a}/releases/tag/${s})`:`[${t}]`} - ${i}
|
|
2716
|
+
`;for(let p of l){let f=n.get(p);if(!f||f.length===0)continue;u+=`
|
|
2717
|
+
### ${p}
|
|
2718
|
+
|
|
2719
|
+
`;for(let y of f){let g=a?` ([${y.hash}](${a}/commit/${y.hash}))`:"";u+=`- ${y.subject} \u2014 ${y.author}${g}
|
|
2720
|
+
`}}let h=Bun.file(o),m="";if(await h.exists())m=await h.text();let c;if(m){let p=m.match(/## \[Unreleased\][^\n]*\n/),f=m.match(/## \[\d+\.\d+\.\d+\]/);if(p){let y=(p.index??0)+p[0].length;c=`${m.slice(0,y)}
|
|
2721
|
+
${u}
|
|
2722
|
+
${m.slice(y)}`}else if(f&&f.index!==void 0)c=`${m.slice(0,f.index)}${u}
|
|
2723
|
+
${m.slice(f.index)}`;else c=`${m.trimEnd()}
|
|
2724
|
+
|
|
2725
|
+
${u}
|
|
2726
|
+
`}else c=`# Changelog
|
|
2727
|
+
|
|
2728
|
+
${u}
|
|
2729
|
+
`;await Bun.write(o,c)}async gitAdd(...e){await ue`git add ${e}`}async gitCommit(e){await ue`git commit --no-verify -m ${e}`}async gitTag(e,t){await ue`git tag -a ${e} -m ${t}`}}st=w([E.command()],st);import{join as Q}from"path";import{TerminalLogger as Ep}from"@ooneex/logger";import{toPascalCase as vp}from"@ooneex/utils";var ji=`import { describe, expect, test } from "bun:test";
|
|
2700
2730
|
import { {{NAME}}Repository } from "@/repositories/{{NAME}}Repository";
|
|
2701
2731
|
|
|
2702
2732
|
describe("{{NAME}}Repository", () => {
|
|
@@ -2883,7 +2913,7 @@ export class {{NAME}}Repository {
|
|
|
2883
2913
|
return await repository.count(criteria ? { where: criteria } : {});
|
|
2884
2914
|
}
|
|
2885
2915
|
}
|
|
2886
|
-
`;class we{getName(){return"make:repository"}getDescription(){return"Generate a new repository class"}async run(e){let{name:t,module:s}=e;if(!t)t=await A({message:"Enter repository name"});t=
|
|
2916
|
+
`;class we{getName(){return"make:repository"}getDescription(){return"Generate a new repository class"}async run(e){let{name:t,module:s}=e;if(!t)t=await A({message:"Enter repository name"});t=vp(t).replace(/Repository$/,"");let r=Ji.replace(/{{NAME}}/g,t),o=s?Q("modules",s):".",i=Q(o,"src","repositories"),a=Q(process.cwd(),i),n=Q(a,`${t}Repository.ts`);await Bun.write(n,r);let l=ji.replace(/{{NAME}}/g,t),d=Q(o,"tests","repositories"),u=Q(process.cwd(),d),h=Q(u,`${t}Repository.spec.ts`);await Bun.write(h,l);let m=new Ep;m.success(`${Q(i,t)}Repository.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),m.success(`${Q(d,t)}Repository.spec.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0});let c=Q(process.cwd(),"package.json"),p=await Bun.file(c).json(),f=p.dependencies??{},y=p.devDependencies??{};if(!f["@ooneex/repository"]&&!y["@ooneex/repository"])await Bun.spawn(["bun","add","@ooneex/repository"],{cwd:process.cwd(),stdout:"ignore",stderr:"inherit"}).exited}}we=w([E.command()],we);import{join as M}from"path";var{Glob:$p}=globalThis.Bun;var ea=`import type { LocaleType } from "@ooneex/translation";
|
|
2887
2917
|
import { random } from "@ooneex/utils";
|
|
2888
2918
|
import {
|
|
2889
2919
|
Column,
|
|
@@ -2942,7 +2972,7 @@ export class BookEntity {
|
|
|
2942
2972
|
@UpdateDateColumn({ name: "updated_at" })
|
|
2943
2973
|
updatedAt?: Date | null;
|
|
2944
2974
|
}
|
|
2945
|
-
`;var
|
|
2975
|
+
`;var ta=`import { decorator, type IMigration, type MigrationClassType } from '@ooneex/migrations';
|
|
2946
2976
|
import type { TransactionSQL } from 'bun';
|
|
2947
2977
|
|
|
2948
2978
|
@decorator.migration()
|
|
@@ -2985,7 +3015,7 @@ export class {{ name }} implements IMigration {
|
|
|
2985
3015
|
return [];
|
|
2986
3016
|
}
|
|
2987
3017
|
}
|
|
2988
|
-
`;var
|
|
3018
|
+
`;var sa=`import { inject } from "@ooneex/container";
|
|
2989
3019
|
import type { ITypeormDatabase } from "@ooneex/database";
|
|
2990
3020
|
import { decorator } from "@ooneex/repository";
|
|
2991
3021
|
import type { FilterResultType } from "@ooneex/types";
|
|
@@ -3109,7 +3139,7 @@ export class BookRepository {
|
|
|
3109
3139
|
return await repository.count(criteria ? { where: criteria } : {});
|
|
3110
3140
|
}
|
|
3111
3141
|
}
|
|
3112
|
-
`;var
|
|
3142
|
+
`;var ra=`import type { ContextType } from "@ooneex/controller";
|
|
3113
3143
|
import { inject } from "@ooneex/container";
|
|
3114
3144
|
import { ERole } from "@ooneex/role";
|
|
3115
3145
|
import { Route } from "@ooneex/routing";
|
|
@@ -3133,7 +3163,7 @@ type CreateBookRouteType = {
|
|
|
3133
3163
|
lang?: LocaleType;
|
|
3134
3164
|
status?: string;
|
|
3135
3165
|
};
|
|
3136
|
-
response: BookEntity |
|
|
3166
|
+
response: BookEntity | Record<string, never>;
|
|
3137
3167
|
};
|
|
3138
3168
|
|
|
3139
3169
|
@Route.post("/books", {
|
|
@@ -3181,7 +3211,7 @@ export class CreateBookController {
|
|
|
3181
3211
|
|
|
3182
3212
|
const book = await this.service.execute({ title, color, description, summarize, pageCount, src, coverImage, tags, topics, categories, lang, status });
|
|
3183
3213
|
|
|
3184
|
-
return context.response.json(book);
|
|
3214
|
+
return context.response.json(book || {});
|
|
3185
3215
|
}
|
|
3186
3216
|
}
|
|
3187
3217
|
`;var oa=`import type { ContextType } from "@ooneex/controller";
|
|
@@ -3221,7 +3251,7 @@ export class DeleteBookController {
|
|
|
3221
3251
|
return context.response.json({ id });
|
|
3222
3252
|
}
|
|
3223
3253
|
}
|
|
3224
|
-
`;var
|
|
3254
|
+
`;var ia=`import type { ContextType } from "@ooneex/controller";
|
|
3225
3255
|
import { inject } from "@ooneex/container";
|
|
3226
3256
|
import { ERole } from "@ooneex/role";
|
|
3227
3257
|
import { Route } from "@ooneex/routing";
|
|
@@ -3231,7 +3261,7 @@ import { GetBookService } from "../services/GetBookService";
|
|
|
3231
3261
|
|
|
3232
3262
|
type GetBookRouteType = {
|
|
3233
3263
|
params: { id: string };
|
|
3234
|
-
response: BookEntity |
|
|
3264
|
+
response: BookEntity | Record<string, never>;
|
|
3235
3265
|
};
|
|
3236
3266
|
|
|
3237
3267
|
@Route.get("/books/:id", {
|
|
@@ -3253,10 +3283,10 @@ export class GetBookController {
|
|
|
3253
3283
|
|
|
3254
3284
|
const book = await this.service.execute({ id });
|
|
3255
3285
|
|
|
3256
|
-
return context.response.json(book);
|
|
3286
|
+
return context.response.json(book || {});
|
|
3257
3287
|
}
|
|
3258
3288
|
}
|
|
3259
|
-
`;var
|
|
3289
|
+
`;var aa=`import type { ContextType } from "@ooneex/controller";
|
|
3260
3290
|
import { inject } from "@ooneex/container";
|
|
3261
3291
|
import { ERole } from "@ooneex/role";
|
|
3262
3292
|
import { Route } from "@ooneex/routing";
|
|
@@ -3266,7 +3296,7 @@ import type { BookEntity } from "../entities/BookEntity";
|
|
|
3266
3296
|
import { ListBooksService } from "../services/ListBooksService";
|
|
3267
3297
|
|
|
3268
3298
|
type ListBooksRouteType = {
|
|
3269
|
-
|
|
3299
|
+
queries: { page?: number; limit?: number; q?: string };
|
|
3270
3300
|
response: FilterResultType<BookEntity>;
|
|
3271
3301
|
};
|
|
3272
3302
|
|
|
@@ -3274,7 +3304,7 @@ type ListBooksRouteType = {
|
|
|
3274
3304
|
name: "book.list",
|
|
3275
3305
|
version: 1,
|
|
3276
3306
|
description: "List all books",
|
|
3277
|
-
|
|
3307
|
+
queries: Assert({
|
|
3278
3308
|
page: "number?",
|
|
3279
3309
|
limit: "number?",
|
|
3280
3310
|
q: "string?",
|
|
@@ -3287,14 +3317,14 @@ export class ListBooksController {
|
|
|
3287
3317
|
) {}
|
|
3288
3318
|
|
|
3289
3319
|
public async index(context: ContextType<ListBooksRouteType>) {
|
|
3290
|
-
const { page, limit, q } = context.
|
|
3320
|
+
const { page, limit, q } = context.queries;
|
|
3291
3321
|
|
|
3292
3322
|
const result = await this.service.execute({ page, limit, q });
|
|
3293
3323
|
|
|
3294
3324
|
return context.response.json(result);
|
|
3295
3325
|
}
|
|
3296
3326
|
}
|
|
3297
|
-
`;var
|
|
3327
|
+
`;var na=`import type { ContextType } from "@ooneex/controller";
|
|
3298
3328
|
import { inject } from "@ooneex/container";
|
|
3299
3329
|
import { ERole } from "@ooneex/role";
|
|
3300
3330
|
import { Route } from "@ooneex/routing";
|
|
@@ -3319,7 +3349,7 @@ type UpdateBookRouteType = {
|
|
|
3319
3349
|
lang?: LocaleType;
|
|
3320
3350
|
status?: string;
|
|
3321
3351
|
};
|
|
3322
|
-
response: BookEntity |
|
|
3352
|
+
response: BookEntity | Record<string, never>;
|
|
3323
3353
|
};
|
|
3324
3354
|
|
|
3325
3355
|
@Route.patch("/books/:id", {
|
|
@@ -3371,10 +3401,10 @@ export class UpdateBookController {
|
|
|
3371
3401
|
|
|
3372
3402
|
const book = await this.service.execute({ id, title, color, description, summarize, pageCount, src, coverImage, tags, topics, categories, lang, status });
|
|
3373
3403
|
|
|
3374
|
-
return context.response.json(book);
|
|
3404
|
+
return context.response.json(book || {});
|
|
3375
3405
|
}
|
|
3376
3406
|
}
|
|
3377
|
-
`;var
|
|
3407
|
+
`;var la=`import { inject } from "@ooneex/container";
|
|
3378
3408
|
import { decorator } from "@ooneex/service";
|
|
3379
3409
|
import type { IService } from "@ooneex/service";
|
|
3380
3410
|
import type { LocaleType } from "@ooneex/translation";
|
|
@@ -3397,12 +3427,12 @@ type ServiceDataType = {
|
|
|
3397
3427
|
};
|
|
3398
3428
|
|
|
3399
3429
|
@decorator.service()
|
|
3400
|
-
export class CreateBookService
|
|
3430
|
+
export class CreateBookService implements IService {
|
|
3401
3431
|
constructor(
|
|
3402
3432
|
@inject(BookRepository) private readonly repository: BookRepository,
|
|
3403
3433
|
) {}
|
|
3404
3434
|
|
|
3405
|
-
public async execute(data?:
|
|
3435
|
+
public async execute(data?: ServiceDataType): Promise<BookEntity | null> {
|
|
3406
3436
|
if (!data) return null;
|
|
3407
3437
|
|
|
3408
3438
|
const book = new BookEntity();
|
|
@@ -3422,7 +3452,7 @@ export class CreateBookService<T extends ServiceDataType = ServiceDataType> impl
|
|
|
3422
3452
|
return await this.repository.create(book);
|
|
3423
3453
|
}
|
|
3424
3454
|
}
|
|
3425
|
-
`;var
|
|
3455
|
+
`;var da=`import { inject } from "@ooneex/container";
|
|
3426
3456
|
import { decorator } from "@ooneex/service";
|
|
3427
3457
|
import type { IService } from "@ooneex/service";
|
|
3428
3458
|
import { BookRepository } from "../repositories/BookRepository";
|
|
@@ -3432,18 +3462,18 @@ type ServiceDataType = {
|
|
|
3432
3462
|
};
|
|
3433
3463
|
|
|
3434
3464
|
@decorator.service()
|
|
3435
|
-
export class DeleteBookService
|
|
3465
|
+
export class DeleteBookService implements IService {
|
|
3436
3466
|
constructor(
|
|
3437
3467
|
@inject(BookRepository) private readonly repository: BookRepository,
|
|
3438
3468
|
) {}
|
|
3439
3469
|
|
|
3440
|
-
public async execute(data?:
|
|
3470
|
+
public async execute(data?: ServiceDataType): Promise<void> {
|
|
3441
3471
|
if (!data) return;
|
|
3442
3472
|
|
|
3443
3473
|
await this.repository.delete({ id: data.id });
|
|
3444
3474
|
}
|
|
3445
3475
|
}
|
|
3446
|
-
`;var
|
|
3476
|
+
`;var ca=`import { inject } from "@ooneex/container";
|
|
3447
3477
|
import { decorator } from "@ooneex/service";
|
|
3448
3478
|
import type { IService } from "@ooneex/service";
|
|
3449
3479
|
import { BookEntity } from "../entities/BookEntity";
|
|
@@ -3454,12 +3484,12 @@ type ServiceDataType = {
|
|
|
3454
3484
|
};
|
|
3455
3485
|
|
|
3456
3486
|
@decorator.service()
|
|
3457
|
-
export class GetBookService
|
|
3487
|
+
export class GetBookService implements IService {
|
|
3458
3488
|
constructor(
|
|
3459
3489
|
@inject(BookRepository) private readonly repository: BookRepository,
|
|
3460
3490
|
) {}
|
|
3461
3491
|
|
|
3462
|
-
public async execute(data?:
|
|
3492
|
+
public async execute(data?: ServiceDataType): Promise<BookEntity | null> {
|
|
3463
3493
|
if (!data) return null;
|
|
3464
3494
|
|
|
3465
3495
|
return await this.repository.findOne(data.id);
|
|
@@ -3479,12 +3509,12 @@ type ServiceDataType = {
|
|
|
3479
3509
|
};
|
|
3480
3510
|
|
|
3481
3511
|
@decorator.service()
|
|
3482
|
-
export class ListBooksService
|
|
3512
|
+
export class ListBooksService implements IService {
|
|
3483
3513
|
constructor(
|
|
3484
3514
|
@inject(BookRepository) private readonly repository: BookRepository,
|
|
3485
3515
|
) {}
|
|
3486
3516
|
|
|
3487
|
-
public async execute(data?:
|
|
3517
|
+
public async execute(data?: ServiceDataType): Promise<FilterResultType<BookEntity>> {
|
|
3488
3518
|
return await this.repository.find({
|
|
3489
3519
|
page: data?.page,
|
|
3490
3520
|
limit: data?.limit,
|
|
@@ -3492,7 +3522,7 @@ export class ListBooksService<T extends ServiceDataType = ServiceDataType> imple
|
|
|
3492
3522
|
});
|
|
3493
3523
|
}
|
|
3494
3524
|
}
|
|
3495
|
-
`;var
|
|
3525
|
+
`;var ma=`import { inject } from "@ooneex/container";
|
|
3496
3526
|
import { decorator } from "@ooneex/service";
|
|
3497
3527
|
import type { IService } from "@ooneex/service";
|
|
3498
3528
|
import type { LocaleType } from "@ooneex/translation";
|
|
@@ -3516,12 +3546,12 @@ type ServiceDataType = {
|
|
|
3516
3546
|
};
|
|
3517
3547
|
|
|
3518
3548
|
@decorator.service()
|
|
3519
|
-
export class UpdateBookService
|
|
3549
|
+
export class UpdateBookService implements IService {
|
|
3520
3550
|
constructor(
|
|
3521
3551
|
@inject(BookRepository) private readonly repository: BookRepository,
|
|
3522
3552
|
) {}
|
|
3523
3553
|
|
|
3524
|
-
public async execute(data?:
|
|
3554
|
+
public async execute(data?: ServiceDataType): Promise<BookEntity | null> {
|
|
3525
3555
|
if (!data) return null;
|
|
3526
3556
|
|
|
3527
3557
|
const { id, ...fields } = data;
|
|
@@ -3531,7 +3561,7 @@ export class UpdateBookService<T extends ServiceDataType = ServiceDataType> impl
|
|
|
3531
3561
|
return await this.repository.findOne(id);
|
|
3532
3562
|
}
|
|
3533
3563
|
}
|
|
3534
|
-
`;import{join as
|
|
3564
|
+
`;import{join as Z}from"path";import{TerminalLogger as Up}from"@ooneex/logger";import{toPascalCase as Gp}from"@ooneex/utils";var ua=`import { describe, expect, test } from "bun:test";
|
|
3535
3565
|
import { {{NAME}}Service } from "@/services/{{NAME}}Service";
|
|
3536
3566
|
|
|
3537
3567
|
describe("{{NAME}}Service", () => {
|
|
@@ -3544,24 +3574,25 @@ describe("{{NAME}}Service", () => {
|
|
|
3544
3574
|
expect(typeof {{NAME}}Service.prototype.execute).toBe("function");
|
|
3545
3575
|
});
|
|
3546
3576
|
});
|
|
3547
|
-
`;var
|
|
3577
|
+
`;var ha=`import { decorator } from "@ooneex/service";
|
|
3548
3578
|
import type { IService } from "@ooneex/service";
|
|
3549
3579
|
|
|
3550
3580
|
type ServiceDataType = Record<string, unknown>;
|
|
3551
3581
|
|
|
3552
3582
|
@decorator.service()
|
|
3553
|
-
export class {{NAME}}Service
|
|
3554
|
-
|
|
3583
|
+
export class {{NAME}}Service implements IService {
|
|
3584
|
+
// biome-ignore lint/suspicious/noExplicitAny: trust me
|
|
3585
|
+
public async execute(data?: ServiceDataType): Promise<any> {
|
|
3555
3586
|
// TODO: Implement service logic
|
|
3556
3587
|
}
|
|
3557
3588
|
}
|
|
3558
|
-
`;class Ee{getName(){return"make:service"}getDescription(){return"Generate a new service class"}async run(e){let{name:t,module:s}=e;if(!t)t=await A({message:"Enter service name"});t=
|
|
3589
|
+
`;class Ee{getName(){return"make:service"}getDescription(){return"Generate a new service class"}async run(e){let{name:t,module:s}=e;if(!t)t=await A({message:"Enter service name"});t=Gp(t).replace(/Service$/,"");let r=ha.replace(/{{NAME}}/g,t),o=s?Z("modules",s):".",i=Z(o,"src","services"),a=Z(process.cwd(),i),n=Z(a,`${t}Service.ts`);await Bun.write(n,r);let l=ua.replace(/{{NAME}}/g,t),d=Z(o,"tests","services"),u=Z(process.cwd(),d),h=Z(u,`${t}Service.spec.ts`);await Bun.write(h,l);let m=new Up;m.success(`${Z(i,t)}Service.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),m.success(`${Z(d,t)}Service.spec.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0});let c=Z(process.cwd(),"package.json"),p=await Bun.file(c).json(),f=p.dependencies??{},y=p.devDependencies??{};if(!f["@ooneex/service"]&&!y["@ooneex/service"])await Bun.spawn(["bun","add","@ooneex/service"],{cwd:process.cwd(),stdout:"ignore",stderr:"inherit"}).exited}}Ee=w([E.command()],Ee);class rt{getName(){return"make:resource:book"}getDescription(){return"Generate book resource (entity, migration, repository)"}async run(){let t=M("modules","book");await new le().run({name:"book",silent:!0,skipMigrations:!1,skipSeeds:!0}),await new be().run({name:"Book",module:"book",tableName:"books"}),await new xe().run({module:"book"}),await new we().run({name:"Book",module:"book"});let a=new ne,n=[{name:"CreateBook",route:{name:"book.create",path:"/books",method:"POST"}},{name:"GetBook",route:{name:"book.get",path:"/books/:id",method:"GET"}},{name:"ListBooks",route:{name:"book.list",path:"/books",method:"GET"}},{name:"UpdateBook",route:{name:"book.update",path:"/books/:id",method:"PATCH"}},{name:"DeleteBook",route:{name:"book.delete",path:"/books/:id",method:"DELETE"}}];for(let y of n)await a.run({...y,module:"book",isSocket:!1});let l=M(process.cwd(),t,"src","controllers");await Bun.write(M(l,"CreateBookController.ts"),ra),await Bun.write(M(l,"GetBookController.ts"),ia),await Bun.write(M(l,"ListBooksController.ts"),aa),await Bun.write(M(l,"UpdateBookController.ts"),na),await Bun.write(M(l,"DeleteBookController.ts"),oa);let d=new Ee,u=["CreateBook","GetBook","ListBooks","UpdateBook","DeleteBook"];for(let y of u)await d.run({name:y,module:"book"});let h=M(process.cwd(),t,"src","services");await Bun.write(M(h,"CreateBookService.ts"),la),await Bun.write(M(h,"GetBookService.ts"),ca),await Bun.write(M(h,"ListBooksService.ts"),pa),await Bun.write(M(h,"UpdateBookService.ts"),ma),await Bun.write(M(h,"DeleteBookService.ts"),da);let m=M(process.cwd(),t,"src","entities","BookEntity.ts");await Bun.write(m,ea);let c=M(process.cwd(),t,"src","migrations"),p=new $p("Migration*.ts");for await(let y of p.scan(c)){if(y==="migrations.ts")continue;let g=y.replace(/\.ts$/,""),b=g.replace("Migration",""),x=ta.replaceAll("{{ name }}",g).replaceAll("{{ version }}",b);await Bun.write(M(c,y),x)}let f=M(process.cwd(),t,"src","repositories","BookRepository.ts");await Bun.write(f,sa)}}rt=w([E.command()],rt);import{join as ot}from"path";import{TerminalLogger as Wp}from"@ooneex/logger";import{seedCreate as Fp}from"@ooneex/seeds";var fa=`#!/usr/bin/env bun
|
|
3559
3590
|
|
|
3560
3591
|
import { seedRun } from "@ooneex/seeds";
|
|
3561
3592
|
import "@/seeds/seeds";
|
|
3562
3593
|
|
|
3563
3594
|
await seedRun();
|
|
3564
|
-
`;class it{getName(){return"make:seed"}getDescription(){return"Generate a new seed file"}async run(e){let{name:t,module:s}=e;if(!t)t=await A({message:"Enter seed name"});let
|
|
3595
|
+
`;class it{getName(){return"make:seed"}getDescription(){return"Generate a new seed file"}async run(e){let{name:t,module:s}=e;if(!t)t=await A({message:"Enter seed name"});let r=s?ot("modules",s):".",o=await Fp({name:t,dir:ot(r,"src/seeds")}),i=ot(process.cwd(),r,"bin","seed","run.ts");if(!await Bun.file(i).exists())await Bun.write(i,fa);let n=ot(process.cwd(),"package.json"),l=Bun.file(n);if(await l.exists()){let c=await l.json();c.scripts=c.scripts||{},c.scripts["seed:run"]="bun ./bin/seed/run.ts",await Bun.write(n,JSON.stringify(c,null,2))}let d=new Wp;d.success(`${o} created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),d.info("Run 'bun run seed:run' to execute seeds",void 0,{showTimestamp:!1,showArrow:!0,showLevel:!1});let u=await Bun.file(n).json(),h=u.dependencies??{},m=u.devDependencies??{};if(!h["@ooneex/seeds"]&&!m["@ooneex/seeds"])await Bun.spawn(["bun","add","--dev","@ooneex/seeds"],{cwd:process.cwd(),stdout:"ignore",stderr:"inherit"}).exited}}it=w([E.command()],it);import{join as X}from"path";import{TerminalLogger as Vp}from"@ooneex/logger";import{toPascalCase as zp,toSnakeCase as Yp}from"@ooneex/utils";var ya=`import { describe, expect, test } from "bun:test";
|
|
3565
3596
|
import { {{NAME}}StorageAdapter } from "@/storage/{{NAME}}StorageAdapter";
|
|
3566
3597
|
|
|
3567
3598
|
describe("{{NAME}}StorageAdapter", () => {
|
|
@@ -3578,7 +3609,7 @@ describe("{{NAME}}StorageAdapter", () => {
|
|
|
3578
3609
|
expect(typeof {{NAME}}StorageAdapter.prototype.getOptions).toBe("function");
|
|
3579
3610
|
});
|
|
3580
3611
|
});
|
|
3581
|
-
`;var
|
|
3612
|
+
`;var ga=`import { Storage, decorator, StorageException } from "@ooneex/storage";
|
|
3582
3613
|
import type { S3Options } from "bun";
|
|
3583
3614
|
|
|
3584
3615
|
@decorator.storage()
|
|
@@ -3633,7 +3664,7 @@ export class {{NAME}}Storage extends Storage {
|
|
|
3633
3664
|
};
|
|
3634
3665
|
}
|
|
3635
3666
|
}
|
|
3636
|
-
`;class at{getName(){return"make:storage"}getDescription(){return"Generate a new storage class"}async run(e){let{name:t,module:s}=e;if(!t)t=await A({message:"Enter storage name"});t=
|
|
3667
|
+
`;class at{getName(){return"make:storage"}getDescription(){return"Generate a new storage class"}async run(e){let{name:t,module:s}=e;if(!t)t=await A({message:"Enter storage name"});t=zp(t).replace(/Storage$/,"");let r=Yp(t).toUpperCase(),o=ga.replace(/{{NAME}}/g,t).replace(/{{NAME_UPPER}}/g,r),i=s?X("modules",s):".",a=X(i,"src","storage"),n=X(process.cwd(),a),l=X(n,`${t}Storage.ts`);await Bun.write(l,o);let d=ya.replace(/{{NAME}}/g,t),u=X(i,"tests","storage"),h=X(process.cwd(),u),m=X(h,`${t}Storage.spec.ts`);await Bun.write(m,d);let c=new Vp;c.success(`${X(a,t)}Storage.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),c.success(`${X(u,t)}Storage.spec.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0});let p=X(process.cwd(),"package.json"),f=await Bun.file(p).json(),y=f.dependencies??{},g=f.devDependencies??{};if(!y["@ooneex/storage"]&&!g["@ooneex/storage"])await Bun.spawn(["bun","add","@ooneex/storage"],{cwd:process.cwd(),stdout:"ignore",stderr:"inherit"}).exited}}at=w([E.command()],at);import{join as j}from"path";import{TerminalLogger as Xp}from"@ooneex/logger";import{toPascalCase as jp}from"@ooneex/utils";var ba=`import { describe, expect, test } from "bun:test";
|
|
3637
3668
|
import { {{NAME}}VectorDatabase } from "@/databases/{{NAME}}VectorDatabase";
|
|
3638
3669
|
|
|
3639
3670
|
describe("{{NAME}}VectorDatabase", () => {
|
|
@@ -3656,7 +3687,7 @@ describe("{{NAME}}VectorDatabase", () => {
|
|
|
3656
3687
|
expect(typeof {{NAME}}VectorDatabase.prototype.getSchema).toBe("function");
|
|
3657
3688
|
});
|
|
3658
3689
|
});
|
|
3659
|
-
`;var
|
|
3690
|
+
`;var xa=`import { VectorDatabase, decorator } from "@ooneex/rag";
|
|
3660
3691
|
import type { EmbeddingModelType, EmbeddingProviderType, FieldValueType } from "@ooneex/rag";
|
|
3661
3692
|
import { Utf8 } from "apache-arrow";
|
|
3662
3693
|
|
|
@@ -3680,8 +3711,8 @@ export class {{NAME}}VectorDatabase extends VectorDatabase<DataType> {
|
|
|
3680
3711
|
};
|
|
3681
3712
|
}
|
|
3682
3713
|
}
|
|
3683
|
-
`;class nt{getName(){return"make:vector-database"}getDescription(){return"Generate a new vector database class"}async run(e){let{name:t,module:s}=e;if(!t)t=await A({message:"Enter vector database name"});t=
|
|
3684
|
-
`),process.exit(1);var
|
|
3685
|
-
`),process.exit(1);var sm={name:
|
|
3714
|
+
`;class nt{getName(){return"make:vector-database"}getDescription(){return"Generate a new vector database class"}async run(e){let{name:t,module:s}=e;if(!t)t=await A({message:"Enter vector database name"});t=jp(t).replace(/VectorDatabase$/,"").replace(/Database$/,"");let r=xa.replace(/{{NAME}}/g,t),o=s?j("modules",s):".",i=j(o,"src","databases"),a=j(process.cwd(),i),n=j(a,`${t}VectorDatabase.ts`);await Bun.write(n,r);let l=ba.replace(/{{NAME}}/g,t),d=j(o,"tests","databases"),u=j(process.cwd(),d),h=j(u,`${t}VectorDatabase.spec.ts`);await Bun.write(h,l);let m=new Xp;m.success(`${j(i,t)}VectorDatabase.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),m.success(`${j(d,t)}VectorDatabase.spec.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0});let c=j(process.cwd(),"package.json"),p=await Bun.file(c).json(),f=p.dependencies??{},y=p.devDependencies??{};if(!f["@ooneex/rag"]&&!y["@ooneex/rag"])await Bun.spawn(["bun","add","@ooneex/rag"],{cwd:process.cwd(),stdout:"ignore",stderr:"inherit"}).exited}}nt=w([E.command()],nt);var{values:J,positionals:tm}=Jp({args:Bun.argv,options:{name:{type:"string"},"route-name":{type:"string"},"route-path":{type:"string"},"route-method":{type:"string"},"is-socket":{type:"boolean"},dir:{type:"string"},channel:{type:"string"},"table-name":{type:"string"},module:{type:"string"},destination:{type:"string"}},strict:!1,allowPositionals:!0}),Kt=new em,Ea=tm[2];if(!Ea)Kt.error(`Command name is required
|
|
3715
|
+
`),process.exit(1);var va=Vt(Ea);if(!va)Kt.info(`No commands found
|
|
3716
|
+
`),process.exit(1);var sm={name:J.name,dir:J.dir,channel:J.channel,isSocket:J["is-socket"],tableName:J["table-name"],module:J.module,destination:J.destination,route:{name:J["route-name"],path:J["route-path"],method:J["route-method"]}};try{await va.run(sm)}catch(e){let t=e instanceof wa?e:new wa(e instanceof Error?e:String(e));Kt.error(t,void 0,{showArrow:!1,showTimestamp:!1,showLevel:!1}),process.exit(1)}
|
|
3686
3717
|
|
|
3687
|
-
//# debugId=
|
|
3718
|
+
//# debugId=B49D739667F8381F64756E2164756E21
|