@virid/express 0.2.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1,14 +1,8 @@
1
1
  /**
2
- * @virid/express v0.2.2
2
+ * @virid/express v0.3.0
3
3
  * Add express functionality to virid
4
4
  */
5
- var P=Object.defineProperty;var Oe=Object.getOwnPropertyDescriptor;var Ce=Object.getOwnPropertyNames;var Pe=Object.prototype.hasOwnProperty;var Te=(t,e,s)=>e in t?P(t,e,{enumerable:!0,configurable:!0,writable:!0,value:s}):t[e]=s;var o=(t,e)=>P(t,"name",{value:e,configurable:!0});var ve=(t,e)=>{for(var s in e)P(t,s,{get:e[s],enumerable:!0})},He=(t,e,s,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of Ce(e))!Pe.call(t,n)&&n!==s&&P(t,n,{get:()=>e[n],enumerable:!(r=Oe(e,n))||r.enumerable});return t};var Ie=t=>He(P({},"__esModule",{value:!0}),t);var p=(t,e,s)=>Te(t,typeof e!="symbol"?e+"":e,s);var ot={};ve(ot,{BadRequest:()=>be,BadRequestResponse:()=>V,Body:()=>ze,ConflictResponse:()=>X,Cookies:()=>Le,Created:()=>$e,CreatedResponse:()=>q,Ctx:()=>Ze,CustomResponse:()=>Qe,CustomResponseResponse:()=>Q,ExpressPlugin:()=>st,Forbidden:()=>De,ForbiddenResponse:()=>N,Headers:()=>Ke,HttpContext:()=>T,HttpError:()=>w,HttpRequestMessage:()=>H,HttpResponse:()=>u,HttpRoute:()=>Fe,HttpSystem:()=>Xe,InternalServerError:()=>U,InternalServerErrorResponse:()=>B,NoContent:()=>Ve,NoContentResponse:()=>$,NotFound:()=>Be,NotFoundResponse:()=>D,Ok:()=>qe,OkResponse:()=>I,Params:()=>et,ParseBoolPipe:()=>xe,ParseIntPipe:()=>he,Query:()=>ke,Req:()=>Ge,Res:()=>Je,Stream:()=>Ye,StreamFile:()=>Ue,StreamFileResponse:()=>R,StreamResponse:()=>y,Unauthorized:()=>Ne,UnauthorizedResponse:()=>b,UnprocessableEntityResponse:()=>z,addAutoPipe:()=>We,getAutoPipe:()=>Y,parseRawCookie:()=>pe});module.exports=Ie(ot);var ge=require("@virid/core");var W=require("@virid/core");var S=require("@virid/core");var fe=require("@virid/core");var K=class K{constructor(e,s,r,n,d){p(this,"id");p(this,"req");p(this,"res");p(this,"timestamp");p(this,"route");p(this,"rc",0);p(this,"isClosed",!1);this.id=e,this.req=s,this.res=r,this.timestamp=n,this.route=d}inc(){this.rc++}dec(){this.rc--,this.rc===0&&this.tryFinalize()}tryFinalize(){if(this.res.writableEnded||this.isClosed)return;this.isClosed=!0;let e=`[Virid Express] Request Orphaned: The connection was closed because all systems finished execution without sending a response.
5
+ var T=Object.defineProperty;var ge=Object.getOwnPropertyDescriptor;var Ee=Object.getOwnPropertyNames;var Re=Object.prototype.hasOwnProperty;var Se=(r,e,t)=>e in r?T(r,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):r[e]=t;var o=(r,e)=>T(r,"name",{value:e,configurable:!0});var ye=(r,e)=>{for(var t in e)T(r,t,{get:e[t],enumerable:!0})},Ce=(r,e,t,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of Ee(e))!Re.call(r,i)&&i!==t&&T(r,i,{get:()=>e[i],enumerable:!(s=ge(e,i))||s.enumerable});return r};var Oe=r=>Ce(T({},"__esModule",{value:!0}),r);var l=(r,e,t)=>Se(r,typeof e!="symbol"?e+"":e,t);var Ge={};ye(Ge,{BadRequest:()=>Ie,BadRequestResponse:()=>b,Body:()=>je,ConflictResponse:()=>Y,Cookies:()=>Xe,Created:()=>Te,CreatedResponse:()=>q,Ctx:()=>ze,CustomResponse:()=>Ve,CustomResponseResponse:()=>U,ExpressPlugin:()=>ce,Forbidden:()=>$e,ForbiddenResponse:()=>D,Headers:()=>Ye,HttpContext:()=>S,HttpError:()=>w,HttpRequestMessage:()=>O,HttpResponse:()=>p,HttpRoute:()=>Ue,HttpSystem:()=>Qe,InternalServerError:()=>B,InternalServerErrorResponse:()=>P,NoContent:()=>Pe,NoContentResponse:()=>V,NotFound:()=>qe,NotFoundResponse:()=>N,Ok:()=>Ae,OkResponse:()=>$,Params:()=>We,ParseBoolPipe:()=>xe,ParseIntPipe:()=>me,Query:()=>Fe,Req:()=>Le,Res:()=>Ke,Stream:()=>ve,StreamFile:()=>be,StreamFileResponse:()=>y,StreamResponse:()=>C,Unauthorized:()=>He,UnauthorizedResponse:()=>v,UnprocessableEntityResponse:()=>X,addAutoPipe:()=>De,getAutoPipe:()=>Ne,getHttpArgs:()=>de,parseRawCookie:()=>ae});module.exports=Oe(Ge);var m=require("@virid/core");var he=require("@virid/core");var L=class L{constructor(e,t,s,i,a){l(this,"id");l(this,"req");l(this,"res");l(this,"timestamp");l(this,"route");l(this,"rc",0);l(this,"isClosed",!1);this.id=e,this.req=t,this.res=s,this.timestamp=i,this.route=a}inc(){this.rc++}dec(){this.rc--,this.rc===0&&this.tryFinalize()}tryFinalize(){if(this.res.writableEnded||this.isClosed)return;this.isClosed=!0;let e=`[Virid Express] Request Orphaned: The connection was closed because all systems finished execution without sending a response.
6
6
  Route: ${this.route}
7
- Uptime: ${Date.now()-this.timestamp}ms`;fe.MessageWriter.error(new Error(e)),this.res.headersSent?this.res.end():this.res.status(500).json({error:"Internal Logic Error",message:"Request processed but no response was returned by any system."})}};o(K,"HttpContext");var T=K,L=class L{constructor(e,s=null,r={}){p(this,"status");p(this,"data");p(this,"headers");this.status=e,this.data=s,this.headers=r}};o(L,"HttpResponse");var u=L,G=class G extends u{constructor(e,s={}){super(200,e,s)}};o(G,"OkResponse");var I=G,J=class J extends u{constructor(e,s={}){super(201,e,s)}};o(J,"CreatedResponse");var q=J,Z=class Z extends u{constructor(){super(204,null)}};o(Z,"NoContentResponse");var $=Z,k=class k extends u{constructor(e="Bad Request"){super(400,{error:e})}};o(k,"BadRequestResponse");var V=k,ee=class ee extends u{constructor(e="Unauthorized"){super(401,{error:e})}};o(ee,"UnauthorizedResponse");var b=ee,te=class te extends u{constructor(e="Forbidden"){super(403,{error:e})}};o(te,"ForbiddenResponse");var N=te,re=class re extends u{constructor(e="Not Found"){super(404,{error:e})}};o(re,"NotFoundResponse");var D=re,se=class se extends u{constructor(e="Conflict"){super(409,{error:e})}};o(se,"ConflictResponse");var X=se,oe=class oe extends u{constructor(e){super(422,{errors:e})}};o(oe,"UnprocessableEntityResponse");var z=oe,ne=class ne extends u{constructor(e="Internal Server Error"){super(500,{error:e})}};o(ne,"InternalServerErrorResponse");var B=ne,ae=class ae extends u{constructor(e,s,r={}){super(e,s,r)}};o(ae,"CustomResponseResponse");var Q=ae,ie=class ie extends u{constructor(s,r={dotfiles:"allow"}){super(206,r);p(this,"filePath");p(this,"options");this.filePath=s,this.options=r}};o(ie,"StreamFileResponse");var R=ie,de=class de extends u{constructor(s,r={}){super(r.status||206,{},r.headers);p(this,"stream");p(this,"options");this.stream=s,this.options=r}};o(de,"StreamResponse");var y=de,qe=o((t,e={})=>new I(t,e),"Ok"),$e=o((t,e={})=>new q(t,e),"Created"),Ve=o(()=>new $,"NoContent"),be=o((t="Bad Request")=>new V(t),"BadRequest"),Ne=o((t="Unauthorized")=>new b(t),"Unauthorized"),De=o((t="Forbidden")=>new N(t),"Forbidden"),Be=o((t="Not Found")=>new D(t),"NotFound"),U=o((t="Internal Server Error")=>new B(t),"InternalServerError"),Qe=o((t,e,s={})=>new Q(t,e,s),"CustomResponse"),Ue=o((t,e)=>new R(t,e),"StreamFile"),Ye=o((t,e)=>new y(t,e),"Stream"),ce=class ce extends Error{constructor(s,r){super(r);p(this,"status");p(this,"message");this.status=s,this.message=r}};o(ce,"HttpError");var w=ce;var m=new Map;function A(t,e){if(!t){e.dec();return}(Array.isArray(t)?t:[t]).forEach(r=>{r instanceof u?je(r,e):r instanceof w?(e.res.status(r.status).json(r.message),m.delete(e.id)):r instanceof S.BaseMessage?S.MessageWriter.write(r):S.MessageWriter.warn(`[Virid Express] Invalid Return Type: ${typeof r}. Expected HttpResponse or Message.`)}),e.dec()}o(A,"handleResult");function je(t,e){let{res:s}=e;if(t.headers&&Object.entries(t.headers).forEach(([r,n])=>s.setHeader(r,n)),t.status&&s.status(t.status),t instanceof R){e.inc(),s.sendFile(t.filePath,t.options,r=>{s.headersSent||S.MessageWriter.error(r,`[Virid Express] SteamFile Error: Path: ${t.filePath}`),e.res.end(),m.delete(e.id),e.isClosed=!0,e.dec()});return}if(t instanceof y){let{stream:r}=t;e.inc(),r.pipe(s);let n=o(()=>{m.has(e.id)&&(e.res.end(),m.delete(e.id),e.isClosed=!0,e.dec())},"cleanup");r.on("end",n),r.on("error",d=>{s.headersSent||S.MessageWriter.error(d,"[Virid Express] Stream Error"),n()}),r.on("close",n);return}s.status(t.status).json(t.data),m.delete(e.id)}o(je,"handleHttpResponse");var me=require("@virid/core");function he(t){let e=parseInt(t,10);if(isNaN(e))throw new w(400,`Validation failed: "${t}" is not a number.`);return e}o(he,"ParseIntPipe");function xe(t){return t==="true"||t==="1"?!0:t==="false"||t==="0"?!1:!!t}o(xe,"ParseBoolPipe");var v=new Map;v.set(Number,he);v.set(Boolean,xe);function We(t,e){if(v.has(t)){me.MessageWriter.error(new Error(`[Virid Express Pipe] Repeated Pipe: Auto pipe for ${t} has already been registered.`));return}v.set(t,e)}o(We,"addAutoPipe");function Y(t){return v.get(t)}o(Y,"getAutoPipe");function pe(t){let e={};if(!t)return e;let s=t.split(";");for(let r of s){let n=r.indexOf("=");if(n===-1)continue;let d=r.substring(0,n).trim();if(!d)continue;let a=r.substring(n+1).trim();a[0]==='"'&&a[a.length-1]==='"'&&(a=a.slice(1,-1));try{e[d]=a.includes("%")?decodeURIComponent(a):a}catch{e[d]=a}}return e}o(pe,"parseRawCookie");var Me=require("@virid/core");var ue=class ue extends Me.EventMessage{constructor(s){super();p(this,"__virid_express_id");this.__virid_express_id=s,m.get(this.__virid_express_id).inc()}get requestId(){return this.__virid_express_id}};o(ue,"HttpRequestMessage");var H=ue;var j=new W.MessageRegistry,_=new Map,_e=0;function Ee(t){for(let[e,s]of j.systemTaskMap.entries())for(let r of s)t.register(e,r.fn,r.priority);j.systemTaskMap.clear()}o(Ee,"registerHttpSystem");function we(t){for(let[e,s]of _.entries()){let{method:r,path:n,httpMessage:d}=s,a=r.toLowerCase();t[a](n,(x,f)=>{let c=_e++>>>0;m.set(c,new T(c,x,f,Date.now(),n));let O=new d(c);f.once("finish",()=>m.delete(c)),f.once("close",()=>m.delete(c)),W.MessageWriter.write(O)})}}o(we,"registerHttpRoute");var F=null;function Se(t,e){F=t,Ee(t),we(e.server)}o(Se,"activateApp");var Re=new Proxy({},{get(t,e){return(...s)=>{if(!F)return ge.MessageWriter.warn(`[Virid Vue] App method "${String(e)}" called before initialization.`),null;let r=F[e];if(typeof r=="function")return Reflect.apply(r,F,s)}}});var h=require("@virid/core");var ye=require("@virid/core"),i={...ye.VIRID_METADATA,HTTPROUTE:"virid:express:route",HTTPSYSTEM:"virid:express:system",BODY:"virid:express:body",QUERY:"virid:express:query",HEADERS:"virid:express:header",REQUEST:"virid:express:request",RESPONSE:"virid:express:response",CONTEXT:"virid:express:context",PARAMS:"virid:express:params",COOKIES:"virid:express:cookie"};function Fe(t){return e=>{let s=`${t.method}:${t.path}`;_.has(s)&&h.MessageWriter.error(new Error(`[Virid Http] Routing Conflict: The request method ${t.method} for path ${t.path} has already been registered by ${e.name}`));let r=[];t.path.split("/").forEach(a=>{a.startsWith(":")&&r.push(a.substring(1))});let d={...t,httpMessage:e,params:r};_.set(s,d)}}o(Fe,"HttpRoute");function Xe(t={priority:0,messageClass:null}){return(e,s,r)=>{let n=r.value,d=Reflect.getMetadata("design:paramtypes",e,s),a=Reflect.getMetadata(i.MESSAGE,e,s)||null,x=tt(e,s,d);if(!d){let M=new Error(`[Virid HttpSystem] System Parameter Loss:
8
- Unable to recognize system parameters, please confirm if import "reflection-metadata" was introduced at the beginning!`);h.MessageWriter.error(M);return}if(d.some(M=>M===void 0)){let M=new Error(`[Virid HttpSystem] Parameter Metadata Loss in "${s}":
9
- One or more parameters have 'undefined' types.
10
- This usually happens when you forget to add a type annotation to a decorated parameter.
11
- Check parameter at index: ${d.indexOf(void 0)}`);h.MessageWriter.error(M);return}if(t.messageClass&&a){h.MessageWriter.error(new Error(`[Virid HttpSystem] Multiple Messages Are Not Allowed: Cannot use @ message() and SystemParams simultaneously in ${s}`));return}if(!t.messageClass&&!a){h.MessageWriter.error(new Error(`[Virid HttpSystem] System Parameter Loss:
12
- Please declare the message type using the Message decorator`));return}let f=t.messageClass??a.messageClass;if(!(f.prototype instanceof H)){h.MessageWriter.error(new Error(`[Virid HttpSystem] Wrong Message Type: ${f.name} is not a derived subclass of HttpRequestMessage!`));return}let c=o(M=>{let E=m.get(M.requestId);if(!E)throw new Error(`[Virid Express HttpSystem] Invalid Request Context: The request context for message ${M.requestId} is missing.`);try{let l=d.map((C,le)=>{if(a&&a.index==le){if(!(M instanceof f)){let Ae=M.constructor.name;throw new Error(`[Virid Express HttpSystem] Type Mismatch: Expected ${f.name}, but received ${Ae}`)}return M}else return rt(C,le,E,x)}),g=n.apply(e,l);return g instanceof Promise?g.then(C=>{A(C,E)}).catch(C=>{throw A(U(),E),C}):A(g,E)}catch(l){throw l instanceof w?A(l,E):A(U(),E),l}},"wrappedSystem"),O={params:d,targetClass:e,methodName:s,originalMethod:n};c.systemContext=O,r.value=c,j.register(f,c,t.priority)}}o(Xe,"HttpSystem");function ze(){return(t,e,s)=>{if(Reflect.hasOwnMetadata(i.BODY,t,e)){h.MessageWriter.error(new Error(`[Virid Express Body] Multiple Body Are Not Allowed: ${e} has multiple @Body() decorators!`));return}let r={index:s};Reflect.defineMetadata(i.BODY,r,t,e)}}o(ze,"Body");function Ke(){return(t,e,s)=>{if(Reflect.hasOwnMetadata(i.HEADERS,t,e)){h.MessageWriter.error(new Error(`[Virid Express Headers] Multiple Header Are Not Allowed: ${e} has multiple @Headers() decorators!`));return}let r={index:s};Reflect.defineMetadata(i.HEADERS,r,t,e)}}o(Ke,"Headers");function Le(){return(t,e,s)=>{if(Reflect.hasOwnMetadata(i.COOKIES,t,e)){h.MessageWriter.error(new Error(`[Virid Express Cookies] Multiple Header Are Not Allowed: ${e} has multiple @Cookies() decorators!`));return}let r={index:s};Reflect.defineMetadata(i.COOKIES,r,t,e)}}o(Le,"Cookies");function Ge(){return(t,e,s)=>{if(Reflect.hasOwnMetadata(i.REQUEST,t,e)){h.MessageWriter.error(new Error(`[Virid Express Req] Multiple Request Objects Are Not Allowed: ${e} has multiple @Req() decorators!`));return}let r={index:s};Reflect.defineMetadata(i.REQUEST,r,t,e)}}o(Ge,"Req");function Je(){return(t,e,s)=>{if(Reflect.hasOwnMetadata(i.RESPONSE,t,e)){h.MessageWriter.error(new Error(`[Virid Express Res] Multiple Response Objects Are Not Allowed: ${e} has multiple @Res() decorators!`));return}let r={index:s};Reflect.defineMetadata(i.RESPONSE,r,t,e)}}o(Je,"Res");function Ze(){return(t,e,s)=>{if(Reflect.hasOwnMetadata(i.CONTEXT,t,e)){h.MessageWriter.error(new Error(`[Virid Express Ctx] Multiple Context Objects Are Not Allowed: ${e} has multiple @Ctx() decorators!`));return}let r={index:s};Reflect.defineMetadata(i.CONTEXT,r,t,e)}}o(Ze,"Ctx");function ke(t,e){return(s,r,n)=>{let a=[...Reflect.getOwnMetadata(i.QUERY,s,r)||[],{index:n,query:t,pipe:e}];Reflect.defineMetadata(i.QUERY,a,s,r)}}o(ke,"Query");function et(t,e){return(s,r,n)=>{let a=[...Reflect.getOwnMetadata(i.PARAMS,s,r)||[],{index:n,key:t,pipe:e}];Reflect.defineMetadata(i.PARAMS,a,s,r)}}o(et,"Params");function tt(t,e,s){let r=Reflect.getOwnMetadata(i.BODY,t,e),n=Reflect.getOwnMetadata(i.HEADERS,t,e),d=Reflect.getOwnMetadata(i.COOKIES,t,e),a=Reflect.getOwnMetadata(i.RESPONSE,t,e),x=Reflect.getOwnMetadata(i.REQUEST,t,e),f=Reflect.getOwnMetadata(i.CONTEXT,t,e),O=(Reflect.getOwnMetadata(i.QUERY,t,e)||[]).map(l=>{if(!l.pipe){let g=s[l.index];l.pipe=Y(g)}return l}),E=(Reflect.getOwnMetadata(i.PARAMS,t,e)||[]).map(l=>{if(!l.pipe){let g=s[l.index];l.pipe=Y(g)}return l});return{bodyMeta:r,headerMeta:n,queryMeta:O,cookiesMeta:d,reqMeta:x,resMeta:a,ctxMeta:f,paramMeta:E}}o(tt,"getHttpMetadata");function rt(t,e,s,r){let{req:n,res:d}=s;if(r.ctxMeta?.index===e)return s;let a=r.paramMeta?.find(c=>c.index===e);if(a){let c=a.key?n.params[a.key]:n.params;return a.pipe&&c!==void 0&&(c=a.pipe(c)),c}if(r.bodyMeta?.index===e)return n.body;if(r.headerMeta?.index===e)return n.headers;if(r.cookiesMeta?.index===e)return pe(n.headers.cookie);if(r.reqMeta?.index===e)return n;if(r.resMeta?.index===e)return d;let x=r.queryMeta?.find(c=>c.index===e);if(x){let c=n.query[x.query];if(c===void 0)throw new Error(`[Virid Express] Missing Query: "${x.query}"`);return x.pipe&&(c=x.pipe(c)),c}let f=Re.get(t);if(!f)throw new Error(`[Virid System] Unknown Inject Type: ${t?.name||"Anonymous Class"} at index ${e}.
13
- Ensure it is registered in the IOC container or has a proper Http Decorator!`);return f}o(rt,"getHttpSystemArgs");var st={name:"@virid/express",install(t,e){Se(t,e)}};0&&(module.exports={BadRequest,BadRequestResponse,Body,ConflictResponse,Cookies,Created,CreatedResponse,Ctx,CustomResponse,CustomResponseResponse,ExpressPlugin,Forbidden,ForbiddenResponse,Headers,HttpContext,HttpError,HttpRequestMessage,HttpResponse,HttpRoute,HttpSystem,InternalServerError,InternalServerErrorResponse,NoContent,NoContentResponse,NotFound,NotFoundResponse,Ok,OkResponse,Params,ParseBoolPipe,ParseIntPipe,Query,Req,Res,Stream,StreamFile,StreamFileResponse,StreamResponse,Unauthorized,UnauthorizedResponse,UnprocessableEntityResponse,addAutoPipe,getAutoPipe,parseRawCookie});
7
+ Uptime: ${Date.now()-this.timestamp}ms`;he.MessageWriter.error(new Error(e)),this.res.headersSent?this.res.end():this.res.status(500).json({error:"Internal Logic Error",message:"Request processed but no response was returned by any system."})}};o(L,"HttpContext");var S=L,K=class K{constructor(e,t=null,s={}){l(this,"status");l(this,"data");l(this,"headers");this.status=e,this.data=t,this.headers=s}};o(K,"HttpResponse");var p=K,z=class z extends p{constructor(e,t={}){super(200,e,t)}};o(z,"OkResponse");var $=z,F=class F extends p{constructor(e,t={}){super(201,e,t)}};o(F,"CreatedResponse");var q=F,W=class W extends p{constructor(){super(204,null)}};o(W,"NoContentResponse");var V=W,_=class _ extends p{constructor(e="Bad Request"){super(400,{error:e})}};o(_,"BadRequestResponse");var b=_,G=class G extends p{constructor(e="Unauthorized"){super(401,{error:e})}};o(G,"UnauthorizedResponse");var v=G,J=class J extends p{constructor(e="Forbidden"){super(403,{error:e})}};o(J,"ForbiddenResponse");var D=J,Z=class Z extends p{constructor(e="Not Found"){super(404,{error:e})}};o(Z,"NotFoundResponse");var N=Z,k=class k extends p{constructor(e="Conflict"){super(409,{error:e})}};o(k,"ConflictResponse");var Y=k,ee=class ee extends p{constructor(e){super(422,{errors:e})}};o(ee,"UnprocessableEntityResponse");var X=ee,te=class te extends p{constructor(e="Internal Server Error"){super(500,{error:e})}};o(te,"InternalServerErrorResponse");var P=te,re=class re extends p{constructor(e,t,s={}){super(e,t,s)}};o(re,"CustomResponseResponse");var U=re,se=class se extends p{constructor(t,s={dotfiles:"allow"}){super(206,s);l(this,"filePath");l(this,"options");this.filePath=t,this.options=s}};o(se,"StreamFileResponse");var y=se,oe=class oe extends p{constructor(t,s={}){super(s.status||206,{},s.headers);l(this,"stream");l(this,"options");this.stream=t,this.options=s}};o(oe,"StreamResponse");var C=oe,Ae=o((r,e={})=>new $(r,e),"Ok"),Te=o((r,e={})=>new q(r,e),"Created"),Pe=o(()=>new V,"NoContent"),Ie=o((r="Bad Request")=>new b(r),"BadRequest"),He=o((r="Unauthorized")=>new v(r),"Unauthorized"),$e=o((r="Forbidden")=>new D(r),"Forbidden"),qe=o((r="Not Found")=>new N(r),"NotFound"),B=o((r="Internal Server Error")=>r instanceof Error?new P(r.message):new P(r),"InternalServerError"),Ve=o((r,e,t={})=>new U(r,e,t),"CustomResponse"),be=o((r,e)=>new y(r,e),"StreamFile"),ve=o((r,e)=>new C(r,e),"Stream"),ie=class ie extends Error{constructor(t,s){super(s);l(this,"status");l(this,"message");this.status=t,this.message=s}};o(ie,"HttpError");var w=ie;var fe=require("@virid/core");function me(r){let e=parseInt(r,10);if(isNaN(e))throw new w(400,`Validation failed: "${r}" is not a number.`);return e}o(me,"ParseIntPipe");function xe(r){return r==="true"||r==="1"?!0:r==="false"||r==="0"?!1:!!r}o(xe,"ParseBoolPipe");var I=new Map;I.set(Number,me);I.set(Boolean,xe);function De(r,e){if(I.has(r)){fe.MessageWriter.error(new Error(`[Virid Express Pipe] Repeated Pipe: Auto pipe for ${r} has already been registered.`));return}I.set(r,e)}o(De,"addAutoPipe");function Ne(r){return I.get(r)}o(Ne,"getAutoPipe");function ae(r){let e={};if(!r)return e;let t=r.split(";");for(let s of t){let i=s.indexOf("=");if(i===-1)continue;let a=s.substring(0,i).trim();if(!a)continue;let n=s.substring(i+1).trim();n[0]==='"'&&n[n.length-1]==='"'&&(n=n.slice(1,-1));try{e[a]=n.includes("%")?decodeURIComponent(n):n}catch{e[a]=n}}return e}o(ae,"parseRawCookie");var we=require("@virid/core");var ne=class ne extends we.EventMessage{constructor(t){super();l(this,"__virid_express_id");this.__virid_express_id=t}get requestId(){return this.__virid_express_id}};o(ne,"HttpRequestMessage");var O=ne;var Me=require("@virid/core"),d={...Me.VIRID_METADATA,HTTPROUTE:"virid:express:route",HTTPSYSTEM:"virid:express:system",BODY:"virid:express:body",QUERY:"virid:express:query",HEADERS:"virid:express:header",REQUEST:"virid:express:request",RESPONSE:"virid:express:response",CONTEXT:"virid:express:context",PARAMS:"virid:express:params",COOKIES:"virid:express:cookie"};function Ue(r){return e=>{let t=[];r.path.split("/").forEach(a=>{a.startsWith(":")&&t.push(a.substring(1))});let i={...r,httpMessage:e,params:t};Reflect.defineMetadata(d.HTTPROUTE,i,e)}}o(Ue,"HttpRoute");function Be(r){let e=[];if(r.forEach((t,s)=>{(t===O||t&&t.prototype instanceof O)&&e.push({type:t,idx:s})}),e.length===0)return null;if(e.length>1){let t=e.map(s=>`[Index: ${s.idx}, Name: ${s.type.name}]`).join(", ");throw new Error(`[Virid System] Multiple Messages: Multiple Message type parameters detected, this is not allowed! specific location: ${t}`)}return e[0]}o(Be,"checkMessageParam");function Qe(r={priority:0,messageClass:null}){return(e,t,s)=>{if(typeof e!="function")throw new Error(`[Virid System] Method Type Error: The Method ${t} is not a static method, please check if there is a static keyword tag.`);let i=s.value,a=Reflect.getMetadata("design:paramtypes",e,t);if(!a)throw new Error('[Virid System] System Parameter Loss: Unable to recognize system parameters, please confirm if import "reflect-metadata" was introduced at the beginning.');let n=a.map((M,A)=>M===void 0?A:-1).filter(M=>M!==-1);if(n.length>0)throw new Error(`[Virid System] Parameter Metadata Loss in "${t}": One or more parameters have 'undefined' types. This usually happens when you forget to add a type annotation or due to circular dependencies. Check parameter at indices: [${n.join(", ")}]`);let c,h=-1,u=Be(a);if(u&&r.messageClass)throw new Error(`[Virid System] Multiple Messages Are Not Allowed: Cannot specify messageClass in decorator options while already declaring it in method parameters at index ${u.idx} in ${t}.`);if(u)c=u.type,h=u.idx;else if(r.messageClass)c=r.messageClass,h=-1;else throw new Error("[Virid System] System Parameter Loss: Please declare the message type either in method parameters or via the Message decorator options.");let x=_e(e,t),f={params:a,targetClass:e,methodName:t,originalMethod:i},H={httpMetadata:x,messageClass:c,messageIdx:h,priority:r.priority||0,batchMode:!1};s.value.systemContext=f,s.value.httpSystemConfig=H}}o(Qe,"HttpSystem");function je(){return(r,e,t)=>{if(Reflect.hasOwnMetadata(d.BODY,r,e))throw new Error(`[Virid Express Body] Multiple Body Are Not Allowed: ${e} has multiple @Body() decorators!`);let s={index:t};Reflect.defineMetadata(d.BODY,s,r,e)}}o(je,"Body");function Ye(){return(r,e,t)=>{if(Reflect.hasOwnMetadata(d.HEADERS,r,e))throw new Error(`[Virid Express Headers] Multiple Header Are Not Allowed: ${e} has multiple @Headers() decorators!`);let s={index:t};Reflect.defineMetadata(d.HEADERS,s,r,e)}}o(Ye,"Headers");function Xe(){return(r,e,t)=>{if(Reflect.hasOwnMetadata(d.COOKIES,r,e))throw new Error(`[Virid Express Cookies] Multiple Header Are Not Allowed: ${e} has multiple @Cookies() decorators!`);let s={index:t};Reflect.defineMetadata(d.COOKIES,s,r,e)}}o(Xe,"Cookies");function Le(){return(r,e,t)=>{if(Reflect.hasOwnMetadata(d.REQUEST,r,e))throw new Error(`[Virid Express Req] Multiple Request Objects Are Not Allowed: ${e} has multiple @Req() decorators!`);let s={index:t};Reflect.defineMetadata(d.REQUEST,s,r,e)}}o(Le,"Req");function Ke(){return(r,e,t)=>{if(Reflect.hasOwnMetadata(d.RESPONSE,r,e))throw new Error(`[Virid Express Res] Multiple Response Objects Are Not Allowed: ${e} has multiple @Res() decorators!`);let s={index:t};Reflect.defineMetadata(d.RESPONSE,s,r,e)}}o(Ke,"Res");function ze(){return(r,e,t)=>{if(Reflect.hasOwnMetadata(d.CONTEXT,r,e))throw new Error(`[Virid Express Ctx] Multiple Context Objects Are Not Allowed: ${e} has multiple @Ctx() decorators!`);let s={index:t};Reflect.defineMetadata(d.CONTEXT,s,r,e)}}o(ze,"Ctx");function Fe(r,e){return(t,s,i)=>{let n=[...Reflect.getOwnMetadata(d.QUERY,t,s)||[],{index:i,query:r,pipe:e}];Reflect.defineMetadata(d.QUERY,n,t,s)}}o(Fe,"Query");function We(r,e){return(t,s,i)=>{let n=[...Reflect.getOwnMetadata(d.PARAMS,t,s)||[],{index:i,key:r,pipe:e}];Reflect.defineMetadata(d.PARAMS,n,t,s)}}o(We,"Params");function _e(r,e){let t=Reflect.getOwnMetadata(d.BODY,r,e),s=Reflect.getOwnMetadata(d.HEADERS,r,e),i=Reflect.getOwnMetadata(d.COOKIES,r,e),a=Reflect.getOwnMetadata(d.RESPONSE,r,e),n=Reflect.getOwnMetadata(d.REQUEST,r,e),c=Reflect.getOwnMetadata(d.CONTEXT,r,e),h=Reflect.getOwnMetadata(d.QUERY,r,e)||[],u=Reflect.getOwnMetadata(d.PARAMS,r,e)||[];return{bodyMeta:t,headerMeta:s,queryMeta:h,paramMeta:u,cookiesMeta:i,reqMeta:n,resMeta:a,ctxMeta:c}}o(_e,"getHttpMetadata");function de(r,e,t){let{req:s,res:i}=e;if(t.ctxMeta?.index===r)return e;let a=t.paramMeta?.find(c=>c.index===r);if(a){let c=a.key?s.params[a.key]:s.params;return a.pipe&&c!==void 0&&(c=a.pipe(c)),c}if(t.bodyMeta?.index===r)return s.body;if(t.headerMeta?.index===r)return s.headers;if(t.cookiesMeta?.index===r)return ae(s.headers.cookie);if(t.reqMeta?.index===r)return s;if(t.resMeta?.index===r)return i;let n=t.queryMeta?.find(c=>c.index===r);if(n){let c=s.query[n.query];if(c===void 0)throw new Error(`[Virid Express] Missing Query: "${n.query}"`);return n.pipe&&(c=n.pipe(c)),c}return null}o(de,"getHttpArgs");var le=class le{constructor(){l(this,"name","@virid/express");l(this,"stagingSystemRegister",new m.MessageRegistry);l(this,"httpRouteRegistry",new Map);l(this,"httpContextStore",new Map);l(this,"_internalHttpIdCounter",0)}register(e){let t=e.systemContext,s=e.httpSystemConfig;if(!t||!s)throw new Error(`[Virid HttpSystem] HttpSystem Parameter Loss: Please declare ${e.name} using the @HttpSystem decorator first.`);return this.stagingSystemRegister.register(t.targetClass,e,s.priority),()=>{}}bindRoute(e){let t=Reflect.getMetadata(d.HTTPROUTE,e);if(!t)throw new Error(`[Virid Http] Routing Error: ${e.name} is not a valid HttpRoute`);let s=`${t.method}:${t.path}`;if(this.httpRouteRegistry.has(s))throw new Error(`[Virid Http] Routing Conflict: The request method ${t.method} for path ${t.path} has already been registered by ${e.name}`);this.httpRouteRegistry.set(s,t)}install(e,t){for(let[s,i]of this.httpRouteRegistry.entries()){let{method:a,path:n,httpMessage:c}=i,h=a.toLowerCase();t.server[h](n,(u,x)=>{let f=this._internalHttpIdCounter++>>>0;new S(f,u,x,Date.now(),n).inc(),this.httpContextStore.set(f,new S(f,u,x,Date.now(),n));let M=new c(f);x.once("finish",()=>this.httpContextStore.delete(f)),x.once("close",()=>this.httpContextStore.delete(f)),m.MessageWriter.write(M)})}for(let[s,i]of this.stagingSystemRegister.systemTaskMap.entries())for(let a of i){let n=a.fn,c=n.systemContext,h=n.httpSystemConfig,{httpMetadata:u,messageClass:x,messageIdx:f}=h,{originalMethod:H,targetClass:M}=c,A=o(Q=>{let g=this.httpContextStore.get(Q.requestId);if(!g)throw new Error(`[Virid Express HttpSystem] Invalid Request Context: The request context for message ${Q.requestId} is missing.`);try{let E=c.params.map((R,pe)=>{if(pe===f)return Q;{let ue=de(pe,g,u);return ue||e.get(R)}}),j=H.apply(M,E);return j instanceof Promise?j.then(R=>{this.handleResult(R,g)}).catch(R=>{throw this.handleResult(B(R),g),R}):this.handleResult(j,g)}catch(E){throw E instanceof w?this.handleResult(E,g):this.handleResult(B(E),g),E}},"wrappedSystem");A.systemContext=c,A.httpSystemConfig=h,e.engine.register(x,A,a.priority)}this.stagingSystemRegister.systemTaskMap.clear()}handleResult(e,t){if(!e){t.dec();return}(Array.isArray(e)?e:[e]).forEach(i=>{i instanceof p?this.handleHttpResponse(i,t):i instanceof w?(t.res.status(i.status).json(i.message),this.httpContextStore.delete(t.id)):i instanceof m.BaseMessage?m.MessageWriter.write(i):m.MessageWriter.warn(`[Virid Express] Invalid Return Type: ${typeof i}. Expected HttpResponse or Message.`)}),t.dec()}handleHttpResponse(e,t){let{res:s}=t;if(e.headers&&Object.entries(e.headers).forEach(([i,a])=>s.setHeader(i,a)),e.status&&s.status(e.status),e instanceof y){t.inc(),s.sendFile(e.filePath,e.options,i=>{s.headersSent||m.MessageWriter.error(i,`[Virid Express] SteamFile Error: Path: ${e.filePath}`),t.res.end(),this.httpContextStore.delete(t.id),t.isClosed=!0,t.dec()});return}if(e instanceof C){let{stream:i}=e;t.inc(),i.pipe(s);let a=o(()=>{this.httpContextStore.has(t.id)&&(t.res.end(),this.httpContextStore.delete(t.id),t.isClosed=!0,t.dec())},"cleanup");i.on("end",a),i.on("error",n=>{s.headersSent||m.MessageWriter.error(n,"[Virid Express] Stream Error"),a()}),i.on("close",a);return}s.status(e.status).json(e.data),this.httpContextStore.delete(t.id)}};o(le,"ExpressPlugin");var ce=le;0&&(module.exports={BadRequest,BadRequestResponse,Body,ConflictResponse,Cookies,Created,CreatedResponse,Ctx,CustomResponse,CustomResponseResponse,ExpressPlugin,Forbidden,ForbiddenResponse,Headers,HttpContext,HttpError,HttpRequestMessage,HttpResponse,HttpRoute,HttpSystem,InternalServerError,InternalServerErrorResponse,NoContent,NoContentResponse,NotFound,NotFoundResponse,Ok,OkResponse,Params,ParseBoolPipe,ParseIntPipe,Query,Req,Res,Stream,StreamFile,StreamFileResponse,StreamResponse,Unauthorized,UnauthorizedResponse,UnprocessableEntityResponse,addAutoPipe,getAutoPipe,getHttpArgs,parseRawCookie});
14
8
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/app.ts","../src/decorators/register.ts","../src/http/context.ts","../src/http/http-response.ts","../src/http/utils.ts","../src/http/message.ts","../src/decorators/express.ts","../src/decorators/constant.ts"],"sourcesContent":["/*\n * Copyright (c) 2026-present Ailrid\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Description: Add express functionality to virid.\n */\nimport { ViridPlugin, type ViridApp } from \"@virid/core\";\nimport { activateApp } from \"./app\";\nimport { PluginOptions } from \"./interfaces\";\n\nexport * from \"./http\";\nexport * from \"./decorators\";\nexport const ExpressPlugin: ViridPlugin<PluginOptions> = {\n name: \"@virid/express\",\n install(app: ViridApp, options) {\n activateApp(app, options as PluginOptions);\n },\n};\n","/*\n * Copyright (c) 2026-present Ailrid.\n * Licensed under the Apache License, Version 2.0.\n * Project: Virid Express\n */\nimport { type ViridApp, MessageWriter } from \"@virid/core\";\nimport { type PluginOptions } from \"./interfaces\";\n\nimport { registerHttpSystem, registerHttpRoute } from \"./decorators/register\";\n\nexport interface IViridApp {\n get(identifier: any): any;\n}\n\nlet activeApp: IViridApp | null = null;\n\nexport function activateApp(app: ViridApp, options: PluginOptions) {\n //看看用户提供的配置\n activeApp = app;\n // 注册http相关的系统\n registerHttpSystem(app);\n //初始化express的路由\n registerHttpRoute(options.server);\n}\n\n/**\n * viridApp 代理\n */\nexport const viridApp: IViridApp = new Proxy({} as IViridApp, {\n get(_, prop: keyof IViridApp) {\n return (...args: any[]) => {\n // 检查实例是否存在\n if (!activeApp) {\n MessageWriter.warn(\n `[Virid Vue] App method \"${String(prop)}\" called before initialization.`,\n );\n return null;\n }\n\n // 正常转发调用\n // 使用 Reflect 确保 this 指向正确,或者直接从 activeApp 调用\n const targetMethod = activeApp[prop];\n if (typeof targetMethod === \"function\") {\n return Reflect.apply(targetMethod, activeApp, args);\n }\n };\n },\n});\n","/*\n * Copyright (c) 2026-present Ailrid.\n * Licensed under the Apache License, Version 2.0.\n * Project: Virid Express\n */\nimport { MessageRegistry, MessageWriter, type ViridApp } from \"@virid/core\";\nimport { type HttpMethod, type HttpRouteInfo } from \"../interfaces\";\nimport { type Express, type Request, type Response } from \"express\";\nimport { httpContextStore } from \"../http/context\";\nimport { HttpContext, type RequestId } from \"../http\";\n// 临时的注册器\nexport const stagingSystemRegister = new MessageRegistry();\n// 路由注册器\nexport const httpRouteRegistry = new Map<string, HttpRouteInfo>();\n\nlet _internalHttpIdCounter = 0;\n\n/**\n * 注册HttpSystem到app的调度器里\n */\nexport function registerHttpSystem(app: ViridApp) {\n for (const [\n messageClass,\n systemTasks,\n ] of stagingSystemRegister.systemTaskMap.entries()) {\n for (const task of systemTasks) {\n app.register(messageClass, task.fn, task.priority);\n }\n }\n stagingSystemRegister.systemTaskMap.clear();\n}\n\n/**\n * 注册express路由\n */\nexport function registerHttpRoute(server: Express) {\n for (const [_, routeInfo] of httpRouteRegistry.entries()) {\n const { method, path, httpMessage } = routeInfo;\n const expressMethod = method.toLowerCase() as HttpMethod;\n\n //挂载\n server[expressMethod](path, (req: Request, res: Response) => {\n // 实例化 Message\n const newId = _internalHttpIdCounter++ >>> 0;\n\n //存一下上下文信息\n httpContextStore.set(\n newId,\n new HttpContext(newId, req, res, Date.now(), path),\n );\n const message = new httpMessage(newId as RequestId);\n // finish 代表响应已发送,close 代表连接意外中断,两者都应清理\n res.once(\"finish\", () => httpContextStore.delete(newId));\n res.once(\"close\", () => httpContextStore.delete(newId));\n // 触发消息\n MessageWriter.write(message);\n });\n }\n}\n","/*\n * Copyright (c) 2026-present Ailrid.\n * Licensed under the Apache License, Version 2.0.\n * Project: Virid Express\n */\nimport { BaseMessage, MessageWriter } from \"@virid/core\";\nimport {\n type HttpContext,\n HttpResponse,\n StreamFileResponse,\n HttpError,\n StreamResponse,\n} from \"./http-response\";\nexport const httpContextStore = new Map<number, HttpContext>();\n\n/**\n * 统一处理 System 返回值\n * @param res System 函数的返回值\n * @param ctx 当前请求的 HttpContext\n */\nexport function handleResult(res: any, context: HttpContext) {\n if (!res) {\n context.dec();\n return;\n }\n // 支持数组形式的批量返回\n const results = Array.isArray(res) ? res : [res];\n results.forEach((item) => {\n // 处理物理响应 (HttpResponse)\n\n if (item instanceof HttpResponse) {\n // 如果是终结响应,则处理\n handleHttpResponse(item, context);\n } else if (item instanceof HttpError) {\n // 处理错误\n context.res.status(item.status).json(item.message);\n // 从 store 中移除\n httpContextStore.delete(context.id);\n } else if (item instanceof BaseMessage) {\n // 转发消息\n MessageWriter.write(item);\n }\n // 其他非法类型警告\n else {\n MessageWriter.warn(\n `[Virid Express] Invalid Return Type: ${typeof item}. Expected HttpResponse or Message.`,\n );\n }\n });\n // system不管是出错了还是执行完毕,handleResult都会执行,引用计数-1并检查是否是0\n // 如果是0,而且此时还没关闭,那就强制关闭\n // 第一种情况:上面执行了handleHttpResponse,那么在这之前HttpContext就已经被删除了\n // 第二种情况:上面转发了HttpRequestMessage,那么这会抹除此次system执行的痕迹,但是HttpContext由于引用计数,不会被删除\n // 第三种情况:上面转发了其他消息或者其他的返回值,那么引用计数-1并检查是否是0,如果是0,那么强制关闭\n context.dec();\n}\n\nfunction handleHttpResponse(response: HttpResponse, ctx: HttpContext) {\n const { res } = ctx;\n //其他情况,直接返回\n if (response.headers) {\n Object.entries(response.headers).forEach(([k, v]) => res.setHeader(k, v));\n }\n if (response.status) res.status(response.status);\n if (response instanceof StreamFileResponse) {\n //返回异步流,强行增加一个rc续命\n ctx.inc();\n res.sendFile(response.filePath, response.options, (err) => {\n if (!res.headersSent) {\n MessageWriter.error(\n err,\n `[Virid Express] SteamFile Error: Path: ${response.filePath}`,\n );\n }\n //强制删除context\n ctx.res.end();\n httpContextStore.delete(ctx.id);\n ctx.isClosed = true;\n ctx.dec();\n });\n return;\n }\n if (response instanceof StreamResponse) {\n const { stream } = response;\n ctx.inc();\n // 管道传输\n stream.pipe(res);\n // 监听结束,收割上下文\n const cleanup = () => {\n if (!httpContextStore.has(ctx.id)) return;\n ctx.res.end();\n httpContextStore.delete(ctx.id);\n ctx.isClosed = true;\n ctx.dec(); // 触发最后的 finalize\n };\n stream.on(\"end\", cleanup);\n stream.on(\"error\", (err) => {\n if (!res.headersSent) {\n MessageWriter.error(err, `[Virid Express] Stream Error`);\n }\n cleanup();\n });\n stream.on(\"close\", cleanup);\n return;\n }\n\n res.status(response.status).json(response.data);\n //强制删除context\n httpContextStore.delete(ctx.id);\n}\n","/*\n * Copyright (c) 2026-present Ailrid.\n * Licensed under the Apache License, Version 2.0.\n * Project: Virid Express\n */\nimport { type Request, type Response } from \"express\";\nimport { Readable } from \"stream\";\nimport { MessageWriter } from \"@virid/core\";\ninterface HttpHeaders {\n [key: string]: string | string[];\n}\nexport class HttpContext {\n public rc: number = 0;\n public isClosed: boolean = false;\n\n constructor(\n public readonly id: number,\n public readonly req: Request,\n public readonly res: Response,\n public readonly timestamp: number,\n public readonly route: string,\n ) {}\n\n /**\n * Increment Reference Count (进入 System)\n */\n inc() {\n this.rc++;\n }\n\n /**\n * Decrement Reference Count (离开 System)\n * 如果归零且未响应,则判定为孤立响应,强制收割\n */\n dec() {\n this.rc--;\n if (this.rc === 0) {\n this.tryFinalize();\n }\n }\n\n private tryFinalize() {\n // 如果已经由 System 正常返回\n // 或者已经强制关闭过,则直接跳过\n if (this.res.writableEnded || this.isClosed) return;\n\n this.isClosed = true;\n\n // 强制报错并关闭连接\n const errorMsg = `[Virid Express] Request Orphaned: The connection was closed because all systems finished execution without sending a response. \n Route: ${this.route}\n Uptime: ${Date.now() - this.timestamp}ms`;\n\n MessageWriter.error(new Error(errorMsg));\n\n if (!this.res.headersSent) {\n this.res.status(500).json({\n error: \"Internal Logic Error\",\n message:\n \"Request processed but no response was returned by any system.\",\n });\n } else {\n // 如果 header 已经发了但没写完,强行结束流\n this.res.end();\n }\n }\n}\n\nexport abstract class HttpResponse {\n constructor(\n public status: number,\n public data: any = null,\n public headers: HttpHeaders = {},\n ) {}\n}\n\n// --- 2xx Success ---\nexport class OkResponse extends HttpResponse {\n constructor(data: any, headers: HttpHeaders = {}) {\n super(200, data, headers);\n }\n}\n\nexport class CreatedResponse extends HttpResponse {\n constructor(data: any, headers: HttpHeaders = {}) {\n super(201, data, headers);\n }\n}\n\nexport class NoContentResponse extends HttpResponse {\n constructor() {\n super(204, null);\n }\n}\n\n// --- 4xx Client Error ---\nexport class BadRequestResponse extends HttpResponse {\n constructor(message: string = \"Bad Request\") {\n super(400, { error: message });\n }\n}\n\nexport class UnauthorizedResponse extends HttpResponse {\n constructor(message: string = \"Unauthorized\") {\n super(401, { error: message });\n }\n}\n\nexport class ForbiddenResponse extends HttpResponse {\n constructor(message: string = \"Forbidden\") {\n super(403, { error: message });\n }\n}\n\nexport class NotFoundResponse extends HttpResponse {\n constructor(message: string = \"Not Found\") {\n super(404, { error: message });\n }\n}\n\nexport class ConflictResponse extends HttpResponse {\n constructor(message: string = \"Conflict\") {\n super(409, { error: message });\n }\n}\n\nexport class UnprocessableEntityResponse extends HttpResponse {\n constructor(errors: any) {\n super(422, { errors });\n }\n}\n\n// --- 5xx Server Error ---\nexport class InternalServerErrorResponse extends HttpResponse {\n constructor(message: string = \"Internal Server Error\") {\n super(500, { error: message });\n }\n}\n\n// --- 万能类 (Custom) ---\nexport class CustomResponseResponse extends HttpResponse {\n constructor(status: number, data: any, headers: HttpHeaders = {}) {\n super(status, data, headers);\n }\n}\n/**\n * @description: Express sendFile 配置项的强类型定义\n */\nexport interface StreamFileOptions {\n /** 根目录(如果 path 是相对路径则必填) */\n root?: string;\n /** * 对以 . 开头的文件处理策略:\n * - allow: 允许发送\n * - deny: 拒绝并返回 403\n * - ignore: 当作不存在返回 404\n */\n dotfiles?: \"allow\" | \"deny\" | \"ignore\";\n /** 是否发送 ETag */\n etag?: boolean;\n /** 扩展的 HTTP 响应头 */\n headers?: HttpHeaders;\n /** 缓存最大时长 (毫秒) */\n maxAge?: number | string;\n /** 是否在 Cache-Control 中添加 immutable */\n immutable?: boolean;\n /** 是否根据文件系统设置 Last-Modified */\n lastModified?: boolean;\n /** 是否支持断点续传 (Range 请求) */\n acceptRanges?: boolean;\n /** 还有一些不常用的(如 cacheControl, extensions)也可以按需添加 */\n}\nexport class StreamFileResponse extends HttpResponse {\n constructor(\n public readonly filePath: string,\n public readonly options: StreamFileOptions = { dotfiles: \"allow\" },\n ) {\n super(206, options);\n }\n}\n\nexport class StreamResponse extends HttpResponse {\n constructor(\n public readonly stream: Readable,\n public readonly options: {\n status?: number;\n headers?: HttpHeaders;\n } = {},\n ) {\n super(options.status || 206, {}, options.headers);\n }\n}\n// --- 辅助工厂函数 ---\n\n/** 200 OK */\nexport const Ok = (data: any, headers: HttpHeaders = {}) =>\n new OkResponse(data, headers);\n\n/** 201 Created */\nexport const Created = (data: any, headers: HttpHeaders = {}) =>\n new CreatedResponse(data, headers);\n\n/** 204 No Content */\nexport const NoContent = () => new NoContentResponse();\n\n/** 400 Bad Request */\nexport const BadRequest = (msg = \"Bad Request\") => new BadRequestResponse(msg);\n\n/** 401 Unauthorized */\nexport const Unauthorized = (msg = \"Unauthorized\") =>\n new UnauthorizedResponse(msg);\n\n/** 403 Forbidden */\nexport const Forbidden = (msg = \"Forbidden\") => new ForbiddenResponse(msg);\n\n/** 404 Not Found */\nexport const NotFound = (msg = \"Not Found\") => new NotFoundResponse(msg);\n\n/** 500 Internal Error */\nexport const InternalServerError = (msg = \"Internal Server Error\") =>\n new InternalServerErrorResponse(msg);\n\nexport const CustomResponse = (\n status: number,\n data: any,\n headers: HttpHeaders = {},\n) => new CustomResponseResponse(status, data, headers);\n\n/** 发送本地文件 (自动处理 Range/206) */\nexport const StreamFile = (path: string, options?: StreamFileOptions) =>\n new StreamFileResponse(path, options);\n/**\n * 发送流响应\n */\nexport const Stream = (stream: Readable, options?: StreamResponse[\"options\"]) =>\n new StreamResponse(stream, options);\n\nexport class HttpError extends Error {\n constructor(\n public readonly status: number,\n public readonly message: string,\n ) {\n super(message);\n }\n}\n","/*\n * Copyright (c) 2026-present Ailrid.\n * Licensed under the Apache License, Version 2.0.\n * Project: Virid Express\n */\nimport { MessageWriter } from \"@virid/core\";\nimport { HttpError } from \".\";\nimport { type TransformPipe } from \"../interfaces\";\n\nexport function ParseIntPipe(val: string) {\n const res = parseInt(val, 10);\n if (isNaN(res))\n throw new HttpError(400, `Validation failed: \"${val}\" is not a number.`);\n return res;\n}\n\nexport function ParseBoolPipe(val: string) {\n if (val === \"true\" || val === \"1\") return true;\n if (val === \"false\" || val === \"0\") return false;\n return !!val;\n}\n\n/** 存储类型与 Pipe 的映射 */\nconst autoPipeMap = new Map<any, TransformPipe<any>>();\nautoPipeMap.set(Number, ParseIntPipe);\nautoPipeMap.set(Boolean, ParseBoolPipe);\n\n/**\n * 让用户注册自定义类型的转换方法\n */\nexport function addAutoPipe<T>(type: T, pipe: TransformPipe<T>) {\n if (autoPipeMap.has(type)) {\n MessageWriter.error(\n new Error(\n `[Virid Express Pipe] Repeated Pipe: Auto pipe for ${type} has already been registered.`,\n ),\n );\n return;\n }\n autoPipeMap.set(type, pipe);\n}\n\n/**\n * 内部调用:根据 TS 类型获取 Pipe\n */\nexport function getAutoPipe<T>(type: T): TransformPipe<T> | undefined {\n return autoPipeMap.get(type);\n}\n\n/**\n * 将 cookie 字符串转换为对象\n */\nexport function parseRawCookie(\n cookieHeader: string | undefined,\n): Record<string, string> {\n const result: Record<string, string> = {};\n\n if (!cookieHeader) return result;\n const pairs = cookieHeader.split(\";\");\n\n for (const pair of pairs) {\n const indexOfEq = pair.indexOf(\"=\");\n if (indexOfEq === -1) continue;\n\n // 提取 key 和 value,并进行 trim 处理\n const key = pair.substring(0, indexOfEq).trim();\n if (!key) continue;\n\n let value = pair.substring(indexOfEq + 1).trim();\n\n if (value[0] === '\"' && value[value.length - 1] === '\"') {\n value = value.slice(1, -1);\n }\n\n try {\n // 只在必要时进行 URL 解码\n result[key] = value.includes(\"%\") ? decodeURIComponent(value) : value;\n } catch (e) {\n // 如果解码失败(比如恶意构造的序列),保留原样,防止崩溃\n result[key] = value;\n }\n }\n\n return result;\n}\n","/*\n * Copyright (c) 2026-present Ailrid.\n * Licensed under the Apache License, Version 2.0.\n * Project: Virid Express\n */\nimport { EventMessage } from \"@virid/core\";\nimport { httpContextStore } from \"./context\";\nexport type RequestId = number & { readonly __brand: unique symbol };\n\nexport class HttpRequestMessage extends EventMessage {\n // id 必须是 RequestId 类型\n constructor(private readonly __virid_express_id: RequestId) {\n super();\n //从context里捞出来自己的,挂上引用计数+1\n httpContextStore.get(this.__virid_express_id)!.inc();\n }\n // 暴露一个只读属性给业务层使用\n public get requestId(): RequestId {\n return this.__virid_express_id;\n }\n}\n","/*\n * Copyright (c) 2026-present Ailrid.\n * Licensed under the Apache License, Version 2.0.\n * Project: Virid Express\n */\nimport {\n type Newable,\n type SystemParams,\n type SystemContext,\n type MessageMetadata,\n MessageWriter,\n} from \"@virid/core\";\nimport {\n type HttpRouteConfig,\n type HttpRouteInfo,\n type BodyMetadata,\n type HeaderMetadata,\n type QueryMetadata,\n type RequestMetadata,\n type ResponseMetadata,\n type ContextMetadata,\n type ParamMetadata,\n type TransformPipe,\n CookieMetadata,\n} from \"../interfaces\";\nimport {\n HttpContext,\n HttpError,\n HttpRequestMessage,\n InternalServerError,\n parseRawCookie,\n} from \"../http\";\nimport { handleResult, httpContextStore } from \"../http/context\";\nimport { httpRouteRegistry, stagingSystemRegister } from \"./register\";\nimport { VIRID_EXPRESS_METADATA } from \"./constant\";\nimport { viridApp } from \"../app\";\nimport { getAutoPipe } from \"../http\";\nexport function HttpRoute(config: HttpRouteConfig) {\n return (constructor: Newable<HttpRequestMessage>) => {\n // 唯一性校验:组合 Method 和 Path\n const routeKey = `${config.method}:${config.path}`;\n if (httpRouteRegistry.has(routeKey)) {\n MessageWriter.error(\n new Error(\n `[Virid Http] Routing Conflict: The request method ${config.method} for path ${config.path} has already been registered by ${constructor.name}`,\n ),\n );\n }\n\n // 路径参数解析\n const params: string[] = [];\n const pathParts = config.path.split(\"/\");\n pathParts.forEach((part) => {\n if (part.startsWith(\":\")) {\n params.push(part.substring(1));\n }\n });\n\n const routeInfo: HttpRouteInfo = {\n ...config,\n httpMessage: constructor,\n params,\n };\n\n // 存入缓冲区\n httpRouteRegistry.set(routeKey, routeInfo);\n };\n}\n\n/**\n * @description: 系统装饰器\n * @param priority 优先级,数值越大越早执行\n */\nexport function HttpSystem(\n params: SystemParams = {\n priority: 0,\n messageClass: null,\n },\n) {\n return (target: any, key: string, descriptor: PropertyDescriptor) => {\n const originalMethod = descriptor.value;\n // 获得元数据\n const types = Reflect.getMetadata(\"design:paramtypes\", target, key);\n const messageMetadata: MessageMetadata | null =\n Reflect.getMetadata(VIRID_EXPRESS_METADATA.MESSAGE, target, key) || null;\n const httpMetadata = getHttpMetadata(target, key, types);\n // 参数检查\n if (!types) {\n const error = new Error(\n `[Virid HttpSystem] System Parameter Loss:\\nUnable to recognize system parameters, please confirm if import \"reflection-metadata\" was introduced at the beginning!`,\n );\n MessageWriter.error(error);\n return;\n }\n // 检查是否有参数类型丢失\n if (types.some((t: any) => t === undefined)) {\n const error =\n new Error(`[Virid HttpSystem] Parameter Metadata Loss in \"${key}\": \n One or more parameters have 'undefined' types. \n This usually happens when you forget to add a type annotation to a decorated parameter.\n Check parameter at index: ${types.indexOf(undefined)}`);\n MessageWriter.error(error);\n return;\n }\n\n // 不能同时使用@message() 和 SystemParams\n if (params.messageClass && messageMetadata) {\n MessageWriter.error(\n new Error(\n `[Virid HttpSystem] Multiple Messages Are Not Allowed: Cannot use @ message() and SystemParams simultaneously in ${key}`,\n ),\n );\n return;\n }\n // @message() 和 SystemParams至少得有一个\n if (!params.messageClass && !messageMetadata) {\n MessageWriter.error(\n new Error(\n `[Virid HttpSystem] System Parameter Loss:\\nPlease declare the message type using the Message decorator`,\n ),\n );\n return;\n }\n // Message必须是继承自HttpRequestMessage\n const messageClass = params.messageClass ?? messageMetadata!.messageClass;\n if (!(messageClass.prototype instanceof HttpRequestMessage)) {\n MessageWriter.error(\n new Error(\n `[Virid HttpSystem] Wrong Message Type: ${messageClass.name} is not a derived subclass of HttpRequestMessage!`,\n ),\n );\n return;\n }\n //封装system\n const wrappedSystem = (currentMessage: HttpRequestMessage) => {\n // 获取当前请求的上下文\n const context = httpContextStore.get(currentMessage.requestId);\n if (!context) {\n //如果没有context,那直接停止执行\n throw new Error(\n `[Virid Express HttpSystem] Invalid Request Context: The request context for message ${currentMessage.requestId} is missing.`,\n );\n }\n try {\n const args = types.map((type: any, index: number) => {\n // 如果是message,则注入\n // 三个条件缺一不可\n if (messageMetadata && messageMetadata.index == index) {\n if (!(currentMessage instanceof messageClass)) {\n // 如果类型不匹配,说明 Dispatcher 路由逻辑或元数据配置有问题\n const receivedName = (currentMessage as object).constructor.name;\n throw new Error(\n `[Virid Express HttpSystem] Type Mismatch: Expected ${messageClass.name}, but received ${receivedName}`,\n );\n }\n return currentMessage;\n } else {\n return getHttpSystemArgs(type, index, context, httpMetadata);\n }\n });\n // 执行业务逻辑\n const result = originalMethod.apply(target, args);\n // 返回值必须是一个新的HttpRequestMessage数组,或者一个HttpResponse类型\n return result instanceof Promise\n ? result\n .then((res) => {\n handleResult(res, context);\n })\n .catch((error) => {\n // 异步出错要给客户端发 500\n handleResult(InternalServerError(), context);\n // 继续抛出,让 Dispatcher 捕获并打印详细堆栈\n throw error;\n })\n : handleResult(result, context);\n } catch (error) {\n if (error instanceof HttpError) {\n // 如果手动 throw new HttpError\n handleResult(error, context);\n } else {\n // 真正的崩溃,返回 500\n handleResult(InternalServerError(), context);\n }\n throw error; // 继续抛出给 Dispatcher 记录日志\n }\n };\n\n // 给包装后的函数挂载上下文信息(供 Dispatcher 读取)\n const systemContext: SystemContext = {\n params: types,\n targetClass: target,\n methodName: key,\n originalMethod: originalMethod,\n };\n (wrappedSystem as any).systemContext = systemContext;\n // 修改方法定义\n descriptor.value = wrappedSystem;\n // 注册到调度中心\n stagingSystemRegister.register(\n messageClass,\n wrappedSystem,\n params.priority,\n );\n };\n}\n\n/**\n * @description: 标记参数为 Body\n */\n\nexport function Body() {\n return (target: any, key: string, index: number) => {\n if (Reflect.hasOwnMetadata(VIRID_EXPRESS_METADATA.BODY, target, key)) {\n MessageWriter.error(\n new Error(\n `[Virid Express Body] Multiple Body Are Not Allowed: ${key} has multiple @Body() decorators!`,\n ),\n );\n return;\n }\n const bodyMetadata = { index } as BodyMetadata;\n Reflect.defineMetadata(\n VIRID_EXPRESS_METADATA.BODY,\n bodyMetadata,\n target,\n key,\n );\n };\n}\n\n/**\n * @description: 标记参数为 Header\n */\n\nexport function Headers() {\n return (target: any, key: string, index: number) => {\n if (Reflect.hasOwnMetadata(VIRID_EXPRESS_METADATA.HEADERS, target, key)) {\n MessageWriter.error(\n new Error(\n `[Virid Express Headers] Multiple Header Are Not Allowed: ${key} has multiple @Headers() decorators!`,\n ),\n );\n return;\n }\n const headerMetadata = { index } as HeaderMetadata;\n Reflect.defineMetadata(\n VIRID_EXPRESS_METADATA.HEADERS,\n headerMetadata,\n target,\n key,\n );\n };\n}\n\n/**\n * @description: 标记参数为 Header\n */\n\nexport function Cookies() {\n return (target: any, key: string, index: number) => {\n if (Reflect.hasOwnMetadata(VIRID_EXPRESS_METADATA.COOKIES, target, key)) {\n MessageWriter.error(\n new Error(\n `[Virid Express Cookies] Multiple Header Are Not Allowed: ${key} has multiple @Cookies() decorators!`,\n ),\n );\n return;\n }\n const cookiesMetadata = { index } as CookieMetadata;\n Reflect.defineMetadata(\n VIRID_EXPRESS_METADATA.COOKIES,\n cookiesMetadata,\n target,\n key,\n );\n };\n}\n\n/**\n * @description: 标记参数为 Request 对象\n */\nexport function Req() {\n return (target: any, key: string, index: number) => {\n // 检查是否已经定义过 Request 元数据,防止一个方法注入多个 Request 参数\n if (Reflect.hasOwnMetadata(VIRID_EXPRESS_METADATA.REQUEST, target, key)) {\n MessageWriter.error(\n new Error(\n `[Virid Express Req] Multiple Request Objects Are Not Allowed: ${key} has multiple @Req() decorators!`,\n ),\n );\n return;\n }\n const requestMetadata: RequestMetadata = { index };\n Reflect.defineMetadata(\n VIRID_EXPRESS_METADATA.REQUEST,\n requestMetadata,\n target,\n key,\n );\n };\n}\n\n/**\n * @description: 标记参数为 Response 对象\n */\nexport function Res() {\n return (target: any, key: string, index: number) => {\n // 检查是否已经定义过 Response 元数据\n if (Reflect.hasOwnMetadata(VIRID_EXPRESS_METADATA.RESPONSE, target, key)) {\n MessageWriter.error(\n new Error(\n `[Virid Express Res] Multiple Response Objects Are Not Allowed: ${key} has multiple @Res() decorators!`,\n ),\n );\n return;\n }\n const responseMetadata: ResponseMetadata = { index };\n Reflect.defineMetadata(\n VIRID_EXPRESS_METADATA.RESPONSE,\n responseMetadata,\n target,\n key,\n );\n };\n}\n\n/**\n * @description: 标记参数为 Context 对象\n */\nexport function Ctx() {\n return (target: any, key: string, index: number) => {\n // 检查是否已经定义过 context 元数据\n if (Reflect.hasOwnMetadata(VIRID_EXPRESS_METADATA.CONTEXT, target, key)) {\n MessageWriter.error(\n new Error(\n `[Virid Express Ctx] Multiple Context Objects Are Not Allowed: ${key} has multiple @Ctx() decorators!`,\n ),\n );\n return;\n }\n const contextMetadata: ContextMetadata = { index };\n Reflect.defineMetadata(\n VIRID_EXPRESS_METADATA.CONTEXT,\n contextMetadata,\n target,\n key,\n );\n };\n}\n\n/**\n * @description: 标记参数为 Query\n */\nexport function Query(query: string, pipe?: TransformPipe<any>) {\n return (target: any, key: string, index: number) => {\n const existingMetadata: QueryMetadata =\n Reflect.getOwnMetadata(VIRID_EXPRESS_METADATA.QUERY, target, key) || [];\n const newMetadata = [...existingMetadata, { index, query, pipe }];\n Reflect.defineMetadata(\n VIRID_EXPRESS_METADATA.QUERY,\n newMetadata,\n target,\n key,\n );\n };\n}\n\n/**\n * @description: 标记参数为指定的路径参数 (如 /user/:id)\n */\nexport function Params(key?: string, pipe?: TransformPipe<any>) {\n return (target: any, keyName: string, index: number) => {\n const existingMetadata: ParamMetadata =\n Reflect.getOwnMetadata(VIRID_EXPRESS_METADATA.PARAMS, target, keyName) ||\n [];\n const newMetadata = [...existingMetadata, { index, key, pipe }];\n Reflect.defineMetadata(\n VIRID_EXPRESS_METADATA.PARAMS,\n newMetadata,\n target,\n keyName,\n );\n };\n}\n/**\n * @description: 获得各种元数据\n */\nfunction getHttpMetadata(target: any, key: string, types: any[]) {\n // 获取所有的元数据配置\n const bodyMeta: BodyMetadata = Reflect.getOwnMetadata(\n VIRID_EXPRESS_METADATA.BODY,\n target,\n key,\n );\n const headerMeta: HeaderMetadata = Reflect.getOwnMetadata(\n VIRID_EXPRESS_METADATA.HEADERS,\n target,\n key,\n );\n const cookiesMeta: CookieMetadata = Reflect.getOwnMetadata(\n VIRID_EXPRESS_METADATA.COOKIES,\n target,\n key,\n );\n\n const resMeta: ResponseMetadata = Reflect.getOwnMetadata(\n VIRID_EXPRESS_METADATA.RESPONSE,\n target,\n key,\n );\n const reqMeta: RequestMetadata = Reflect.getOwnMetadata(\n VIRID_EXPRESS_METADATA.REQUEST,\n target,\n key,\n );\n const ctxMeta: ContextMetadata = Reflect.getOwnMetadata(\n VIRID_EXPRESS_METADATA.CONTEXT,\n target,\n key,\n );\n const rawQueryMeta: QueryMetadata =\n Reflect.getOwnMetadata(VIRID_EXPRESS_METADATA.QUERY, target, key) || [];\n const queryMeta = rawQueryMeta.map((item) => {\n // 如果没指定 pipe,根据 types[item.index] 自动分配\n if (!item.pipe) {\n const paramType = types[item.index];\n item.pipe = getAutoPipe(paramType);\n }\n return item;\n });\n const rawParamMeta: ParamMetadata =\n Reflect.getOwnMetadata(VIRID_EXPRESS_METADATA.PARAMS, target, key) || [];\n const paramMeta = rawParamMeta.map((item) => {\n if (!item.pipe) {\n const paramType = types[item.index];\n item.pipe = getAutoPipe(paramType);\n }\n return item;\n });\n return {\n bodyMeta,\n headerMeta,\n queryMeta,\n cookiesMeta,\n reqMeta,\n resMeta,\n ctxMeta,\n paramMeta,\n };\n}\n\nfunction getHttpSystemArgs(\n type: any,\n index: number,\n context: HttpContext,\n httpMetadata: ReturnType<typeof getHttpMetadata>,\n): any {\n const { req, res } = context;\n\n // 匹配 @Ctx()\n if (httpMetadata.ctxMeta?.index === index) return context;\n\n // 匹配 @Param() -> 获取路由参数 (:id 等)\n const paramItem = httpMetadata.paramMeta?.find((p) => p.index === index);\n if (paramItem) {\n let val = paramItem.key ? req.params[paramItem.key] : req.params;\n\n // 如果有 Pipe 且值不是 undefined,进行转换\n if (paramItem.pipe && val !== undefined) {\n val = paramItem.pipe(val);\n }\n return val;\n }\n\n // 匹配 @Body() -> 获取请求体\n if (httpMetadata.bodyMeta?.index === index) return req.body;\n\n // 匹配 @Header() -> 获取请求头\n if (httpMetadata.headerMeta?.index === index) return req.headers;\n\n // 匹配 @Cookie() -> 获取Cookie\n if (httpMetadata.cookiesMeta?.index === index)\n return parseRawCookie(req.headers.cookie);\n\n // 匹配 @Req() 和 @Res() -> 原生 Express 对象\n if (httpMetadata.reqMeta?.index === index) return req;\n if (httpMetadata.resMeta?.index === index) return res;\n\n // 匹配 @Query('name') -> 获取特定的 Query 参数\n const queryItem = httpMetadata.queryMeta?.find((q) => q.index === index);\n if (queryItem) {\n let val = req.query[queryItem.query];\n if (val === undefined) {\n throw new Error(`[Virid Express] Missing Query: \"${queryItem.query}\"`);\n }\n\n // 执行 Pipe 转换\n if (queryItem.pipe) {\n val = queryItem.pipe(val);\n }\n return val;\n }\n\n // 处理普通的 IOC 容器依赖注入 (DI)\n const param = viridApp.get(type);\n if (!param) {\n throw new Error(\n `[Virid System] Unknown Inject Type: ${type?.name || \"Anonymous Class\"} at index ${index}. \n Ensure it is registered in the IOC container or has a proper Http Decorator!`,\n );\n }\n\n return param;\n}\n","/*\n * Copyright (c) 2026-present Ailrid.\n * Licensed under the Apache License, Version 2.0.\n * Project: Virid Express\n */\nimport { VIRID_METADATA } from \"@virid/core\";\n\nexport const VIRID_EXPRESS_METADATA = {\n ...VIRID_METADATA,\n HTTPROUTE: \"virid:express:route\",\n HTTPSYSTEM: \"virid:express:system\",\n BODY: \"virid:express:body\",\n QUERY: \"virid:express:query\",\n HEADERS: \"virid:express:header\",\n REQUEST: \"virid:express:request\",\n RESPONSE: \"virid:express:response\",\n CONTEXT: \"virid:express:context\",\n PARAMS: \"virid:express:params\",\n COOKIES: \"virid:express:cookie\",\n} as const;\n"],"mappings":"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","names":["index_exports","__export","BadRequest","BadRequestResponse","Body","ConflictResponse","Cookies","Created","CreatedResponse","Ctx","CustomResponse","CustomResponseResponse","ExpressPlugin","Forbidden","ForbiddenResponse","Headers","HttpContext","HttpError","HttpRequestMessage","HttpResponse","HttpRoute","HttpSystem","InternalServerError","InternalServerErrorResponse","NoContent","NoContentResponse","NotFound","NotFoundResponse","Ok","OkResponse","Params","ParseBoolPipe","ParseIntPipe","Query","Req","Res","Stream","StreamFile","StreamFileResponse","StreamResponse","Unauthorized","UnauthorizedResponse","UnprocessableEntityResponse","addAutoPipe","getAutoPipe","parseRawCookie","__toCommonJS","import_core","import_core","import_core","import_core","HttpContext","id","req","res","timestamp","route","rc","isClosed","inc","dec","tryFinalize","writableEnded","errorMsg","Date","now","MessageWriter","error","Error","headersSent","end","status","json","message","_HttpContext","HttpResponse","data","headers","_HttpResponse","OkResponse","_OkResponse","CreatedResponse","_CreatedResponse","NoContentResponse","_NoContentResponse","BadRequestResponse","_BadRequestResponse","UnauthorizedResponse","_UnauthorizedResponse","ForbiddenResponse","_ForbiddenResponse","NotFoundResponse","_NotFoundResponse","ConflictResponse","_ConflictResponse","UnprocessableEntityResponse","errors","_UnprocessableEntityResponse","InternalServerErrorResponse","_InternalServerErrorResponse","CustomResponseResponse","_CustomResponseResponse","StreamFileResponse","filePath","options","dotfiles","_StreamFileResponse","StreamResponse","stream","_StreamResponse","Ok","__name","Created","NoContent","BadRequest","msg","Unauthorized","Forbidden","NotFound","InternalServerError","CustomResponse","StreamFile","path","Stream","HttpError","_HttpError","httpContextStore","Map","handleResult","res","context","dec","Array","isArray","forEach","item","HttpResponse","handleHttpResponse","HttpError","status","json","message","delete","id","BaseMessage","MessageWriter","write","warn","response","ctx","headers","Object","entries","k","v","setHeader","StreamFileResponse","inc","sendFile","filePath","options","err","headersSent","error","end","isClosed","StreamResponse","stream","pipe","cleanup","__name","has","on","data","import_core","ParseIntPipe","val","res","parseInt","isNaN","HttpError","ParseBoolPipe","autoPipeMap","Map","set","Number","Boolean","addAutoPipe","type","pipe","has","MessageWriter","error","Error","getAutoPipe","get","parseRawCookie","cookieHeader","result","pairs","split","pair","indexOfEq","indexOf","key","substring","trim","value","length","slice","includes","decodeURIComponent","import_core","HttpRequestMessage","EventMessage","__virid_express_id","httpContextStore","get","inc","requestId","_HttpRequestMessage","stagingSystemRegister","MessageRegistry","httpRouteRegistry","Map","_internalHttpIdCounter","registerHttpSystem","app","messageClass","systemTasks","systemTaskMap","entries","task","register","fn","priority","clear","registerHttpRoute","server","_","routeInfo","method","path","httpMessage","expressMethod","toLowerCase","req","res","newId","httpContextStore","set","HttpContext","Date","now","message","once","delete","MessageWriter","write","activeApp","activateApp","app","options","registerHttpSystem","registerHttpRoute","server","viridApp","Proxy","get","_","prop","args","MessageWriter","warn","String","targetMethod","Reflect","apply","import_core","import_core","VIRID_EXPRESS_METADATA","VIRID_METADATA","HTTPROUTE","HTTPSYSTEM","BODY","QUERY","HEADERS","REQUEST","RESPONSE","CONTEXT","PARAMS","COOKIES","HttpRoute","config","constructor","routeKey","method","path","httpRouteRegistry","has","MessageWriter","error","Error","name","params","split","forEach","part","startsWith","push","substring","routeInfo","httpMessage","set","HttpSystem","priority","messageClass","target","key","descriptor","originalMethod","value","types","Reflect","getMetadata","messageMetadata","VIRID_EXPRESS_METADATA","MESSAGE","httpMetadata","getHttpMetadata","some","t","undefined","indexOf","prototype","HttpRequestMessage","wrappedSystem","__name","currentMessage","context","httpContextStore","get","requestId","args","map","type","index","receivedName","getHttpSystemArgs","result","apply","Promise","then","res","handleResult","catch","InternalServerError","HttpError","systemContext","targetClass","methodName","stagingSystemRegister","register","Body","hasOwnMetadata","BODY","bodyMetadata","defineMetadata","Headers","HEADERS","headerMetadata","Cookies","COOKIES","cookiesMetadata","Req","REQUEST","requestMetadata","Res","RESPONSE","responseMetadata","Ctx","CONTEXT","contextMetadata","Query","query","pipe","newMetadata","getOwnMetadata","QUERY","Params","keyName","PARAMS","bodyMeta","headerMeta","cookiesMeta","resMeta","reqMeta","ctxMeta","queryMeta","item","paramType","getAutoPipe","paramMeta","req","paramItem","find","p","val","body","headers","parseRawCookie","cookie","queryItem","q","param","viridApp","ExpressPlugin","name","install","app","options","activateApp"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/http/response.ts","../src/http/utils.ts","../src/http/message.ts","../src/decorators/constant.ts","../src/decorators/decorator.ts"],"sourcesContent":["/*\n * Copyright (c) 2026-present Ailrid\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Description: Add express functionality to virid.\n */\nimport {\n ViridPlugin,\n type ViridApp,\n MessageRegistry,\n MessageWriter,\n Newable,\n SystemContext,\n BaseMessage,\n} from \"@virid/core\";\nimport { getHttpArgs } from \"./decorators\";\nimport {\n HttpSystemConfig,\n type HttpMethod,\n type HttpRouteInfo,\n} from \"./interfaces\";\n\nimport {\n HttpContext,\n HttpError,\n HttpRequestMessage,\n HttpResponse,\n InternalServerError,\n RequestId,\n StreamFileResponse,\n StreamResponse,\n} from \"./http\";\n\nimport { PluginOptions } from \"./interfaces\";\nimport { type Request, type Response } from \"express\";\nimport { VIRID_EXPRESS_METADATA } from \"./decorators/constant\";\nexport * from \"./http\";\nexport * from \"./decorators\";\n\nexport class ExpressPlugin implements ViridPlugin<PluginOptions> {\n name = \"@virid/express\";\n // temporary Registry\n private stagingSystemRegister = new MessageRegistry();\n // route Registry\n private httpRouteRegistry = new Map<string, HttpRouteInfo>();\n\n private httpContextStore = new Map<number, HttpContext>();\n\n private _internalHttpIdCounter = 0;\n\n register(systemFn: (...args: any[]) => any): () => void {\n // @ts-expect-error: get systemContext from systemFn\n const systemContext: SystemContext = systemFn.systemContext;\n // @ts-expect-error: get httpSystemConfig from systemFn\n const httpSystemConfig: HttpSystemConfig = systemFn.httpSystemConfig;\n if (!systemContext || !httpSystemConfig) {\n throw new Error(\n `[Virid HttpSystem] HttpSystem Parameter Loss: Please declare ${systemFn.name} using the @HttpSystem decorator first.`,\n );\n }\n this.stagingSystemRegister.register(\n systemContext.targetClass,\n systemFn,\n httpSystemConfig.priority,\n );\n return () => {};\n }\n\n bindRoute(constructor: Newable<HttpRequestMessage>) {\n const config: HttpRouteInfo = Reflect.getMetadata(\n VIRID_EXPRESS_METADATA.HTTPROUTE,\n constructor,\n );\n if (!config) {\n throw new Error(\n `[Virid Http] Routing Error: ${constructor.name} is not a valid HttpRoute`,\n );\n }\n // Uniqueness verification: Combining Method and Path\n const routeKey = `${config.method}:${config.path}`;\n if (this.httpRouteRegistry.has(routeKey)) {\n throw new Error(\n `[Virid Http] Routing Conflict: The request method ${config.method} for path ${config.path} has already been registered by ${constructor.name}`,\n );\n } else {\n this.httpRouteRegistry.set(routeKey, config);\n }\n }\n\n install(app: ViridApp, options: PluginOptions) {\n // register for express routing\n for (const [_, routeInfo] of this.httpRouteRegistry.entries()) {\n const { method, path, httpMessage } = routeInfo;\n const expressMethod = method.toLowerCase() as HttpMethod;\n\n options.server[expressMethod](path, (req: Request, res: Response) => {\n // instantiate Message\n const newId = this._internalHttpIdCounter++ >>> 0;\n\n // save contextual information\n const context = new HttpContext(newId, req, res, Date.now(), path);\n context.inc();\n this.httpContextStore.set(\n newId,\n new HttpContext(newId, req, res, Date.now(), path),\n );\n const message = new httpMessage(newId as RequestId);\n // finish means the response has been sent, close means the connection was unexpectedly interrupted, both should be cleaned up\n res.once(\"finish\", () => this.httpContextStore.delete(newId));\n res.once(\"close\", () => this.httpContextStore.delete(newId));\n // send message\n MessageWriter.write(message);\n });\n }\n\n // register HttpSystem into the app's scheduler\n for (const [\n messageClass,\n systemTasks,\n ] of this.stagingSystemRegister.systemTaskMap.entries()) {\n for (const task of systemTasks) {\n const systemFn = task.fn;\n // @ts-expect-error: get systemContext from systemFn\n const systemContext: SystemContext = systemFn.systemContext;\n // @ts-expect-error: get httpSystemConfig from systemFn\n const httpSystemConfig: HttpSystemConfig = systemFn.httpSystemConfig;\n const { httpMetadata, messageClass, messageIdx } = httpSystemConfig;\n const { originalMethod, targetClass } = systemContext;\n const wrappedSystem = (currentMessage: HttpRequestMessage) => {\n // retrieve the context of the current request\n const context = this.httpContextStore.get(currentMessage.requestId);\n if (!context) {\n throw new Error(\n `[Virid Express HttpSystem] Invalid Request Context: The request context for message ${currentMessage.requestId} is missing.`,\n );\n }\n try {\n const args = systemContext.params.map(\n (type: any, index: number) => {\n // If it is a message, inject\n if (index === messageIdx) {\n return currentMessage;\n } else {\n // Otherwise, try injecting HTTP parameters or components\n const arg = getHttpArgs(index, context, httpMetadata);\n return arg ? arg : app.get(type);\n }\n },\n );\n const result = originalMethod.apply(targetClass, args);\n return result instanceof Promise\n ? result\n .then((res) => {\n this.handleResult(res, context);\n })\n .catch((error) => {\n // asynchronous error needs to send 500 to the client\n this.handleResult(InternalServerError(error), context);\n // continue throwing, let Dispatcher capture and print detailed stack\n throw error;\n })\n : this.handleResult(result, context);\n } catch (error) {\n if (error instanceof HttpError) {\n // if manually throw new HttpError\n this.handleResult(error, context);\n } else {\n // real crash, return 500\n this.handleResult(InternalServerError(error as Error), context);\n }\n throw error; // continue throwing, let Dispatcher capture and print detailed stack\n }\n };\n wrappedSystem.systemContext = systemContext;\n wrappedSystem.httpSystemConfig = httpSystemConfig;\n app.engine.register(messageClass, wrappedSystem, task.priority);\n }\n }\n this.stagingSystemRegister.systemTaskMap.clear();\n }\n\n handleResult(res: any, context: HttpContext) {\n if (!res) {\n context.dec();\n return;\n }\n const results = Array.isArray(res) ? res : [res];\n results.forEach((item) => {\n if (item instanceof HttpResponse) {\n // if it is a termination response, handle it\n this.handleHttpResponse(item, context);\n } else if (item instanceof HttpError) {\n // handling errors\n context.res.status(item.status).json(item.message);\n this.httpContextStore.delete(context.id);\n } else if (item instanceof BaseMessage) {\n MessageWriter.write(item);\n } else {\n MessageWriter.warn(\n `[Virid Express] Invalid Return Type: ${typeof item}. Expected HttpResponse or Message.`,\n );\n }\n });\n //Whether the system encounters an error or completes execution, handleResult will execute with a reference count of -1 and check if it is 0\n //If it is 0 and it has not been closed yet, then force it to close\n //The first scenario: If handleHttpResponse is executed above, then HttpContext has already been deleted before that\n //The second scenario: If the HttpRequestMessage is forwarded above, it will erase the trace of the system execution, but the HttpContext will not be deleted due to reference counting\n //The third scenario: If other messages or return values are forwarded above, the reference count will be -1 and checked if it is 0. If it is 0, it will be forcibly closed\n context.dec();\n }\n\n handleHttpResponse(response: HttpResponse, ctx: HttpContext) {\n const { res } = ctx;\n\n if (response.headers) {\n Object.entries(response.headers).forEach(([k, v]) => res.setHeader(k, v));\n }\n\n if (response.status) res.status(response.status);\n\n if (response instanceof StreamFileResponse) {\n // return asynchronous stream and forcefully add an RC extension\n ctx.inc();\n res.sendFile(response.filePath, response.options, (err) => {\n if (!res.headersSent) {\n MessageWriter.error(\n err,\n `[Virid Express] SteamFile Error: Path: ${response.filePath}`,\n );\n }\n ctx.res.end();\n this.httpContextStore.delete(ctx.id);\n ctx.isClosed = true;\n ctx.dec();\n });\n return;\n }\n if (response instanceof StreamResponse) {\n const { stream } = response;\n ctx.inc();\n stream.pipe(res);\n // end of listening, harvest context\n const cleanup = () => {\n if (!this.httpContextStore.has(ctx.id)) return;\n ctx.res.end();\n this.httpContextStore.delete(ctx.id);\n ctx.isClosed = true;\n ctx.dec();\n };\n stream.on(\"end\", cleanup);\n stream.on(\"error\", (err) => {\n if (!res.headersSent) {\n MessageWriter.error(err, `[Virid Express] Stream Error`);\n }\n cleanup();\n });\n stream.on(\"close\", cleanup);\n return;\n }\n\n res.status(response.status).json(response.data);\n this.httpContextStore.delete(ctx.id);\n }\n}\n","/*\n * Copyright (c) 2026-present Ailrid.\n * Licensed under the Apache License, Version 2.0.\n * Project: Virid Express\n */\nimport { type Request, type Response } from \"express\";\nimport { Readable } from \"stream\";\nimport { MessageWriter } from \"@virid/core\";\ninterface HttpHeaders {\n [key: string]: string | string[];\n}\nexport class HttpContext {\n public rc: number = 0;\n public isClosed: boolean = false;\n\n constructor(\n public readonly id: number,\n public readonly req: Request,\n public readonly res: Response,\n public readonly timestamp: number,\n public readonly route: string,\n ) {}\n\n inc() {\n this.rc++;\n }\n\n dec() {\n this.rc--;\n if (this.rc === 0) {\n this.tryFinalize();\n }\n }\n\n private tryFinalize() {\n if (this.res.writableEnded || this.isClosed) return;\n\n this.isClosed = true;\n\n const errorMsg = `[Virid Express] Request Orphaned: The connection was closed because all systems finished execution without sending a response. \n Route: ${this.route}\n Uptime: ${Date.now() - this.timestamp}ms`;\n\n MessageWriter.error(new Error(errorMsg));\n\n if (!this.res.headersSent) {\n this.res.status(500).json({\n error: \"Internal Logic Error\",\n message:\n \"Request processed but no response was returned by any system.\",\n });\n } else {\n this.res.end();\n }\n }\n}\n\nexport abstract class HttpResponse {\n constructor(\n public status: number,\n public data: any = null,\n public headers: HttpHeaders = {},\n ) {}\n}\n\n// --- 2xx Success ---\nexport class OkResponse extends HttpResponse {\n constructor(data: any, headers: HttpHeaders = {}) {\n super(200, data, headers);\n }\n}\n\nexport class CreatedResponse extends HttpResponse {\n constructor(data: any, headers: HttpHeaders = {}) {\n super(201, data, headers);\n }\n}\n\nexport class NoContentResponse extends HttpResponse {\n constructor() {\n super(204, null);\n }\n}\n\n// --- 4xx Client Error ---\nexport class BadRequestResponse extends HttpResponse {\n constructor(message: string = \"Bad Request\") {\n super(400, { error: message });\n }\n}\n\nexport class UnauthorizedResponse extends HttpResponse {\n constructor(message: string = \"Unauthorized\") {\n super(401, { error: message });\n }\n}\n\nexport class ForbiddenResponse extends HttpResponse {\n constructor(message: string = \"Forbidden\") {\n super(403, { error: message });\n }\n}\n\nexport class NotFoundResponse extends HttpResponse {\n constructor(message: string = \"Not Found\") {\n super(404, { error: message });\n }\n}\n\nexport class ConflictResponse extends HttpResponse {\n constructor(message: string = \"Conflict\") {\n super(409, { error: message });\n }\n}\n\nexport class UnprocessableEntityResponse extends HttpResponse {\n constructor(errors: any) {\n super(422, { errors });\n }\n}\n\n// --- 5xx Server Error ---\nexport class InternalServerErrorResponse extends HttpResponse {\n constructor(message: string = \"Internal Server Error\") {\n super(500, { error: message });\n }\n}\n\n// --- 万能类 (Custom) ---\nexport class CustomResponseResponse extends HttpResponse {\n constructor(status: number, data: any, headers: HttpHeaders = {}) {\n super(status, data, headers);\n }\n}\n/**\n * @description: Express sendFile 配置项的强类型定义\n */\nexport interface StreamFileOptions {\n /** 根目录(如果 path 是相对路径则必填) */\n root?: string;\n /** * 对以 . 开头的文件处理策略:\n * - allow: 允许发送\n * - deny: 拒绝并返回 403\n * - ignore: 当作不存在返回 404\n */\n dotfiles?: \"allow\" | \"deny\" | \"ignore\";\n /** 是否发送 ETag */\n etag?: boolean;\n /** 扩展的 HTTP 响应头 */\n headers?: HttpHeaders;\n /** 缓存最大时长 (毫秒) */\n maxAge?: number | string;\n /** 是否在 Cache-Control 中添加 immutable */\n immutable?: boolean;\n /** 是否根据文件系统设置 Last-Modified */\n lastModified?: boolean;\n /** 是否支持断点续传 (Range 请求) */\n acceptRanges?: boolean;\n}\nexport class StreamFileResponse extends HttpResponse {\n constructor(\n public readonly filePath: string,\n public readonly options: StreamFileOptions = { dotfiles: \"allow\" },\n ) {\n super(206, options);\n }\n}\n\nexport class StreamResponse extends HttpResponse {\n constructor(\n public readonly stream: Readable,\n public readonly options: {\n status?: number;\n headers?: HttpHeaders;\n } = {},\n ) {\n super(options.status || 206, {}, options.headers);\n }\n}\n\n/** 200 OK */\nexport const Ok = (data: any, headers: HttpHeaders = {}) =>\n new OkResponse(data, headers);\n\n/** 201 Created */\nexport const Created = (data: any, headers: HttpHeaders = {}) =>\n new CreatedResponse(data, headers);\n\n/** 204 No Content */\nexport const NoContent = () => new NoContentResponse();\n\n/** 400 Bad Request */\nexport const BadRequest = (msg = \"Bad Request\") => new BadRequestResponse(msg);\n\n/** 401 Unauthorized */\nexport const Unauthorized = (msg = \"Unauthorized\") =>\n new UnauthorizedResponse(msg);\n\n/** 403 Forbidden */\nexport const Forbidden = (msg = \"Forbidden\") => new ForbiddenResponse(msg);\n\n/** 404 Not Found */\nexport const NotFound = (msg = \"Not Found\") => new NotFoundResponse(msg);\n\n/** 500 Internal Error */\nexport const InternalServerError = (\n msg: string | Error = \"Internal Server Error\",\n) => {\n return msg instanceof Error\n ? new InternalServerErrorResponse(msg.message)\n : new InternalServerErrorResponse(msg);\n};\n\nexport const CustomResponse = (\n status: number,\n data: any,\n headers: HttpHeaders = {},\n) => new CustomResponseResponse(status, data, headers);\n\n/** 发送本地文件 (自动处理 Range/206) */\nexport const StreamFile = (path: string, options?: StreamFileOptions) =>\n new StreamFileResponse(path, options);\n/**\n * 发送流响应\n */\nexport const Stream = (stream: Readable, options?: StreamResponse[\"options\"]) =>\n new StreamResponse(stream, options);\n\nexport class HttpError extends Error {\n constructor(\n public readonly status: number,\n public readonly message: string,\n ) {\n super(message);\n }\n}\n","/*\n * Copyright (c) 2026-present Ailrid.\n * Licensed under the Apache License, Version 2.0.\n * Project: Virid Express\n */\nimport { MessageWriter } from \"@virid/core\";\nimport { HttpError } from \".\";\nimport { type TransformPipe } from \"../interfaces\";\n\nexport function ParseIntPipe(val: string) {\n const res = parseInt(val, 10);\n if (isNaN(res))\n throw new HttpError(400, `Validation failed: \"${val}\" is not a number.`);\n return res;\n}\n\nexport function ParseBoolPipe(val: string) {\n if (val === \"true\" || val === \"1\") return true;\n if (val === \"false\" || val === \"0\") return false;\n return !!val;\n}\n\nconst autoPipeMap = new Map<any, TransformPipe<any>>();\nautoPipeMap.set(Number, ParseIntPipe);\nautoPipeMap.set(Boolean, ParseBoolPipe);\n\nexport function addAutoPipe<T>(type: T, pipe: TransformPipe<T>) {\n if (autoPipeMap.has(type)) {\n MessageWriter.error(\n new Error(\n `[Virid Express Pipe] Repeated Pipe: Auto pipe for ${type} has already been registered.`,\n ),\n );\n return;\n }\n autoPipeMap.set(type, pipe);\n}\n\nexport function getAutoPipe<T>(type: T): TransformPipe<T> | undefined {\n return autoPipeMap.get(type);\n}\n\nexport function parseRawCookie(\n cookieHeader: string | undefined,\n): Record<string, string> {\n const result: Record<string, string> = {};\n\n if (!cookieHeader) return result;\n const pairs = cookieHeader.split(\";\");\n\n for (const pair of pairs) {\n const indexOfEq = pair.indexOf(\"=\");\n if (indexOfEq === -1) continue;\n\n // 提取 key 和 value,并进行 trim 处理\n const key = pair.substring(0, indexOfEq).trim();\n if (!key) continue;\n\n let value = pair.substring(indexOfEq + 1).trim();\n\n if (value[0] === '\"' && value[value.length - 1] === '\"') {\n value = value.slice(1, -1);\n }\n\n try {\n result[key] = value.includes(\"%\") ? decodeURIComponent(value) : value;\n } catch (e) {\n result[key] = value;\n }\n }\n\n return result;\n}\n","/*\n * Copyright (c) 2026-present Ailrid.\n * Licensed under the Apache License, Version 2.0.\n * Project: Virid Express\n */\nimport { EventMessage } from \"@virid/core\";\nexport type RequestId = number & { readonly __brand: unique symbol };\n\nexport class HttpRequestMessage extends EventMessage {\n // ID must be of type RequestId\n constructor(private readonly __virid_express_id: RequestId) {\n super();\n }\n // expose a read-only attribute for use by the business layer\n public get requestId(): RequestId {\n return this.__virid_express_id;\n }\n}\n","/*\n * Copyright (c) 2026-present Ailrid.\n * Licensed under the Apache License, Version 2.0.\n * Project: Virid Express\n */\nimport { VIRID_METADATA } from \"@virid/core\";\n\nexport const VIRID_EXPRESS_METADATA = {\n ...VIRID_METADATA,\n HTTPROUTE: \"virid:express:route\",\n HTTPSYSTEM: \"virid:express:system\",\n BODY: \"virid:express:body\",\n QUERY: \"virid:express:query\",\n HEADERS: \"virid:express:header\",\n REQUEST: \"virid:express:request\",\n RESPONSE: \"virid:express:response\",\n CONTEXT: \"virid:express:context\",\n PARAMS: \"virid:express:params\",\n COOKIES: \"virid:express:cookie\",\n} as const;\n","/*\n * Copyright (c) 2026-present Ailrid.\n * Licensed under the Apache License, Version 2.0.\n * Project: Virid Express\n */\nimport { type Newable, type SystemContext } from \"@virid/core\";\nimport {\n type HttpRouteConfig,\n type HttpRouteInfo,\n type BodyMetadata,\n type HeaderMetadata,\n type QueryMetadata,\n type RequestMetadata,\n type ResponseMetadata,\n type ContextMetadata,\n type ParamMetadata,\n type TransformPipe,\n type CookieMetadata,\n type HttpSystemParams,\n type HttpMetadata,\n type HttpSystemConfig,\n} from \"../interfaces\";\nimport { HttpContext, HttpRequestMessage, parseRawCookie } from \"../http\";\n\nimport { VIRID_EXPRESS_METADATA } from \"./constant\";\n\nexport function HttpRoute(config: HttpRouteConfig) {\n return (constructor: Newable<HttpRequestMessage>) => {\n const params: string[] = [];\n const pathParts = config.path.split(\"/\");\n pathParts.forEach((part) => {\n if (part.startsWith(\":\")) {\n params.push(part.substring(1));\n }\n });\n\n const routeInfo: HttpRouteInfo = {\n ...config,\n httpMessage: constructor,\n params,\n };\n Reflect.defineMetadata(\n VIRID_EXPRESS_METADATA.HTTPROUTE,\n routeInfo,\n constructor,\n );\n };\n}\n\n/**\n * Check if there are multiple message type parameters in the parameters\n * @param types Parameter list\n */\nfunction checkMessageParam(types: Array<any>) {\n const foundMatches: { type: Newable<HttpRequestMessage>; idx: number }[] = [];\n\n types.forEach((type, idx) => {\n const isHttpRequestMessage =\n type === HttpRequestMessage ||\n (type && type.prototype instanceof HttpRequestMessage);\n\n if (isHttpRequestMessage) {\n foundMatches.push({ type, idx });\n }\n });\n\n if (foundMatches.length === 0) {\n return null;\n }\n\n if (foundMatches.length > 1) {\n const errorDetails = foundMatches\n .map((item) => `[Index: ${item.idx}, Name: ${item.type.name}]`)\n .join(\", \");\n\n throw new Error(\n `[Virid System] Multiple Messages: Multiple Message type parameters detected, this is not allowed! specific location: ${errorDetails}`,\n );\n }\n\n return foundMatches[0];\n}\n\n/**\n * @description: 系统装饰器\n * @param priority 优先级,数值越大越早执行\n */\nexport function HttpSystem(\n params: HttpSystemParams = {\n priority: 0,\n messageClass: null,\n },\n) {\n return (target: any, key: string, descriptor: PropertyDescriptor) => {\n if (typeof target !== \"function\") {\n throw new Error(\n `[Virid System] Method Type Error: The Method ${key} is not a static method, please check if there is a static keyword tag.`,\n );\n }\n\n const originalMethod = descriptor.value;\n const types: Array<any> = Reflect.getMetadata(\n \"design:paramtypes\",\n target,\n key,\n );\n\n // Verify if metadata exists\n if (!types) {\n throw new Error(\n `[Virid System] System Parameter Loss: Unable to recognize system parameters, please confirm if import \"reflect-metadata\" was introduced at the beginning.`,\n );\n }\n\n // Verify if there are undefined parameters\n const undefinedIndices = types\n .map((t, i) => (t === undefined ? i : -1))\n .filter((i) => i !== -1);\n if (undefinedIndices.length > 0) {\n throw new Error(\n `[Virid System] Parameter Metadata Loss in \"${key}\": One or more parameters have 'undefined' types. This usually happens when you forget to add a type annotation or due to circular dependencies. Check parameter at indices: [${undefinedIndices.join(\", \")}]`,\n );\n }\n\n let messageClass: Newable<HttpRequestMessage>;\n // eslint-disable-next-line no-useless-assignment\n let messageIdx: number = -1;\n const matchedMessage = checkMessageParam(types); // { type: any, idx: number } | null\n if (matchedMessage && params.messageClass) {\n throw new Error(\n `[Virid System] Multiple Messages Are Not Allowed: Cannot specify messageClass in decorator options while already declaring it in method parameters at index ${matchedMessage.idx} in ${key}.`,\n );\n }\n\n if (matchedMessage) {\n messageClass = matchedMessage.type;\n messageIdx = matchedMessage.idx; // In single mode, idx points to the location of a specific BaseMessage subclass\n } else if (params.messageClass) {\n messageClass = params.messageClass;\n messageIdx = -1; // Only provided in the configuration, cannot be found in the parameters, set to -1\n } else {\n throw new Error(\n `[Virid System] System Parameter Loss: Please declare the message type either in method parameters or via the Message decorator options.`,\n );\n }\n const httpMetadata = getHttpMetadata(target, key);\n\n // Attach contextual information to the packaged function\n const systemContext: SystemContext = {\n params: types,\n targetClass: target,\n methodName: key,\n originalMethod: originalMethod,\n };\n const httpSystemConfig: HttpSystemConfig = {\n httpMetadata: httpMetadata,\n messageClass: messageClass,\n messageIdx: messageIdx,\n priority: params.priority || 0,\n batchMode: false,\n };\n\n // Purely mounting data without changing the execution logic of the original method\n (descriptor.value as any).systemContext = systemContext;\n (descriptor.value as any).httpSystemConfig = httpSystemConfig;\n };\n}\n\nexport function Body() {\n return (target: any, key: string, index: number) => {\n if (Reflect.hasOwnMetadata(VIRID_EXPRESS_METADATA.BODY, target, key)) {\n throw new Error(\n `[Virid Express Body] Multiple Body Are Not Allowed: ${key} has multiple @Body() decorators!`,\n );\n }\n const bodyMetadata = { index } as BodyMetadata;\n Reflect.defineMetadata(\n VIRID_EXPRESS_METADATA.BODY,\n bodyMetadata,\n target,\n key,\n );\n };\n}\n\nexport function Headers() {\n return (target: any, key: string, index: number) => {\n if (Reflect.hasOwnMetadata(VIRID_EXPRESS_METADATA.HEADERS, target, key)) {\n throw new Error(\n `[Virid Express Headers] Multiple Header Are Not Allowed: ${key} has multiple @Headers() decorators!`,\n );\n }\n const headerMetadata = { index } as HeaderMetadata;\n Reflect.defineMetadata(\n VIRID_EXPRESS_METADATA.HEADERS,\n headerMetadata,\n target,\n key,\n );\n };\n}\n\nexport function Cookies() {\n return (target: any, key: string, index: number) => {\n if (Reflect.hasOwnMetadata(VIRID_EXPRESS_METADATA.COOKIES, target, key)) {\n throw new Error(\n `[Virid Express Cookies] Multiple Header Are Not Allowed: ${key} has multiple @Cookies() decorators!`,\n );\n }\n const cookiesMetadata = { index } as CookieMetadata;\n Reflect.defineMetadata(\n VIRID_EXPRESS_METADATA.COOKIES,\n cookiesMetadata,\n target,\n key,\n );\n };\n}\n\nexport function Req() {\n return (target: any, key: string, index: number) => {\n if (Reflect.hasOwnMetadata(VIRID_EXPRESS_METADATA.REQUEST, target, key)) {\n throw new Error(\n `[Virid Express Req] Multiple Request Objects Are Not Allowed: ${key} has multiple @Req() decorators!`,\n );\n }\n const requestMetadata: RequestMetadata = { index };\n Reflect.defineMetadata(\n VIRID_EXPRESS_METADATA.REQUEST,\n requestMetadata,\n target,\n key,\n );\n };\n}\n\nexport function Res() {\n return (target: any, key: string, index: number) => {\n if (Reflect.hasOwnMetadata(VIRID_EXPRESS_METADATA.RESPONSE, target, key)) {\n throw new Error(\n `[Virid Express Res] Multiple Response Objects Are Not Allowed: ${key} has multiple @Res() decorators!`,\n );\n }\n const responseMetadata: ResponseMetadata = { index };\n Reflect.defineMetadata(\n VIRID_EXPRESS_METADATA.RESPONSE,\n responseMetadata,\n target,\n key,\n );\n };\n}\n\nexport function Ctx() {\n return (target: any, key: string, index: number) => {\n if (Reflect.hasOwnMetadata(VIRID_EXPRESS_METADATA.CONTEXT, target, key)) {\n throw new Error(\n `[Virid Express Ctx] Multiple Context Objects Are Not Allowed: ${key} has multiple @Ctx() decorators!`,\n );\n }\n const contextMetadata: ContextMetadata = { index };\n Reflect.defineMetadata(\n VIRID_EXPRESS_METADATA.CONTEXT,\n contextMetadata,\n target,\n key,\n );\n };\n}\n\nexport function Query(query: string, pipe?: TransformPipe<any>) {\n return (target: any, key: string, index: number) => {\n const existingMetadata: QueryMetadata =\n Reflect.getOwnMetadata(VIRID_EXPRESS_METADATA.QUERY, target, key) || [];\n const newMetadata = [...existingMetadata, { index, query, pipe }];\n Reflect.defineMetadata(\n VIRID_EXPRESS_METADATA.QUERY,\n newMetadata,\n target,\n key,\n );\n };\n}\n\nexport function Params(key?: string, pipe?: TransformPipe<any>) {\n return (target: any, keyName: string, index: number) => {\n const existingMetadata: ParamMetadata =\n Reflect.getOwnMetadata(VIRID_EXPRESS_METADATA.PARAMS, target, keyName) ||\n [];\n const newMetadata = [...existingMetadata, { index, key, pipe }];\n Reflect.defineMetadata(\n VIRID_EXPRESS_METADATA.PARAMS,\n newMetadata,\n target,\n keyName,\n );\n };\n}\n\nfunction getHttpMetadata(target: any, key: string): HttpMetadata {\n const bodyMeta: BodyMetadata = Reflect.getOwnMetadata(\n VIRID_EXPRESS_METADATA.BODY,\n target,\n key,\n );\n const headerMeta: HeaderMetadata = Reflect.getOwnMetadata(\n VIRID_EXPRESS_METADATA.HEADERS,\n target,\n key,\n );\n const cookiesMeta: CookieMetadata = Reflect.getOwnMetadata(\n VIRID_EXPRESS_METADATA.COOKIES,\n target,\n key,\n );\n\n const resMeta: ResponseMetadata = Reflect.getOwnMetadata(\n VIRID_EXPRESS_METADATA.RESPONSE,\n target,\n key,\n );\n const reqMeta: RequestMetadata = Reflect.getOwnMetadata(\n VIRID_EXPRESS_METADATA.REQUEST,\n target,\n key,\n );\n const ctxMeta: ContextMetadata = Reflect.getOwnMetadata(\n VIRID_EXPRESS_METADATA.CONTEXT,\n target,\n key,\n );\n\n const queryMeta: QueryMetadata =\n Reflect.getOwnMetadata(VIRID_EXPRESS_METADATA.QUERY, target, key) || [];\n\n const paramMeta: ParamMetadata =\n Reflect.getOwnMetadata(VIRID_EXPRESS_METADATA.PARAMS, target, key) || [];\n\n return {\n bodyMeta,\n headerMeta,\n queryMeta,\n paramMeta,\n cookiesMeta,\n reqMeta,\n resMeta,\n ctxMeta,\n };\n}\n\nexport function getHttpArgs(\n index: number,\n context: HttpContext,\n httpMetadata: HttpMetadata,\n): any {\n const { req, res } = context;\n\n // 匹配 @Ctx()\n if (httpMetadata.ctxMeta?.index === index) return context;\n\n // 匹配 @Param() -> 获取路由参数 (:id 等)\n const paramItem = httpMetadata.paramMeta?.find((p) => p.index === index);\n if (paramItem) {\n let val = paramItem.key ? req.params[paramItem.key] : req.params;\n\n // 如果有 Pipe 且值不是 undefined,进行转换\n if (paramItem.pipe && val !== undefined) {\n val = paramItem.pipe(val);\n }\n return val;\n }\n\n // @Body()\n if (httpMetadata.bodyMeta?.index === index) return req.body;\n\n // @Header()\n if (httpMetadata.headerMeta?.index === index) return req.headers;\n\n // @Cookie()\n if (httpMetadata.cookiesMeta?.index === index)\n return parseRawCookie(req.headers.cookie);\n\n // @Req() 和 @Res()\n if (httpMetadata.reqMeta?.index === index) return req;\n if (httpMetadata.resMeta?.index === index) return res;\n\n // @Query('name')\n const queryItem = httpMetadata.queryMeta?.find((q) => q.index === index);\n if (queryItem) {\n let val = req.query[queryItem.query];\n if (val === undefined) {\n throw new Error(`[Virid Express] Missing Query: \"${queryItem.query}\"`);\n }\n\n if (queryItem.pipe) {\n val = queryItem.pipe(val);\n }\n return val;\n }\n return null;\n}\n"],"mappings":"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","names":["index_exports","__export","BadRequest","BadRequestResponse","Body","ConflictResponse","Cookies","Created","CreatedResponse","Ctx","CustomResponse","CustomResponseResponse","ExpressPlugin","Forbidden","ForbiddenResponse","Headers","HttpContext","HttpError","HttpRequestMessage","HttpResponse","HttpRoute","HttpSystem","InternalServerError","InternalServerErrorResponse","NoContent","NoContentResponse","NotFound","NotFoundResponse","Ok","OkResponse","Params","ParseBoolPipe","ParseIntPipe","Query","Req","Res","Stream","StreamFile","StreamFileResponse","StreamResponse","Unauthorized","UnauthorizedResponse","UnprocessableEntityResponse","addAutoPipe","getAutoPipe","getHttpArgs","parseRawCookie","__toCommonJS","import_core","import_core","HttpContext","id","req","res","timestamp","route","rc","isClosed","inc","dec","tryFinalize","writableEnded","errorMsg","Date","now","MessageWriter","error","Error","headersSent","end","status","json","message","_HttpContext","HttpResponse","data","headers","_HttpResponse","OkResponse","_OkResponse","CreatedResponse","_CreatedResponse","NoContentResponse","_NoContentResponse","BadRequestResponse","_BadRequestResponse","UnauthorizedResponse","_UnauthorizedResponse","ForbiddenResponse","_ForbiddenResponse","NotFoundResponse","_NotFoundResponse","ConflictResponse","_ConflictResponse","UnprocessableEntityResponse","errors","_UnprocessableEntityResponse","InternalServerErrorResponse","_InternalServerErrorResponse","CustomResponseResponse","_CustomResponseResponse","StreamFileResponse","filePath","options","dotfiles","_StreamFileResponse","StreamResponse","stream","_StreamResponse","Ok","__name","Created","NoContent","BadRequest","msg","Unauthorized","Forbidden","NotFound","InternalServerError","CustomResponse","StreamFile","path","Stream","HttpError","_HttpError","import_core","ParseIntPipe","val","res","parseInt","isNaN","HttpError","ParseBoolPipe","autoPipeMap","Map","set","Number","Boolean","addAutoPipe","type","pipe","has","MessageWriter","error","Error","getAutoPipe","get","parseRawCookie","cookieHeader","result","pairs","split","pair","indexOfEq","indexOf","key","substring","trim","value","length","slice","includes","decodeURIComponent","import_core","HttpRequestMessage","EventMessage","__virid_express_id","requestId","_HttpRequestMessage","import_core","VIRID_EXPRESS_METADATA","VIRID_METADATA","HTTPROUTE","HTTPSYSTEM","BODY","QUERY","HEADERS","REQUEST","RESPONSE","CONTEXT","PARAMS","COOKIES","HttpRoute","config","constructor","params","path","split","forEach","part","startsWith","push","substring","routeInfo","httpMessage","Reflect","defineMetadata","VIRID_EXPRESS_METADATA","HTTPROUTE","checkMessageParam","types","foundMatches","type","idx","HttpRequestMessage","prototype","length","errorDetails","map","item","name","join","Error","HttpSystem","priority","messageClass","target","key","descriptor","originalMethod","value","getMetadata","undefinedIndices","t","i","undefined","filter","messageIdx","matchedMessage","httpMetadata","getHttpMetadata","systemContext","targetClass","methodName","httpSystemConfig","batchMode","Body","index","hasOwnMetadata","BODY","bodyMetadata","Headers","HEADERS","headerMetadata","Cookies","COOKIES","cookiesMetadata","Req","REQUEST","requestMetadata","Res","RESPONSE","responseMetadata","Ctx","CONTEXT","contextMetadata","Query","query","pipe","newMetadata","getOwnMetadata","QUERY","Params","keyName","PARAMS","bodyMeta","headerMeta","cookiesMeta","resMeta","reqMeta","ctxMeta","queryMeta","paramMeta","getHttpArgs","context","req","res","paramItem","find","p","val","body","headers","parseRawCookie","cookie","queryItem","q","ExpressPlugin","name","stagingSystemRegister","MessageRegistry","httpRouteRegistry","Map","httpContextStore","_internalHttpIdCounter","register","systemFn","systemContext","httpSystemConfig","Error","targetClass","priority","bindRoute","constructor","config","Reflect","getMetadata","VIRID_EXPRESS_METADATA","HTTPROUTE","routeKey","method","path","has","set","install","app","options","_","routeInfo","entries","httpMessage","expressMethod","toLowerCase","server","req","res","newId","HttpContext","Date","now","inc","message","once","delete","MessageWriter","write","messageClass","systemTasks","systemTaskMap","task","fn","httpMetadata","messageIdx","originalMethod","wrappedSystem","__name","currentMessage","context","get","requestId","args","params","map","type","index","arg","getHttpArgs","result","apply","Promise","then","handleResult","catch","error","InternalServerError","HttpError","engine","clear","dec","Array","isArray","forEach","item","HttpResponse","handleHttpResponse","status","json","id","BaseMessage","warn","response","ctx","headers","Object","k","v","setHeader","StreamFileResponse","sendFile","filePath","err","headersSent","end","isClosed","StreamResponse","stream","pipe","cleanup","on","data","_ExpressPlugin"]}
package/dist/index.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { EventMessage, Newable, SystemParams, ViridPlugin } from '@virid/core';
1
+ import { Newable, EventMessage, ViridPlugin, ViridApp } from '@virid/core';
2
2
  import { Request, Response, Express } from 'express';
