@ooneex/cli 1.3.0 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +286 -120
- package/dist/index.js.map +5 -5
- 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
|
|
4
|
-
`),d=i.length;if(d>0&&i.includes("unstyle"))i=[...new Set(["unstyle",...i])].reverse();while(d-- >0)n=s(e.styles[i[d]],n,l);return n},r=(a,i,n)=>{e.styles[a]=t({name:a,codes:i}),(e.keys[n]||(e.keys[n]=[])).push(a),Reflect.defineProperty(e,a,{configurable:!0,enumerable:!0,set(d){e.alias(a,d)},get(){let d=(m)=>o(m,d.stack);return Reflect.setPrototypeOf(d,e),d.stack=this.stack?this.stack.concat(a):[a],d}})};return r("reset",[0,0],"modifier"),r("bold",[1,22],"modifier"),r("dim",[2,22],"modifier"),r("italic",[3,23],"modifier"),r("underline",[4,24],"modifier"),r("inverse",[7,27],"modifier"),r("hidden",[8,28],"modifier"),r("strikethrough",[9,29],"modifier"),r("black",[30,39],"color"),r("red",[31,39],"color"),r("green",[32,39],"color"),r("yellow",[33,39],"color"),r("blue",[34,39],"color"),r("magenta",[35,39],"color"),r("cyan",[36,39],"color"),r("white",[37,39],"color"),r("gray",[90,39],"color"),r("grey",[90,39],"color"),r("bgBlack",[40,49],"bg"),r("bgRed",[41,49],"bg"),r("bgGreen",[42,49],"bg"),r("bgYellow",[43,49],"bg"),r("bgBlue",[44,49],"bg"),r("bgMagenta",[45,49],"bg"),r("bgCyan",[46,49],"bg"),r("bgWhite",[47,49],"bg"),r("blackBright",[90,39],"bright"),r("redBright",[91,39],"bright"),r("greenBright",[92,39],"bright"),r("yellowBright",[93,39],"bright"),r("blueBright",[94,39],"bright"),r("magentaBright",[95,39],"bright"),r("cyanBright",[96,39],"bright"),r("whiteBright",[97,39],"bright"),r("bgBlackBright",[100,49],"bgBright"),r("bgRedBright",[101,49],"bgBright"),r("bgGreenBright",[102,49],"bgBright"),r("bgYellowBright",[103,49],"bgBright"),r("bgBlueBright",[104,49],"bgBright"),r("bgMagentaBright",[105,49],"bgBright"),r("bgCyanBright",[106,49],"bgBright"),r("bgWhiteBright",[107,49],"bgBright"),e.ansiRegex=
|
|
5
|
-
`+s,width:r=80}=t,a=(o+s).match(/[^\S\n]/g)||[];r-=a.length;let i=`.{1,${r}}([\\s\\u200B]+|$)|[^\\s\\u200B]+?([\\s\\u200B]+|$)`,n=e.trim(),l=new RegExp(i,"g"),d=n.match(l)||[];if(d=d.map((m)=>m.replace(/\n$/,"")),t.padEnd)d=d.map((m)=>m.padEnd(r," "));if(t.padStart)d=d.map((m)=>m.padStart(r," "));return s+d.join(o)};
|
|
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=ln.exec(e))o.meta=!0,o.shift=/^[A-Z]$/.test(s[1]);else if(s=dn.exec(e)){let r=[...e];if(r[0]==="\x1B"&&r[1]==="\x1B")o.option=!0;let a=[s[1],s[2],s[4],s[6]].filter(Boolean).join(""),i=(s[3]||s[5]||1)-1;o.ctrl=!!(i&4),o.meta=!!(i&10),o.shift=!!(i&1),o.code=a,o.name=mn[a],o.shift=cn(a)||o.shift,o.ctrl=pn(a)||o.ctrl}return o};_e.listen=(e={},t)=>{let{stdin:s}=e;if(!s||s!==process.stdin&&!s.isTTY)throw Error("Invalid stream passed");let o=ns.createInterface({terminal:!0,input:s});ns.emitKeypressEvents(s,o);let r=new nn((n,l)=>t(n,_e(n,l),o)),a=s.isRaw;if(s.isTTY)s.setRawMode(!0);return s.on("keypress",r.enqueue),o.resume(),()=>{if(s.isTTY)s.setRawMode(a);s.removeListener("keypress",r.enqueue),r.destroy(),o.pause(),o.close()}};_e.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};ls.exports=_e});var ms=w((zc,ds)=>{ds.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};un(e,s,o)}};function un(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 a=setInterval(()=>{o.ms=Date.now()-o.start,o.tick++,e.render()},r);return o.stop=()=>{o.loading=!1,clearInterval(a)},Reflect.defineProperty(o,"interval",{value:a}),e.once("close",()=>o.stop()),o.stop}});var us=w((Zc,ps)=>{var{define:hn,width:fn}=R();class cs{constructor(e){let t=e.options;hn(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=fn(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"}}ps.exports=cs});var fs=w((Qc,hs)=>{var ct=R(),C=Ce(),pt={default:C.noop,noop:C.noop,set inverse(e){this._inverse=e},get inverse(){return this._inverse||ct.inverse(this.primary)},set complement(e){this._complement=e},get complement(){return this._complement||ct.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}};pt.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=ct.merge({},pt,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};hs.exports=pt});var ys=w((Xc,gs)=>{var ut=process.platform==="win32",H=Ce(),gn=R(),ht={...H.symbols,upDownDoubleArrow:"\u21D5",upDownDoubleArrow2:"\u2B0D",upDownArrow:"\u2195",asterisk:"*",asterism:"\u2042",bulletWhite:"\u25E6",electricArrow:"\u2301",ellipsisLarge:"\u22EF",ellipsisSmall:"\u2026",fullBlock:"\u2588",identicalTo:"\u2261",indicator:H.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:H.symbols.question,submitted:H.symbols.check,cancelled:H.symbols.cross},separator:{pending:H.symbols.pointerSmall,submitted:H.symbols.middot,cancelled:H.symbols.middot},radio:{off:ut?"( )":"\u25EF",on:ut?"(*)":"\u25C9",disabled:ut?"(|)":"\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"]};ht.merge=(e)=>{let t=gn.merge({},H.symbols,ht,e.symbols);return delete t.merge,t};gs.exports=ht});var ws=w((Jc,bs)=>{var yn=fs(),bn=ys(),wn=R();bs.exports=(e)=>{e.options=wn.merge({},e.options.theme,e.options),e.symbols=bn.merge(e.options),e.styles=yn.merge(e.options)}});var vs=w((Es,As)=>{var xs=process.env.TERM_PROGRAM==="Apple_Terminal",xn=se(),ft=R(),B=As.exports=Es,gt=!1,oe=B.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["+(xs?"8":"u"),savePosition:"\x1B["+(xs?"7":"s"),screen:"\x1B[2J",show:"\x1B[?25h",up:"\x1B[1J"},ne=B.cursor={get hidden(){return gt},hide(){return gt=!0,oe.hide},show(){return gt=!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?ne.left(-e):e>0?ne.right(e):"",s+=t<0?ne.up(-t):t>0?ne.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:a,size:i,value:n}=e;if(o=ft.isPrimitive(o)?String(o):"",r=ft.isPrimitive(r)?String(r):"",n=ft.isPrimitive(n)?String(n):"",i){let l=B.cursor.up(i)+B.cursor.to(this.strLen(a)),d=r.length-s;if(d>0)l+=B.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&&!a.includes(o))l+=this.strLen(o);return B.cursor.move(l)}}},yt=B.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+=B.erase.line+(s<e-1?B.cursor.up(1):"");if(e)t+=B.code.beginning;return t}};B.clear=(e="",t=process.stdout.columns)=>{if(!t)return yt.line+ne.to(0);let s=(a)=>[...xn(a)].length,o=e.split(/\r?\n/),r=0;for(let a of o)r+=1+Math.floor(Math.max(s(a)-1,0)/t);return(yt.line+ne.prevLine()).repeat(r-1)+yt.line+ne.to(0)}});var ue=w((ep,Ts)=>{var En=ye("events"),Ns=se(),bt=mt(),An=ms(),vn=us(),Nn=ws(),D=R(),le=vs();class wt extends En{constructor(e={}){super();this.name=e.name,this.type=e.type,this.options=e,Nn(this),An(this),this.state=new vn(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=Sn(this.options.margin),this.setMaxListeners(0),Tn(this)}async keypress(e,t={}){this.keypressed=!0;let s=bt.action(e,bt(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(le.code.beep)}cursorHide(){this.stdout.write(le.cursor.hide());let e=D.onExit(()=>this.cursorShow());this.on("close",()=>{this.cursorShow(),e()})}cursorShow(){this.stdout.write(le.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(le.cursor.down(e)+le.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:a="",value:i=""}=this,n=this.state.size=s.length,l={after:t,cursor:o,initial:r,input:a,prompt:e,size:n,value:i},d=le.cursor.restore(l);if(d)this.stdout.write(d)}sections(){let{buffer:e,input:t,prompt:s}=this.state;s=Ns(s);let o=Ns(e),r=o.indexOf(s),a=o.slice(0,r),n=o.slice(r).split(`
|
|
7
|
-
`),l=n[0],d=n[n.length-1],h=(s+(t?" "+t:"")).length,
|
|
3
|
+
var di=Object.create;var{getPrototypeOf:mi,defineProperty:Gt,getOwnPropertyNames:ci}=Object;var pi=Object.prototype.hasOwnProperty;function ui(e){return this[e]}var hi,fi,te=(e,t,s)=>{var o=e!=null&&typeof e==="object";if(o){var r=t?hi??=new WeakMap:fi??=new WeakMap,a=r.get(e);if(a)return a}s=e!=null?di(mi(e)):{};let i=t||!e||!e.__esModule?Gt(s,"default",{value:e,enumerable:!0}):s;for(let n of ci(e))if(!pi.call(i,n))Gt(i,n,{get:ui.bind(e,n),enumerable:!0});if(o)r.set(e,i);return i};var x=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var b=function(e,t,s,o){var r=arguments.length,a=r<3?t:o===null?o=Object.getOwnPropertyDescriptor(t,s):o,i;if(typeof Reflect==="object"&&typeof Reflect.decorate==="function")a=Reflect.decorate(e,t,s,o);else for(var n=e.length-1;n>=0;n--)if(i=e[n])a=(r<3?i(a):r>3?i(t,s,a):i(t,s))||a;return r>3&&a&&Object.defineProperty(t,s,a),a};var ye=import.meta.require;var Vt=x((Kc,be)=>{var vi=typeof process<"u"&&process.env.TERM_PROGRAM==="Hyper",Ni=typeof process<"u"&&process.platform==="win32",Kt=typeof process<"u"&&process.platform==="linux",nt={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"},Ht=Object.assign({},nt,{check:"\u221A",cross:"\xD7",ellipsisLarge:"...",ellipsis:"...",info:"i",questionSmall:"?",pointer:">",pointerSmall:"\xBB",radioOff:"( )",radioOn:"(*)",warning:"\u203C"}),Ft=Object.assign({},nt,{ballotCross:"\u2718",check:"\u2714",cross:"\u2716",ellipsisLarge:"\u22EF",ellipsis:"\u2026",info:"\u2139",questionFull:"\uFF1F",questionSmall:"\uFE56",pointer:Kt?"\u25B8":"\u276F",pointerSmall:Kt?"\u2023":"\u203A",radioOff:"\u25EF",radioOn:"\u25C9",warning:"\u26A0"});be.exports=Ni&&!vi?Ht:Ft;Reflect.defineProperty(be.exports,"common",{enumerable:!1,value:nt});Reflect.defineProperty(be.exports,"windows",{enumerable:!1,value:Ht});Reflect.defineProperty(be.exports,"other",{enumerable:!1,value:Ft})});var Ce=x((Hc,lt)=>{var Ti=(e)=>e!==null&&typeof e==="object"&&!Array.isArray(e),Si=/[\u001b\u009b][[\]#;?()]*(?:(?:(?:[^\W_]*;?[^\W_]*)\u0007)|(?:(?:[0-9]{1,4}(;[0-9]{0,4})*)?[~0-9=<>cf-nqrtyA-PRZ]))/g,Ci=()=>{if(typeof process<"u")return process.env.FORCE_COLOR!=="0";return!1},Yt=()=>{let e={enabled:Ci(),visible:!0,styles:{},keys:{}},t=(a)=>{let i=a.open=`\x1B[${a.codes[0]}m`,n=a.close=`\x1B[${a.codes[1]}m`,l=a.regex=new RegExp(`\\u001b\\[${a.codes[1]}m`,"g");return a.wrap=(d,m)=>{if(d.includes(n))d=d.replace(l,n+i);let h=i+d+n;return m?h.replace(/\r*\n/g,`${n}$&${i}`):h},a},s=(a,i,n)=>{return typeof a==="function"?a(i):a.wrap(i,n)},o=(a,i)=>{if(a===""||a==null)return"";if(e.enabled===!1)return a;if(e.visible===!1)return"";let n=""+a,l=n.includes(`
|
|
4
|
+
`),d=i.length;if(d>0&&i.includes("unstyle"))i=[...new Set(["unstyle",...i])].reverse();while(d-- >0)n=s(e.styles[i[d]],n,l);return n},r=(a,i,n)=>{e.styles[a]=t({name:a,codes:i}),(e.keys[n]||(e.keys[n]=[])).push(a),Reflect.defineProperty(e,a,{configurable:!0,enumerable:!0,set(d){e.alias(a,d)},get(){let d=(m)=>o(m,d.stack);return Reflect.setPrototypeOf(d,e),d.stack=this.stack?this.stack.concat(a):[a],d}})};return r("reset",[0,0],"modifier"),r("bold",[1,22],"modifier"),r("dim",[2,22],"modifier"),r("italic",[3,23],"modifier"),r("underline",[4,24],"modifier"),r("inverse",[7,27],"modifier"),r("hidden",[8,28],"modifier"),r("strikethrough",[9,29],"modifier"),r("black",[30,39],"color"),r("red",[31,39],"color"),r("green",[32,39],"color"),r("yellow",[33,39],"color"),r("blue",[34,39],"color"),r("magenta",[35,39],"color"),r("cyan",[36,39],"color"),r("white",[37,39],"color"),r("gray",[90,39],"color"),r("grey",[90,39],"color"),r("bgBlack",[40,49],"bg"),r("bgRed",[41,49],"bg"),r("bgGreen",[42,49],"bg"),r("bgYellow",[43,49],"bg"),r("bgBlue",[44,49],"bg"),r("bgMagenta",[45,49],"bg"),r("bgCyan",[46,49],"bg"),r("bgWhite",[47,49],"bg"),r("blackBright",[90,39],"bright"),r("redBright",[91,39],"bright"),r("greenBright",[92,39],"bright"),r("yellowBright",[93,39],"bright"),r("blueBright",[94,39],"bright"),r("magentaBright",[95,39],"bright"),r("cyanBright",[96,39],"bright"),r("whiteBright",[97,39],"bright"),r("bgBlackBright",[100,49],"bgBright"),r("bgRedBright",[101,49],"bgBright"),r("bgGreenBright",[102,49],"bgBright"),r("bgYellowBright",[103,49],"bgBright"),r("bgBlueBright",[104,49],"bgBright"),r("bgMagentaBright",[105,49],"bgBright"),r("bgCyanBright",[106,49],"bgBright"),r("bgWhiteBright",[107,49],"bgBright"),e.ansiRegex=Si,e.hasColor=e.hasAnsi=(a)=>{return e.ansiRegex.lastIndex=0,typeof a==="string"&&a!==""&&e.ansiRegex.test(a)},e.alias=(a,i)=>{let n=typeof i==="string"?e[i]:i;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:a}),e.styles[a]=n,n.stack=[a];Reflect.defineProperty(e,a,{configurable:!0,enumerable:!0,set(l){e.alias(a,l)},get(){let l=(d)=>o(d,l.stack);return Reflect.setPrototypeOf(l,e),l.stack=this.stack?this.stack.concat(n.stack):n.stack,l}})},e.theme=(a)=>{if(!Ti(a))throw TypeError("Expected theme to be an object");for(let i of Object.keys(a))e.alias(i,a[i]);return e},e.alias("unstyle",(a)=>{if(typeof a==="string"&&a!=="")return e.ansiRegex.lastIndex=0,a.replace(e.ansiRegex,"");return""}),e.alias("noop",(a)=>a),e.none=e.clear=e.noop,e.stripColor=e.unstyle,e.symbols=Vt(),e.define=r,e};lt.exports=Yt();lt.exports.create=Yt});var R=x((Ri)=>{var Mi=Object.prototype.toString,O=Ce(),jt=!1,we=new Set,zt={yellow:"blue",cyan:"red",green:"magenta",black:"white",blue:"yellow",red:"cyan",magenta:"green",white:"black"};Ri.longest=(e,t)=>{return e.reduce((s,o)=>Math.max(s,t?o[t].length:o.length),0)};Ri.hasColor=(e)=>!!e&&O.hasColor(e);var Me=Ri.isObject=(e)=>{return e!==null&&typeof e==="object"&&!Array.isArray(e)};Ri.nativeType=(e)=>{return Mi.call(e).slice(8,-1).toLowerCase().replace(/\s/g,"")};Ri.isAsyncFn=(e)=>{return Ri.nativeType(e)==="asyncfunction"};Ri.isPrimitive=(e)=>{return e!=null&&typeof e!=="object"&&typeof e!=="function"};Ri.resolve=(e,t,...s)=>{if(typeof t==="function")return t.call(e,...s);return t};Ri.scrollDown=(e=[])=>[...e.slice(1),e[0]];Ri.scrollUp=(e=[])=>[e.pop(),...e];Ri.reorder=(e=[])=>{let t=e.slice();return t.sort((s,o)=>{if(s.index>o.index)return 1;if(s.index<o.index)return-1;return 0}),t};Ri.swap=(e,t,s)=>{let o=e.length,r=s===o?0:s<0?o-1:s,a=e[t];e[t]=e[r],e[r]=a};Ri.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};Ri.height=(e,t=20)=>{let s=e&&e.rows?e.rows:t;if(e&&typeof e.getWindowSize==="function")s=e.getWindowSize()[1];return s};Ri.wordWrap=(e,t={})=>{if(!e)return e;if(typeof t==="number")t={width:t};let{indent:s="",newline:o=`
|
|
5
|
+
`+s,width:r=80}=t,a=(o+s).match(/[^\S\n]/g)||[];r-=a.length;let i=`.{1,${r}}([\\s\\u200B]+|$)|[^\\s\\u200B]+?([\\s\\u200B]+|$)`,n=e.trim(),l=new RegExp(i,"g"),d=n.match(l)||[];if(d=d.map((m)=>m.replace(/\n$/,"")),t.padEnd)d=d.map((m)=>m.padEnd(r," "));if(t.padStart)d=d.map((m)=>m.padStart(r," "));return s+d.join(o)};Ri.unmute=(e)=>{let t=e.stack.find((o)=>O.keys.color.includes(o));if(t)return O[t];if(e.stack.find((o)=>o.slice(2)==="bg"))return O[t.slice(2)];return(o)=>o};Ri.pascal=(e)=>e?e[0].toUpperCase()+e.slice(1):"";Ri.inverse=(e)=>{if(!e||!e.stack)return e;let t=e.stack.find((o)=>O.keys.color.includes(o));if(t){let o=O["bg"+Ri.pascal(t)];return o?o.black:e}let s=e.stack.find((o)=>o.slice(0,2)==="bg");if(s)return O[s.slice(2).toLowerCase()]||e;return O.none};Ri.complement=(e)=>{if(!e||!e.stack)return e;let t=e.stack.find((o)=>O.keys.color.includes(o)),s=e.stack.find((o)=>o.slice(0,2)==="bg");if(t&&!s)return O[zt[t]||t];if(s){let o=s.slice(2).toLowerCase(),r=zt[o];if(!r)return e;return O["bg"+Ri.pascal(r)]||e}return O.none};Ri.meridiem=(e)=>{let t=e.getHours(),s=e.getMinutes(),o=t>=12?"pm":"am";t=t%12;let r=t===0?12:t,a=s<10?"0"+s:s;return r+":"+a+" "+o};Ri.set=(e={},t="",s)=>{return t.split(".").reduce((o,r,a,i)=>{let n=i.length-1>a?o[r]||{}:s;if(!Ri.isObject(n)&&a<i.length-1)n={};return o[r]=n},e)};Ri.get=(e={},t="",s)=>{let o=e[t]==null?t.split(".").reduce((r,a)=>r&&r[a],e):e[t];return o==null?s:o};Ri.mixin=(e,t)=>{if(!Me(e))return t;if(!Me(t))return e;for(let s of Object.keys(t)){let o=Object.getOwnPropertyDescriptor(t,s);if(hasOwnProperty.call(o,"value"))if(hasOwnProperty.call(e,s)&&Me(o.value)){let r=Object.getOwnPropertyDescriptor(e,s);if(Me(r.value)&&r.value!==o.value)e[s]=Ri.merge({},e[s],t[s]);else Reflect.defineProperty(e,s,o)}else Reflect.defineProperty(e,s,o);else Reflect.defineProperty(e,s,o)}return e};Ri.merge=(...e)=>{let t={};for(let s of e)Ri.mixin(t,s);return t};Ri.mixinEmitter=(e,t)=>{let s=t.constructor.prototype;for(let o of Object.keys(s)){let r=s[o];if(typeof r==="function")Ri.define(e,o,r.bind(t));else Ri.define(e,o,r)}};var Re=(e,t)=>{if(jt)return;if(jt=!0,we.forEach((s)=>s()),e===!0)process.exit(128+t)},Zt=Re.bind(null,!0,15),Qt=Re.bind(null,!0,2);Ri.onExit=(e)=>{if(we.size===0)process.once("SIGTERM",Zt),process.once("SIGINT",Qt),process.once("exit",Re);return we.add(e),()=>{if(we.delete(e),we.size===0)process.off("SIGTERM",Zt),process.off("SIGINT",Qt),process.off("exit",Re)}};Ri.define=(e,t,s)=>{Reflect.defineProperty(e,t,{value:s})};Ri.defineExport=(e,t,s)=>{let o;Reflect.defineProperty(e,t,{enumerable:!0,configurable:!0,set(r){o=r},get(){return o?o():s()}})}});var ss=x((Vc,ts)=>{ts.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=x((Yc,os)=>{var Ji=ss();os.exports=(e)=>typeof e==="string"?e.replace(Ji(),""):e});var rs=x((en)=>{en.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"};en.shift={up:"shiftUp",down:"shiftDown",left:"shiftLeft",right:"shiftRight",tab:"prev"};en.fn={up:"pageUp",down:"pageDown",left:"pageLeft",right:"pageRight",delete:"deleteForward"};en.option={b:"backward",f:"forward",d:"cutRight",left:"cutLeft",up:"altUp",down:"altDown"};en.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 is=x((zc,as)=>{as.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 mt=x((Zc,ls)=>{var ns=ye("readline"),nn=rs(),ln=is(),dn=/^(?:\x1b)([a-zA-Z0-9])$/,mn=/^(?:\x1b+)(O|N|\[|\[\[)(?:(\d+)(?:;(\d+))?([~^$])|(?:1;)?(\d+)?([a-zA-Z]))/,cn={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 pn(e){return["[a","[b","[c","[d","[e","[2$","[3$","[5$","[6$","[7$","[8$","[Z"].includes(e)}function un(e){return["Oa","Ob","Oc","Od","Oe","[2^","[3^","[5^","[6^","[7^","[8^"].includes(e)}var _e=(e="",t={})=>{let s,o={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=o.sequence||"";if(o.sequence=o.sequence||e||o.name,e==="\r")o.raw=void 0,o.name="return";else if(e===`
|
|
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=dn.exec(e))o.meta=!0,o.shift=/^[A-Z]$/.test(s[1]);else if(s=mn.exec(e)){let r=[...e];if(r[0]==="\x1B"&&r[1]==="\x1B")o.option=!0;let a=[s[1],s[2],s[4],s[6]].filter(Boolean).join(""),i=(s[3]||s[5]||1)-1;o.ctrl=!!(i&4),o.meta=!!(i&10),o.shift=!!(i&1),o.code=a,o.name=cn[a],o.shift=pn(a)||o.shift,o.ctrl=un(a)||o.ctrl}return o};_e.listen=(e={},t)=>{let{stdin:s}=e;if(!s||s!==process.stdin&&!s.isTTY)throw Error("Invalid stream passed");let o=ns.createInterface({terminal:!0,input:s});ns.emitKeypressEvents(s,o);let r=new ln((n,l)=>t(n,_e(n,l),o)),a=s.isRaw;if(s.isTTY)s.setRawMode(!0);return s.on("keypress",r.enqueue),o.resume(),()=>{if(s.isTTY)s.setRawMode(a);s.removeListener("keypress",r.enqueue),r.destroy(),o.pause(),o.close()}};_e.action=(e,t,s)=>{let o={...nn,...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};ls.exports=_e});var ms=x((Qc,ds)=>{ds.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};hn(e,s,o)}};function hn(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 a=setInterval(()=>{o.ms=Date.now()-o.start,o.tick++,e.render()},r);return o.stop=()=>{o.loading=!1,clearInterval(a)},Reflect.defineProperty(o,"interval",{value:a}),e.once("close",()=>o.stop()),o.stop}});var us=x((Xc,ps)=>{var{define:fn,width:gn}=R();class cs{constructor(e){let t=e.options;fn(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=gn(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"}}ps.exports=cs});var fs=x((Jc,hs)=>{var ct=R(),M=Ce(),pt={default:M.noop,noop:M.noop,set inverse(e){this._inverse=e},get inverse(){return this._inverse||ct.inverse(this.primary)},set complement(e){this._complement=e},get complement(){return this._complement||ct.complement(this.primary)},primary:M.cyan,success:M.green,danger:M.magenta,strong:M.bold,warning:M.yellow,muted:M.dim,disabled:M.gray,dark:M.dim.gray,underline:M.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}};pt.merge=(e={})=>{if(e.styles&&typeof e.styles.enabled==="boolean")M.enabled=e.styles.enabled;if(e.styles&&typeof e.styles.visible==="boolean")M.visible=e.styles.visible;let t=ct.merge({},pt,e.styles);delete t.merge;for(let s of Object.keys(M))if(!hasOwnProperty.call(t,s))Reflect.defineProperty(t,s,{get:()=>M[s]});for(let s of Object.keys(M.styles))if(!hasOwnProperty.call(t,s))Reflect.defineProperty(t,s,{get:()=>M[s]});return t};hs.exports=pt});var ys=x((ep,gs)=>{var ut=process.platform==="win32",H=Ce(),yn=R(),ht={...H.symbols,upDownDoubleArrow:"\u21D5",upDownDoubleArrow2:"\u2B0D",upDownArrow:"\u2195",asterisk:"*",asterism:"\u2042",bulletWhite:"\u25E6",electricArrow:"\u2301",ellipsisLarge:"\u22EF",ellipsisSmall:"\u2026",fullBlock:"\u2588",identicalTo:"\u2261",indicator:H.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:H.symbols.question,submitted:H.symbols.check,cancelled:H.symbols.cross},separator:{pending:H.symbols.pointerSmall,submitted:H.symbols.middot,cancelled:H.symbols.middot},radio:{off:ut?"( )":"\u25EF",on:ut?"(*)":"\u25C9",disabled:ut?"(|)":"\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"]};ht.merge=(e)=>{let t=yn.merge({},H.symbols,ht,e.symbols);return delete t.merge,t};gs.exports=ht});var ws=x((tp,bs)=>{var bn=fs(),wn=ys(),xn=R();bs.exports=(e)=>{e.options=xn.merge({},e.options.theme,e.options),e.symbols=wn.merge(e.options),e.styles=bn.merge(e.options)}});var vs=x((Es,As)=>{var xs=process.env.TERM_PROGRAM==="Apple_Terminal",En=se(),ft=R(),L=As.exports=Es,gt=!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["+(xs?"8":"u"),savePosition:"\x1B["+(xs?"7":"s"),screen:"\x1B[2J",show:"\x1B[?25h",up:"\x1B[1J"},ne=L.cursor={get hidden(){return gt},hide(){return gt=!0,oe.hide},show(){return gt=!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?ne.left(-e):e>0?ne.right(e):"",s+=t<0?ne.up(-t):t>0?ne.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:a,size:i,value:n}=e;if(o=ft.isPrimitive(o)?String(o):"",r=ft.isPrimitive(r)?String(r):"",n=ft.isPrimitive(n)?String(n):"",i){let l=L.cursor.up(i)+L.cursor.to(this.strLen(a)),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&&!a.includes(o))l+=this.strLen(o);return L.cursor.move(l)}}},yt=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 yt.line+ne.to(0);let s=(a)=>[...En(a)].length,o=e.split(/\r?\n/),r=0;for(let a of o)r+=1+Math.floor(Math.max(s(a)-1,0)/t);return(yt.line+ne.prevLine()).repeat(r-1)+yt.line+ne.to(0)}});var ue=x((sp,Ts)=>{var An=ye("events"),Ns=se(),bt=mt(),vn=ms(),Nn=us(),Tn=ws(),D=R(),le=vs();class wt extends An{constructor(e={}){super();this.name=e.name,this.type=e.type,this.options=e,Tn(this),vn(this),this.state=new Nn(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=Cn(this.options.margin),this.setMaxListeners(0),Sn(this)}async keypress(e,t={}){this.keypressed=!0;let s=bt.action(e,bt(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(le.code.beep)}cursorHide(){this.stdout.write(le.cursor.hide());let e=D.onExit(()=>this.cursorShow());this.on("close",()=>{this.cursorShow(),e()})}cursorShow(){this.stdout.write(le.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(le.cursor.down(e)+le.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:a="",value:i=""}=this,n=this.state.size=s.length,l={after:t,cursor:o,initial:r,input:a,prompt:e,size:n,value:i},d=le.cursor.restore(l);if(d)this.stdout.write(d)}sections(){let{buffer:e,input:t,prompt:s}=this.state;s=Ns(s);let o=Ns(e),r=o.indexOf(s),a=o.slice(0,r),n=o.slice(r).split(`
|
|
7
|
+
`),l=n[0],d=n[n.length-1],h=(s+(t?" "+t:"")).length,c=h<l.length?l.slice(h+1):"";return{header:a,prompt:l,after:c,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
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(le.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=bt.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 o=t.onSubmit.bind(this),r=this.submit.bind(this);delete this.options.onSubmit,this.submit=async()=>{return await o(this.name,this.value,this),r()}}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:o,state:r,symbols:a,timers:i}=this,n=i&&i[e];r.timer=n;let l=o[e]||r[e]||a[e],d=t&&t[e]!=null?t[e]:await l;if(d==="")return d;let m=await this.resolve(d,r,t,s);if(!m&&t&&t[e])return this.resolve(l,r,t,s);return m}async prefix(){let e=await this.element("prefix")||this.symbols,t=this.timers&&this.timers.prefix,s=this.state;if(s.timer=t,D.isObject(e))e=e[s.status]||e.pending;if(!D.hasColor(e))return(this.styles[s.status]||this.styles.pending)(e);return e}async message(){let e=await this.element("message");if(!D.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 o=e[s.status]||e.pending||s.separator,r=await this.resolve(o,s);if(D.isObject(r))r=r[s.status]||r.pending;if(!D.hasColor(r))return this.styles.muted(r);return r}async pointer(e,t){let s=await this.element("pointer",e,t);if(typeof s==="string"&&D.hasColor(s))return s;if(s){let o=this.styles,r=this.index===t,a=r?o.primary:(l)=>l,i=await this.resolve(s[r?"on":"off"]||s,this.state),n=!D.hasColor(i)?a(i):i;return r?n:" ".repeat(i.length)}}async indicator(e,t){let s=await this.element("indicator",e,t);if(typeof s==="string"&&D.hasColor(s))return s;if(s){let o=this.styles,r=e.enabled===!0,a=r?o.success:o.dark,i=s[r?"on":"off"]||s;return!D.hasColor(i)?a(i):i}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(!D.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 D.resolve(this,e,...t)}get base(){return wt.prototype}get style(){return this.styles[this.state.status]}get height(){return this.options.rows||D.height(this.stdout,25)}get width(){return this.options.columns||D.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
|
|
11
|
-
`:" ",o=[];for(let r=0;r<4;r++){let a=s(r);if(t[r])o.push(a.repeat(t[r]));else o.push("")}return o}Ts.exports=wt});var Ms=w((tp,Cs)=>{var Cn=R(),Ss={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 Ss.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}};Cs.exports=(e,t={})=>{let s=Cn.merge({},Ss,t.roles);return s[e]||s.default}});var xe=w((sp,Is)=>{var Mn=se(),Rn=ue(),_n=Ms(),De=R(),{reorder:xt,scrollUp:Dn,scrollDown:In,isObject:Rs,swap:Pn}=De;class Ds extends Rn{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(Rs(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(a,i)=>{if(typeof a==="function")a=await a.call(this);if(a instanceof Promise)a=await a;for(let n=0;n<a.length;n++){let l=a[n]=await this.toChoice(a[n],o++,i);if(s.push(l),l.choices)await r(l.choices,l)}return s};return r(e,t).then((a)=>{return this.state.loadingChoices=!1,a})}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=_n(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,De.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,Mn(e.message).length);let a={...e};if(e.reset=(i=a.input,n=a.value)=>{for(let l of Object.keys(a))e[l]=a[l];e.input=i,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 _s(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,a=this.choices.find((i)=>o===i.index);if(!a.enabled&&this.selected.length>=this.maxSelected)return this.alert();if(this.visible.indexOf(a)===-1){let i=xt(this.choices),n=i.indexOf(a);if(r.index>n){let l=i.slice(n,n+this.limit),d=i.filter((m)=>!l.includes(m));this.choices=l.concat(d)}else{let l=n-this.limit+1;this.choices=i.slice(l).concat(i.slice(0,l))}}return this.index=this.choices.indexOf(a),this.toggle(this.focused),this.render()};return clearTimeout(this.numberTimeout),new Promise((s)=>{let o=this.choices.length,r=this.num,a=(i=!1,n)=>{if(clearTimeout(this.numberTimeout),i)n=t(r);this.num="",s(n)};if(r==="0"||r.length===1&&Number(r+"0")>o)return a(!0);if(Number(r)>o)return a(!1,this.alert());this.numberTimeout=setTimeout(()=>a(!0),this.delay)})}home(){return this.choices=xt(this.choices),this.index=0,this.render()}end(){let e=this.choices.length-this.limit,t=xt(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=Dn(this.choices),this.index=e,this.isDisabled())return this.up();return this.render()}scrollDown(e=this.visible.length-1){if(this.choices=In(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){Pn(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:(i,n)=>[i.name,n].includes(e),a=(this.options.multiple?this.state._choices:this.choices).filter(o);if(t)return a.map((i)=>i[t]);return a}find(e,t){if(Rs(e))return t?e[t]:e;let o=typeof e==="function"?e:(a,i)=>[a.name,i].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((a)=>a.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=De.reorder(r);return this.value=o?r.map((a)=>a.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 _s(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 _s(e,t){if(t instanceof Promise)return t;if(typeof t==="function"){if(De.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}Is.exports=Ds});var re=w((op,Os)=>{var On=xe(),Et=R();class Ps extends On{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"&&!Et.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||""),a=await this.resolve(e.hint,this.state,e,t);if(a&&!Et.hasColor(a))a=this.styles.muted(a);let i=this.indent(e),n=await this.choiceMessage(e,t),l=()=>[this.margin[3],i+o+r,n,this.margin[1],a].filter(Boolean).join(" ");if(e.role==="heading")return l();if(e.disabled){if(!Et.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,a)=>await this.renderChoice(r,a)),t=await Promise.all(e);if(!t.length)t.push(this.styles.danger("No matching choices"));let s=this.margin[0]+t.join(`
|
|
10
|
+
`.repeat(t))}catch(e){}this.emit("close")}start(){if(!this.stop&&this.options.show!==!1)this.stop=bt.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 o=t.onSubmit.bind(this),r=this.submit.bind(this);delete this.options.onSubmit,this.submit=async()=>{return await o(this.name,this.value,this),r()}}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:o,state:r,symbols:a,timers:i}=this,n=i&&i[e];r.timer=n;let l=o[e]||r[e]||a[e],d=t&&t[e]!=null?t[e]:await l;if(d==="")return d;let m=await this.resolve(d,r,t,s);if(!m&&t&&t[e])return this.resolve(l,r,t,s);return m}async prefix(){let e=await this.element("prefix")||this.symbols,t=this.timers&&this.timers.prefix,s=this.state;if(s.timer=t,D.isObject(e))e=e[s.status]||e.pending;if(!D.hasColor(e))return(this.styles[s.status]||this.styles.pending)(e);return e}async message(){let e=await this.element("message");if(!D.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 o=e[s.status]||e.pending||s.separator,r=await this.resolve(o,s);if(D.isObject(r))r=r[s.status]||r.pending;if(!D.hasColor(r))return this.styles.muted(r);return r}async pointer(e,t){let s=await this.element("pointer",e,t);if(typeof s==="string"&&D.hasColor(s))return s;if(s){let o=this.styles,r=this.index===t,a=r?o.primary:(l)=>l,i=await this.resolve(s[r?"on":"off"]||s,this.state),n=!D.hasColor(i)?a(i):i;return r?n:" ".repeat(i.length)}}async indicator(e,t){let s=await this.element("indicator",e,t);if(typeof s==="string"&&D.hasColor(s))return s;if(s){let o=this.styles,r=e.enabled===!0,a=r?o.success:o.dark,i=s[r?"on":"off"]||s;return!D.hasColor(i)?a(i):i}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(!D.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 D.resolve(this,e,...t)}get base(){return wt.prototype}get style(){return this.styles[this.state.status]}get height(){return this.options.rows||D.height(this.stdout,25)}get width(){return this.options.columns||D.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 Sn(e){let t=(r)=>{return e[r]===void 0||typeof e[r]==="function"},s=["actions","choices","initial","margin","roles","styles","symbols","theme","timers","value"],o=["body","footer","error","header","hint","indicator","message","prefix","separator","skip"];for(let r of Object.keys(e.options)){if(s.includes(r))continue;if(/^on[A-Z]/.test(r))continue;let a=e.options[r];if(typeof a==="function"&&t(r)){if(!o.includes(r))e[r]=a.bind(e)}else if(typeof e[r]!=="function")e[r]=a}}function Cn(e){if(typeof e==="number")e=[e,e,e,e];let t=[].concat(e||[]),s=(r)=>r%2===0?`
|
|
11
|
+
`:" ",o=[];for(let r=0;r<4;r++){let a=s(r);if(t[r])o.push(a.repeat(t[r]));else o.push("")}return o}Ts.exports=wt});var Ms=x((op,Cs)=>{var Mn=R(),Ss={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 Ss.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}};Cs.exports=(e,t={})=>{let s=Mn.merge({},Ss,t.roles);return s[e]||s.default}});var xe=x((rp,Is)=>{var Rn=se(),_n=ue(),Dn=Ms(),De=R(),{reorder:xt,scrollUp:In,scrollDown:Pn,isObject:Rs,swap:On}=De;class Ds extends _n{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(Rs(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(a,i)=>{if(typeof a==="function")a=await a.call(this);if(a instanceof Promise)a=await a;for(let n=0;n<a.length;n++){let l=a[n]=await this.toChoice(a[n],o++,i);if(s.push(l),l.choices)await r(l.choices,l)}return s};return r(e,t).then((a)=>{return this.state.loadingChoices=!1,a})}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=Dn(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,De.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,Rn(e.message).length);let a={...e};if(e.reset=(i=a.input,n=a.value)=>{for(let l of Object.keys(a))e[l]=a[l];e.input=i,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 _s(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,a=this.choices.find((i)=>o===i.index);if(!a.enabled&&this.selected.length>=this.maxSelected)return this.alert();if(this.visible.indexOf(a)===-1){let i=xt(this.choices),n=i.indexOf(a);if(r.index>n){let l=i.slice(n,n+this.limit),d=i.filter((m)=>!l.includes(m));this.choices=l.concat(d)}else{let l=n-this.limit+1;this.choices=i.slice(l).concat(i.slice(0,l))}}return this.index=this.choices.indexOf(a),this.toggle(this.focused),this.render()};return clearTimeout(this.numberTimeout),new Promise((s)=>{let o=this.choices.length,r=this.num,a=(i=!1,n)=>{if(clearTimeout(this.numberTimeout),i)n=t(r);this.num="",s(n)};if(r==="0"||r.length===1&&Number(r+"0")>o)return a(!0);if(Number(r)>o)return a(!1,this.alert());this.numberTimeout=setTimeout(()=>a(!0),this.delay)})}home(){return this.choices=xt(this.choices),this.index=0,this.render()}end(){let e=this.choices.length-this.limit,t=xt(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=In(this.choices),this.index=e,this.isDisabled())return this.up();return this.render()}scrollDown(e=this.visible.length-1){if(this.choices=Pn(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){On(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:(i,n)=>[i.name,n].includes(e),a=(this.options.multiple?this.state._choices:this.choices).filter(o);if(t)return a.map((i)=>i[t]);return a}find(e,t){if(Rs(e))return t?e[t]:e;let o=typeof e==="function"?e:(a,i)=>[a.name,i].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((a)=>a.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=De.reorder(r);return this.value=o?r.map((a)=>a.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 _s(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 _s(e,t){if(t instanceof Promise)return t;if(typeof t==="function"){if(De.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}Is.exports=Ds});var re=x((ap,Os)=>{var Bn=xe(),Et=R();class Ps extends Bn{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"&&!Et.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||""),a=await this.resolve(e.hint,this.state,e,t);if(a&&!Et.hasColor(a))a=this.styles.muted(a);let i=this.indent(e),n=await this.choiceMessage(e,t),l=()=>[this.margin[3],i+o+r,n,this.margin[1],a].filter(Boolean).join(" ");if(e.role==="heading")return l();if(e.disabled){if(!Et.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,a)=>await this.renderChoice(r,a)),t=await Promise.all(e);if(!t.length)t.push(this.styles.danger("No matching choices"));let s=this.margin[0]+t.join(`
|
|
12
12
|
`),o;if(this.options.choicesHeader)o=await this.resolve(this.options.choicesHeader,this.state);return[o,s].filter(Boolean).join(`
|
|
13
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="",o=await this.header(),r=await this.prefix(),a=await this.separator(),i=await this.message();if(this.options.promptLine!==!1)s=[r,i,a,""].join(" "),this.state.prompt=s;let n=await this.format(),l=await this.error()||await this.hint(),d=await this.renderChoices(),m=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([o,s,d,m].filter(Boolean).join(`
|
|
14
|
-
`)),this.write(this.margin[2]),this.restore()}}Os.exports=Ps});var Us=
|
|
15
|
-
`)),this.restore()}set value(e){super.value=e}get value(){return this.cast(super.value)}}Ys.exports=Vs});var Zs=
|
|
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),o=t.split(" ");this.state.clipboard.push(o.pop()),this.input=o.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
|
|
17
|
-
`)),this.restore()}}to.exports=eo});var oo=
|
|
14
|
+
`)),this.write(this.margin[2]),this.restore()}}Os.exports=Ps});var Us=x((ip,Ls)=>{var Ln=re(),Un=(e,t)=>{let s=e?new RegExp(e,"ig"):/$^/;return(o)=>{return e?o.replace(s,(r)=>t(r)):o}};class Bs extends Ln{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((o)=>o.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=(r,a)=>{if(!r)return r;if(e.stack)return e(r);return e.call(this,r)},s=Un(this.input,t),o=this.choices;this.choices=o.map((r)=>({...r,message:s(r.message)})),await super.render(),this.choices=o}submit(){if(this.options.multiple)this.value=this.selected.map((e)=>e.name);return super.submit()}}Ls.exports=Bs});var vt=x((np,$s)=>{var At=R();$s.exports=(e,t={})=>{e.cursorHide();let{input:s="",initial:o="",pos:r,showCursor:a=!0,color:i}=t,n=i||e.styles.placeholder,l=At.inverse(e.styles.primary),d=(f)=>l(e.styles.black(f)),m=s,h=" ",c=d(h);if(e.blink&&e.blink.off===!0)d=(f)=>f,c="";if(a&&r===0&&o===""&&s==="")return d(h);if(a&&r===0&&(s===o||s===""))return d(o[0])+n(o.slice(1));o=At.isPrimitive(o)?`${o}`:"",s=At.isPrimitive(s)?`${s}`:"";let p=o&&o.startsWith(s)&&o!==s,u=p?d(o[s.length]):c;if(r!==s.length&&a===!0)m=s.slice(0,r)+d(s[r])+s.slice(r+1),u="";if(a===!1)u="";if(p){let f=e.styles.unstyle(m+u);return m+u+n(o.slice(f.length))}return m+u}});var Ie=x((lp,ks)=>{var $n=se(),Gn=re(),kn=vt();class Gs extends Gn{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:o}=t;return t.value=t.input=o.slice(0,s)+e+o.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 o=`${s}`.slice(0,t)+`${s}`.slice(t+1);return e.value=e.input=o,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:o}=this,{cursor:r,initial:a="",name:i,input:n=""}=e,{muted:l,submitted:d,primary:m,danger:h}=o,c=this.index===t,p=e.validate||(()=>!0),u=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[i]=n||a,g=n?"success":"dark";if(await p.call(e,y,this.state)!==!0)g="danger";let E=o[g],A=E(await this.indicator(e,t))+(e.pad||""),N=this.indent(e),C=()=>[N,A,f+u,n].filter(Boolean).join(" ");if(s.submitted)return f=$n(f),n=d(n),C();if(e.format)n=await e.format.call(this,n,e,t);else{let _=this.styles.muted;n=kn(this,{input:n,initial:a,pos:r,showCursor:c,color:_})}if(!this.isValue(n))n=this.styles.muted(this.symbols.ellipsis);if(e.result)this.values[i]=await e.result.call(this,y,e,t);if(c)f=m(f);if(e.error)n+=(n?" ":"")+h(e.error.trim());else if(e.hint)n+=(n?" ":"")+l(e.hint.trim());return C()}async submit(){return this.value=this.values,super.base.submit.call(this)}}ks.exports=Gs});var Nt=x((dp,qs)=>{var Wn=Ie(),qn=()=>{throw Error("expected prompt to have a custom authenticate method")},Ws=(e=qn)=>{class t extends Wn{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 Ws(s)}}return t};qs.exports=Ws()});var Fs=x((mp,Hs)=>{var Kn=Nt();function Hn(e,t){if(e.username===this.options.username&&e.password===this.options.password)return!0;return!1}var Ks=(e=Hn)=>{let t=[{name:"username",message:"username"},{name:"password",message:"password",format(o){if(this.options.showPassword)return o;return(this.state.submitted?this.styles.primary:this.styles.muted)(this.symbols.asterisk.repeat(o.length))}}];class s extends Kn.create(e){constructor(o){super({...o,choices:t})}static create(o){return Ks(o)}}return s};Hs.exports=Ks()});var Pe=x((cp,Ys)=>{var Fn=ue(),{isPrimitive:Vn,hasColor:Yn}=R();class Vs extends Fn{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 Vn(e)&&(this.isTrue(e)||this.isFalse(e))}async hint(){if(this.state.status==="pending"){let e=await this.element("hint");if(!Yn(e))return this.styles.muted(e);return e}}async render(){let{input:e,size:t}=this.state,s=await this.prefix(),o=await this.separator(),r=await this.message(),a=this.styles.muted(this.default),i=[s,r,a,o].filter(Boolean).join(" ");this.state.prompt=i;let n=await this.header(),l=this.value=this.cast(e),d=await this.format(l),m=await this.error()||await this.hint(),h=await this.footer();if(m&&!i.includes(m))d+=" "+m;i+=" "+d,this.clear(t),this.write([n,i,h].filter(Boolean).join(`
|
|
15
|
+
`)),this.restore()}set value(e){super.value=e}get value(){return this.cast(super.value)}}Ys.exports=Vs});var Zs=x((pp,zs)=>{var jn=Pe();class js extends jn{constructor(e){super(e);this.default=this.options.default||(this.initial?"(Y/n)":"(y/N)")}}zs.exports=js});var Js=x((up,Xs)=>{var zn=re(),Zn=Ie(),he=Zn.prototype;class Qs extends zn{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,o=s.parent||{};if(!s.editable&&!o.editable){if(e==="a"||e==="i")return super[e]()}return he.dispatch.call(this,e,t)}append(e,t){return he.append.call(this,e,t)}delete(e,t){return he.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?he.next.call(this):super.next()}prev(){return this.focused.editable?he.prev.call(this):super.prev()}async indicator(e,t){let s=e.indicator||"",o=e.editable?s:super.indicator(e,t);return await this.resolve(o,this.state,e,t)||""}indent(e){return e.role==="heading"?"":e.editable?" ":" "}async renderChoice(e,t){if(e.indent="",e.editable)return he.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)}}Xs.exports=Qs});var de=x((hp,to)=>{var Qn=ue(),Xn=mt(),Jn=vt(),{isPrimitive:el}=R();class eo extends Qn{constructor(e){super(e);if(this.initial=el(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?Xn(e,{}):{}){let s=Date.now(),o=s-this.lastKeypress;this.lastKeypress=s;let r=t.name==="return"||t.name==="enter",a=this.state.prevKeypress,i;if(this.state.prevKeypress=t,this.keypressTimeout!=null&&r){if(o<this.keypressTimeout)return this.submit();this.state.multilineBuffer=this.state.multilineBuffer||"",this.state.multilineBuffer+=e,i=!0,a=null}if(i||this.options.multiline&&r){if(!a||a.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),o=t.split(" ");this.state.clipboard.push(o.pop()),this.input=o.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 Jn(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(),o=await this.message(),r=[t,o,s].filter(Boolean).join(" ");this.state.prompt=r;let a=await this.header(),i=await this.format(),n=await this.error()||await this.hint(),l=await this.footer();if(n&&!i.includes(n))i+=" "+n;r+=" "+i,this.clear(e),this.write([a,r,l].filter(Boolean).join(`
|
|
17
|
+
`)),this.restore()}}to.exports=eo});var oo=x((fp,so)=>{var tl=(e)=>e.filter((t,s)=>e.lastIndexOf(t)===s),Oe=(e)=>tl(e).filter(Boolean);so.exports=(e,t={},s="")=>{let{past:o=[],present:r=""}=t,a,i;switch(e){case"prev":case"undo":return a=o.slice(0,o.length-1),i=o[o.length-1]||"",{past:Oe([s,...a]),present:i};case"next":case"redo":return a=o.slice(1),i=o[0]||"",{past:Oe([...a,s]),present:i};case"save":return{past:Oe([...o,s]),present:""};case"remove":if(i=Oe(o.filter((n)=>n!==s)),r="",i.length)r=i.pop();return{past:i,present:r};default:throw Error(`Invalid action: "${e}"`)}}});var Tt=x((gp,io)=>{var sl=de(),ro=oo();class ao extends sl{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=ro(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=ro("save",this.data,this.input),this.store.set("values",this.data)}submit(){if(this.store&&this.autosave===!0)this.save();return super.submit()}}io.exports=ao});var mo=x((yp,lo)=>{var ol=de();class no extends ol{format(){return""}}lo.exports=no});var uo=x((bp,po)=>{var rl=de();class co extends rl{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()}}po.exports=co});var go=x((wp,fo)=>{var al=re();class ho extends al{constructor(e){super({...e,multiple:!0})}}fo.exports=ho});var St=x((xp,bo)=>{var il=de();class yo extends il{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()}}bo.exports=yo});var Eo=x((Ep,xo)=>{var nl=de();class wo extends nl{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))}}xo.exports=wo});var To=x((Ap,No)=>{var ll=se(),dl=xe(),Ao=R();class vo extends dl{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
18
|
`;let t=e.startNumber||1;if(typeof this.scale==="number")this.scaleKey=!1,this.scale=Array(this.scale).fill(0).map((s,o)=>({name:o+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,o=Math.round(s/(t.length-1)),a=t.map((n)=>this.styles.strong(n)).join(" ".repeat(o)),i=" ".repeat(this.widths[0]);return this.margin[3]+i+this.margin[1]+a}scaleIndicator(e,t,s){if(typeof this.options.scaleIndicator==="function")return this.options.scaleIndicator.call(this,e,t,s);let o=e.scaleIndex===t.index;if(t.disabled)return this.styles.hint(this.symbols.radio.disabled);if(o)return this.styles.success(this.symbols.radio.on);return this.symbols.radio.off}renderScale(e,t){let s=e.scale.map((r)=>this.scaleIndicator(e,r,t)),o=this.term==="Hyper"?"":" ";return s.join(o+this.symbols.line.repeat(this.edgeLength))}async renderChoice(e,t){await this.onChoice(e,t);let s=this.index===t,o=await this.pointer(e,t),r=await e.hint;if(r&&!Ao.hasColor(r))r=this.styles.muted(r);let a=(
|
|
20
|
-
`).map((
|
|
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,o=Math.round(s/(t.length-1)),a=t.map((n)=>this.styles.strong(n)).join(" ".repeat(o)),i=" ".repeat(this.widths[0]);return this.margin[3]+i+this.margin[1]+a}scaleIndicator(e,t,s){if(typeof this.options.scaleIndicator==="function")return this.options.scaleIndicator.call(this,e,t,s);let o=e.scaleIndex===t.index;if(t.disabled)return this.styles.hint(this.symbols.radio.disabled);if(o)return this.styles.success(this.symbols.radio.on);return this.symbols.radio.off}renderScale(e,t){let s=e.scale.map((r)=>this.scaleIndicator(e,r,t)),o=this.term==="Hyper"?"":" ";return s.join(o+this.symbols.line.repeat(this.edgeLength))}async renderChoice(e,t){await this.onChoice(e,t);let s=this.index===t,o=await this.pointer(e,t),r=await e.hint;if(r&&!Ao.hasColor(r))r=this.styles.muted(r);let a=(p)=>this.margin[3]+p.replace(/\s+$/,"").padEnd(this.widths[0]," "),i=this.newline,n=this.indent(e),l=await this.resolve(e.message,this.state,e,t),d=await this.renderScale(e,t),m=this.margin[1]+this.margin[3];this.scaleLength=ll(d).length,this.widths[0]=Math.min(this.widths[0],this.width-this.scaleLength-m.length);let c=Ao.wordWrap(l,{width:this.widths[0],newline:i}).split(`
|
|
20
|
+
`).map((p)=>a(p)+this.margin[1]);if(s)d=this.styles.info(d),c=c.map((p)=>this.styles.info(p));if(c[0]+=d,this.linebreak)c.push("");return[n+o,c.join(`
|
|
21
21
|
`)].filter(Boolean)}async renderChoices(){if(this.state.submitted)return"";this.tableize();let e=this.visible.map(async(o,r)=>await this.renderChoice(o,r)),t=await Promise.all(e),s=await this.renderScaleHeading();return this.margin[0]+[s,...t.map((o)=>o.join(" "))].join(`
|
|
22
|
-
`)}async render(){let{submitted:e,size:t}=this.state,s=await this.prefix(),o=await this.separator(),r=await this.message(),a="";if(this.options.promptLine!==!1)a=[s,r,o,""].join(" "),this.state.prompt=a;let i=await this.header(),n=await this.format(),l=await this.renderScaleKey(),d=await this.error()||await this.hint(),m=await this.renderChoices(),h=await this.footer(),
|
|
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)}}No.exports=vo});var Ro=
|
|
24
|
-
`){
|
|
25
|
-
`).map((
|
|
26
|
-
`),h.output}};function Ct(e,t,s,o){return(r,a,i,n)=>{if(typeof i.field[e]==="function")return i.field[e].call(t,r,a,i,n);return[o,r].find((l)=>t.isValue(l))}}});var Io=
|
|
27
|
-
`].find((g)=>g!=null),a=await this.prefix(),i=await this.separator(),n=await this.message(),l=[a,n,i].filter(Boolean).join(" ");this.state.prompt=l;let d=await this.header(),m=await this.error()||"",h=await this.hint()||"",
|
|
28
|
-
`;return this.state.error=i,super.submit()}if(t.size)return this.state.error="Required: "+[...t.keys()].join(", "),super.submit();let a=
|
|
22
|
+
`)}async render(){let{submitted:e,size:t}=this.state,s=await this.prefix(),o=await this.separator(),r=await this.message(),a="";if(this.options.promptLine!==!1)a=[s,r,o,""].join(" "),this.state.prompt=a;let i=await this.header(),n=await this.format(),l=await this.renderScaleKey(),d=await this.error()||await this.hint(),m=await this.renderChoices(),h=await this.footer(),c=this.emptyError;if(n)a+=n;if(d&&!a.includes(d))a+=" "+d;if(e&&!n&&!m.trim()&&this.multiple&&c!=null)a+=this.styles.danger(c);if(this.clear(t),this.write([i,a,l,m,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)}}No.exports=vo});var Ro=x((vp,Mo)=>{var So=se(),ml=(e="")=>{return typeof e==="string"?e.replace(/^['"]|['"]$/g,""):""};class Co{constructor(e){this.name=e.key,this.field=e.field||{},this.value=ml(e.initial||this.field.initial||""),this.message=e.message||this.name,this.cursor=0,this.input="",this.lines=[]}}var cl=async(e={},t={},s=(o)=>o)=>{let o=new Set,r=e.fields||[],a=e.template,i=[],n=[],l=[],d=1;if(typeof a==="function")a=await a();let m=-1,h=()=>a[++m],c=()=>a[m+1],p=(u)=>{u.line=d,i.push(u)};p({type:"bos",value:""});while(m<a.length-1){let u=h();if(/^[^\S\n ]$/.test(u)){p({type:"text",value:u});continue}if(u===`
|
|
24
|
+
`){p({type:"newline",value:u}),d++;continue}if(u==="\\"){u+=h(),p({type:"text",value:u});continue}if((u==="$"||u==="#"||u==="{")&&c()==="{"){let y=h();u+=y;let g={type:"template",open:u,inner:"",close:"",value:u},E;while(E=h()){if(E==="}"){if(c()==="}")E+=h();g.value+=E,g.close=E;break}if(E===":")g.initial="",g.key=g.inner;else if(g.initial!==void 0)g.initial+=E;g.value+=E,g.inner+=E}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),p(g),l.push(g.key),o.add(g.key);let A=n.find((N)=>N.name===g.key);if(g.field=r.find((N)=>N.name===g.key),!A)A=new Co(g),n.push(A);A.lines.push(g.line-1);continue}let f=i[i.length-1];if(f.type==="text"&&f.line===d)f.value+=u;else p({type:"text",value:u})}return p({type:"eos",value:""}),{input:a,tabstops:i,unique:o,keys:l,items:n}};Mo.exports=async(e)=>{let t=e.options,s=new Set(t.required===!0?[]:t.required||[]),o={...t.values,...t.initial},{tabstops:r,items:a,keys:i}=await cl(t,o),n=Ct("result",e,t),l=Ct("format",e,t),d=Ct("validate",e,t,!0),m=e.isValue.bind(e);return async(h={},c=!1)=>{let p=0;h.required=s,h.items=a,h.keys=i,h.output="";let u=async(E,A,N,C)=>{let _=await d(E,A,N,C);if(_===!1)return"Invalid field "+N.name;return _};for(let E of r){let{value:A,key:N}=E;if(E.type!=="template"){if(A)h.output+=A;continue}if(E.type==="template"){let C=a.find((pe)=>pe.name===N);if(t.required===!0)h.required.add(C.name);let _=[C.input,h.values[C.value],C.value,A].find(m),ee=(C.field||{}).message||E.inner;if(c){let pe=await u(h.values[N],h,C,p);if(pe&&typeof pe==="string"||pe===!1){h.invalid.set(N,pe);continue}h.invalid.delete(N);let li=await n(h.values[N],h,C,p);h.output+=So(li);continue}C.placeholder=!1;let ni=A;if(A=await l(A,h,C,p),_!==A)h.values[N]=_,A=e.styles.typing(_),h.missing.delete(ee);else if(h.values[N]=void 0,_=`<${ee}>`,A=e.styles.primary(_),C.placeholder=!0,h.required.has(N))h.missing.add(ee);if(h.missing.has(ee)&&h.validating)A=e.styles.warning(_);if(h.invalid.has(N)&&h.validating)A=e.styles.danger(_);if(p===h.index)if(ni!==A)A=e.styles.underline(A);else A=e.styles.heading(So(A));p++}if(A)h.output+=A}let f=h.output.split(`
|
|
25
|
+
`).map((E)=>" "+E),y=a.length,g=0;for(let E of a){if(h.invalid.has(E.name))E.lines.forEach((A)=>{if(f[A][0]!==" ")return;f[A]=h.styles.danger(h.symbols.bullet)+f[A].slice(1)});if(e.isValue(h.values[E.name]))g++}return h.completed=(g/y*100).toFixed(0),h.output=f.join(`
|
|
26
|
+
`),h.output}};function Ct(e,t,s,o){return(r,a,i,n)=>{if(typeof i.field[e]==="function")return i.field[e].call(t,r,a,i,n);return[o,r].find((l)=>t.isValue(l))}}});var Io=x((Np,Do)=>{var pl=se(),ul=Ro(),hl=ue();class _o extends hl{constructor(e){super(e);this.cursorHide(),this.reset(!0)}async initialize(){this.interpolate=await ul(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(),o=s.input.slice(0,this.cursor),r=s.input.slice(this.cursor);this.input=s.input=`${o}${e}${r}`,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:o}=this.state,r=[this.options.newline,`
|
|
27
|
+
`].find((g)=>g!=null),a=await this.prefix(),i=await this.separator(),n=await this.message(),l=[a,n,i].filter(Boolean).join(" ");this.state.prompt=l;let d=await this.header(),m=await this.error()||"",h=await this.hint()||"",c=s?"":await this.interpolate(this.state),p=this.state.key=t[e]||"",u=await this.format(p),f=await this.footer();if(u)l+=" "+u;if(h&&!u&&this.state.completed===0)l+=" "+h;this.clear(o);let y=[d,l,c,f,m.trim()];this.write(y.filter(Boolean).join(r)),this.restore()}getItem(e){let{items:t,keys:s,index:o}=this.state,r=t.find((a)=>a.name===s[o]);if(r&&r.input!=null)this.input=r.input,this.cursor=r.cursor;return r}async submit(){if(typeof this.interpolate!=="function")await this.initialize();await this.interpolate(this.state,!0);let{invalid:e,missing:t,output:s,values:o}=this.state;if(e.size){let i="";for(let[n,l]of e)i+=`Invalid ${n}: ${l}
|
|
28
|
+
`;return this.state.error=i,super.submit()}if(t.size)return this.state.error="Required: "+[...t.keys()].join(", "),super.submit();let a=pl(s).split(`
|
|
29
29
|
`).map((i)=>i.slice(1)).join(`
|
|
30
|
-
`);return this.value={values:o,result:a},super.submit()}}Do.exports=_o});var Bo=
|
|
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=
|
|
32
|
-
`);if(s)
|
|
30
|
+
`);return this.value={values:o,result:a},super.submit()}}Do.exports=_o});var Bo=x((Tp,Oo)=>{var fl=re();class Po extends fl{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),o=this.symbols.identicalTo+" ",r=this.index===t&&this.sorting?this.styles.muted(o):" ";if(this.options.drag===!1)r="";if(this.options.numbered===!0)return r+`${t+1} - `+s;return r+s}get selected(){return this.choices}submit(){return this.value=this.choices.map((e)=>e.value),super.submit()}}Oo.exports=Po});var $o=x((Sp,Uo)=>{var gl=xe();class Lo extends gl{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=yl(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((o)=>o.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,o=this.term==="Hyper",r=!o?8:9,a=!o?" ":"",i=this.symbols.line.repeat(r),n=" ".repeat(r+(o?0:1)),l=(E)=>(E?this.styles.success("\u25C9"):"\u25EF")+a,d=t+1+".",m=s?this.styles.heading:this.styles.noop,h=await this.resolve(e.message,this.state,e,t),c=this.indent(e),p=c+e.scale.map((E,A)=>l(A===e.scaleIdx)).join(i),u=(E)=>E===e.scaleIdx?m(E):E,f=c+e.scale.map((E,A)=>u(A)).join(n),y=()=>[d,h].filter(Boolean).join(" "),g=()=>[y(),p,f," "].filter(Boolean).join(`
|
|
32
|
+
`);if(s)p=this.styles.cyan(p),f=this.styles.cyan(f);return g()}async renderChoices(){if(this.state.submitted)return"";let e=this.visible.map(async(s,o)=>await this.renderChoice(s,o)),t=await Promise.all(e);if(!t.length)t.push(this.styles.danger("No matching choices"));return t.join(`
|
|
33
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(),o=await this.separator(),r=await this.message(),a=[s,r,o].filter(Boolean).join(" ");this.state.prompt=a;let i=await this.header(),n=await this.format(),l=await this.error()||await this.hint(),d=await this.renderChoices(),m=await this.footer();if(n||!l)a+=" "+n;if(l&&!a.includes(l))a+=" "+l;if(e&&!n&&!d&&this.multiple&&this.type!=="form")a+=this.styles.danger(this.emptyError);this.clear(t),this.write([a,i,d,m].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
|
|
35
|
-
`)),this.write(this.margin[2]),this.restore()}}ko.exports=Go});var Ho=w((Sp,Ko)=>{var bl=re();class qo extends bl{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)}}}Ko.exports=qo});var Vo=w((Mt)=>{var Fo=R(),T=(e,t)=>{Fo.defineExport(Mt,e,t),Fo.defineExport(Mt,e.toLowerCase(),t)};T("AutoComplete",()=>Us());T("BasicAuth",()=>Fs());T("Confirm",()=>Zs());T("Editable",()=>Js());T("Form",()=>Ie());T("Input",()=>Tt());T("Invisible",()=>mo());T("List",()=>uo());T("MultiSelect",()=>go());T("Numeral",()=>St());T("Password",()=>Eo());T("Scale",()=>To());T("Select",()=>re());T("Snippet",()=>Io());T("Sort",()=>Bo());T("Survey",()=>$o());T("Text",()=>Tt());T("Toggle",()=>Wo());T("Quiz",()=>Ho())});var jo=w((Mp,Yo)=>{Yo.exports={ArrayPrompt:xe(),AuthPrompt:Nt(),BooleanPrompt:Pe(),NumberPrompt:St(),StringPrompt:de()}});var ie=w((Rp,Zo)=>{var zo=ye("assert"),_t=ye("events"),ae=R();class U extends _t{constructor(e,t){super();this.options=ae.merge({},e),this.answers={...t}}register(e,t){if(ae.isObject(e)){for(let o of Object.keys(e))this.register(o,e[o]);return this}zo.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(ae.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=ae.merge({},this.options,e),{type:s,name:o}=e,{set:r,get:a}=ae;if(typeof s==="function")s=await s.call(this,e,this.answers);if(!s)return this.answers[o];if(s==="number")s="numeral";zo(this.prompts[s],`Prompt "${s}" is not registered`);let i=new this.prompts[s](t),n=a(this.answers,o);if(i.state.answers=this.answers,i.enquirer=this,o)i.on("submit",(d)=>{this.emit("answer",o,d,i),r(this.answers,o,d)});let l=i.emit.bind(i);if(i.emit=(...d)=>{return this.emit.call(this,...d),l(...d)},this.emit("prompt",i,this),t.autofill&&n!=null){if(i.value=i.input=n,t.autofill==="show")await i.submit()}else n=i.value=await i.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||ue()}static get prompts(){return Vo()}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=(...a)=>{return e.emit(...a),r(...a)},o.prompt(t)};return ae.mixinEmitter(e,new _t),e}}ae.mixinEmitter(U,new _t);var Rt=U.prompts;for(let e of Object.keys(Rt)){let t=e.toLowerCase(),s=(o)=>new Rt[e](o).run();if(U.prompt[t]=s,U[t]=s,!U[e])Reflect.defineProperty(U,e,{get:()=>Rt[e]})}var Ee=(e)=>{ae.defineExport(U,e,()=>U.types[e])};Ee("ArrayPrompt");Ee("AuthPrompt");Ee("BooleanPrompt");Ee("NumberPrompt");Ee("StringPrompt");Zo.exports=U});var Sa=w((Lt,Ut)=>{(function(e,t){if(typeof Lt==="object"&&typeof Ut==="object")Ut.exports=t();else if(typeof define==="function"&&define.amd)define(function(){return t()});else e.pluralize=t()})(Lt,function(){var e=[],t=[],s={},o={},r={};function a(c){if(typeof c==="string")return new RegExp("^"+c+"$","i");return c}function i(c,u){if(c===u)return u;if(c===c.toLowerCase())return u.toLowerCase();if(c===c.toUpperCase())return u.toUpperCase();if(c[0]===c[0].toUpperCase())return u.charAt(0).toUpperCase()+u.substr(1).toLowerCase();return u.toLowerCase()}function n(c,u){return c.replace(/\$(\d{1,2})/g,function(f,E){return u[E]||""})}function l(c,u){return c.replace(u[0],function(f,E){var g=n(u[1],arguments);if(f==="")return i(c[E-1],g);return i(f,g)})}function d(c,u,f){if(!c.length||s.hasOwnProperty(c))return u;var E=f.length;while(E--){var g=f[E];if(g[0].test(u))return l(u,g)}return u}function m(c,u,f){return function(E){var g=E.toLowerCase();if(u.hasOwnProperty(g))return i(E,g);if(c.hasOwnProperty(g))return i(E,c[g]);return d(g,E,f)}}function h(c,u,f,E){return function(g){var x=g.toLowerCase();if(u.hasOwnProperty(x))return!0;if(c.hasOwnProperty(x))return!1;return d(x,x,f)===x}}function p(c,u,f){var E=u===1?p.singular(c):p.plural(c);return(f?u+" ":"")+E}return p.plural=m(r,o,e),p.isPlural=h(r,o,e),p.singular=m(o,r,t),p.isSingular=h(o,r,t),p.addPluralRule=function(c,u){e.push([a(c),u])},p.addSingularRule=function(c,u){t.push([a(c),u])},p.addUncountableRule=function(c){if(typeof c==="string"){s[c.toLowerCase()]=!0;return}p.addPluralRule(c,"$0"),p.addSingularRule(c,"$0")},p.addIrregularRule=function(c,u){u=u.toLowerCase(),c=c.toLowerCase(),r[c]=u,o[u]=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 p.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 p.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 p.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(p.addUncountableRule),p})});import{parseArgs as wc}from"util";import{Exception as oi}from"@ooneex/exception";import{TerminalLogger as xc}from"@ooneex/logger";import{container as fi}from"@ooneex/container";var Te=[];var kt=(e)=>{let t=null;return Te.find((s)=>{return t=fi.get(s),t.getName()===e}),t};import{homedir as xi}from"os";import{join as it}from"path";import{TerminalLogger as Ei}from"@ooneex/logger";import{container as gi,EContainerScope as yi}from"@ooneex/container";var b={command:(e=yi.Singleton)=>{return(t)=>{gi.add(t,e),Te.push(t)}}};var Wt=`#compdef oo ooneex
|
|
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 yl(e,t={}){if(Array.isArray(t.scale))return t.scale.map((o)=>({...o}));let s=[];for(let o=1;o<e+1;o++)s.push({i:o,selected:!1});return s}Uo.exports=Lo});var Wo=x((Cp,ko)=>{var bl=Pe();class Go extends bl{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(),o=await this.separator(),r=await this.message(),a=await this.format(),i=await this.error()||await this.hint(),n=await this.footer(),l=[s,r,o,a].join(" ");if(this.state.prompt=l,i&&!l.includes(i))l+=" "+i;this.clear(e),this.write([t,l,n].filter(Boolean).join(`
|
|
35
|
+
`)),this.write(this.margin[2]),this.restore()}}ko.exports=Go});var Ho=x((Mp,Ko)=>{var wl=re();class qo extends wl{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)}}}Ko.exports=qo});var Vo=x((Mt)=>{var Fo=R(),T=(e,t)=>{Fo.defineExport(Mt,e,t),Fo.defineExport(Mt,e.toLowerCase(),t)};T("AutoComplete",()=>Us());T("BasicAuth",()=>Fs());T("Confirm",()=>Zs());T("Editable",()=>Js());T("Form",()=>Ie());T("Input",()=>Tt());T("Invisible",()=>mo());T("List",()=>uo());T("MultiSelect",()=>go());T("Numeral",()=>St());T("Password",()=>Eo());T("Scale",()=>To());T("Select",()=>re());T("Snippet",()=>Io());T("Sort",()=>Bo());T("Survey",()=>$o());T("Text",()=>Tt());T("Toggle",()=>Wo());T("Quiz",()=>Ho())});var jo=x((_p,Yo)=>{Yo.exports={ArrayPrompt:xe(),AuthPrompt:Nt(),BooleanPrompt:Pe(),NumberPrompt:St(),StringPrompt:de()}});var ie=x((Dp,Zo)=>{var zo=ye("assert"),_t=ye("events"),ae=R();class U extends _t{constructor(e,t){super();this.options=ae.merge({},e),this.answers={...t}}register(e,t){if(ae.isObject(e)){for(let o of Object.keys(e))this.register(o,e[o]);return this}zo.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(ae.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=ae.merge({},this.options,e),{type:s,name:o}=e,{set:r,get:a}=ae;if(typeof s==="function")s=await s.call(this,e,this.answers);if(!s)return this.answers[o];if(s==="number")s="numeral";zo(this.prompts[s],`Prompt "${s}" is not registered`);let i=new this.prompts[s](t),n=a(this.answers,o);if(i.state.answers=this.answers,i.enquirer=this,o)i.on("submit",(d)=>{this.emit("answer",o,d,i),r(this.answers,o,d)});let l=i.emit.bind(i);if(i.emit=(...d)=>{return this.emit.call(this,...d),l(...d)},this.emit("prompt",i,this),t.autofill&&n!=null){if(i.value=i.input=n,t.autofill==="show")await i.submit()}else n=i.value=await i.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||ue()}static get prompts(){return Vo()}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=(...a)=>{return e.emit(...a),r(...a)},o.prompt(t)};return ae.mixinEmitter(e,new _t),e}}ae.mixinEmitter(U,new _t);var Rt=U.prompts;for(let e of Object.keys(Rt)){let t=e.toLowerCase(),s=(o)=>new Rt[e](o).run();if(U.prompt[t]=s,U[t]=s,!U[e])Reflect.defineProperty(U,e,{get:()=>Rt[e]})}var Ee=(e)=>{ae.defineExport(U,e,()=>U.types[e])};Ee("ArrayPrompt");Ee("AuthPrompt");Ee("BooleanPrompt");Ee("NumberPrompt");Ee("StringPrompt");Zo.exports=U});var Ca=x((Lt,Ut)=>{(function(e,t){if(typeof Lt==="object"&&typeof Ut==="object")Ut.exports=t();else if(typeof define==="function"&&define.amd)define(function(){return t()});else e.pluralize=t()})(Lt,function(){var e=[],t=[],s={},o={},r={};function a(p){if(typeof p==="string")return new RegExp("^"+p+"$","i");return p}function i(p,u){if(p===u)return u;if(p===p.toLowerCase())return u.toLowerCase();if(p===p.toUpperCase())return u.toUpperCase();if(p[0]===p[0].toUpperCase())return u.charAt(0).toUpperCase()+u.substr(1).toLowerCase();return u.toLowerCase()}function n(p,u){return p.replace(/\$(\d{1,2})/g,function(f,y){return u[y]||""})}function l(p,u){return p.replace(u[0],function(f,y){var g=n(u[1],arguments);if(f==="")return i(p[y-1],g);return i(f,g)})}function d(p,u,f){if(!p.length||s.hasOwnProperty(p))return u;var y=f.length;while(y--){var g=f[y];if(g[0].test(u))return l(u,g)}return u}function m(p,u,f){return function(y){var g=y.toLowerCase();if(u.hasOwnProperty(g))return i(y,g);if(p.hasOwnProperty(g))return i(y,p[g]);return d(g,y,f)}}function h(p,u,f,y){return function(g){var E=g.toLowerCase();if(u.hasOwnProperty(E))return!0;if(p.hasOwnProperty(E))return!1;return d(E,E,f)===E}}function c(p,u,f){var y=u===1?c.singular(p):c.plural(p);return(f?u+" ":"")+y}return c.plural=m(r,o,e),c.isPlural=h(r,o,e),c.singular=m(o,r,t),c.isSingular=h(o,r,t),c.addPluralRule=function(p,u){e.push([a(p),u])},c.addSingularRule=function(p,u){t.push([a(p),u])},c.addUncountableRule=function(p){if(typeof p==="string"){s[p.toLowerCase()]=!0;return}c.addPluralRule(p,"$0"),c.addSingularRule(p,"$0")},c.addIrregularRule=function(p,u){u=u.toLowerCase(),p=p.toLowerCase(),r[p]=u,o[u]=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 c.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 c.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 c.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(c.addUncountableRule),c})});import{parseArgs as Ec}from"util";import{Exception as ri}from"@ooneex/exception";import{TerminalLogger as Ac}from"@ooneex/logger";import{container as gi}from"@ooneex/container";var Te=[];var kt=(e)=>{let t=null;return Te.find((s)=>{return t=gi.get(s),t.getName()===e}),t};import{homedir as Ei}from"os";import{join as it}from"path";import{TerminalLogger as Ai}from"@ooneex/logger";import{container as yi,EContainerScope as bi}from"@ooneex/container";var w={command:(e=bi.Singleton)=>{return(t)=>{yi.add(t,e),Te.push(t)}}};var Wt=`#compdef oo ooneex
|
|
36
36
|
|
|
37
37
|
_oo_modules() {
|
|
38
38
|
local -a modules
|
|
@@ -258,9 +258,9 @@ _ooneex() {
|
|
|
258
258
|
}
|
|
259
259
|
|
|
260
260
|
_ooneex "$@"
|
|
261
|
-
`;class Se{getName(){return"completion:zsh"}getDescription(){return"Install Zsh completion for oo command"}async run(){let e=it(
|
|
261
|
+
`;class Se{getName(){return"completion:zsh"}getDescription(){return"Install Zsh completion for oo command"}async run(){let e=it(Ei(),".zsh"),t=it(e,"_oo");await Bun.write(t,Wt);let s=it(e,"_ooneex");await Bun.write(s,qt);let o=new Ai;o.success(`${t} created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),o.success(`${s} created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),o.info(`Add the following to your .zshrc if not already present:
|
|
262
262
|
fpath=(~/.zsh $fpath)
|
|
263
|
-
autoload -Uz compinit && compinit`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0})}}Se=
|
|
263
|
+
autoload -Uz compinit && compinit`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0})}}Se=b([w.command()],Se);import{join as F}from"path";import{TerminalLogger as Sl}from"@ooneex/logger";import{toPascalCase as Cl}from"@ooneex/utils";var Qo=te(ie(),1);import{Assert as xl,Validation as El}from"@ooneex/validation";var Al=1,vl=/^[a-zA-Z][a-zA-Z0-9-]*$/;class Ae extends El{getConstraint(){return xl(`string >= ${Al}`)}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 o=e;if(!vl.test(o))return{isValid:!1,message:this.getErrorMessage()||"Invalid name format"};return{isValid:!0}}}var v=async(e)=>{return(await Qo.prompt({type:"input",name:"name",message:e.message,validate:(s)=>{let r=new Ae().validate(s);if(!r.isValid)return r.message||"Controller name is invalid";return!0}})).name};var Xo=`import { describe, expect, test } from "bun:test";
|
|
264
264
|
import { {{NAME}}Ai } from "@/ai/{{NAME}}Ai";
|
|
265
265
|
|
|
266
266
|
describe("{{NAME}}Ai", () => {
|
|
@@ -296,7 +296,7 @@ export class {{NAME}}Ai implements IAiChat<OpenAiConfigType> {
|
|
|
296
296
|
yield* this.ai.runStream(prompt || "My prompt", config);
|
|
297
297
|
}
|
|
298
298
|
}
|
|
299
|
-
`;class Be{getName(){return"make:ai"}getDescription(){return"Generate a new AI class"}async run(e){let{name:t,module:s}=e;if(!t)t=await v({message:"Enter name"});t=
|
|
299
|
+
`;class Be{getName(){return"make:ai"}getDescription(){return"Generate a new AI class"}async run(e){let{name:t,module:s}=e;if(!t)t=await v({message:"Enter name"});t=Cl(t).replace(/Ai$/,"");let o=Jo.replace(/{{NAME}}/g,t),r=s?F("modules",s):".",a=F(r,"src","ai"),i=F(process.cwd(),a),n=F(i,`${t}Ai.ts`);await Bun.write(n,o);let l=Xo.replace(/{{NAME}}/g,t),d=F(r,"tests","ai"),m=F(process.cwd(),d),h=F(m,`${t}Ai.spec.ts`);await Bun.write(h,l);let c=new Sl;c.success(`${F(a,t)}Ai.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),c.success(`${F(d,t)}Ai.spec.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0})}}Be=b([w.command()],Be);import{join as V}from"path";import{TerminalLogger as _l}from"@ooneex/logger";import{toPascalCase as Dl}from"@ooneex/utils";var er=`import { describe, expect, test } from "bun:test";
|
|
300
300
|
import { {{NAME}}Analytics } from "@/analytics/{{NAME}}Analytics";
|
|
301
301
|
|
|
302
302
|
describe("{{NAME}}Analytics", () => {
|
|
@@ -320,7 +320,7 @@ export class {{NAME}}Analytics<T extends CaptureOptionsType = CaptureOptionsType
|
|
|
320
320
|
// console.log("Analytics captured:", options);
|
|
321
321
|
}
|
|
322
322
|
}
|
|
323
|
-
`;class Le{getName(){return"make:analytics"}getDescription(){return"Generate a new analytics class"}async run(e){let{name:t,module:s}=e;if(!t)t=await v({message:"Enter analytics name"});t=
|
|
323
|
+
`;class Le{getName(){return"make:analytics"}getDescription(){return"Generate a new analytics class"}async run(e){let{name:t,module:s}=e;if(!t)t=await v({message:"Enter analytics name"});t=Dl(t).replace(/Analytics$/,"");let o=tr.replace(/{{NAME}}/g,t),r=s?V("modules",s):".",a=V(r,"src","analytics"),i=V(process.cwd(),a),n=V(i,`${t}Analytics.ts`);await Bun.write(n,o);let l=er.replace(/{{NAME}}/g,t),d=V(r,"tests","analytics"),m=V(process.cwd(),d),h=V(m,`${t}Analytics.spec.ts`);await Bun.write(h,l);let c=new _l;c.success(`${V(a,t)}Analytics.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),c.success(`${V(d,t)}Analytics.spec.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0})}}Le=b([w.command()],Le);import{join as S}from"path";import{TerminalLogger as Xl}from"@ooneex/logger";import{toKebabCase as Jl,toSnakeCase as ed}from"@ooneex/utils";var sr=te(ie(),1);var or=async(e)=>{let t=new Ae;return(await sr.prompt({type:"input",name:"destination",message:e.message,initial:e.initial||".",validate:(o)=>{let r=t.validate(o);if(!r.isValid)return r.message||"Invalid destination";return!0}})).destination};var rr=`import { RuleConfigSeverity, type UserConfig } from "@commitlint/types";
|
|
324
324
|
|
|
325
325
|
const Configuration: UserConfig = {
|
|
326
326
|
extends: ["@commitlint/config-conventional"],
|
|
@@ -338,7 +338,6 @@ const Configuration: UserConfig = {
|
|
|
338
338
|
[
|
|
339
339
|
"common",
|
|
340
340
|
"app",
|
|
341
|
-
// Add your scopes here
|
|
342
341
|
],
|
|
343
342
|
],
|
|
344
343
|
"scope-case": [RuleConfigSeverity.Error, "always", "lower-case"],
|
|
@@ -847,6 +846,15 @@ PORT=3000
|
|
|
847
846
|
# Server hostname (default: 0.0.0.0)
|
|
848
847
|
HOST_NAME=
|
|
849
848
|
|
|
849
|
+
# =============================================================================
|
|
850
|
+
# API
|
|
851
|
+
# =============================================================================
|
|
852
|
+
|
|
853
|
+
# Comma-separated internal API URLs
|
|
854
|
+
INTERNAL_API_URLS=
|
|
855
|
+
# Comma-separated external API URLs
|
|
856
|
+
EXTERNAL_API_URLS=
|
|
857
|
+
|
|
850
858
|
# =============================================================================
|
|
851
859
|
# Logs
|
|
852
860
|
# =============================================================================
|
|
@@ -1096,7 +1104,6 @@ await app.run();
|
|
|
1096
1104
|
"fmt": "bunx biome check --write",
|
|
1097
1105
|
"lint": "bunx nx run-many -t lint --output-style=stream --verbose",
|
|
1098
1106
|
"test": "bunx nx run-many -t test --output-style=stream --verbose",
|
|
1099
|
-
"docker": "bunx nx run-many -t docker --output-style=stream --verbose",
|
|
1100
1107
|
"docker:stop": "bunx nx run-many -t docker:stop --output-style=stream --verbose",
|
|
1101
1108
|
"migration:up": "bunx nx run-many -t migration:up --output-style=stream --verbose",
|
|
1102
1109
|
"seed:run": "bunx nx run-many -t seed:run --output-style=stream --verbose",
|
|
@@ -1160,7 +1167,164 @@ await app.run();
|
|
|
1160
1167
|
]
|
|
1161
1168
|
}
|
|
1162
1169
|
}
|
|
1163
|
-
`;var hr
|
|
1170
|
+
`;var hr=`# {{NAME}}
|
|
1171
|
+
|
|
1172
|
+
A modular, enterprise-grade backend framework built with TypeScript and Bun, powered by the **@ooneex** ecosystem.
|
|
1173
|
+
|
|
1174
|
+
## Prerequisites
|
|
1175
|
+
|
|
1176
|
+
- [Bun](https://bun.sh) (latest)
|
|
1177
|
+
- [Docker](https://www.docker.com/) & Docker Compose
|
|
1178
|
+
|
|
1179
|
+
## Getting Started
|
|
1180
|
+
|
|
1181
|
+
### 1. Install dependencies
|
|
1182
|
+
|
|
1183
|
+
\`\`\`bash
|
|
1184
|
+
bun install
|
|
1185
|
+
\`\`\`
|
|
1186
|
+
|
|
1187
|
+
### 2. Configure environment
|
|
1188
|
+
|
|
1189
|
+
\`\`\`bash
|
|
1190
|
+
cp modules/app/.env.example modules/app/.env
|
|
1191
|
+
\`\`\`
|
|
1192
|
+
|
|
1193
|
+
Edit \`modules/app/.env\` with your configuration values.
|
|
1194
|
+
|
|
1195
|
+
### 3. Run migrations and seeds
|
|
1196
|
+
|
|
1197
|
+
\`\`\`bash
|
|
1198
|
+
bun run migration:up
|
|
1199
|
+
bun run seed:run
|
|
1200
|
+
\`\`\`
|
|
1201
|
+
|
|
1202
|
+
### 4. Start the development server
|
|
1203
|
+
|
|
1204
|
+
\`\`\`bash
|
|
1205
|
+
bun run dev
|
|
1206
|
+
\`\`\`
|
|
1207
|
+
|
|
1208
|
+
The server starts on \`http://localhost:3000\` by default.
|
|
1209
|
+
|
|
1210
|
+
## Commands
|
|
1211
|
+
|
|
1212
|
+
| Command | Description |
|
|
1213
|
+
| ---------------------- | ------------------------------------ |
|
|
1214
|
+
| \`bun run dev\` | Start dev server with Docker |
|
|
1215
|
+
| \`bun run build\` | Build for production |
|
|
1216
|
+
| \`bun run test\` | Run all tests |
|
|
1217
|
+
| \`bun run lint\` | Run TypeScript check + Biome linting |
|
|
1218
|
+
| \`bun run fmt\` | Format code with Biome |
|
|
1219
|
+
| \`bun run migration:up\` | Execute pending database migrations |
|
|
1220
|
+
| \`bun run seed:run\` | Populate database with seed data |
|
|
1221
|
+
| \`bun run docker:stop\` | Stop all Docker containers |
|
|
1222
|
+
| \`bun run commit\` | Interactive conventional commit |
|
|
1223
|
+
|
|
1224
|
+
## Module Architecture
|
|
1225
|
+
|
|
1226
|
+
Each module under \`modules/\` follows a consistent structure and registers its components via a Module class:
|
|
1227
|
+
|
|
1228
|
+
\`\`\`typescript
|
|
1229
|
+
@decorator.module({
|
|
1230
|
+
controllers: [], // HTTP / WebSocket route handlers
|
|
1231
|
+
entities: [], // TypeORM database entities
|
|
1232
|
+
permissions: [], // Role-based access control
|
|
1233
|
+
middlewares: [], // HTTP middleware pipeline
|
|
1234
|
+
cronJobs: [], // Scheduled tasks
|
|
1235
|
+
events: [], // Pub/Sub event handlers
|
|
1236
|
+
})
|
|
1237
|
+
class AppModule {}
|
|
1238
|
+
\`\`\`
|
|
1239
|
+
|
|
1240
|
+
## Docker
|
|
1241
|
+
|
|
1242
|
+
### Production build
|
|
1243
|
+
|
|
1244
|
+
\`\`\`bash
|
|
1245
|
+
docker build -t {{NAME}} --build-arg DATABASE_URL=<url> modules/app
|
|
1246
|
+
docker run -p 3000:3000 {{NAME}}
|
|
1247
|
+
\`\`\`
|
|
1248
|
+
|
|
1249
|
+
## Code Quality
|
|
1250
|
+
|
|
1251
|
+
- **Formatter/Linter:** Biome (double quotes, 2-space indent, 120 char line width)
|
|
1252
|
+
- **Commit conventions:** Conventional Commits enforced via Commitlint + Husky
|
|
1253
|
+
- **Pre-commit hooks:** Biome check + TypeScript type check on staged files
|
|
1254
|
+
|
|
1255
|
+
## Ooneex CLI
|
|
1256
|
+
|
|
1257
|
+
The **@ooneex/cli** provides code scaffolding commands to quickly generate modules, controllers, services, entities, pub/sub events, and more.
|
|
1258
|
+
|
|
1259
|
+
### Install
|
|
1260
|
+
|
|
1261
|
+
\`\`\`bash
|
|
1262
|
+
bun add -g @ooneex/cli
|
|
1263
|
+
\`\`\`
|
|
1264
|
+
|
|
1265
|
+
After installation, both \`ooneex\` and \`oo\` commands are available globally.
|
|
1266
|
+
|
|
1267
|
+
### Install Zsh Completion
|
|
1268
|
+
|
|
1269
|
+
\`\`\`bash
|
|
1270
|
+
oo completion:zsh
|
|
1271
|
+
\`\`\`
|
|
1272
|
+
|
|
1273
|
+
Then add the following to your \`~/.zshrc\`:
|
|
1274
|
+
|
|
1275
|
+
\`\`\`bash
|
|
1276
|
+
fpath=(~/.zsh $fpath)
|
|
1277
|
+
autoload -Uz compinit && compinit
|
|
1278
|
+
\`\`\`
|
|
1279
|
+
|
|
1280
|
+
Restart your terminal to enable autocompletion for all \`oo\` commands.
|
|
1281
|
+
|
|
1282
|
+
### Examples
|
|
1283
|
+
|
|
1284
|
+
#### Generate a new module
|
|
1285
|
+
|
|
1286
|
+
\`\`\`bash
|
|
1287
|
+
oo make:module --name=billing
|
|
1288
|
+
\`\`\`
|
|
1289
|
+
|
|
1290
|
+
#### Generate a controller
|
|
1291
|
+
|
|
1292
|
+
\`\`\`bash
|
|
1293
|
+
oo make:controller --name=invoice --module=billing --route-path=/invoices --route-method=GET
|
|
1294
|
+
\`\`\`
|
|
1295
|
+
|
|
1296
|
+
#### Generate a service
|
|
1297
|
+
|
|
1298
|
+
\`\`\`bash
|
|
1299
|
+
oo make:service --name=invoice --module=billing
|
|
1300
|
+
\`\`\`
|
|
1301
|
+
|
|
1302
|
+
#### Generate an entity
|
|
1303
|
+
|
|
1304
|
+
\`\`\`bash
|
|
1305
|
+
oo make:entity --name=invoice --module=billing --table-name=invoices
|
|
1306
|
+
\`\`\`
|
|
1307
|
+
|
|
1308
|
+
#### Generate a pub/sub event
|
|
1309
|
+
|
|
1310
|
+
\`\`\`bash
|
|
1311
|
+
oo make:pubsub --name=invoice-created --module=billing --channel=billing.invoice.created
|
|
1312
|
+
\`\`\`
|
|
1313
|
+
|
|
1314
|
+
### Install Claude Skills
|
|
1315
|
+
|
|
1316
|
+
Generate Claude skill definitions for AI-assisted code scaffolding:
|
|
1317
|
+
|
|
1318
|
+
\`\`\`bash
|
|
1319
|
+
oo make:claude:skill
|
|
1320
|
+
\`\`\`
|
|
1321
|
+
|
|
1322
|
+
This creates \`.claude/skills/\` in your project with skill guides for each \`make:*\` command (controller, service, entity, pubsub, etc.), enabling Claude to scaffold code following your project's conventions.
|
|
1323
|
+
|
|
1324
|
+
## License
|
|
1325
|
+
|
|
1326
|
+
Proprietary - All rights reserved.
|
|
1327
|
+
`;var fr=`{
|
|
1164
1328
|
"compilerOptions": {
|
|
1165
1329
|
"jsx": "react-jsx",
|
|
1166
1330
|
"lib": ["ES2022", "DOM"],
|
|
@@ -1189,7 +1353,7 @@ await app.run();
|
|
|
1189
1353
|
},
|
|
1190
1354
|
"exclude": ["node_modules", ".github", ".husky", ".nx", ".zed", ".vscode"]
|
|
1191
1355
|
}
|
|
1192
|
-
`;import{join as
|
|
1356
|
+
`;import{join as B}from"path";import{TerminalLogger as zl}from"@ooneex/logger";import{toKebabCase as Zl,toPascalCase as Ql}from"@ooneex/utils";var gr=`import type { ModuleType } from "@ooneex/module";
|
|
1193
1357
|
|
|
1194
1358
|
export const {{NAME}}Module: ModuleType = {
|
|
1195
1359
|
controllers: [],
|
|
@@ -1199,7 +1363,7 @@ export const {{NAME}}Module: ModuleType = {
|
|
|
1199
1363
|
cronJobs: [],
|
|
1200
1364
|
events: [],
|
|
1201
1365
|
};
|
|
1202
|
-
`;var
|
|
1366
|
+
`;var yr=`{
|
|
1203
1367
|
"name": "@module/{{NAME}}",
|
|
1204
1368
|
"description": "",
|
|
1205
1369
|
"version": "0.0.1",
|
|
@@ -1208,7 +1372,7 @@ export const {{NAME}}Module: ModuleType = {
|
|
|
1208
1372
|
"lint": "tsgo --noEmit && bunx biome lint"
|
|
1209
1373
|
}
|
|
1210
1374
|
}
|
|
1211
|
-
`;var
|
|
1375
|
+
`;var br=`import { describe, expect, test } from "bun:test";
|
|
1212
1376
|
import { {{NAME}}Module } from "@/{{NAME}}Module";
|
|
1213
1377
|
|
|
1214
1378
|
describe("{{NAME}}Module", () => {
|
|
@@ -1232,7 +1396,7 @@ describe("{{NAME}}Module", () => {
|
|
|
1232
1396
|
expect(Array.isArray({{NAME}}Module.events)).toBe(true);
|
|
1233
1397
|
});
|
|
1234
1398
|
});
|
|
1235
|
-
`;var
|
|
1399
|
+
`;var wr=`{
|
|
1236
1400
|
"extends": "../../tsconfig.json",
|
|
1237
1401
|
"compilerOptions": {
|
|
1238
1402
|
"types": ["@types/bun"],
|
|
@@ -1245,8 +1409,11 @@ describe("{{NAME}}Module", () => {
|
|
|
1245
1409
|
}
|
|
1246
1410
|
`;class fe{getName(){return"make:module"}getDescription(){return"Generate a new module"}async addToAppModule(e,t,s){let o=await Bun.file(e).text(),r=`${t}Module`,a=`@${s}/${r}`,i=`import { ${r} } from "${a}";
|
|
1247
1411
|
`,n=o.lastIndexOf("import "),l=o.indexOf(`
|
|
1248
|
-
`,n);o=`${o.slice(0,l+1)}${i}${o.slice(l+1)}`;let d=["controllers","entities","permissions","middlewares","cronJobs","events"];for(let m of d){let h=new RegExp(`(${m}:\\s*\\[)([^\\]]*)`,"s"),
|
|
1249
|
-
|
|
1412
|
+
`,n);o=`${o.slice(0,l+1)}${i}${o.slice(l+1)}`;let d=["controllers","entities","permissions","middlewares","cronJobs","events"];for(let m of d){let h=new RegExp(`(${m}:\\s*\\[)([^\\]]*)`,"s"),c=o.match(h);if(c){let p=c[2]?.trim(),u=`...${r}.${m}`,f=p?`${p}, ${u}`:u;o=o.replace(h,`$1${f}`)}}await Bun.write(e,o)}async addModuleScope(e,t){let s=await Bun.file(e).text(),o=/("scope-enum":\s*\[\s*RuleConfigSeverity\.Error,\s*"always",\s*\[)([\s\S]*?)(\])/,r=s.match(o);if(r){let a=r[2]?.trim()??"",i=`"${t}"`;if(!a.includes(i)){let n=a?`${a}
|
|
1413
|
+
${i},`:`
|
|
1414
|
+
${i},`;s=s.replace(o,`$1${n}
|
|
1415
|
+
$3`),await Bun.write(e,s)}}}async addPathAlias(e,t){let s=await Bun.file(e).text(),o=JSON.parse(s);o.compilerOptions??={},o.compilerOptions.paths??={},o.compilerOptions.paths[`@${t}/*`]=[`../${t}/src/*`],await Bun.write(e,`${JSON.stringify(o,null,2)}
|
|
1416
|
+
`)}async run(e){let{cwd:t=process.cwd(),silent:s=!1,skipMigrations:o=!1,skipSeeds:r=!1}=e,{name:a}=e;if(!a)a=await v({message:"Enter module name"});let i=Ql(a).replace(/Module$/,""),n=Zl(i),l=B(t,"modules",n),d=B(l,"src"),m=B(l,"tests"),h=gr.replace(/{{NAME}}/g,i),c=yr.replace(/{{NAME}}/g,n),p=br.replace(/{{NAME}}/g,i);if(await Bun.write(B(d,`${i}Module.ts`),h),!o)await Bun.write(B(d,"migrations","migrations.ts"),"");if(!r)await Bun.write(B(d,"seeds","seeds.ts"),"");if(await Bun.write(B(l,"package.json"),c),await Bun.write(B(l,"tsconfig.json"),wr),await Bun.write(B(m,`${i}Module.spec.ts`),p),n!=="app"){let f=B(t,"modules","app","src","AppModule.ts");if(await Bun.file(f).exists())await this.addToAppModule(f,i,n);let y=B(t,"modules","app","tsconfig.json");if(await Bun.file(y).exists())await this.addPathAlias(y,n)}let u=B(t,".commitlintrc.ts");if(await Bun.file(u).exists())await this.addModuleScope(u,n);if(!s)new zl().success(`modules/${n} created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0})}}fe=b([w.command()],fe);class Ue{getName(){return"make:app"}getDescription(){return"Generate a new application"}async run(e){let{name:t,destination:s}=e;if(!t)t=await v({message:"Enter application name"});let o=Jl(t);if(!s)s=await or({message:"Enter destination path",initial:o});let r=ur.replace(/{{NAME}}/g,o);await Bun.write(S(s,".commitlintrc.ts"),rr),await Bun.write(S(s,".gitignore"),ar),await Bun.write(S(s,"biome.jsonc"),nr),await Bun.write(S(s,"bunfig.toml"),lr),await Bun.write(S(s,"nx.json"),pr),await Bun.write(S(s,"package.json"),r),await Bun.write(S(s,"README.md"),hr.replace(/{{NAME}}/g,o)),await Bun.write(S(s,"tsconfig.json"),fr),await Bun.write(S(s,".husky","commit-msg"),'bunx commitlint --edit "$1"'),await Bun.write(S(s,".husky","pre-commit"),"lint-staged"),await new fe().run({name:"app",cwd:s,silent:!0,skipMigrations:!0,skipSeeds:!0});let i=S(s,"modules","app","package.json"),n=await Bun.file(i).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(i,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(S(s,"modules","app",".env"),l),await Bun.write(S(s,"modules","app",".env.example"),Dt),await Bun.write(S(s,"modules","app","src","databases","AppDatabase.ts"),ir),await Bun.write(S(s,"modules","app","src","index.ts"),cr);let d=ed(t),m=mr.replace(/{{NAME}}/g,d);await Bun.write(S(s,"modules","app","docker-compose.yml"),m);let h=dr.replace(/{{NAME}}/g,d);await Bun.write(S(s,"modules","app","Dockerfile"),h),await Bun.write(S(s,"modules","app","var",".gitkeep"),""),new Xl().success(`${o} created successfully at ${s}`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0})}}Ue=b([w.command()],Ue);import{join as Y}from"path";import{TerminalLogger as od}from"@ooneex/logger";import{toPascalCase as rd}from"@ooneex/utils";var xr=`import { describe, expect, test } from "bun:test";
|
|
1250
1417
|
import { {{NAME}}Cache } from "@/cache/{{NAME}}Cache";
|
|
1251
1418
|
|
|
1252
1419
|
describe("{{NAME}}Cache", () => {
|
|
@@ -1274,7 +1441,7 @@ describe("{{NAME}}Cache", () => {
|
|
|
1274
1441
|
expect(typeof {{NAME}}Cache.prototype.has).toBe("function");
|
|
1275
1442
|
});
|
|
1276
1443
|
});
|
|
1277
|
-
`;var
|
|
1444
|
+
`;var Er=`import { CacheException, decorator } from "@ooneex/cache";
|
|
1278
1445
|
import type { ICache } from "@ooneex/cache";
|
|
1279
1446
|
|
|
1280
1447
|
@decorator.cache()
|
|
@@ -1295,7 +1462,7 @@ export class {{NAME}}Cache implements ICache {
|
|
|
1295
1462
|
throw new CacheException(\`Failed to check if key "\${key}" exists: Not implemented\`);
|
|
1296
1463
|
}
|
|
1297
1464
|
}
|
|
1298
|
-
`;class $e{getName(){return"make:cache"}getDescription(){return"Generate a new cache class"}async run(e){let{name:t,module:s}=e;if(!t)t=await v({message:"Enter cache name"});t=sd(t).replace(/Cache$/,"");let o=xr.replace(/{{NAME}}/g,t),r=s?Y("modules",s):".",a=Y(r,"src","cache"),i=Y(process.cwd(),a),n=Y(i,`${t}Cache.ts`);await Bun.write(n,o);let l=wr.replace(/{{NAME}}/g,t),d=Y(r,"tests","cache"),m=Y(process.cwd(),d),h=Y(m,`${t}Cache.spec.ts`);await Bun.write(h,l);let p=new td;p.success(`${Y(a,t)}Cache.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),p.success(`${Y(d,t)}Cache.spec.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0})}}$e=y([b.command()],$e);import{join as Ge}from"path";import{TerminalLogger as Ed}from"@ooneex/logger";var Er="---\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\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 Ar="---\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\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 vr="---\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\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 Nr="---\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\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\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\nEdit `src/types/routes/<route.name>.ts` to define the route's type contract.\n\n**Add or remove `params`, `payload`, and `queries` based on context:**\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 generated 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\nexport type <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\nexport type <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\nexport type <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\nexport type <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- Implement the `index` method with actual controller logic\n- Inject any required dependencies (repositories, services) via the constructor\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\";\nimport type { <TypeName>RouteType } from \"../types/routes/<route.name>\";\n\n@Route.<method>(\"<route.path>\", {\n name: \"<route.name>\",\n version: 1,\n description: \"\",\n params: {\n // id: Assert(\"string\"),\n },\n payload: Assert({\n\n }),\n queries: Assert({\n\n }),\n response: Assert({\n\n }),\n roles: [ERole.USER],\n})\nexport class <Name>Controller {\n public async index(context: ContextType<<TypeName>RouteType>) {\n // const { id } = context.params;\n\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\";\nimport type { <TypeName>RouteType } from \"../types/routes/<route.name>\";\n\n@Route.socket(\"<route.path>\", {\n name: \"<route.name>\",\n version: 1,\n description: \"\",\n params: {\n // id: Assert(\"string\"),\n },\n payload: Assert({\n\n }),\n queries: Assert({\n\n }),\n response: Assert({\n\n }),\n roles: [ERole.USER],\n})\nexport class <Name>Controller {\n public async index(context: ContextType<<TypeName>RouteType>) {\n // const { id } = context.params;\n\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 src/types/routes/<route.name>.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 Tr="---\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\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 Sr="---\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\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 Cr="---\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\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 Mr="---\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\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 Rr="---\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\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 _r="---\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\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 Dr="---\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\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 Ir="---\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\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 Pr="---\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\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 Or="---\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\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 Br="---\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\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 Lr="---\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\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 Ur="---\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\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 $r="---\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\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 Ad={"make.ai":Er,"make.analytics":Ar,"make.cache":vr,"make.controller":Nr,"make.cron":Tr,"make.database":Sr,"make.entity":Cr,"make.logger":Mr,"make.mailer":Rr,"make.middleware":_r,"make.migration":Dr,"make.permission":Ir,"make.pubsub":Pr,"make.repository":Or,"make.seed":Br,"make.service":Lr,"make.storage":Ur,"make.vector-database":$r};class ke{getName(){return"make:claude:skill"}getDescription(){return"Generate Claude skills from templates"}async run(){let e=Ge(".claude","skills"),t=Ge(process.cwd(),e),s=new Ed;for(let[o,r]of Object.entries(Ad)){let a=o.replace(/\./g,"-"),i=Ge(t,a,"SKILL.md");await Bun.write(i,r),s.success(`${Ge(e,a,"SKILL.md")} created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0})}}}ke=y([b.command()],ke);import{basename as $d,join as I}from"path";import{TerminalLogger as Gd}from"@ooneex/logger";import{toKebabCase as kd,toPascalCase as Bt,trim as Wd}from"@ooneex/utils";var Gr=te(ie(),1),ge=async(e)=>{return(await Gr.prompt({type:"confirm",name:"confirm",message:e.message})).confirm};var ve=["GET","POST","PUT","DELETE","PATCH","OPTIONS","HEAD"];var kr=te(ie(),1);import{Assert as vd,Validation as Nd}from"@ooneex/validation";class It extends Nd{getConstraint(){return vd("string >= 3")}getErrorMessage(){return`Route method must be one of: ${ve.join(", ")}`}validate(e,t){let s=super.validate(e,t);if(!s.isValid)return s;let o=e;if(o.trim()!==o)return{isValid:!1,message:this.getErrorMessage()||"Invalid route method format"};let r=o.toUpperCase();if(!ve.includes(r))return{isValid:!1,message:this.getErrorMessage()||"Invalid route method"};return{isValid:!0}}}var Wr=async(e)=>{return(await kr.prompt({type:"select",name:"method",message:e.message,initial:e.initial??0,choices:ve.map((s)=>s),validate:(s)=>{let r=new It().validate(s);if(!r.isValid)return r.message||"Route method is invalid";return!0}})).method};var qr=te(ie(),1);import{Assert as Td,Validation as Sd}from"@ooneex/validation";var Cd=/^[a-zA-Z0-9]+\.[a-zA-Z0-9]+\.[a-zA-Z0-9]+$/;class Pt extends Sd{getConstraint(){return Td("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 o=e;if(o.trim()!==o)return{isValid:!1,message:this.getErrorMessage()||"Invalid route name format"};if(!Cd.test(o))return{isValid:!1,message:this.getErrorMessage()||"Invalid route name format"};let r=o.split(".");if(r.length!==3)return{isValid:!1,message:this.getErrorMessage()||"Invalid route name format"};let[a,i,n]=r;if(!a||!i||!n)return{isValid:!1,message:this.getErrorMessage()||"Invalid route name format"};return{isValid:!0}}}var Kr=async(e)=>{return(await qr.prompt({type:"input",name:"routeName",message:e.message,validate:(s)=>{let r=new Pt().validate(s);if(!r.isValid)return r.message||"Route name is invalid";return!0}})).routeName};var Hr=te(ie(),1);import{Assert as Md,Validation as Rd}from"@ooneex/validation";var _d=1,Dd=/^\/[\w\-/:]*$/,Id=/^[a-zA-Z0-9\-_]+$/,Pd=/^:[a-zA-Z][a-zA-Z0-9]*$/;class Ot extends Rd{getConstraint(){return Md(`string >= ${_d}`)}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 o=e;if(o.trim()!==o)return{isValid:!1,message:this.getErrorMessage()||"Invalid route path format"};if(!o.startsWith("/"))return{isValid:!1,message:"Route path must start with '/'"};if(o.length>1&&o.endsWith("/"))return{isValid:!1,message:"Route path cannot end with '/' (except for root path)"};if(!Dd.test(o))return{isValid:!1,message:this.getErrorMessage()||"Invalid route path format"};if(o==="/")return{isValid:!0};let r=o.slice(1).split("/");for(let a of r){if(!a)return{isValid:!1,message:"Route path cannot contain empty segments (double slashes)"};if(a.startsWith(":")){if(!Pd.test(a))return{isValid:!1,message:`Invalid parameter segment '${a}'. Parameters must follow format ':paramName' with alphanumeric characters only`}}else if(!Id.test(a))return{isValid:!1,message:`Invalid path segment '${a}'. Segments must contain only letters, numbers, hyphens, and underscores`}}return{isValid:!0}}}var Fr=async(e)=>{return(await Hr.prompt({type:"input",name:"path",message:e.message,initial:e.initial??"/",validate:(s)=>{let r=new Ot().validate(s);if(!r.isValid)return r.message||"Route path is invalid";return!0}})).path};var Vr=`import type { ContextType } from "@ooneex/socket";
|
|
1465
|
+
`;class $e{getName(){return"make:cache"}getDescription(){return"Generate a new cache class"}async run(e){let{name:t,module:s}=e;if(!t)t=await v({message:"Enter cache name"});t=rd(t).replace(/Cache$/,"");let o=Er.replace(/{{NAME}}/g,t),r=s?Y("modules",s):".",a=Y(r,"src","cache"),i=Y(process.cwd(),a),n=Y(i,`${t}Cache.ts`);await Bun.write(n,o);let l=xr.replace(/{{NAME}}/g,t),d=Y(r,"tests","cache"),m=Y(process.cwd(),d),h=Y(m,`${t}Cache.spec.ts`);await Bun.write(h,l);let c=new od;c.success(`${Y(a,t)}Cache.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),c.success(`${Y(d,t)}Cache.spec.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0})}}$e=b([w.command()],$e);import{join as Ge}from"path";import{TerminalLogger as vd}from"@ooneex/logger";var Ar="---\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\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 vr="---\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\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 Nr="---\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\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 Tr="---\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\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\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\nEdit `src/types/routes/<route.name>.ts` to define the route's type contract.\n\n**Add or remove `params`, `payload`, and `queries` based on context:**\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 generated 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\nexport type <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\nexport type <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\nexport type <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\nexport type <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- Implement the `index` method with actual controller logic\n- Inject any required dependencies (repositories, services) via the constructor\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\";\nimport type { <TypeName>RouteType } from \"../types/routes/<route.name>\";\n\n@Route.<method>(\"<route.path>\", {\n name: \"<route.name>\",\n version: 1,\n description: \"\",\n params: {\n // id: Assert(\"string\"),\n },\n payload: Assert({\n\n }),\n queries: Assert({\n\n }),\n response: Assert({\n\n }),\n roles: [ERole.USER],\n})\nexport class <Name>Controller {\n public async index(context: ContextType<<TypeName>RouteType>) {\n // const { id } = context.params;\n\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\";\nimport type { <TypeName>RouteType } from \"../types/routes/<route.name>\";\n\n@Route.socket(\"<route.path>\", {\n name: \"<route.name>\",\n version: 1,\n description: \"\",\n params: {\n // id: Assert(\"string\"),\n },\n payload: Assert({\n\n }),\n queries: Assert({\n\n }),\n response: Assert({\n\n }),\n roles: [ERole.USER],\n})\nexport class <Name>Controller {\n public async index(context: ContextType<<TypeName>RouteType>) {\n // const { id } = context.params;\n\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 src/types/routes/<route.name>.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 Sr="---\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\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 Cr="---\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\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 Mr="---\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\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 Rr="---\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\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 _r="---\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\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 Dr="---\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\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 Ir="---\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\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 Pr="---\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\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 Or="---\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\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 Br="---\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\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 Lr="---\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\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 Ur="---\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\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 $r="---\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\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 Gr="---\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\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 Nd={"make.ai":Ar,"make.analytics":vr,"make.cache":Nr,"make.controller":Tr,"make.cron":Sr,"make.database":Cr,"make.entity":Mr,"make.logger":Rr,"make.mailer":_r,"make.middleware":Dr,"make.migration":Ir,"make.permission":Pr,"make.pubsub":Or,"make.repository":Br,"make.seed":Lr,"make.service":Ur,"make.storage":$r,"make.vector-database":Gr};class ke{getName(){return"make:claude:skill"}getDescription(){return"Generate Claude skills from templates"}async run(){let e=Ge(".claude","skills"),t=Ge(process.cwd(),e),s=new vd;for(let[o,r]of Object.entries(Nd)){let a=o.replace(/\./g,"-"),i=Ge(t,a,"SKILL.md");await Bun.write(i,r),s.success(`${Ge(e,a,"SKILL.md")} created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0})}}}ke=b([w.command()],ke);import{basename as kd,join as I}from"path";import{TerminalLogger as Wd}from"@ooneex/logger";import{toKebabCase as qd,toPascalCase as Bt,trim as Kd}from"@ooneex/utils";var kr=te(ie(),1),ge=async(e)=>{return(await kr.prompt({type:"confirm",name:"confirm",message:e.message})).confirm};var ve=["GET","POST","PUT","DELETE","PATCH","OPTIONS","HEAD"];var Wr=te(ie(),1);import{Assert as Td,Validation as Sd}from"@ooneex/validation";class It extends Sd{getConstraint(){return Td("string >= 3")}getErrorMessage(){return`Route method must be one of: ${ve.join(", ")}`}validate(e,t){let s=super.validate(e,t);if(!s.isValid)return s;let o=e;if(o.trim()!==o)return{isValid:!1,message:this.getErrorMessage()||"Invalid route method format"};let r=o.toUpperCase();if(!ve.includes(r))return{isValid:!1,message:this.getErrorMessage()||"Invalid route method"};return{isValid:!0}}}var qr=async(e)=>{return(await Wr.prompt({type:"select",name:"method",message:e.message,initial:e.initial??0,choices:ve.map((s)=>s),validate:(s)=>{let r=new It().validate(s);if(!r.isValid)return r.message||"Route method is invalid";return!0}})).method};var Kr=te(ie(),1);import{Assert as Cd,Validation as Md}from"@ooneex/validation";var Rd=/^[a-zA-Z0-9]+\.[a-zA-Z0-9]+\.[a-zA-Z0-9]+$/;class Pt extends Md{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 o=e;if(o.trim()!==o)return{isValid:!1,message:this.getErrorMessage()||"Invalid route name format"};if(!Rd.test(o))return{isValid:!1,message:this.getErrorMessage()||"Invalid route name format"};let r=o.split(".");if(r.length!==3)return{isValid:!1,message:this.getErrorMessage()||"Invalid route name format"};let[a,i,n]=r;if(!a||!i||!n)return{isValid:!1,message:this.getErrorMessage()||"Invalid route name format"};return{isValid:!0}}}var Hr=async(e)=>{return(await Kr.prompt({type:"input",name:"routeName",message:e.message,validate:(s)=>{let r=new Pt().validate(s);if(!r.isValid)return r.message||"Route name is invalid";return!0}})).routeName};var Fr=te(ie(),1);import{Assert as _d,Validation as Dd}from"@ooneex/validation";var Id=1,Pd=/^\/[\w\-/:]*$/,Od=/^[a-zA-Z0-9\-_]+$/,Bd=/^:[a-zA-Z][a-zA-Z0-9]*$/;class Ot extends Dd{getConstraint(){return _d(`string >= ${Id}`)}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 o=e;if(o.trim()!==o)return{isValid:!1,message:this.getErrorMessage()||"Invalid route path format"};if(!o.startsWith("/"))return{isValid:!1,message:"Route path must start with '/'"};if(o.length>1&&o.endsWith("/"))return{isValid:!1,message:"Route path cannot end with '/' (except for root path)"};if(!Pd.test(o))return{isValid:!1,message:this.getErrorMessage()||"Invalid route path format"};if(o==="/")return{isValid:!0};let r=o.slice(1).split("/");for(let a of r){if(!a)return{isValid:!1,message:"Route path cannot contain empty segments (double slashes)"};if(a.startsWith(":")){if(!Bd.test(a))return{isValid:!1,message:`Invalid parameter segment '${a}'. Parameters must follow format ':paramName' with alphanumeric characters only`}}else if(!Od.test(a))return{isValid:!1,message:`Invalid path segment '${a}'. Segments must contain only letters, numbers, hyphens, and underscores`}}return{isValid:!0}}}var Vr=async(e)=>{return(await Fr.prompt({type:"input",name:"path",message:e.message,initial:e.initial??"/",validate:(s)=>{let r=new Ot().validate(s);if(!r.isValid)return r.message||"Route path is invalid";return!0}})).path};var Yr=`import type { ContextType } from "@ooneex/socket";
|
|
1299
1466
|
import { ERole } from "@ooneex/role";
|
|
1300
1467
|
import { Route } from "@ooneex/routing";
|
|
1301
1468
|
import { Assert } from "@ooneex/validation";
|
|
@@ -1328,7 +1495,7 @@ export class {{NAME}}Controller {
|
|
|
1328
1495
|
});
|
|
1329
1496
|
}
|
|
1330
1497
|
}
|
|
1331
|
-
`;var
|
|
1498
|
+
`;var jr=`import { describe, expect, test } from "bun:test";
|
|
1332
1499
|
import { {{NAME}}Controller } from "@/controllers/{{NAME}}Controller";
|
|
1333
1500
|
|
|
1334
1501
|
describe("{{NAME}}Controller", () => {
|
|
@@ -1341,7 +1508,7 @@ describe("{{NAME}}Controller", () => {
|
|
|
1341
1508
|
expect(typeof {{NAME}}Controller.prototype.index).toBe("function");
|
|
1342
1509
|
});
|
|
1343
1510
|
});
|
|
1344
|
-
`;var
|
|
1511
|
+
`;var zr=`import type { ContextType } from "@ooneex/controller";
|
|
1345
1512
|
import { ERole } from "@ooneex/role";
|
|
1346
1513
|
import { Route } from "@ooneex/routing";
|
|
1347
1514
|
import { Assert } from "@ooneex/validation";
|
|
@@ -1374,7 +1541,7 @@ export class {{NAME}}Controller {
|
|
|
1374
1541
|
});
|
|
1375
1542
|
}
|
|
1376
1543
|
}
|
|
1377
|
-
`;var
|
|
1544
|
+
`;var Zr=`export type {{TYPE_NAME}}RouteType = {
|
|
1378
1545
|
params: {
|
|
1379
1546
|
|
|
1380
1547
|
},
|
|
@@ -1390,7 +1557,7 @@ export class {{NAME}}Controller {
|
|
|
1390
1557
|
};
|
|
1391
1558
|
`;class We{getName(){return"make:controller"}getDescription(){return"Generate a new controller class"}async addToModule(e,t){let s=await Bun.file(e).text(),o=`${t}Controller`,r=`import { ${o} } from "./controllers/${o}";
|
|
1392
1559
|
`,a=s.lastIndexOf("import "),i=s.indexOf(`
|
|
1393
|
-
`,a);s=`${s.slice(0,i+1)}${r}${s.slice(i+1)}`;let n=/(controllers:\s*\[)([^\]]*)/s,l=s.match(n);if(l){let d=l[2]?.trim(),m=d?`${d}, ${o}`:o;s=s.replace(n,`$1${m}`)}await Bun.write(e,s)}async run(e){let{name:t,module:s,isSocket:o}=e;if(!t)t=await v({message:"Enter controller name"});if(o===void 0)o=await ge({message:"Is this a socket controller?"});t=Bt(t).replace(/Controller$/,"");let{route:r={}}=e,i=(o?
|
|
1560
|
+
`,a);s=`${s.slice(0,i+1)}${r}${s.slice(i+1)}`;let n=/(controllers:\s*\[)([^\]]*)/s,l=s.match(n);if(l){let d=l[2]?.trim(),m=d?`${d}, ${o}`:o;s=s.replace(n,`$1${m}`)}await Bun.write(e,s)}async run(e){let{name:t,module:s,isSocket:o}=e;if(!t)t=await v({message:"Enter controller name"});if(o===void 0)o=await ge({message:"Is this a socket controller?"});t=Bt(t).replace(/Controller$/,"");let{route:r={}}=e,i=(o?Yr:zr).replaceAll("{{NAME}}",t),n="",l="";if(!r.name)r.name=await Hr({message:"Enter route name (e.g., api.user.create)"});if(n=Bt(r.name),l=r.name,i=i.replaceAll("{{ROUTE_NAME}}",r.name).replaceAll("{{TYPE_NAME}}",n).replaceAll("{{TYPE_NAME_FILE}}",l),!r.path)r.path=await Vr({message:"Enter route path",initial:"/"});let d=`/${qd(Kd(r.path,"/"))}`;if(i=i.replaceAll("{{ROUTE_PATH}}",d),!o&&!r.method)r.method=await qr({message:"Enter route method"});if(!o&&r.method)i=i.replaceAll("{{ROUTE_METHOD}}",r.method.toLowerCase());let m=s?I("modules",s):".",h=I(m,"src","controllers"),c=I(process.cwd(),h),p=I(c,`${t}Controller.ts`);await Bun.write(p,i);let u=I(m,"src","types","routes"),f=I(process.cwd(),u),y=I(f,`${l}.ts`),g=Zr.replaceAll("{{TYPE_NAME}}",n);await Bun.write(y,g);let E=jr.replace(/{{NAME}}/g,t),A=I(m,"tests","controllers"),N=I(process.cwd(),A),C=I(N,`${t}Controller.spec.ts`);await Bun.write(C,E);let _=Bt(kd(process.cwd())),Ne=I(process.cwd(),"src",`${_}Module.ts`);if(await Bun.file(Ne).exists())await this.addToModule(Ne,t);let ee=new Wd;ee.success(`${I(h,t)}Controller.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),ee.success(`${I(u,l)}.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),ee.success(`${I(A,t)}Controller.spec.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0})}}We=b([w.command()],We);import{basename as Vd,join as $}from"path";import{TerminalLogger as Yd}from"@ooneex/logger";import{toPascalCase as Jr}from"@ooneex/utils";var Qr=`import { describe, expect, test } from "bun:test";
|
|
1394
1561
|
import { {{NAME}}Cron } from "@/cron/{{NAME}}Cron";
|
|
1395
1562
|
|
|
1396
1563
|
describe("{{NAME}}Cron", () => {
|
|
@@ -1413,7 +1580,7 @@ describe("{{NAME}}Cron", () => {
|
|
|
1413
1580
|
expect(typeof {{NAME}}Cron.prototype.handler).toBe("function");
|
|
1414
1581
|
});
|
|
1415
1582
|
});
|
|
1416
|
-
`;var
|
|
1583
|
+
`;var Xr=`import type { TimeZoneType } from "@ooneex/country";
|
|
1417
1584
|
import type { CronTimeType } from "@ooneex/cron";
|
|
1418
1585
|
import { Cron, decorator } from "@ooneex/cron";
|
|
1419
1586
|
|
|
@@ -1436,7 +1603,7 @@ export class {{NAME}}Cron extends Cron {
|
|
|
1436
1603
|
}
|
|
1437
1604
|
`;class qe{getName(){return"make:cron"}getDescription(){return"Generate a new cron class"}async addToModule(e,t){let s=await Bun.file(e).text(),o=`${t}Cron`,r=`import { ${o} } from "./cron/${o}";
|
|
1438
1605
|
`,a=s.lastIndexOf("import "),i=s.indexOf(`
|
|
1439
|
-
`,a);s=`${s.slice(0,i+1)}${r}${s.slice(i+1)}`;let n=/(cronJobs:\s*\[)([^\]]*)/s,l=s.match(n);if(l){let d=l[2]?.trim(),m=d?`${d}, ${o}`:o;s=s.replace(n,`$1${m}`)}await Bun.write(e,s)}async run(e){let{name:t,module:s}=e;if(!t)t=await v({message:"Enter cron name"});t=
|
|
1606
|
+
`,a);s=`${s.slice(0,i+1)}${r}${s.slice(i+1)}`;let n=/(cronJobs:\s*\[)([^\]]*)/s,l=s.match(n);if(l){let d=l[2]?.trim(),m=d?`${d}, ${o}`:o;s=s.replace(n,`$1${m}`)}await Bun.write(e,s)}async run(e){let{name:t,module:s}=e;if(!t)t=await v({message:"Enter cron name"});t=Jr(t).replace(/Cron$/,"");let o=Xr.replace(/{{NAME}}/g,t),r=s?$("modules",s):".",a=$(r,"src","cron"),i=$(process.cwd(),a),n=$(i,`${t}Cron.ts`);await Bun.write(n,o);let l=Qr.replace(/{{NAME}}/g,t),d=$(r,"tests","cron"),m=$(process.cwd(),d),h=$(m,`${t}Cron.spec.ts`);await Bun.write(h,l);let c=Jr(Vd(process.cwd())),p=$(process.cwd(),"src",`${c}Module.ts`);if(await Bun.file(p).exists())await this.addToModule(p,t);let u=new Yd;u.success(`${$(a,t)}Cron.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),u.success(`${$(d,t)}Cron.spec.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0})}}qe=b([w.command()],qe);import{join as j}from"path";import{TerminalLogger as Zd}from"@ooneex/logger";import{toPascalCase as Qd}from"@ooneex/utils";var ea=`import { describe, expect, test } from "bun:test";
|
|
1440
1607
|
import { {{NAME}}Database } from "@/databases/{{NAME}}Database";
|
|
1441
1608
|
|
|
1442
1609
|
describe("{{NAME}}Database", () => {
|
|
@@ -1449,7 +1616,7 @@ describe("{{NAME}}Database", () => {
|
|
|
1449
1616
|
expect(typeof {{NAME}}Database.prototype.getSource).toBe("function");
|
|
1450
1617
|
});
|
|
1451
1618
|
});
|
|
1452
|
-
`;var
|
|
1619
|
+
`;var ta=`import { DataSource } from "typeorm";
|
|
1453
1620
|
import { TypeormDatabase, DatabaseException, decorator } from "@ooneex/database";
|
|
1454
1621
|
|
|
1455
1622
|
@decorator.database()
|
|
@@ -1472,7 +1639,7 @@ export class {{NAME}}Database extends TypeormDatabase {
|
|
|
1472
1639
|
return this.source;
|
|
1473
1640
|
}
|
|
1474
1641
|
}
|
|
1475
|
-
`;class Ke{getName(){return"make:database"}getDescription(){return"Generate a new database class"}async run(e){let{name:t,module:s}=e;if(!t)t=await v({message:"Enter database name"});t=
|
|
1642
|
+
`;class Ke{getName(){return"make:database"}getDescription(){return"Generate a new database class"}async run(e){let{name:t,module:s}=e;if(!t)t=await v({message:"Enter database name"});t=Qd(t).replace(/DatabaseAdapter$/,"").replace(/Database$/,"");let o=ta.replace(/{{NAME}}/g,t),r=s?j("modules",s):".",a=j(r,"src","databases"),i=j(process.cwd(),a),n=j(i,`${t}Database.ts`);await Bun.write(n,o);let l=ea.replace(/{{NAME}}/g,t),d=j(r,"tests","databases"),m=j(process.cwd(),d),h=j(m,`${t}Database.spec.ts`);await Bun.write(h,l);let c=new Zd;c.success(`${j(a,t)}Database.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),c.success(`${j(d,t)}Database.spec.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0})}}Ke=b([w.command()],Ke);import{join as Ta}from"path";import{TerminalLogger as ym}from"@ooneex/logger";var{YAML:Sa}=globalThis.Bun;var oa=te(ie(),1),sa=["clickhouse","elasticsearch","grafana","jaeger","keycloak","libretranslate","maildev","memcached","minio","mongodb","mysql","nats","postgres","prometheus","rabbitmq","redis","temporal","vault"],ra=async(e)=>{return(await oa.prompt({type:"autocomplete",name:"service",message:e.message,initial:e.initial,choices:sa.map((s)=>s),validate:(s)=>{if(!sa.includes(s))return"Docker service is invalid";return!0}})).service};var aa=`services:
|
|
1476
1643
|
# ClickHouse - Column-oriented OLAP database for analytics
|
|
1477
1644
|
# Docs: https://clickhouse.com/docs
|
|
1478
1645
|
# HTTP API: http://localhost:8123
|
|
@@ -1493,7 +1660,7 @@ export class {{NAME}}Database extends TypeormDatabase {
|
|
|
1493
1660
|
|
|
1494
1661
|
volumes:
|
|
1495
1662
|
clickhouse_data:
|
|
1496
|
-
`;var
|
|
1663
|
+
`;var ia=`services:
|
|
1497
1664
|
# Elasticsearch - Full-text search and analytics engine
|
|
1498
1665
|
# Docs: https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html
|
|
1499
1666
|
# HTTP API: http://localhost:9200
|
|
@@ -1514,7 +1681,7 @@ volumes:
|
|
|
1514
1681
|
|
|
1515
1682
|
volumes:
|
|
1516
1683
|
elasticsearch_data:
|
|
1517
|
-
`;var
|
|
1684
|
+
`;var na=`services:
|
|
1518
1685
|
# Grafana - Metrics visualization and dashboards
|
|
1519
1686
|
# Docs: https://grafana.com/docs/grafana/latest/
|
|
1520
1687
|
# Web UI: http://localhost:3000 (ooneex/ooneex)
|
|
@@ -1532,7 +1699,7 @@ volumes:
|
|
|
1532
1699
|
|
|
1533
1700
|
volumes:
|
|
1534
1701
|
grafana_data:
|
|
1535
|
-
`;var
|
|
1702
|
+
`;var la=`services:
|
|
1536
1703
|
# Jaeger - Distributed tracing system
|
|
1537
1704
|
# Docs: https://www.jaegertracing.io/docs/
|
|
1538
1705
|
# Web UI: http://localhost:16686
|
|
@@ -1546,7 +1713,7 @@ volumes:
|
|
|
1546
1713
|
- "16686:16686"
|
|
1547
1714
|
- "6831:6831/udp"
|
|
1548
1715
|
- "14268:14268"
|
|
1549
|
-
`;var
|
|
1716
|
+
`;var da=`services:
|
|
1550
1717
|
# Keycloak - Identity and access management
|
|
1551
1718
|
# Docs: https://www.keycloak.org/documentation
|
|
1552
1719
|
# Admin Console: http://localhost:8080 (ooneex/ooneex)
|
|
@@ -1560,7 +1727,7 @@ volumes:
|
|
|
1560
1727
|
- KEYCLOAK_ADMIN=ooneex
|
|
1561
1728
|
- KEYCLOAK_ADMIN_PASSWORD=ooneex
|
|
1562
1729
|
command: start-dev
|
|
1563
|
-
`;var
|
|
1730
|
+
`;var ma=`services:
|
|
1564
1731
|
# LibreTranslate - Self-hosted machine translation API
|
|
1565
1732
|
# Docs: https://libretranslate.com/docs/
|
|
1566
1733
|
# API: http://localhost:4000
|
|
@@ -1587,7 +1754,7 @@ volumes:
|
|
|
1587
1754
|
|
|
1588
1755
|
volumes:
|
|
1589
1756
|
libretranslate_models:
|
|
1590
|
-
`;var
|
|
1757
|
+
`;var ca=`services:
|
|
1591
1758
|
# MailDev - Email testing tool with web UI
|
|
1592
1759
|
# Docs: https://github.com/maildev/maildev
|
|
1593
1760
|
# Web UI: http://localhost:1080
|
|
@@ -1598,7 +1765,7 @@ volumes:
|
|
|
1598
1765
|
ports:
|
|
1599
1766
|
- "1080:1080"
|
|
1600
1767
|
- "1025:1025"
|
|
1601
|
-
`;var
|
|
1768
|
+
`;var pa=`services:
|
|
1602
1769
|
# Memcached - Distributed memory caching system
|
|
1603
1770
|
# Docs: https://memcached.org/
|
|
1604
1771
|
# Connection: localhost:11211
|
|
@@ -1608,7 +1775,7 @@ volumes:
|
|
|
1608
1775
|
restart: "on-failure"
|
|
1609
1776
|
ports:
|
|
1610
1777
|
- "11211:11211"
|
|
1611
|
-
`;var
|
|
1778
|
+
`;var ua=`services:
|
|
1612
1779
|
# MinIO - S3-compatible object storage
|
|
1613
1780
|
# Docs: https://min.io/docs/minio/container/index.html
|
|
1614
1781
|
# API: http://localhost:9000
|
|
@@ -1629,7 +1796,7 @@ volumes:
|
|
|
1629
1796
|
|
|
1630
1797
|
volumes:
|
|
1631
1798
|
minio_data:
|
|
1632
|
-
`;var
|
|
1799
|
+
`;var ha=`services:
|
|
1633
1800
|
# MongoDB - NoSQL document database
|
|
1634
1801
|
# Docs: https://www.mongodb.com/docs/
|
|
1635
1802
|
# Connection: mongodb://ooneex:ooneex@localhost:27017/ooneex
|
|
@@ -1648,7 +1815,7 @@ volumes:
|
|
|
1648
1815
|
|
|
1649
1816
|
volumes:
|
|
1650
1817
|
mongodb_data:
|
|
1651
|
-
`;var
|
|
1818
|
+
`;var fa=`services:
|
|
1652
1819
|
# MySQL - Alternative relational database
|
|
1653
1820
|
# Docs: https://dev.mysql.com/doc/
|
|
1654
1821
|
# Connection: mysql://ooneex:ooneex@localhost:3306/ooneex
|
|
@@ -1668,7 +1835,7 @@ volumes:
|
|
|
1668
1835
|
|
|
1669
1836
|
volumes:
|
|
1670
1837
|
mysql_db:
|
|
1671
|
-
`;var
|
|
1838
|
+
`;var ga=`services:
|
|
1672
1839
|
# NATS - High-performance messaging system with JetStream
|
|
1673
1840
|
# Docs: https://docs.nats.io/
|
|
1674
1841
|
# Client: localhost:4222
|
|
@@ -1681,7 +1848,7 @@ volumes:
|
|
|
1681
1848
|
- "4222:4222"
|
|
1682
1849
|
- "8222:8222"
|
|
1683
1850
|
command: "--jetstream --http_port 8222"
|
|
1684
|
-
`;var
|
|
1851
|
+
`;var ya=`services:
|
|
1685
1852
|
# Jade - FastAPI REST API to fetch YouTube metadata and download videos or audio via Dockerized microservice.
|
|
1686
1853
|
# API: http://localhost:8000
|
|
1687
1854
|
# Docs: http://localhost:8000/docs
|
|
@@ -1699,7 +1866,7 @@ volumes:
|
|
|
1699
1866
|
|
|
1700
1867
|
volumes:
|
|
1701
1868
|
jade_data:
|
|
1702
|
-
`;var
|
|
1869
|
+
`;var ba=`services:
|
|
1703
1870
|
# PostgreSQL - Primary relational database
|
|
1704
1871
|
# Docs: https://www.postgresql.org/docs/
|
|
1705
1872
|
# Connection: postgresql://ooneex:ooneex@localhost:5432/ooneex
|
|
@@ -1720,7 +1887,7 @@ volumes:
|
|
|
1720
1887
|
|
|
1721
1888
|
volumes:
|
|
1722
1889
|
postgres_db:
|
|
1723
|
-
`;var
|
|
1890
|
+
`;var wa=`services:
|
|
1724
1891
|
# Prometheus - Metrics collection and monitoring
|
|
1725
1892
|
# Docs: https://prometheus.io/docs/
|
|
1726
1893
|
# Web UI: http://localhost:9090
|
|
@@ -1735,7 +1902,7 @@ volumes:
|
|
|
1735
1902
|
|
|
1736
1903
|
volumes:
|
|
1737
1904
|
prometheus_data:
|
|
1738
|
-
`;var
|
|
1905
|
+
`;var xa=`services:
|
|
1739
1906
|
# RabbitMQ - Message broker for async processing
|
|
1740
1907
|
# Docs: https://www.rabbitmq.com/docs
|
|
1741
1908
|
# AMQP: amqp://ooneex:ooneex@localhost:5672/ooneex
|
|
@@ -1757,7 +1924,7 @@ volumes:
|
|
|
1757
1924
|
|
|
1758
1925
|
volumes:
|
|
1759
1926
|
rabbitmq_data:
|
|
1760
|
-
`;var
|
|
1927
|
+
`;var Ea=`services:
|
|
1761
1928
|
# Redis - In-memory data store for caching and sessions
|
|
1762
1929
|
# Docs: https://redis.io/docs/
|
|
1763
1930
|
# Connection: redis://localhost:6379
|
|
@@ -1772,7 +1939,7 @@ volumes:
|
|
|
1772
1939
|
|
|
1773
1940
|
volumes:
|
|
1774
1941
|
redis_data:
|
|
1775
|
-
`;var
|
|
1942
|
+
`;var Aa=`services:
|
|
1776
1943
|
# Temporal - Workflow orchestration engine
|
|
1777
1944
|
# Docs: https://docs.temporal.io/
|
|
1778
1945
|
# gRPC: localhost:7233
|
|
@@ -1789,7 +1956,7 @@ volumes:
|
|
|
1789
1956
|
- POSTGRES_USER=ooneex
|
|
1790
1957
|
- POSTGRES_PWD=ooneex
|
|
1791
1958
|
- POSTGRES_SEEDS=postgres
|
|
1792
|
-
`;var
|
|
1959
|
+
`;var va=`services:
|
|
1793
1960
|
# Vault - Secrets management and encryption
|
|
1794
1961
|
# Docs: https://developer.hashicorp.com/vault/docs
|
|
1795
1962
|
# Web UI: http://localhost:8200 (token: ooneex)
|
|
@@ -1804,20 +1971,20 @@ volumes:
|
|
|
1804
1971
|
- VAULT_DEV_LISTEN_ADDRESS=0.0.0.0:8200
|
|
1805
1972
|
cap_add:
|
|
1806
1973
|
- IPC_LOCK
|
|
1807
|
-
`;var
|
|
1974
|
+
`;var Na={clickhouse:aa,elasticsearch:ia,grafana:na,"ooneex-jade":ya,jaeger:la,keycloak:da,libretranslate:ma,maildev:ca,memcached:pa,minio:ua,mongodb:ha,mysql:fa,nats:ga,postgres:ba,prometheus:wa,rabbitmq:xa,redis:Ea,temporal:Aa,vault:va};function bm(e){let t=e.split(`
|
|
1808
1975
|
`),s=[],o=!1;for(let r of t){if(r.startsWith("services:")){o=!0;continue}if(o){if(r.startsWith("volumes:")||r.startsWith("networks:"))break;s.push(r)}}return s.join(`
|
|
1809
|
-
`)}function
|
|
1810
|
-
volumes:`),u=
|
|
1811
|
-
networks:`),f=-1;if(
|
|
1812
|
-
${m}${
|
|
1813
|
-
${m}`;for(let
|
|
1814
|
-
volumes:`)){let g=
|
|
1815
|
-
volumes:`),
|
|
1816
|
-
${
|
|
1976
|
+
`)}function wm(e){let t=Sa.parse(e);return t.volumes?Object.keys(t.volumes):[]}class He{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 ra({message:"Select docker service"});let s=Na[t],o=Ta(process.cwd(),"docker-compose.yml"),r=new ym,a=Bun.file(o);if(await a.exists()){let l=await a.text(),d=Sa.parse(l);if(d.services&&t in d.services){r.warn(`Service "${t}" already exists in docker-compose.yml`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0});return}let m=bm(s),h=wm(s),c=l,p=c.indexOf(`
|
|
1977
|
+
volumes:`),u=c.indexOf(`
|
|
1978
|
+
networks:`),f=-1;if(p!==-1&&u!==-1)f=Math.min(p,u);else if(p!==-1)f=p;else if(u!==-1)f=u;if(f!==-1)c=`${c.slice(0,f)}
|
|
1979
|
+
${m}${c.slice(f)}`;else c=`${c.trimEnd()}
|
|
1980
|
+
${m}`;for(let y of h)if(!c.includes(` ${y}:`))if(c.includes(`
|
|
1981
|
+
volumes:`)){let g=c.indexOf(`
|
|
1982
|
+
volumes:`),E=c.slice(g+9);c=`${c.slice(0,g+9)}
|
|
1983
|
+
${y}:${E}`}else c=`${c.trimEnd()}
|
|
1817
1984
|
|
|
1818
1985
|
volumes:
|
|
1819
|
-
${
|
|
1820
|
-
`;await Bun.write(o,
|
|
1986
|
+
${y}:
|
|
1987
|
+
`;await Bun.write(o,c)}else await Bun.write(o,s);let i=Ta(process.cwd(),"package.json"),n=Bun.file(i);if(await n.exists()){let l=await n.json();l.scripts=l.scripts||{},l.scripts.docker="docker compose up -d",await Bun.write(i,JSON.stringify(l,null,2))}r.success(`Service "${t}" added to docker-compose.yml`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),r.info("Run 'bun run docker' to start docker containers",void 0,{showTimestamp:!1,showArrow:!0,showLevel:!1})}}He=b([w.command()],He);var Da=te(Ca(),1);import{basename as Am,join as G}from"path";import{TerminalLogger as vm}from"@ooneex/logger";import{toPascalCase as _a,toSnakeCase as Nm}from"@ooneex/utils";var Ma=`import { describe, expect, test } from "bun:test";
|
|
1821
1988
|
import { {{NAME}}Entity } from "@/entities/{{NAME}}Entity";
|
|
1822
1989
|
|
|
1823
1990
|
describe("{{NAME}}Entity", () => {
|
|
@@ -1882,7 +2049,7 @@ describe("{{NAME}}Entity", () => {
|
|
|
1882
2049
|
expect("deletedAt" in entity).toBe(true);
|
|
1883
2050
|
});
|
|
1884
2051
|
});
|
|
1885
|
-
`;var
|
|
2052
|
+
`;var Ra=`import type { LocaleType } from "@ooneex/translation";
|
|
1886
2053
|
import { random } from "@ooneex/utils";
|
|
1887
2054
|
import { Column, CreateDateColumn, DeleteDateColumn, PrimaryColumn, UpdateDateColumn } from "typeorm";
|
|
1888
2055
|
|
|
@@ -1935,7 +2102,7 @@ export class {{NAME}}Entity extends BaseEntity {
|
|
|
1935
2102
|
}
|
|
1936
2103
|
`;class Fe{getName(){return"make:entity"}getDescription(){return"Generate a new entity class"}async addToModule(e,t){let s=await Bun.file(e).text(),o=`${t}Entity`,r=`import { ${o} } from "./entities/${o}";
|
|
1937
2104
|
`,a=s.lastIndexOf("import "),i=s.indexOf(`
|
|
1938
|
-
`,a);s=`${s.slice(0,i+1)}${r}${s.slice(i+1)}`;let n=/(entities:\s*\[)([^\]]*)/s,l=s.match(n);if(l){let d=l[2]?.trim(),m=d?`${d}, ${o}`:o;s=s.replace(n,`$1${m}`)}await Bun.write(e,s)}async run(e){let{name:t,module:s,tableName:o}=e;if(!t)t=await v({message:"Enter entity name"});if(t=
|
|
2105
|
+
`,a);s=`${s.slice(0,i+1)}${r}${s.slice(i+1)}`;let n=/(entities:\s*\[)([^\]]*)/s,l=s.match(n);if(l){let d=l[2]?.trim(),m=d?`${d}, ${o}`:o;s=s.replace(n,`$1${m}`)}await Bun.write(e,s)}async run(e){let{name:t,module:s,tableName:o}=e;if(!t)t=await v({message:"Enter entity name"});if(t=_a(t).replace(/Entity$/,""),!o)o=Nm(Da.default(t));let r=Ra.replace(/{{NAME}}/g,t).replace(/{{TABLE_NAME}}/g,o),a=s?G("modules",s):".",i=G(a,"src","entities"),n=G(process.cwd(),i),l=G(n,`${t}Entity.ts`);await Bun.write(l,r);let d=Ma.replace(/{{NAME}}/g,t),m=G(a,"tests","entities"),h=G(process.cwd(),m),c=G(h,`${t}Entity.spec.ts`);await Bun.write(c,d);let p=_a(Am(process.cwd())),u=G(process.cwd(),"src",`${p}Module.ts`);if(await Bun.file(u).exists())await this.addToModule(u,t);let f=new vm;f.success(`${G(i,t)}Entity.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),f.success(`${G(m,t)}Entity.spec.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0})}}Fe=b([w.command()],Fe);import{join as z}from"path";import{TerminalLogger as Cm}from"@ooneex/logger";import{toPascalCase as Mm}from"@ooneex/utils";var Ia=`import { describe, expect, test } from "bun:test";
|
|
1939
2106
|
import { {{NAME}}Logger } from "@/loggers/{{NAME}}Logger";
|
|
1940
2107
|
|
|
1941
2108
|
describe("{{NAME}}Logger", () => {
|
|
@@ -1978,7 +2145,7 @@ describe("{{NAME}}Logger", () => {
|
|
|
1978
2145
|
expect(typeof {{NAME}}Logger.prototype.error).toBe("function");
|
|
1979
2146
|
});
|
|
1980
2147
|
});
|
|
1981
|
-
`;var
|
|
2148
|
+
`;var Pa=`import type { IException } from "@ooneex/exception";
|
|
1982
2149
|
import type { ILogger } from "@ooneex/logger";
|
|
1983
2150
|
import type { ScalarType } from "@ooneex/types";
|
|
1984
2151
|
import { decorator } from "@ooneex/logger";
|
|
@@ -2013,7 +2180,7 @@ export class {{NAME}}Logger implements ILogger {
|
|
|
2013
2180
|
// Handle error logging
|
|
2014
2181
|
}
|
|
2015
2182
|
}
|
|
2016
|
-
`;class Ve{getName(){return"make:logger"}getDescription(){return"Generate a new logger class"}async run(e){let{name:t,module:s}=e;if(!t)t=await v({message:"Enter logger name"});t=
|
|
2183
|
+
`;class Ve{getName(){return"make:logger"}getDescription(){return"Generate a new logger class"}async run(e){let{name:t,module:s}=e;if(!t)t=await v({message:"Enter logger name"});t=Mm(t).replace(/Logger$/,"");let o=Pa.replace(/{{NAME}}/g,t),r=s?z("modules",s):".",a=z(r,"src","loggers"),i=z(process.cwd(),a),n=z(i,`${t}Logger.ts`);await Bun.write(n,o);let l=Ia.replace(/{{NAME}}/g,t),d=z(r,"tests","loggers"),m=z(process.cwd(),d),h=z(m,`${t}Logger.spec.ts`);await Bun.write(h,l);let c=new Cm;c.success(`${z(a,t)}Logger.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),c.success(`${z(d,t)}Logger.spec.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0})}}Ve=b([w.command()],Ve);import{join as P}from"path";import{TerminalLogger as Pm}from"@ooneex/logger";import{toPascalCase as Om}from"@ooneex/utils";var Oa=`import { describe, expect, test } from "bun:test";
|
|
2017
2184
|
import { {{NAME}}Mailer } from "@/mailers/{{NAME}}Mailer";
|
|
2018
2185
|
|
|
2019
2186
|
describe("{{NAME}}Mailer", () => {
|
|
@@ -2026,7 +2193,7 @@ describe("{{NAME}}Mailer", () => {
|
|
|
2026
2193
|
expect(typeof {{NAME}}Mailer.prototype.send).toBe("function");
|
|
2027
2194
|
});
|
|
2028
2195
|
});
|
|
2029
|
-
`;var
|
|
2196
|
+
`;var Ba=`import { inject } from "@ooneex/container";
|
|
2030
2197
|
import type { IMailer } from "@ooneex/mailer";
|
|
2031
2198
|
import { type {{NAME}}MailerPropsType, {{NAME}}MailerTemplate } from "./{{NAME}}MailerTemplate";
|
|
2032
2199
|
|
|
@@ -2050,7 +2217,7 @@ export class {{NAME}}Mailer implements IMailer {
|
|
|
2050
2217
|
});
|
|
2051
2218
|
}
|
|
2052
2219
|
}
|
|
2053
|
-
`;var
|
|
2220
|
+
`;var La=`import { describe, expect, test } from "bun:test";
|
|
2054
2221
|
import { {{NAME}}MailerTemplate } from "@/mailers/{{NAME}}MailerTemplate";
|
|
2055
2222
|
|
|
2056
2223
|
describe("{{NAME}}MailerTemplate", () => {
|
|
@@ -2062,7 +2229,7 @@ describe("{{NAME}}MailerTemplate", () => {
|
|
|
2062
2229
|
expect(typeof {{NAME}}MailerTemplate).toBe("function");
|
|
2063
2230
|
});
|
|
2064
2231
|
});
|
|
2065
|
-
`;var
|
|
2232
|
+
`;var Ua=`import { MailerLayout } from "@ooneex/mailer";
|
|
2066
2233
|
|
|
2067
2234
|
export type {{NAME}}MailerPropsType = {
|
|
2068
2235
|
link: string;
|
|
@@ -2077,7 +2244,7 @@ export const {{NAME}}MailerTemplate = (props?: {{NAME}}MailerPropsType) => (
|
|
|
2077
2244
|
<MailerLayout.Footer />
|
|
2078
2245
|
</MailerLayout>
|
|
2079
2246
|
);
|
|
2080
|
-
`;class Ye{getName(){return"make:mailer"}getDescription(){return"Generate a new mailer class"}async run(e){let{name:t,module:s}=e;if(!t)t=await v({message:"Enter mailer name"});t=
|
|
2247
|
+
`;class Ye{getName(){return"make:mailer"}getDescription(){return"Generate a new mailer class"}async run(e){let{name:t,module:s}=e;if(!t)t=await v({message:"Enter mailer name"});t=Om(t).replace(/Mailer$/,"");let o=Ba.replace(/{{NAME}}/g,t),r=Ua.replace(/{{NAME}}/g,t),a=s?P("modules",s):".",i=P(a,"src","mailers"),n=P(process.cwd(),i),l=P(n,`${t}Mailer.ts`),d=P(n,`${t}MailerTemplate.tsx`);await Bun.write(l,o),await Bun.write(d,r);let m=Oa.replace(/{{NAME}}/g,t),h=La.replace(/{{NAME}}/g,t),c=P(a,"tests","mailers"),p=P(process.cwd(),c),u=P(p,`${t}Mailer.spec.ts`),f=P(p,`${t}MailerTemplate.spec.ts`);await Bun.write(u,m),await Bun.write(f,h);let y=new Pm;y.success(`${P(i,t)}Mailer.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),y.success(`${P(i,t)}MailerTemplate.tsx created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),y.success(`${P(c,t)}Mailer.spec.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),y.success(`${P(c,t)}MailerTemplate.spec.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0})}}Ye=b([w.command()],Ye);import{basename as $m,join as k}from"path";import{TerminalLogger as Gm}from"@ooneex/logger";import{toPascalCase as Wa}from"@ooneex/utils";var $a=`import type { ContextType } from "@ooneex/socket";
|
|
2081
2248
|
import { decorator, type IMiddleware } from "@ooneex/middleware";
|
|
2082
2249
|
|
|
2083
2250
|
@decorator.middleware()
|
|
@@ -2089,7 +2256,7 @@ export class {{NAME}}Middleware implements IMiddleware {
|
|
|
2089
2256
|
return context
|
|
2090
2257
|
}
|
|
2091
2258
|
}
|
|
2092
|
-
`;var
|
|
2259
|
+
`;var Ga=`import { describe, expect, test } from "bun:test";
|
|
2093
2260
|
import { {{NAME}}Middleware } from "@/middlewares/{{NAME}}Middleware";
|
|
2094
2261
|
|
|
2095
2262
|
describe("{{NAME}}Middleware", () => {
|
|
@@ -2102,7 +2269,7 @@ describe("{{NAME}}Middleware", () => {
|
|
|
2102
2269
|
expect(typeof {{NAME}}Middleware.prototype.handler).toBe("function");
|
|
2103
2270
|
});
|
|
2104
2271
|
});
|
|
2105
|
-
`;var
|
|
2272
|
+
`;var ka=`import type { ContextType } from "@ooneex/controller";
|
|
2106
2273
|
import { decorator, type IMiddleware } from "@ooneex/middleware";
|
|
2107
2274
|
|
|
2108
2275
|
@decorator.middleware()
|
|
@@ -2116,7 +2283,7 @@ export class {{NAME}}Middleware implements IMiddleware {
|
|
|
2116
2283
|
}
|
|
2117
2284
|
`;class je{getName(){return"make:middleware"}getDescription(){return"Generate a new middleware class"}async addToModule(e,t){let s=await Bun.file(e).text(),o=`${t}Middleware`,r=`import { ${o} } from "./middlewares/${o}";
|
|
2118
2285
|
`,a=s.lastIndexOf("import "),i=s.indexOf(`
|
|
2119
|
-
`,a);s=`${s.slice(0,i+1)}${r}${s.slice(i+1)}`;let n=/(middlewares:\s*\[)([^\]]*)/s,l=s.match(n);if(l){let d=l[2]?.trim(),m=d?`${d}, ${o}`:o;s=s.replace(n,`$1${m}`)}await Bun.write(e,s)}async run(e){let{name:t,module:s,isSocket:o}=e;if(!t)t=await v({message:"Enter middleware name"});if(o===void 0)o=await ge({message:"Is this a socket middleware?"});t=
|
|
2286
|
+
`,a);s=`${s.slice(0,i+1)}${r}${s.slice(i+1)}`;let n=/(middlewares:\s*\[)([^\]]*)/s,l=s.match(n);if(l){let d=l[2]?.trim(),m=d?`${d}, ${o}`:o;s=s.replace(n,`$1${m}`)}await Bun.write(e,s)}async run(e){let{name:t,module:s,isSocket:o}=e;if(!t)t=await v({message:"Enter middleware name"});if(o===void 0)o=await ge({message:"Is this a socket middleware?"});t=Wa(t).replace(/Middleware$/,"");let a=(o?$a:ka).replace(/{{NAME}}/g,t),i=s?k("modules",s):".",n=k(i,"src","middlewares"),l=k(process.cwd(),n),d=k(l,`${t}Middleware.ts`);await Bun.write(d,a);let m=Ga.replace(/{{NAME}}/g,t),h=k(i,"tests","middlewares"),c=k(process.cwd(),h),p=k(c,`${t}Middleware.spec.ts`);await Bun.write(p,m);let u=Wa($m(process.cwd())),f=k(process.cwd(),"src",`${u}Module.ts`);if(await Bun.file(f).exists())await this.addToModule(f,t);let y=new Gm;y.success(`${k(n,t)}Middleware.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),y.success(`${k(h,t)}Middleware.spec.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0})}}je=b([w.command()],je);import{join as ze}from"path";import{TerminalLogger as Wm}from"@ooneex/logger";import{migrationCreate as qm}from"@ooneex/migrations";var qa=`#!/usr/bin/env bun
|
|
2120
2287
|
|
|
2121
2288
|
import { migrationUp } from "@ooneex/migrations";
|
|
2122
2289
|
import "@/migrations/migrations";
|
|
@@ -2125,7 +2292,7 @@ await migrationUp({
|
|
|
2125
2292
|
databaseUrl: Bun.env.DATABASE_URL || ":memory:",
|
|
2126
2293
|
tableName: "migrations",
|
|
2127
2294
|
});
|
|
2128
|
-
`;class Ze{getName(){return"make:migration"}getDescription(){return"Generate a new migration file"}async run(e){let{module:t}=e,s=t?ze("modules",t):".",o=await
|
|
2295
|
+
`;class Ze{getName(){return"make:migration"}getDescription(){return"Generate a new migration file"}async run(e){let{module:t}=e,s=t?ze("modules",t):".",o=await qm({dir:ze(s,"src/migrations")}),r=ze(process.cwd(),s,"bin","migration","up.ts");if(!await Bun.file(r).exists())await Bun.write(r,qa);let i=ze(process.cwd(),"package.json"),n=Bun.file(i);if(await n.exists()){let d=await n.json();d.scripts=d.scripts||{},d.scripts["migration:up"]="bun ./bin/migration/up.ts",await Bun.write(i,JSON.stringify(d,null,2))}let l=new Wm;l.success(`${o} 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})}}Ze=b([w.command()],Ze);import{basename as Fm,join as W}from"path";import{TerminalLogger as Vm}from"@ooneex/logger";import{toPascalCase as Fa}from"@ooneex/utils";var Ka=`import { describe, expect, test } from "bun:test";
|
|
2129
2296
|
import { Permission } from "@ooneex/permission";
|
|
2130
2297
|
import { {{NAME}}Permission } from "@/permissions/{{NAME}}Permission";
|
|
2131
2298
|
|
|
@@ -2150,7 +2317,7 @@ describe("{{NAME}}Permission", () => {
|
|
|
2150
2317
|
});
|
|
2151
2318
|
|
|
2152
2319
|
});
|
|
2153
|
-
`;var
|
|
2320
|
+
`;var Ha=`import { decorator, Permission } from "@ooneex/permission";
|
|
2154
2321
|
import type { IUser } from "@ooneex/user";
|
|
2155
2322
|
|
|
2156
2323
|
@decorator.permission()
|
|
@@ -2191,7 +2358,7 @@ export class {{NAME}}Permission extends Permission {
|
|
|
2191
2358
|
}
|
|
2192
2359
|
`;class Qe{getName(){return"make:permission"}getDescription(){return"Generate a new permission class"}async addToModule(e,t){let s=await Bun.file(e).text(),o=`${t}Permission`,r=`import { ${o} } from "./permissions/${o}";
|
|
2193
2360
|
`,a=s.lastIndexOf("import "),i=s.indexOf(`
|
|
2194
|
-
`,a);s=`${s.slice(0,i+1)}${r}${s.slice(i+1)}`;let n=/(permissions:\s*\[)([^\]]*)/s,l=s.match(n);if(l){let d=l[2]?.trim(),m=d?`${d}, ${o}`:o;s=s.replace(n,`$1${m}`)}await Bun.write(e,s)}async run(e){let{name:t,module:s}=e;if(!t)t=await v({message:"Enter permission name"});t=
|
|
2361
|
+
`,a);s=`${s.slice(0,i+1)}${r}${s.slice(i+1)}`;let n=/(permissions:\s*\[)([^\]]*)/s,l=s.match(n);if(l){let d=l[2]?.trim(),m=d?`${d}, ${o}`:o;s=s.replace(n,`$1${m}`)}await Bun.write(e,s)}async run(e){let{name:t,module:s}=e;if(!t)t=await v({message:"Enter permission name"});t=Fa(t).replace(/Permission$/,"");let o=Ha.replace(/{{NAME}}/g,t),r=s?W("modules",s):".",a=W(r,"src","permissions"),i=W(process.cwd(),a),n=W(i,`${t}Permission.ts`);await Bun.write(n,o);let l=Ka.replace(/{{NAME}}/g,t),d=W(r,"tests","permissions"),m=W(process.cwd(),d),h=W(m,`${t}Permission.spec.ts`);await Bun.write(h,l);let c=Fa(Fm(process.cwd())),p=W(process.cwd(),"src",`${c}Module.ts`);if(await Bun.file(p).exists())await this.addToModule(p,t);let u=new Vm;u.success(`${W(a,t)}Permission.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),u.success(`${W(d,t)}Permission.spec.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0})}}Qe=b([w.command()],Qe);import{basename as zm,join as q}from"path";import{TerminalLogger as Zm}from"@ooneex/logger";import{toKebabCase as Qm,toPascalCase as ja}from"@ooneex/utils";var Va=`import { describe, expect, test } from "bun:test";
|
|
2195
2362
|
import { {{NAME}}PubSub } from "@/pubsub/{{NAME}}PubSub";
|
|
2196
2363
|
|
|
2197
2364
|
describe("{{NAME}}PubSub", () => {
|
|
@@ -2229,7 +2396,7 @@ describe("{{NAME}}PubSub", () => {
|
|
|
2229
2396
|
expect(typeof {{NAME}}PubSub.prototype.unsubscribeAll).toBe("function");
|
|
2230
2397
|
});
|
|
2231
2398
|
});
|
|
2232
|
-
`;var
|
|
2399
|
+
`;var Ya=`import { inject } from "@ooneex/container";
|
|
2233
2400
|
import type { ScalarType } from "@ooneex/types";
|
|
2234
2401
|
import { decorator, PubSub, RedisPubSub } from "@ooneex/pub-sub";
|
|
2235
2402
|
|
|
@@ -2253,26 +2420,25 @@ export class {{NAME}}Event<Data extends Record<string, ScalarType> = Record<stri
|
|
|
2253
2420
|
}
|
|
2254
2421
|
`;class Xe{getName(){return"make:pubsub"}getDescription(){return"Generate a new PubSub event class"}async addToModule(e,t){let s=await Bun.file(e).text(),o=`${t}Event`,r=`import { ${o} } from "./events/${o}";
|
|
2255
2422
|
`,a=s.lastIndexOf("import "),i=s.indexOf(`
|
|
2256
|
-
`,a);s=`${s.slice(0,i+1)}${r}${s.slice(i+1)}`;let n=/(events:\s*\[)([^\]]*)/s,l=s.match(n);if(l){let d=l[2]?.trim(),m=d?`${d}, ${o}`:o;s=s.replace(n,`$1${m}`)}await Bun.write(e,s)}async run(e){let{name:t,module:s,channel:o}=e;if(!t)t=await v({message:"Enter name"});if(t=
|
|
2257
|
-
`),await this.updateChangelog(n,u,
|
|
2258
|
-
`);return}if(e.success(`
|
|
2259
|
-
${r} package(s) released`,void 0,o),await ge({message:"Push commits and tags to remote?"}))try{await ce`git push && git push --tags`,e.success("Pushed commits and tags to remote",void 0,o)}catch{e.error("Failed to push to remote",void 0,o)}}async getLastTag(e){try{let s=(await ce`git --no-pager tag --list "${e}@*" --sort=-v:refname`.quiet()).text().trim();if(!s)return null;return s.split(`
|
|
2423
|
+
`,a);s=`${s.slice(0,i+1)}${r}${s.slice(i+1)}`;let n=/(events:\s*\[)([^\]]*)/s,l=s.match(n);if(l){let d=l[2]?.trim(),m=d?`${d}, ${o}`:o;s=s.replace(n,`$1${m}`)}await Bun.write(e,s)}async run(e){let{name:t,module:s,channel:o}=e;if(!t)t=await v({message:"Enter name"});if(t=ja(t).replace(/PubSub$/,""),!o)o=Qm(t);let r=Ya.replace(/{{NAME}}/g,t).replace(/{{CHANNEL}}/g,o),a=s?q("modules",s):".",i=q(a,"src","events"),n=q(process.cwd(),i),l=q(n,`${t}Event.ts`);await Bun.write(l,r);let d=Va.replace(/{{NAME}}/g,t),m=q(a,"tests","events"),h=q(process.cwd(),m),c=q(h,`${t}Event.spec.ts`);await Bun.write(c,d);let p=ja(zm(process.cwd())),u=q(process.cwd(),"src",`${p}Module.ts`);if(await Bun.file(u).exists())await this.addToModule(u,t);let f=new Zm;f.success(`${q(i,t)}Event.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),f.success(`${q(m,t)}Event.spec.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0})}}Xe=b([w.command()],Xe);import{readdir as Xm}from"fs/promises";import{join as me}from"path";var{$:ce}=globalThis.Bun;import{TerminalLogger as Jm}from"@ooneex/logger";var ec={feat:"Added",fix:"Fixed",refactor:"Changed",perf:"Changed",style:"Changed",docs:"Changed",build:"Changed",ci:"Changed",chore:"Changed",revert:"Removed"};class Je{getName(){return"make:release"}getDescription(){return"Release packages with version bump, changelog, and git tag"}async run(){let e=new Jm,t=process.cwd(),s=[];for(let{name:i,type:n}of[{name:"packages",type:"package"},{name:"modules",type:"module"}])try{let l=await Xm(me(t,i),{withFileTypes:!0});s.push(...l.filter((d)=>d.isDirectory()).map((d)=>({base:me(i,d.name),type:n})))}catch{}let o={showTimestamp:!1,showArrow:!1,useSymbol:!0};if(s.length===0){e.error("No packages or modules found",void 0,o);return}let r=0;for(let i of s){let n=me(t,i.base),l=me(n,"package.json"),d=Bun.file(l);if(!await d.exists())continue;let m=await d.json(),h=await this.getLastTag(m.name),c=await this.getCommitsSinceTag(h,i.base);if(c.length===0)continue;let p=this.determineBumpType(c),u=this.bumpVersion(m.version,p);m.version=u;let f=`${m.name}@${u}`;await Bun.write(l,`${JSON.stringify(m,null,2)}
|
|
2424
|
+
`),await this.updateChangelog(n,u,f,c),await this.gitAdd(me(i.base,"package.json"),me(i.base,"CHANGELOG.md")),await this.gitCommit(`chore(release): ${m.name}@${u}`),await this.gitTag(f,`chore(release): ${m.name}@${u}`),e.success(`${m.name}@${u} released (${p} bump, ${c.length} commit(s))`,void 0,o),r++}if(r===0){e.info(`No packages have unreleased commits
|
|
2425
|
+
`);return}if(e.success(`${r} package(s) released`,void 0,o),await ge({message:"Push commits and tags to remote?"}))try{await ce`git push && git push --tags`,e.success("Pushed commits and tags to remote",void 0,o)}catch{e.error("Failed to push to remote",void 0,o)}}async getLastTag(e){try{let s=(await ce`git --no-pager tag --list "${e}@*" --sort=-v:refname`.quiet()).text().trim();if(!s)return null;return s.split(`
|
|
2260
2426
|
`)[0]??null}catch{return null}}async getCommitsSinceTag(e,t){let s=e?`${e}..HEAD`:"HEAD",o="%H|%an|%s";try{let a=(await ce`git --no-pager log ${s} --format=${"%H|%an|%s"} -- ${t}`.quiet()).text().trim();if(!a)return[];let i=[],n=/^([a-z]+)\(([^)]+)\):\s*(.+)$/;for(let l of a.split(`
|
|
2261
|
-
`)){let[d,m,...h]=l.split("|"),
|
|
2262
|
-
`;for(let
|
|
2263
|
-
### ${
|
|
2427
|
+
`)){let[d,m,...h]=l.split("|"),c=h.join("|");if(!d||!m||!c)continue;let p=c.match(n);if(p){let[,u,f,y]=p;if(u&&f&&y)i.push({hash:d.substring(0,8),type:u,scope:f,subject:y,author:m})}}return i}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),[o=0,r=0,a=0]=s;if(t==="minor")return`${o}.${r+1}.0`;return`${o}.${r}.${a+1}`}async getRepoUrl(){try{return(await ce`git --no-pager remote get-url origin`.quiet()).text().trim().replace(/\.git$/,"").replace(/^git@([^:]+):/,"https://$1/")}catch{return null}}async updateChangelog(e,t,s,o){let r=me(e,"CHANGELOG.md"),a=new Date().toISOString().split("T")[0],i=await this.getRepoUrl(),n=new Map;for(let u of o){let f=ec[u.type]??"Changed",y=n.get(f)??[];y.push(u),n.set(f,y)}let l=["Added","Changed","Deprecated","Removed","Fixed","Security"],m=`## ${i?`[${t}](${i}/releases/tag/${s})`:`[${t}]`} - ${a}
|
|
2428
|
+
`;for(let u of l){let f=n.get(u);if(!f||f.length===0)continue;m+=`
|
|
2429
|
+
### ${u}
|
|
2264
2430
|
|
|
2265
|
-
`;for(let
|
|
2266
|
-
`}}let
|
|
2267
|
-
${
|
|
2268
|
-
${
|
|
2269
|
-
${
|
|
2431
|
+
`;for(let y of f){let g=i?` ([${y.hash}](${i}/commit/${y.hash}))`:"";m+=`- ${y.subject} \u2014 ${y.author}${g}
|
|
2432
|
+
`}}let h=Bun.file(r),c="";if(await h.exists())c=await h.text();let p;if(c){let u=c.match(/## \[Unreleased\][^\n]*\n/),f=c.match(/## \[\d+\.\d+\.\d+\]/);if(u){let y=(u.index??0)+u[0].length;p=`${c.slice(0,y)}
|
|
2433
|
+
${m}
|
|
2434
|
+
${c.slice(y)}`}else if(f&&f.index!==void 0)p=`${c.slice(0,f.index)}${m}
|
|
2435
|
+
${c.slice(f.index)}`;else p=`${c.trimEnd()}
|
|
2270
2436
|
|
|
2271
|
-
${
|
|
2272
|
-
`}else
|
|
2437
|
+
${m}
|
|
2438
|
+
`}else p=`# Changelog
|
|
2273
2439
|
|
|
2274
|
-
${
|
|
2275
|
-
`;await Bun.write(
|
|
2440
|
+
${m}
|
|
2441
|
+
`;await Bun.write(r,p)}async gitAdd(...e){await ce`git add ${e}`}async gitCommit(e){await ce`git commit --no-verify -m ${e}`}async gitTag(e,t){await ce`git tag -a ${e} -m ${t}`}}Je=b([w.command()],Je);import{join as Z}from"path";import{TerminalLogger as oc}from"@ooneex/logger";import{toPascalCase as rc}from"@ooneex/utils";var za=`import { describe, expect, test } from "bun:test";
|
|
2276
2442
|
import { {{NAME}}Repository } from "@/repositories/{{NAME}}Repository";
|
|
2277
2443
|
|
|
2278
2444
|
describe("{{NAME}}Repository", () => {
|
|
@@ -2335,7 +2501,7 @@ describe("{{NAME}}Repository", () => {
|
|
|
2335
2501
|
expect(typeof {{NAME}}Repository.prototype.count).toBe("function");
|
|
2336
2502
|
});
|
|
2337
2503
|
});
|
|
2338
|
-
`;var
|
|
2504
|
+
`;var Za=`import { inject } from "@ooneex/container";
|
|
2339
2505
|
import type { ITypeormDatabase } from "@ooneex/database";
|
|
2340
2506
|
import { decorator } from "@ooneex/repository";
|
|
2341
2507
|
import type { FilterResultType } from "@ooneex/types";
|
|
@@ -2457,13 +2623,13 @@ export class {{NAME}}Repository {
|
|
|
2457
2623
|
return await repository.count(criteria ? { where: criteria } : {});
|
|
2458
2624
|
}
|
|
2459
2625
|
}
|
|
2460
|
-
`;class et{getName(){return"make:repository"}getDescription(){return"Generate a new repository class"}async run(e){let{name:t,module:s}=e;if(!t)t=await v({message:"Enter repository name"});t=
|
|
2626
|
+
`;class et{getName(){return"make:repository"}getDescription(){return"Generate a new repository class"}async run(e){let{name:t,module:s}=e;if(!t)t=await v({message:"Enter repository name"});t=rc(t).replace(/Repository$/,"");let o=Za.replace(/{{NAME}}/g,t),r=s?Z("modules",s):".",a=Z(r,"src","repositories"),i=Z(process.cwd(),a),n=Z(i,`${t}Repository.ts`);await Bun.write(n,o);let l=za.replace(/{{NAME}}/g,t),d=Z(r,"tests","repositories"),m=Z(process.cwd(),d),h=Z(m,`${t}Repository.spec.ts`);await Bun.write(h,l);let c=new oc;c.success(`${Z(a,t)}Repository.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),c.success(`${Z(d,t)}Repository.spec.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0})}}et=b([w.command()],et);import{join as tt}from"path";import{TerminalLogger as ic}from"@ooneex/logger";import{seedCreate as nc}from"@ooneex/seeds";var Qa=`#!/usr/bin/env bun
|
|
2461
2627
|
|
|
2462
2628
|
import { seedRun } from "@ooneex/seeds";
|
|
2463
2629
|
import "@/seeds/seeds";
|
|
2464
2630
|
|
|
2465
2631
|
await seedRun();
|
|
2466
|
-
`;class st{getName(){return"make:seed"}getDescription(){return"Generate a new seed file"}async run(e){let{name:t,module:s}=e;if(!t)t=await v({message:"Enter seed name"});let o=s?tt("modules",s):".",r=await
|
|
2632
|
+
`;class st{getName(){return"make:seed"}getDescription(){return"Generate a new seed file"}async run(e){let{name:t,module:s}=e;if(!t)t=await v({message:"Enter seed name"});let o=s?tt("modules",s):".",r=await nc({name:t,dir:tt(o,"src/seeds")}),a=tt(process.cwd(),o,"bin","seed","run.ts");if(!await Bun.file(a).exists())await Bun.write(a,Qa);let n=tt(process.cwd(),"package.json"),l=Bun.file(n);if(await l.exists()){let m=await l.json();m.scripts=m.scripts||{},m.scripts["seed:run"]="bun ./bin/seed/run.ts",await Bun.write(n,JSON.stringify(m,null,2))}let d=new ic;d.success(`${r} 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})}}st=b([w.command()],st);import{join as Q}from"path";import{TerminalLogger as mc}from"@ooneex/logger";import{toPascalCase as cc}from"@ooneex/utils";var Xa=`import { describe, expect, test } from "bun:test";
|
|
2467
2633
|
import { {{NAME}}Service } from "@/services/{{NAME}}Service";
|
|
2468
2634
|
|
|
2469
2635
|
describe("{{NAME}}Service", () => {
|
|
@@ -2476,7 +2642,7 @@ describe("{{NAME}}Service", () => {
|
|
|
2476
2642
|
expect(typeof {{NAME}}Service.prototype.execute).toBe("function");
|
|
2477
2643
|
});
|
|
2478
2644
|
});
|
|
2479
|
-
`;var
|
|
2645
|
+
`;var Ja=`import { decorator } from "@ooneex/service";
|
|
2480
2646
|
import type { IService } from "@ooneex/service";
|
|
2481
2647
|
|
|
2482
2648
|
type ServiceDataType = Record<string, unknown>;
|
|
@@ -2487,7 +2653,7 @@ export class {{NAME}}Service<T extends ServiceDataType = ServiceDataType> implem
|
|
|
2487
2653
|
// TODO: Implement service logic
|
|
2488
2654
|
}
|
|
2489
2655
|
}
|
|
2490
|
-
`;class ot{getName(){return"make:service"}getDescription(){return"Generate a new service class"}async run(e){let{name:t,module:s}=e;if(!t)t=await v({message:"Enter service name"});t=
|
|
2656
|
+
`;class ot{getName(){return"make:service"}getDescription(){return"Generate a new service class"}async run(e){let{name:t,module:s}=e;if(!t)t=await v({message:"Enter service name"});t=cc(t).replace(/Service$/,"");let o=Ja.replace(/{{NAME}}/g,t),r=s?Q("modules",s):".",a=Q(r,"src","services"),i=Q(process.cwd(),a),n=Q(i,`${t}Service.ts`);await Bun.write(n,o);let l=Xa.replace(/{{NAME}}/g,t),d=Q(r,"tests","services"),m=Q(process.cwd(),d),h=Q(m,`${t}Service.spec.ts`);await Bun.write(h,l);let c=new mc;c.success(`${Q(a,t)}Service.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),c.success(`${Q(d,t)}Service.spec.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0})}}ot=b([w.command()],ot);import{join as X}from"path";import{TerminalLogger as hc}from"@ooneex/logger";import{toPascalCase as fc,toSnakeCase as gc}from"@ooneex/utils";var ei=`import { describe, expect, test } from "bun:test";
|
|
2491
2657
|
import { {{NAME}}StorageAdapter } from "@/storage/{{NAME}}StorageAdapter";
|
|
2492
2658
|
|
|
2493
2659
|
describe("{{NAME}}StorageAdapter", () => {
|
|
@@ -2504,7 +2670,7 @@ describe("{{NAME}}StorageAdapter", () => {
|
|
|
2504
2670
|
expect(typeof {{NAME}}StorageAdapter.prototype.getOptions).toBe("function");
|
|
2505
2671
|
});
|
|
2506
2672
|
});
|
|
2507
|
-
`;var
|
|
2673
|
+
`;var ti=`import { Storage, decorator, StorageException } from "@ooneex/storage";
|
|
2508
2674
|
import type { S3Options } from "bun";
|
|
2509
2675
|
|
|
2510
2676
|
@decorator.storage()
|
|
@@ -2559,7 +2725,7 @@ export class {{NAME}}Storage extends Storage {
|
|
|
2559
2725
|
};
|
|
2560
2726
|
}
|
|
2561
2727
|
}
|
|
2562
|
-
`;class rt{getName(){return"make:storage"}getDescription(){return"Generate a new storage class"}async run(e){let{name:t,module:s}=e;if(!t)t=await v({message:"Enter storage name"});t=
|
|
2728
|
+
`;class rt{getName(){return"make:storage"}getDescription(){return"Generate a new storage class"}async run(e){let{name:t,module:s}=e;if(!t)t=await v({message:"Enter storage name"});t=fc(t).replace(/Storage$/,"");let o=gc(t).toUpperCase(),r=ti.replace(/{{NAME}}/g,t).replace(/{{NAME_UPPER}}/g,o),a=s?X("modules",s):".",i=X(a,"src","storage"),n=X(process.cwd(),i),l=X(n,`${t}Storage.ts`);await Bun.write(l,r);let d=ei.replace(/{{NAME}}/g,t),m=X(a,"tests","storage"),h=X(process.cwd(),m),c=X(h,`${t}Storage.spec.ts`);await Bun.write(c,d);let p=new hc;p.success(`${X(i,t)}Storage.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),p.success(`${X(m,t)}Storage.spec.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0})}}rt=b([w.command()],rt);import{join as J}from"path";import{TerminalLogger as wc}from"@ooneex/logger";import{toPascalCase as xc}from"@ooneex/utils";var si=`import { describe, expect, test } from "bun:test";
|
|
2563
2729
|
import { {{NAME}}VectorDatabase } from "@/databases/{{NAME}}VectorDatabase";
|
|
2564
2730
|
|
|
2565
2731
|
describe("{{NAME}}VectorDatabase", () => {
|
|
@@ -2582,7 +2748,7 @@ describe("{{NAME}}VectorDatabase", () => {
|
|
|
2582
2748
|
expect(typeof {{NAME}}VectorDatabase.prototype.getSchema).toBe("function");
|
|
2583
2749
|
});
|
|
2584
2750
|
});
|
|
2585
|
-
`;var
|
|
2751
|
+
`;var oi=`import { VectorDatabase, decorator } from "@ooneex/rag";
|
|
2586
2752
|
import type { EmbeddingModelType, EmbeddingProviderType, FieldValueType } from "@ooneex/rag";
|
|
2587
2753
|
import { Utf8 } from "apache-arrow";
|
|
2588
2754
|
|
|
@@ -2606,8 +2772,8 @@ export class {{NAME}}VectorDatabase extends VectorDatabase<DataType> {
|
|
|
2606
2772
|
};
|
|
2607
2773
|
}
|
|
2608
2774
|
}
|
|
2609
|
-
`;class at{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 v({message:"Enter vector database name"});t=
|
|
2610
|
-
`),process.exit(1);var
|
|
2611
|
-
`),process.exit(1);var
|
|
2775
|
+
`;class at{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 v({message:"Enter vector database name"});t=xc(t).replace(/VectorDatabase$/,"").replace(/Database$/,"");let o=oi.replace(/{{NAME}}/g,t),r=s?J("modules",s):".",a=J(r,"src","databases"),i=J(process.cwd(),a),n=J(i,`${t}VectorDatabase.ts`);await Bun.write(n,o);let l=si.replace(/{{NAME}}/g,t),d=J(r,"tests","databases"),m=J(process.cwd(),d),h=J(m,`${t}VectorDatabase.spec.ts`);await Bun.write(h,l);let c=new wc;c.success(`${J(a,t)}VectorDatabase.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0}),c.success(`${J(d,t)}VectorDatabase.spec.ts created successfully`,void 0,{showTimestamp:!1,showArrow:!1,useSymbol:!0})}}at=b([w.command()],at);var{values:K,positionals:vc}=Ec({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}),$t=new Ac,ai=vc[2];if(!ai)$t.error(`Command name is required
|
|
2776
|
+
`),process.exit(1);var ii=kt(ai);if(!ii)$t.info(`No commands found
|
|
2777
|
+
`),process.exit(1);var Nc={name:K.name,dir:K.dir,channel:K.channel,isSocket:K["is-socket"],tableName:K["table-name"],module:K.module,destination:K.destination,route:{name:K["route-name"],path:K["route-path"],method:K["route-method"]}};try{await ii.run(Nc)}catch(e){let t=e instanceof ri?e:new ri(e instanceof Error?e:String(e));$t.error(t,void 0,{showArrow:!1,showTimestamp:!1,showLevel:!1}),process.exit(1)}
|
|
2612
2778
|
|
|
2613
|
-
//# debugId=
|
|
2779
|
+
//# debugId=CC702DB50A23AF7564756E2164756E21
|