@elysiumjs/core 0.6.1 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +37 -0
- package/README.md +36 -21
- package/dist/app.d.ts +65 -67
- package/dist/command.d.ts +20 -4
- package/dist/connections.d.ts +17 -0
- package/dist/container.d.ts +128 -0
- package/dist/errors.d.ts +159 -0
- package/dist/event-wiring.d.ts +23 -0
- package/dist/event.d.ts +38 -1
- package/dist/http.d.ts +3 -3
- package/dist/index.d.ts +11 -13
- package/dist/index.js +14 -14
- package/dist/kernel.d.ts +71 -0
- package/dist/metadata.d.ts +46 -0
- package/dist/middleware.d.ts +12 -2
- package/dist/module-context.d.ts +20 -0
- package/dist/module-graph.d.ts +68 -0
- package/dist/module.d.ts +83 -25
- package/dist/redis.d.ts +53 -100
- package/dist/service.d.ts +60 -16
- package/dist/testing.d.ts +39 -0
- package/dist/utils.d.ts +24 -7
- package/dist/wamp.d.ts +72 -92
- package/package.json +5 -9
- package/dist/cache.d.ts +0 -113
- package/dist/database.d.ts +0 -112
- package/dist/job.d.ts +0 -105
- package/dist/model.d.ts +0 -2413
- package/dist/repository.d.ts +0 -175
- package/dist/tenancy.d.ts +0 -244
- package/dist/worker.d.ts +0 -219
package/dist/index.js
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
var
|
|
2
|
+
var __legacyDecorateClassTS=function(decorators,target,key,desc){var c=arguments.length,r=c<3?target:desc===null?desc=Object.getOwnPropertyDescriptor(target,key):desc,d;if(typeof Reflect==="object"&&typeof Reflect.decorate==="function")r=Reflect.decorate(decorators,target,key,desc);else for(var i=decorators.length-1;i>=0;i--)if(d=decorators[i])r=(c<3?d(r):c>3?d(target,key,r):d(target,key))||r;return c>3&&r&&Object.defineProperty(target,key,r),r};import{t as t2}from"elysia";import{AsyncLocalStorage as AsyncLocalStorage2}from"async_hooks";import{openapi as openapiPlugin}from"@elysiajs/openapi";import{Value}from"@sinclair/typebox/value";import{Elysia}from"elysia";import{first}from"radash";import{isArray,trim}from"radash";import*as readline from"readline";import{isEmpty,omit}from"radash";var ConsoleFormat;((ConsoleFormat)=>{ConsoleFormat[ConsoleFormat.BLACK=0]="BLACK";ConsoleFormat[ConsoleFormat.RED=1]="RED";ConsoleFormat[ConsoleFormat.GREEN=2]="GREEN";ConsoleFormat[ConsoleFormat.YELLOW=3]="YELLOW";ConsoleFormat[ConsoleFormat.BLUE=4]="BLUE";ConsoleFormat[ConsoleFormat.MAGENTA=5]="MAGENTA";ConsoleFormat[ConsoleFormat.CYAN=6]="CYAN";ConsoleFormat[ConsoleFormat.WHITE=7]="WHITE";ConsoleFormat[ConsoleFormat.GRAY=8]="GRAY";ConsoleFormat[ConsoleFormat.BOLD=9]="BOLD";ConsoleFormat[ConsoleFormat.UNDERLINE=10]="UNDERLINE";ConsoleFormat[ConsoleFormat.ITALIC=11]="ITALIC";ConsoleFormat[ConsoleFormat.INVERSE=12]="INVERSE"})(ConsoleFormat||={});var formatMap={[0]:Bun.color("black","ansi")||Bun.color("black","ansi-256")||"",[1]:Bun.color("red","ansi")||Bun.color("red","ansi-256")||"",[2]:Bun.color("green","ansi")||Bun.color("green","ansi-256")||"",[3]:Bun.color("yellow","ansi")||Bun.color("yellow","ansi-256")||"",[4]:Bun.color("blue","ansi")||Bun.color("blue","ansi-256")||"",[5]:Bun.color("magenta","ansi")||Bun.color("magenta","ansi-256")||"",[6]:Bun.color("cyan","ansi")||Bun.color("cyan","ansi-256")||"",[7]:Bun.color("white","ansi")||Bun.color("white","ansi-256")||"",[8]:Bun.color("gray","ansi")||Bun.color("gray","ansi-256")||"",[9]:"\x1B[1m",[10]:"\x1B[4m",[11]:"\x1B[3m",[12]:"\x1B[7m"};class InteractsWithConsole{static SPACE_WIDTH=60;write(message,newLine=!0,out=process.stdout){out.write(message+(newLine?`
|
|
3
3
|
`:""))}newLine(){this.write(`
|
|
4
|
-
`,!1)}info(
|
|
5
|
-
`).map((
|
|
6
|
-
`),8));let
|
|
4
|
+
`,!1)}info(message){this.write(`${this.format("\u2139",4)} ${message}`)}success(message){this.write(`${this.format("\u2714",2)} ${message}`)}warning(message){this.write(`${this.format("\u26A0",3)} ${message}`)}error(message){this.write(`${this.format("\u2716",1)} ${message}`,!0,process.stderr)}debug(message){if(process.env.DEBUG)this.write(`\uD83D\uDD0D ${message}`)}trace(error,title){if(!error)return;let errorName=error.name||"Error",errorMessage=error.message||"An error occurred",errorStack=error.stack||"";if(title)this.title(title);else this.newLine();if(this.write(this.format(`${errorName}: ${errorMessage}`,1)),error.stack)this.write(this.format("Stack Trace:",9)),this.write(this.format(errorStack.split(`
|
|
5
|
+
`).map((line)=>` ${line}`).join(`
|
|
6
|
+
`),8));let customProps=omit(error,["name","message","stack"]);if(!isEmpty(customProps))this.write(this.format("Additional Information:",9)),Object.keys(customProps).forEach((prop)=>{let value=error[prop];this.write(` ${prop}: ${JSON.stringify(value)}`)});this.newLine()}title(title){this.newLine(),this.write(this.format(title,9,10)),this.newLine()}section(header){this.newLine(),this.write(`\x1B[1m${header}\x1B[0m`)}table(data,columns){if(data.length===0){this.info("No data to display");return}let keys=Object.keys(columns||data[0]),widths={};for(let key of keys){let columnConfig=columns?.[key];if(columnConfig?.width){widths[key]=columnConfig.width;continue}let headerLength=(columnConfig?.header||String(key)).length,maxDataLength=Math.max(...data.map((row)=>{let value=row[key];if(columnConfig?.format)return columnConfig.format(value).length;return String(value===null||value===void 0?"":value).length}));widths[key]=Math.max(headerLength,maxDataLength)}let header="",separator="";for(let key of keys){let headerText=columns?.[key]?.header||String(key),width=widths[key];header+=`| ${headerText.padEnd(width)} `,separator+=`| ${"-".repeat(width)} `}header+="|",separator+="|",this.write(header),this.write(separator);for(let row of data){let line="";for(let key of keys){let columnConfig=columns?.[key],width=widths[key],value=row[key],displayValue;if(columnConfig?.format)displayValue=columnConfig.format(value);else displayValue=String(value===null||value===void 0?"":value);line+=`| ${displayValue.padEnd(width)} `}line+="|",this.write(line)}this.newLine()}format(text,...styles){return`${styles.map((style)=>formatMap[style]).join("")}${text}\x1B[0m`}bold(text){return this.format(text,9)}italic(text){return this.format(text,11)}underline(text){return this.format(text,10)}clear(){process.stdout.write("\x1Bc")}moveCursor(x,y){process.stdout.moveCursor(x,y)}clearLine(){process.stdout.clearLine(0),process.stdout.cursorTo(0)}async prompt(question,defaultValue){let rl=readline.createInterface({input:process.stdin,output:process.stdout}),defaultText=defaultValue?` (default: ${defaultValue})`:"";return new Promise((resolve)=>{rl.question(`${question}${defaultText}: `,(answer)=>{rl.close(),resolve(answer||defaultValue||"")})})}async promptPassword(question){let rl=readline.createInterface({input:process.stdin,output:process.stdout});return process.stdin.setRawMode?.(!0),new Promise((resolve)=>{let password="";process.stdout.write(`${question}: `),process.stdin.on("data",(data)=>{let char=data.toString();if(char==="\r"||char===`
|
|
7
7
|
`){process.stdout.write(`
|
|
8
|
-
`),process.stdin.setRawMode?.(!1),process.stdin.removeAllListeners("data"),X.close(),$(Y);return}if(G==="\b"||G==="\x7F"){if(Y.length>0)Y=Y.slice(0,-1),process.stdout.write("\b \b");return}Y+=G,process.stdout.write("*")})})}async confirm(Q,X=!1){let $=X?"Y/n":"y/N",Y=await this.prompt(`${Q} [${$}]`);if(!Y)return X;return Y.toLowerCase()==="y"||Y.toLowerCase()==="yes"}async select(Q,X,$=0){if(X.length===0)throw Error("No options provided for selection");this.write(Q),X.forEach((G,U)=>{let _=U===$;this.write(` ${U+1}. ${G}${_?" (default)":""}`)});let Y=await this.prompt("Enter your choice (number)");if(!Y)return X[$];let Z=parseInt(Y,10)-1;if(isNaN(Z)||Z<0||Z>=X.length)return this.warning(`Invalid selection. Using default: ${X[$]}`),X[$];return X[Z]}formatTime(Q){if(Q<60)return`${Q.toFixed(1)}s`;if(Q<3600)return`${Math.floor(Q/60)}m ${Math.floor(Q%60)}s`;return`${Math.floor(Q/3600)}h ${Math.floor(Q%3600/60)}m`}}var VQ,MX;var QQ=_Q(()=>{((L)=>{L[L.BLACK=0]="BLACK";L[L.RED=1]="RED";L[L.GREEN=2]="GREEN";L[L.YELLOW=3]="YELLOW";L[L.BLUE=4]="BLUE";L[L.MAGENTA=5]="MAGENTA";L[L.CYAN=6]="CYAN";L[L.WHITE=7]="WHITE";L[L.GRAY=8]="GRAY";L[L.BOLD=9]="BOLD";L[L.UNDERLINE=10]="UNDERLINE";L[L.ITALIC=11]="ITALIC";L[L.INVERSE=12]="INVERSE"})(VQ||={});MX={[0]:Bun.color("black","ansi")||Bun.color("black","ansi-256")||"",[1]:Bun.color("red","ansi")||Bun.color("red","ansi-256")||"",[2]:Bun.color("green","ansi")||Bun.color("green","ansi-256")||"",[3]:Bun.color("yellow","ansi")||Bun.color("yellow","ansi-256")||"",[4]:Bun.color("blue","ansi")||Bun.color("blue","ansi-256")||"",[5]:Bun.color("magenta","ansi")||Bun.color("magenta","ansi-256")||"",[6]:Bun.color("cyan","ansi")||Bun.color("cyan","ansi-256")||"",[7]:Bun.color("white","ansi")||Bun.color("white","ansi-256")||"",[8]:Bun.color("gray","ansi")||Bun.color("gray","ansi-256")||"",[9]:"\x1B[1m",[10]:"\x1B[4m",[11]:"\x1B[3m",[12]:"\x1B[7m"}});import{isObject as LQ,isPrimitive as jX}from"radash";function s(Q,...X){if(!X.length)return Q;let $=X.shift();if($===void 0)return Q;if(LQ(Q)&&LQ($))for(let Y in $)if(LQ($[Y])){if(!Q[Y])Object.assign(Q,{[Y]:$[Y]})}else if(Array.isArray($[Y])){if(!Array.isArray(Q[Y]))Q[Y]=[];if($[Y].length>0&&!LQ($[Y][0]))Q[Y]=[...new Set([...Q[Y],...$[Y]])];else $[Y].forEach((Z,G)=>{if(LQ(Z)&&Q[Y][G])Q[Y][G]=s(Q[Y][G],Z);else if(!Q[Y].includes(Z))Q[Y].push(Z)})}else if(jX($[Y]))Q[Y]??=$[Y];else s(Q[Y],$[Y]);return s(Q,...X)}var P,n=()=>new Promise((Q)=>process.nextTick(Q));var p=_Q(()=>{((w)=>(w.app=Symbol("elysium:Application"),w.controller=Symbol("elysium:Controller"),w.middlewares=Symbol("elysium:MiddlewaresList"),w.services=Symbol("elysium:ServicesList"),w.websocket=Symbol("elysium:WebSocket"),w.wamp=Symbol("elysium:Wamp"),w.http=Symbol("elysium:Http"),w.job=Symbol("elysium:Job"),w.arg=Symbol("elysium:CommandArguments"),w.elysiaPlugin=Symbol("elysium:ElysiaPlugin"),w.middlewareGuards=Symbol("elysium:MiddlewareGuards")))(P||={})});import{isString as XQ}from"radash";var yQ,FX=(Q)=>{return typeof Q==="function"&&Q.prototype&&Q.prototype.constructor===Q},gQ,vQ=(Q)=>{return typeof Q==="object"&&Q!==null&&gQ in Q},v,B;var y=_Q(()=>{p();(($)=>{$[$.SINGLETON=0]="SINGLETON";$[$.FACTORY=1]="FACTORY"})(yQ||={});gQ=Symbol("lazy"),v=new Map;((E)=>{E.register=(O)=>{return function(L){let V=O?.name??L.name,A=O?.scope??0;if(B.exists(V))console.error(`A service with the name ${V} has already been registered.`),process.exit(1);let C=()=>B.make(L);if(A===0){let R=C();v.set(V,{scope:A,factory(){return R}})}else v.set(V,{scope:A,factory:C})}},E.inject=(O)=>{return function(L,V,A){let C=Reflect.getMetadata(P.services,L,V)??[],R=Reflect.getMetadata("design:paramtypes",L,V)??[],J=XQ(O)?O:O?.name??R[A].name;C.push({name:J,index:A}),Reflect.defineMetadata(P.services,C,L,V)}},E.get=(O)=>{let L=XQ(O)?O:O.name;if(E.exists(L)){let V=v.get(L);if(vQ(V)){let A=V.resolver();return v.set(L,{scope:0,factory:()=>A}),A}return V.factory()}return null},E.registerLazy=(O,L)=>{if(v.has(O)&&!vQ(v.get(O)))throw Error(`Service ${O} already registered`);v.set(O,{[gQ]:!0,resolver:L})},E.make=(O)=>{let L=Reflect.getMetadata(P.services,O)??[],V=[];return L.forEach((A)=>{let C=E.get(A.name);if(C===null)console.error(`Cannot inject service ${A.name}. No service was registered with the name: ${A.name}`),process.exit(1);V[A.index]=C}),new O(...V)},E.bind=(O,L)=>{let V=E.make(O);return E.instance(L??O.name,V)};function U(O,L){let V=XQ(O)?O:L??O.name;if(E.exists(V))console.error(`A service with the name ${V} has already been registered.`),process.exit(1);let A=()=>{return FX(O)?E.make(O):L()};return v.set(V,{scope:1,factory:A}),A()}E.factory=U,E.instance=(O,L)=>{let V=XQ(O)?O:O.name;if(E.exists(V))console.error(`A service with the name ${V} has already been registered.`),process.exit(1);return v.set(V,{scope:0,factory(){return L}}),L},E.remove=(O)=>{let L=XQ(O)?O:O.name;v.delete(L)},E.exists=(O)=>{let L=XQ(O)?O:O.name;return v.has(L)},E.clear=()=>{v.clear()},E.keys=(O)=>{let L="^"+O.replace(/[-[\]{}()+.,\\^$|#\s]/g,"\\$&").replace(/\*/g,".*").replace(/\?/g,".")+"$",V=new RegExp(L);return Array.from(v.keys()).filter((A)=>V.test(A))}})(B||={})});import"reflect-metadata";import{assign as xX,uid as kX}from"radash";var sQ;var oQ=_Q(()=>{QQ();y();p();sQ=class sQ extends q{#Q;#X;#$="pending";#Y;static register(Q={}){return function(X){Q=xX({name:X.name,queue:"default"},Q);let $=`job.${Q.name}`;B.instance($,X),Reflect.defineMetadata(P.job,{name:$,queue:Q.queue},X)}}id;createdAt;get startedAt(){return this.#Q}get completedAt(){return this.#X}get status(){return this.#$}constructor(Q){super();this.id=Q||this.generateJobId(),this.createdAt=new Date}async run(){try{this.#$="running",this.#Q=new Date,this.debug(`Job ${this.id} started at ${this.#Q.toISOString()}`),await this.execute(),this.#$="completed",this.#X=new Date,this.debug(`Job ${this.id} completed at ${this.#X.toISOString()}`)}catch(Q){if(this.#Y=Q instanceof Error?Q:Error(String(Q)),this.#$!=="cancelled")this.#$="failed";this.#X=new Date,this.trace(this.#Y)}}cancel(){this.#$="cancelled"}generateJobId(){return`job_${Date.now()}_${kX(8)}`}}});var tQ={};hQ(tQ,{WorkerPool:()=>JQ,Worker:()=>EQ});import{uid as qX}from"radash";var rQ,EQ,JQ;var IQ=_Q(()=>{QQ();y();p();rQ=globalThis.Worker;EQ=class EQ extends q{#Q;queues=new Map;defaultQueueName="default";static spawn(Q,X=["default"],$){let Y=new this;Y.debug(`Worker ${Y.id} starting with queues: ${X.join(", ")}`);for(let Z of X)Y.createQueue({name:Z,concurrency:$?.concurrency??1,maxRetries:$?.maxRetries??5,retryDelay:$?.retryDelay??5000,pauseOnError:$?.pauseOnError??!1});return Q.addEventListener("message",async(Z)=>{let{type:G="job:process",jobId:U,job:_,args:M,queue:H="default"}=Z.data;switch(G){case"job:cancel":let z=Y.cancelJob(U,H);Q.postMessage({type:"job:canceled",jobId:U,queue:H,success:z,count:z?1:0});break;case"job:cancelAll":let K=Y.cancelAllJobs(H);Q.postMessage({type:"jobs:canceled",queue:H,count:K});break;case"job:process":Y.debug(`Worker ${Y.id} received job ${_} for queue ${H}`);try{let O=B.get(_);if(!O)throw Y.error(`Job class ${_} not found`),Error(`Job class ${_} not found`);let L=new O(...M||[]);Y.addJob(L,H),Q.postMessage({type:"job:received",jobId:L.id,queue:H})}catch(O){Y.trace({...O,...$??{}},`Error while adding job '${_}' to queue '${H}' with worker ${Y.id}`),Q.postMessage({type:"job:error",jobName:_,error:O.message})}break}}),Q.addEventListener("error",(Z)=>{Y.trace({...Z.error,filename:Z.filename},`Worker ${Y.id} error:`)}),Q.addEventListener("unhandledrejection",(Z)=>{Y.trace(Z,`Worker ${Y.id} unhandled rejection:`)}),Q.postMessage({type:"worker:ready",id:Y.id,queues:X}),Y}constructor(){super();this.#Q=qX(24),this.createQueue({name:this.defaultQueueName})}get id(){return this.#Q}createQueue(Q){if(this.queues.has(Q.name))return this.debug(`Queue with name '${Q.name}' already exists`),this;let X={options:{...Q,concurrency:Q.concurrency||1,maxRetries:Q.maxRetries||0,retryDelay:Q.retryDelay||1000,pauseOnError:Q.pauseOnError||!1},jobs:[],processing:0,paused:!1,draining:!1};return this.queues.set(Q.name,X),this.debug(`Created queue '${Q.name}'`),this}addJob(Q,X=this.defaultQueueName){let $=this.queues.get(X);if(!$)return this.error(`Queue '${X}' does not exist`),this;if($.draining)return this.warning(`Queue '${X}' is draining, job ${Q.id} will not be added`),this;let Y={job:Q,retries:0,queueName:X};if($.jobs.push(Y),this.debug(`Added job ${Q.id} to queue '${X}'`),!$.paused&&$.processing<$.options.concurrency)this.processNextJob(X);return this}pause(Q){if(Q){let X=this.queues.get(Q);if(X)X.paused=!0,this.info(`Paused queue '${Q}'`)}else for(let[X]of this.queues.entries())this.pause(X);return this}resume(Q){if(Q){let X=this.queues.get(Q);if(X)X.paused=!1,this.info(`Resumed queue '${Q}'`),this.processQueueJobs(Q)}else for(let[X]of this.queues.entries())this.resume(X);return this}drain(Q){if(Q){let X=this.queues.get(Q);if(X)X.draining=!0,this.info(`Draining queue '${Q}'`)}else for(let[X]of this.queues.entries())this.drain(X);return this}clear(Q){if(Q){let X=this.queues.get(Q);if(X){let $=X.jobs.length;X.jobs=[],this.info(`Cleared ${$} jobs from queue '${Q}'`)}}else for(let[X,$]of this.queues.entries()){let Y=$.jobs.length;$.jobs=[],this.info(`Cleared ${Y} jobs from queue '${X}'`)}return this}size(Q=this.defaultQueueName){let X=this.queues.get(Q);if(!X)throw Error(`Queue '${Q}' does not exist`);return X.jobs.length}totalSize(){let Q=0;for(let X of this.queues.values())Q+=X.jobs.length;return Q}async processNextJob(Q){let X=this.queues.get(Q);if(!X||X.paused||X.processing>=X.options.concurrency)return;let $=X.jobs.shift();if(!$)return;if($.job.status==="cancelled"){this.info(`Skipping cancelled job ${$.job.id}`),X.processing--,this.processQueueJobs(Q);return}X.processing++;try{if(this.debug(`Processing job ${$.job.id} from queue '${Q}'`),await $.job.run(),$.job.status==="failed"){if($.retries<X.options.maxRetries)$.retries++,this.warning(`Job ${$.job.id} failed, retrying (${$.retries}/${X.options.maxRetries})`),setTimeout(()=>{if($.job.status!=="cancelled")X.jobs.push($),this.processQueueJobs(Q);else this.info(`Skipping cancelled job ${$.job.id} during retry delay`)},X.options.retryDelay);else if(this.error(`Job ${$.job.id} failed after ${$.retries} retries`),X.options.pauseOnError)this.pause(Q),this.warning(`Queue '${Q}' paused due to job failure`)}else if($.job.status==="completed")this.success(`Job ${$.job.id} completed successfully`);else this.info(`Job ${$.job.id} cancelled while running`)}catch(Y){if(this.error(`Unexpected error processing job ${$.job.id}: ${Y}`),X.options.pauseOnError)this.pause(Q),this.warning(`Queue '${Q}' paused due to unexpected error`)}finally{X.processing--,this.processQueueJobs(Q)}}processQueueJobs(Q){let X=this.queues.get(Q);if(!X||X.paused)return;while(X.jobs.length>0&&X.processing<X.options.concurrency)this.processNextJob(Q)}getStats(){let Q={};for(let[X,$]of this.queues.entries())Q[X]={waiting:$.jobs.length,processing:$.processing,paused:$.paused,draining:$.draining};return Q}cancelJob(Q,X){if(X)return this.cancelJobInQueue(Q,X);else{let $=!1;for(let[Y]of this.queues.entries())if(this.cancelJobInQueue(Q,Y)){$=!0;break}return $}}cancelJobInQueue(Q,X){let $=this.queues.get(X);if(!$)return!1;let Y=$.jobs.findIndex((Z)=>Z.job.id===Q);if(Y>=0)return $.jobs[Y].job.cancel(),this.info(`Canceled job ${Q} in queue '${X}'`),!0;return!1}cancelAllJobs(Q){let X=0;if(Q){let $=this.queues.get(Q);if($)X=$.jobs.length,$.jobs.forEach((Y)=>{Y.job.cancel()}),this.info(`Canceled ${X} jobs in queue '${Q}'`)}else for(let[$,Y]of this.queues.entries()){let Z=Y.jobs.length;Y.jobs.forEach((G)=>{G.job.cancel()}),X+=Z,this.info(`Canceled ${Z} jobs in queue '${$}'`)}return X}};JQ=class JQ extends q{workers=[];currentWorkerIndex=0;queueWorkerMap=new Map;static instance=new JQ;constructor(){super()}async init(){}async addWorker(Q=[]){let X;if(Bun.main.endsWith(".js"))X=new rQ("./index.js",{argv:["work",...Q.map((Y)=>`--queue=${Y}`)]});else{let Y=await Array.fromAsync(new Bun.Glob("./src/**/*.job.ts").scan());X=new rQ("./index.ts",{preload:Y,argv:["work",...Q.map((Z)=>`--queue=${Z}`)]})}X.addEventListener("error",(Y)=>{this.trace({message:"An error occurred inside a worker process",stack:Y.message,name:"WorkerError"}),this.removeWorker(X),this.addWorker(Q)}),X.addEventListener("messageerror",(Y)=>{this.error(`Worker message error: ${Y}`)}),X.addEventListener("message",(Y)=>{if(Y.data.type==="worker:ready")this.debug(`Worker ${Y.data.id} ready with queues: ${Y.data.queues.join(", ")}`);else if(Y.data.type==="job:received")this.debug(`Job ${Y.data.jobId} received by worker for queue ${Y.data.queue}`);else if(Y.data.type==="job:error")this.error(`Error processing job ${Y.data.jobName}: ${Y.data.error}`);else this.debug(`Worker message: ${JSON.stringify(Y.data)}`)}),this.workers.push(X);for(let Y of Q){if(!this.queueWorkerMap.has(Y))this.queueWorkerMap.set(Y,[]);this.queueWorkerMap.get(Y).push(X)}}removeWorker(Q){let X=Q??this.workers.pop();if(!X)return;X.terminate();for(let[$,Y]of this.queueWorkerMap.entries())this.queueWorkerMap.set($,Y.filter((Z)=>Z!==X));if(Q)this.workers=this.workers.filter(($)=>$!==X)}terminate(){while(this.workers.length>0)this.removeWorker();this.queueWorkerMap.clear()}runJob(Q,...X){if(!Reflect.hasMetadata(P.job,Q))throw Error(`Job ${Q.name} is not marked with @job() decorator`);let{name:$,queue:Y="default"}=Reflect.getMetadata(P.job,Q),Z=this.queueWorkerMap.get(Y)||this.workers;if(Z.length===0)throw Error(`No workers available for queue '${Y}'`);let G=this.currentWorkerIndex%Z.length;Z[G].postMessage({job:$,args:X,queue:Y}),this.currentWorkerIndex=(this.currentWorkerIndex+1)%this.workers.length}cancelJob(Q,X){for(let $ of this.workers)$.postMessage({type:"job:cancel",jobId:Q,queue:X});return this.workers.length>0}cancelAllJobs(Q){for(let X of this.workers)X.postMessage({type:"job:cancelAll",queue:Q});return this.workers.length>0}}});import{t as P2}from"elysia";QQ();import{AsyncLocalStorage as hX}from"async_hooks";import{parseArgs as bX}from"util";import{swagger as vX}from"@elysiajs/swagger";import{Value as HQ}from"@sinclair/typebox/value";import{Elysia as yX}from"elysia";import{first as gX}from"radash";import{getTableName as uQ,is as mQ,Table as iQ}from"drizzle-orm";import{drizzle as wX}from"drizzle-orm/bun-sql";import{Cache as fX}from"drizzle-orm/cache/core";import{createCache as dQ}from"cache-manager";import{KeyvCacheableMemory as IX}from"cacheable";import{Keyv as lQ}from"keyv";import{alphabetical as TX}from"radash";import{EventEmitter as AX}from"events";import{omit as EX}from"radash";import{EventEmitter as KX}from"events";import{isString as bQ}from"radash";class b extends KX{static instance=new b;constructor(){super();this.on("error",(Q)=>this.emitError(Q))}emitError(Q){this.emit("elysium:error",{data:Q,source:null})}emitEvent(Q,X,$=null){this.emit(Q,{data:X,source:$})}}var N;((c)=>{c.emit=(U,_,M=null)=>{b.instance.emitEvent(U,_,M)};function X(U,_){if(bQ(U))b.instance.on(U,_);else return function(M,H,z){let K=async function(L){try{await z.value(L)}catch(V){b.instance.emitError(V)}};if(U.prepend??!1)b.instance.prependListener(U.event,K);else b.instance.on(U.event,K)}}c.on=X;function $(U,_){if(bQ(U))b.instance.once(U,_);else return function(M,H,z){let K=async function(L){try{await z.value(L)}catch(V){b.instance.emitError(V)}};if(U.prepend??!1)b.instance.prependOnceListener(U.event,K);else b.instance.once(U.event,K)}}c.once=$,c.off=(U)=>{b.instance.removeAllListeners(U)},c.clear=()=>{b.instance.removeAllListeners()},c.listen=(U)=>{if(U.mode==="on")return X(U);else if(U.mode==="once")return $(U);return function(_,M,H){console.error("Unknown mode provided to @listen. Use either 'on' or 'once'.")}}})(N||={});y();class jQ extends AX{#Q;#X;#$="::";#Y=1000;#Z=!0;#G=!1;#U;constructor(Q){super();N.once("elysium:app:launched",()=>{this.#Q=o.getConnection(Q.connection)}),this.#U=Q.connection,this.#X=Q.namespace,this.#$=Q.keyPrefixSeparator??"::",this.#Y=Q.clearBatchSize??1000,this.#Z=Q.useUnlink??!0,this.#G=Q.noNamespaceAffectsAll??!1,this.on("error",(X)=>{N.emit("elysium:error",X)})}get client(){return this.#Q}get opts(){return{namespace:this.#X,keyPrefixSeparator:this.#$,clearBatchSize:this.#Y,noNamespaceAffectsAll:this.#G,dialect:"redis",url:this.#U}}get namespace(){return this.#X}set namespace(Q){this.#X=Q}async get(Q){Q=this.createKeyPrefix(Q,this.#X);let X=await this.client.get(Q);return X===null?void 0:X}async set(Q,X,$){if(Q=this.createKeyPrefix(Q,this.#X),$)await this.client.set(Q,X,"PX",$);else await this.client.set(Q,X)}async setMany(Q){let X=[];for(let{key:$,value:Y,ttl:Z}of Q){let G=this.createKeyPrefix($,this.#X);if(Z)X.push(this.client.set(G,Y,"PX",Z));else X.push(this.client.set(G,Y))}await Promise.all(X)}async delete(Q){return Q=this.createKeyPrefix(Q,this.#X),await(this.#Z?this.client.send("UNLINK",[Q]):this.client.del(Q))>0}async clear(){try{if(!this.#X&&this.#G){await this.client.send("FLUSHDB",[]);return}let Q="0",X=this.#Y,$=this.#X?`${this.#X}${this.#$}*`:"*",Y=[];do{let Z=await this.client.send("SCAN",[Q,"MATCH",$,"COUNT",X.toString(),"TYPE","string"]),[G,U]=Z;if(Q=G.toString(),U.length===0)continue;if(!this.#X)U=U.filter((_)=>!_.includes(this.#$));Y.push(U.map((_)=>this.client.del(_)))}while(Q!=="0");await Promise.all(Y)}catch(Q){this.emit("error",Q)}}async has(Q){return Q=this.createKeyPrefix(Q,this.#X),this.client.exists(Q)}async hasMany(Q){let X=[];for(let $ of Q){let Y=this.createKeyPrefix($,this.#X);X.push(this.client.exists(Y))}return Promise.all(X)}async getMany(Q){if(Q.length===0)return[];return Q=Q.map(($)=>this.createKeyPrefix($,this.#X)),await this.client.mget(...Q)}async disconnect(){this.client.close()}async deleteMany(Q){let X=!1,$=[];for(let Z of Q){let G=this.createKeyPrefix(Z,this.#X);if(this.#Z)$.push(this.client.send("UNLINK",[G]));else $.push(this.client.del(G))}let Y=await Promise.all($);for(let Z of Y)if(typeof Z==="number"&&Z>0)X=!0;return X}async*iterator(Q){let X=Q?`${Q}${this.#$}*`:"*",$="0";do{let Y=await this.client.send("SCAN",[$,"MATCH",X,"TYPE","string"]),[Z,G]=Y;if($=Z.toString(),!Q&&!this.#G)G=G.filter((U)=>!U.includes(this.#$));if(G.length>0){let U=await this.client.mget(...G);for(let _ of G.keys()){let M=this.getKeyWithoutPrefix(G[_],Q),H=U[_];yield[M,H]}}}while($!=="0")}createKeyPrefix(Q,X){return X?`${X}${this.#$}${Q}`:Q}getKeyWithoutPrefix(Q,X){return X?Q.replace(`${X}${this.#$}`,""):Q}}var o;((g)=>{let Q=(U)=>{return`redis.connection.${U}`};g.getConnection=(U)=>{if(!B.exists(Q(U)))console.error(`No Redis connection with name ${U} found. Please make sure to register the connection before using it.`),process.exit(1);return B.get(Q(U))},g.registerConnection=(U,_)=>{if(B.exists(Q(U)))console.error(`A Redis connection with the name ${U} has already been registered.`),process.exit(1);return B.instance(Q(U),new Bun.RedisClient(_.url,EX(_,["url"])))},g.connectionExists=(U)=>{return B.exists(Q(U))},g.getDefaultConnection=()=>{return g.getConnection("default")},g.setDefaultConnection=(U)=>{let _=Q("default");return B.remove(_),B.instance(_,g.getConnection(U))}})(o||={});var pQ=(Q)=>{let X=dQ({stores:[new lQ({store:Q,namespace:"cache"})]}),$=new Map;return{...X,tags(...Y){let Z=`cache__${TX(Y,(U)=>U).join("__")}`,G=$.get(Z);if(!G)G=dQ({stores:[new lQ({store:Q,namespace:Z})]}),$.set(Z,G);return G}}};class u{static#Q;static#X;static weak=Object.seal({map:new WeakMap,get(Q){if(!this.map.has(Q))this.map.set(Q,{});return this.map.get(Q)},del(Q){this.map.delete(Q)}});static get redis(){if(!u.#Q)u.#Q=pQ(new jQ({connection:"cache"}));return u.#Q}static get memory(){if(!u.#X)u.#X=pQ(new IX({ttl:60000,lruSize:5000}));return u.#X}}y();class FQ extends fX{cacheStrategy;globalTtl;#Q;usedTablesPerKey={};constructor(Q="explicit",X=1,$="redis"){super();this.cacheStrategy=Q;this.globalTtl=X;this.#Q=u[$].tags("database")}strategy(){return this.cacheStrategy}async get(Q){return await this.#Q.get(Q)??void 0}async put(Q,X,$,Y,Z){await this.#Q.set(Q,X,(Z?.ex??this.globalTtl)*1000);for(let G of $){let U=this.usedTablesPerKey[G];if(U===void 0)this.usedTablesPerKey[G]=[Q];else U.push(Q)}}async onMutate(Q){let X=Q.tags?Array.isArray(Q.tags)?Q.tags:[Q.tags]:[],$=Q.tables?Array.isArray(Q.tables)?Q.tables:[Q.tables]:[],Y=new Set;for(let Z of $){let G=mQ(Z,iQ)?uQ(Z):Z,U=this.usedTablesPerKey[G]??[];for(let _ of U)Y.add(_)}if(Y.size>0||X.length>0){await this.#Q.mdel(X),await this.#Q.mdel([...Y]);for(let Z of $){let G=mQ(Z,iQ)?uQ(Z):Z;this.usedTablesPerKey[G]=[]}}}}var h;((d)=>{let Q=(U)=>{return`db.connection.${U}`};d.getConnection=(U)=>{if(!B.exists(Q(U)))console.error(`No connection with name ${U} found. Please make sure to register the connection before using it.`),process.exit(1);return B.get(Q(U))},d.registerConnection=(U,_)=>{if(B.exists(Q(U)))console.error(`A connection with the name ${U} has already been registered.`),process.exit(1);return B.instance(Q(U),wX({..._,cache:_.cache===void 0?void 0:_.cache===!0?new FQ:_.cache.enabled?new FQ(_.cache.strategy,_.cache.ttl,_.cache.storage):void 0}))},d.connectionExists=(U)=>{return B.exists(Q(U))},d.getDefaultConnection=()=>{return d.getConnection("default")},d.setDefaultConnection=(U)=>{let _=Q("default");return B.remove(_),B.instance(_,d.getConnection(U))}})(h||={});var RQ=new Map,AQ=(Q)=>{for(let[X,$]of Object.entries(Q))RQ.set(X,$)},cQ;(($Q)=>($Q.get=(Y,Z)=>{return RQ.get(Y)??Z},$Q.exists=(Y)=>{return RQ.has(Y)},$Q.clear=()=>{RQ.clear()}))(cQ||={});y();p();var m=(Q,X,$)=>{return f.context.run(new Map([["tenant",X.tenant],["http:context",X]]),async()=>{for(let Y of Q)try{let Z=await Y[$](X);if(Z!==void 0)return Z}catch(Z){throw Z}})},YQ=(Q,X)=>{let $=Q.map((Y)=>B.make(Y));X.onRequest((Y)=>{return m($,Y,"onRequest")}),X.onTransform((Y)=>{return m($,Y,"onTransform")}),X.onBeforeHandle((Y)=>{return m($,Y,"onBeforeHandle")}),X.onAfterHandle((Y)=>{return m($,Y,"onAfterHandle")}),X.onAfterResponse((Y)=>{return m($,Y,"onAfterResponse")})};class ZQ{static register(...Q){return function(X,$,Y){if($===void 0&&Y===void 0){let Z=Reflect.getMetadata(P.middlewares,X)??[];Z.push(...Q),Reflect.defineMetadata(P.middlewares,Z,X)}else{let Z=Reflect.getMetadata(P.middlewares,X,$)??[];Z.push(...Q),Reflect.defineMetadata(P.middlewares,Z,X,$)}}}static guards(Q){class X extends this{}return Reflect.defineMetadata(P.middlewareGuards,Q,X),X}get logger(){return B.get("logger").child({middleware:this.constructor.name})}get guards(){return Reflect.getMetadata(P.middlewareGuards,this.constructor)??[]}onRequest(Q){}onTransform(Q){}onAfterHandle(Q){}onBeforeHandle(Q){}onAfterResponse(Q){}}y();p();import{Elysia as CX}from"elysia";import{omit as SX}from"radash";import NX from"wampy";y();p();class nQ extends WebSocket{protocols;constructor(Q,X){super(Q,X);this.protocols=X}get protocol(){return this.protocols?.[0]??"wamp.2.json"}}var r;((x)=>{let Q=(H)=>{return`wamp.connection.${H}`};x.getConnection=(H)=>{if(!B.exists(Q(H)))console.error(`No WAMP connection with name ${H} found. Please make sure to register the connection before using it.`),process.exit(1);return B.get(Q(H))},x.registerConnection=(H,z)=>{if(B.exists(Q(H)))console.error(`A WAMP connection with name ${H} already exists. Please ensure to register a new connection before overwriting it.`),process.exit(1);let K=new NX(z.url,{ws:nQ,...SX(z,["url"]),onError(){z.onError?.(),N.emit("elysium:error",Error(`An error occurred in WAMP connection ${H}`))}}),O=z.maxRetries??5,L=z.retryInterval??5000,V=0,A=async()=>{try{await K.connect()}catch(C){if(console.error(`Failed to connect to WAMP server (attempt ${V+1}/${O}):`,C),V<O)V++,setTimeout(A,L);else console.error(`Max retry attempts (${O}) reached. Giving up.`),N.emit("elysium:error",Error(`Failed to establish WAMP connection ${H} after ${O} attempts`))}};return A(),B.instance(Q(H),K)},x.connectionExists=(H)=>{return B.exists(Q(H))},x.getDefaultConnection=()=>{return x.getConnection("default")},x.setDefaultConnection=(H)=>{let z=Q("default");return B.remove(z),B.instance(z,x.getConnection(H))},x.controller=(H)=>{return function(z){async function K(){console.log(`Registering Wamp controller for connection ${H.connection} using ${z.name}`),await n();let O=B.make(z),L=Reflect.getMetadata(P.wamp,z)??{},V=r.getConnection(H.connection??"default"),A=new CX;return A.onStart(async(C)=>{let R=L.registrations??[],J=L.subscriptions??[];for(let W of R)V.register(W.topic,W.handler.bind(O),W.options).then((T)=>{console.log(`Registered ${W.topic} with id ${T.registrationId}`)});for(let W of J)V.subscribe(W.topic,W.handler.bind(O),W.options).then((T)=>{console.log(`Subscribed ${W.topic} with id ${T.subscriptionId}`)})}),A}Reflect.defineMetadata(P.elysiaPlugin,K,z)}},x.register=(H,z)=>{return function(K,O,L){let V=Reflect.getMetadata(P.wamp,K.constructor)??{};V.registrations??=[],V.registrations.push({topic:H,options:z,handler:L.value}),Reflect.defineMetadata(P.wamp,V,K.constructor)}},x.subscribe=(H,z)=>{return function(K,O,L){let V=Reflect.getMetadata(P.wamp,K.constructor)??{};V.subscriptions??=[],V.subscriptions.push({topic:H,options:z,handler:L.value}),Reflect.defineMetadata(P.wamp,V,K.constructor)}}})(r||={});class f extends q{#Q;#X;_appContextStorage=new hX;static get instance(){return B.get("elysium.app")}static get context(){return f.instance._appContextStorage}static register(Q={}){return function(X){let $,Y=Object.getPrototypeOf(X);while(Y&&Y!==Object.prototype){let G=Reflect.getMetadata(P.app,Y);if(G){$=G;break}Y=Object.getPrototypeOf(Y)}if($)Q=s($,Q);let Z=Reflect.getMetadata(P.app,X);if(Z)Q=s(Z,Q);Q=s({modules:[],swagger:!1},Q),Reflect.defineMetadata(P.app,Q,X)}}constructor(){super();let{env:Q,debug:X}=Reflect.getMetadata(P.app,this.constructor)??{};if(this.#X=X??!1,Q){let G=HQ.Convert(Q,HQ.Clone(Bun.env));if(this.#X&&!HQ.Check(Q,G)){let U=HQ.Errors(Q,G).First();this.trace(U,"Invalid environment configuration")}AQ(HQ.Clean(Q,G))}else AQ(Bun.env);B.instance("elysium.app",this);let{database:$,redis:Y,wamp:Z}=Reflect.getMetadata(P.app,this.constructor);if(Y){for(let G in Y.connections)o.registerConnection(G,Y.connections[G]);if(o.connectionExists(Y.default))o.setDefaultConnection(Y.default)}if($){for(let G in $.connections)h.registerConnection(G,$.connections[G]);if(h.connectionExists($.default))h.setDefaultConnection($.default)}if(Z){for(let G in Z.connections)r.registerConnection(G,Z.connections[G]);if(r.connectionExists(Z.default))r.setDefaultConnection(Z.default)}this.run().then(()=>N.emit("elysium:app:launched",this,this)).catch((G)=>{N.emit("elysium:error",G),this.trace(G,"An error occurred while launching the application"),process.exit(1)})}get elysia(){return this.#Q}get isDebug(){return this.#X}set isDebug(Q){this.#X=Q}async onError(Q){return!0}async onStart(Q){}async onStop(Q){}async run(){let Q=process.argv.slice(2),X=Q[0];if(!X)this.commandDescribe();else switch(X){case"serve":return this.commandServe();case"work":return this.commandWork(Q.slice(1));case"help":{let $=Q[1];if($){let Z=this.getCommands().find((G)=>G.command===$);if(Z){let G=B.make(Z);return this.write(await G.help()),process.exit(0)}console.error(`Command <${$}> not found.`)}else console.error("No command provided. Usage: styx help <command>");this.commandList();break}case"list":{this.write(this.bold("Available commands:")),this.commandList();break}default:{let $=Q.slice(1);return this.commandExec(X,$)}}return process.exit(0)}getConfig(Q){return Reflect.getMetadata(P.app,this.constructor)?.[Q]??null}async commandExec(Q,X){let Y=this.getCommands().find((Z)=>Z.command===Q);if(!Y)return console.error(`Command ${Q} not found`),this.commandList(),process.exit(1);try{let Z=B.make(Y);if(await Z.init(...X))await Z.run();else{let U=await Z.help();this.write(U)}return process.exit(0)}catch(Z){return console.error(Z.message),process.exit(1)}}getCommands(){return B.keys("elysium.command.*").map(($)=>B.get($)).filter(($)=>$!==null).filter(($)=>Bun.env.NODE_ENV==="production"?!$.dev:!0)}async commandWork(Q){this.info("Starting worker process...");let{values:X}=bX({args:Q,options:{queue:{type:"string",multiple:!0,default:["default"],short:"q"},concurrency:{type:"string",default:"1",short:"c"},["max-retries"]:{type:"string",default:"5",short:"r"},["retry-delay"]:{type:"string",default:"5000",short:"d"},["pause-on-error"]:{type:"boolean",default:!1,short:"p"}}}),{Worker:$}=await Promise.resolve().then(() => (IQ(),tQ)),Y=X.queue.map((G)=>G.split(",")).reduce((G,U)=>G.concat(U),[]),Z=$.spawn(self,Y,{concurrency:parseInt(X.concurrency,10),maxRetries:parseInt(X["max-retries"],10),retryDelay:parseInt(X["retry-delay"],10),pauseOnError:X["pause-on-error"]});this.success(`Worker process ${this.format(Z.id,2)} started with queues: ${Y.map((G)=>this.format(G,6)).join(", ")}`)}async commandServe(){let{server:Q,modules:X,swagger:$,plugins:Y}=Reflect.getMetadata(P.app,this.constructor);if(this.#Q=new yX(Q).onRequest((G)=>{if(this.isDebug)console.log(G.request.method,G.request.url)}),N.emit("elysium:server:before-init",this,this),this.#Q.resolve({as:"global"},({request:G})=>({tenant:G.headers.get("x-tenant-id")??"public"})),$)this.#Q.use(vX($));if(Y&&Y.length>0){this.debug("Registering plugins...");for(let G of Y)this.#Q.use(await G(this))}this.#Q.onError({as:"global"},async(G)=>{if(await this.onError(G)){N.emit("elysium:error",G),this.trace({name:"HttpError",message:"Unexpected error while handling HTTP request",stack:G.error.stack,...G.error});let U={};if(typeof G.code==="number")return G.error.response;else switch(G.code){case"VALIDATION":{U={scope:G.error.type,code:G.error.message};break}case"INTERNAL_SERVER_ERROR":{U={message:G.error.message};break}}return{type:G.code,data:U}}}).onStart(async(G)=>{await this.onStart(G),N.emit("elysium:server:start",G,this)}).onStop(async(G)=>{await this.onStop(G),N.emit("elysium:server:stop",G,this),this._appContextStorage.disable()});let Z=Reflect.getMetadata(P.middlewares,this.constructor)??[];YQ(Z,this.#Q);for(let G of X){let U=Reflect.getMetadata(P.elysiaPlugin,G);if(U===void 0)return console.error(`Invalid module class ${G.name} registered in app ${this.constructor.name}. Ensure that you used the @module() decorator on the module.`),process.exit(1);let _=B.bind(G);await _.beforeRegister(),this.#Q.use(await U(_)),await _.afterRegister()}N.emit("elysium:server:after-init",this,this),this.#Q.listen(Q?.port??(parseInt(process.env.PORT,10)||3000)),process.on("SIGINT",()=>{this.#Q.stop().then(()=>process.exit(0))})}commandDescribe(){this.section(`${this.bold("Usage:")} ${this.format("styx",5)} <command> [options]`),this.section(this.bold("Core Commands:")),this.newLine(),this.commandDescription("serve","","Starts the server."),this.commandDescription("help","<command>","Displays help for a command."),this.commandDescription("list","","List all available application commands."),this.section(this.bold("Application Commands:")),this.commandList()}commandList(){let X=this.getCommands().reduce(($,Y)=>{let Z=gX(Y.command.split(":")),G=$.get(Z)??[];return G.push(Y),$.set(Z,G),$},new Map);for(let[$,Y]of X){this.section(this.format($,4));for(let Z of Y)this.commandDescription(Z.command,"",Z.description)}}commandDescription(Q,X,$,Y=q.SPACE_WIDTH){X=X.length===0?" ":` ${X} `,this.write(` ${this.format(Q,6)}${X}${"\u2219".repeat(Y-Q.length-X.length)} ${$}`)}}QQ();y();p();import{isArray as dX,trim as lX}from"radash";var aQ;((G)=>{G.STRING="string";G.NUMBER="number";G.BOOLEAN="boolean";G.ENUM="enum";G.ARRAY="array"})(aQ||={});class eQ extends q{static command="command";static description="Command description";static dev=!1;static register(Q={}){return function(X){let $=X,Z=`elysium.command.${Q.name??$.command}`;if(B.exists(Z))return X;return B.instance(Z,X),X}}static arg(Q={}){return function(X,$){let Y=Reflect.getMetadata(P.arg,X.constructor)??[],Z=Reflect.getMetadata("design:type",X,$),G=Q.type;if(!G&&Z){if(Z===Array){if(G="array",!Q.arrayType)Q={...Q,arrayType:"string"}}else if(Z.constructor!==Object)switch(Z.name.toLowerCase()){case"number":G="number";break;case"boolean":G="boolean";break;case"string":G="string";break;default:G=void 0}else if(Object.values(Z).length>0){if(G="enum",!Q.enum)Q={...Q,enum:Object.values(Z)}}}Y.push({name:Q.name??$,description:Q.description,required:Q.required??!1,default:Q.default,type:G,enum:Q.enum,arrayType:Q.arrayType,propertyKey:$}),Reflect.defineMetadata(P.arg,Y,X.constructor)}}async init(...Q){let X=this.processArgs(Q),$=this.validateArgs(X);if(!$.valid){if($.missing.length>0)console.error(`Missing required arguments: ${$.missing.join(", ")}
|
|
9
|
-
`);return!1}if(Object.keys(
|
|
10
|
-
`;
|
|
8
|
+
`),process.stdin.setRawMode?.(!1),process.stdin.removeAllListeners("data"),rl.close(),resolve(password);return}if(char==="\b"||char==="\x7F"){if(password.length>0)password=password.slice(0,-1),process.stdout.write("\b \b");return}password+=char,process.stdout.write("*")})})}async confirm(question,defaultValue=!1){let defaultText=defaultValue?"Y/n":"y/N",answer=await this.prompt(`${question} [${defaultText}]`);if(!answer)return defaultValue;return answer.toLowerCase()==="y"||answer.toLowerCase()==="yes"}async select(question,options,defaultIndex=0){if(options.length===0)throw Error("No options provided for selection");this.write(question),options.forEach((option,index)=>{let isDefault=index===defaultIndex;this.write(` ${index+1}. ${option}${isDefault?" (default)":""}`)});let selection=await this.prompt("Enter your choice (number)");if(!selection)return options[defaultIndex];let index=parseInt(selection,10)-1;if(isNaN(index)||index<0||index>=options.length)return this.warning(`Invalid selection. Using default: ${options[defaultIndex]}`),options[defaultIndex];return options[index]}formatTime(seconds){if(seconds<60)return`${seconds.toFixed(1)}s`;if(seconds<3600)return`${Math.floor(seconds/60)}m ${Math.floor(seconds%60)}s`;return`${Math.floor(seconds/3600)}h ${Math.floor(seconds%3600/60)}m`}}var STORE_KEY=Symbol.for("elysium:metadata"),store=globalThis[STORE_KEY]??=new WeakMap,foreign=(name)=>{let fn=Reflect[name];return typeof fn==="function"?fn:void 0},findOwn=(key,target,propertyKey)=>{let entries=store.get(target)?.get(propertyKey);if(entries?.has(key))return{value:entries.get(key)};let getOwn=foreign("getOwnMetadata");if(!getOwn)return;let hasOwn=foreign("hasOwnMetadata"),value=getOwn(key,target,propertyKey);return value!==void 0||Boolean(hasOwn?.(key,target,propertyKey))?{value}:void 0},find=(key,target,propertyKey)=>{for(let current=target;current;current=Object.getPrototypeOf(current)){let found=findOwn(key,current,propertyKey);if(found)return found}return},Metadata;((Metadata)=>(Metadata.define=(key,value,target,propertyKey)=>{let members=store.get(target);if(!members)store.set(target,members=new Map);let entries=members.get(propertyKey);if(!entries)members.set(propertyKey,entries=new Map);entries.set(key,value)},Metadata.getOwn=(key,target,propertyKey)=>findOwn(key,target,propertyKey)?.value,Metadata.get=(key,target,propertyKey)=>find(key,target,propertyKey)?.value,Metadata.has=(key,target,propertyKey)=>find(key,target,propertyKey)!==void 0))(Metadata||={});if(typeof Reflect.metadata!=="function")Object.defineProperty(Reflect,"metadata",{configurable:!0,writable:!0,value:(key,value)=>(target,propertyKey)=>{Metadata.define(key,value,target,propertyKey),foreign("defineMetadata")?.(key,value,target,propertyKey)}});import{isObject}from"radash";var Symbols;((Symbols)=>(Symbols.app=Symbol("elysium:Application"),Symbols.controller=Symbol("elysium:Controller"),Symbols.middlewares=Symbol("elysium:MiddlewaresList"),Symbols.services=Symbol("elysium:ServicesList"),Symbols.websocket=Symbol("elysium:WebSocket"),Symbols.wamp=Symbol("elysium:Wamp"),Symbols.http=Symbol("elysium:Http"),Symbols.arg=Symbol("elysium:CommandArguments"),Symbols.elysiaPlugin=Symbol("elysium:ElysiaPlugin"),Symbols.middlewareGuards=Symbol("elysium:MiddlewareGuards"),Symbols.eventListeners=Symbol("elysium:EventListeners"),Symbols.serviceOptions=Symbol("elysium:ServiceOptions"),Symbols.module=Symbol("elysium:Module"),Symbols.configuredModule=Symbol("elysium:ConfiguredModule"),Symbols.moduleConfig=Symbol("elysium:ModuleConfig"),Symbols.command=Symbol("elysium:Command")))(Symbols||={});function currentEnvironment(){return Bun.env.NODE_ENV??"development"}var nextTick=()=>new Promise((resolve)=>process.nextTick(resolve));function cloneValue(value){if(Array.isArray(value))return value.map(cloneValue);if(isObject(value)){let out={};for(let key of Reflect.ownKeys(value))if(Object.prototype.propertyIsEnumerable.call(value,key))out[key]=cloneValue(value[key]);return out}return value}function mergeInto(target,source){for(let key of Object.keys(source)){let value=source[key];if(isObject(value)){if(isObject(target[key]))mergeInto(target[key],value);else if(target[key]===void 0)target[key]=cloneValue(value)}else if(Array.isArray(value)){if(!Array.isArray(target[key]))target[key]=[];let current=target[key];if(value.length>0&&!isObject(value[0]))target[key]=[...new Set([...current,...value])];else value.forEach((item,index)=>{if(isObject(item)&&isObject(current[index]))mergeInto(current[index],item);else if(!current.includes(item))current.push(cloneValue(item))})}else if(target[key]===void 0)target[key]=value}}function deepMerge(target,...sources){let result=cloneValue(target);for(let source of sources)if(isObject(result)&&isObject(source))mergeInto(result,source);return result}var CommandArgumentType;((CommandArgumentType)=>{CommandArgumentType.STRING="string";CommandArgumentType.NUMBER="number";CommandArgumentType.BOOLEAN="boolean";CommandArgumentType.ENUM="enum";CommandArgumentType.ARRAY="array"})(CommandArgumentType||={});function getCommandName(cls){return Metadata.get(Symbols.command,cls)?.name??cls.command}class Command extends InteractsWithConsole{static command="command";static description="Command description";static dev=!1;static boot=!1;static register(options={}){return function(target){Metadata.define(Symbols.command,options,target)}}static arg(props={}){return function(target,propertyKey){let args=Metadata.get(Symbols.arg,target.constructor)??[],propertyType=Metadata.get("design:type",target,propertyKey),inferredType=props.type;if(!inferredType&&propertyType){if(propertyType===Array){if(inferredType="array",!props.arrayType)props={...props,arrayType:"string"}}else if(propertyType.constructor!==Object)switch(propertyType.name.toLowerCase()){case"number":inferredType="number";break;case"boolean":inferredType="boolean";break;case"string":inferredType="string";break;default:inferredType=void 0}else if(Object.values(propertyType).length>0){if(inferredType="enum",!props.enum)props={...props,enum:Object.values(propertyType)}}}args.push({name:props.name??propertyKey,description:props.description,required:props.required??!1,default:props.default,type:inferredType,enum:props.enum,arrayType:props.arrayType,propertyKey}),Metadata.define(Symbols.arg,args,target.constructor)}}async init(...argv){let args=this.processArgs(argv),validation=this.validateArgs(args);if(!validation.valid){if(validation.missing.length>0)console.error(`Missing required arguments: ${validation.missing.join(", ")}
|
|
9
|
+
`);return!1}if(Object.keys(args).includes("help"))return!1;let commandArgs=this.getArguments();for(let arg of commandArgs)if(args[arg.name]!==void 0)this[arg.propertyKey]=args[arg.name];return!0}getArguments(){return Metadata.get(Symbols.arg,this.constructor)||[]}async help(){let helpText=`${this.bold("Command:")} ${this.format(this.constructor.command,5)}
|
|
10
|
+
`;helpText+=`${this.bold("Description:")} ${this.constructor.description}
|
|
11
11
|
|
|
12
|
-
`;let
|
|
13
|
-
`;for(let
|
|
14
|
-
|
|
12
|
+
`;let args=this.getArguments();if(args.length>0){helpText+=`${this.bold("Arguments:")}
|
|
13
|
+
`;for(let arg of args){let requiredText=this.format(arg.required?"(required)":"(optional)",1,9),defaultText=arg.default!==void 0?this.format(`[default: ${arg.default}]`,8,11):"",typeText="";if(arg.type==="array")typeText=`<array of ${arg.arrayType||"string"}s>`;else if(arg.type)typeText=`<${arg.type}>`;let enumText=arg.enum?` [${arg.enum.join("|")}]`:"";if(helpText+=` ${this.format(`--${arg.name}`,6)} ${typeText}${enumText} ${requiredText} ${defaultText}
|
|
14
|
+
`,arg.description)helpText+=` ${arg.description}
|
|
15
15
|
|
|
16
|
-
`}}else
|
|
17
|
-
`;return
|
|
18
|
-
`)}validateArgs(
|
|
19
|
-
`);return{valid:X.length===0&&$.length===0,missing:X}}processArgs(Q){let X={},$=this.getArguments();for(let Y=0;Y<Q.length;Y++){let Z=Q[Y];if(Z.startsWith("--")){let G=Z.slice(2);if(Y+1<Q.length&&!Q[Y+1].startsWith("--"))X[G]=Q[Y+1],Y++;else X[G]=!0}}for(let Y of $){if(X[Y.name]===void 0&&Y.default!==void 0){X[Y.name]=Y.default;continue}if(X[Y.name]===void 0)continue;if(typeof X[Y.name]==="string")switch(Y.type||this.inferType(Y.default)){case"number":X[Y.name]=Number(X[Y.name]);break;case"boolean":let G=X[Y.name].toLowerCase();X[Y.name]=G==="true"||G==="1"||G==="yes";break;case"enum":if(Y.enum&&Y.enum.length>0&&typeof Y.enum[0]==="number")X[Y.name]=Number(X[Y.name]);break;case"array":let U=X[Y.name].split(",").map((_)=>_.trim());if(Y.arrayType)X[Y.name]=U.map((_)=>{switch(Y.arrayType){case"number":return Number(_);case"boolean":return _.toLowerCase()==="true"||_.toLowerCase()==="1"||_.toLowerCase()==="yes";case"enum":return _;default:return _}});else X[Y.name]=U;break;case"string":default:break}}return X}progress(Q,X="Processing"){return new QX(Q,X)}spinner(Q="Processing",X,$){return new XX(Q,X,$)}inferType(Q){if(Q===void 0)return"string";switch(typeof Q){case"number":return"number";case"boolean":return"boolean";default:return dX(Q)?"array":"string"}}}class QX extends q{#Q=!1;#X=0;#$=0;#Y="";#Z=0;constructor(Q=0,X="Processing"){super();this.#X=Q,this.#Y=X,this.#Q=!0,this.#$=0,this.#Z=Date.now(),this.update(0)}update(Q=1,X){if(!this.#Q)return;if(this.#$+=Q,X)this.#Y=X;let $=Math.min(100,Math.floor(this.#$/this.#X*100)),Z=(Date.now()-this.#Z)/1000,G=0,U=0,_="";if(this.#$>0)G=Z/this.#$*this.#X,U=Math.max(0,G-Z),_=` | ${this.formatTime(Z)} elapsed | ${this.formatTime(U)} remaining`;let M=30,H=Math.floor($/100*M),z=M-H,K="["+"=".repeat(H)+(z>0?">":"")+" ".repeat(Math.max(0,z-(z>0?1:0)))+"]",O=`${this.#Y}: ${K} ${$}% (${this.#$}/${this.#X})${_}`;if(this.clearLine(),this.write(O,!1),this.#$>=this.#X)this.complete()}complete(Q){if(!this.#Q)return;this.#$=this.#X;let $=(Date.now()-this.#Z)/1000;if(this.clearLine(),Q)this.write(`${Q} (completed in ${this.formatTime($)})`);else this.write(`${this.#Y} completed in ${this.formatTime($)}`);this.#Q=!1}pause(Q){if(!this.#Q)return;this.newLine(),this.write(Q),this.update(0)}isActive(){return this.#Q}getCurrent(){return this.#$}getTotal(){return this.#X}getPercentage(){return Math.min(100,Math.floor(this.#$/this.#X*100))}}class XX extends q{#Q=!1;#X="";#$=0;#Y=null;#Z=0;#G=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"];#U=80;constructor(Q="Processing",X,$){super();if(this.#X=Q,X)this.#G=X;if($)this.#U=$;if(this.#Q)return;this.#Q=!0,this.#$=Date.now(),this.#Z=0,this.#Y=setInterval(()=>{this.render()},this.#U),this.render()}update(Q){if(!this.#Q)return;this.#X=Q}complete(Q,X=!0){if(!this.#Q)return;if(this.#Y)clearInterval(this.#Y),this.#Y=null;let Y=(Date.now()-this.#$)/1000;this.clearLine();let Z=this.formatTime(Y);if(Q)this[X?"success":"error"](`${Q} (${Z})`);else this[X?"success":"error"](`${this.#X} completed in ${Z}`);this.#Q=!1}fail(Q){this.complete(Q,!1)}pause(Q){if(!this.#Q)return;if(this.#Y)clearInterval(this.#Y),this.#Y=null;this.clearLine(),this.write(Q),this.#Y=setInterval(()=>{this.render()},this.#U)}isActive(){return this.#Q}getElapsedTime(){return(Date.now()-this.#$)/1000}render(){if(!this.#Q)return;let Q=this.getElapsedTime(),X=this.#G[this.#Z];this.#Z=(this.#Z+1)%this.#G.length,this.clearLine(),this.write(`${X} ${this.#X} (${this.formatTime(Q)})`,!1)}}QQ();class TQ{context;constructor(Q={}){this.context=Q}trace(Q,X){console.debug(`[TRACE] ${Q}`,{...this.context,...X})}debug(Q,X){console.debug(`[DEBUG] ${Q}`,{...this.context,...X})}info(Q,X){console.info(`[INFO] ${Q}`,{...this.context,...X})}warn(Q,X){console.warn(`[WARN] ${Q}`,{...this.context,...X})}error(Q,X){console.error(`[ERROR] ${Q}`,{...this.context,...X})}fatal(Q,X){console.error(`[FATAL] ${Q}`,{...this.context,...X})}child(Q){return new TQ({...this.context,...Q})}}import{Elysia as pX,sse as uX,t as $X}from"elysia";import{assign as mX,isEmpty as WQ,objectify as iX}from"radash";y();p();var cX=(Q)=>{let X=Reflect.getMetadata("http:body",Q.target,Q.propertyKey),$=Reflect.getMetadata("http:params",Q.target,Q.propertyKey)??[],Y=Reflect.getMetadata("http:query",Q.target,Q.propertyKey),Z=Reflect.getMetadata("http:rawContext",Q.target,Q.propertyKey),G=Reflect.getMetadata("http:customDecorators",Q.target,Q.propertyKey)??[],U=Reflect.getMetadata(P.middlewares,Q.target,Q.propertyKey)??[],_=Reflect.getMetadata(P.services,Q.target,Q.propertyKey)??[],{path:M,method:H,handler:z,target:K,response:O,operationId:L,description:V,transactional:A}=Q,C=Reflect.getMetadata(P.http,K.constructor)??[];C.push({path:M,method:H,body:X,params:$,query:Y,customDecorators:G,rawContext:Z,handler:z,middlewares:U,response:O,operationId:L,description:V,services:_,transactional:A}),Reflect.defineMetadata(P.http,C,K.constructor)},YX;(($)=>{$[$.SERVER=0]="SERVER";$[$.REQUEST=1]="REQUEST"})(YX||={});var ZX;((D)=>(D.controller=(R={path:"/"})=>{return function(J){async function W(){console.log(`Registering HTTP controller for ${R.path} using ${J.name}`),await n(),R=mX({path:"/",scope:0,tags:[]},R);let T=new pX({prefix:R.path,name:J.name}),i=(()=>{if(R.scope===0)return()=>{let j=B.make(J);return()=>j};else if(R.scope===1)return()=>()=>B.make(J);else throw Error(`Invalid scope for controller: ${J.name}`)})();T.resolve({as:"local"},()=>({controller:i()}));let GQ=Reflect.getMetadata("http:onRequest",J)??{};if(GQ.handler)T.onRequest((j)=>{let e=i()();return GQ.handler.call(e,j)});let PX=Reflect.getMetadata(P.middlewares,J)??[];YQ(PX,T);let zX=Reflect.getMetadata(P.http,J)??[];for(let j of zX){let e=async(I)=>{let F=[];if(j.rawContext)F[j.rawContext.index]=I;if(j.body)F[j.body.index]=I.body;if(j.query)F[j.query.index]=I.query;if(!WQ(j.params))for(let S of j.params)F[S.index]=I.params[S.slug];if(!WQ(j.customDecorators))for(let S of j.customDecorators)F[S.index]=await S.handler(I);if(!WQ(j.services))for(let S of j.services)F[S.index]=B.get(S.name);return F},BX=j.handler.constructor.name.includes("GeneratorFunction"),kQ=j.method==="elysium:SSE",VX=j.transactional??R.transactional??!1,MQ=j.body&&j.body.schema===void 0&&j.body.validator!==void 0;j.method=kQ?"GET":j.method;let RX=()=>{let I=(F)=>{if(VX)return function(...S){return h.getDefaultConnection().transaction((BQ)=>{return f.context.run(new Map([["tenant",F.tenant],["http:context",F],["db:tx",BQ]]),()=>{try{return j.handler.call(F.controller(),...S)}catch(UQ){throw BQ.rollback(),UQ}})})};return function(...S){return f.context.run(new Map([["tenant",F.tenant],["http:context",F]]),()=>j.handler.call(F.controller(),...S))}};if(BX)return async function*(F){let S=I(F),BQ=await e(F);try{for await(let UQ of S(...BQ))yield UQ}catch(UQ){yield UQ}};if(kQ)return async function*(F){let S=I(F);F.set.headers["content-type"]="text/event-stream",F.set.headers["cache-control"]="no-cache",F.set.headers.connection="keep-alive";while(!0)yield uX(await S(...await e(F))),await Bun.sleep(10)};if(MQ)return async function(F){if(await j.body.validator.validate(F))return await I(F)(...await e(F));throw F.status(400,"Invalid request body")};return async function(F){return await I(F)(...await e(F))}},qQ=iX(j.params??[],(I)=>I.slug,(I)=>I.schema),zQ=j.middlewares.map((I)=>B.make(I));T.route(j.method,j.path,RX(),{config:{},async transform(I){if(MQ&&!await j.body.validator.authorize(I))throw I.status(401,"Unauthorized");return m(zQ,I,"onTransform")},beforeHandle(I){return m(zQ,I,"onBeforeHandle")},afterHandle(I){return m(zQ,I,"onAfterHandle")},afterResponse(I){return m(zQ,I,"onAfterResponse")},detail:{tags:R.tags,description:j.description,operationId:j.operationId},body:MQ?j.body?.validator?.schema:j.body?.schema,response:j.response,params:WQ(qQ)?void 0:$X.Object(qQ)})}return T}Reflect.defineMetadata(P.elysiaPlugin,W,J)}},D.sse=(R={})=>{let{path:J="/",...W}=R;return D.custom({method:"elysium:SSE",path:J,...W})},D.get=(R={})=>{let{path:J="/",...W}=R;return D.custom({method:"GET",path:J,...W})},D.post=(R={})=>{let{path:J="/",...W}=R;return D.custom({method:"POST",path:J,...W})},D.put=(R={})=>{let{path:J="/",...W}=R;return D.custom({method:"PUT",path:J,...W})},D.del=(R={})=>{let{path:J="/",...W}=R;return D.custom({method:"DELETE",path:J,...W})},D.patch=(R={})=>{let{path:J="/",...W}=R;return D.custom({method:"PATCH",path:J,...W})},D.head=(R={})=>{let{path:J="/",...W}=R??{};return D.custom({method:"HEAD",path:J,...W})},D.options=(R={})=>{let{path:J="/",...W}=R;return D.custom({method:"OPTIONS",path:J,...W})},D.trace=(R={})=>{let{path:J="/",...W}=R;return D.custom({method:"TRACE",path:J,...W})},D.custom=({path:R="/",...J})=>{return function(W,T,i){process.nextTick(()=>{cX({path:R,handler:i.value,target:W,propertyKey:T,...J})})}},D.onRequest=()=>{return function(R,J,W){let T=Reflect.getMetadata("http:onRequest",R.constructor)??{};T.handler=W.value,Reflect.defineMetadata("http:onRequest",T,R.constructor)}},D.context=()=>{return function(R,J,W){Reflect.defineMetadata("http:rawContext",{index:W},R,J)}},D.param=(R,J)=>{return function(W,T,i){let GQ=Reflect.getMetadata("http:params",W,T)??[];GQ.push({slug:R,schema:J??$X.String(),index:i}),Reflect.defineMetadata("http:params",GQ,W,T)}},D.query=(R)=>{return function(J,W,T){Reflect.defineMetadata("http:query",{schema:R,index:T},J,W)}},D.body=(R)=>{return function(J,W,T){if(typeof R==="function")Reflect.defineMetadata("http:body",{validator:R,index:T},J,W);else Reflect.defineMetadata("http:body",{schema:R,index:T},J,W)}},D.decorate=(R)=>{return()=>{return function(J,W,T){let i=Reflect.getMetadata("http:customDecorators",J,W)??[];i.push({handler:R,index:T}),Reflect.defineMetadata("http:customDecorators",i,J,W)}}}))(ZX||={});oQ();class GX extends ZQ{async onRequest(Q){Q.__requestStartTime=Date.now(),this.logger.info("Incoming request",{method:Q.request.method,path:new URL(Q.request.url).pathname})}async onAfterResponse(Q){let X=Date.now()-(Q.__requestStartTime??0);this.logger.info("Request completed",{method:Q.request.method,path:new URL(Q.request.url).pathname,duration:`${X}ms`})}}import{getTableConfig as Y0,pgTable as Z0}from"drizzle-orm/pg-core";import{t as k}from"elysia";var LX={};hQ(LX,{wrapTenantSchema:()=>CQ,withTenant:()=>aX,withRLS:()=>eX,setConnectionTenant:()=>Q0,registerTenantSchema:()=>_X,getTenantSchema:()=>UX,getSessionTenant:()=>X0,getCurrentTenant:()=>fQ,getConfig:()=>tX,createRLSPolicy:()=>$0,configure:()=>rX,TenantMiddleware:()=>OQ,StrictTenantMiddleware:()=>NQ,SimpleTenantMiddleware:()=>SQ});import{sql as t}from"drizzle-orm";import{pgPolicy as nX,pgSchema as sX,pgTable as oX}from"drizzle-orm/pg-core";var a={mode:"schema"},wQ=new Map,DQ=new Map,rX=(Q)=>{a=Q},tX=()=>a,fQ=()=>{if(!f.instance||!f.context.getStore)return null;return f.context.getStore()?.get("tenant")??null},aX=(Q,X)=>{let $=f.context.getStore(),Y=new Map($);return Y.set("tenant",Q),f.context.run(Y,X)},UX=(Q)=>{return DQ.get(Q)??_X(Q)},_X=(Q)=>{if(DQ.has(Q))return DQ.get(Q);let X=sX(Q);return DQ.set(Q,X),X},CQ=(Q,X,$)=>{if(Q==="public")return oX(X,$);let Y=`${Q}.${X}`;if(wQ.has(Y))return wQ.get(Y);let G=UX(Q).table(X,$);return wQ.set(Y,G),G},eX=async(Q,X,$="default")=>{let Y=h.getConnection($),Z=a.rls?.sessionVariable??"app.current_tenant",G=Q??"public";return Y.transaction(async(U)=>{return await U.execute(t`SELECT set_config(${Z}, ${G}, true)`),X(U)})},Q0=async(Q,X="default")=>{let $=h.getConnection(X),Y=a.rls?.sessionVariable??"app.current_tenant",Z=Q??"public";await $.execute(t`SELECT set_config(${Y}, ${Z}, false)`)},X0=async(Q="default")=>{let X=h.getConnection(Q),$=a.rls?.sessionVariable??"app.current_tenant";return(await X.execute(t`SELECT current_setting(${$}, true) as tenant`))?.rows?.[0]?.tenant??null},$0=(Q,X,$)=>{let Y=a.rls?.sessionVariable??"app.current_tenant",Z=X??a.rls?.defaultColumn??"tenant_id",G=$??`${Q}_tenant_isolation`;return nX(G,{for:"all",to:"public",using:t`${t.identifier(Z)} = current_setting(${Y}, true)::text`,withCheck:t`${t.identifier(Z)} = current_setting(${Y}, true)::text`})};class OQ extends ZQ{header="x-tenant-id";allowPublic=!0;connectionName="default";async validateTenant(Q){return!0}async onTenantResolved(Q,X){}onTenantError(Q,X){if(Q==="missing")throw Error("Tenant ID required");else throw Error("Invalid tenant")}async onRequest(Q){let X=Q.request.headers.get(this.header);if(!X||X==="public"){if(this.allowPublic){Q.tenant="public";return}return this.onTenantError("missing",Q)}if(!await this.validateTenant(X))return this.onTenantError("invalid",Q);Q.tenant=X,await this.onTenantResolved(X,Q)}}class SQ extends OQ{}class NQ extends OQ{allowPublic=!1}var xQ=(Q,{mode:X="select"}={})=>{let{columns:$}=Y0(Q);if($===void 0)return k.Object({});let Y={};for(let Z of $){if(["create","update"].includes(X)&&Z.primary)continue;if(Y[Z.name]=G0(Z),!Z.notNull)Y[Z.name]=k.Nullable(Y[Z.name]);if(X==="update"||Z.hasDefault||!Z.notNull)Y[Z.name]=k.Optional(Y[Z.name])}return k.Object(Y)},G0=(Q)=>{let X=(()=>{switch(Q.dataType){case"string":return k.String({format:Q.columnType==="PgUUID"?"uuid":void 0});case"number":return k.Number();case"boolean":return k.Boolean();case"array":return k.Array(k.Any());case"json":return k.Object({});case"date":case"localDate":case"localDateTime":return k.Transform(k.String({format:Q.dataType==="date"?"date":"date-time"})).Decode(($)=>new Date($)).Encode(($)=>$.toISOString());case"bigint":return k.BigInt();case"buffer":return k.File();default:return k.Never()}})();if(!Q.notNull)X=k.Optional(X);else X=k.Required(X);return X},U0=(Q,X,$)=>{let Y=Z0(Q,X,$);class Z{static $inferSelect=Y.$inferSelect;static $inferInsert=Y.$inferInsert;static $inferUpdate=Y.$inferInsert;static get table(){if(!f.instance||!f.context.getStore)return Y;if(this.supportTenancy){let G=fQ()??"public";return CQ(G,this.tableName,this.columns)}return Y}static tableName=Q;static columns=X;static extraConfig=$;static insertSchema=xQ(Y,{mode:"create"});static updateSchema=xQ(Y,{mode:"update"});static selectSchema=xQ(Y,{mode:"select"});static supportTenancy=!1}return Z};import{Elysia as _0}from"elysia";import{assign as L0}from"radash";p();class HX{static register(Q={}){return function(X){async function $(Y){console.log(`Registering module ${X.name}`),await n();let Z=L0({controllers:[]},Q),G=new _0({name:X.name,prefix:Q.prefix});G.resolve({as:"local"},()=>({module:Y}));let U=Reflect.getMetadata(P.middlewares,X)??[];YQ(U,G);for(let _ of Z.controllers){let M=Reflect.getMetadata(P.elysiaPlugin,_);if(M===void 0)console.error(`Invalid controller class ${_.name} registered in module ${X.name}. Ensure that you either used the @Http.controller(), the @Websocket.controller(), or the @Wamp.controller() decorators on the class.`),process.exit(1);else G.use(await M())}return G}Reflect.defineMetadata(P.elysiaPlugin,$,X)}}beforeRegister(){return Promise.resolve()}afterRegister(){return Promise.resolve()}}import{eq as PQ}from"drizzle-orm";var H0=(Q)=>{class X{static Model=Q;static connection="default";get db(){let $=this.constructor.connection,Y=null;if($==="default")Y=f.context.getStore()?.get("db:tx")??null;return Y??h.getConnection($)}async all(){return await this.db.select().from(Q.table)}async paginate($,Y=1){let Z=await this.db.$count(Q.table),G=Math.max(Y-1,0)*$;return{page:Y,total:Z,data:await this.db.select().from(Q.table).offset(G).limit($)}}async find($){let[Y]=await this.db.select().from(Q.table).where(PQ(Q.table.id,$));return Y??null}async findBy($,Y){let[Z]=await this.db.select().from(Q.table).where(PQ(Q.table[$],Y));return Z??null}async insert($){let[Y]=await this.db.insert(Q.table).values($).returning();return Y}async update($,Y){let[Z]=await this.db.update(Q.table).set(Y).where(PQ(Q.table.id,$)).returning();return Z}async updateAll($){return await this.db.update(Q.table).set($).returning()}async delete($){let[Y]=await this.db.delete(Q.table).where(PQ(Q.table.id,$)).returning();return Y}async deleteAll(){return await this.db.delete(Q.table).returning()}async exists($){return await this.db.$count(Q.table,PQ(Q.table.id,$))>0}}return X};y();import{Elysia as O0}from"elysia";y();p();var OX;((l)=>(l.controller=(U)=>{return function(_){async function M(){console.log(`Registering Websocket route for ${U.path} using ${_.name}`),await n();let H=B.make(_),z=Reflect.getMetadata(P.websocket,_)??{},K=z.open?.bind(H),O=z.close?.bind(H),L=z.message?.bind(H),V=z.drain?.bind(H),A=z.error?.bind(H)??((R)=>N.emit("elysium:error",R.error)),C=new O0;return C.ws(U.path,{open:K,close:O,message:L,drain:V,error:A,body:z.body,...U.options}),C}Reflect.defineMetadata(P.elysiaPlugin,M,_)}},l.onOpen=()=>{return function(U,_,M){let H=Reflect.getMetadata(P.websocket,U.constructor)??{};H.open=M.value,Reflect.defineMetadata(P.websocket,H,U.constructor)}},l.onClose=()=>{return function(U,_,M){let H=Reflect.getMetadata(P.websocket,U.constructor)??{};H.close=M.value,Reflect.defineMetadata(P.websocket,H,U.constructor)}},l.onMessage=(U)=>{return function(_,M,H){let z=Reflect.getMetadata(P.websocket,_.constructor)??{};z.message=H.value,z.body=U,Reflect.defineMetadata(P.websocket,z,_.constructor)}},l.onDrain=()=>{return function(U,_,M){let H=Reflect.getMetadata(P.websocket,U.constructor)??{};H.drain=M.value,Reflect.defineMetadata(P.websocket,H,U.constructor)}},l.onError=()=>{return function(U,_,M){let H=Reflect.getMetadata(P.websocket,U.constructor)??{};H.error=M.value,Reflect.defineMetadata(P.websocket,H,U.constructor)}}))(OX||={});IQ();export{P2 as t,JQ as WorkerPool,EQ as Worker,OX as Websocket,r as Wamp,OQ as TenantMiddleware,LX as Tenancy,NQ as StrictTenantMiddleware,SQ as SimpleTenantMiddleware,yQ as ServiceScope,B as Service,GX as RequestLoggerMiddleware,H0 as Repository,o as Redis,HX as Module,U0 as Model,ZQ as Middleware,sQ as Job,q as InteractsWithConsole,YX as HttpControllerScope,ZX as Http,N as Event,cQ as Env,h as Database,TQ as ConsoleLogger,VQ as ConsoleFormat,aQ as CommandArgumentType,eQ as Command,u as Cache,f as Application};
|
|
16
|
+
`}}else helpText+=`This command has no arguments.
|
|
17
|
+
`;return trim(helpText,`
|
|
18
|
+
`)}validateArgs(args){let missing=[],invalid=[],commandArgs=this.getArguments();if(Object.keys(args).includes("help"))return{valid:!0,missing:[]};for(let arg of commandArgs){if(arg.required&&(args[arg.name]===void 0||args[arg.name]===null)){missing.push(arg.name);continue}if(args[arg.name]===void 0)continue;if(arg.type==="enum"&&arg.enum&&!arg.enum.includes(args[arg.name]))invalid.push(`${arg.name} (must be one of: ${arg.enum.join(", ")})`);if(arg.type==="array"&&arg.arrayType==="enum"&&arg.enum){let invalidItems=args[arg.name].filter((item)=>!arg.enum.includes(item));if(invalidItems.length>0)invalid.push(`${arg.name} (contains invalid values: ${invalidItems.join(", ")}. Must be one of: ${arg.enum.join(", ")})`)}}if(invalid.length>0)console.error(`Invalid argument values: ${invalid.join(", ")}
|
|
19
|
+
`);return{valid:missing.length===0&&invalid.length===0,missing}}processArgs(argv){let processed={},commandArgs=this.getArguments();for(let i=0;i<argv.length;i++){let arg=argv[i];if(arg.startsWith("--")){let argName=arg.slice(2);if(i+1<argv.length&&!argv[i+1].startsWith("--"))processed[argName]=argv[i+1],i++;else processed[argName]=!0}}for(let arg of commandArgs){if(processed[arg.name]===void 0&&arg.default!==void 0){processed[arg.name]=arg.default;continue}if(processed[arg.name]===void 0)continue;if(typeof processed[arg.name]==="string")switch(arg.type||this.inferType(arg.default)){case"number":processed[arg.name]=Number(processed[arg.name]);break;case"boolean":let value=processed[arg.name].toLowerCase();processed[arg.name]=value==="true"||value==="1"||value==="yes";break;case"enum":if(arg.enum&&arg.enum.length>0&&typeof arg.enum[0]==="number")processed[arg.name]=Number(processed[arg.name]);break;case"array":let arrayValues=processed[arg.name].split(",").map((item)=>item.trim());if(arg.arrayType)processed[arg.name]=arrayValues.map((item)=>{switch(arg.arrayType){case"number":return Number(item);case"boolean":return item.toLowerCase()==="true"||item.toLowerCase()==="1"||item.toLowerCase()==="yes";case"enum":return item;default:return item}});else processed[arg.name]=arrayValues;break;case"string":default:break}}return processed}progress(total,title="Processing"){return new CommandProgressBar(total,title)}spinner(title="Processing",frames,frameDelay){return new CommandSpinner(title,frames,frameDelay)}inferType(defaultValue){if(defaultValue===void 0)return"string";switch(typeof defaultValue){case"number":return"number";case"boolean":return"boolean";default:return isArray(defaultValue)?"array":"string"}}}class CommandProgressBar extends InteractsWithConsole{#active=!1;#total=0;#current=0;#title="";#startTime=0;constructor(total=0,title="Processing"){super();this.#total=total,this.#title=title,this.#active=!0,this.#current=0,this.#startTime=Date.now(),this.update(0)}update(increment=1,newTitle){if(!this.#active)return;if(this.#current+=increment,newTitle)this.#title=newTitle;let percentage=Math.min(100,Math.floor(this.#current/this.#total*100)),elapsedSec=(Date.now()-this.#startTime)/1000,estimatedTotalSec=0,estimatedRemainingSec=0,timeInfo="";if(this.#current>0)estimatedTotalSec=elapsedSec/this.#current*this.#total,estimatedRemainingSec=Math.max(0,estimatedTotalSec-elapsedSec),timeInfo=` | ${this.formatTime(elapsedSec)} elapsed | ${this.formatTime(estimatedRemainingSec)} remaining`;let barWidth=30,completedWidth=Math.floor(percentage/100*barWidth),remainingWidth=barWidth-completedWidth,bar="["+"=".repeat(completedWidth)+(remainingWidth>0?">":"")+" ".repeat(Math.max(0,remainingWidth-(remainingWidth>0?1:0)))+"]",progressLine=`${this.#title}: ${bar} ${percentage}% (${this.#current}/${this.#total})${timeInfo}`;if(this.clearLine(),this.write(progressLine,!1),this.#current>=this.#total)this.complete()}complete(message){if(!this.#active)return;this.#current=this.#total;let elapsedSec=(Date.now()-this.#startTime)/1000;if(this.clearLine(),message)this.write(`${message} (completed in ${this.formatTime(elapsedSec)})`);else this.write(`${this.#title} completed in ${this.formatTime(elapsedSec)}`);this.#active=!1}pause(message){if(!this.#active)return;this.newLine(),this.write(message),this.update(0)}isActive(){return this.#active}getCurrent(){return this.#current}getTotal(){return this.#total}getPercentage(){return Math.min(100,Math.floor(this.#current/this.#total*100))}}class CommandSpinner extends InteractsWithConsole{#active=!1;#title="";#startTime=0;#intervalId=null;#currentFrame=0;#frames=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"];#frameDelay=80;constructor(title="Processing",frames,frameDelay){super();if(this.#title=title,frames)this.#frames=frames;if(frameDelay)this.#frameDelay=frameDelay;if(this.#active)return;this.#active=!0,this.#startTime=Date.now(),this.#currentFrame=0,this.#intervalId=setInterval(()=>{this.render()},this.#frameDelay),this.render()}update(newTitle){if(!this.#active)return;this.#title=newTitle}complete(message,success=!0){if(!this.#active)return;if(this.#intervalId)clearInterval(this.#intervalId),this.#intervalId=null;let elapsedSec=(Date.now()-this.#startTime)/1000;this.clearLine();let time=this.formatTime(elapsedSec);if(message)this[success?"success":"error"](`${message} (${time})`);else this[success?"success":"error"](`${this.#title} completed in ${time}`);this.#active=!1}fail(message){this.complete(message,!1)}pause(message){if(!this.#active)return;if(this.#intervalId)clearInterval(this.#intervalId),this.#intervalId=null;this.clearLine(),this.write(message),this.#intervalId=setInterval(()=>{this.render()},this.#frameDelay)}isActive(){return this.#active}getElapsedTime(){return(Date.now()-this.#startTime)/1000}render(){if(!this.#active)return;let elapsedSec=this.getElapsedTime(),frame=this.#frames[this.#currentFrame];this.#currentFrame=(this.#currentFrame+1)%this.#frames.length,this.clearLine(),this.write(`${frame} ${this.#title} (${this.formatTime(elapsedSec)})`,!1)}}var env=new Map,initEnv=(vars)=>{for(let[key,value]of Object.entries(vars))env.set(key,value)},Env;((Env)=>(Env.get=(name,defaultValue)=>env.get(name)??defaultValue,Env.exists=(name)=>env.has(name),Env.clear=()=>{env.clear()}))(Env||={});class ElysiumError extends Error{constructor(message){super(message);this.name=new.target.name}}class ModuleCycleError extends ElysiumError{path;constructor(path){super(`Module import cycle detected: ${path.join(" -> ")}`);this.path=path}}class InvalidModuleError extends ElysiumError{className;constructor(className){super(`${className} is not a valid module. Decorate it with @Module().`);this.className=className}}class DuplicateGlobalServiceError extends ElysiumError{serviceName;modules;constructor(serviceName,modules){super(`Global service "${serviceName}" is declared by both ${modules[0]} and ${modules[1]}.`);this.serviceName=serviceName;this.modules=modules}}class DuplicateCommandError extends ElysiumError{command;modules;constructor(command,modules){super(`Command "${command}" is registered by both ${modules[0]} and ${modules[1]}.`);this.command=command;this.modules=modules}}class ConflictingModuleConfigError extends ElysiumError{module;sites;constructor(module,sites){super(`Module ${module} is configured with conflicting options at ${sites[0]} and ${sites[1]}.`);this.module=module;this.sites=sites}}class MissingModuleConfigError extends ElysiumError{module;keys;constructor(module,keys){super(`Module ${module} is missing required configuration: ${keys.join(", ")}.`);this.module=module;this.keys=keys}}class InvalidModuleConfigError extends ElysiumError{module;key;reason;constructor(module,key,reason){super(`Module ${module} has an invalid "${key}" configuration: ${reason}.`);this.module=module;this.key=key;this.reason=reason}}class ServiceNotVisibleError extends ElysiumError{service;requester;module;owner;constructor(service,requester,module,owner){let where=module?` in module ${module}`:"",hint=owner?` Either import ${owner} or add it to ${owner}'s exports.`:"";super(`Service "${service}" requested by ${requester}${where} is not visible.${hint}`);this.service=service;this.requester=requester;this.module=module;this.owner=owner}}class ServiceNotFoundError extends ElysiumError{service;constructor(service){super(`Service "${service}" was not found.`);this.service=service}}class ServiceNotReadyError extends ElysiumError{service;owner;constructor(service,owner=null){let where=owner?` Its module ${owner} initialises asynchronously.`:"";super(`Service "${service}" is not ready yet.${where} Use "await Service.resolve()" to await it, or set "static boot = true" on the command to initialise every module before it runs.`);this.service=service;this.owner=owner}}class CircularDependencyError extends ElysiumError{path;constructor(path){super(`Circular service dependency detected: ${path.join(" -> ")}`);this.path=path}}class DuplicateModuleNameError extends ElysiumError{moduleName;constructor(moduleName){super(`Two different modules are both named "${moduleName}". Module names identify modules in configuration and errors, so they must be unique: rename one of them.`);this.moduleName=moduleName}}class EnvironmentSkippedModuleError extends ElysiumError{service;requester;skippedModule;environment;constructor(service,requester,skippedModule,environment){super(`Service "${service}" requested by ${requester} belongs to module ${skippedModule}, which is skipped in the "${environment}" environment.`);this.service=service;this.requester=requester;this.skippedModule=skippedModule;this.environment=environment}}class InvalidControllerError extends ElysiumError{className;moduleName;constructor(className,moduleName){super(`${className}, listed in the controllers of ${moduleName}, is not a controller. Decorate it with @Http.controller(), @Websocket.controller() or @Wamp.controller().`);this.className=className;this.moduleName=moduleName}}class EventListenerNotSupportedError extends ElysiumError{className;method;moduleName;constructor(className,method,moduleName){super(`${className}.${method} (module ${moduleName}) is an instance event listener, but ${className} is not listed in the services of ${moduleName}. Make the method static or register the class as a service.`);this.className=className;this.method=method;this.moduleName=moduleName}}import{EventEmitter}from"events";import{isString}from"radash";class EventBus extends EventEmitter{static instance=new EventBus;constructor(){super();this.on("error",(error)=>this.emitError(error))}emitError(error){this.emit("elysium:error",{data:error,source:null})}emitEvent(event,data,source=null){this.emit(event,{data,source})}}function getEventListeners(cls){return Metadata.getOwn(Symbols.eventListeners,cls)??[]}var recordListener=(target,method,mode,props)=>{let isStatic=typeof target==="function",owner=isStatic?target:target.constructor;Metadata.define(Symbols.eventListeners,[...getEventListeners(owner),{event:props.event,method,mode,prepend:props.prepend??!1,static:isStatic}],owner)},Event;((Event)=>{Event.emit=(event,data,source=null)=>{EventBus.instance.emitEvent(event,data,source)};function on(event,handler){if(isString(event))EventBus.instance.on(event,handler);else return function(target,propertyKey){recordListener(target,propertyKey,"on",event)}}Event.on=on;function once(event,handler){if(isString(event))EventBus.instance.once(event,handler);else return function(target,propertyKey){recordListener(target,propertyKey,"once",event)}}Event.once=once,Event.off=(event)=>{EventBus.instance.removeAllListeners(event)},Event.clear=()=>{EventBus.instance.removeAllListeners()},Event.listen=(options)=>{if(options.mode==="on")return on(options);else if(options.mode==="once")return once(options);return function(_target,_propertyKey,_descriptor){console.error("Unknown mode provided to @listen. Use either 'on' or 'once'.")}}})(Event||={});import{isEqual as isEqual2}from"radash";import{AsyncLocalStorage}from"async_hooks";var storage=new AsyncLocalStorage,ModuleContext;((ModuleContext)=>{function run(node,fn){return storage.run(node,fn)}ModuleContext.run=run;function current(){return storage.getStore()}ModuleContext.current=current})(ModuleContext||={});import{isString as isString2}from"radash";var ServiceScope;((ServiceScope)=>{ServiceScope[ServiceScope.SINGLETON=0]="SINGLETON";ServiceScope[ServiceScope.FACTORY=1]="FACTORY"})(ServiceScope||={});var isClass=(value)=>typeof value==="function"&&value.prototype&&value.prototype.constructor===value,nameOf=(service)=>isString2(service)?service:service.name,Service;((Service)=>{Service.register=(props)=>function(target){Metadata.define(Symbols.serviceOptions,props??{},target)},Service.inject=(service)=>function(target,propertyKey,parameterIndex){let services=Metadata.get(Symbols.services,target,propertyKey)??[],types=Metadata.get("design:paramtypes",target,propertyKey)??[],name=isString2(service)?service:service?.name??types[parameterIndex].name;services.push({name,index:parameterIndex}),Metadata.define(Symbols.services,services,target,propertyKey)},Service.get=(service)=>Container.get(nameOf(service)),Service.resolve=(service)=>Container.resolve(nameOf(service),"Service.resolve"),Service.registerLazy=(name,resolver)=>{addGlobal(name,0,resolver)},Service.make=(service)=>Container.make(service),Service.bind=(service,name)=>{let s=Service.make(service);return Service.instance(name??service.name,s)};function factory(serviceOrName,nameOrFactory){let serviceName=isString2(serviceOrName)?serviceOrName:nameOrFactory??serviceOrName.name,create=()=>isClass(serviceOrName)?Service.make(serviceOrName):nameOrFactory();return addGlobal(serviceName,1,create),create()}Service.factory=factory,Service.instance=(service,instance)=>(addGlobal(nameOf(service),0,()=>instance,{instance}),instance),Service.remove=(service)=>{Container.removeGlobal(nameOf(service))},Service.exists=(service)=>Container.hasGlobal(nameOf(service)),Service.isConstructed=(name)=>Container.constructed().some((entry)=>entry.name===name),Service.clear=()=>{Container.clearGlobal()},Service.keys=(pattern)=>{let regexPattern="^"+pattern.replace(/[-[\]{}()+.,\\^$|#\s]/g,"\\$&").replace(/\*/g,".*").replace(/\?/g,".")+"$",regex=new RegExp(regexPattern);return Container.globalNames().filter((key)=>regex.test(key))};let addGlobal=(name,scope,create,prebuilt)=>{Container.add({name,scope,global:!0,owner:null,create,initialised:prebuilt!==void 0,...prebuilt?{instance:prebuilt.instance}:{}})}})(Service||={});var GLOBAL_OWNER="<global>",globalScope=new Map,moduleScopes=new Map,building=[],constructedEntries=[],overridden=new Set,visibility=null,moduleInitHook=null,skippedLookup=null,isPromise=(value)=>typeof value==="object"&&value!==null&&typeof value.then==="function",ownerId=(owner)=>owner?.id??GLOBAL_OWNER,inOwnerContext=(owner,fn)=>owner?ModuleContext.run(owner,fn):fn(),runOnInit=(entry,instance)=>{let onInit=instance?.onInit;if(typeof onInit!=="function")return;let result=inOwnerContext(entry.owner,()=>onInit.call(instance));return isPromise(result)?result.then(()=>{return}):void 0},construct=(entry)=>{let at=building.indexOf(entry);if(at!==-1)throw new CircularDependencyError([...building.slice(at),entry].map((e)=>e.name));building.push(entry);try{return inOwnerContext(entry.owner,entry.create)}finally{building.pop()}},instantiate=(entry)=>{if(entry.scope===1){let instance=construct(entry);return{instance,ready:runOnInit(entry,instance)}}if(entry.initFailure)throw entry.initFailure.error;if("instance"in entry)return{instance:entry.instance,ready:entry.initialised?void 0:entry.initPromise};let instance=construct(entry);entry.instance=instance,constructedEntries.push({entry,instance});let ready;try{ready=runOnInit(entry,instance)}catch(error){throw entry.initFailure={error},error}if(ready)entry.initPromise=ready.then(()=>{entry.initialised=!0},(error)=>{throw entry.initFailure={error},error}),entry.initPromise.catch(()=>{});else entry.initialised=!0;return{instance,ready:entry.initPromise}},needsOwnerInit=(entry)=>entry.owner!==null&&(entry.scope===1||!("instance"in entry)),entryValue=(entry)=>{if(needsOwnerInit(entry)&&moduleInitHook){let pending=moduleInitHook(entry.owner);if(isPromise(pending))throw pending.catch(()=>{}),new ServiceNotReadyError(entry.name,entry.owner?.id??null)}let{instance,ready}=instantiate(entry);if(ready)throw new ServiceNotReadyError(entry.name,entry.owner?.id??null);return instance},prepare=async(entry,path)=>{let at=path.indexOf(entry);if(at!==-1)throw new CircularDependencyError([...path.slice(at),entry].map((e)=>e.name));let trail=[...path,entry];if(needsOwnerInit(entry)&&moduleInitHook)await moduleInitHook(entry.owner);if(!entry.cls||"instance"in entry&&entry.scope!==1)return;let dependencies=Metadata.get(Symbols.services,entry.cls)??[],found=inOwnerContext(entry.owner,()=>dependencies.map((dependency)=>Container.lookup(dependency.name,ModuleContext.current())));for(let dependency of found){if(!dependency)continue;if(dependency.entry.scope===1)await prepare(dependency.entry,trail);else await entryValueAsync(dependency.entry,trail)}},entryValueAsync=async(entry,path=[])=>{await prepare(entry,path);let{instance,ready}=instantiate(entry);return await ready,instance},Container;((Container)=>{function register(owner,def,config){let isClass=typeof def==="function",options=isClass?Metadata.get(Symbols.serviceOptions,def)??{}:def,name=options.name??(isClass?def.name:"");if(overridden.has(name))return name;return add({name,scope:options.scope??0,global:options.global??owner===null,owner,cls:isClass?def:void 0,create:isClass?()=>make(def):()=>def.factory(config,(service)=>require2(service,def.name)),initialised:!1}),name}Container.register=register;function add(entry){if(entry.global||!entry.owner){let existing=globalScope.get(entry.name);if(existing)throw new DuplicateGlobalServiceError(entry.name,[ownerId(existing.owner),ownerId(entry.owner)]);globalScope.set(entry.name,entry);return}let scope=moduleScopes.get(entry.owner);if(!scope)scope=new Map,moduleScopes.set(entry.owner,scope);if(scope.has(entry.name))throw new ElysiumError(`Service "${entry.name}" is declared twice in module ${entry.owner.id}.`);scope.set(entry.name,entry)}Container.add=add;function setOverrides(names){overridden=new Set(names??[])}Container.setOverrides=setOverrides;function setVisibility(resolver){visibility=resolver}Container.setVisibility=setVisibility;function setModuleInitHook(hook){moduleInitHook=hook}Container.setModuleInitHook=setModuleInitHook;function setSkippedLookup(lookup){skippedLookup=lookup}Container.setSkippedLookup=setSkippedLookup;function lookup(name,from){let found=(entry)=>entry?{entry,owner:entry.owner}:null;if(from){let own=moduleScopes.get(from)?.get(name);if(own)return found(own);for(let imported of visibility?.visibleOwners(from)??[]){let exported=visibility.exportsOf(imported);if(exported===!0||exported.includes(name)){let entry=moduleScopes.get(imported)?.get(name);if(entry)return found(entry)}}}return found(globalScope.get(name))}Container.lookup=lookup;function get(name){let found=lookup(name,ModuleContext.current());return found?entryValue(found.entry):null}Container.get=get;async function resolve(name,requester){let found=lookup(name,ModuleContext.current());if(!found)throw notFound(name,requester);return entryValueAsync(found.entry)}Container.resolve=resolve;function make(cls){let dependencies=Metadata.get(Symbols.services,cls)??[],params=[];for(let dependency of dependencies)params[dependency.index]=require2(dependency.name,cls.name);return new cls(...params)}Container.make=make;function require2(service,requester){let name=typeof service==="string"?service:service.name,found=lookup(name,ModuleContext.current());if(!found)throw notFound(name,requester);return entryValue(found.entry)}function notFound(name,requester){let skipped=skippedLookup?.(name);if(skipped)return new EnvironmentSkippedModuleError(name,requester,skipped.module,skipped.environment);let hidden=[...moduleScopes.values()].map((scope)=>scope.get(name)).find((entry)=>entry!==void 0);return hidden?new ServiceNotVisibleError(name,requester,ModuleContext.current()?.id??null,hidden.owner?.id??null):new ServiceNotFoundError(name)}Container.hasGlobal=(name)=>globalScope.has(name),Container.globalNames=()=>[...globalScope.keys()],Container.removeGlobal=(name)=>{globalScope.delete(name)},Container.clearGlobal=()=>{globalScope.clear()},Container.constructed=()=>constructedEntries.filter(({entry})=>!entry.initFailure).map(({entry,instance})=>({name:entry.name,instance,owner:entry.owner}));function reset(){globalScope.clear(),moduleScopes.clear(),constructedEntries.length=0}Container.reset=reset})(Container||={});var serviceName=(cls)=>Metadata.get(Symbols.serviceOptions,cls)?.name??cls.name,handlerFor=(node,cls,meta)=>{let method=meta.method;return async(data)=>{try{await ModuleContext.run(node,async()=>{if(meta.static)return cls[method](data);return(await Container.resolve(serviceName(cls),cls.name))[method](data)})}catch(e){EventBus.instance.emitError(e)}}};function wireEventListeners(node,owned,services){let plan=[...new Set(owned)].flatMap((cls)=>getEventListeners(cls).map((meta)=>{if(!meta.static&&!services.has(cls))throw new EventListenerNotSupportedError(cls.name,String(meta.method),node.id);return{meta,wrapper:handlerFor(node,cls,meta)}})),bus=EventBus.instance;return plan.map(({meta,wrapper})=>{if(meta.mode==="once")meta.prepend?bus.prependOnceListener(meta.event,wrapper):bus.once(meta.event,wrapper);else meta.prepend?bus.prependListener(meta.event,wrapper):bus.on(meta.event,wrapper);return{event:meta.event,wrapper}})}function isConfiguredModule(value){return typeof value==="object"&&value!==null&&value[Symbols.configuredModule]===!0}function getModuleProps(cls){let props=Metadata.get(Symbols.module,cls);if(props===void 0)throw new InvalidModuleError(cls.name);return props}class Module{static register(props={}){return function(target){Metadata.define(Symbols.module,props,target)}}static configurable(options={}){class ConfigurableModule extends Module{static get config(){return`elysium.module.${this.name}.config`}static with(config){return{[Symbols.configuredModule]:!0,module:this,config}}static resolveConfig(input={}){let resolved=deepMerge({...input},{...options.defaults??{}}),missing=(options.required??[]).filter((key)=>resolved[key]===void 0);if(missing.length>0)throw new MissingModuleConfigError(this.name,missing.map(String));return resolved}get config(){return Metadata.get(Symbols.moduleConfig,this)}}return ConfigurableModule}onInit(){}onDestroy(){}onServe(_app){}}import{isEqual}from"radash";var APP_SITE="<app>",unwrap=(entry)=>isConfiguredModule(entry)?entry.module:entry,isActive=(props,environment)=>props.env===void 0||props.env.includes(environment);function discover(roots,environment){let records=new Map,skipped=[],done=new Set,stack=[],visit=(cls)=>{if(done.has(cls))return;let at=stack.indexOf(cls);if(at!==-1)throw new ModuleCycleError([...stack.slice(at),cls].map((c)=>c.name));let props=getModuleProps(cls);if(!isActive(props,environment)){if(!skipped.includes(cls))skipped.push(cls);return}stack.push(cls);let record={cls,props,imports:[],configs:[]};for(let entry of props.imports??[]){let target=unwrap(entry);if(visit(target),!records.has(target)&&!done.has(target))continue;if(!record.imports.includes(target))record.imports.push(target);if(isConfiguredModule(entry))record.configs.push({target,config:entry.config})}stack.pop(),done.add(cls),records.set(cls,record)};for(let root of roots)visit(unwrap(root));return{records,skipped}}function computeDepths(roots,records){let depths=new Map,frontier=roots.filter((r)=>records.has(r));frontier.forEach((r)=>depths.set(r,1));for(let depth=1;frontier.length>0;depth++){let next=[];for(let cls of frontier)for(let imported of records.get(cls).imports)if(!depths.has(imported))depths.set(imported,depth+1),next.push(imported);frontier=next}return depths}function commandsOf(props,environment){return(props.commands??[]).filter((c)=>!(environment==="production"&&c.dev===!0))}function assertUniqueNames(classes){let seen=new Map;for(let cls of classes){let other=seen.get(cls.name);if(other!==void 0&&other!==cls)throw new DuplicateModuleNameError(cls.name);seen.set(cls.name,cls)}}function assertUniqueCommands(nodes,environment){let seen=new Map;for(let node of nodes)for(let command of commandsOf(node.props,environment)){let name=getCommandName(command),owner=seen.get(name);if(owner!==void 0&&owner!==node.id)throw new DuplicateCommandError(name,[owner,node.id]);seen.set(name,node.id)}}var isModuleClass=(value)=>typeof value==="function"&&Metadata.get(Symbols.module,value)!==void 0,serviceName2=(cls)=>Metadata.get(Symbols.serviceOptions,cls)?.name??cls.name;function buildModuleGraph(rootModules,environment=currentEnvironment()){let{records,skipped}=discover(rootModules,environment);assertUniqueNames([...records.keys()]);let rootClasses=rootModules.map(unwrap),depths=computeDepths(rootClasses,records),sources=new Map,addSource=(target,source)=>sources.set(target,[...sources.get(target)??[],source]);for(let root of rootModules){let target=unwrap(root);if(isConfiguredModule(root)&&records.has(target))addSource(target,{site:APP_SITE,depth:1,config:root.config})}for(let record of records.values())for(let{target,config}of record.configs)addSource(target,{site:record.cls.name,depth:depths.get(record.cls)+1,config});let byClass=new Map;for(let record of records.values())byClass.set(record.cls,{id:record.cls.name,moduleClass:record.cls,props:record.props,imports:record.imports.map((i)=>byClass.get(i)),depth:depths.get(record.cls),configSources:sources.get(record.cls)??[]});let nodes=[...byClass.values()];return assertUniqueCommands(nodes,environment),{nodes,skipped,environment,node:(cls)=>byClass.get(cls),visibleOwners:(node)=>{let result=[],add=(owner)=>{if(owner===void 0||result.includes(owner))return;result.push(owner);let exported=owner.props.exports;if(Array.isArray(exported)){for(let entry of exported)if(isModuleClass(entry))add(byClass.get(entry))}};return node.imports.forEach(add),result},exportsOf:(node)=>{let exported=node.props.exports;if(exported===!0)return!0;return(exported??[]).filter((e)=>!isModuleClass(e)).map((e)=>typeof e==="string"?e:serviceName2(e))},collect:(key)=>nodes.flatMap((module)=>(key==="commands"?commandsOf(module.props,environment):module.props[key]??[]).map((item)=>({item,module})))}}function selectConfig(node){if(node.configSources.length===0)return;let best=Math.min(...node.configSources.map((s)=>s.depth)),tied=node.configSources.filter((s)=>s.depth===best),objects=tied.filter((s)=>typeof s.config!=="function");for(let other of objects.slice(1))if(!isEqual(objects[0].config,other.config))throw new ConflictingModuleConfigError(node.id,[objects[0].site,other.site]);return tied[0]}var KERNEL_SERVICE="elysium.kernel",isConfigurable=(cls)=>typeof cls.resolveConfig==="function",evaluate=(config)=>typeof config==="function"?config():config,scopeOf=(def)=>(typeof def==="function"?Metadata.get(Symbols.serviceOptions,def)?.scope:def.scope)??0,nameOf2=(def)=>typeof def==="function"?Metadata.get(Symbols.serviceOptions,def)?.name??def.name:def.name;class Kernel{moduleGraph;instances=new Map;registered=new Map;initialised=new Set;initialising=new Set;initOrder=[];inFlight=new Map;failures=new Map;ownClasses=new Map;wired=[];shutdownPromise;constructor(moduleGraph){this.moduleGraph=moduleGraph}get graph(){return this.moduleGraph}async register(){let{graph}=this;Service.instance(KERNEL_SERVICE,this),Container.setVisibility(graph),Container.setModuleInitHook((node)=>this.initialised.has(node)||this.initialising.has(node)||this.initSync(node)?void 0:this.initModule(node)),Container.setSkippedLookup(this.buildSkippedLookup());for(let node of graph.nodes){let config=await this.resolveNodeConfig(node),instance=ModuleContext.run(node,()=>Service.make(node.moduleClass));Metadata.define(Symbols.moduleConfig,config,instance),this.instances.set(node,instance);let registered=[];if(isConfigurable(node.moduleClass))Container.register(node,{name:node.moduleClass.config,factory:()=>config},config);let{services}=node.props,defs=typeof services==="function"?services(config):services??[],serviceClasses=defs.filter((d)=>typeof d==="function");this.ownClasses.set(node,{owned:[...serviceClasses,...node.props.controllers??[]],services:new Set(serviceClasses)});for(let def of defs)registered.push({name:Container.register(node,def,config),scope:scopeOf(def)});this.registered.set(node,registered)}}initModule(node){if(this.initialised.has(node))return Promise.resolve();let failure=this.failures.get(node);if(failure)return Promise.reject(failure.error);let pending=this.inFlight.get(node);if(!pending)pending=this.runInit(node),pending.catch(()=>{}),this.inFlight.set(node,pending);return pending}async bootEager(){for(let node of this.graph.nodes)await this.initModule(node);for(let node of this.graph.nodes)for(let{name,scope}of this.registered.get(node)??[]){if(scope===1)continue;await ModuleContext.run(node,()=>Service.resolve(name))}}async prepare(cls,owner){await this.initModule(owner);let dependencies=Metadata.get(Symbols.services,cls)??[];for(let{name}of dependencies)await ModuleContext.run(owner,()=>Container.resolve(name,cls.name));return ModuleContext.run(owner,()=>Service.make(cls))}moduleInstance(node){let instance=this.instances.get(node);if(!instance)throw new ElysiumError(`Module ${node.id} has not been registered.`);return instance}shutdown(){return this.shutdownPromise??=this.runShutdown(),this.shutdownPromise}async runInit(node){for(let imported of node.imports)await this.initModule(imported);await this.initOwn(node)}initOwn(node){let instance=this.moduleInstance(node),own=this.ownClasses.get(node);if(own)this.wired.push(...wireEventListeners(node,own.owned,own.services));this.initialising.add(node);let result;try{result=ModuleContext.run(node,()=>instance.onInit())}catch(error){throw this.initialising.delete(node),error}let done=()=>{this.initialising.delete(node),this.initialised.add(node),this.initOrder.push(node)};if(typeof result?.then==="function")return Promise.resolve(result).then(done,(error)=>{throw this.initialising.delete(node),error});done();return}initSync(node){if(this.initialised.has(node)||this.initialising.has(node))return!0;let failure=this.failures.get(node);if(failure)throw failure.error;if(this.inFlight.has(node))return!1;for(let imported of node.imports)if(!this.initSync(imported))return!1;let pending;try{pending=this.initOwn(node)}catch(error){throw this.failures.set(node,{error}),error}if(!pending)return!0;return pending.catch(()=>{}),this.inFlight.set(node,pending),!1}async runShutdown(){for(let{event,wrapper}of this.wired.splice(0))EventBus.instance.removeListener(event,wrapper);let targets=[...Container.constructed().map(({name,instance,owner})=>({label:`service ${name}`,instance,owner})).reverse(),...[...this.initOrder].reverse().map((node)=>({label:`module ${node.id}`,instance:this.instances.get(node),owner:node}))];for(let{label,instance,owner}of targets){let onDestroy=instance?.onDestroy;if(typeof onDestroy!=="function")continue;try{let call=()=>onDestroy.call(instance);await(owner?ModuleContext.run(owner,call):call())}catch(error){console.error(`Error while destroying ${label}:`,error)}}}async resolveNodeConfig(node){let selected=selectConfig(node),input;if(selected){input=await evaluate(selected.config);let tied=node.configSources.filter((s)=>s.depth===selected.depth);if(tied.length>1&&tied.some((s)=>typeof s.config==="function")){for(let other of tied.filter((s)=>s!==selected))if(!isEqual2(input,await evaluate(other.config)))throw new ConflictingModuleConfigError(node.id,[selected.site,other.site])}}return isConfigurable(node.moduleClass)?node.moduleClass.resolveConfig(input):void 0}buildSkippedLookup(){let owners=new Map;for(let cls of this.graph.skipped){let{services}=getModuleProps(cls);if(!Array.isArray(services))continue;for(let def of services)owners.set(nameOf2(def),cls.name)}let{environment}=this.graph;return(name)=>{let module=owners.get(name);return module===void 0?null:{module,environment}}}}var executeMiddlewareChain=(middlewares,context,method,node=null)=>{let chain=async()=>{for(let middleware of middlewares){let result=await middleware[method](context);if(result!==void 0)return result}};return Application.context.run(new Map([["tenant",context.tenant],["http:context",context]]),()=>node?ModuleContext.run(node,chain):chain())},makeMiddlewares=(middlewares,node)=>middlewares.map((middleware)=>node?ModuleContext.run(node,()=>Service.make(middleware)):Service.make(middleware)),applyMiddlewares=(middlewares,plugin,node)=>{let mi=makeMiddlewares(middlewares,node);plugin.onRequest((c)=>executeMiddlewareChain(mi,c,"onRequest",node)),plugin.onTransform((c)=>executeMiddlewareChain(mi,c,"onTransform",node)),plugin.onBeforeHandle((c)=>executeMiddlewareChain(mi,c,"onBeforeHandle",node)),plugin.onAfterHandle((c)=>executeMiddlewareChain(mi,c,"onAfterHandle",node)),plugin.onAfterResponse((c)=>executeMiddlewareChain(mi,c,"onAfterResponse",node))};class Middleware{static register(...middlewares){return function(target,propertyKey,descriptor){if(propertyKey===void 0&&descriptor===void 0){let m=Metadata.get(Symbols.middlewares,target)??[];m.push(...middlewares),Metadata.define(Symbols.middlewares,m,target)}else{let m=Metadata.get(Symbols.middlewares,target,propertyKey)??[];m.push(...middlewares),Metadata.define(Symbols.middlewares,m,target,propertyKey)}}}static guards(guards){class GuardedMiddleware extends this{}return Metadata.define(Symbols.middlewareGuards,guards,GuardedMiddleware),GuardedMiddleware}get logger(){return Service.get("logger").child({middleware:this.constructor.name})}get guards(){return Metadata.get(Symbols.middlewareGuards,this.constructor)??[]}onRequest(_ctx){}onTransform(_ctx){}onAfterHandle(_ctx){}onBeforeHandle(_ctx){}onAfterResponse(_ctx){}}var resetContainer=()=>{Container.reset(),Container.setOverrides(null),Container.setVisibility(null),Container.setModuleInitHook(null),Container.setSkippedLookup(null)};async function createTestingApp(options){let{modules,overrides={},environment="test",boot="lazy"}=options;resetContainer();try{let graph=buildModuleGraph(modules,environment),kernel=new Kernel(graph);Container.setOverrides(Object.keys(overrides));for(let[name,value]of Object.entries(overrides))Service.instance(name,value);if(await kernel.register(),boot==="eager")await kernel.bootEager();return{kernel,get:async(name,from)=>{let resolve=()=>Service.resolve(name);if(!from)return resolve();let node=graph.node(from);if(!node)throw new ElysiumError(`Module ${from.name} is not part of the test graph.`);return ModuleContext.run(node,resolve)},shutdown:async()=>{await kernel.shutdown(),resetContainer()}}}catch(error){throw resetContainer(),error}}var fallbackContext=new AsyncLocalStorage2;class Application extends InteractsWithConsole{#elysia;#debug;#kernel;#onSignal;_appContextStorage=new AsyncLocalStorage2;static get instance(){return Service.get("elysium.app")}static get context(){return Application.instance?._appContextStorage??fallbackContext}static register(props={}){return function(target){let parentMetadata,proto=Object.getPrototypeOf(target);while(proto&&proto!==Object.prototype){if(parentMetadata=Metadata.getOwn(Symbols.app,proto),parentMetadata)break;proto=Object.getPrototypeOf(proto)}let ownMetadata=Metadata.getOwn(Symbols.app,target),modules=[...parentMetadata?.modules??[],...ownMetadata?.modules??[],...props.modules??[]],withoutModules=({modules:_modules,...rest})=>rest;props={...deepMerge(withoutModules(props),withoutModules(ownMetadata??{}),withoutModules(parentMetadata??{}),{openapi:!1}),modules},Metadata.define(Symbols.app,props,target)}}constructor(){super();let{env,debug}=Metadata.get(Symbols.app,this.constructor)??{};if(this.#debug=debug??!1,env){let rawEnv=Value.Convert(env,Value.Clone(Bun.env));if(this.#debug&&!Value.Check(env,rawEnv)){let error=Value.Errors(env,rawEnv).First();this.trace(error,"Invalid environment configuration")}initEnv(Value.Clean(env,rawEnv))}else initEnv(Bun.env);Service.remove("elysium.app"),Service.instance("elysium.app",this)}static start(){return new this().run()}static testing(options){return createTestingApp(options)}get kernel(){if(!this.#kernel)throw new ElysiumError("The application has not been started yet.");return this.#kernel}get elysia(){return this.#elysia}get isDebug(){return this.#debug}set isDebug(debug){this.#debug=debug}async onError(_error){return!0}async onStart(_elysia){}async onStop(_elysia){}async run(argv=process.argv.slice(2)){this.installSignalHandlers();try{let{modules}=this.props();return this.#kernel=new Kernel(buildModuleGraph(modules??[])),await this.dispatch(argv)}catch(error){return this.fail(error)}}props(){return Metadata.get(Symbols.app,this.constructor)??{}}async dispatch([action,...rest]){switch(action){case void 0:return this.commandDescribe(),this.exit(0);case"serve":return this.commandServe();case"list":return this.write(this.bold("Available commands:")),this.commandList(),this.exit(0);case"help":return this.commandHelp(rest[0]);default:return this.commandExec(action,rest)}}async fail(error){let message=error instanceof Error?error.message:String(error);if(this.error(message),!(error instanceof ElysiumError)&&this.isDebug)this.trace(error);return Event.emit("elysium:error",error),await this.#kernel?.shutdown(),this.exit(1)}exit(code){return this.removeSignalHandlers(),process.exit(code)}removeSignalHandlers(){if(!this.#onSignal)return;process.off("SIGINT",this.#onSignal),process.off("SIGTERM",this.#onSignal),this.#onSignal=void 0}installSignalHandlers(){this.removeSignalHandlers();let onSignal=async()=>{this.removeSignalHandlers();let code=0;try{await this.#elysia?.stop()}catch(error){code=1,this.error(error instanceof Error?error.message:String(error))}finally{try{await this.#kernel?.shutdown()}catch(error){code=1,this.error(error instanceof Error?error.message:String(error))}this.exit(code)}};this.#onSignal=onSignal,process.on("SIGINT",onSignal),process.on("SIGTERM",onSignal)}getCommands(){return this.kernel.graph.collect("commands")}findCommand(name){return this.getCommands().find(({item})=>getCommandName(item)===name)}async prepareCommand({item,module},forHelp=!1){let eager=item.boot&&!forHelp;if(await this.bootKernel(eager),!eager)return this.kernel.prepare(item,module);return ModuleContext.run(module,()=>Service.make(item))}async bootKernel(eager){if(await this.kernel.register(),eager)await this.kernel.bootEager();Event.emit("elysium:app:launched",this,this)}async commandHelp(name){let found=name?this.findCommand(name):void 0;if(!found)return this.error(name?`Command <${name}> not found.`:"No command provided. Usage: styx help <command>"),this.commandList(),this.exit(1);let command=await this.prepareCommand(found,!0);return this.write(await ModuleContext.run(found.module,()=>command.help())),await this.kernel.shutdown(),this.exit(0)}async commandExec(name,argv){let found=this.findCommand(name);if(!found)return this.error(`Command ${name} not found`),this.commandList(),this.exit(1);let command=await this.prepareCommand(found);return await ModuleContext.run(found.module,async()=>{if(await command.init(...argv))await command.run();else this.write(await command.help())}),await this.kernel.shutdown(),this.exit(0)}async commandServe(){let{server,openapi,plugins}=this.props();if(await this.bootKernel(!0),this.#elysia=new Elysia(server).onRequest((c)=>{if(this.isDebug)console.log(c.request.method,c.request.url)}),Event.emit("elysium:server:before-init",this,this),this.#elysia.resolve({as:"global"},({request})=>({tenant:request.headers.get("x-tenant-id")??"public"})),openapi)this.#elysia.use(openapiPlugin(openapi));for(let plugin of plugins??[])this.#elysia.use(await plugin(this));this.setupServerHooks();let middlewares=Metadata.get(Symbols.middlewares,this.constructor)??[];applyMiddlewares(middlewares,this.#elysia,null),await this.serveModules(),Event.emit("elysium:server:after-init",this,this),this.#elysia.listen(server?.port??(parseInt(process.env.PORT,10)||3000))}async serveModules(){let{nodes}=this.kernel.graph;for(let node of nodes){let instance=this.kernel.moduleInstance(node);await ModuleContext.run(node,()=>instance.onServe(this.#elysia))}for(let node of nodes)if(node.props.controllers?.length)this.debug(`Mounting module ${node.id}...`),this.#elysia.use(await this.mountModule(node))}async mountModule(node){let app=new Elysia({name:node.id,prefix:node.props.prefix}),middlewares=Metadata.get(Symbols.middlewares,node.moduleClass)??[];applyMiddlewares(middlewares,app,node);for(let controller of node.props.controllers??[]){let plugin=Metadata.get(Symbols.elysiaPlugin,controller);if(!plugin)throw new InvalidControllerError(controller.name,node.id);app.use(await plugin(node))}return app}setupServerHooks(){this.#elysia.onError({as:"global"},(e)=>this.handleServerError(e)).onStart(async(elysia)=>{await this.onStart(elysia),Event.emit("elysium:server:start",elysia,this)}).onStop(async(elysia)=>{await this.onStop(elysia),Event.emit("elysium:server:stop",elysia,this),this.removeSignalHandlers(),await this.#kernel?.shutdown(),this._appContextStorage.disable()})}async handleServerError(e){if(!await this.onError(e))return;if(Event.emit("elysium:error",e),this.trace({name:"HttpError",message:"Unexpected error while handling HTTP request",stack:e.error.stack,...e.error}),typeof e.code==="number")return e.error.response;let data={};switch(e.code){case"VALIDATION":data={scope:e.error.type,code:e.error.message};break;case"INTERNAL_SERVER_ERROR":data={message:e.error.message};break}return{type:e.code,data}}commandDescribe(){this.section(`${this.bold("Usage:")} ${this.format("styx",5)} <command> [options]`),this.section(this.bold("Core Commands:")),this.newLine(),this.commandDescription("serve","","Starts the server."),this.commandDescription("help","<command>","Displays help for a command."),this.commandDescription("list","","List all available application commands."),this.section(this.bold("Application Commands:")),this.commandList()}commandList(){let groups=this.getCommands().reduce((acc,{item})=>{let groupKey=first(getCommandName(item).split(":"));return acc.set(groupKey,[...acc.get(groupKey)??[],item]),acc},new Map);for(let[group,groupCommands]of groups){this.section(this.format(group,4));for(let commandClass of groupCommands)this.commandDescription(getCommandName(commandClass),"",commandClass.description)}}commandDescription(command,args,description,width=InteractsWithConsole.SPACE_WIDTH){args=args.length===0?" ":` ${args} `,this.write(` ${this.format(command,6)}${args}${"\u2219".repeat(width-command.length-args.length)} ${description}`)}}class ConsoleLogger{context;constructor(context={}){this.context=context}trace(msg,ctx){console.debug(`[TRACE] ${msg}`,{...this.context,...ctx})}debug(msg,ctx){console.debug(`[DEBUG] ${msg}`,{...this.context,...ctx})}info(msg,ctx){console.info(`[INFO] ${msg}`,{...this.context,...ctx})}warn(msg,ctx){console.warn(`[WARN] ${msg}`,{...this.context,...ctx})}error(msg,ctx){console.error(`[ERROR] ${msg}`,{...this.context,...ctx})}fatal(msg,ctx){console.error(`[FATAL] ${msg}`,{...this.context,...ctx})}child(ctx){return new ConsoleLogger({...this.context,...ctx})}}import{Elysia as Elysia2,sse as esse,t}from"elysia";import{assign,isEmpty as isEmpty2,objectify}from"radash";async function*iterateInModule(node,generator){let finished=!1;try{while(!0){let step=await ModuleContext.run(node,()=>generator.next());if(step.done){finished=!0;return}yield step.value}}catch(error){throw finished=!0,error}finally{if(!finished)await ModuleContext.run(node,()=>generator.return(void 0))}}var registerHttpRequestHandler=(props)=>{let body=Metadata.get("http:body",props.target,props.propertyKey),params=Metadata.get("http:params",props.target,props.propertyKey)??[],query=Metadata.get("http:query",props.target,props.propertyKey),rawContext=Metadata.get("http:rawContext",props.target,props.propertyKey),customDecorators=Metadata.get("http:customDecorators",props.target,props.propertyKey)??[],middlewares=Metadata.get(Symbols.middlewares,props.target,props.propertyKey)??[],services=Metadata.get(Symbols.services,props.target,props.propertyKey)??[],{path,method,handler,target,response,operationId,description,transactional}=props,metadata=Metadata.get(Symbols.http,target.constructor)??[];metadata.push({path,method,body,params,query,customDecorators,rawContext,handler,middlewares,response,operationId,description,services,transactional}),Metadata.define(Symbols.http,metadata,target.constructor)},HttpControllerScope;((HttpControllerScope)=>{HttpControllerScope[HttpControllerScope.SERVER=0]="SERVER";HttpControllerScope[HttpControllerScope.REQUEST=1]="REQUEST"})(HttpControllerScope||={});var Http;((Http)=>(Http.controller=(props={path:"/"})=>function(target){async function handleHttp(node){await nextTick(),props=assign({path:"/",scope:0,tags:[]},props);let app=new Elysia2({prefix:props.path,name:`${node.id}:${target.name}`}),getController=(()=>{if(props.scope===0){let controller=ModuleContext.run(node,()=>Service.make(target));return()=>()=>controller}else if(props.scope===1)return()=>()=>ModuleContext.run(node,()=>Service.make(target));else throw Error(`Invalid scope for controller: ${target.name}`)})();app.resolve({as:"local"},()=>({controller:getController()}));let onRequest=Metadata.get("http:onRequest",target)??{};if(onRequest.handler)app.onRequest((c)=>{let controller=getController()();return ModuleContext.run(node,()=>onRequest.handler.call(controller,c))});let middlewares=Metadata.get(Symbols.middlewares,target)??[];applyMiddlewares(middlewares,app,node);let metadata=Metadata.get(Symbols.http,target)??[];for(let route of metadata){let getParameters=async(c)=>{let parameters=[];if(route.rawContext)parameters[route.rawContext.index]=c;if(route.body)parameters[route.body.index]=c.body;if(route.query)parameters[route.query.index]=c.query;if(!isEmpty2(route.params))for(let param of route.params)parameters[param.index]=c.params[param.slug];if(!isEmpty2(route.customDecorators))for(let customDecorator of route.customDecorators)parameters[customDecorator.index]=await ModuleContext.run(node,()=>customDecorator.handler(c));if(!isEmpty2(route.services))for(let service of route.services)parameters[service.index]=ModuleContext.run(node,()=>Service.get(service.name));return parameters},isGenerator=route.handler.constructor.name.includes("GeneratorFunction"),isSSE=route.method==="elysium:SSE",isTransactional=route.transactional??props.transactional??!1,isValidator=route.body&&route.body.schema===void 0&&route.body.validator!==void 0;route.method=isSSE?"GET":route.method;let getHandler=()=>{let initTransactedHandler=(c)=>{if(isTransactional)return function(...args){return Service.get("db.connection.default").transaction((tx)=>Application.context.run(new Map([["tenant",c.tenant],["http:context",c],["db:tx",tx]]),()=>ModuleContext.run(node,()=>{try{return route.handler.call(c.controller(),...args)}catch(e){throw tx.rollback(),e}})))};return function(...args){return Application.context.run(new Map([["tenant",c.tenant],["http:context",c]]),()=>ModuleContext.run(node,()=>route.handler.call(c.controller(),...args)))}};if(isGenerator)return async function*(c){let handler=initTransactedHandler(c),params=await getParameters(c);try{yield*iterateInModule(node,handler(...params))}catch(error){yield error}};if(isSSE)return async function*(c){let handler=initTransactedHandler(c);c.set.headers["content-type"]="text/event-stream",c.set.headers["cache-control"]="no-cache",c.set.headers.connection="keep-alive";while(!0)yield esse(await handler(...await getParameters(c))),await Bun.sleep(10)};if(isValidator)return async function(c){if(await ModuleContext.run(node,()=>route.body.validator.validate(c)))return await initTransactedHandler(c)(...await getParameters(c));throw c.status(400,"Invalid request body")};return async function(c){return await initTransactedHandler(c)(...await getParameters(c))}},params=objectify(route.params??[],(p)=>p.slug,(p)=>p.schema),mi=makeMiddlewares(route.middlewares,node);app.route(route.method,route.path,getHandler(),{config:{},async transform(c){if(isValidator&&!await ModuleContext.run(node,()=>route.body.validator.authorize(c)))throw c.status(401,"Unauthorized");return executeMiddlewareChain(mi,c,"onTransform",node)},beforeHandle(c){return executeMiddlewareChain(mi,c,"onBeforeHandle",node)},afterHandle(c){return executeMiddlewareChain(mi,c,"onAfterHandle",node)},afterResponse(c){return executeMiddlewareChain(mi,c,"onAfterResponse",node)},detail:{tags:props.tags,description:route.description,operationId:route.operationId},body:isValidator?route.body?.validator?.schema:route.body?.schema,response:route.response,params:isEmpty2(params)?void 0:t.Object(params)})}return app}Metadata.define(Symbols.elysiaPlugin,handleHttp,target)},Http.sse=(props={})=>{let{path="/",...rest}=props;return Http.custom({method:"elysium:SSE",path,...rest})},Http.get=(props={})=>{let{path="/",...rest}=props;return Http.custom({method:"GET",path,...rest})},Http.post=(props={})=>{let{path="/",...rest}=props;return Http.custom({method:"POST",path,...rest})},Http.put=(props={})=>{let{path="/",...rest}=props;return Http.custom({method:"PUT",path,...rest})},Http.del=(props={})=>{let{path="/",...rest}=props;return Http.custom({method:"DELETE",path,...rest})},Http.patch=(props={})=>{let{path="/",...rest}=props;return Http.custom({method:"PATCH",path,...rest})},Http.head=(props={})=>{let{path="/",...rest}=props??{};return Http.custom({method:"HEAD",path,...rest})},Http.options=(props={})=>{let{path="/",...rest}=props;return Http.custom({method:"OPTIONS",path,...rest})},Http.trace=(props={})=>{let{path="/",...rest}=props;return Http.custom({method:"TRACE",path,...rest})},Http.custom=({path="/",...rest})=>function(target,propertyKey,descriptor){process.nextTick(()=>{registerHttpRequestHandler({path,handler:descriptor.value,target,propertyKey,...rest})})},Http.onRequest=()=>function(target,_,descriptor){let metadata=Metadata.get("http:onRequest",target.constructor)??{};metadata.handler=descriptor.value,Metadata.define("http:onRequest",metadata,target.constructor)},Http.context=()=>function(target,propertyKey,parameterIndex){Metadata.define("http:rawContext",{index:parameterIndex},target,propertyKey)},Http.param=(slug,schema)=>function(target,propertyKey,parameterIndex){let params=Metadata.get("http:params",target,propertyKey)??[];params.push({slug,schema:schema??t.String(),index:parameterIndex}),Metadata.define("http:params",params,target,propertyKey)},Http.query=(schema)=>function(target,propertyKey,parameterIndex){Metadata.define("http:query",{schema,index:parameterIndex},target,propertyKey)},Http.body=(schema)=>function(target,propertyKey,parameterIndex){if(typeof schema==="function")Metadata.define("http:body",{validator:schema,index:parameterIndex},target,propertyKey);else Metadata.define("http:body",{schema,index:parameterIndex},target,propertyKey)},Http.decorate=(handler)=>()=>function(target,propertyKey,parameterIndex){let decorators=Metadata.get("http:customDecorators",target,propertyKey)??[];decorators.push({handler,index:parameterIndex}),Metadata.define("http:customDecorators",decorators,target,propertyKey)}))(Http||={});class RequestLoggerMiddleware extends Middleware{async onRequest(ctx){ctx.__requestStartTime=Date.now(),this.logger.info("Incoming request",{method:ctx.request.method,path:new URL(ctx.request.url).pathname})}async onAfterResponse(ctx){let duration=Date.now()-(ctx.__requestStartTime??0);this.logger.info("Request completed",{method:ctx.request.method,path:new URL(ctx.request.url).pathname,duration:`${duration}ms`})}}var DEFAULT="default";function needsDefaultAlias(module,config){if(!Object.hasOwn(config.connections,config.default))throw new InvalidModuleConfigError(module,"default",`"${config.default}" is not one of the declared connections`);if(config.default===DEFAULT)return!1;if(Object.hasOwn(config.connections,DEFAULT))throw new InvalidModuleConfigError(module,"connections",`a connection named "default" conflicts with the default alias to "${config.default}"`);return!0}async function runAll(tasks){let errors=(await Promise.allSettled(tasks.map(async(task)=>task()))).flatMap((r)=>r.status==="rejected"?[r.reason]:[]);if(errors.length===1)throw errors[0];if(errors.length>1)throw AggregateError(errors,"Several connections failed to close.")}import{omit as omit2}from"radash";var Redis;((Redis)=>(Redis.getConnectionName=(name)=>`redis.connection.${name}`,Redis.getConnection=(name="default")=>{let client=Service.get(Redis.getConnectionName(name));if(client===null)throw new ServiceNotFoundError(Redis.getConnectionName(name));return client},Redis.connectionExists=(name)=>Service.exists(Redis.getConnectionName(name)),Redis.getDefaultConnection=()=>Redis.getConnection("default")))(Redis||={});class RedisModule extends Module.configurable({defaults:{default:"default"},required:["connections"]}){async onDestroy(){let names=Object.keys(this.config.connections).map(Redis.getConnectionName),clients=Container.constructed().filter(({name})=>names.includes(name));await runAll(clients.map(({instance})=>()=>instance.close()))}}RedisModule=__legacyDecorateClassTS([Module.register({services:(config)=>{let alias=needsDefaultAlias("RedisModule",config);return[...Object.entries(config.connections).map(([name,props])=>({name:Redis.getConnectionName(name),global:!0,factory:()=>new Bun.RedisClient(props.url,omit2(props,["url"]))})),...alias?[{name:Redis.getConnectionName("default"),global:!0,factory:(_config,get)=>get(Redis.getConnectionName(config.default))}]:[]]}})],RedisModule);import{Elysia as Elysia3}from"elysia";import{omit as omit3}from"radash";import Wampy from"wampy";class WampWebsocket extends WebSocket{protocols;constructor(url,protocols){super(url,protocols);this.protocols=protocols}get protocol(){return this.protocols?.[0]??"wamp.2.json"}}var Wamp;((Wamp2)=>(Wamp2.getConnectionName=(name)=>`wamp.connection.${name}`,Wamp2.getConnection=(name="default")=>{let client=Service.get(Wamp2.getConnectionName(name));if(client===null)throw new ServiceNotFoundError(Wamp2.getConnectionName(name));return client},Wamp2.connectionExists=(name)=>Service.exists(Wamp2.getConnectionName(name)),Wamp2.getDefaultConnection=()=>Wamp2.getConnection("default"),Wamp2.createClient=(name,config)=>{let client=new Wampy(config.url,{ws:WampWebsocket,...omit3(config,["url","onOpen"]),onError(error){config.onError?.(error),Event.emit("elysium:error",Error(`An error occurred in WAMP connection ${name}`))}}),maxRetries=config.maxRetries??5,retryInterval=config.retryInterval??5000,retryCount=0,closed=!1,timer,disconnect=client.disconnect.bind(client);client.disconnect=()=>(closed=!0,clearTimeout(timer),disconnect());let tryConnect=async()=>{if(closed)return;try{await client.connect()}catch(e){if(console.error(`Failed to connect to WAMP server (attempt ${retryCount+1}/${maxRetries}):`,e),retryCount<maxRetries)retryCount++,timer=setTimeout(tryConnect,retryInterval);else console.error(`Max retry attempts (${maxRetries}) reached. Giving up.`),Event.emit("elysium:error",Error(`Failed to establish WAMP connection ${name} after ${maxRetries} attempts`));return}if(closed)return;try{await config.onOpen?.()}catch(error){Event.emit("elysium:error",error)}};return tryConnect(),client},Wamp2.controller=(options)=>function(target){async function handleWamp(node){await nextTick();let controller=ModuleContext.run(node,()=>Service.make(target)),inModule=(handler)=>(...args)=>ModuleContext.run(node,()=>handler.apply(controller,args)),metadata=Metadata.get(Symbols.wamp,target)??{},w=Wamp.getConnection(options.connection??"default"),app=new Elysia3({name:`${node.id}:${target.name}`});return app.onStart(async(_)=>{let registrations=metadata.registrations??[],subscriptions=metadata.subscriptions??[];for(let registration of registrations)w.register(registration.topic,inModule(registration.handler),registration.options).then((r)=>{console.log(`Registered ${registration.topic} with id ${r.registrationId}`)});for(let subscription of subscriptions)w.subscribe(subscription.topic,inModule(subscription.handler),subscription.options).then((s)=>{console.log(`Subscribed ${subscription.topic} with id ${s.subscriptionId}`)})}),app}Metadata.define(Symbols.elysiaPlugin,handleWamp,target)},Wamp2.register=(topic,options)=>function(target,_propertyKey,descriptor){let metadata=Metadata.get(Symbols.wamp,target.constructor)??{};metadata.registrations??=[],metadata.registrations.push({topic,options,handler:descriptor.value}),Metadata.define(Symbols.wamp,metadata,target.constructor)},Wamp2.subscribe=(topic,options)=>function(target,_propertyKey,descriptor){let metadata=Metadata.get(Symbols.wamp,target.constructor)??{};metadata.subscriptions??=[],metadata.subscriptions.push({topic,options,handler:descriptor.value}),Metadata.define(Symbols.wamp,metadata,target.constructor)}))(Wamp||={});class WampModule extends Module.configurable({defaults:{default:"default"},required:["connections"]}){async onDestroy(){let names=Object.keys(this.config.connections).map(Wamp.getConnectionName),clients=Container.constructed().filter(({name})=>names.includes(name));await runAll(clients.map(({instance})=>()=>instance.disconnect()))}}WampModule=__legacyDecorateClassTS([Module.register({services:(config)=>{let alias=needsDefaultAlias("WampModule",config);return[...Object.entries(config.connections).map(([name,props])=>({name:Wamp.getConnectionName(name),global:!0,factory:()=>Wamp.createClient(name,props)})),...alias?[{name:Wamp.getConnectionName("default"),global:!0,factory:(_config,get)=>get(Wamp.getConnectionName(config.default))}]:[]]}})],WampModule);import{Elysia as Elysia4}from"elysia";var Websocket;((Websocket)=>(Websocket.controller=(props)=>function(target){async function handleWebsocket(node){await nextTick();let controller=ModuleContext.run(node,()=>Service.make(target)),metadata=Metadata.get(Symbols.websocket,target)??{},inModule=(handler)=>(...args)=>ModuleContext.run(node,()=>handler?.apply(controller,args)),open=metadata.open&&inModule(metadata.open),close=metadata.close&&inModule(metadata.close),message=metadata.message&&inModule(metadata.message),drain=metadata.drain&&inModule(metadata.drain),error=metadata.error?inModule(metadata.error):(e)=>Event.emit("elysium:error",e.error),app=new Elysia4({name:`${node.id}:${target.name}`});return app.ws(props.path,{open,close,message,drain,error,body:metadata.body,...props.options}),app}Metadata.define(Symbols.elysiaPlugin,handleWebsocket,target)},Websocket.onOpen=()=>function(target,_,descriptor){let metadata=Metadata.get(Symbols.websocket,target.constructor)??{};metadata.open=descriptor.value,Metadata.define(Symbols.websocket,metadata,target.constructor)},Websocket.onClose=()=>function(target,_,descriptor){let metadata=Metadata.get(Symbols.websocket,target.constructor)??{};metadata.close=descriptor.value,Metadata.define(Symbols.websocket,metadata,target.constructor)},Websocket.onMessage=(schema)=>function(target,_,descriptor){let metadata=Metadata.get(Symbols.websocket,target.constructor)??{};metadata.message=descriptor.value,metadata.body=schema,Metadata.define(Symbols.websocket,metadata,target.constructor)},Websocket.onDrain=()=>function(target,_,descriptor){let metadata=Metadata.get(Symbols.websocket,target.constructor)??{};metadata.drain=descriptor.value,Metadata.define(Symbols.websocket,metadata,target.constructor)},Websocket.onError=()=>function(target,_,descriptor){let metadata=Metadata.get(Symbols.websocket,target.constructor)??{};metadata.error=descriptor.value,Metadata.define(Symbols.websocket,metadata,target.constructor)}))(Websocket||={});export{Application,CircularDependencyError,Command,CommandArgumentType,ConflictingModuleConfigError,ConsoleFormat,ConsoleLogger,DuplicateCommandError,DuplicateGlobalServiceError,DuplicateModuleNameError,ElysiumError,Env,EnvironmentSkippedModuleError,Event,EventListenerNotSupportedError,Http,HttpControllerScope,InteractsWithConsole,InvalidModuleConfigError,InvalidModuleError,KERNEL_SERVICE,Kernel,Metadata,Middleware,MissingModuleConfigError,Module,ModuleContext,ModuleCycleError,Redis,RedisModule,RequestLoggerMiddleware,Service,ServiceNotFoundError,ServiceNotReadyError,ServiceNotVisibleError,ServiceScope,Wamp,WampModule,Websocket,needsDefaultAlias,runAll,t2 as t};
|
package/dist/kernel.d.ts
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { Class } from 'type-fest';
|
|
2
|
+
import type { Module } from './module';
|
|
3
|
+
import type { ModuleGraph, ModuleNode } from './module-graph';
|
|
4
|
+
/** The global service name under which the kernel registers itself. */
|
|
5
|
+
export declare const KERNEL_SERVICE = "elysium.kernel";
|
|
6
|
+
/**
|
|
7
|
+
* Turns a module graph into a running container: registers configs and services,
|
|
8
|
+
* initialises modules (eagerly or on demand) and shuts everything down in order.
|
|
9
|
+
*
|
|
10
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
11
|
+
*/
|
|
12
|
+
export declare class Kernel {
|
|
13
|
+
private readonly moduleGraph;
|
|
14
|
+
private readonly instances;
|
|
15
|
+
private readonly registered;
|
|
16
|
+
private readonly initialised;
|
|
17
|
+
private readonly initialising;
|
|
18
|
+
private readonly initOrder;
|
|
19
|
+
private readonly inFlight;
|
|
20
|
+
private readonly failures;
|
|
21
|
+
private readonly ownClasses;
|
|
22
|
+
private readonly wired;
|
|
23
|
+
private shutdownPromise;
|
|
24
|
+
constructor(moduleGraph: ModuleGraph);
|
|
25
|
+
/** The module graph this kernel runs. */
|
|
26
|
+
get graph(): ModuleGraph;
|
|
27
|
+
/**
|
|
28
|
+
* Phase 2: resolves each module's config, instantiates the module and registers its services.
|
|
29
|
+
* @throws {ConflictingModuleConfigError | MissingModuleConfigError}
|
|
30
|
+
*/
|
|
31
|
+
register(): Promise<void>;
|
|
32
|
+
/**
|
|
33
|
+
* Initialises a module, after its imports. Idempotent: concurrent callers share one run,
|
|
34
|
+
* and a failure is remembered and rethrown.
|
|
35
|
+
*/
|
|
36
|
+
initModule(node: ModuleNode): Promise<void>;
|
|
37
|
+
/** Initialises every module in graph order, then constructs every non-factory service. */
|
|
38
|
+
bootEager(): Promise<void>;
|
|
39
|
+
/**
|
|
40
|
+
* Lazily builds a class owned by `owner`, such as a command: initialises the owner,
|
|
41
|
+
* awaits its injected dependencies, then constructs it in the owner's context.
|
|
42
|
+
*/
|
|
43
|
+
prepare<T>(cls: Class<T>, owner: ModuleNode): Promise<T>;
|
|
44
|
+
/** The instance of a registered module. */
|
|
45
|
+
moduleInstance(node: ModuleNode): Module;
|
|
46
|
+
/**
|
|
47
|
+
* Destroys constructed services in reverse construction order, then initialised
|
|
48
|
+
* modules in reverse init order. Errors are logged, not thrown. Idempotent.
|
|
49
|
+
*/
|
|
50
|
+
shutdown(): Promise<void>;
|
|
51
|
+
private runInit;
|
|
52
|
+
/**
|
|
53
|
+
* Wires the listeners and runs the `onInit` of a module whose imports are initialised.
|
|
54
|
+
* The module is recorded as initialised at once when `onInit` is synchronous.
|
|
55
|
+
* @returns A promise when `onInit` is asynchronous.
|
|
56
|
+
*/
|
|
57
|
+
private initOwn;
|
|
58
|
+
/**
|
|
59
|
+
* Initialises a module synchronously when that is possible: every import is (or can be
|
|
60
|
+
* made) initialised the same way and `onInit` returns no promise.
|
|
61
|
+
* @returns Whether the module is initialised. When `false`, its initialisation is
|
|
62
|
+
* asynchronous and has been started or is in flight.
|
|
63
|
+
* @throws The error of a failing synchronous `onInit`, which is remembered.
|
|
64
|
+
*/
|
|
65
|
+
private initSync;
|
|
66
|
+
private runShutdown;
|
|
67
|
+
/** Evaluates the config that applies to `node`, checking function-form ties. */
|
|
68
|
+
private resolveNodeConfig;
|
|
69
|
+
/** Maps class and factory service names of skipped modules to the module that declares them. */
|
|
70
|
+
private buildSkippedLookup;
|
|
71
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
type MetadataKey = string | symbol;
|
|
2
|
+
type PropertyKey = string | symbol | undefined;
|
|
3
|
+
/**
|
|
4
|
+
* Stores decorator metadata on classes and their members.
|
|
5
|
+
*
|
|
6
|
+
* Reads walk the prototype chain, so a subclass sees the metadata of its parents. When another
|
|
7
|
+
* library has loaded `reflect-metadata`, values stored there are read as well.
|
|
8
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
9
|
+
*/
|
|
10
|
+
export declare namespace Metadata {
|
|
11
|
+
/**
|
|
12
|
+
* Sets a metadata value on a class, or on one of its members.
|
|
13
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
14
|
+
* @param key The metadata key.
|
|
15
|
+
* @param value The value to store.
|
|
16
|
+
* @param target The class, or the prototype holding the member.
|
|
17
|
+
* @param propertyKey The member name, when the metadata belongs to a member.
|
|
18
|
+
*/
|
|
19
|
+
const define: (key: MetadataKey, value: unknown, target: object, propertyKey?: PropertyKey) => void;
|
|
20
|
+
/**
|
|
21
|
+
* Gets a metadata value set on the target itself, ignoring its parents.
|
|
22
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
23
|
+
* @param key The metadata key.
|
|
24
|
+
* @param target The class, or the prototype holding the member.
|
|
25
|
+
* @param propertyKey The member name, when the metadata belongs to a member.
|
|
26
|
+
*/
|
|
27
|
+
const getOwn: <T = any>(key: MetadataKey, target: object, propertyKey?: PropertyKey) => NoInfer<T> | undefined;
|
|
28
|
+
/**
|
|
29
|
+
* Gets a metadata value from the target or its nearest parent that has one.
|
|
30
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
31
|
+
* @param key The metadata key.
|
|
32
|
+
* @param target The class, or the prototype holding the member.
|
|
33
|
+
* @param propertyKey The member name, when the metadata belongs to a member.
|
|
34
|
+
*/
|
|
35
|
+
const get: <T = any>(key: MetadataKey, target: object, propertyKey?: PropertyKey) => NoInfer<T> | undefined;
|
|
36
|
+
/**
|
|
37
|
+
* Checks whether the target or one of its parents has the key, even when its value is
|
|
38
|
+
* `undefined`.
|
|
39
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
40
|
+
* @param key The metadata key.
|
|
41
|
+
* @param target The class, or the prototype holding the member.
|
|
42
|
+
* @param propertyKey The member name, when the metadata belongs to a member.
|
|
43
|
+
*/
|
|
44
|
+
const has: (key: MetadataKey, target: object, propertyKey?: PropertyKey) => boolean;
|
|
45
|
+
}
|
|
46
|
+
export {};
|
package/dist/middleware.d.ts
CHANGED
|
@@ -2,21 +2,31 @@ import type { AnyElysia } from 'elysia';
|
|
|
2
2
|
import type { Class } from 'type-fest';
|
|
3
3
|
import type { Context } from './http';
|
|
4
4
|
import type { LoggerInterface } from './logger';
|
|
5
|
+
import type { ModuleNode } from './module-graph';
|
|
5
6
|
/**
|
|
6
7
|
* Execute a chain of middlewares, stopping on the first return or throw.
|
|
7
8
|
* @author Axel Nana <axel.nana@workbud.com>
|
|
8
9
|
* @param middlewares The list of middleware instances to execute.
|
|
9
10
|
* @param context The context to pass to each middleware.
|
|
10
11
|
* @param method The method to call on each middleware.
|
|
12
|
+
* @param node The module the middlewares belong to. The chain runs in its context.
|
|
11
13
|
*/
|
|
12
|
-
export declare const executeMiddlewareChain: (middlewares: Middleware[], context: any, method: Exclude<keyof Middleware,
|
|
14
|
+
export declare const executeMiddlewareChain: (middlewares: Middleware[], context: any, method: Exclude<keyof Middleware, 'guards'>, node?: ModuleNode | null) => Promise<any>;
|
|
15
|
+
/**
|
|
16
|
+
* Builds middleware instances in the context of a module.
|
|
17
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
18
|
+
* @param middlewares The middleware classes.
|
|
19
|
+
* @param node The owning module, or `null` to build them with global visibility only.
|
|
20
|
+
*/
|
|
21
|
+
export declare const makeMiddlewares: (middlewares: Class<Middleware>[], node: ModuleNode | null) => Middleware[];
|
|
13
22
|
/**
|
|
14
23
|
* Apply a list of middlewares to an Elysia plugin.
|
|
15
24
|
* @author Axel Nana <axel.nana@workbud.com>
|
|
16
25
|
* @param middlewares The list of middlewares to apply.
|
|
17
26
|
* @param plugin The Elysia plugin instance.
|
|
27
|
+
* @param node The module the middlewares belong to, or `null` for application-level middlewares.
|
|
18
28
|
*/
|
|
19
|
-
export declare const applyMiddlewares: (middlewares: Class<Middleware>[], plugin: AnyElysia) => void;
|
|
29
|
+
export declare const applyMiddlewares: (middlewares: Class<Middleware>[], plugin: AnyElysia, node: ModuleNode | null) => void;
|
|
20
30
|
/**
|
|
21
31
|
* Base class for middleware.
|
|
22
32
|
* @author Axel Nana <axel.nana@workbud.com>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ModuleNode } from './module-graph';
|
|
2
|
+
/**
|
|
3
|
+
* Tracks which module is currently being booted or is serving a request,
|
|
4
|
+
* so that service lookups can enforce module visibility.
|
|
5
|
+
*
|
|
6
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
7
|
+
*/
|
|
8
|
+
export declare namespace ModuleContext {
|
|
9
|
+
/**
|
|
10
|
+
* Runs `fn` with `node` as the current module. The context follows async continuations.
|
|
11
|
+
* @param node The module to make current.
|
|
12
|
+
* @param fn The function to run.
|
|
13
|
+
* @returns The value returned by `fn`.
|
|
14
|
+
*/
|
|
15
|
+
function run<T>(node: ModuleNode, fn: () => T): T;
|
|
16
|
+
/**
|
|
17
|
+
* Gets the module current in this async context, if any.
|
|
18
|
+
*/
|
|
19
|
+
function current(): ModuleNode | undefined;
|
|
20
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { Class } from 'type-fest';
|
|
2
|
+
import type { ConfiguredModule, ModuleClass, ModuleProps } from './module';
|
|
3
|
+
/**
|
|
4
|
+
* A configuration given to a module from one import site.
|
|
5
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
6
|
+
*/
|
|
7
|
+
export type ConfigSource = {
|
|
8
|
+
readonly site: string;
|
|
9
|
+
readonly depth: number;
|
|
10
|
+
readonly config: ConfiguredModule<unknown>['config'];
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* A module in the graph.
|
|
14
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
15
|
+
*/
|
|
16
|
+
export type ModuleNode = {
|
|
17
|
+
readonly id: string;
|
|
18
|
+
readonly moduleClass: ModuleClass;
|
|
19
|
+
readonly props: ModuleProps;
|
|
20
|
+
readonly imports: readonly ModuleNode[];
|
|
21
|
+
readonly depth: number;
|
|
22
|
+
readonly configSources: readonly ConfigSource[];
|
|
23
|
+
};
|
|
24
|
+
type Collectable = 'controllers' | 'commands' | 'jobs';
|
|
25
|
+
/**
|
|
26
|
+
* The resolved module graph.
|
|
27
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
28
|
+
*/
|
|
29
|
+
export type ModuleGraph = {
|
|
30
|
+
/** Active modules, imports first. */
|
|
31
|
+
readonly nodes: readonly ModuleNode[];
|
|
32
|
+
/** Modules excluded by their `env`. */
|
|
33
|
+
readonly skipped: readonly ModuleClass[];
|
|
34
|
+
/** The environment the graph was built for. */
|
|
35
|
+
readonly environment: string;
|
|
36
|
+
node(cls: ModuleClass): ModuleNode | undefined;
|
|
37
|
+
/** The direct imports of `node`, plus the modules they re-export. */
|
|
38
|
+
visibleOwners(node: ModuleNode): readonly ModuleNode[];
|
|
39
|
+
/** The service names `node` exports, or `true` when it exports everything. */
|
|
40
|
+
exportsOf(node: ModuleNode): readonly string[] | true;
|
|
41
|
+
/** Gathers controllers, commands or jobs across modules, with their owner. */
|
|
42
|
+
collect<K extends Collectable>(key: K): readonly {
|
|
43
|
+
item: Class<any>;
|
|
44
|
+
module: ModuleNode;
|
|
45
|
+
}[];
|
|
46
|
+
};
|
|
47
|
+
type Entry = ModuleClass | ConfiguredModule<any>;
|
|
48
|
+
/**
|
|
49
|
+
* Builds the module graph from decorator metadata. Pure: constructs nothing.
|
|
50
|
+
*
|
|
51
|
+
* @param rootModules The modules declared by the application.
|
|
52
|
+
* @param environment The active environment.
|
|
53
|
+
* @throws {ModuleCycleError} On an import cycle.
|
|
54
|
+
* @throws {DuplicateModuleNameError} When two different module classes share a name.
|
|
55
|
+
* @throws {DuplicateCommandError} When two modules register the same command.
|
|
56
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
57
|
+
*/
|
|
58
|
+
export declare function buildModuleGraph(rootModules: Entry[], environment?: string): ModuleGraph;
|
|
59
|
+
/**
|
|
60
|
+
* Picks the configuration that applies to a module: the one from the lowest depth.
|
|
61
|
+
* Equal object-form configs at the same depth are accepted; different ones conflict.
|
|
62
|
+
* Function-form configs are not compared here.
|
|
63
|
+
*
|
|
64
|
+
* @throws {ConflictingModuleConfigError} When two different object configs tie.
|
|
65
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
66
|
+
*/
|
|
67
|
+
export declare function selectConfig(node: ModuleNode): ConfigSource | undefined;
|
|
68
|
+
export {};
|