3
3
  import { Readable } from 'stream';
4
4
 
@@ -14,14 +14,7 @@ declare class HttpContext {
14
14
  rc: number;
15
15
  isClosed: boolean;
16
16
  constructor(id: number, req: Request, res: Response, timestamp: number, route: string);
17
- /**
18
- * Increment Reference Count (进入 System)
19
- */
20
17
  inc(): void;
21
- /**
22
- * Decrement Reference Count (离开 System)
23
- * 如果归零且未响应,则判定为孤立响应,强制收割
24
- */
25
18
  dec(): void;
26
19
  private tryFinalize;
27
20
  }
@@ -120,7 +113,7 @@ declare const Forbidden: (msg?: string) => ForbiddenResponse;
120
113
  /** 404 Not Found */
121
114
  declare const NotFound: (msg?: string) => NotFoundResponse;
122
115
  /** 500 Internal Error */
123
- declare const InternalServerError: (msg?: string) => InternalServerErrorResponse;
116
+ declare const InternalServerError: (msg?: string | Error) => InternalServerErrorResponse;
124
117
  declare const CustomResponse: (status: number, data: any, headers?: HttpHeaders) => CustomResponseResponse;
125
118
  /** 发送本地文件 (自动处理 Range/206) */
126
119
  declare const StreamFile: (path: string, options?: StreamFileOptions) => StreamFileResponse;
@@ -134,19 +127,65 @@ declare class HttpError extends Error {
134
127
  constructor(status: number, message: string);
135
128
  }
136
129
 
130
+ type HttpMethod = "get" | "post" | "put" | "delete" | "patch";
131
+ interface HttpRouteConfig {
132
+ path: string;
133
+ method: HttpMethod;
134
+ }
135
+ interface HttpSystemParams {
136
+ priority?: number;
137
+ messageClass?: Newable<HttpRequestMessage> | null;
138
+ }
139
+ interface BodyMetadata {
140
+ index: number;
141
+ }
142
+ interface CookieMetadata {
143
+ index: number;
144
+ }
145
+ interface HeaderMetadata {
146
+ index: number;
147
+ }
148
+ type TransformPipe<T> = (value: any) => T;
149
+ type QueryMetadata = QueryItem[];
150
+ interface RequestMetadata {
151
+ index: number;
152
+ }
153
+ interface ResponseMetadata {
154
+ index: number;
155
+ }
156
+ interface ContextMetadata {
157
+ index: number;
158
+ }
159
+ interface QueryItem {
160
+ index: number;
161
+ query: string;
162
+ pipe?: TransformPipe<any>;
163
+ }
164
+ interface ParamItem {
165
+ index: number;
166
+ key?: string;
167
+ pipe?: TransformPipe<any>;
168
+ }
169
+ type ParamMetadata = ParamItem[];
170
+ interface HttpMetadata {
171
+ bodyMeta: BodyMetadata;
172
+ headerMeta: HeaderMetadata;
173
+ queryMeta: QueryMetadata;
174
+ paramMeta: ParamMetadata;
175
+ cookiesMeta: CookieMetadata;
176
+ reqMeta: RequestMetadata;
177
+ resMeta: ResponseMetadata;
178
+ ctxMeta: ContextMetadata;
179
+ }
180
+
181
+ interface PluginOptions {
182
+ server: Express;
183
+ }
184
+
137
185
  declare function ParseIntPipe(val: string): number;
138
186
  declare function ParseBoolPipe(val: string): boolean;
139
- /**
140
- * 让用户注册自定义类型的转换方法
141
- */
142
187
  declare function addAutoPipe<T>(type: T, pipe: TransformPipe<T>): void;
143
- /**
144
- * 内部调用:根据 TS 类型获取 Pipe
145
- */
146
188
  declare function getAutoPipe<T>(type: T): TransformPipe<T> | undefined;
147
- /**
148
- * 将 cookie 字符串转换为对象
149
- */
150
189
  declare function parseRawCookie(cookieHeader: string | undefined): Record<string, string>;
151
190
 
152
191
  type RequestId = number & {
@@ -158,56 +197,33 @@ declare class HttpRequestMessage extends EventMessage {
158
197
  get requestId(): RequestId;
159
198
  }
160
199
 
161
- type HttpMethod = "get" | "post" | "put" | "delete" | "patch";
162
- interface HttpRouteConfig {
163
- path: string;
164
- method: HttpMethod;
165
- }
166
- type TransformPipe<T> = (value: any) => T;
167
-
168
- interface PluginOptions {
169
- server: Express;
170
- }
171
-
172
200
  declare function HttpRoute(config: HttpRouteConfig): (constructor: Newable<HttpRequestMessage>) => void;
173
201
  /**
174
202
  * @description: 系统装饰器
175
203
  * @param priority 优先级,数值越大越早执行
176
204
  */
177
- declare function HttpSystem(params?: SystemParams): (target: any, key: string, descriptor: PropertyDescriptor) => void;
178
- /**
179
- * @description: 标记参数为 Body
180
- */
205
+ declare function HttpSystem(params?: HttpSystemParams): (target: any, key: string, descriptor: PropertyDescriptor) => void;
181
206
  declare function Body(): (target: any, key: string, index: number) => void;
182
- /**
183
- * @description: 标记参数为 Header
184
- */
185
207
  declare function Headers(): (target: any, key: string, index: number) => void;
186
- /**
187
- * @description: 标记参数为 Header
188
- */
189
208
  declare function Cookies(): (target: any, key: string, index: number) => void;
190
- /**
191
- * @description: 标记参数为 Request 对象
192
- */
193
209
  declare function Req(): (target: any, key: string, index: number) => void;
194
- /**
195
- * @description: 标记参数为 Response 对象
196
- */
197
210
  declare function Res(): (target: any, key: string, index: number) => void;
198
- /**
199
- * @description: 标记参数为 Context 对象
200
- */
201
211
  declare function Ctx(): (target: any, key: string, index: number) => void;
202
- /**
203
- * @description: 标记参数为 Query
204
- */
205
212
  declare function Query(query: string, pipe?: TransformPipe<any>): (target: any, key: string, index: number) => void;
206
- /**
207
- * @description: 标记参数为指定的路径参数 (如 /user/:id)
208
- */
209
213
  declare function Params(key?: string, pipe?: TransformPipe<any>): (target: any, keyName: string, index: number) => void;
214
+ declare function getHttpArgs(index: number, context: HttpContext, httpMetadata: HttpMetadata): any;
210
215
 
211
- declare const ExpressPlugin: ViridPlugin<PluginOptions>;
216
+ declare class ExpressPlugin implements ViridPlugin<PluginOptions> {
217
+ name: string;
218
+ private stagingSystemRegister;
219
+ private httpRouteRegistry;
220
+ private httpContextStore;
221
+ private _internalHttpIdCounter;
222
+ register(systemFn: (...args: any[]) => any): () => void;
223
+ bindRoute(constructor: Newable<HttpRequestMessage>): void;
224
+ install(app: ViridApp, options: PluginOptions): void;
225
+ handleResult(res: any, context: HttpContext): void;
226
+ handleHttpResponse(response: HttpResponse, ctx: HttpContext): void;
227
+ }
212
228
 
213
- export { BadRequest, BadRequestResponse, Body, ConflictResponse, Cookies, Created, CreatedResponse, Ctx, CustomResponse, CustomResponseResponse, ExpressPlugin, Forbidden, ForbiddenResponse, Headers, HttpContext, HttpError, HttpRequestMessage, HttpResponse, HttpRoute, HttpSystem, InternalServerError, InternalServerErrorResponse, NoContent, NoContentResponse, NotFound, NotFoundResponse, Ok, OkResponse, Params, ParseBoolPipe, ParseIntPipe, Query, Req, type RequestId, Res, Stream, StreamFile, type StreamFileOptions, StreamFileResponse, StreamResponse, Unauthorized, UnauthorizedResponse, UnprocessableEntityResponse, addAutoPipe, getAutoPipe, parseRawCookie };
229
+ export { BadRequest, BadRequestResponse, Body, ConflictResponse, Cookies, Created, CreatedResponse, Ctx, CustomResponse, CustomResponseResponse, ExpressPlugin, Forbidden, ForbiddenResponse, Headers, HttpContext, HttpError, HttpRequestMessage, HttpResponse, HttpRoute, HttpSystem, InternalServerError, InternalServerErrorResponse, NoContent, NoContentResponse, NotFound, NotFoundResponse, Ok, OkResponse, Params, ParseBoolPipe, ParseIntPipe, Query, Req, type RequestId, Res, Stream, StreamFile, type StreamFileOptions, StreamFileResponse, StreamResponse, Unauthorized, UnauthorizedResponse, UnprocessableEntityResponse, addAutoPipe, getAutoPipe, getHttpArgs, parseRawCookie };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { EventMessage, Newable, SystemParams, ViridPlugin } from '@virid/core';
1
+ import { Newable, EventMessage, ViridPlugin, ViridApp } from '@virid/core';
2
2
  import { Request, Response, Express } from 'express';
3
3
  import { Readable } from 'stream';
4
4
 
@@ -14,14 +14,7 @@ declare class HttpContext {
14
14
  rc: number;
15
15
  isClosed: boolean;
16
16
  constructor(id: number, req: Request, res: Response, timestamp: number, route: string);
17
- /**
18
- * Increment Reference Count (进入 System)
19
- */
20
17
  inc(): void;
21
- /**
22
- * Decrement Reference Count (离开 System)
23
- * 如果归零且未响应,则判定为孤立响应,强制收割
24
- */
25
18
  dec(): void;
26
19
  private tryFinalize;
27
20
  }
@@ -120,7 +113,7 @@ declare const Forbidden: (msg?: string) => ForbiddenResponse;
120
113
  /** 404 Not Found */
121
114
  declare const NotFound: (msg?: string) => NotFoundResponse;
122
115
  /** 500 Internal Error */
123
- declare const InternalServerError: (msg?: string) => InternalServerErrorResponse;
116
+ declare const InternalServerError: (msg?: string | Error) => InternalServerErrorResponse;
124
117
  declare const CustomResponse: (status: number, data: any, headers?: HttpHeaders) => CustomResponseResponse;
125
118
  /** 发送本地文件 (自动处理 Range/206) */
126
119
  declare const StreamFile: (path: string, options?: StreamFileOptions) => StreamFileResponse;
@@ -134,19 +127,65 @@ declare class HttpError extends Error {
134
127
  constructor(status: number, message: string);
135
128
  }
136
129
 
130
+ type HttpMethod = "get" | "post" | "put" | "delete" | "patch";
131
+ interface HttpRouteConfig {
132
+ path: string;
133
+ method: HttpMethod;
134
+ }
135
+ interface HttpSystemParams {
136
+ priority?: number;
137
+ messageClass?: Newable<HttpRequestMessage> | null;
138
+ }
139
+ interface BodyMetadata {
140
+ index: number;
141
+ }
142
+ interface CookieMetadata {
143
+ index: number;
144
+ }
145
+ interface HeaderMetadata {
146
+ index: number;
147
+ }
148
+ type TransformPipe<T> = (value: any) => T;
149
+ type QueryMetadata = QueryItem[];
150
+ interface RequestMetadata {
151
+ index: number;
152
+ }
153
+ interface ResponseMetadata {
154
+ index: number;
155
+ }
156
+ interface ContextMetadata {
157
+ index: number;
158
+ }
159
+ interface QueryItem {
160
+ index: number;
161
+ query: string;
162
+ pipe?: TransformPipe<any>;
163
+ }
164
+ interface ParamItem {
165
+ index: number;
166
+ key?: string;
167
+ pipe?: TransformPipe<any>;
168
+ }
169
+ type ParamMetadata = ParamItem[];
170
+ interface HttpMetadata {
171
+ bodyMeta: BodyMetadata;
172
+ headerMeta: HeaderMetadata;
173
+ queryMeta: QueryMetadata;
174
+ paramMeta: ParamMetadata;
175
+ cookiesMeta: CookieMetadata;
176
+ reqMeta: RequestMetadata;
177
+ resMeta: ResponseMetadata;
178
+ ctxMeta: ContextMetadata;
179
+ }
180
+
181
+ interface PluginOptions {
182
+ server: Express;
183
+ }
184
+
137
185
  declare function ParseIntPipe(val: string): number;
138
186
  declare function ParseBoolPipe(val: string): boolean;
139
- /**
140
- * 让用户注册自定义类型的转换方法
141
- */
142
187
  declare function addAutoPipe<T>(type: T, pipe: TransformPipe<T>): void;
143
- /**
144
- * 内部调用:根据 TS 类型获取 Pipe
145
- */
146
188
  declare function getAutoPipe<T>(type: T): TransformPipe<T> | undefined;
147
- /**
148
- * 将 cookie 字符串转换为对象
149
- */
150
189
  declare function parseRawCookie(cookieHeader: string | undefined): Record<string, string>;
151
190
 
152
191
  type RequestId = number & {
@@ -158,56 +197,33 @@ declare class HttpRequestMessage extends EventMessage {
158
197
  get requestId(): RequestId;
159
198
  }
160
199
 
161
- type HttpMethod = "get" | "post" | "put" | "delete" | "patch";
162
- interface HttpRouteConfig {
163
- path: string;
164
- method: HttpMethod;
165
- }
166
- type TransformPipe<T> = (value: any) => T;
167
-
168
- interface PluginOptions {
169
- server: Express;
170
- }
171
-
172
200
  declare function HttpRoute(config: HttpRouteConfig): (constructor: Newable<HttpRequestMessage>) => void;
173
201
  /**
174
202
  * @description: 系统装饰器
175
203
  * @param priority 优先级,数值越大越早执行
176
204
  */
177
- declare function HttpSystem(params?: SystemParams): (target: any, key: string, descriptor: PropertyDescriptor) => void;
178
- /**
179
- * @description: 标记参数为 Body
180
- */
205
+ declare function HttpSystem(params?: HttpSystemParams): (target: any, key: string, descriptor: PropertyDescriptor) => void;
181
206
  declare function Body(): (target: any, key: string, index: number) => void;
182
- /**
183
- * @description: 标记参数为 Header
184
- */
185
207
  declare function Headers(): (target: any, key: string, index: number) => void;
186
- /**
187
- * @description: 标记参数为 Header
188
- */
189
208
  declare function Cookies(): (target: any, key: string, index: number) => void;
190
- /**
191
- * @description: 标记参数为 Request 对象
192
- */
193
209
  declare function Req(): (target: any, key: string, index: number) => void;
194
- /**
195
- * @description: 标记参数为 Response 对象
196
- */
197
210
  declare function Res(): (target: any, key: string, index: number) => void;
198
- /**
199
- * @description: 标记参数为 Context 对象
200
- */
201
211
  declare function Ctx(): (target: any, key: string, index: number) => void;
202
- /**
203
- * @description: 标记参数为 Query
204
- */
205
212
  declare function Query(query: string, pipe?: TransformPipe<any>): (target: any, key: string, index: number) => void;
206
- /**
207
- * @description: 标记参数为指定的路径参数 (如 /user/:id)
208
- */
209
213
  declare function Params(key?: string, pipe?: TransformPipe<any>): (target: any, keyName: string, index: number) => void;
214
+ declare function getHttpArgs(index: number, context: HttpContext, httpMetadata: HttpMetadata): any;
210
215
 
211
- declare const ExpressPlugin: ViridPlugin<PluginOptions>;
216
+ declare class ExpressPlugin implements ViridPlugin<PluginOptions> {
217
+ name: string;
218
+ private stagingSystemRegister;
219
+ private httpRouteRegistry;
220
+ private httpContextStore;
221
+ private _internalHttpIdCounter;
222
+ register(systemFn: (...args: any[]) => any): () => void;
223
+ bindRoute(constructor: Newable<HttpRequestMessage>): void;
224
+ install(app: ViridApp, options: PluginOptions): void;
225
+ handleResult(res: any, context: HttpContext): void;
226
+ handleHttpResponse(response: HttpResponse, ctx: HttpContext): void;
227
+ }
212
228
 
213
- export { BadRequest, BadRequestResponse, Body, ConflictResponse, Cookies, Created, CreatedResponse, Ctx, CustomResponse, CustomResponseResponse, ExpressPlugin, Forbidden, ForbiddenResponse, Headers, HttpContext, HttpError, HttpRequestMessage, HttpResponse, HttpRoute, HttpSystem, InternalServerError, InternalServerErrorResponse, NoContent, NoContentResponse, NotFound, NotFoundResponse, Ok, OkResponse, Params, ParseBoolPipe, ParseIntPipe, Query, Req, type RequestId, Res, Stream, StreamFile, type StreamFileOptions, StreamFileResponse, StreamResponse, Unauthorized, UnauthorizedResponse, UnprocessableEntityResponse, addAutoPipe, getAutoPipe, parseRawCookie };
229
+ export { BadRequest, BadRequestResponse, Body, ConflictResponse, Cookies, Created, CreatedResponse, Ctx, CustomResponse, CustomResponseResponse, ExpressPlugin, Forbidden, ForbiddenResponse, Headers, HttpContext, HttpError, HttpRequestMessage, HttpResponse, HttpRoute, HttpSystem, InternalServerError, InternalServerErrorResponse, NoContent, NoContentResponse, NotFound, NotFoundResponse, Ok, OkResponse, Params, ParseBoolPipe, ParseIntPipe, Query, Req, type RequestId, Res, Stream, StreamFile, type StreamFileOptions, StreamFileResponse, StreamResponse, Unauthorized, UnauthorizedResponse, UnprocessableEntityResponse, addAutoPipe, getAutoPipe, getHttpArgs, parseRawCookie };
package/dist/index.js CHANGED
@@ -1,14 +1,8 @@
1
1
  /**
2
- * @virid/express v0.2.2
2
+ * @virid/express v0.3.0
3
3
  * Add express functionality to virid
4
4
  */
5
- var de=Object.defineProperty;var Me=(t,e,s)=>e in t?de(t,e,{enumerable:!0,configurable:!0,writable:!0,value:s}):t[e]=s;var o=(t,e)=>de(t,"name",{value:e,configurable:!0});var p=(t,e,s)=>Me(t,typeof e!="symbol"?e+"":e,s);import{MessageWriter as Te}from"@virid/core";import{MessageRegistry as Oe,MessageWriter as Ce}from"@virid/core";import{BaseMessage as we,MessageWriter as T}from"@virid/core";import{MessageWriter as Ee}from"@virid/core";var W=class W{constructor(e,s,r,n,d){p(this,"id");p(this,"req");p(this,"res");p(this,"timestamp");p(this,"route");p(this,"rc",0);p(this,"isClosed",!1);this.id=e,this.req=s,this.res=r,this.timestamp=n,this.route=d}inc(){this.rc++}dec(){this.rc--,this.rc===0&&this.tryFinalize()}tryFinalize(){if(this.res.writableEnded||this.isClosed)return;this.isClosed=!0;let e=`[Virid Express] Request Orphaned: The connection was closed because all systems finished execution without sending a response.
5
+ var ne=Object.defineProperty;var he=(r,e,t)=>e in r?ne(r,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):r[e]=t;var o=(r,e)=>ne(r,"name",{value:e,configurable:!0});var l=(r,e,t)=>he(r,typeof e!="symbol"?e+"":e,t);import{MessageRegistry as Se,MessageWriter as T,BaseMessage as ye}from"@virid/core";import{MessageWriter as fe}from"@virid/core";var j=class j{constructor(e,t,s,i,a){l(this,"id");l(this,"req");l(this,"res");l(this,"timestamp");l(this,"route");l(this,"rc",0);l(this,"isClosed",!1);this.id=e,this.req=t,this.res=s,this.timestamp=i,this.route=a}inc(){this.rc++}dec(){this.rc--,this.rc===0&&this.tryFinalize()}tryFinalize(){if(this.res.writableEnded||this.isClosed)return;this.isClosed=!0;let e=`[Virid Express] Request Orphaned: The connection was closed because all systems finished execution without sending a response.
6
6
  Route: ${this.route}
7
- Uptime: ${Date.now()-this.timestamp}ms`;Ee.error(new Error(e)),this.res.headersSent?this.res.end():this.res.status(500).json({error:"Internal Logic Error",message:"Request processed but no response was returned by any system."})}};o(W,"HttpContext");var P=W,_=class _{constructor(e,s=null,r={}){p(this,"status");p(this,"data");p(this,"headers");this.status=e,this.data=s,this.headers=r}};o(_,"HttpResponse");var u=_,F=class F extends u{constructor(e,s={}){super(200,e,s)}};o(F,"OkResponse");var $=F,X=class X extends u{constructor(e,s={}){super(201,e,s)}};o(X,"CreatedResponse");var V=X,z=class z extends u{constructor(){super(204,null)}};o(z,"NoContentResponse");var b=z,K=class K extends u{constructor(e="Bad Request"){super(400,{error:e})}};o(K,"BadRequestResponse");var N=K,L=class L extends u{constructor(e="Unauthorized"){super(401,{error:e})}};o(L,"UnauthorizedResponse");var D=L,G=class G extends u{constructor(e="Forbidden"){super(403,{error:e})}};o(G,"ForbiddenResponse");var B=G,J=class J extends u{constructor(e="Not Found"){super(404,{error:e})}};o(J,"NotFoundResponse");var Q=J,Z=class Z extends u{constructor(e="Conflict"){super(409,{error:e})}};o(Z,"ConflictResponse");var ce=Z,k=class k extends u{constructor(e){super(422,{errors:e})}};o(k,"UnprocessableEntityResponse");var pe=k,ee=class ee extends u{constructor(e="Internal Server Error"){super(500,{error:e})}};o(ee,"InternalServerErrorResponse");var U=ee,te=class te extends u{constructor(e,s,r={}){super(e,s,r)}};o(te,"CustomResponseResponse");var Y=te,re=class re extends u{constructor(s,r={dotfiles:"allow"}){super(206,r);p(this,"filePath");p(this,"options");this.filePath=s,this.options=r}};o(re,"StreamFileResponse");var A=re,se=class se extends u{constructor(s,r={}){super(r.status||206,{},r.headers);p(this,"stream");p(this,"options");this.stream=s,this.options=r}};o(se,"StreamResponse");var O=se,Ve=o((t,e={})=>new $(t,e),"Ok"),be=o((t,e={})=>new V(t,e),"Created"),Ne=o(()=>new b,"NoContent"),De=o((t="Bad Request")=>new N(t),"BadRequest"),Be=o((t="Unauthorized")=>new D(t),"Unauthorized"),Qe=o((t="Forbidden")=>new B(t),"Forbidden"),Ue=o((t="Not Found")=>new Q(t),"NotFound"),j=o((t="Internal Server Error")=>new U(t),"InternalServerError"),Ye=o((t,e,s={})=>new Y(t,e,s),"CustomResponse"),je=o((t,e)=>new A(t,e),"StreamFile"),We=o((t,e)=>new O(t,e),"Stream"),oe=class oe extends Error{constructor(s,r){super(r);p(this,"status");p(this,"message");this.status=s,this.message=r}};o(oe,"HttpError");var w=oe;var m=new Map;function S(t,e){if(!t){e.dec();return}(Array.isArray(t)?t:[t]).forEach(r=>{r instanceof u?ge(r,e):r instanceof w?(e.res.status(r.status).json(r.message),m.delete(e.id)):r instanceof we?T.write(r):T.warn(`[Virid Express] Invalid Return Type: ${typeof r}. Expected HttpResponse or Message.`)}),e.dec()}o(S,"handleResult");function ge(t,e){let{res:s}=e;if(t.headers&&Object.entries(t.headers).forEach(([r,n])=>s.setHeader(r,n)),t.status&&s.status(t.status),t instanceof A){e.inc(),s.sendFile(t.filePath,t.options,r=>{s.headersSent||T.error(r,`[Virid Express] SteamFile Error: Path: ${t.filePath}`),e.res.end(),m.delete(e.id),e.isClosed=!0,e.dec()});return}if(t instanceof O){let{stream:r}=t;e.inc(),r.pipe(s);let n=o(()=>{m.has(e.id)&&(e.res.end(),m.delete(e.id),e.isClosed=!0,e.dec())},"cleanup");r.on("end",n),r.on("error",d=>{s.headersSent||T.error(d,"[Virid Express] Stream Error"),n()}),r.on("close",n);return}s.status(t.status).json(t.data),m.delete(e.id)}o(ge,"handleHttpResponse");import{MessageWriter as Se}from"@virid/core";function Re(t){let e=parseInt(t,10);if(isNaN(e))throw new w(400,`Validation failed: "${t}" is not a number.`);return e}o(Re,"ParseIntPipe");function ye(t){return t==="true"||t==="1"?!0:t==="false"||t==="0"?!1:!!t}o(ye,"ParseBoolPipe");var C=new Map;C.set(Number,Re);C.set(Boolean,ye);function Ze(t,e){if(C.has(t)){Se.error(new Error(`[Virid Express Pipe] Repeated Pipe: Auto pipe for ${t} has already been registered.`));return}C.set(t,e)}o(Ze,"addAutoPipe");function ne(t){return C.get(t)}o(ne,"getAutoPipe");function ue(t){let e={};if(!t)return e;let s=t.split(";");for(let r of s){let n=r.indexOf("=");if(n===-1)continue;let d=r.substring(0,n).trim();if(!d)continue;let a=r.substring(n+1).trim();a[0]==='"'&&a[a.length-1]==='"'&&(a=a.slice(1,-1));try{e[d]=a.includes("%")?decodeURIComponent(a):a}catch{e[d]=a}}return e}o(ue,"parseRawCookie");import{EventMessage as Ae}from"@virid/core";var ae=class ae extends Ae{constructor(s){super();p(this,"__virid_express_id");this.__virid_express_id=s,m.get(this.__virid_express_id).inc()}get requestId(){return this.__virid_express_id}};o(ae,"HttpRequestMessage");var v=ae;var H=new Oe,I=new Map,Pe=0;function le(t){for(let[e,s]of H.systemTaskMap.entries())for(let r of s)t.register(e,r.fn,r.priority);H.systemTaskMap.clear()}o(le,"registerHttpSystem");function fe(t){for(let[e,s]of I.entries()){let{method:r,path:n,httpMessage:d}=s,a=r.toLowerCase();t[a](n,(h,f)=>{let c=Pe++>>>0;m.set(c,new P(c,h,f,Date.now(),n));let R=new d(c);f.once("finish",()=>m.delete(c)),f.once("close",()=>m.delete(c)),Ce.write(R)})}}o(fe,"registerHttpRoute");var q=null;function me(t,e){q=t,le(t),fe(e.server)}o(me,"activateApp");var he=new Proxy({},{get(t,e){return(...s)=>{if(!q)return Te.warn(`[Virid Vue] App method "${String(e)}" called before initialization.`),null;let r=q[e];if(typeof r=="function")return Reflect.apply(r,q,s)}}});import{MessageWriter as M}from"@virid/core";import{VIRID_METADATA as ve}from"@virid/core";var i={...ve,HTTPROUTE:"virid:express:route",HTTPSYSTEM:"virid:express:system",BODY:"virid:express:body",QUERY:"virid:express:query",HEADERS:"virid:express:header",REQUEST:"virid:express:request",RESPONSE:"virid:express:response",CONTEXT:"virid:express:context",PARAMS:"virid:express:params",COOKIES:"virid:express:cookie"};function Pt(t){return e=>{let s=`${t.method}:${t.path}`;I.has(s)&&M.error(new Error(`[Virid Http] Routing Conflict: The request method ${t.method} for path ${t.path} has already been registered by ${e.name}`));let r=[];t.path.split("/").forEach(a=>{a.startsWith(":")&&r.push(a.substring(1))});let d={...t,httpMessage:e,params:r};I.set(s,d)}}o(Pt,"HttpRoute");function Tt(t={priority:0,messageClass:null}){return(e,s,r)=>{let n=r.value,d=Reflect.getMetadata("design:paramtypes",e,s),a=Reflect.getMetadata(i.MESSAGE,e,s)||null,h=He(e,s,d);if(!d){let x=new Error(`[Virid HttpSystem] System Parameter Loss:
8
- Unable to recognize system parameters, please confirm if import "reflection-metadata" was introduced at the beginning!`);M.error(x);return}if(d.some(x=>x===void 0)){let x=new Error(`[Virid HttpSystem] Parameter Metadata Loss in "${s}":
9
- One or more parameters have 'undefined' types.
10
- This usually happens when you forget to add a type annotation to a decorated parameter.
11
- Check parameter at index: ${d.indexOf(void 0)}`);M.error(x);return}if(t.messageClass&&a){M.error(new Error(`[Virid HttpSystem] Multiple Messages Are Not Allowed: Cannot use @ message() and SystemParams simultaneously in ${s}`));return}if(!t.messageClass&&!a){M.error(new Error(`[Virid HttpSystem] System Parameter Loss:
12
- Please declare the message type using the Message decorator`));return}let f=t.messageClass??a.messageClass;if(!(f.prototype instanceof v)){M.error(new Error(`[Virid HttpSystem] Wrong Message Type: ${f.name} is not a derived subclass of HttpRequestMessage!`));return}let c=o(x=>{let E=m.get(x.requestId);if(!E)throw new Error(`[Virid Express HttpSystem] Invalid Request Context: The request context for message ${x.requestId} is missing.`);try{let l=d.map((y,ie)=>{if(a&&a.index==ie){if(!(x instanceof f)){let xe=x.constructor.name;throw new Error(`[Virid Express HttpSystem] Type Mismatch: Expected ${f.name}, but received ${xe}`)}return x}else return Ie(y,ie,E,h)}),g=n.apply(e,l);return g instanceof Promise?g.then(y=>{S(y,E)}).catch(y=>{throw S(j(),E),y}):S(g,E)}catch(l){throw l instanceof w?S(l,E):S(j(),E),l}},"wrappedSystem"),R={params:d,targetClass:e,methodName:s,originalMethod:n};c.systemContext=R,r.value=c,H.register(f,c,t.priority)}}o(Tt,"HttpSystem");function vt(){return(t,e,s)=>{if(Reflect.hasOwnMetadata(i.BODY,t,e)){M.error(new Error(`[Virid Express Body] Multiple Body Are Not Allowed: ${e} has multiple @Body() decorators!`));return}let r={index:s};Reflect.defineMetadata(i.BODY,r,t,e)}}o(vt,"Body");function Ht(){return(t,e,s)=>{if(Reflect.hasOwnMetadata(i.HEADERS,t,e)){M.error(new Error(`[Virid Express Headers] Multiple Header Are Not Allowed: ${e} has multiple @Headers() decorators!`));return}let r={index:s};Reflect.defineMetadata(i.HEADERS,r,t,e)}}o(Ht,"Headers");function It(){return(t,e,s)=>{if(Reflect.hasOwnMetadata(i.COOKIES,t,e)){M.error(new Error(`[Virid Express Cookies] Multiple Header Are Not Allowed: ${e} has multiple @Cookies() decorators!`));return}let r={index:s};Reflect.defineMetadata(i.COOKIES,r,t,e)}}o(It,"Cookies");function qt(){return(t,e,s)=>{if(Reflect.hasOwnMetadata(i.REQUEST,t,e)){M.error(new Error(`[Virid Express Req] Multiple Request Objects Are Not Allowed: ${e} has multiple @Req() decorators!`));return}let r={index:s};Reflect.defineMetadata(i.REQUEST,r,t,e)}}o(qt,"Req");function $t(){return(t,e,s)=>{if(Reflect.hasOwnMetadata(i.RESPONSE,t,e)){M.error(new Error(`[Virid Express Res] Multiple Response Objects Are Not Allowed: ${e} has multiple @Res() decorators!`));return}let r={index:s};Reflect.defineMetadata(i.RESPONSE,r,t,e)}}o($t,"Res");function Vt(){return(t,e,s)=>{if(Reflect.hasOwnMetadata(i.CONTEXT,t,e)){M.error(new Error(`[Virid Express Ctx] Multiple Context Objects Are Not Allowed: ${e} has multiple @Ctx() decorators!`));return}let r={index:s};Reflect.defineMetadata(i.CONTEXT,r,t,e)}}o(Vt,"Ctx");function bt(t,e){return(s,r,n)=>{let a=[...Reflect.getOwnMetadata(i.QUERY,s,r)||[],{index:n,query:t,pipe:e}];Reflect.defineMetadata(i.QUERY,a,s,r)}}o(bt,"Query");function Nt(t,e){return(s,r,n)=>{let a=[...Reflect.getOwnMetadata(i.PARAMS,s,r)||[],{index:n,key:t,pipe:e}];Reflect.defineMetadata(i.PARAMS,a,s,r)}}o(Nt,"Params");function He(t,e,s){let r=Reflect.getOwnMetadata(i.BODY,t,e),n=Reflect.getOwnMetadata(i.HEADERS,t,e),d=Reflect.getOwnMetadata(i.COOKIES,t,e),a=Reflect.getOwnMetadata(i.RESPONSE,t,e),h=Reflect.getOwnMetadata(i.REQUEST,t,e),f=Reflect.getOwnMetadata(i.CONTEXT,t,e),R=(Reflect.getOwnMetadata(i.QUERY,t,e)||[]).map(l=>{if(!l.pipe){let g=s[l.index];l.pipe=ne(g)}return l}),E=(Reflect.getOwnMetadata(i.PARAMS,t,e)||[]).map(l=>{if(!l.pipe){let g=s[l.index];l.pipe=ne(g)}return l});return{bodyMeta:r,headerMeta:n,queryMeta:R,cookiesMeta:d,reqMeta:h,resMeta:a,ctxMeta:f,paramMeta:E}}o(He,"getHttpMetadata");function Ie(t,e,s,r){let{req:n,res:d}=s;if(r.ctxMeta?.index===e)return s;let a=r.paramMeta?.find(c=>c.index===e);if(a){let c=a.key?n.params[a.key]:n.params;return a.pipe&&c!==void 0&&(c=a.pipe(c)),c}if(r.bodyMeta?.index===e)return n.body;if(r.headerMeta?.index===e)return n.headers;if(r.cookiesMeta?.index===e)return ue(n.headers.cookie);if(r.reqMeta?.index===e)return n;if(r.resMeta?.index===e)return d;let h=r.queryMeta?.find(c=>c.index===e);if(h){let c=n.query[h.query];if(c===void 0)throw new Error(`[Virid Express] Missing Query: "${h.query}"`);return h.pipe&&(c=h.pipe(c)),c}let f=he.get(t);if(!f)throw new Error(`[Virid System] Unknown Inject Type: ${t?.name||"Anonymous Class"} at index ${e}.
13
- Ensure it is registered in the IOC container or has a proper Http Decorator!`);return f}o(Ie,"getHttpSystemArgs");var jt={name:"@virid/express",install(t,e){me(t,e)}};export{De as BadRequest,N as BadRequestResponse,vt as Body,ce as ConflictResponse,It as Cookies,be as Created,V as CreatedResponse,Vt as Ctx,Ye as CustomResponse,Y as CustomResponseResponse,jt as ExpressPlugin,Qe as Forbidden,B as ForbiddenResponse,Ht as Headers,P as HttpContext,w as HttpError,v as HttpRequestMessage,u as HttpResponse,Pt as HttpRoute,Tt as HttpSystem,j as InternalServerError,U as InternalServerErrorResponse,Ne as NoContent,b as NoContentResponse,Ue as NotFound,Q as NotFoundResponse,Ve as Ok,$ as OkResponse,Nt as Params,ye as ParseBoolPipe,Re as ParseIntPipe,bt as Query,qt as Req,$t as Res,We as Stream,je as StreamFile,A as StreamFileResponse,O as StreamResponse,Be as Unauthorized,D as UnauthorizedResponse,pe as UnprocessableEntityResponse,Ze as addAutoPipe,ne as getAutoPipe,ue as parseRawCookie};
7
+ Uptime: ${Date.now()-this.timestamp}ms`;fe.error(new Error(e)),this.res.headersSent?this.res.end():this.res.status(500).json({error:"Internal Logic Error",message:"Request processed but no response was returned by any system."})}};o(j,"HttpContext");var S=j,Y=class Y{constructor(e,t=null,s={}){l(this,"status");l(this,"data");l(this,"headers");this.status=e,this.data=t,this.headers=s}};o(Y,"HttpResponse");var p=Y,X=class X extends p{constructor(e,t={}){super(200,e,t)}};o(X,"OkResponse");var q=X,L=class L extends p{constructor(e,t={}){super(201,e,t)}};o(L,"CreatedResponse");var V=L,K=class K extends p{constructor(){super(204,null)}};o(K,"NoContentResponse");var b=K,z=class z extends p{constructor(e="Bad Request"){super(400,{error:e})}};o(z,"BadRequestResponse");var v=z,F=class F extends p{constructor(e="Unauthorized"){super(401,{error:e})}};o(F,"UnauthorizedResponse");var D=F,W=class W extends p{constructor(e="Forbidden"){super(403,{error:e})}};o(W,"ForbiddenResponse");var N=W,_=class _ extends p{constructor(e="Not Found"){super(404,{error:e})}};o(_,"NotFoundResponse");var U=_,G=class G extends p{constructor(e="Conflict"){super(409,{error:e})}};o(G,"ConflictResponse");var de=G,J=class J extends p{constructor(e){super(422,{errors:e})}};o(J,"UnprocessableEntityResponse");var ce=J,Z=class Z extends p{constructor(e="Internal Server Error"){super(500,{error:e})}};o(Z,"InternalServerErrorResponse");var I=Z,k=class k extends p{constructor(e,t,s={}){super(e,t,s)}};o(k,"CustomResponseResponse");var B=k,ee=class ee extends p{constructor(t,s={dotfiles:"allow"}){super(206,s);l(this,"filePath");l(this,"options");this.filePath=t,this.options=s}};o(ee,"StreamFileResponse");var y=ee,te=class te extends p{constructor(t,s={}){super(s.status||206,{},s.headers);l(this,"stream");l(this,"options");this.stream=t,this.options=s}};o(te,"StreamResponse");var C=te,Ae=o((r,e={})=>new q(r,e),"Ok"),Te=o((r,e={})=>new V(r,e),"Created"),Pe=o(()=>new b,"NoContent"),Ie=o((r="Bad Request")=>new v(r),"BadRequest"),He=o((r="Unauthorized")=>new D(r),"Unauthorized"),$e=o((r="Forbidden")=>new N(r),"Forbidden"),qe=o((r="Not Found")=>new U(r),"NotFound"),Q=o((r="Internal Server Error")=>r instanceof Error?new I(r.message):new I(r),"InternalServerError"),Ve=o((r,e,t={})=>new B(r,e,t),"CustomResponse"),be=o((r,e)=>new y(r,e),"StreamFile"),ve=o((r,e)=>new C(r,e),"Stream"),re=class re extends Error{constructor(t,s){super(s);l(this,"status");l(this,"message");this.status=t,this.message=s}};o(re,"HttpError");var M=re;import{MessageWriter as me}from"@virid/core";function xe(r){let e=parseInt(r,10);if(isNaN(e))throw new M(400,`Validation failed: "${r}" is not a number.`);return e}o(xe,"ParseIntPipe");function we(r){return r==="true"||r==="1"?!0:r==="false"||r==="0"?!1:!!r}o(we,"ParseBoolPipe");var O=new Map;O.set(Number,xe);O.set(Boolean,we);function Qe(r,e){if(O.has(r)){me.error(new Error(`[Virid Express Pipe] Repeated Pipe: Auto pipe for ${r} has already been registered.`));return}O.set(r,e)}o(Qe,"addAutoPipe");function je(r){return O.get(r)}o(je,"getAutoPipe");function le(r){let e={};if(!r)return e;let t=r.split(";");for(let s of t){let i=s.indexOf("=");if(i===-1)continue;let a=s.substring(0,i).trim();if(!a)continue;let n=s.substring(i+1).trim();n[0]==='"'&&n[n.length-1]==='"'&&(n=n.slice(1,-1));try{e[a]=n.includes("%")?decodeURIComponent(n):n}catch{e[a]=n}}return e}o(le,"parseRawCookie");import{EventMessage as Me}from"@virid/core";var se=class se extends Me{constructor(t){super();l(this,"__virid_express_id");this.__virid_express_id=t}get requestId(){return this.__virid_express_id}};o(se,"HttpRequestMessage");var A=se;import{VIRID_METADATA as ge}from"@virid/core";var d={...ge,HTTPROUTE:"virid:express:route",HTTPSYSTEM:"virid:express:system",BODY:"virid:express:body",QUERY:"virid:express:query",HEADERS:"virid:express:header",REQUEST:"virid:express:request",RESPONSE:"virid:express:response",CONTEXT:"virid:express:context",PARAMS:"virid:express:params",COOKIES:"virid:express:cookie"};function tt(r){return e=>{let t=[];r.path.split("/").forEach(a=>{a.startsWith(":")&&t.push(a.substring(1))});let i={...r,httpMessage:e,params:t};Reflect.defineMetadata(d.HTTPROUTE,i,e)}}o(tt,"HttpRoute");function Ee(r){let e=[];if(r.forEach((t,s)=>{(t===A||t&&t.prototype instanceof A)&&e.push({type:t,idx:s})}),e.length===0)return null;if(e.length>1){let t=e.map(s=>`[Index: ${s.idx}, Name: ${s.type.name}]`).join(", ");throw new Error(`[Virid System] Multiple Messages: Multiple Message type parameters detected, this is not allowed! specific location: ${t}`)}return e[0]}o(Ee,"checkMessageParam");function rt(r={priority:0,messageClass:null}){return(e,t,s)=>{if(typeof e!="function")throw new Error(`[Virid System] Method Type Error: The Method ${t} is not a static method, please check if there is a static keyword tag.`);let i=s.value,a=Reflect.getMetadata("design:paramtypes",e,t);if(!a)throw new Error('[Virid System] System Parameter Loss: Unable to recognize system parameters, please confirm if import "reflect-metadata" was introduced at the beginning.');let n=a.map((x,R)=>x===void 0?R:-1).filter(x=>x!==-1);if(n.length>0)throw new Error(`[Virid System] Parameter Metadata Loss in "${t}": One or more parameters have 'undefined' types. This usually happens when you forget to add a type annotation or due to circular dependencies. Check parameter at indices: [${n.join(", ")}]`);let c,h=-1,u=Ee(a);if(u&&r.messageClass)throw new Error(`[Virid System] Multiple Messages Are Not Allowed: Cannot specify messageClass in decorator options while already declaring it in method parameters at index ${u.idx} in ${t}.`);if(u)c=u.type,h=u.idx;else if(r.messageClass)c=r.messageClass,h=-1;else throw new Error("[Virid System] System Parameter Loss: Please declare the message type either in method parameters or via the Message decorator options.");let m=Re(e,t),f={params:a,targetClass:e,methodName:t,originalMethod:i},P={httpMetadata:m,messageClass:c,messageIdx:h,priority:r.priority||0,batchMode:!1};s.value.systemContext=f,s.value.httpSystemConfig=P}}o(rt,"HttpSystem");function st(){return(r,e,t)=>{if(Reflect.hasOwnMetadata(d.BODY,r,e))throw new Error(`[Virid Express Body] Multiple Body Are Not Allowed: ${e} has multiple @Body() decorators!`);let s={index:t};Reflect.defineMetadata(d.BODY,s,r,e)}}o(st,"Body");function ot(){return(r,e,t)=>{if(Reflect.hasOwnMetadata(d.HEADERS,r,e))throw new Error(`[Virid Express Headers] Multiple Header Are Not Allowed: ${e} has multiple @Headers() decorators!`);let s={index:t};Reflect.defineMetadata(d.HEADERS,s,r,e)}}o(ot,"Headers");function it(){return(r,e,t)=>{if(Reflect.hasOwnMetadata(d.COOKIES,r,e))throw new Error(`[Virid Express Cookies] Multiple Header Are Not Allowed: ${e} has multiple @Cookies() decorators!`);let s={index:t};Reflect.defineMetadata(d.COOKIES,s,r,e)}}o(it,"Cookies");function at(){return(r,e,t)=>{if(Reflect.hasOwnMetadata(d.REQUEST,r,e))throw new Error(`[Virid Express Req] Multiple Request Objects Are Not Allowed: ${e} has multiple @Req() decorators!`);let s={index:t};Reflect.defineMetadata(d.REQUEST,s,r,e)}}o(at,"Req");function nt(){return(r,e,t)=>{if(Reflect.hasOwnMetadata(d.RESPONSE,r,e))throw new Error(`[Virid Express Res] Multiple Response Objects Are Not Allowed: ${e} has multiple @Res() decorators!`);let s={index:t};Reflect.defineMetadata(d.RESPONSE,s,r,e)}}o(nt,"Res");function dt(){return(r,e,t)=>{if(Reflect.hasOwnMetadata(d.CONTEXT,r,e))throw new Error(`[Virid Express Ctx] Multiple Context Objects Are Not Allowed: ${e} has multiple @Ctx() decorators!`);let s={index:t};Reflect.defineMetadata(d.CONTEXT,s,r,e)}}o(dt,"Ctx");function ct(r,e){return(t,s,i)=>{let n=[...Reflect.getOwnMetadata(d.QUERY,t,s)||[],{index:i,query:r,pipe:e}];Reflect.defineMetadata(d.QUERY,n,t,s)}}o(ct,"Query");function lt(r,e){return(t,s,i)=>{let n=[...Reflect.getOwnMetadata(d.PARAMS,t,s)||[],{index:i,key:r,pipe:e}];Reflect.defineMetadata(d.PARAMS,n,t,s)}}o(lt,"Params");function Re(r,e){let t=Reflect.getOwnMetadata(d.BODY,r,e),s=Reflect.getOwnMetadata(d.HEADERS,r,e),i=Reflect.getOwnMetadata(d.COOKIES,r,e),a=Reflect.getOwnMetadata(d.RESPONSE,r,e),n=Reflect.getOwnMetadata(d.REQUEST,r,e),c=Reflect.getOwnMetadata(d.CONTEXT,r,e),h=Reflect.getOwnMetadata(d.QUERY,r,e)||[],u=Reflect.getOwnMetadata(d.PARAMS,r,e)||[];return{bodyMeta:t,headerMeta:s,queryMeta:h,paramMeta:u,cookiesMeta:i,reqMeta:n,resMeta:a,ctxMeta:c}}o(Re,"getHttpMetadata");function pe(r,e,t){let{req:s,res:i}=e;if(t.ctxMeta?.index===r)return e;let a=t.paramMeta?.find(c=>c.index===r);if(a){let c=a.key?s.params[a.key]:s.params;return a.pipe&&c!==void 0&&(c=a.pipe(c)),c}if(t.bodyMeta?.index===r)return s.body;if(t.headerMeta?.index===r)return s.headers;if(t.cookiesMeta?.index===r)return le(s.headers.cookie);if(t.reqMeta?.index===r)return s;if(t.resMeta?.index===r)return i;let n=t.queryMeta?.find(c=>c.index===r);if(n){let c=s.query[n.query];if(c===void 0)throw new Error(`[Virid Express] Missing Query: "${n.query}"`);return n.pipe&&(c=n.pipe(c)),c}return null}o(pe,"getHttpArgs");var oe=class oe{constructor(){l(this,"name","@virid/express");l(this,"stagingSystemRegister",new Se);l(this,"httpRouteRegistry",new Map);l(this,"httpContextStore",new Map);l(this,"_internalHttpIdCounter",0)}register(e){let t=e.systemContext,s=e.httpSystemConfig;if(!t||!s)throw new Error(`[Virid HttpSystem] HttpSystem Parameter Loss: Please declare ${e.name} using the @HttpSystem decorator first.`);return this.stagingSystemRegister.register(t.targetClass,e,s.priority),()=>{}}bindRoute(e){let t=Reflect.getMetadata(d.HTTPROUTE,e);if(!t)throw new Error(`[Virid Http] Routing Error: ${e.name} is not a valid HttpRoute`);let s=`${t.method}:${t.path}`;if(this.httpRouteRegistry.has(s))throw new Error(`[Virid Http] Routing Conflict: The request method ${t.method} for path ${t.path} has already been registered by ${e.name}`);this.httpRouteRegistry.set(s,t)}install(e,t){for(let[s,i]of this.httpRouteRegistry.entries()){let{method:a,path:n,httpMessage:c}=i,h=a.toLowerCase();t.server[h](n,(u,m)=>{let f=this._internalHttpIdCounter++>>>0;new S(f,u,m,Date.now(),n).inc(),this.httpContextStore.set(f,new S(f,u,m,Date.now(),n));let x=new c(f);m.once("finish",()=>this.httpContextStore.delete(f)),m.once("close",()=>this.httpContextStore.delete(f)),T.write(x)})}for(let[s,i]of this.stagingSystemRegister.systemTaskMap.entries())for(let a of i){let n=a.fn,c=n.systemContext,h=n.httpSystemConfig,{httpMetadata:u,messageClass:m,messageIdx:f}=h,{originalMethod:P,targetClass:x}=c,R=o(H=>{let w=this.httpContextStore.get(H.requestId);if(!w)throw new Error(`[Virid Express HttpSystem] Invalid Request Context: The request context for message ${H.requestId} is missing.`);try{let g=c.params.map((E,ie)=>{if(ie===f)return H;{let ae=pe(ie,w,u);return ae||e.get(E)}}),$=P.apply(x,g);return $ instanceof Promise?$.then(E=>{this.handleResult(E,w)}).catch(E=>{throw this.handleResult(Q(E),w),E}):this.handleResult($,w)}catch(g){throw g instanceof M?this.handleResult(g,w):this.handleResult(Q(g),w),g}},"wrappedSystem");R.systemContext=c,R.httpSystemConfig=h,e.engine.register(m,R,a.priority)}this.stagingSystemRegister.systemTaskMap.clear()}handleResult(e,t){if(!e){t.dec();return}(Array.isArray(e)?e:[e]).forEach(i=>{i instanceof p?this.handleHttpResponse(i,t):i instanceof M?(t.res.status(i.status).json(i.message),this.httpContextStore.delete(t.id)):i instanceof ye?T.write(i):T.warn(`[Virid Express] Invalid Return Type: ${typeof i}. Expected HttpResponse or Message.`)}),t.dec()}handleHttpResponse(e,t){let{res:s}=t;if(e.headers&&Object.entries(e.headers).forEach(([i,a])=>s.setHeader(i,a)),e.status&&s.status(e.status),e instanceof y){t.inc(),s.sendFile(e.filePath,e.options,i=>{s.headersSent||T.error(i,`[Virid Express] SteamFile Error: Path: ${e.filePath}`),t.res.end(),this.httpContextStore.delete(t.id),t.isClosed=!0,t.dec()});return}if(e instanceof C){let{stream:i}=e;t.inc(),i.pipe(s);let a=o(()=>{this.httpContextStore.has(t.id)&&(t.res.end(),this.httpContextStore.delete(t.id),t.isClosed=!0,t.dec())},"cleanup");i.on("end",a),i.on("error",n=>{s.headersSent||T.error(n,"[Virid Express] Stream Error"),a()}),i.on("close",a);return}s.status(e.status).json(e.data),this.httpContextStore.delete(t.id)}};o(oe,"ExpressPlugin");var ue=oe;export{Ie as BadRequest,v as BadRequestResponse,st as Body,de as ConflictResponse,it as Cookies,Te as Created,V as CreatedResponse,dt as Ctx,Ve as CustomResponse,B as CustomResponseResponse,ue as ExpressPlugin,$e as Forbidden,N as ForbiddenResponse,ot as Headers,S as HttpContext,M as HttpError,A as HttpRequestMessage,p as HttpResponse,tt as HttpRoute,rt as HttpSystem,Q as InternalServerError,I as InternalServerErrorResponse,Pe as NoContent,b as NoContentResponse,qe as NotFound,U as NotFoundResponse,Ae as Ok,q as OkResponse,lt as Params,we as ParseBoolPipe,xe as ParseIntPipe,ct as Query,at as Req,nt as Res,ve as Stream,be as StreamFile,y as StreamFileResponse,C as StreamResponse,He as Unauthorized,D as UnauthorizedResponse,ce as UnprocessableEntityResponse,Qe as addAutoPipe,je as getAutoPipe,pe as getHttpArgs,le as parseRawCookie};
14
8
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/app.ts","../src/decorators/register.ts","../src/http/context.ts","../src/http/http-response.ts","../src/http/utils.ts","../src/http/message.ts","../src/decorators/express.ts","../src/decorators/constant.ts","../src/index.ts"],"sourcesContent":["/*\n * Copyright (c) 2026-present Ailrid.\n * Licensed under the Apache License, Version 2.0.\n * Project: Virid Express\n */\nimport { type ViridApp, MessageWriter } from \"@virid/core\";\nimport { type PluginOptions } from \"./interfaces\";\n\nimport { registerHttpSystem, registerHttpRoute } from \"./decorators/register\";\n\nexport interface IViridApp {\n get(identifier: any): any;\n}\n\nlet activeApp: IViridApp | null = null;\n\nexport function activateApp(app: ViridApp, options: PluginOptions) {\n //看看用户提供的配置\n activeApp = app;\n // 注册http相关的系统\n registerHttpSystem(app);\n //初始化express的路由\n registerHttpRoute(options.server);\n}\n\n/**\n * viridApp 代理\n */\nexport const viridApp: IViridApp = new Proxy({} as IViridApp, {\n get(_, prop: keyof IViridApp) {\n return (...args: any[]) => {\n // 检查实例是否存在\n if (!activeApp) {\n MessageWriter.warn(\n `[Virid Vue] App method \"${String(prop)}\" called before initialization.`,\n );\n return null;\n }\n\n // 正常转发调用\n // 使用 Reflect 确保 this 指向正确,或者直接从 activeApp 调用\n const targetMethod = activeApp[prop];\n if (typeof targetMethod === \"function\") {\n return Reflect.apply(targetMethod, activeApp, args);\n }\n };\n },\n});\n","/*\n * Copyright (c) 2026-present Ailrid.\n * Licensed under the Apache License, Version 2.0.\n * Project: Virid Express\n */\nimport { MessageRegistry, MessageWriter, type ViridApp } from \"@virid/core\";\nimport { type HttpMethod, type HttpRouteInfo } from \"../interfaces\";\nimport { type Express, type Request, type Response } from \"express\";\nimport { httpContextStore } from \"../http/context\";\nimport { HttpContext, type RequestId } from \"../http\";\n// 临时的注册器\nexport const stagingSystemRegister = new MessageRegistry();\n// 路由注册器\nexport const httpRouteRegistry = new Map<string, HttpRouteInfo>();\n\nlet _internalHttpIdCounter = 0;\n\n/**\n * 注册HttpSystem到app的调度器里\n */\nexport function registerHttpSystem(app: ViridApp) {\n for (const [\n messageClass,\n systemTasks,\n ] of stagingSystemRegister.systemTaskMap.entries()) {\n for (const task of systemTasks) {\n app.register(messageClass, task.fn, task.priority);\n }\n }\n stagingSystemRegister.systemTaskMap.clear();\n}\n\n/**\n * 注册express路由\n */\nexport function registerHttpRoute(server: Express) {\n for (const [_, routeInfo] of httpRouteRegistry.entries()) {\n const { method, path, httpMessage } = routeInfo;\n const expressMethod = method.toLowerCase() as HttpMethod;\n\n //挂载\n server[expressMethod](path, (req: Request, res: Response) => {\n // 实例化 Message\n const newId = _internalHttpIdCounter++ >>> 0;\n\n //存一下上下文信息\n httpContextStore.set(\n newId,\n new HttpContext(newId, req, res, Date.now(), path),\n );\n const message = new httpMessage(newId as RequestId);\n // finish 代表响应已发送,close 代表连接意外中断,两者都应清理\n res.once(\"finish\", () => httpContextStore.delete(newId));\n res.once(\"close\", () => httpContextStore.delete(newId));\n // 触发消息\n MessageWriter.write(message);\n });\n }\n}\n","/*\n * Copyright (c) 2026-present Ailrid.\n * Licensed under the Apache License, Version 2.0.\n * Project: Virid Express\n */\nimport { BaseMessage, MessageWriter } from \"@virid/core\";\nimport {\n type HttpContext,\n HttpResponse,\n StreamFileResponse,\n HttpError,\n StreamResponse,\n} from \"./http-response\";\nexport const httpContextStore = new Map<number, HttpContext>();\n\n/**\n * 统一处理 System 返回值\n * @param res System 函数的返回值\n * @param ctx 当前请求的 HttpContext\n */\nexport function handleResult(res: any, context: HttpContext) {\n if (!res) {\n context.dec();\n return;\n }\n // 支持数组形式的批量返回\n const results = Array.isArray(res) ? res : [res];\n results.forEach((item) => {\n // 处理物理响应 (HttpResponse)\n\n if (item instanceof HttpResponse) {\n // 如果是终结响应,则处理\n handleHttpResponse(item, context);\n } else if (item instanceof HttpError) {\n // 处理错误\n context.res.status(item.status).json(item.message);\n // 从 store 中移除\n httpContextStore.delete(context.id);\n } else if (item instanceof BaseMessage) {\n // 转发消息\n MessageWriter.write(item);\n }\n // 其他非法类型警告\n else {\n MessageWriter.warn(\n `[Virid Express] Invalid Return Type: ${typeof item}. Expected HttpResponse or Message.`,\n );\n }\n });\n // system不管是出错了还是执行完毕,handleResult都会执行,引用计数-1并检查是否是0\n // 如果是0,而且此时还没关闭,那就强制关闭\n // 第一种情况:上面执行了handleHttpResponse,那么在这之前HttpContext就已经被删除了\n // 第二种情况:上面转发了HttpRequestMessage,那么这会抹除此次system执行的痕迹,但是HttpContext由于引用计数,不会被删除\n // 第三种情况:上面转发了其他消息或者其他的返回值,那么引用计数-1并检查是否是0,如果是0,那么强制关闭\n context.dec();\n}\n\nfunction handleHttpResponse(response: HttpResponse, ctx: HttpContext) {\n const { res } = ctx;\n //其他情况,直接返回\n if (response.headers) {\n Object.entries(response.headers).forEach(([k, v]) => res.setHeader(k, v));\n }\n if (response.status) res.status(response.status);\n if (response instanceof StreamFileResponse) {\n //返回异步流,强行增加一个rc续命\n ctx.inc();\n res.sendFile(response.filePath, response.options, (err) => {\n if (!res.headersSent) {\n MessageWriter.error(\n err,\n `[Virid Express] SteamFile Error: Path: ${response.filePath}`,\n );\n }\n //强制删除context\n ctx.res.end();\n httpContextStore.delete(ctx.id);\n ctx.isClosed = true;\n ctx.dec();\n });\n return;\n }\n if (response instanceof StreamResponse) {\n const { stream } = response;\n ctx.inc();\n // 管道传输\n stream.pipe(res);\n // 监听结束,收割上下文\n const cleanup = () => {\n if (!httpContextStore.has(ctx.id)) return;\n ctx.res.end();\n httpContextStore.delete(ctx.id);\n ctx.isClosed = true;\n ctx.dec(); // 触发最后的 finalize\n };\n stream.on(\"end\", cleanup);\n stream.on(\"error\", (err) => {\n if (!res.headersSent) {\n MessageWriter.error(err, `[Virid Express] Stream Error`);\n }\n cleanup();\n });\n stream.on(\"close\", cleanup);\n return;\n }\n\n res.status(response.status).json(response.data);\n //强制删除context\n httpContextStore.delete(ctx.id);\n}\n","/*\n * Copyright (c) 2026-present Ailrid.\n * Licensed under the Apache License, Version 2.0.\n * Project: Virid Express\n */\nimport { type Request, type Response } from \"express\";\nimport { Readable } from \"stream\";\nimport { MessageWriter } from \"@virid/core\";\ninterface HttpHeaders {\n [key: string]: string | string[];\n}\nexport class HttpContext {\n public rc: number = 0;\n public isClosed: boolean = false;\n\n constructor(\n public readonly id: number,\n public readonly req: Request,\n public readonly res: Response,\n public readonly timestamp: number,\n public readonly route: string,\n ) {}\n\n /**\n * Increment Reference Count (进入 System)\n */\n inc() {\n this.rc++;\n }\n\n /**\n * Decrement Reference Count (离开 System)\n * 如果归零且未响应,则判定为孤立响应,强制收割\n */\n dec() {\n this.rc--;\n if (this.rc === 0) {\n this.tryFinalize();\n }\n }\n\n private tryFinalize() {\n // 如果已经由 System 正常返回\n // 或者已经强制关闭过,则直接跳过\n if (this.res.writableEnded || this.isClosed) return;\n\n this.isClosed = true;\n\n // 强制报错并关闭连接\n const errorMsg = `[Virid Express] Request Orphaned: The connection was closed because all systems finished execution without sending a response. \n Route: ${this.route}\n Uptime: ${Date.now() - this.timestamp}ms`;\n\n MessageWriter.error(new Error(errorMsg));\n\n if (!this.res.headersSent) {\n this.res.status(500).json({\n error: \"Internal Logic Error\",\n message:\n \"Request processed but no response was returned by any system.\",\n });\n } else {\n // 如果 header 已经发了但没写完,强行结束流\n this.res.end();\n }\n }\n}\n\nexport abstract class HttpResponse {\n constructor(\n public status: number,\n public data: any = null,\n public headers: HttpHeaders = {},\n ) {}\n}\n\n// --- 2xx Success ---\nexport class OkResponse extends HttpResponse {\n constructor(data: any, headers: HttpHeaders = {}) {\n super(200, data, headers);\n }\n}\n\nexport class CreatedResponse extends HttpResponse {\n constructor(data: any, headers: HttpHeaders = {}) {\n super(201, data, headers);\n }\n}\n\nexport class NoContentResponse extends HttpResponse {\n constructor() {\n super(204, null);\n }\n}\n\n// --- 4xx Client Error ---\nexport class BadRequestResponse extends HttpResponse {\n constructor(message: string = \"Bad Request\") {\n super(400, { error: message });\n }\n}\n\nexport class UnauthorizedResponse extends HttpResponse {\n constructor(message: string = \"Unauthorized\") {\n super(401, { error: message });\n }\n}\n\nexport class ForbiddenResponse extends HttpResponse {\n constructor(message: string = \"Forbidden\") {\n super(403, { error: message });\n }\n}\n\nexport class NotFoundResponse extends HttpResponse {\n constructor(message: string = \"Not Found\") {\n super(404, { error: message });\n }\n}\n\nexport class ConflictResponse extends HttpResponse {\n constructor(message: string = \"Conflict\") {\n super(409, { error: message });\n }\n}\n\nexport class UnprocessableEntityResponse extends HttpResponse {\n constructor(errors: any) {\n super(422, { errors });\n }\n}\n\n// --- 5xx Server Error ---\nexport class InternalServerErrorResponse extends HttpResponse {\n constructor(message: string = \"Internal Server Error\") {\n super(500, { error: message });\n }\n}\n\n// --- 万能类 (Custom) ---\nexport class CustomResponseResponse extends HttpResponse {\n constructor(status: number, data: any, headers: HttpHeaders = {}) {\n super(status, data, headers);\n }\n}\n/**\n * @description: Express sendFile 配置项的强类型定义\n */\nexport interface StreamFileOptions {\n /** 根目录(如果 path 是相对路径则必填) */\n root?: string;\n /** * 对以 . 开头的文件处理策略:\n * - allow: 允许发送\n * - deny: 拒绝并返回 403\n * - ignore: 当作不存在返回 404\n */\n dotfiles?: \"allow\" | \"deny\" | \"ignore\";\n /** 是否发送 ETag */\n etag?: boolean;\n /** 扩展的 HTTP 响应头 */\n headers?: HttpHeaders;\n /** 缓存最大时长 (毫秒) */\n maxAge?: number | string;\n /** 是否在 Cache-Control 中添加 immutable */\n immutable?: boolean;\n /** 是否根据文件系统设置 Last-Modified */\n lastModified?: boolean;\n /** 是否支持断点续传 (Range 请求) */\n acceptRanges?: boolean;\n /** 还有一些不常用的(如 cacheControl, extensions)也可以按需添加 */\n}\nexport class StreamFileResponse extends HttpResponse {\n constructor(\n public readonly filePath: string,\n public readonly options: StreamFileOptions = { dotfiles: \"allow\" },\n ) {\n super(206, options);\n }\n}\n\nexport class StreamResponse extends HttpResponse {\n constructor(\n public readonly stream: Readable,\n public readonly options: {\n status?: number;\n headers?: HttpHeaders;\n } = {},\n ) {\n super(options.status || 206, {}, options.headers);\n }\n}\n// --- 辅助工厂函数 ---\n\n/** 200 OK */\nexport const Ok = (data: any, headers: HttpHeaders = {}) =>\n new OkResponse(data, headers);\n\n/** 201 Created */\nexport const Created = (data: any, headers: HttpHeaders = {}) =>\n new CreatedResponse(data, headers);\n\n/** 204 No Content */\nexport const NoContent = () => new NoContentResponse();\n\n/** 400 Bad Request */\nexport const BadRequest = (msg = \"Bad Request\") => new BadRequestResponse(msg);\n\n/** 401 Unauthorized */\nexport const Unauthorized = (msg = \"Unauthorized\") =>\n new UnauthorizedResponse(msg);\n\n/** 403 Forbidden */\nexport const Forbidden = (msg = \"Forbidden\") => new ForbiddenResponse(msg);\n\n/** 404 Not Found */\nexport const NotFound = (msg = \"Not Found\") => new NotFoundResponse(msg);\n\n/** 500 Internal Error */\nexport const InternalServerError = (msg = \"Internal Server Error\") =>\n new InternalServerErrorResponse(msg);\n\nexport const CustomResponse = (\n status: number,\n data: any,\n headers: HttpHeaders = {},\n) => new CustomResponseResponse(status, data, headers);\n\n/** 发送本地文件 (自动处理 Range/206) */\nexport const StreamFile = (path: string, options?: StreamFileOptions) =>\n new StreamFileResponse(path, options);\n/**\n * 发送流响应\n */\nexport const Stream = (stream: Readable, options?: StreamResponse[\"options\"]) =>\n new StreamResponse(stream, options);\n\nexport class HttpError extends Error {\n constructor(\n public readonly status: number,\n public readonly message: string,\n ) {\n super(message);\n }\n}\n","/*\n * Copyright (c) 2026-present Ailrid.\n * Licensed under the Apache License, Version 2.0.\n * Project: Virid Express\n */\nimport { MessageWriter } from \"@virid/core\";\nimport { HttpError } from \".\";\nimport { type TransformPipe } from \"../interfaces\";\n\nexport function ParseIntPipe(val: string) {\n const res = parseInt(val, 10);\n if (isNaN(res))\n throw new HttpError(400, `Validation failed: \"${val}\" is not a number.`);\n return res;\n}\n\nexport function ParseBoolPipe(val: string) {\n if (val === \"true\" || val === \"1\") return true;\n if (val === \"false\" || val === \"0\") return false;\n return !!val;\n}\n\n/** 存储类型与 Pipe 的映射 */\nconst autoPipeMap = new Map<any, TransformPipe<any>>();\nautoPipeMap.set(Number, ParseIntPipe);\nautoPipeMap.set(Boolean, ParseBoolPipe);\n\n/**\n * 让用户注册自定义类型的转换方法\n */\nexport function addAutoPipe<T>(type: T, pipe: TransformPipe<T>) {\n if (autoPipeMap.has(type)) {\n MessageWriter.error(\n new Error(\n `[Virid Express Pipe] Repeated Pipe: Auto pipe for ${type} has already been registered.`,\n ),\n );\n return;\n }\n autoPipeMap.set(type, pipe);\n}\n\n/**\n * 内部调用:根据 TS 类型获取 Pipe\n */\nexport function getAutoPipe<T>(type: T): TransformPipe<T> | undefined {\n return autoPipeMap.get(type);\n}\n\n/**\n * 将 cookie 字符串转换为对象\n */\nexport function parseRawCookie(\n cookieHeader: string | undefined,\n): Record<string, string> {\n const result: Record<string, string> = {};\n\n if (!cookieHeader) return result;\n const pairs = cookieHeader.split(\";\");\n\n for (const pair of pairs) {\n const indexOfEq = pair.indexOf(\"=\");\n if (indexOfEq === -1) continue;\n\n // 提取 key 和 value,并进行 trim 处理\n const key = pair.substring(0, indexOfEq).trim();\n if (!key) continue;\n\n let value = pair.substring(indexOfEq + 1).trim();\n\n if (value[0] === '\"' && value[value.length - 1] === '\"') {\n value = value.slice(1, -1);\n }\n\n try {\n // 只在必要时进行 URL 解码\n result[key] = value.includes(\"%\") ? decodeURIComponent(value) : value;\n } catch (e) {\n // 如果解码失败(比如恶意构造的序列),保留原样,防止崩溃\n result[key] = value;\n }\n }\n\n return result;\n}\n","/*\n * Copyright (c) 2026-present Ailrid.\n * Licensed under the Apache License, Version 2.0.\n * Project: Virid Express\n */\nimport { EventMessage } from \"@virid/core\";\nimport { httpContextStore } from \"./context\";\nexport type RequestId = number & { readonly __brand: unique symbol };\n\nexport class HttpRequestMessage extends EventMessage {\n // id 必须是 RequestId 类型\n constructor(private readonly __virid_express_id: RequestId) {\n super();\n //从context里捞出来自己的,挂上引用计数+1\n httpContextStore.get(this.__virid_express_id)!.inc();\n }\n // 暴露一个只读属性给业务层使用\n public get requestId(): RequestId {\n return this.__virid_express_id;\n }\n}\n","/*\n * Copyright (c) 2026-present Ailrid.\n * Licensed under the Apache License, Version 2.0.\n * Project: Virid Express\n */\nimport {\n type Newable,\n type SystemParams,\n type SystemContext,\n type MessageMetadata,\n MessageWriter,\n} from \"@virid/core\";\nimport {\n type HttpRouteConfig,\n type HttpRouteInfo,\n type BodyMetadata,\n type HeaderMetadata,\n type QueryMetadata,\n type RequestMetadata,\n type ResponseMetadata,\n type ContextMetadata,\n type ParamMetadata,\n type TransformPipe,\n CookieMetadata,\n} from \"../interfaces\";\nimport {\n HttpContext,\n HttpError,\n HttpRequestMessage,\n InternalServerError,\n parseRawCookie,\n} from \"../http\";\nimport { handleResult, httpContextStore } from \"../http/context\";\nimport { httpRouteRegistry, stagingSystemRegister } from \"./register\";\nimport { VIRID_EXPRESS_METADATA } from \"./constant\";\nimport { viridApp } from \"../app\";\nimport { getAutoPipe } from \"../http\";\nexport function HttpRoute(config: HttpRouteConfig) {\n return (constructor: Newable<HttpRequestMessage>) => {\n // 唯一性校验:组合 Method 和 Path\n const routeKey = `${config.method}:${config.path}`;\n if (httpRouteRegistry.has(routeKey)) {\n MessageWriter.error(\n new Error(\n `[Virid Http] Routing Conflict: The request method ${config.method} for path ${config.path} has already been registered by ${constructor.name}`,\n ),\n );\n }\n\n // 路径参数解析\n const params: string[] = [];\n const pathParts = config.path.split(\"/\");\n pathParts.forEach((part) => {\n if (part.startsWith(\":\")) {\n params.push(part.substring(1));\n }\n });\n\n const routeInfo: HttpRouteInfo = {\n ...config,\n httpMessage: constructor,\n params,\n };\n\n // 存入缓冲区\n httpRouteRegistry.set(routeKey, routeInfo);\n };\n}\n\n/**\n * @description: 系统装饰器\n * @param priority 优先级,数值越大越早执行\n */\nexport function HttpSystem(\n params: SystemParams = {\n priority: 0,\n messageClass: null,\n },\n) {\n return (target: any, key: string, descriptor: PropertyDescriptor) => {\n const originalMethod = descriptor.value;\n // 获得元数据\n const types = Reflect.getMetadata(\"design:paramtypes\", target, key);\n const messageMetadata: MessageMetadata | null =\n Reflect.getMetadata(VIRID_EXPRESS_METADATA.MESSAGE, target, key) || null;\n const httpMetadata = getHttpMetadata(target, key, types);\n // 参数检查\n if (!types) {\n const error = new Error(\n `[Virid HttpSystem] System Parameter Loss:\\nUnable to recognize system parameters, please confirm if import \"reflection-metadata\" was introduced at the beginning!`,\n );\n MessageWriter.error(error);\n return;\n }\n // 检查是否有参数类型丢失\n if (types.some((t: any) => t === undefined)) {\n const error =\n new Error(`[Virid HttpSystem] Parameter Metadata Loss in \"${key}\": \n One or more parameters have 'undefined' types. \n This usually happens when you forget to add a type annotation to a decorated parameter.\n Check parameter at index: ${types.indexOf(undefined)}`);\n MessageWriter.error(error);\n return;\n }\n\n // 不能同时使用@message() 和 SystemParams\n if (params.messageClass && messageMetadata) {\n MessageWriter.error(\n new Error(\n `[Virid HttpSystem] Multiple Messages Are Not Allowed: Cannot use @ message() and SystemParams simultaneously in ${key}`,\n ),\n );\n return;\n }\n // @message() 和 SystemParams至少得有一个\n if (!params.messageClass && !messageMetadata) {\n MessageWriter.error(\n new Error(\n `[Virid HttpSystem] System Parameter Loss:\\nPlease declare the message type using the Message decorator`,\n ),\n );\n return;\n }\n // Message必须是继承自HttpRequestMessage\n const messageClass = params.messageClass ?? messageMetadata!.messageClass;\n if (!(messageClass.prototype instanceof HttpRequestMessage)) {\n MessageWriter.error(\n new Error(\n `[Virid HttpSystem] Wrong Message Type: ${messageClass.name} is not a derived subclass of HttpRequestMessage!`,\n ),\n );\n return;\n }\n //封装system\n const wrappedSystem = (currentMessage: HttpRequestMessage) => {\n // 获取当前请求的上下文\n const context = httpContextStore.get(currentMessage.requestId);\n if (!context) {\n //如果没有context,那直接停止执行\n throw new Error(\n `[Virid Express HttpSystem] Invalid Request Context: The request context for message ${currentMessage.requestId} is missing.`,\n );\n }\n try {\n const args = types.map((type: any, index: number) => {\n // 如果是message,则注入\n // 三个条件缺一不可\n if (messageMetadata && messageMetadata.index == index) {\n if (!(currentMessage instanceof messageClass)) {\n // 如果类型不匹配,说明 Dispatcher 路由逻辑或元数据配置有问题\n const receivedName = (currentMessage as object).constructor.name;\n throw new Error(\n `[Virid Express HttpSystem] Type Mismatch: Expected ${messageClass.name}, but received ${receivedName}`,\n );\n }\n return currentMessage;\n } else {\n return getHttpSystemArgs(type, index, context, httpMetadata);\n }\n });\n // 执行业务逻辑\n const result = originalMethod.apply(target, args);\n // 返回值必须是一个新的HttpRequestMessage数组,或者一个HttpResponse类型\n return result instanceof Promise\n ? result\n .then((res) => {\n handleResult(res, context);\n })\n .catch((error) => {\n // 异步出错要给客户端发 500\n handleResult(InternalServerError(), context);\n // 继续抛出,让 Dispatcher 捕获并打印详细堆栈\n throw error;\n })\n : handleResult(result, context);\n } catch (error) {\n if (error instanceof HttpError) {\n // 如果手动 throw new HttpError\n handleResult(error, context);\n } else {\n // 真正的崩溃,返回 500\n handleResult(InternalServerError(), context);\n }\n throw error; // 继续抛出给 Dispatcher 记录日志\n }\n };\n\n // 给包装后的函数挂载上下文信息(供 Dispatcher 读取)\n const systemContext: SystemContext = {\n params: types,\n targetClass: target,\n methodName: key,\n originalMethod: originalMethod,\n };\n (wrappedSystem as any).systemContext = systemContext;\n // 修改方法定义\n descriptor.value = wrappedSystem;\n // 注册到调度中心\n stagingSystemRegister.register(\n messageClass,\n wrappedSystem,\n params.priority,\n );\n };\n}\n\n/**\n * @description: 标记参数为 Body\n */\n\nexport function Body() {\n return (target: any, key: string, index: number) => {\n if (Reflect.hasOwnMetadata(VIRID_EXPRESS_METADATA.BODY, target, key)) {\n MessageWriter.error(\n new Error(\n `[Virid Express Body] Multiple Body Are Not Allowed: ${key} has multiple @Body() decorators!`,\n ),\n );\n return;\n }\n const bodyMetadata = { index } as BodyMetadata;\n Reflect.defineMetadata(\n VIRID_EXPRESS_METADATA.BODY,\n bodyMetadata,\n target,\n key,\n );\n };\n}\n\n/**\n * @description: 标记参数为 Header\n */\n\nexport function Headers() {\n return (target: any, key: string, index: number) => {\n if (Reflect.hasOwnMetadata(VIRID_EXPRESS_METADATA.HEADERS, target, key)) {\n MessageWriter.error(\n new Error(\n `[Virid Express Headers] Multiple Header Are Not Allowed: ${key} has multiple @Headers() decorators!`,\n ),\n );\n return;\n }\n const headerMetadata = { index } as HeaderMetadata;\n Reflect.defineMetadata(\n VIRID_EXPRESS_METADATA.HEADERS,\n headerMetadata,\n target,\n key,\n );\n };\n}\n\n/**\n * @description: 标记参数为 Header\n */\n\nexport function Cookies() {\n return (target: any, key: string, index: number) => {\n if (Reflect.hasOwnMetadata(VIRID_EXPRESS_METADATA.COOKIES, target, key)) {\n MessageWriter.error(\n new Error(\n `[Virid Express Cookies] Multiple Header Are Not Allowed: ${key} has multiple @Cookies() decorators!`,\n ),\n );\n return;\n }\n const cookiesMetadata = { index } as CookieMetadata;\n Reflect.defineMetadata(\n VIRID_EXPRESS_METADATA.COOKIES,\n cookiesMetadata,\n target,\n key,\n );\n };\n}\n\n/**\n * @description: 标记参数为 Request 对象\n */\nexport function Req() {\n return (target: any, key: string, index: number) => {\n // 检查是否已经定义过 Request 元数据,防止一个方法注入多个 Request 参数\n if (Reflect.hasOwnMetadata(VIRID_EXPRESS_METADATA.REQUEST, target, key)) {\n MessageWriter.error(\n new Error(\n `[Virid Express Req] Multiple Request Objects Are Not Allowed: ${key} has multiple @Req() decorators!`,\n ),\n );\n return;\n }\n const requestMetadata: RequestMetadata = { index };\n Reflect.defineMetadata(\n VIRID_EXPRESS_METADATA.REQUEST,\n requestMetadata,\n target,\n key,\n );\n };\n}\n\n/**\n * @description: 标记参数为 Response 对象\n */\nexport function Res() {\n return (target: any, key: string, index: number) => {\n // 检查是否已经定义过 Response 元数据\n if (Reflect.hasOwnMetadata(VIRID_EXPRESS_METADATA.RESPONSE, target, key)) {\n MessageWriter.error(\n new Error(\n `[Virid Express Res] Multiple Response Objects Are Not Allowed: ${key} has multiple @Res() decorators!`,\n ),\n );\n return;\n }\n const responseMetadata: ResponseMetadata = { index };\n Reflect.defineMetadata(\n VIRID_EXPRESS_METADATA.RESPONSE,\n responseMetadata,\n target,\n key,\n );\n };\n}\n\n/**\n * @description: 标记参数为 Context 对象\n */\nexport function Ctx() {\n return (target: any, key: string, index: number) => {\n // 检查是否已经定义过 context 元数据\n if (Reflect.hasOwnMetadata(VIRID_EXPRESS_METADATA.CONTEXT, target, key)) {\n MessageWriter.error(\n new Error(\n `[Virid Express Ctx] Multiple Context Objects Are Not Allowed: ${key} has multiple @Ctx() decorators!`,\n ),\n );\n return;\n }\n const contextMetadata: ContextMetadata = { index };\n Reflect.defineMetadata(\n VIRID_EXPRESS_METADATA.CONTEXT,\n contextMetadata,\n target,\n key,\n );\n };\n}\n\n/**\n * @description: 标记参数为 Query\n */\nexport function Query(query: string, pipe?: TransformPipe<any>) {\n return (target: any, key: string, index: number) => {\n const existingMetadata: QueryMetadata =\n Reflect.getOwnMetadata(VIRID_EXPRESS_METADATA.QUERY, target, key) || [];\n const newMetadata = [...existingMetadata, { index, query, pipe }];\n Reflect.defineMetadata(\n VIRID_EXPRESS_METADATA.QUERY,\n newMetadata,\n target,\n key,\n );\n };\n}\n\n/**\n * @description: 标记参数为指定的路径参数 (如 /user/:id)\n */\nexport function Params(key?: string, pipe?: TransformPipe<any>) {\n return (target: any, keyName: string, index: number) => {\n const existingMetadata: ParamMetadata =\n Reflect.getOwnMetadata(VIRID_EXPRESS_METADATA.PARAMS, target, keyName) ||\n [];\n const newMetadata = [...existingMetadata, { index, key, pipe }];\n Reflect.defineMetadata(\n VIRID_EXPRESS_METADATA.PARAMS,\n newMetadata,\n target,\n keyName,\n );\n };\n}\n/**\n * @description: 获得各种元数据\n */\nfunction getHttpMetadata(target: any, key: string, types: any[]) {\n // 获取所有的元数据配置\n const bodyMeta: BodyMetadata = Reflect.getOwnMetadata(\n VIRID_EXPRESS_METADATA.BODY,\n target,\n key,\n );\n const headerMeta: HeaderMetadata = Reflect.getOwnMetadata(\n VIRID_EXPRESS_METADATA.HEADERS,\n target,\n key,\n );\n const cookiesMeta: CookieMetadata = Reflect.getOwnMetadata(\n VIRID_EXPRESS_METADATA.COOKIES,\n target,\n key,\n );\n\n const resMeta: ResponseMetadata = Reflect.getOwnMetadata(\n VIRID_EXPRESS_METADATA.RESPONSE,\n target,\n key,\n );\n const reqMeta: RequestMetadata = Reflect.getOwnMetadata(\n VIRID_EXPRESS_METADATA.REQUEST,\n target,\n key,\n );\n const ctxMeta: ContextMetadata = Reflect.getOwnMetadata(\n VIRID_EXPRESS_METADATA.CONTEXT,\n target,\n key,\n );\n const rawQueryMeta: QueryMetadata =\n Reflect.getOwnMetadata(VIRID_EXPRESS_METADATA.QUERY, target, key) || [];\n const queryMeta = rawQueryMeta.map((item) => {\n // 如果没指定 pipe,根据 types[item.index] 自动分配\n if (!item.pipe) {\n const paramType = types[item.index];\n item.pipe = getAutoPipe(paramType);\n }\n return item;\n });\n const rawParamMeta: ParamMetadata =\n Reflect.getOwnMetadata(VIRID_EXPRESS_METADATA.PARAMS, target, key) || [];\n const paramMeta = rawParamMeta.map((item) => {\n if (!item.pipe) {\n const paramType = types[item.index];\n item.pipe = getAutoPipe(paramType);\n }\n return item;\n });\n return {\n bodyMeta,\n headerMeta,\n queryMeta,\n cookiesMeta,\n reqMeta,\n resMeta,\n ctxMeta,\n paramMeta,\n };\n}\n\nfunction getHttpSystemArgs(\n type: any,\n index: number,\n context: HttpContext,\n httpMetadata: ReturnType<typeof getHttpMetadata>,\n): any {\n const { req, res } = context;\n\n // 匹配 @Ctx()\n if (httpMetadata.ctxMeta?.index === index) return context;\n\n // 匹配 @Param() -> 获取路由参数 (:id 等)\n const paramItem = httpMetadata.paramMeta?.find((p) => p.index === index);\n if (paramItem) {\n let val = paramItem.key ? req.params[paramItem.key] : req.params;\n\n // 如果有 Pipe 且值不是 undefined,进行转换\n if (paramItem.pipe && val !== undefined) {\n val = paramItem.pipe(val);\n }\n return val;\n }\n\n // 匹配 @Body() -> 获取请求体\n if (httpMetadata.bodyMeta?.index === index) return req.body;\n\n // 匹配 @Header() -> 获取请求头\n if (httpMetadata.headerMeta?.index === index) return req.headers;\n\n // 匹配 @Cookie() -> 获取Cookie\n if (httpMetadata.cookiesMeta?.index === index)\n return parseRawCookie(req.headers.cookie);\n\n // 匹配 @Req() 和 @Res() -> 原生 Express 对象\n if (httpMetadata.reqMeta?.index === index) return req;\n if (httpMetadata.resMeta?.index === index) return res;\n\n // 匹配 @Query('name') -> 获取特定的 Query 参数\n const queryItem = httpMetadata.queryMeta?.find((q) => q.index === index);\n if (queryItem) {\n let val = req.query[queryItem.query];\n if (val === undefined) {\n throw new Error(`[Virid Express] Missing Query: \"${queryItem.query}\"`);\n }\n\n // 执行 Pipe 转换\n if (queryItem.pipe) {\n val = queryItem.pipe(val);\n }\n return val;\n }\n\n // 处理普通的 IOC 容器依赖注入 (DI)\n const param = viridApp.get(type);\n if (!param) {\n throw new Error(\n `[Virid System] Unknown Inject Type: ${type?.name || \"Anonymous Class\"} at index ${index}. \n Ensure it is registered in the IOC container or has a proper Http Decorator!`,\n );\n }\n\n return param;\n}\n","/*\n * Copyright (c) 2026-present Ailrid.\n * Licensed under the Apache License, Version 2.0.\n * Project: Virid Express\n */\nimport { VIRID_METADATA } from \"@virid/core\";\n\nexport const VIRID_EXPRESS_METADATA = {\n ...VIRID_METADATA,\n HTTPROUTE: \"virid:express:route\",\n HTTPSYSTEM: \"virid:express:system\",\n BODY: \"virid:express:body\",\n QUERY: \"virid:express:query\",\n HEADERS: \"virid:express:header\",\n REQUEST: \"virid:express:request\",\n RESPONSE: \"virid:express:response\",\n CONTEXT: \"virid:express:context\",\n PARAMS: \"virid:express:params\",\n COOKIES: \"virid:express:cookie\",\n} as const;\n","/*\n * Copyright (c) 2026-present Ailrid\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Description: Add express functionality to virid.\n */\nimport { ViridPlugin, type ViridApp } from \"@virid/core\";\nimport { activateApp } from \"./app\";\nimport { PluginOptions } from \"./interfaces\";\n\nexport * from \"./http\";\nexport * from \"./decorators\";\nexport const ExpressPlugin: ViridPlugin<PluginOptions> = {\n name: \"@virid/express\",\n install(app: ViridApp, options) {\n activateApp(app, options as PluginOptions);\n },\n};\n"],"mappings":"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","names":["MessageWriter","MessageRegistry","MessageWriter","BaseMessage","MessageWriter","MessageWriter","HttpContext","id","req","res","timestamp","route","rc","isClosed","inc","dec","tryFinalize","writableEnded","errorMsg","Date","now","MessageWriter","error","Error","headersSent","end","status","json","message","_HttpContext","HttpResponse","data","headers","_HttpResponse","OkResponse","_OkResponse","CreatedResponse","_CreatedResponse","NoContentResponse","_NoContentResponse","BadRequestResponse","_BadRequestResponse","UnauthorizedResponse","_UnauthorizedResponse","ForbiddenResponse","_ForbiddenResponse","NotFoundResponse","_NotFoundResponse","ConflictResponse","_ConflictResponse","UnprocessableEntityResponse","errors","_UnprocessableEntityResponse","InternalServerErrorResponse","_InternalServerErrorResponse","CustomResponseResponse","_CustomResponseResponse","StreamFileResponse","filePath","options","dotfiles","_StreamFileResponse","StreamResponse","stream","_StreamResponse","Ok","__name","Created","NoContent","BadRequest","msg","Unauthorized","Forbidden","NotFound","InternalServerError","CustomResponse","StreamFile","path","Stream","HttpError","_HttpError","httpContextStore","Map","handleResult","res","context","dec","Array","isArray","forEach","item","HttpResponse","handleHttpResponse","HttpError","status","json","message","delete","id","BaseMessage","MessageWriter","write","warn","response","ctx","headers","Object","entries","k","v","setHeader","StreamFileResponse","inc","sendFile","filePath","options","err","headersSent","error","end","isClosed","StreamResponse","stream","pipe","cleanup","__name","has","on","data","MessageWriter","ParseIntPipe","val","res","parseInt","isNaN","HttpError","ParseBoolPipe","autoPipeMap","Map","set","Number","Boolean","addAutoPipe","type","pipe","has","MessageWriter","error","Error","getAutoPipe","get","parseRawCookie","cookieHeader","result","pairs","split","pair","indexOfEq","indexOf","key","substring","trim","value","length","slice","includes","decodeURIComponent","EventMessage","HttpRequestMessage","EventMessage","__virid_express_id","httpContextStore","get","inc","requestId","_HttpRequestMessage","stagingSystemRegister","MessageRegistry","httpRouteRegistry","Map","_internalHttpIdCounter","registerHttpSystem","app","messageClass","systemTasks","systemTaskMap","entries","task","register","fn","priority","clear","registerHttpRoute","server","_","routeInfo","method","path","httpMessage","expressMethod","toLowerCase","req","res","newId","httpContextStore","set","HttpContext","Date","now","message","once","delete","MessageWriter","write","activeApp","activateApp","app","options","registerHttpSystem","registerHttpRoute","server","viridApp","Proxy","get","_","prop","args","MessageWriter","warn","String","targetMethod","Reflect","apply","MessageWriter","VIRID_METADATA","VIRID_EXPRESS_METADATA","HTTPROUTE","HTTPSYSTEM","BODY","QUERY","HEADERS","REQUEST","RESPONSE","CONTEXT","PARAMS","COOKIES","HttpRoute","config","constructor","routeKey","method","path","httpRouteRegistry","has","MessageWriter","error","Error","name","params","split","forEach","part","startsWith","push","substring","routeInfo","httpMessage","set","HttpSystem","priority","messageClass","target","key","descriptor","originalMethod","value","types","Reflect","getMetadata","messageMetadata","VIRID_EXPRESS_METADATA","MESSAGE","httpMetadata","getHttpMetadata","some","t","undefined","indexOf","prototype","HttpRequestMessage","wrappedSystem","__name","currentMessage","context","httpContextStore","get","requestId","args","map","type","index","receivedName","getHttpSystemArgs","result","apply","Promise","then","res","handleResult","catch","InternalServerError","HttpError","systemContext","targetClass","methodName","stagingSystemRegister","register","Body","hasOwnMetadata","BODY","bodyMetadata","defineMetadata","Headers","HEADERS","headerMetadata","Cookies","COOKIES","cookiesMetadata","Req","REQUEST","requestMetadata","Res","RESPONSE","responseMetadata","Ctx","CONTEXT","contextMetadata","Query","query","pipe","newMetadata","getOwnMetadata","QUERY","Params","keyName","PARAMS","bodyMeta","headerMeta","cookiesMeta","resMeta","reqMeta","ctxMeta","queryMeta","item","paramType","getAutoPipe","paramMeta","req","paramItem","find","p","val","body","headers","parseRawCookie","cookie","queryItem","q","param","viridApp","ExpressPlugin","name","install","app","options","activateApp"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/http/response.ts","../src/http/utils.ts","../src/http/message.ts","../src/decorators/constant.ts","../src/decorators/decorator.ts"],"sourcesContent":["/*\n * Copyright (c) 2026-present Ailrid\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Description: Add express functionality to virid.\n */\nimport {\n ViridPlugin,\n type ViridApp,\n MessageRegistry,\n MessageWriter,\n Newable,\n SystemContext,\n BaseMessage,\n} from \"@virid/core\";\nimport { getHttpArgs } from \"./decorators\";\nimport {\n HttpSystemConfig,\n type HttpMethod,\n type HttpRouteInfo,\n} from \"./interfaces\";\n\nimport {\n HttpContext,\n HttpError,\n HttpRequestMessage,\n HttpResponse,\n InternalServerError,\n RequestId,\n StreamFileResponse,\n StreamResponse,\n} from \"./http\";\n\nimport { PluginOptions } from \"./interfaces\";\nimport { type Request, type Response } from \"express\";\nimport { VIRID_EXPRESS_METADATA } from \"./decorators/constant\";\nexport * from \"./http\";\nexport * from \"./decorators\";\n\nexport class ExpressPlugin implements ViridPlugin<PluginOptions> {\n name = \"@virid/express\";\n // temporary Registry\n private stagingSystemRegister = new MessageRegistry();\n // route Registry\n private httpRouteRegistry = new Map<string, HttpRouteInfo>();\n\n private httpContextStore = new Map<number, HttpContext>();\n\n private _internalHttpIdCounter = 0;\n\n register(systemFn: (...args: any[]) => any): () => void {\n // @ts-expect-error: get systemContext from systemFn\n const systemContext: SystemContext = systemFn.systemContext;\n // @ts-expect-error: get httpSystemConfig from systemFn\n const httpSystemConfig: HttpSystemConfig = systemFn.httpSystemConfig;\n if (!systemContext || !httpSystemConfig) {\n throw new Error(\n `[Virid HttpSystem] HttpSystem Parameter Loss: Please declare ${systemFn.name} using the @HttpSystem decorator first.`,\n );\n }\n this.stagingSystemRegister.register(\n systemContext.targetClass,\n systemFn,\n httpSystemConfig.priority,\n );\n return () => {};\n }\n\n bindRoute(constructor: Newable<HttpRequestMessage>) {\n const config: HttpRouteInfo = Reflect.getMetadata(\n VIRID_EXPRESS_METADATA.HTTPROUTE,\n constructor,\n );\n if (!config) {\n throw new Error(\n `[Virid Http] Routing Error: ${constructor.name} is not a valid HttpRoute`,\n );\n }\n // Uniqueness verification: Combining Method and Path\n const routeKey = `${config.method}:${config.path}`;\n if (this.httpRouteRegistry.has(routeKey)) {\n throw new Error(\n `[Virid Http] Routing Conflict: The request method ${config.method} for path ${config.path} has already been registered by ${constructor.name}`,\n );\n } else {\n this.httpRouteRegistry.set(routeKey, config);\n }\n }\n\n install(app: ViridApp, options: PluginOptions) {\n // register for express routing\n for (const [_, routeInfo] of this.httpRouteRegistry.entries()) {\n const { method, path, httpMessage } = routeInfo;\n const expressMethod = method.toLowerCase() as HttpMethod;\n\n options.server[expressMethod](path, (req: Request, res: Response) => {\n // instantiate Message\n const newId = this._internalHttpIdCounter++ >>> 0;\n\n // save contextual information\n const context = new HttpContext(newId, req, res, Date.now(), path);\n context.inc();\n this.httpContextStore.set(\n newId,\n new HttpContext(newId, req, res, Date.now(), path),\n );\n const message = new httpMessage(newId as RequestId);\n // finish means the response has been sent, close means the connection was unexpectedly interrupted, both should be cleaned up\n res.once(\"finish\", () => this.httpContextStore.delete(newId));\n res.once(\"close\", () => this.httpContextStore.delete(newId));\n // send message\n MessageWriter.write(message);\n });\n }\n\n // register HttpSystem into the app's scheduler\n for (const [\n messageClass,\n systemTasks,\n ] of this.stagingSystemRegister.systemTaskMap.entries()) {\n for (const task of systemTasks) {\n const systemFn = task.fn;\n // @ts-expect-error: get systemContext from systemFn\n const systemContext: SystemContext = systemFn.systemContext;\n // @ts-expect-error: get httpSystemConfig from systemFn\n const httpSystemConfig: HttpSystemConfig = systemFn.httpSystemConfig;\n const { httpMetadata, messageClass, messageIdx } = httpSystemConfig;\n const { originalMethod, targetClass } = systemContext;\n const wrappedSystem = (currentMessage: HttpRequestMessage) => {\n // retrieve the context of the current request\n const context = this.httpContextStore.get(currentMessage.requestId);\n if (!context) {\n throw new Error(\n `[Virid Express HttpSystem] Invalid Request Context: The request context for message ${currentMessage.requestId} is missing.`,\n );\n }\n try {\n const args = systemContext.params.map(\n (type: any, index: number) => {\n // If it is a message, inject\n if (index === messageIdx) {\n return currentMessage;\n } else {\n // Otherwise, try injecting HTTP parameters or components\n const arg = getHttpArgs(index, context, httpMetadata);\n return arg ? arg : app.get(type);\n }\n },\n );\n const result = originalMethod.apply(targetClass, args);\n return result instanceof Promise\n ? result\n .then((res) => {\n this.handleResult(res, context);\n })\n .catch((error) => {\n // asynchronous error needs to send 500 to the client\n this.handleResult(InternalServerError(error), context);\n // continue throwing, let Dispatcher capture and print detailed stack\n throw error;\n })\n : this.handleResult(result, context);\n } catch (error) {\n if (error instanceof HttpError) {\n // if manually throw new HttpError\n this.handleResult(error, context);\n } else {\n // real crash, return 500\n this.handleResult(InternalServerError(error as Error), context);\n }\n throw error; // continue throwing, let Dispatcher capture and print detailed stack\n }\n };\n wrappedSystem.systemContext = systemContext;\n wrappedSystem.httpSystemConfig = httpSystemConfig;\n app.engine.register(messageClass, wrappedSystem, task.priority);\n }\n }\n this.stagingSystemRegister.systemTaskMap.clear();\n }\n\n handleResult(res: any, context: HttpContext) {\n if (!res) {\n context.dec();\n return;\n }\n const results = Array.isArray(res) ? res : [res];\n results.forEach((item) => {\n if (item instanceof HttpResponse) {\n // if it is a termination response, handle it\n this.handleHttpResponse(item, context);\n } else if (item instanceof HttpError) {\n // handling errors\n context.res.status(item.status).json(item.message);\n this.httpContextStore.delete(context.id);\n } else if (item instanceof BaseMessage) {\n MessageWriter.write(item);\n } else {\n MessageWriter.warn(\n `[Virid Express] Invalid Return Type: ${typeof item}. Expected HttpResponse or Message.`,\n );\n }\n });\n //Whether the system encounters an error or completes execution, handleResult will execute with a reference count of -1 and check if it is 0\n //If it is 0 and it has not been closed yet, then force it to close\n //The first scenario: If handleHttpResponse is executed above, then HttpContext has already been deleted before that\n //The second scenario: If the HttpRequestMessage is forwarded above, it will erase the trace of the system execution, but the HttpContext will not be deleted due to reference counting\n //The third scenario: If other messages or return values are forwarded above, the reference count will be -1 and checked if it is 0. If it is 0, it will be forcibly closed\n context.dec();\n }\n\n handleHttpResponse(response: HttpResponse, ctx: HttpContext) {\n const { res } = ctx;\n\n if (response.headers) {\n Object.entries(response.headers).forEach(([k, v]) => res.setHeader(k, v));\n }\n\n if (response.status) res.status(response.status);\n\n if (response instanceof StreamFileResponse) {\n // return asynchronous stream and forcefully add an RC extension\n ctx.inc();\n res.sendFile(response.filePath, response.options, (err) => {\n if (!res.headersSent) {\n MessageWriter.error(\n err,\n `[Virid Express] SteamFile Error: Path: ${response.filePath}`,\n );\n }\n ctx.res.end();\n this.httpContextStore.delete(ctx.id);\n ctx.isClosed = true;\n ctx.dec();\n });\n return;\n }\n if (response instanceof StreamResponse) {\n const { stream } = response;\n ctx.inc();\n stream.pipe(res);\n // end of listening, harvest context\n const cleanup = () => {\n if (!this.httpContextStore.has(ctx.id)) return;\n ctx.res.end();\n this.httpContextStore.delete(ctx.id);\n ctx.isClosed = true;\n ctx.dec();\n };\n stream.on(\"end\", cleanup);\n stream.on(\"error\", (err) => {\n if (!res.headersSent) {\n MessageWriter.error(err, `[Virid Express] Stream Error`);\n }\n cleanup();\n });\n stream.on(\"close\", cleanup);\n return;\n }\n\n res.status(response.status).json(response.data);\n this.httpContextStore.delete(ctx.id);\n }\n}\n","/*\n * Copyright (c) 2026-present Ailrid.\n * Licensed under the Apache License, Version 2.0.\n * Project: Virid Express\n */\nimport { type Request, type Response } from \"express\";\nimport { Readable } from \"stream\";\nimport { MessageWriter } from \"@virid/core\";\ninterface HttpHeaders {\n [key: string]: string | string[];\n}\nexport class HttpContext {\n public rc: number = 0;\n public isClosed: boolean = false;\n\n constructor(\n public readonly id: number,\n public readonly req: Request,\n public readonly res: Response,\n public readonly timestamp: number,\n public readonly route: string,\n ) {}\n\n inc() {\n this.rc++;\n }\n\n dec() {\n this.rc--;\n if (this.rc === 0) {\n this.tryFinalize();\n }\n }\n\n private tryFinalize() {\n if (this.res.writableEnded || this.isClosed) return;\n\n this.isClosed = true;\n\n const errorMsg = `[Virid Express] Request Orphaned: The connection was closed because all systems finished execution without sending a response. \n Route: ${this.route}\n Uptime: ${Date.now() - this.timestamp}ms`;\n\n MessageWriter.error(new Error(errorMsg));\n\n if (!this.res.headersSent) {\n this.res.status(500).json({\n error: \"Internal Logic Error\",\n message:\n \"Request processed but no response was returned by any system.\",\n });\n } else {\n this.res.end();\n }\n }\n}\n\nexport abstract class HttpResponse {\n constructor(\n public status: number,\n public data: any = null,\n public headers: HttpHeaders = {},\n ) {}\n}\n\n// --- 2xx Success ---\nexport class OkResponse extends HttpResponse {\n constructor(data: any, headers: HttpHeaders = {}) {\n super(200, data, headers);\n }\n}\n\nexport class CreatedResponse extends HttpResponse {\n constructor(data: any, headers: HttpHeaders = {}) {\n super(201, data, headers);\n }\n}\n\nexport class NoContentResponse extends HttpResponse {\n constructor() {\n super(204, null);\n }\n}\n\n// --- 4xx Client Error ---\nexport class BadRequestResponse extends HttpResponse {\n constructor(message: string = \"Bad Request\") {\n super(400, { error: message });\n }\n}\n\nexport class UnauthorizedResponse extends HttpResponse {\n constructor(message: string = \"Unauthorized\") {\n super(401, { error: message });\n }\n}\n\nexport class ForbiddenResponse extends HttpResponse {\n constructor(message: string = \"Forbidden\") {\n super(403, { error: message });\n }\n}\n\nexport class NotFoundResponse extends HttpResponse {\n constructor(message: string = \"Not Found\") {\n super(404, { error: message });\n }\n}\n\nexport class ConflictResponse extends HttpResponse {\n constructor(message: string = \"Conflict\") {\n super(409, { error: message });\n }\n}\n\nexport class UnprocessableEntityResponse extends HttpResponse {\n constructor(errors: any) {\n super(422, { errors });\n }\n}\n\n// --- 5xx Server Error ---\nexport class InternalServerErrorResponse extends HttpResponse {\n constructor(message: string = \"Internal Server Error\") {\n super(500, { error: message });\n }\n}\n\n// --- 万能类 (Custom) ---\nexport class CustomResponseResponse extends HttpResponse {\n constructor(status: number, data: any, headers: HttpHeaders = {}) {\n super(status, data, headers);\n }\n}\n/**\n * @description: Express sendFile 配置项的强类型定义\n */\nexport interface StreamFileOptions {\n /** 根目录(如果 path 是相对路径则必填) */\n root?: string;\n /** * 对以 . 开头的文件处理策略:\n * - allow: 允许发送\n * - deny: 拒绝并返回 403\n * - ignore: 当作不存在返回 404\n */\n dotfiles?: \"allow\" | \"deny\" | \"ignore\";\n /** 是否发送 ETag */\n etag?: boolean;\n /** 扩展的 HTTP 响应头 */\n headers?: HttpHeaders;\n /** 缓存最大时长 (毫秒) */\n maxAge?: number | string;\n /** 是否在 Cache-Control 中添加 immutable */\n immutable?: boolean;\n /** 是否根据文件系统设置 Last-Modified */\n lastModified?: boolean;\n /** 是否支持断点续传 (Range 请求) */\n acceptRanges?: boolean;\n}\nexport class StreamFileResponse extends HttpResponse {\n constructor(\n public readonly filePath: string,\n public readonly options: StreamFileOptions = { dotfiles: \"allow\" },\n ) {\n super(206, options);\n }\n}\n\nexport class StreamResponse extends HttpResponse {\n constructor(\n public readonly stream: Readable,\n public readonly options: {\n status?: number;\n headers?: HttpHeaders;\n } = {},\n ) {\n super(options.status || 206, {}, options.headers);\n }\n}\n\n/** 200 OK */\nexport const Ok = (data: any, headers: HttpHeaders = {}) =>\n new OkResponse(data, headers);\n\n/** 201 Created */\nexport const Created = (data: any, headers: HttpHeaders = {}) =>\n new CreatedResponse(data, headers);\n\n/** 204 No Content */\nexport const NoContent = () => new NoContentResponse();\n\n/** 400 Bad Request */\nexport const BadRequest = (msg = \"Bad Request\") => new BadRequestResponse(msg);\n\n/** 401 Unauthorized */\nexport const Unauthorized = (msg = \"Unauthorized\") =>\n new UnauthorizedResponse(msg);\n\n/** 403 Forbidden */\nexport const Forbidden = (msg = \"Forbidden\") => new ForbiddenResponse(msg);\n\n/** 404 Not Found */\nexport const NotFound = (msg = \"Not Found\") => new NotFoundResponse(msg);\n\n/** 500 Internal Error */\nexport const InternalServerError = (\n msg: string | Error = \"Internal Server Error\",\n) => {\n return msg instanceof Error\n ? new InternalServerErrorResponse(msg.message)\n : new InternalServerErrorResponse(msg);\n};\n\nexport const CustomResponse = (\n status: number,\n data: any,\n headers: HttpHeaders = {},\n) => new CustomResponseResponse(status, data, headers);\n\n/** 发送本地文件 (自动处理 Range/206) */\nexport const StreamFile = (path: string, options?: StreamFileOptions) =>\n new StreamFileResponse(path, options);\n/**\n * 发送流响应\n */\nexport const Stream = (stream: Readable, options?: StreamResponse[\"options\"]) =>\n new StreamResponse(stream, options);\n\nexport class HttpError extends Error {\n constructor(\n public readonly status: number,\n public readonly message: string,\n ) {\n super(message);\n }\n}\n","/*\n * Copyright (c) 2026-present Ailrid.\n * Licensed under the Apache License, Version 2.0.\n * Project: Virid Express\n */\nimport { MessageWriter } from \"@virid/core\";\nimport { HttpError } from \".\";\nimport { type TransformPipe } from \"../interfaces\";\n\nexport function ParseIntPipe(val: string) {\n const res = parseInt(val, 10);\n if (isNaN(res))\n throw new HttpError(400, `Validation failed: \"${val}\" is not a number.`);\n return res;\n}\n\nexport function ParseBoolPipe(val: string) {\n if (val === \"true\" || val === \"1\") return true;\n if (val === \"false\" || val === \"0\") return false;\n return !!val;\n}\n\nconst autoPipeMap = new Map<any, TransformPipe<any>>();\nautoPipeMap.set(Number, ParseIntPipe);\nautoPipeMap.set(Boolean, ParseBoolPipe);\n\nexport function addAutoPipe<T>(type: T, pipe: TransformPipe<T>) {\n if (autoPipeMap.has(type)) {\n MessageWriter.error(\n new Error(\n `[Virid Express Pipe] Repeated Pipe: Auto pipe for ${type} has already been registered.`,\n ),\n );\n return;\n }\n autoPipeMap.set(type, pipe);\n}\n\nexport function getAutoPipe<T>(type: T): TransformPipe<T> | undefined {\n return autoPipeMap.get(type);\n}\n\nexport function parseRawCookie(\n cookieHeader: string | undefined,\n): Record<string, string> {\n const result: Record<string, string> = {};\n\n if (!cookieHeader) return result;\n const pairs = cookieHeader.split(\";\");\n\n for (const pair of pairs) {\n const indexOfEq = pair.indexOf(\"=\");\n if (indexOfEq === -1) continue;\n\n // 提取 key 和 value,并进行 trim 处理\n const key = pair.substring(0, indexOfEq).trim();\n if (!key) continue;\n\n let value = pair.substring(indexOfEq + 1).trim();\n\n if (value[0] === '\"' && value[value.length - 1] === '\"') {\n value = value.slice(1, -1);\n }\n\n try {\n result[key] = value.includes(\"%\") ? decodeURIComponent(value) : value;\n } catch (e) {\n result[key] = value;\n }\n }\n\n return result;\n}\n","/*\n * Copyright (c) 2026-present Ailrid.\n * Licensed under the Apache License, Version 2.0.\n * Project: Virid Express\n */\nimport { EventMessage } from \"@virid/core\";\nexport type RequestId = number & { readonly __brand: unique symbol };\n\nexport class HttpRequestMessage extends EventMessage {\n // ID must be of type RequestId\n constructor(private readonly __virid_express_id: RequestId) {\n super();\n }\n // expose a read-only attribute for use by the business layer\n public get requestId(): RequestId {\n return this.__virid_express_id;\n }\n}\n","/*\n * Copyright (c) 2026-present Ailrid.\n * Licensed under the Apache License, Version 2.0.\n * Project: Virid Express\n */\nimport { VIRID_METADATA } from \"@virid/core\";\n\nexport const VIRID_EXPRESS_METADATA = {\n ...VIRID_METADATA,\n HTTPROUTE: \"virid:express:route\",\n HTTPSYSTEM: \"virid:express:system\",\n BODY: \"virid:express:body\",\n QUERY: \"virid:express:query\",\n HEADERS: \"virid:express:header\",\n REQUEST: \"virid:express:request\",\n RESPONSE: \"virid:express:response\",\n CONTEXT: \"virid:express:context\",\n PARAMS: \"virid:express:params\",\n COOKIES: \"virid:express:cookie\",\n} as const;\n","/*\n * Copyright (c) 2026-present Ailrid.\n * Licensed under the Apache License, Version 2.0.\n * Project: Virid Express\n */\nimport { type Newable, type SystemContext } from \"@virid/core\";\nimport {\n type HttpRouteConfig,\n type HttpRouteInfo,\n type BodyMetadata,\n type HeaderMetadata,\n type QueryMetadata,\n type RequestMetadata,\n type ResponseMetadata,\n type ContextMetadata,\n type ParamMetadata,\n type TransformPipe,\n type CookieMetadata,\n type HttpSystemParams,\n type HttpMetadata,\n type HttpSystemConfig,\n} from \"../interfaces\";\nimport { HttpContext, HttpRequestMessage, parseRawCookie } from \"../http\";\n\nimport { VIRID_EXPRESS_METADATA } from \"./constant\";\n\nexport function HttpRoute(config: HttpRouteConfig) {\n return (constructor: Newable<HttpRequestMessage>) => {\n const params: string[] = [];\n const pathParts = config.path.split(\"/\");\n pathParts.forEach((part) => {\n if (part.startsWith(\":\")) {\n params.push(part.substring(1));\n }\n });\n\n const routeInfo: HttpRouteInfo = {\n ...config,\n httpMessage: constructor,\n params,\n };\n Reflect.defineMetadata(\n VIRID_EXPRESS_METADATA.HTTPROUTE,\n routeInfo,\n constructor,\n );\n };\n}\n\n/**\n * Check if there are multiple message type parameters in the parameters\n * @param types Parameter list\n */\nfunction checkMessageParam(types: Array<any>) {\n const foundMatches: { type: Newable<HttpRequestMessage>; idx: number }[] = [];\n\n types.forEach((type, idx) => {\n const isHttpRequestMessage =\n type === HttpRequestMessage ||\n (type && type.prototype instanceof HttpRequestMessage);\n\n if (isHttpRequestMessage) {\n foundMatches.push({ type, idx });\n }\n });\n\n if (foundMatches.length === 0) {\n return null;\n }\n\n if (foundMatches.length > 1) {\n const errorDetails = foundMatches\n .map((item) => `[Index: ${item.idx}, Name: ${item.type.name}]`)\n .join(\", \");\n\n throw new Error(\n `[Virid System] Multiple Messages: Multiple Message type parameters detected, this is not allowed! specific location: ${errorDetails}`,\n );\n }\n\n return foundMatches[0];\n}\n\n/**\n * @description: 系统装饰器\n * @param priority 优先级,数值越大越早执行\n */\nexport function HttpSystem(\n params: HttpSystemParams = {\n priority: 0,\n messageClass: null,\n },\n) {\n return (target: any, key: string, descriptor: PropertyDescriptor) => {\n if (typeof target !== \"function\") {\n throw new Error(\n `[Virid System] Method Type Error: The Method ${key} is not a static method, please check if there is a static keyword tag.`,\n );\n }\n\n const originalMethod = descriptor.value;\n const types: Array<any> = Reflect.getMetadata(\n \"design:paramtypes\",\n target,\n key,\n );\n\n // Verify if metadata exists\n if (!types) {\n throw new Error(\n `[Virid System] System Parameter Loss: Unable to recognize system parameters, please confirm if import \"reflect-metadata\" was introduced at the beginning.`,\n );\n }\n\n // Verify if there are undefined parameters\n const undefinedIndices = types\n .map((t, i) => (t === undefined ? i : -1))\n .filter((i) => i !== -1);\n if (undefinedIndices.length > 0) {\n throw new Error(\n `[Virid System] Parameter Metadata Loss in \"${key}\": One or more parameters have 'undefined' types. This usually happens when you forget to add a type annotation or due to circular dependencies. Check parameter at indices: [${undefinedIndices.join(\", \")}]`,\n );\n }\n\n let messageClass: Newable<HttpRequestMessage>;\n // eslint-disable-next-line no-useless-assignment\n let messageIdx: number = -1;\n const matchedMessage = checkMessageParam(types); // { type: any, idx: number } | null\n if (matchedMessage && params.messageClass) {\n throw new Error(\n `[Virid System] Multiple Messages Are Not Allowed: Cannot specify messageClass in decorator options while already declaring it in method parameters at index ${matchedMessage.idx} in ${key}.`,\n );\n }\n\n if (matchedMessage) {\n messageClass = matchedMessage.type;\n messageIdx = matchedMessage.idx; // In single mode, idx points to the location of a specific BaseMessage subclass\n } else if (params.messageClass) {\n messageClass = params.messageClass;\n messageIdx = -1; // Only provided in the configuration, cannot be found in the parameters, set to -1\n } else {\n throw new Error(\n `[Virid System] System Parameter Loss: Please declare the message type either in method parameters or via the Message decorator options.`,\n );\n }\n const httpMetadata = getHttpMetadata(target, key);\n\n // Attach contextual information to the packaged function\n const systemContext: SystemContext = {\n params: types,\n targetClass: target,\n methodName: key,\n originalMethod: originalMethod,\n };\n const httpSystemConfig: HttpSystemConfig = {\n httpMetadata: httpMetadata,\n messageClass: messageClass,\n messageIdx: messageIdx,\n priority: params.priority || 0,\n batchMode: false,\n };\n\n // Purely mounting data without changing the execution logic of the original method\n (descriptor.value as any).systemContext = systemContext;\n (descriptor.value as any).httpSystemConfig = httpSystemConfig;\n };\n}\n\nexport function Body() {\n return (target: any, key: string, index: number) => {\n if (Reflect.hasOwnMetadata(VIRID_EXPRESS_METADATA.BODY, target, key)) {\n throw new Error(\n `[Virid Express Body] Multiple Body Are Not Allowed: ${key} has multiple @Body() decorators!`,\n );\n }\n const bodyMetadata = { index } as BodyMetadata;\n Reflect.defineMetadata(\n VIRID_EXPRESS_METADATA.BODY,\n bodyMetadata,\n target,\n key,\n );\n };\n}\n\nexport function Headers() {\n return (target: any, key: string, index: number) => {\n if (Reflect.hasOwnMetadata(VIRID_EXPRESS_METADATA.HEADERS, target, key)) {\n throw new Error(\n `[Virid Express Headers] Multiple Header Are Not Allowed: ${key} has multiple @Headers() decorators!`,\n );\n }\n const headerMetadata = { index } as HeaderMetadata;\n Reflect.defineMetadata(\n VIRID_EXPRESS_METADATA.HEADERS,\n headerMetadata,\n target,\n key,\n );\n };\n}\n\nexport function Cookies() {\n return (target: any, key: string, index: number) => {\n if (Reflect.hasOwnMetadata(VIRID_EXPRESS_METADATA.COOKIES, target, key)) {\n throw new Error(\n `[Virid Express Cookies] Multiple Header Are Not Allowed: ${key} has multiple @Cookies() decorators!`,\n );\n }\n const cookiesMetadata = { index } as CookieMetadata;\n Reflect.defineMetadata(\n VIRID_EXPRESS_METADATA.COOKIES,\n cookiesMetadata,\n target,\n key,\n );\n };\n}\n\nexport function Req() {\n return (target: any, key: string, index: number) => {\n if (Reflect.hasOwnMetadata(VIRID_EXPRESS_METADATA.REQUEST, target, key)) {\n throw new Error(\n `[Virid Express Req] Multiple Request Objects Are Not Allowed: ${key} has multiple @Req() decorators!`,\n );\n }\n const requestMetadata: RequestMetadata = { index };\n Reflect.defineMetadata(\n VIRID_EXPRESS_METADATA.REQUEST,\n requestMetadata,\n target,\n key,\n );\n };\n}\n\nexport function Res() {\n return (target: any, key: string, index: number) => {\n if (Reflect.hasOwnMetadata(VIRID_EXPRESS_METADATA.RESPONSE, target, key)) {\n throw new Error(\n `[Virid Express Res] Multiple Response Objects Are Not Allowed: ${key} has multiple @Res() decorators!`,\n );\n }\n const responseMetadata: ResponseMetadata = { index };\n Reflect.defineMetadata(\n VIRID_EXPRESS_METADATA.RESPONSE,\n responseMetadata,\n target,\n key,\n );\n };\n}\n\nexport function Ctx() {\n return (target: any, key: string, index: number) => {\n if (Reflect.hasOwnMetadata(VIRID_EXPRESS_METADATA.CONTEXT, target, key)) {\n throw new Error(\n `[Virid Express Ctx] Multiple Context Objects Are Not Allowed: ${key} has multiple @Ctx() decorators!`,\n );\n }\n const contextMetadata: ContextMetadata = { index };\n Reflect.defineMetadata(\n VIRID_EXPRESS_METADATA.CONTEXT,\n contextMetadata,\n target,\n key,\n );\n };\n}\n\nexport function Query(query: string, pipe?: TransformPipe<any>) {\n return (target: any, key: string, index: number) => {\n const existingMetadata: QueryMetadata =\n Reflect.getOwnMetadata(VIRID_EXPRESS_METADATA.QUERY, target, key) || [];\n const newMetadata = [...existingMetadata, { index, query, pipe }];\n Reflect.defineMetadata(\n VIRID_EXPRESS_METADATA.QUERY,\n newMetadata,\n target,\n key,\n );\n };\n}\n\nexport function Params(key?: string, pipe?: TransformPipe<any>) {\n return (target: any, keyName: string, index: number) => {\n const existingMetadata: ParamMetadata =\n Reflect.getOwnMetadata(VIRID_EXPRESS_METADATA.PARAMS, target, keyName) ||\n [];\n const newMetadata = [...existingMetadata, { index, key, pipe }];\n Reflect.defineMetadata(\n VIRID_EXPRESS_METADATA.PARAMS,\n newMetadata,\n target,\n keyName,\n );\n };\n}\n\nfunction getHttpMetadata(target: any, key: string): HttpMetadata {\n const bodyMeta: BodyMetadata = Reflect.getOwnMetadata(\n VIRID_EXPRESS_METADATA.BODY,\n target,\n key,\n );\n const headerMeta: HeaderMetadata = Reflect.getOwnMetadata(\n VIRID_EXPRESS_METADATA.HEADERS,\n target,\n key,\n );\n const cookiesMeta: CookieMetadata = Reflect.getOwnMetadata(\n VIRID_EXPRESS_METADATA.COOKIES,\n target,\n key,\n );\n\n const resMeta: ResponseMetadata = Reflect.getOwnMetadata(\n VIRID_EXPRESS_METADATA.RESPONSE,\n target,\n key,\n );\n const reqMeta: RequestMetadata = Reflect.getOwnMetadata(\n VIRID_EXPRESS_METADATA.REQUEST,\n target,\n key,\n );\n const ctxMeta: ContextMetadata = Reflect.getOwnMetadata(\n VIRID_EXPRESS_METADATA.CONTEXT,\n target,\n key,\n );\n\n const queryMeta: QueryMetadata =\n Reflect.getOwnMetadata(VIRID_EXPRESS_METADATA.QUERY, target, key) || [];\n\n const paramMeta: ParamMetadata =\n Reflect.getOwnMetadata(VIRID_EXPRESS_METADATA.PARAMS, target, key) || [];\n\n return {\n bodyMeta,\n headerMeta,\n queryMeta,\n paramMeta,\n cookiesMeta,\n reqMeta,\n resMeta,\n ctxMeta,\n };\n}\n\nexport function getHttpArgs(\n index: number,\n context: HttpContext,\n httpMetadata: HttpMetadata,\n): any {\n const { req, res } = context;\n\n // 匹配 @Ctx()\n if (httpMetadata.ctxMeta?.index === index) return context;\n\n // 匹配 @Param() -> 获取路由参数 (:id 等)\n const paramItem = httpMetadata.paramMeta?.find((p) => p.index === index);\n if (paramItem) {\n let val = paramItem.key ? req.params[paramItem.key] : req.params;\n\n // 如果有 Pipe 且值不是 undefined,进行转换\n if (paramItem.pipe && val !== undefined) {\n val = paramItem.pipe(val);\n }\n return val;\n }\n\n // @Body()\n if (httpMetadata.bodyMeta?.index === index) return req.body;\n\n // @Header()\n if (httpMetadata.headerMeta?.index === index) return req.headers;\n\n // @Cookie()\n if (httpMetadata.cookiesMeta?.index === index)\n return parseRawCookie(req.headers.cookie);\n\n // @Req() 和 @Res()\n if (httpMetadata.reqMeta?.index === index) return req;\n if (httpMetadata.resMeta?.index === index) return res;\n\n // @Query('name')\n const queryItem = httpMetadata.queryMeta?.find((q) => q.index === index);\n if (queryItem) {\n let val = req.query[queryItem.query];\n if (val === undefined) {\n throw new Error(`[Virid Express] Missing Query: \"${queryItem.query}\"`);\n }\n\n if (queryItem.pipe) {\n val = queryItem.pipe(val);\n }\n return val;\n }\n return null;\n}\n"],"mappings":";;;;4NAiBA,OAGEA,mBAAAA,GACAC,iBAAAA,EAGAC,eAAAA,OACK,cClBP,OAASC,iBAAAA,OAAqB,cAIvB,IAAMC,EAAN,MAAMA,CAAAA,CAIX,YACkBC,EACAC,EACAC,EACAC,EACAC,EAChB,8EATKC,EAAAA,UAAa,GACbC,EAAAA,gBAAoB,SAGTN,GAAAA,OACAC,IAAAA,OACAC,IAAAA,OACAC,UAAAA,OACAC,MAAAA,CACf,CAEHG,KAAM,CACJ,KAAKF,IACP,CAEAG,KAAM,CACJ,KAAKH,KACD,KAAKA,KAAO,GACd,KAAKI,YAAW,CAEpB,CAEQA,aAAc,CACpB,GAAI,KAAKP,IAAIQ,eAAiB,KAAKJ,SAAU,OAE7C,KAAKA,SAAW,GAEhB,IAAMK,EAAW;aACR,KAAKP,KAAK;cACTQ,KAAKC,IAAG,EAAK,KAAKV,SAAS,KAErCW,GAAcC,MAAM,IAAIC,MAAML,CAAAA,CAAAA,EAEzB,KAAKT,IAAIe,YAOZ,KAAKf,IAAIgB,IAAG,EANZ,KAAKhB,IAAIiB,OAAO,GAAA,EAAKC,KAAK,CACxBL,MAAO,uBACPM,QACE,+DACJ,CAAA,CAIJ,CACF,EA5CatB,EAAAA,EAAAA,eAAN,IAAMA,EAANuB,EA8CeC,EAAf,MAAeA,CAAAA,CACpB,YACSJ,EACAK,EAAY,KACZC,EAAuB,CAAC,EAC/B,wDAHON,OAAAA,OACAK,KAAAA,OACAC,QAAAA,CACN,CACL,EANsBF,EAAAA,EAAAA,gBAAf,IAAeA,EAAfG,EASMC,EAAN,MAAMA,UAAmBJ,CAAAA,CAC9B,YAAYC,EAAWC,EAAuB,CAAC,EAAG,CAChD,MAAM,IAAKD,EAAMC,CAAAA,CACnB,CACF,EAJgCF,EAAAA,EAAAA,cAAzB,IAAMI,EAANC,EAMMC,EAAN,MAAMA,UAAwBN,CAAAA,CACnC,YAAYC,EAAWC,EAAuB,CAAC,EAAG,CAChD,MAAM,IAAKD,EAAMC,CAAAA,CACnB,CACF,EAJqCF,EAAAA,EAAAA,mBAA9B,IAAMM,EAANC,EAMMC,EAAN,MAAMA,UAA0BR,CAAAA,CACrC,aAAc,CACZ,MAAM,IAAK,IAAA,CACb,CACF,EAJuCA,EAAAA,EAAAA,qBAAhC,IAAMQ,EAANC,EAOMC,EAAN,MAAMA,UAA2BV,CAAAA,CACtC,YAAYF,EAAkB,cAAe,CAC3C,MAAM,IAAK,CAAEN,MAAOM,CAAQ,CAAA,CAC9B,CACF,EAJwCE,EAAAA,EAAAA,sBAAjC,IAAMU,EAANC,EAMMC,EAAN,MAAMA,UAA6BZ,CAAAA,CACxC,YAAYF,EAAkB,eAAgB,CAC5C,MAAM,IAAK,CAAEN,MAAOM,CAAQ,CAAA,CAC9B,CACF,EAJ0CE,EAAAA,EAAAA,wBAAnC,IAAMY,EAANC,EAMMC,EAAN,MAAMA,UAA0Bd,CAAAA,CACrC,YAAYF,EAAkB,YAAa,CACzC,MAAM,IAAK,CAAEN,MAAOM,CAAQ,CAAA,CAC9B,CACF,EAJuCE,EAAAA,EAAAA,qBAAhC,IAAMc,EAANC,EAMMC,EAAN,MAAMA,UAAyBhB,CAAAA,CACpC,YAAYF,EAAkB,YAAa,CACzC,MAAM,IAAK,CAAEN,MAAOM,CAAQ,CAAA,CAC9B,CACF,EAJsCE,EAAAA,EAAAA,oBAA/B,IAAMgB,EAANC,EAMMC,EAAN,MAAMA,UAAyBlB,CAAAA,CACpC,YAAYF,EAAkB,WAAY,CACxC,MAAM,IAAK,CAAEN,MAAOM,CAAQ,CAAA,CAC9B,CACF,EAJsCE,EAAAA,EAAAA,oBAA/B,IAAMkB,GAANC,EAMMC,EAAN,MAAMA,UAAoCpB,CAAAA,CAC/C,YAAYqB,EAAa,CACvB,MAAM,IAAK,CAAEA,OAAAA,CAAO,CAAA,CACtB,CACF,EAJiDrB,EAAAA,EAAAA,+BAA1C,IAAMoB,GAANE,EAOMC,EAAN,MAAMA,UAAoCvB,CAAAA,CAC/C,YAAYF,EAAkB,wBAAyB,CACrD,MAAM,IAAK,CAAEN,MAAOM,CAAQ,CAAA,CAC9B,CACF,EAJiDE,EAAAA,EAAAA,+BAA1C,IAAMuB,EAANC,EAOMC,EAAN,MAAMA,UAA+BzB,CAAAA,CAC1C,YAAYJ,EAAgBK,EAAWC,EAAuB,CAAC,EAAG,CAChE,MAAMN,EAAQK,EAAMC,CAAAA,CACtB,CACF,EAJ4CF,EAAAA,EAAAA,0BAArC,IAAMyB,EAANC,EA8BMC,GAAN,MAAMA,WAA2B3B,CAAAA,CACtC,YACkB4B,EACAC,EAA6B,CAAEC,SAAU,OAAQ,EACjE,CACA,MAAM,IAAKD,CAAAA,uCAAAA,KAHKD,SAAAA,EAAAA,KACAC,QAAAA,CAGlB,CACF,EAPwC7B,EAAAA,GAAAA,sBAAjC,IAAM2B,EAANI,GASMC,GAAN,MAAMA,WAAuBhC,CAAAA,CAClC,YACkBiC,EACAJ,EAGZ,CAAC,EACL,CACA,MAAMA,EAAQjC,QAAU,IAAK,CAAC,EAAGiC,EAAQ3B,OAAO,qCAAA,KANhC+B,OAAAA,EAAAA,KACAJ,QAAAA,CAMlB,CACF,EAVoC7B,EAAAA,GAAAA,kBAA7B,IAAMgC,EAANE,GAaMC,GAAKC,EAAA,CAACnC,EAAWC,EAAuB,CAAC,IACpD,IAAIE,EAAWH,EAAMC,CAAAA,EADL,MAILmC,GAAUD,EAAA,CAACnC,EAAWC,EAAuB,CAAC,IACzD,IAAII,EAAgBL,EAAMC,CAAAA,EADL,WAIVoC,GAAYF,EAAA,IAAM,IAAI5B,EAAV,aAGZ+B,GAAaH,EAAA,CAACI,EAAM,gBAAkB,IAAI9B,EAAmB8B,CAAAA,EAAhD,cAGbC,GAAeL,EAAA,CAACI,EAAM,iBACjC,IAAI5B,EAAqB4B,CAAAA,EADC,gBAIfE,GAAYN,EAAA,CAACI,EAAM,cAAgB,IAAI1B,EAAkB0B,CAAAA,EAA7C,aAGZG,GAAWP,EAAA,CAACI,EAAM,cAAgB,IAAIxB,EAAiBwB,CAAAA,EAA5C,YAGXI,EAAsBR,EAAA,CACjCI,EAAsB,0BAEfA,aAAe/C,MAClB,IAAI8B,EAA4BiB,EAAI1C,OAAO,EAC3C,IAAIyB,EAA4BiB,CAAAA,EALH,uBAQtBK,GAAiBT,EAAA,CAC5BxC,EACAK,EACAC,EAAuB,CAAC,IACrB,IAAIuB,EAAuB7B,EAAQK,EAAMC,CAAAA,EAJhB,kBAOjB4C,GAAaV,EAAA,CAACW,EAAclB,IACvC,IAAIF,EAAmBoB,EAAMlB,CAAAA,EADL,cAKbmB,GAASZ,EAAA,CAACH,EAAkBJ,IACvC,IAAIG,EAAeC,EAAQJ,CAAAA,EADP,UAGToB,GAAN,MAAMA,WAAkBxD,KAAAA,CAC7B,YACkBG,EACAE,EAChB,CACA,MAAMA,CAAAA,qCAAAA,KAHUF,OAAAA,EAAAA,KACAE,QAAAA,CAGlB,CACF,EAP+BL,EAAAA,GAAAA,aAAxB,IAAMwD,EAANC,GC/NP,OAASC,iBAAAA,OAAqB,cAIvB,SAASC,GAAaC,EAAW,CACtC,IAAMC,EAAMC,SAASF,EAAK,EAAA,EAC1B,GAAIG,MAAMF,CAAAA,EACR,MAAM,IAAIG,EAAU,IAAK,uBAAuBJ,CAAAA,oBAAuB,EACzE,OAAOC,CACT,CALgBF,EAAAA,GAAAA,gBAOT,SAASM,GAAcL,EAAW,CACvC,OAAIA,IAAQ,QAAUA,IAAQ,IAAY,GACtCA,IAAQ,SAAWA,IAAQ,IAAY,GACpC,CAAC,CAACA,CACX,CAJgBK,EAAAA,GAAAA,iBAMhB,IAAMC,EAAc,IAAIC,IACxBD,EAAYE,IAAIC,OAAQV,EAAAA,EACxBO,EAAYE,IAAIE,QAASL,EAAAA,EAElB,SAASM,GAAeC,EAASC,EAAsB,CAC5D,GAAIP,EAAYQ,IAAIF,CAAAA,EAAO,CACzBG,GAAcC,MACZ,IAAIC,MACF,qDAAqDL,CAAAA,+BAAmC,CAAA,EAG5F,MACF,CACAN,EAAYE,IAAII,EAAMC,CAAAA,CACxB,CAVgBF,EAAAA,GAAAA,eAYT,SAASO,GAAeN,EAAO,CACpC,OAAON,EAAYa,IAAIP,CAAAA,CACzB,CAFgBM,EAAAA,GAAAA,eAIT,SAASE,GACdC,EAAgC,CAEhC,IAAMC,EAAiC,CAAC,EAExC,GAAI,CAACD,EAAc,OAAOC,EAC1B,IAAMC,EAAQF,EAAaG,MAAM,GAAA,EAEjC,QAAWC,KAAQF,EAAO,CACxB,IAAMG,EAAYD,EAAKE,QAAQ,GAAA,EAC/B,GAAID,IAAc,GAAI,SAGtB,IAAME,EAAMH,EAAKI,UAAU,EAAGH,CAAAA,EAAWI,KAAI,EAC7C,GAAI,CAACF,EAAK,SAEV,IAAIG,EAAQN,EAAKI,UAAUH,EAAY,CAAA,EAAGI,KAAI,EAE1CC,EAAM,CAAA,IAAO,KAAOA,EAAMA,EAAMC,OAAS,CAAA,IAAO,MAClDD,EAAQA,EAAME,MAAM,EAAG,EAAC,GAG1B,GAAI,CACFX,EAAOM,CAAAA,EAAOG,EAAMG,SAAS,GAAA,EAAOC,mBAAmBJ,CAAAA,EAASA,CAClE,MAAY,CACVT,EAAOM,CAAAA,EAAOG,CAChB,CACF,CAEA,OAAOT,CACT,CA9BgBF,EAAAA,GAAAA,kBCrChB,OAASgB,gBAAAA,OAAoB,cAGtB,IAAMC,GAAN,MAAMA,WAA2BC,EAAAA,CAEtC,YAA6BC,EAA+B,CAC1D,MAAK,+BAAA,KADsBA,mBAAAA,CAE7B,CAEA,IAAWC,WAAuB,CAChC,OAAO,KAAKD,kBACd,CACF,EATwCD,EAAAA,GAAAA,sBAAjC,IAAMD,EAANI,GCHP,OAASC,kBAAAA,OAAsB,cAExB,IAAMC,EAAyB,CACpC,GAAGD,GACHE,UAAW,sBACXC,WAAY,uBACZC,KAAM,qBACNC,MAAO,sBACPC,QAAS,uBACTC,QAAS,wBACTC,SAAU,yBACVC,QAAS,wBACTC,OAAQ,uBACRC,QAAS,sBACX,ECOO,SAASC,GAAUC,EAAuB,CAC/C,OAAQC,GAAAA,CACN,IAAMC,EAAmB,CAAA,EACPF,EAAOG,KAAKC,MAAM,GAAA,EAC1BC,QAASC,GAAAA,CACbA,EAAKC,WAAW,GAAA,GAClBL,EAAOM,KAAKF,EAAKG,UAAU,CAAA,CAAA,CAE/B,CAAA,EAEA,IAAMC,EAA2B,CAC/B,GAAGV,EACHW,YAAaV,EACbC,OAAAA,CACF,EACAU,QAAQC,eACNC,EAAuBC,UACvBL,EACAT,CAAAA,CAEJ,CACF,CArBgBF,EAAAA,GAAAA,aA2BhB,SAASiB,GAAkBC,EAAiB,CAC1C,IAAMC,EAAqE,CAAA,EAY3E,GAVAD,EAAMZ,QAAQ,CAACc,EAAMC,IAAAA,EAEjBD,IAASE,GACRF,GAAQA,EAAKG,qBAAqBD,IAGnCH,EAAaV,KAAK,CAAEW,KAAAA,EAAMC,IAAAA,CAAI,CAAA,CAElC,CAAA,EAEIF,EAAaK,SAAW,EAC1B,OAAO,KAGT,GAAIL,EAAaK,OAAS,EAAG,CAC3B,IAAMC,EAAeN,EAClBO,IAAKC,GAAS,WAAWA,EAAKN,GAAG,WAAWM,EAAKP,KAAKQ,IAAI,GAAG,EAC7DC,KAAK,IAAA,EAER,MAAM,IAAIC,MACR,wHAAwHL,CAAAA,EAAc,CAE1I,CAEA,OAAON,EAAa,CAAA,CACtB,CA5BSF,EAAAA,GAAAA,qBAkCF,SAASc,GACd5B,EAA2B,CACzB6B,SAAU,EACVC,aAAc,IAChB,EAAC,CAED,MAAO,CAACC,EAAaC,EAAaC,IAAAA,CAChC,GAAI,OAAOF,GAAW,WACpB,MAAM,IAAIJ,MACR,gDAAgDK,CAAAA,yEAA4E,EAIhI,IAAME,EAAiBD,EAAWE,MAC5BpB,EAAoBL,QAAQ0B,YAChC,oBACAL,EACAC,CAAAA,EAIF,GAAI,CAACjB,EACH,MAAM,IAAIY,MACR,2JAA2J,EAK/J,IAAMU,EAAmBtB,EACtBQ,IAAI,CAACe,EAAGC,IAAOD,IAAME,OAAYD,EAAI,EAAC,EACtCE,OAAQF,GAAMA,IAAM,EAAC,EACxB,GAAIF,EAAiBhB,OAAS,EAC5B,MAAM,IAAIM,MACR,8CAA8CK,CAAAA,iLAAoLK,EAAiBX,KAAK,IAAA,CAAA,GAAQ,EAIpQ,IAAII,EAEAY,EAAqB,GACnBC,EAAiB7B,GAAkBC,CAAAA,EACzC,GAAI4B,GAAkB3C,EAAO8B,aAC3B,MAAM,IAAIH,MACR,+JAA+JgB,EAAezB,GAAG,OAAOc,CAAAA,GAAM,EAIlM,GAAIW,EACFb,EAAea,EAAe1B,KAC9ByB,EAAaC,EAAezB,YACnBlB,EAAO8B,aAChBA,EAAe9B,EAAO8B,aACtBY,EAAa,OAEb,OAAM,IAAIf,MACR,yIAAyI,EAG7I,IAAMiB,EAAeC,GAAgBd,EAAQC,CAAAA,EAGvCc,EAA+B,CACnC9C,OAAQe,EACRgC,YAAahB,EACbiB,WAAYhB,EACZE,eAAgBA,CAClB,EACMe,EAAqC,CACzCL,aAAcA,EACdd,aAAcA,EACdY,WAAYA,EACZb,SAAU7B,EAAO6B,UAAY,EAC7BqB,UAAW,EACb,EAGCjB,EAAWE,MAAcW,cAAgBA,EACzCb,EAAWE,MAAcc,iBAAmBA,CAC/C,CACF,CA/EgBrB,EAAAA,GAAAA,cAiFT,SAASuB,IAAAA,CACd,MAAO,CAACpB,EAAaC,EAAaoB,IAAAA,CAChC,GAAI1C,QAAQ2C,eAAezC,EAAuB0C,KAAMvB,EAAQC,CAAAA,EAC9D,MAAM,IAAIL,MACR,uDAAuDK,CAAAA,mCAAsC,EAGjG,IAAMuB,EAAe,CAAEH,MAAAA,CAAM,EAC7B1C,QAAQC,eACNC,EAAuB0C,KACvBC,EACAxB,EACAC,CAAAA,CAEJ,CACF,CAfgBmB,EAAAA,GAAAA,QAiBT,SAASK,IAAAA,CACd,MAAO,CAACzB,EAAaC,EAAaoB,IAAAA,CAChC,GAAI1C,QAAQ2C,eAAezC,EAAuB6C,QAAS1B,EAAQC,CAAAA,EACjE,MAAM,IAAIL,MACR,4DAA4DK,CAAAA,sCAAyC,EAGzG,IAAM0B,EAAiB,CAAEN,MAAAA,CAAM,EAC/B1C,QAAQC,eACNC,EAAuB6C,QACvBC,EACA3B,EACAC,CAAAA,CAEJ,CACF,CAfgBwB,EAAAA,GAAAA,WAiBT,SAASG,IAAAA,CACd,MAAO,CAAC5B,EAAaC,EAAaoB,IAAAA,CAChC,GAAI1C,QAAQ2C,eAAezC,EAAuBgD,QAAS7B,EAAQC,CAAAA,EACjE,MAAM,IAAIL,MACR,4DAA4DK,CAAAA,sCAAyC,EAGzG,IAAM6B,EAAkB,CAAET,MAAAA,CAAM,EAChC1C,QAAQC,eACNC,EAAuBgD,QACvBC,EACA9B,EACAC,CAAAA,CAEJ,CACF,CAfgB2B,EAAAA,GAAAA,WAiBT,SAASG,IAAAA,CACd,MAAO,CAAC/B,EAAaC,EAAaoB,IAAAA,CAChC,GAAI1C,QAAQ2C,eAAezC,EAAuBmD,QAAShC,EAAQC,CAAAA,EACjE,MAAM,IAAIL,MACR,iEAAiEK,CAAAA,kCAAqC,EAG1G,IAAMgC,EAAmC,CAAEZ,MAAAA,CAAM,EACjD1C,QAAQC,eACNC,EAAuBmD,QACvBC,EACAjC,EACAC,CAAAA,CAEJ,CACF,CAfgB8B,EAAAA,GAAAA,OAiBT,SAASG,IAAAA,CACd,MAAO,CAAClC,EAAaC,EAAaoB,IAAAA,CAChC,GAAI1C,QAAQ2C,eAAezC,EAAuBsD,SAAUnC,EAAQC,CAAAA,EAClE,MAAM,IAAIL,MACR,kEAAkEK,CAAAA,kCAAqC,EAG3G,IAAMmC,EAAqC,CAAEf,MAAAA,CAAM,EACnD1C,QAAQC,eACNC,EAAuBsD,SACvBC,EACApC,EACAC,CAAAA,CAEJ,CACF,CAfgBiC,EAAAA,GAAAA,OAiBT,SAASG,IAAAA,CACd,MAAO,CAACrC,EAAaC,EAAaoB,IAAAA,CAChC,GAAI1C,QAAQ2C,eAAezC,EAAuByD,QAAStC,EAAQC,CAAAA,EACjE,MAAM,IAAIL,MACR,iEAAiEK,CAAAA,kCAAqC,EAG1G,IAAMsC,EAAmC,CAAElB,MAAAA,CAAM,EACjD1C,QAAQC,eACNC,EAAuByD,QACvBC,EACAvC,EACAC,CAAAA,CAEJ,CACF,CAfgBoC,EAAAA,GAAAA,OAiBT,SAASG,GAAMC,EAAeC,EAAyB,CAC5D,MAAO,CAAC1C,EAAaC,EAAaoB,IAAAA,CAGhC,IAAMsB,EAAc,IADlBhE,QAAQiE,eAAe/D,EAAuBgE,MAAO7C,EAAQC,CAAAA,GAAQ,CAAA,EAC7B,CAAEoB,MAAAA,EAAOoB,MAAAA,EAAOC,KAAAA,CAAK,GAC/D/D,QAAQC,eACNC,EAAuBgE,MACvBF,EACA3C,EACAC,CAAAA,CAEJ,CACF,CAZgBuC,EAAAA,GAAAA,SAcT,SAASM,GAAO7C,EAAcyC,EAAyB,CAC5D,MAAO,CAAC1C,EAAa+C,EAAiB1B,IAAAA,CAIpC,IAAMsB,EAAc,IAFlBhE,QAAQiE,eAAe/D,EAAuBmE,OAAQhD,EAAQ+C,CAAAA,GAC9D,CAAA,EACwC,CAAE1B,MAAAA,EAAOpB,IAAAA,EAAKyC,KAAAA,CAAK,GAC7D/D,QAAQC,eACNC,EAAuBmE,OACvBL,EACA3C,EACA+C,CAAAA,CAEJ,CACF,CAbgBD,EAAAA,GAAAA,UAehB,SAAShC,GAAgBd,EAAaC,EAAW,CAC/C,IAAMgD,EAAyBtE,QAAQiE,eACrC/D,EAAuB0C,KACvBvB,EACAC,CAAAA,EAEIiD,EAA6BvE,QAAQiE,eACzC/D,EAAuB6C,QACvB1B,EACAC,CAAAA,EAEIkD,EAA8BxE,QAAQiE,eAC1C/D,EAAuBgD,QACvB7B,EACAC,CAAAA,EAGImD,EAA4BzE,QAAQiE,eACxC/D,EAAuBsD,SACvBnC,EACAC,CAAAA,EAEIoD,EAA2B1E,QAAQiE,eACvC/D,EAAuBmD,QACvBhC,EACAC,CAAAA,EAEIqD,EAA2B3E,QAAQiE,eACvC/D,EAAuByD,QACvBtC,EACAC,CAAAA,EAGIsD,EACJ5E,QAAQiE,eAAe/D,EAAuBgE,MAAO7C,EAAQC,CAAAA,GAAQ,CAAA,EAEjEuD,EACJ7E,QAAQiE,eAAe/D,EAAuBmE,OAAQhD,EAAQC,CAAAA,GAAQ,CAAA,EAExE,MAAO,CACLgD,SAAAA,EACAC,WAAAA,EACAK,UAAAA,EACAC,UAAAA,EACAL,YAAAA,EACAE,QAAAA,EACAD,QAAAA,EACAE,QAAAA,CACF,CACF,CAjDSxC,EAAAA,GAAAA,mBAmDF,SAAS2C,GACdpC,EACAqC,EACA7C,EAA0B,CAE1B,GAAM,CAAE8C,IAAAA,EAAKC,IAAAA,CAAG,EAAKF,EAGrB,GAAI7C,EAAayC,SAASjC,QAAUA,EAAO,OAAOqC,EAGlD,IAAMG,EAAYhD,EAAa2C,WAAWM,KAAMC,GAAMA,EAAE1C,QAAUA,CAAAA,EAClE,GAAIwC,EAAW,CACb,IAAIG,EAAMH,EAAU5D,IAAM0D,EAAI1F,OAAO4F,EAAU5D,GAAG,EAAI0D,EAAI1F,OAG1D,OAAI4F,EAAUnB,MAAQsB,IAAQvD,SAC5BuD,EAAMH,EAAUnB,KAAKsB,CAAAA,GAEhBA,CACT,CAGA,GAAInD,EAAaoC,UAAU5B,QAAUA,EAAO,OAAOsC,EAAIM,KAGvD,GAAIpD,EAAaqC,YAAY7B,QAAUA,EAAO,OAAOsC,EAAIO,QAGzD,GAAIrD,EAAasC,aAAa9B,QAAUA,EACtC,OAAO8C,GAAeR,EAAIO,QAAQE,MAAM,EAG1C,GAAIvD,EAAawC,SAAShC,QAAUA,EAAO,OAAOsC,EAClD,GAAI9C,EAAauC,SAAS/B,QAAUA,EAAO,OAAOuC,EAGlD,IAAMS,EAAYxD,EAAa0C,WAAWO,KAAMQ,GAAMA,EAAEjD,QAAUA,CAAAA,EAClE,GAAIgD,EAAW,CACb,IAAIL,EAAML,EAAIlB,MAAM4B,EAAU5B,KAAK,EACnC,GAAIuB,IAAQvD,OACV,MAAM,IAAIb,MAAM,mCAAmCyE,EAAU5B,KAAK,GAAG,EAGvE,OAAI4B,EAAU3B,OACZsB,EAAMK,EAAU3B,KAAKsB,CAAAA,GAEhBA,CACT,CACA,OAAO,IACT,CAlDgBP,EAAAA,GAAAA,eL5ST,IAAMc,GAAN,MAAMA,EAAAA,CAAN,cACLC,EAAAA,YAAO,kBAECC,EAAAA,6BAAwB,IAAIC,IAE5BC,EAAAA,yBAAoB,IAAIC,KAExBC,EAAAA,wBAAmB,IAAID,KAEvBE,EAAAA,8BAAyB,GAEjCC,SAASC,EAA+C,CAEtD,IAAMC,EAA+BD,EAASC,cAExCC,EAAqCF,EAASE,iBACpD,GAAI,CAACD,GAAiB,CAACC,EACrB,MAAM,IAAIC,MACR,gEAAgEH,EAASR,IAAI,yCAAyC,EAG1H,YAAKC,sBAAsBM,SACzBE,EAAcG,YACdJ,EACAE,EAAiBG,QAAQ,EAEpB,IAAA,CAAO,CAChB,CAEAC,UAAUC,EAA0C,CAClD,IAAMC,EAAwBC,QAAQC,YACpCC,EAAuBC,UACvBL,CAAAA,EAEF,GAAI,CAACC,EACH,MAAM,IAAIL,MACR,+BAA+BI,EAAYf,IAAI,2BAA2B,EAI9E,IAAMqB,EAAW,GAAGL,EAAOM,MAAM,IAAIN,EAAOO,IAAI,GAChD,GAAI,KAAKpB,kBAAkBqB,IAAIH,CAAAA,EAC7B,MAAM,IAAIV,MACR,qDAAqDK,EAAOM,MAAM,aAAaN,EAAOO,IAAI,mCAAmCR,EAAYf,IAAI,EAAE,EAGjJ,KAAKG,kBAAkBsB,IAAIJ,EAAUL,CAAAA,CAEzC,CAEAU,QAAQC,EAAeC,EAAwB,CAE7C,OAAW,CAACC,EAAGC,CAAAA,IAAc,KAAK3B,kBAAkB4B,QAAO,EAAI,CAC7D,GAAM,CAAET,OAAAA,EAAQC,KAAAA,EAAMS,YAAAA,CAAW,EAAKF,EAChCG,EAAgBX,EAAOY,YAAW,EAExCN,EAAQO,OAAOF,CAAAA,EAAeV,EAAM,CAACa,EAAcC,IAAAA,CAEjD,IAAMC,EAAQ,KAAKhC,2BAA6B,EAGhC,IAAIiC,EAAYD,EAAOF,EAAKC,EAAKG,KAAKC,IAAG,EAAIlB,CAAAA,EACrDmB,IAAG,EACX,KAAKrC,iBAAiBoB,IACpBa,EACA,IAAIC,EAAYD,EAAOF,EAAKC,EAAKG,KAAKC,IAAG,EAAIlB,CAAAA,CAAAA,EAE/C,IAAMoB,EAAU,IAAIX,EAAYM,CAAAA,EAEhCD,EAAIO,KAAK,SAAU,IAAM,KAAKvC,iBAAiBwC,OAAOP,CAAAA,CAAAA,EACtDD,EAAIO,KAAK,QAAS,IAAM,KAAKvC,iBAAiBwC,OAAOP,CAAAA,CAAAA,EAErDQ,EAAcC,MAAMJ,CAAAA,CACtB,CAAA,CACF,CAGA,OAAW,CACTK,EACAC,CAAAA,IACG,KAAKhD,sBAAsBiD,cAAcnB,QAAO,EACnD,QAAWoB,KAAQF,EAAa,CAC9B,IAAMzC,EAAW2C,EAAKC,GAEhB3C,EAA+BD,EAASC,cAExCC,EAAqCF,EAASE,iBAC9C,CAAE2C,aAAAA,EAAcL,aAAAA,EAAcM,WAAAA,CAAU,EAAK5C,EAC7C,CAAE6C,eAAAA,EAAgB3C,YAAAA,CAAW,EAAKH,EAClC+C,EAAgBC,EAACC,GAAAA,CAErB,IAAMC,EAAU,KAAKtD,iBAAiBuD,IAAIF,EAAeG,SAAS,EAClE,GAAI,CAACF,EACH,MAAM,IAAIhD,MACR,uFAAuF+C,EAAeG,SAAS,cAAc,EAGjI,GAAI,CACF,IAAMC,EAAOrD,EAAcsD,OAAOC,IAChC,CAACC,EAAWC,KAAAA,CAEV,GAAIA,KAAUZ,EACZ,OAAOI,EACF,CAEL,IAAMS,GAAMC,GAAYF,GAAOP,EAASN,CAAAA,EACxC,OAAOc,IAAYxC,EAAIiC,IAAIK,CAAAA,CAC7B,CACF,CAAA,EAEII,EAASd,EAAee,MAAM1D,EAAakD,CAAAA,EACjD,OAAOO,aAAkBE,QACrBF,EACGG,KAAMnC,GAAAA,CACL,KAAKoC,aAAapC,EAAKsB,CAAAA,CACzB,CAAA,EACCe,MAAOC,GAAAA,CAEN,WAAKF,aAAaG,EAAoBD,CAAAA,EAAQhB,CAAAA,EAExCgB,CACR,CAAA,EACF,KAAKF,aAAaJ,EAAQV,CAAAA,CAChC,OAASgB,EAAO,CACd,MAAIA,aAAiBE,EAEnB,KAAKJ,aAAaE,EAAOhB,CAAAA,EAGzB,KAAKc,aAAaG,EAAoBD,CAAAA,EAAiBhB,CAAAA,EAEnDgB,CACR,CACF,EA5CsB,iBA6CtBnB,EAAc/C,cAAgBA,EAC9B+C,EAAc9C,iBAAmBA,EACjCiB,EAAImD,OAAOvE,SAASyC,EAAcQ,EAAeL,EAAKtC,QAAQ,CAChE,CAEF,KAAKZ,sBAAsBiD,cAAc6B,MAAK,CAChD,CAEAN,aAAapC,EAAUsB,EAAsB,CAC3C,GAAI,CAACtB,EAAK,CACRsB,EAAQqB,IAAG,EACX,MACF,EACgBC,MAAMC,QAAQ7C,CAAAA,EAAOA,EAAM,CAACA,IACpC8C,QAASC,GAAAA,CACXA,aAAgBC,EAElB,KAAKC,mBAAmBF,EAAMzB,CAAAA,EACrByB,aAAgBP,GAEzBlB,EAAQtB,IAAIkD,OAAOH,EAAKG,MAAM,EAAEC,KAAKJ,EAAKzC,OAAO,EACjD,KAAKtC,iBAAiBwC,OAAOc,EAAQ8B,EAAE,GAC9BL,aAAgBM,GACzB5C,EAAcC,MAAMqC,CAAAA,EAEpBtC,EAAc6C,KACZ,wCAAwC,OAAOP,CAAAA,qCAAyC,CAG9F,CAAA,EAMAzB,EAAQqB,IAAG,CACb,CAEAM,mBAAmBM,EAAwBC,EAAkB,CAC3D,GAAM,CAAExD,IAAAA,CAAG,EAAKwD,EAQhB,GANID,EAASE,SACXC,OAAOhE,QAAQ6D,EAASE,OAAO,EAAEX,QAAQ,CAAC,CAACa,EAAGC,CAAAA,IAAO5D,EAAI6D,UAAUF,EAAGC,CAAAA,CAAAA,EAGpEL,EAASL,QAAQlD,EAAIkD,OAAOK,EAASL,MAAM,EAE3CK,aAAoBO,EAAoB,CAE1CN,EAAInD,IAAG,EACPL,EAAI+D,SAASR,EAASS,SAAUT,EAAShE,QAAU0E,GAAAA,CAC5CjE,EAAIkE,aACPzD,EAAc6B,MACZ2B,EACA,0CAA0CV,EAASS,QAAQ,EAAE,EAGjER,EAAIxD,IAAImE,IAAG,EACX,KAAKnG,iBAAiBwC,OAAOgD,EAAIJ,EAAE,EACnCI,EAAIY,SAAW,GACfZ,EAAIb,IAAG,CACT,CAAA,EACA,MACF,CACA,GAAIY,aAAoBc,EAAgB,CACtC,GAAM,CAAEC,OAAAA,CAAM,EAAKf,EACnBC,EAAInD,IAAG,EACPiE,EAAOC,KAAKvE,CAAAA,EAEZ,IAAMwE,EAAUpD,EAAA,IAAA,CACT,KAAKpD,iBAAiBmB,IAAIqE,EAAIJ,EAAE,IACrCI,EAAIxD,IAAImE,IAAG,EACX,KAAKnG,iBAAiBwC,OAAOgD,EAAIJ,EAAE,EACnCI,EAAIY,SAAW,GACfZ,EAAIb,IAAG,EACT,EANgB,WAOhB2B,EAAOG,GAAG,MAAOD,CAAAA,EACjBF,EAAOG,GAAG,QAAUR,GAAAA,CACbjE,EAAIkE,aACPzD,EAAc6B,MAAM2B,EAAK,8BAA8B,EAEzDO,EAAAA,CACF,CAAA,EACAF,EAAOG,GAAG,QAASD,CAAAA,EACnB,MACF,CAEAxE,EAAIkD,OAAOK,EAASL,MAAM,EAAEC,KAAKI,EAASmB,IAAI,EAC9C,KAAK1G,iBAAiBwC,OAAOgD,EAAIJ,EAAE,CACrC,CACF,EAhOa1F,EAAAA,GAAAA,iBAAN,IAAMA,GAANiH","names":["MessageRegistry","MessageWriter","BaseMessage","MessageWriter","HttpContext","id","req","res","timestamp","route","rc","isClosed","inc","dec","tryFinalize","writableEnded","errorMsg","Date","now","MessageWriter","error","Error","headersSent","end","status","json","message","_HttpContext","HttpResponse","data","headers","_HttpResponse","OkResponse","_OkResponse","CreatedResponse","_CreatedResponse","NoContentResponse","_NoContentResponse","BadRequestResponse","_BadRequestResponse","UnauthorizedResponse","_UnauthorizedResponse","ForbiddenResponse","_ForbiddenResponse","NotFoundResponse","_NotFoundResponse","ConflictResponse","_ConflictResponse","UnprocessableEntityResponse","errors","_UnprocessableEntityResponse","InternalServerErrorResponse","_InternalServerErrorResponse","CustomResponseResponse","_CustomResponseResponse","StreamFileResponse","filePath","options","dotfiles","_StreamFileResponse","StreamResponse","stream","_StreamResponse","Ok","__name","Created","NoContent","BadRequest","msg","Unauthorized","Forbidden","NotFound","InternalServerError","CustomResponse","StreamFile","path","Stream","HttpError","_HttpError","MessageWriter","ParseIntPipe","val","res","parseInt","isNaN","HttpError","ParseBoolPipe","autoPipeMap","Map","set","Number","Boolean","addAutoPipe","type","pipe","has","MessageWriter","error","Error","getAutoPipe","get","parseRawCookie","cookieHeader","result","pairs","split","pair","indexOfEq","indexOf","key","substring","trim","value","length","slice","includes","decodeURIComponent","EventMessage","HttpRequestMessage","EventMessage","__virid_express_id","requestId","_HttpRequestMessage","VIRID_METADATA","VIRID_EXPRESS_METADATA","HTTPROUTE","HTTPSYSTEM","BODY","QUERY","HEADERS","REQUEST","RESPONSE","CONTEXT","PARAMS","COOKIES","HttpRoute","config","constructor","params","path","split","forEach","part","startsWith","push","substring","routeInfo","httpMessage","Reflect","defineMetadata","VIRID_EXPRESS_METADATA","HTTPROUTE","checkMessageParam","types","foundMatches","type","idx","HttpRequestMessage","prototype","length","errorDetails","map","item","name","join","Error","HttpSystem","priority","messageClass","target","key","descriptor","originalMethod","value","getMetadata","undefinedIndices","t","i","undefined","filter","messageIdx","matchedMessage","httpMetadata","getHttpMetadata","systemContext","targetClass","methodName","httpSystemConfig","batchMode","Body","index","hasOwnMetadata","BODY","bodyMetadata","Headers","HEADERS","headerMetadata","Cookies","COOKIES","cookiesMetadata","Req","REQUEST","requestMetadata","Res","RESPONSE","responseMetadata","Ctx","CONTEXT","contextMetadata","Query","query","pipe","newMetadata","getOwnMetadata","QUERY","Params","keyName","PARAMS","bodyMeta","headerMeta","cookiesMeta","resMeta","reqMeta","ctxMeta","queryMeta","paramMeta","getHttpArgs","context","req","res","paramItem","find","p","val","body","headers","parseRawCookie","cookie","queryItem","q","ExpressPlugin","name","stagingSystemRegister","MessageRegistry","httpRouteRegistry","Map","httpContextStore","_internalHttpIdCounter","register","systemFn","systemContext","httpSystemConfig","Error","targetClass","priority","bindRoute","constructor","config","Reflect","getMetadata","VIRID_EXPRESS_METADATA","HTTPROUTE","routeKey","method","path","has","set","install","app","options","_","routeInfo","entries","httpMessage","expressMethod","toLowerCase","server","req","res","newId","HttpContext","Date","now","inc","message","once","delete","MessageWriter","write","messageClass","systemTasks","systemTaskMap","task","fn","httpMetadata","messageIdx","originalMethod","wrappedSystem","__name","currentMessage","context","get","requestId","args","params","map","type","index","arg","getHttpArgs","result","apply","Promise","then","handleResult","catch","error","InternalServerError","HttpError","engine","clear","dec","Array","isArray","forEach","item","HttpResponse","handleHttpResponse","status","json","id","BaseMessage","warn","response","ctx","headers","Object","k","v","setHeader","StreamFileResponse","sendFile","filePath","err","headersSent","end","isClosed","StreamResponse","stream","pipe","cleanup","on","data","_ExpressPlugin"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@virid/express",
3
3
  "type": "module",
4
- "version": "0.2.2",
4
+ "version": "0.3.0",
5
5
  "description": "Add express functionality to virid",
6
6
  "author": "Ailrid",
7
7
  "license": "Apache 2.0",
@@ -33,9 +33,9 @@
33
33
  },
34
34
  "dependencies": {},
35
35
  "peerDependencies": {
36
- "express": "^4.17.1 || ^5.0.0",
37
- "@types/express": "^5.0.6",
38
- "@virid/core": "0.2.2"
36
+ "express": ">=4.17.1",
37
+ "@types/express": ">=4.17.1",
38
+ "@virid/core": "0.3.0"
39
39
  },
40
40
  "scripts": {
41
41
  "build": "tsup --config tsup.config.ts"