tezx 1.0.0 → 1.0.2

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.mjs CHANGED
@@ -1,5 +1,2492 @@
1
- var D=Object.defineProperty;var d=(l,t)=>D(l,"name",{value:t,configurable:!0});import{createRequire as P}from"node:module";const N=P(import.meta.url);class j{static{d(this,"HeadersParser")}headers=new Map;constructor(t){t&&this.add(t)}add(t){if(Array.isArray(t))for(const[e,s]of t)this.set(e,s);else if(typeof Headers<"u"&&t instanceof Headers)for(const[e,s]of t.entries())this.set(e,s);else if(typeof t=="object")for(const e in t)Object.prototype.hasOwnProperty.call(t,e)&&this.set(e,t[e]);return this}set(t,e){return this.headers.set(t.toLowerCase(),Array.isArray(e)?e:[e]),this}get(t){const e=this.headers.get(t.toLowerCase());return e?e[0]:void 0}getAll(t){return this.headers.get(t.toLowerCase())||[]}has(t){return this.headers.has(t.toLowerCase())}delete(t){return this.headers.delete(t.toLowerCase())}append(t,e){const s=t.toLowerCase();return this.headers.has(s)?this.headers.get(s).push(e):this.headers.set(s,[e]),this}entries(){return this.headers.entries()}keys(){return this.headers.keys()}values(){return this.headers.values()}forEach(t){for(const[e,s]of this.headers)t(s,e)}toObject(){const t={};for(const[e,s]of this.headers.entries())t[e]=s.length>1?s:s[0];return t}}Object.defineProperty(j,"name",{value:"Headers"});class x{static{d(this,"EnvironmentDetector")}static get getEnvironment(){return typeof Bun<"u"?"bun":typeof Deno<"u"?"deno":typeof process<"u"&&process.versions?.node?"node":"unknown"}static detectProtocol(t){try{return this.getEnvironment==="node"?t?.socket?.encrypted?"https":"http":"unknown"}catch{throw new Error("Failed to detect protocol.")}}static getHost(t){try{return t?.get("host")||"unknown"}catch{throw new Error("Failed to get host.")}}}async function O(l){const t=x.getEnvironment;if(t==="node")return new Promise((e,s)=>{let n="";l.on("data",r=>{n+=r.toString()}),l.on("end",()=>{try{e(JSON.parse(n))}catch{s(new Error("Invalid JSON format"))}})});if(t==="deno"||t==="bun")return await l.json();throw new Error("Unsupported environment for multipart parsing")}d(O,"parseJsonBody");async function k(l){const t=x.getEnvironment;if(t==="node")return new Promise((e,s)=>{let n="";l.on("data",r=>{n+=r.toString()}),l.on("end",()=>{try{e(n)}catch{s(new Error("Invalid JSON format"))}})});if(t==="deno"||t==="bun")return await l.text();throw new Error("Unsupported environment for multipart parsing")}d(k,"parseTextBody");async function L(l){const t=x.getEnvironment;if(t==="node")return new Promise((e,s)=>{let n="";l.on("data",r=>{n+=r.toString("binary")}),l.on("end",()=>{try{const r=n.split("&"),i={};r.forEach(o=>{const[a,c]=o.split("=");i[decodeURIComponent(a)]=decodeURIComponent(c||"")}),e(i)}catch{s(new Error("Invalid x-www-form-urlencoded format"))}})});if(t==="deno"||t==="bun"){const e=await l.formData(),s={};for(const[n,r]of e.entries())s[n]=r;return s}else throw new Error("Unsupported environment for multipart parsing")}d(L,"parseUrlEncodedBody");async function H(l,t,e){const s=x.getEnvironment;if(e?.sanitized,s==="node")return new Promise((n,r)=>{let i="";l.on("data",o=>{i+=o.toString("binary")}),l.on("end",()=>{try{const o={};i.split("----------------------------").forEach(h=>{const u=h.match(/name="(.*)"\r\n\r\n(.*)\r\n/);if(u&&u.length===3){const f=u[1],p=u[2];o[f]=p}});const c=i.split(`--${t}`);for(const h of c)if(h.includes("filename")){const u=h.match(/filename="([^"]+)"/),f=h.match(/name="([^"]+)"/),p=h.match(/Content-Type: ([^\r\n]+)/);if(u&&f&&p){let m=u[1];const y=f[1],g=p[1];e?.sanitized&&(m=`${Date.now()}-${m.replace(/\s+/g,"")?.replace(/[^a-zA-Z0-9.-]/g,"-")}`?.toLowerCase()),Array.isArray(e?.allowedTypes)&&!e.allowedTypes?.includes(g)&&r(`Invalid file type: "${g}". Allowed types: ${e.allowedTypes.join(", ")}`);const C=h.indexOf(`\r
2
- \r
3
- `)+4,v=Buffer.from(h.substring(C),"binary"),E=v.buffer.slice(v.byteOffset,v.byteOffset+v.byteLength);typeof e?.maxSize<"u"&&v.byteLength>e.maxSize&&r(`File size exceeds the limit: ${v.byteLength} bytes (Max: ${e.maxSize} bytes)`);const T=new File([E],m,{type:g});o[y]?Array.isArray(o[y])?o[y].push(T):o[y]=[o[y],T]:o[y]=T}}n(o)}catch{}})});if(s==="deno"||s==="bun"){const n=await l.formData(),r={};for(const[i,o]of n.entries()){let a=o;if(a instanceof File&&typeof e=="object"){let c=a.name;if(e?.sanitized&&(c=`${Date.now()}-${c.replace(/\s+/g,"")?.replace(/[^a-zA-Z0-9.-]/g,"-")}`?.toLowerCase()),Array.isArray(e?.allowedTypes)&&!e.allowedTypes?.includes(a.type))throw new Error(`Invalid file type: "${a.type}". Allowed types: ${e.allowedTypes.join(", ")}`);if(typeof e?.maxSize<"u"&&a.size>e.maxSize)throw new Error(`File size exceeds the limit: ${a.size} bytes (Max: ${e.maxSize} bytes)`);a=new File([await a.arrayBuffer()],c,{type:a.type})}r[i]?Array.isArray(r[i])?r[i].push(a):r[i]=[r[i],a]:r[i]=a}return r}else throw new Error("Unsupported environment for multipart parsing")}d(H,"parseMultipartBody");function z(l){const t=/^(?:(\w+):\/\/)?(?:([^:@]+)?(?::([^@]+))?@)?([^:/?#]+)?(?::(\d+))?(\/[^?#]*)?(?:\?([^#]*))?(?:#(.*))?$/;let e=l.match(t);const[s,n,r,i,o,a,c,h,u]=e;let f=o;n&&(f=n+"://"+o),a&&(f=f+":"+a);let p=c;p?.endsWith("/")&&p.slice(0,-1);function m(){return h?(decodeURIComponent(h).split("&")?.map(v=>{const[E,T]=v.split("=");return{[E]:T}})).reduce(function(v,E){return{...v,...E}},{}):{}}return d(m,"query"),{pathname:p,hash:u,protocol:n,origin:f,username:r,password:i,hostname:o,href:l,port:a,query:m()}}d(z,"urlParse");class I{static{d(this,"Request")}headers=new j;url;method;urlRef={hash:void 0,protocol:void 0,origin:void 0,username:void 0,password:void 0,hostname:void 0,port:void 0,href:void 0,query:{},pathname:"/"};query;#e;params={};constructor(t,e){if(this.headers=new j(t?.headers),this.method=t?.method?.toUpperCase(),this.params=e,this.#e=t,x.getEnvironment=="node"){const s=x.detectProtocol(t),n=x.getHost(this.headers);this.url=`${s}://${n}${t.url}`}else this.url=t.url;this.urlRef=z(this.url),this.query=this.urlRef.query}async text(){return await k(this.#e)}async json(){return(this.headers.get("content-type")||"").includes("application/json")?await O(this.#e):{}}async formData(t){const e=this.headers.get("content-type")||"";if(!e)throw Error("Invalid Content-Type");if(e.includes("application/json"))return await O(this.#e);if(e.includes("application/x-www-form-urlencoded"))return L(this.#e);if(e.includes("multipart/form-data")){const s=e?.split("; ")?.[1]?.split("=")?.[1];if(!s)throw Error("Boundary not found");return await H(this.#e,s,t)}else return{}}}class B{static{d(this,"JetResponse")}static json(t,...e){let s=200,n={"Content-Type":"application/json; charset=utf-8"};return typeof e[0]=="number"?(s=e[0],typeof e[1]=="object"&&(n={...n,...e[1]})):typeof e[0]=="object"&&(n={...n,...e[0]}),new Response(JSON.stringify(t),{status:s,headers:n})}static html(t,...e){let s=200,n={"Content-Type":"text/html; charset=utf-8"};return typeof e[0]=="number"?(s=e[0],typeof e[1]=="object"&&(n={...n,...e[1]})):typeof e[0]=="object"&&(n={...n,...e[0]}),new Response(t,{status:s,headers:n})}static text(t,...e){let s=200,n={"Content-Type":"text/plain; charset=utf-8"};return typeof e[0]=="number"?(s=e[0],typeof e[1]=="object"&&(n={...n,...e[1]})):typeof e[0]=="object"&&(n={...n,...e[0]}),new Response(t,{status:s,headers:n})}static xml(t,...e){let s=200,n={"Content-Type":"application/xml; charset=utf-8"};return typeof e[0]=="number"?(s=e[0],typeof e[1]=="object"&&(n={...n,...e[1]})):typeof e[0]=="object"&&(n={...n,...e[0]}),new Response(t,{status:s,headers:n})}static send(t,...e){let s=200,n={};return typeof e[0]=="number"?(s=e[0],typeof e[1]=="object"&&(n=e[1])):typeof e[0]=="object"&&(n=e[0]),n["Content-Type"]||(typeof t=="string"?n["Content-Type"]="text/plain;":typeof t=="object"&&t!==null?(n["Content-Type"]="application/json;",t=JSON.stringify(t)):n["Content-Type"]="application/octet-stream"),new Response(t,{status:s,headers:n})}static redirect(t,e=302,s){return new Response(null,{status:e,headers:{Location:t}})}static async download(t,e){try{let s=!1;const n=x.getEnvironment;if(n==="node"){const{existsSync:i}=await import("fs");s=i(t)}else if(n==="bun")s=Bun.file(t).exists();else if(n==="deno")try{await Deno.stat(t),s=!0}catch{s=!1}if(!s)throw Error("File not found");let r;if(n==="node"){const{readFileSync:i}=await import("fs");r=await i(t)}else n==="bun"?r=await Bun.file(t).arrayBuffer().then(i=>new Uint8Array(i)):n==="deno"&&(r=await Deno.readFile(t));return new Response(r,{status:200,headers:{"Content-Disposition":`attachment; filename="${e}"`,"Content-Type":"application/octet-stream","Content-Length":r.byteLength.toString()}})}catch(s){throw Error("Internal Server Error"+s?.message)}}static async sendFile(t,...e){try{const s=x.getEnvironment,n=t;let r=!1;if(s==="node"){const{existsSync:p}=await import("fs");r=p(n)}else if(s==="bun")r=Bun.file(n).exists();else if(s==="deno")try{await Deno.stat(n),r=!0}catch{r=!1}if(!r)throw Error("File not found");let i=0;if(s==="node"){const{statSync:p}=await import("fs");i=p(n).size}else s==="bun"?i=(await Bun.file(n).arrayBuffer()).byteLength:s==="deno"&&(i=(await Deno.stat(n)).size);const o={html:"text/html",htm:"text/html",css:"text/css",js:"application/javascript",json:"application/json",png:"image/png",jpg:"image/jpeg",jpeg:"image/jpeg",gif:"image/gif",svg:"image/svg+xml",ico:"image/x-icon",pdf:"application/pdf",txt:"text/plain",xml:"application/xml",mp4:"video/mp4",webm:"video/webm",ogg:"audio/ogg",mp3:"audio/mpeg",wav:"audio/wav",zip:"application/zip",gz:"application/gzip",tar:"application/x-tar"},a=t.split(".").pop()?.toLowerCase()||"",c=o[a]||"application/octet-stream";let h;if(s==="node"){const{createReadStream:p}=await import("fs");h=p(n)}else s==="bun"?h=Bun.file(n).stream():s==="deno"&&(h=(await Deno.open(n,{read:!0})).readable);let u={"Content-Type":c,"Content-Length":i.toString()},f="";return typeof e[0]=="string"?(f=e[0],typeof e[1]=="object"&&(u={...u,...e[1]})):typeof e[0]=="object"&&(u={...u,...e[0]}),f&&(u["Content-Disposition"]=`attachment; filename="${f}"`),new Response(h,{status:200,headers:u})}catch(s){throw Error("Internal Server Error"+s?.message)}}}class q{static{d(this,"State")}state;constructor(){this.state=new Map}set(t,e){this.state.set(t,e)}get(t){return this.state.get(t)}delete(t){return this.state.delete(t)}has(t){return this.state.has(t)}keys(){return Array.from(this.state.keys())}values(){return Array.from(this.state.values())}entries(){return Array.from(this.state.entries())}clear(){this.state.clear()}}const M={100:"Continue",101:"Switching Protocols",102:"Processing",103:"Early Hints",200:"OK",201:"Created",202:"Accepted",203:"Non-Authoritative Information",204:"No Content",205:"Reset Content",206:"Partial Content",207:"Multi-Status",208:"Already Reported",226:"IM Used",300:"Multiple Choices",301:"Moved Permanently",302:"Found",303:"See Other",304:"Not Modified",305:"Use Proxy",306:"Switch Proxy",307:"Temporary Redirect",308:"Permanent Redirect",400:"Bad Request",401:"Unauthorized",402:"Payment Required",403:"Forbidden",404:"Not Found",405:"Method Not Allowed",406:"Not Acceptable",407:"Proxy Authentication Required",408:"Request Timeout",409:"Conflict",410:"Gone",411:"Length Required",412:"Precondition Failed",413:"Payload Too Large",414:"URI Too Long",415:"Unsupported Media Type",416:"Range Not Satisfiable",417:"Expectation Failed",418:"I'm a Teapot",421:"Misdirected Request",422:"Unprocessable Entity",423:"Locked",424:"Failed Dependency",425:"Too Early",426:"Upgrade Required",428:"Precondition Required",429:"Too Many Requests",431:"Request Header Fields Too Large",451:"Unavailable For Legal Reasons",500:"Internal Server Error",501:"Not Implemented",502:"Bad Gateway",503:"Service Unavailable",504:"Gateway Timeout",505:"HTTP Version Not Supported",506:"Variant Also Negotiates",507:"Insufficient Storage",508:"Loop Detected",510:"Not Extended",511:"Network Authentication Required"};class U{static{d(this,"Context")}#e;env={};headers=new j;res=new Response;pathname;url;method;#t=200;state=new q;#n={};#r;finalized=!1;#s;#o;#i;#a;#l=!0;#c;#d;#f;#u;#h;constructor(t){this.#e=t,this.method=t?.method?.toUpperCase(),this.pathname=this.req.urlRef.pathname,this.url=this.req.url}get cookies(){const t=this.headers.getAll("cookie");let e={};if(Array.isArray(t)&&t.length!=0){const s=t.join("; ").split(";");for(const n of s){const[r,i]=n?.trim()?.split("=");e[r]=decodeURIComponent(i)}}else if(typeof t=="string"){const s=t.split(";");for(const n of s){const[r,i]=n?.trim()?.split("=");e[r]=decodeURIComponent(i)}}return{get:d(s=>e?.[s],"get"),all:d(()=>e,"all"),delete:d((s,n)=>{const r="",i={...n,expires:new Date(0)},o=`${s}=${r};${F(i)}`;this.headers.set("Set-Cookie",o)},"delete"),set:d((s,n,r)=>{const i=`${s}=${n};${F(r||{})}`;this.headers.set("Set-Cookie",i)},"set")}}json(t,...e){let s=this.#t,n={"Content-Type":"application/json; charset=utf-8"};return typeof e[0]=="number"?(s=e[0],typeof e[1]=="object"&&(n={...n,...e[1]})):typeof e[0]=="object"&&(n={...n,...e[0]}),new Response(JSON.stringify(t),{status:s,headers:n})}send(t,...e){let s=this.#t,n={};return typeof e[0]=="number"?(s=e[0],typeof e[1]=="object"&&(n=e[1])):typeof e[0]=="object"&&(n=e[0]),n["Content-Type"]||(typeof t=="string"?n["Content-Type"]="text/plain;":typeof t=="object"&&t!==null?(n["Content-Type"]="application/json;",t=JSON.stringify(t)):n["Content-Type"]="application/octet-stream"),new Response(t,{status:s,headers:n})}html(t,...e){let s=this.#t,n={"Content-Type":"text/html; charset=utf-8"};return typeof e[0]=="number"?(s=e[0],typeof e[1]=="object"&&(n={...n,...e[1]})):typeof e[0]=="object"&&(n={...n,...e[0]}),new Response(t,{status:s,headers:n})}text(t,...e){let s=this.#t,n={"Content-Type":"text/plain; charset=utf-8"};return typeof e[0]=="number"?(s=e[0],typeof e[1]=="object"&&(n={...n,...e[1]})):typeof e[0]=="object"&&(n={...n,...e[0]}),new Response(t,{status:s,headers:n})}xml(t,...e){let s=this.#t,n={"Content-Type":"application/xml; charset=utf-8"};return typeof e[0]=="number"?(s=e[0],typeof e[1]=="object"&&(n={...n,...e[1]})):typeof e[0]=="object"&&(n={...n,...e[0]}),new Response(t,{status:s,headers:n})}status=d(t=>(this.#t=t,this),"status");redirect(t,e=302,s){return B.redirect(t,e,s)}async download(t,e){return await B.download(t,e)}async sendFile(t,...e){return await B.sendFile(t,...e)}get req(){return new I(this.#e,this.params)}set params(t){this.#n=t}get params(){return this.#n}}function F(l){const t=[];return l.maxAge&&t.push(`Max-Age=${l.maxAge}`),l.expires&&t.push(`Expires=${l.expires.toUTCString()}`),l.path&&t.push(`Path=${l.path}`),l.domain&&t.push(`Domain=${l.domain}`),l.secure&&t.push("Secure"),l.httpOnly&&t.push("HttpOnly"),l.sameSite&&t.push(`SameSite=${l.sameSite}`),t.join("; ")}d(F,"serializeOptions");let b=class{static{d(this,"GlobalConfig")}static middlewareRule="ignore";static env;static notFound=d(l=>{const{method:t,urlRef:{pathname:e}}=l.req;return new Response(`${t}: '${e}' could not find
4
- `,{headers:{"Content-Type":"text/plain"},status:404})},"notFound");static onError=d((l,t)=>{throw Error(l)},"onError");static loggerFn=d(()=>({}),"loggerFn")};function W(l){async function t(s,n){console.log(n.addr);const r=await l.serve(s);return r instanceof Response?r:new Response(r.body,{status:r.status,statusText:r.statusText||M[r?.status],headers:new Headers(r.headers)})}d(t,"handleRequest");function e(s,n){const r=typeof Deno<"u";try{const i=r?Deno.serve({port:s},t):null;if(!i)throw new Error("Deno is not find");const a=`\x1B[1m\u{1F680} Deno Accelero Server running at \x1B[1;34mhttp\x1B[0m://localhost:${s}/\x1B[0m`;if(typeof n=="function")n(a);else{const c=b.loggerFn();c.success&&c.success(a)}return i}catch(i){throw new Error(i?.message)}}return d(e,"listen"),{listen:e}}d(W,"denoAdapter");function J(l){function t(e,s){const n=typeof Bun<"u"?Bun.serve:null;try{if(!n)throw new Error("Bun is not find");const r=n({port:e,async fetch(a){console.log(r.requestIP(a));const c=await l.serve(a);return c instanceof Response?c:new Response(c.body,{status:c.status,statusText:c.statusText||M[c?.status],headers:new Headers(c.headers)})}}),o=`\x1B[1m Bun \u{1F680}Accelero Server running at \x1B[1;34mhttp\x1B[0m://localhost:${e}/\x1B[0m`;if(typeof s=="function")s(o);else{const a=b.loggerFn();a.success&&a.success(o)}return r}catch(r){throw new Error(r?.message)}}return d(t,"listen"),{listen:t}}d(J,"bunAdapter");function V(l){function t(e,s){import("http").then(n=>{let r=n.createServer(async(i,o)=>{const a=await l.serve(i);console.log(i.socket.remoteAddress);const c=a?.statusText;if(!(a instanceof Response))throw new Error("Invalid response from Accelero.serve");const h=Object.fromEntries(await a.headers.entries());c&&(o.statusMessage=c),o.writeHead(a.status,h);const{Readable:u}=await import("stream");if(a.body instanceof u)a.body.pipe(o);else{const f=await a.arrayBuffer();o.end(Buffer.from(f))}});r.listen(e,()=>{const o=`\x1B[1m NodeJS \u{1F680}Accelero Server running at \x1B[1;34mhttp\x1B[0m://localhost:${e}/\x1B[0m`;if(typeof s=="function")s(o);else{const a=b.loggerFn();a.success&&a.success(o)}return r})}).catch(n=>{throw Error(n.message)})}return d(t,"listen"),{listen:t}}d(V,"nodeAdapter");class G{static{d(this,"CommonHandler")}notFound(t){return b.notFound=t,this}onError(t){return b.onError=t,this}}class R{static{d(this,"TriMiddleware")}children=new Map;middlewares=[];groupMiddlewares=new Map;isOptional=!1;pathname;constructor(t="/"){this.pathname=t}}class _ extends G{static{d(this,"MiddlewareConfigure")}triMiddlewares=new R;basePath;constructor(t="/"){super(),this.basePath=t}addMiddleware(t,e){const s=`${this.basePath}/${t}`?.split("/").filter(Boolean);let n=this.triMiddlewares;for(const r of s)if(r.startsWith("*"))n.children.has("*")||n.children.set("*",new R),n=n.children.get("*");else if(r.startsWith(":")){const i=r?.endsWith("?");if(i){n.isOptional=i;continue}n.children.has(":")||n.children.set(":",new R),n=n.children.get(":")}else n.children.has(r)||n.children.set(r,new R),n=n.children.get(r);n.middlewares.push(...e)}}class A{static{d(this,"TrieRouter")}children=new Map;handlers=new Map;pathname;paramName;isParam=!1;constructor(t="/"){this.children=new Map,this.pathname=t}}class $ extends _{static{d(this,"Router")}routers=new Map;rootNode;constructor({basePath:t="/",env:e={}}={}){super(t),this.basePath=t,b.env={...b.env,...e},this.rootNode=new A(t),this.get.bind(this),this.post.bind(this),this.put.bind(this),this.delete.bind(this),this.all.bind(this),this.#s.bind(this),this.addRouter.bind(this),this.group.bind(this)}get(t,...e){return this.#e("GET",t,...e),this}post(t,...e){return this.#e("POST",t,...e),this}put(t,...e){return this.#e("PUT",t,...e),this}patch(t,...e){return this.#e("PATCH",t,...e),this}delete(t,...e){return this.#e("DELETE",t,...e),this}options(t,...e){return this.#e("OPTIONS",t,...e),this}head(t,...e){return this.#e("HEAD",t,...e),this}all(t,...e){return this.#e("ALL",t,...e),this}addRoute(t,e,...s){return this.#e(t,e,...s),this}addRouter(t,e){return this.#s(t,e)}group(t,e){const s=new $({basePath:t,env:b.env});return e(s),this.#s("/",s),this}use(...t){let e="/",s=[],n;return typeof t[0]=="string"?(e=t[0],Array.isArray(t[1])?(s=t[1],n=t[2]):typeof t[1]=="function"?(s=[t[1]],n=t[2]):n=t[1]):typeof t[0]=="function"?t.length===1?s=[t[0]]:(s=[t[0]],n=t[1]):Array.isArray(t[0])?(s=t[0],n=t[1]):t[0]instanceof $&&(n=t[0]),this.#n(e,s),n&&n instanceof $&&this.addRouter(e,n),this}#e(t,e,...s){if(s.length===0)throw new Error("At least one handler is required.");let n=[],r;if(s.length>1?(Array.isArray(s[0])?n=s[0]:typeof s[0]=="function"&&(n=[s[0]]),r=s[s.length-1]):r=s[0],typeof r!="function")throw new Error("Route callback function is missing or invalid.");if(!n.every(i=>typeof i=="function"))throw new Error("Middleware must be a function or an array of functions.");this.#t(t,e,r,n)}#t(t,e,s,n){const r=`${this.basePath}/${e}`.replace(/\\/g,"")?.split("/").filter(Boolean);let i=r.join("/");if(/(\/\*|\?)/.test(i)){let a=this.routers.get(i);return a?a.set(t,{callback:s,middlewares:n}):(a=new Map,a.set(t,{callback:s,middlewares:n}),this.routers.set(i,a))}let o=this.rootNode;for(const a of r)a.startsWith(":")?(o.children.has(":")||o.children.set(":",new A),o=o.children.get(":"),o.isParam=!0,o.paramName||(o.paramName=a.slice(1))):(o.children.has(a)||o.children.set(a,new A),o=o.children.get(a));o.handlers.set(t,{callback:s,middlewares:n}),o.pathname=e}#n(t,e){this.addMiddleware(t,e)}#r(){return`HNDLR-${Date.now().toString(16)}-${Math.random().toString(16).slice(2)}`}#s(t,e){const s=`${this.basePath}/${t}`.replace(/\\/g,"")?.split("/").filter(Boolean);let n;if(b.middlewareRule=="ignore"&&(n=this.#r()),e.routers.size)for(const[o,a]of e.routers){let c=o;if(s.length!==0&&(c=s?.join("/")+"/"+o),this.routers.has(c)){const h=this.routers.get(c);for(const[u,f]of a)f.handlerID=n,h.set(u,f);continue}if(n)for(const[h,u]of a)u.handlerID=n;this.routers.set(c,a)}let r=this.rootNode,i=this.triMiddlewares;if(s.length==0)this.#o(r,i,e,n);else{for(const o of s)o.startsWith(":")?(r.children.has(":")||r.children.set(":",new A),r=r.children.get(":"),r.isParam=!0,r.paramName||(r.paramName=o.slice(1))):(r.children.has(o)||r.children.set(o,new A),r=r.children.get(o));for(const o of s)if(o.startsWith("*"))i.children.has("*")||i.children.set("*",new R),i=i.children.get("*");else if(o.startsWith(":")){const a=o?.endsWith("?");if(a){i.isOptional=a;continue}i.children.has(":")||i.children.set(":",new R),i=i.children.get(":")}else i.children.has(o)||i.children.set(o,new R),i=i.children.get(o);this.#o(r,i,e,n)}}#o(t,e,s,n){function r(c,h){let u=h;for(const f of c)if(u.children.has(f[0])){let p=u.children.get(f[0]);for(const[m,y]of f[1].handlers){let g={...y,handlerID:n};p.handlers.set(m,g)}f[1].children.size&&r(f[1].children,p)}else{if(n){let p=d(function(m){for(const[y,g]of m.handlers)g.handlerID=n;for(const[y,g]of m.children)p(g)},"assignHandlerIDs2");p(f[1])}u.children.set(f[0],f[1])}}d(r,"addSubRouter");function i(c,h){let u=h;for(const[f,p]of c)if(u.children.has(f)){let m=u.children.get(f);if(n){let y=[...p.middlewares];m.groupMiddlewares.set(n,y)}else m.middlewares.push(...p.middlewares);p.children.size&&i(p.children,m)}else{if(n){let m=d(function(y){let g=[...y.middlewares];y.groupMiddlewares.set(n,g);for(const[,C]of y.children)m(C)},"assignHandlerIDs2");m(p)}u.children.set(f,p)}}d(i,"addMiddleware");let o=s.rootNode;const a=s.triMiddlewares;for(const[c,h]of o.handlers){let u={...h,handlerID:n};t.handlers.set(c,u)}o.children.size>0&&r(o.children,t),n?e.groupMiddlewares.set(n,[...a.middlewares]):e.middlewares.push(...a.middlewares),a.children.size>0&&i(a.children,e)}}function Z({path:l,urlPattern:t}){let e={};l=l.replace(/^\/+|\/+$/g,""),t=t.replace(/^\/+|\/+$/g,"");const s=l?l.split("/"):[],n=t?t.split("/"):[],r=s.length,i=n.length;if(r>i&&!t.includes("*"))return{success:!1,params:{}};let o=0;for(let a=0;a<i;a++){const c=n[a];if(c?.startsWith("*")){const u=n.slice(a+1);let f=c.length==1?"*":c?.slice(1);if(u.length>0){const p=u.join("/"),m=s.slice(r-u.length).join("/"),y=s.slice(o,r-u.length).join("/");return p!==m||!y?{success:!1,params:{}}:(e[f]=y,{success:!0,params:e})}else{const p=s.slice(o).join("/");return p?(e[f]=p,{success:!0,params:e}):{success:!1,params:{}}}}if(c.startsWith(":")&&c.endsWith("?")){const u=c.slice(1,-1),f=n[a+1];if(f&&!f.startsWith(":")&&f!=="*"&&o<r&&s[o]===f){e[u]=null;continue}const m=n.slice(a+1).filter(g=>!(g.startsWith(":")&&g.endsWith("?"))).length;r-o===m?e[u]=null:o<r?(e[u]=s[o],o++):e[u]=null;continue}if(c.startsWith(":")){const u=c.slice(1);if(!/^[a-zA-Z0-9_]+$/.test(u))return{success:!1,params:{}};if(o<r)e[u]=s[o],o++;else return{success:!1,params:{}};continue}const h=s[o];if(c!==h)return{success:!1,params:{}};o++}return o<r?{success:!1,params:{}}:{success:!0,params:e}}d(Z,"useParams");class K extends ${static{d(this,"Accelero")}constructor({basePath:t="/",middlewareRule:e="follow",env:s={},logger:n=void 0}={}){super({basePath:t,env:s}),b.middlewareRule=e,n&&(b.loggerFn=n),this.serve=this.serve.bind(this)}#e(t,e){const s=this.routers;for(let n of this.routers.keys()){const{success:r,params:i}=Z({path:e,urlPattern:n}),o=s.get(n)?.get(t)||s.get(n)?.get("ALL");if(r&&o)return{handlerID:o.handlerID,callback:o.callback,middlewares:o.middlewares,params:i}}return null}#t(t,e){const s=e.split("/").filter(Boolean),n={};let r=this.rootNode;for(let i of s)if(r.children.has(i))r=r.children.get(i);else if(r.children.has(":"))r=r.children.get(":"),r.paramName&&(n[r.paramName]=i);else return null;if(r?.handlers?.size&&r?.pathname){const i=r.handlers.get(t)||r.handlers.get("ALL");return i?{handlerID:i?.handlerID,middlewares:i.middlewares,callback:i.callback,params:n}:null}return null}findRoute(t,e){return this.#t(t,e)||this.#e(t,e)}#n(t,e){return async s=>{let n=0;const r=d(async()=>n<t.length?t[n++](s,r):await e(s),"next");return await r()}}#r(t,e){const s=t.split("/").filter(Boolean);let n=[],r=this.triMiddlewares;for(let i of s){if(r.children.has(i))r=r.children.get(i);else if(r.children.has("*"))r=r.children.get("*");else if(r.children.has(":"))r=r.children.get(":");else break;e?n.push(...r.groupMiddlewares.get(e)||[]):n.push(...r.middlewares)}return n}async#s(t){let e=new U(t);const s=e.req.urlRef,{pathname:n}=s;let r=this.#r(n);e.env=b.env;const i=b.loggerFn();i.request&&i.request(e.method,e.pathname);try{return await this.#n([...this.triMiddlewares.middlewares,...r],async o=>{const a=this.findRoute(o.req.method,n);if(a?.callback){o.params=a.params;const c=a.callback,h=a.handlerID;let u=[...a.middlewares];h&&u.push(...this.#r(n,h));const f=await this.#n(u,c)(o);f?.headers&&o.headers.add(f.headers);const p=f?.statusText||M[f?.status]||"",m=f.status||200;let y=o.headers.toObject();return i.response&&i.response(o.method,o.pathname,m),f instanceof Response?new Response(f.body,{status:m,statusText:p,headers:y}):new Response(f.body,{status:m,statusText:p,headers:y})}else return i.response&&i.response(o.method,o.pathname,404),b.notFound(o)})(e)}catch(o){let a=o;return o instanceof Error&&(a=o.message),i.error&&i.error(`${M[500]}: ${a} `),b.onError(a,e)}}async serve(t){return this.#s(t)}}function Q(l,t){try{let e=!1,s=x.getEnvironment;if(s==="node"||s==="bun"){const{existsSync:i}=N("fs");e=i(l)}else if(s==="deno")try{Deno.statSync(l),e=!0}catch{e=!1}if(!e)return;let n="";if(s==="node"||s==="bun"){const{readFileSync:i}=N("fs");n=i(l,"utf8")}else s==="deno"&&(n=new TextDecoder("utf-8").decode(Deno.readFileSync(l)));const r=n.split(`
5
- `);for(const i of r){const o=i.trim();if(!o||o.startsWith("#"))continue;const[a,c]=o.split("=",2).map(h=>h.trim());if(a&&c){const h=c.replace(/^"(.*)"$/,"$1").replace(/^'(.*)'$/,"$1");t[a]=h,s==="node"||s==="bun"?process.env[a]=h:s==="deno"&&Deno.env.set(a,h)}}}catch(e){console.error(`[dotenv] Error parsing file: ${l}`,e)}}d(Q,"parseEnvFile");function X(l="./"){const t={},e=[".env",".env.local",`.env.${process?.env?.NODE_ENV||"development"}`,`.env.${process?.env?.NODE_ENV||"development"}.local`];for(const s of e)Q(`${l}${s}`,t);return t}d(X,"loadEnv");const w={reset:"\x1B[0m",bold:"\x1B[1m",gray:"\x1B[90m",red:"\x1B[31m",green:"\x1B[32m",yellow:"\x1B[33m",blue:"\x1B[34m",magenta:"\x1B[35m",cyan:"\x1B[36m",bgBlue:"\x1B[44m",bgMagenta:"\x1B[45m"},S=d((l,t,...e)=>{const s=new Date().toISOString(),n={info:w.blue,warn:w.yellow,error:w.red,debug:w.cyan,success:w.green},r=`${w.gray}[${s}]${w.reset}`,i=`${n[l]}[${l.toUpperCase()}]${w.reset}`;console.log(`${r} ${i} ${t}`,...e?.flat())},"loggerOutput");function Y(){const l=performance.now();return{request:d((t,e)=>{console.log(`${w.bold}<-- ${w.reset}${w.bgMagenta} ${t} ${w.reset} ${e}`)},"request"),response:d((t,e,s)=>{const n=performance.now()-l;console.log(`${w.bold}--> ${w.reset}${w.bgBlue} ${t} ${w.reset} ${e} ${w.yellow}${s}${w.reset} ${w.magenta}${n.toFixed(2)}ms${w.reset}`)},"response"),info:d((t,...e)=>S("info",t,...e),"info"),warn:d((t,...e)=>S("warn",t,...e),"warn"),error:d((t,...e)=>S("error",t,...e),"error"),debug:d((t,...e)=>S("debug",t,...e),"debug"),success:d((t,...e)=>S("success",t,...e),"success")}}d(Y,"logger");function ee(l={}){const{methods:t,allowedHeaders:e,credentials:s,exposedHeaders:n,maxAge:r,origin:i}=l;return async(o,a)=>{const c=o.req.headers.get("origin")||"";let h="*";return typeof i=="string"?h=i:i instanceof RegExp?h=i.test(c)?c:"":Array.isArray(i)?h=i.some(f=>{if(typeof f=="string")return f===c;if(f instanceof RegExp)return f.test(c)})?c:"":typeof i=="function"&&(h=i(c)?c:""),o.headers.set("Access-Control-Allow-Origin",h),o.headers.set("Access-Control-Allow-Methods",(t||["GET","POST","PUT","DELETE"]).join(", ")),o.headers.set("Access-Control-Allow-Headers",(e||["Content-Type","Authorization"]).join(", ")),n&&o.headers.set("Access-Control-Expose-Headers",n.join(", ")),s&&o.headers.set("Access-Control-Allow-Credentials","true"),r&&o.headers.set("Access-Control-Max-Age",r.toString()),o.req.method==="OPTIONS"?new Response(null,{status:204,headers:o.headers.toObject()}):await a()}}d(ee,"cors");export{K as Accelero,B as JetResponse,$ as Router,J as bunAdapter,ee as cors,W as denoAdapter,X as loadEnv,Y as logger,V as nodeAdapter};
1
+ import{createRequire as _pkgrollCR}from"node:module";const require=_pkgrollCR(import.meta.url);let GlobalConfig = class {
2
+ static notFound = (ctx2) => {
3
+ const {
4
+ method,
5
+ urlRef: { pathname }
6
+ } = ctx2.req;
7
+ return ctx2.text(`${method}: '${pathname}' could not find
8
+ `, 404);
9
+ };
10
+ static onError = (err, ctx2) => {
11
+ return ctx2.text(err, 500);
12
+ };
13
+ static allowDuplicateMw = false;
14
+ static overwriteMethod = true;
15
+ static enableLogger = false;
16
+ static loggerFn = () => {
17
+ return {};
18
+ };
19
+ };
20
+
21
+ function denoAdapter(TezX2) {
22
+ async function handleRequest(req, x) {
23
+ const response = await TezX2.serve(req);
24
+ if (response instanceof Response) {
25
+ return response;
26
+ } else {
27
+ return new Response(response.body, {
28
+ status: response.status,
29
+ statusText: response.statusText || "",
30
+ headers: new Headers(response.headers)
31
+ });
32
+ }
33
+ }
34
+ function listen(port, callback) {
35
+ const isDeno = typeof Deno !== "undefined";
36
+ try {
37
+ const server = isDeno ? Deno.serve({ port }, handleRequest) : null;
38
+ if (!server) {
39
+ throw new Error("Deno is not find");
40
+ }
41
+ const protocol = "\x1B[1;34mhttp\x1B[0m";
42
+ const message = `\x1B[1m\u{1F680} Deno TezX Server running at ${protocol}://localhost:${port}/\x1B[0m`;
43
+ if (typeof callback === "function") {
44
+ callback(message);
45
+ } else {
46
+ const logger = GlobalConfig.loggerFn();
47
+ if (logger.success) {
48
+ logger.success(message);
49
+ }
50
+ }
51
+ return server;
52
+ } catch (err) {
53
+ throw new Error(err?.message);
54
+ }
55
+ }
56
+ return {
57
+ listen
58
+ };
59
+ }
60
+ function bunAdapter(TezX2) {
61
+ function listen(port, callback) {
62
+ const serve = typeof Bun !== "undefined" ? Bun.serve : null;
63
+ try {
64
+ if (!serve) {
65
+ throw new Error("Bun is not find");
66
+ }
67
+ const server = serve({
68
+ port,
69
+ async fetch(req) {
70
+ const response = await TezX2.serve(req);
71
+ if (response instanceof Response) {
72
+ return response;
73
+ } else {
74
+ return new Response(response.body, {
75
+ status: response.status,
76
+ statusText: response.statusText || "",
77
+ headers: new Headers(response.headers)
78
+ });
79
+ }
80
+ }
81
+ });
82
+ const protocol = "\x1B[1;34mhttp\x1B[0m";
83
+ const message = `\x1B[1m Bun TezX Server running at ${protocol}://localhost:${port}/\x1B[0m`;
84
+ if (typeof callback == "function") {
85
+ callback(message);
86
+ } else {
87
+ const logger = GlobalConfig.loggerFn();
88
+ if (logger.success) {
89
+ logger.success(message);
90
+ }
91
+ }
92
+ return server;
93
+ } catch (err) {
94
+ throw new Error(err?.message);
95
+ }
96
+ }
97
+ return {
98
+ listen
99
+ };
100
+ }
101
+ function nodeAdapter(TezX2) {
102
+ function listen(port, callback) {
103
+ import('http').then((r) => {
104
+ let server = r.createServer(async (req, res) => {
105
+ const response = await TezX2.serve(req);
106
+ const statusText = response?.statusText;
107
+ if (!(response instanceof Response)) {
108
+ throw new Error("Invalid response from TezX.serve");
109
+ }
110
+ const headers = Object.fromEntries(await response.headers.entries());
111
+ if (statusText) {
112
+ res.statusMessage = statusText;
113
+ }
114
+ res.writeHead(response.status, headers);
115
+ const { Readable } = await import('stream');
116
+ if (response.body instanceof Readable) {
117
+ response.body.pipe(res);
118
+ } else {
119
+ const body = await response.arrayBuffer();
120
+ res.end(Buffer.from(body));
121
+ }
122
+ });
123
+ server.listen(port, () => {
124
+ const protocol = "\x1B[1;34mhttp\x1B[0m";
125
+ const message = `\x1B[1m NodeJS TezX Server running at ${protocol}://localhost:${port}/\x1B[0m`;
126
+ if (typeof callback == "function") {
127
+ callback(message);
128
+ } else {
129
+ const logger = GlobalConfig.loggerFn();
130
+ if (logger.success) {
131
+ logger.success(message);
132
+ }
133
+ }
134
+ return server;
135
+ });
136
+ }).catch((r) => {
137
+ throw Error(r.message);
138
+ });
139
+ }
140
+ return {
141
+ listen
142
+ };
143
+ }
144
+
145
+ class EnvironmentDetector {
146
+ static get getEnvironment() {
147
+ if (typeof Bun !== "undefined") return "bun";
148
+ if (typeof Deno !== "undefined") return "deno";
149
+ if (typeof process !== "undefined" && process.versions?.node) return "node";
150
+ return "unknown";
151
+ }
152
+ static detectProtocol(req) {
153
+ try {
154
+ if (this.getEnvironment === "node") {
155
+ return req?.socket?.encrypted ? "https" : "http";
156
+ }
157
+ return "unknown";
158
+ } catch (error) {
159
+ throw new Error("Failed to detect protocol.");
160
+ }
161
+ }
162
+ static getHost(headers) {
163
+ try {
164
+ return headers?.get("host") || "unknown";
165
+ } catch (error) {
166
+ throw new Error("Failed to get host.");
167
+ }
168
+ }
169
+ }
170
+
171
+ const mimeTypes = {
172
+ // Text/Web Formats
173
+ html: "text/html",
174
+ htm: "text/html",
175
+ css: "text/css",
176
+ js: "text/javascript",
177
+ mjs: "text/javascript",
178
+ json: "application/json",
179
+ xml: "application/xml",
180
+ txt: "text/plain",
181
+ md: "text/markdown",
182
+ csv: "text/csv",
183
+ tsv: "text/tab-separated-values",
184
+ rtf: "application/rtf",
185
+ markdown: "text/markdown",
186
+ // Image Formats
187
+ png: "image/png",
188
+ jpg: "image/jpeg",
189
+ jpeg: "image/jpeg",
190
+ gif: "image/gif",
191
+ svg: "image/svg+xml",
192
+ webp: "image/webp",
193
+ ico: "image/x-icon",
194
+ bmp: "image/bmp",
195
+ tiff: "image/tiff",
196
+ psd: "image/vnd.adobe.photoshop",
197
+ // Video Formats
198
+ mp4: "video/mp4",
199
+ webm: "video/webm",
200
+ ogg: "video/ogg",
201
+ mov: "video/quicktime",
202
+ avi: "video/x-msvideo",
203
+ wmv: "video/x-ms-wmv",
204
+ flv: "video/x-flv",
205
+ "3gp": "video/3gpp",
206
+ // Audio Formats
207
+ mp3: "audio/mpeg",
208
+ wav: "audio/wav",
209
+ aac: "audio/aac",
210
+ flac: "audio/flac",
211
+ m4a: "audio/mp4",
212
+ mid: "audio/midi",
213
+ midi: "audio/midi",
214
+ // Font Formats
215
+ woff: "font/woff",
216
+ woff2: "font/woff2",
217
+ ttf: "font/ttf",
218
+ otf: "font/otf",
219
+ eot: "application/vnd.ms-fontobject",
220
+ // Application/Document Formats
221
+ pdf: "application/pdf",
222
+ odp: "application/vnd.oasis.opendocument.presentation",
223
+ zip: "application/zip",
224
+ gz: "application/gzip",
225
+ tar: "application/x-tar",
226
+ rar: "application/x-rar-compressed",
227
+ _7z: "application/x-7z-compressed",
228
+ bz2: "application/x-bzip2",
229
+ "7z": "application/x-7z-compressed",
230
+ doc: "application/msword",
231
+ docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
232
+ xls: "application/vnd.ms-excel",
233
+ xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
234
+ ppt: "application/vnd.ms-powerpoint",
235
+ pptx: "application/vnd.openxmlformats-officedocument.presentationml.presentation",
236
+ odt: "application/vnd.oasis.opendocument.text",
237
+ ods: "application/vnd.oasis.opendocument.spreadsheet",
238
+ // Programming/Data Formats
239
+ wasm: "application/wasm",
240
+ map: "application/json",
241
+ // Source maps
242
+ yaml: "application/yaml",
243
+ yml: "application/yaml",
244
+ proto: "text/plain",
245
+ graphql: "application/graphql",
246
+ // Security/Config Formats
247
+ pem: "application/x-pem-file",
248
+ cer: "application/pkix-cert",
249
+ crt: "application/x-x509-ca-cert",
250
+ key: "application/x-pem-file",
251
+ pfx: "application/x-pkcs12",
252
+ // 3D/Model Formats
253
+ glb: "model/gltf-binary",
254
+ gltf: "model/gltf+json",
255
+ obj: "model/obj",
256
+ stl: "model/stl",
257
+ // Virtual/Mixed Reality
258
+ usdz: "model/vnd.usdz+zip",
259
+ // System Formats
260
+ exe: "application/x-msdownload",
261
+ dmg: "application/x-apple-diskimage",
262
+ deb: "application/x-debian-package",
263
+ rpm: "application/x-redhat-package-manager",
264
+ apk: "application/vnd.android.package-archive",
265
+ // Special Web Formats
266
+ webmanifest: "application/manifest+json",
267
+ ics: "text/calendar",
268
+ vcf: "text/vcard",
269
+ warc: "application/warc",
270
+ atom: "application/atom+xml",
271
+ rss: "application/rss+xml",
272
+ // Executables and scripts
273
+ dll: "application/x-msdownload",
274
+ sh: "application/x-sh",
275
+ py: "text/x-python",
276
+ rb: "text/x-ruby",
277
+ pl: "text/x-perl",
278
+ php: "application/x-httpd-php",
279
+ // Miscellaneous
280
+ torrent: "application/x-bittorrent",
281
+ ipa: "application/vnd.iphone",
282
+ eps: "application/postscript",
283
+ ps: "application/postscript",
284
+ ai: "application/postscript",
285
+ swf: "application/x-shockwave-flash",
286
+ jar: "application/java-archive",
287
+ gcode: "text/x.gcode"
288
+ };
289
+ const defaultMimeType = "application/octet-stream";
290
+ async function getFiles(dir, basePath = "/", ref, option) {
291
+ const files = [];
292
+ const runtime = EnvironmentDetector.getEnvironment;
293
+ if (runtime == "deno") {
294
+ for await (const entry of Deno.readDir(dir)) {
295
+ const path = `${dir}/${entry.name}`;
296
+ if (entry.isDirectory) {
297
+ files.push(
298
+ ...await getFiles(path, `${basePath}/${entry.name}`, ref, option)
299
+ );
300
+ } else {
301
+ const x = `${basePath}/${entry.name}`;
302
+ files.push({
303
+ file: path,
304
+ path: x.replace(/\\/g, "/")
305
+ });
306
+ }
307
+ }
308
+ } else {
309
+ const fs = await import('fs/promises');
310
+ const path = await import('path');
311
+ const entries = await fs.readdir(dir, { withFileTypes: true });
312
+ for (const entry of entries) {
313
+ const fullPath = path.join(dir, entry.name);
314
+ if (entry.isDirectory()) {
315
+ files.push(
316
+ ...await getFiles(
317
+ fullPath,
318
+ `${basePath}/${entry.name}`,
319
+ ref,
320
+ option
321
+ )
322
+ );
323
+ } else {
324
+ const path2 = `${basePath}/${entry.name}`;
325
+ files.push({
326
+ file: fullPath,
327
+ path: path2.replace(/\\/g, "/")
328
+ });
329
+ }
330
+ }
331
+ }
332
+ files.forEach((r) => {
333
+ ref.get(r.path, (ctx2) => {
334
+ if (option.cacheControl) {
335
+ ctx2.headers.set("Cache-Control", option.cacheControl);
336
+ }
337
+ if (option.headers) {
338
+ ctx2.headers.add(option.headers);
339
+ }
340
+ return ctx2.sendFile(r.file);
341
+ });
342
+ });
343
+ return files;
344
+ }
345
+
346
+ class TezResponse {
347
+ static json(body, ...args) {
348
+ let status = 200;
349
+ let headers = {
350
+ "Content-Type": "application/json; charset=utf-8"
351
+ };
352
+ if (typeof args[0] === "number") {
353
+ status = args[0];
354
+ if (typeof args[1] === "object") {
355
+ headers = { ...headers, ...args[1] };
356
+ }
357
+ } else if (typeof args[0] === "object") {
358
+ headers = { ...headers, ...args[0] };
359
+ }
360
+ return new Response(JSON.stringify(body), {
361
+ status,
362
+ headers
363
+ });
364
+ }
365
+ static html(data, ...args) {
366
+ let status = 200;
367
+ let headers = {
368
+ "Content-Type": "text/html; charset=utf-8"
369
+ };
370
+ if (typeof args[0] === "number") {
371
+ status = args[0];
372
+ if (typeof args[1] === "object") {
373
+ headers = { ...headers, ...args[1] };
374
+ }
375
+ } else if (typeof args[0] === "object") {
376
+ headers = { ...headers, ...args[0] };
377
+ }
378
+ return new Response(data, {
379
+ status,
380
+ headers
381
+ });
382
+ }
383
+ static text(data, ...args) {
384
+ let status = 200;
385
+ let headers = {
386
+ "Content-Type": "text/plain; charset=utf-8"
387
+ };
388
+ if (typeof args[0] === "number") {
389
+ status = args[0];
390
+ if (typeof args[1] === "object") {
391
+ headers = { ...headers, ...args[1] };
392
+ }
393
+ } else if (typeof args[0] === "object") {
394
+ headers = { ...headers, ...args[0] };
395
+ }
396
+ return new Response(data, {
397
+ status,
398
+ headers
399
+ });
400
+ }
401
+ static xml(data, ...args) {
402
+ let status = 200;
403
+ let headers = {
404
+ "Content-Type": "application/xml; charset=utf-8"
405
+ };
406
+ if (typeof args[0] === "number") {
407
+ status = args[0];
408
+ if (typeof args[1] === "object") {
409
+ headers = { ...headers, ...args[1] };
410
+ }
411
+ } else if (typeof args[0] === "object") {
412
+ headers = { ...headers, ...args[0] };
413
+ }
414
+ return new Response(data, {
415
+ status,
416
+ headers
417
+ });
418
+ }
419
+ static send(body, ...args) {
420
+ let status = 200;
421
+ let headers = {};
422
+ if (typeof args[0] === "number") {
423
+ status = args[0];
424
+ if (typeof args[1] === "object") {
425
+ headers = args[1];
426
+ }
427
+ } else if (typeof args[0] === "object") {
428
+ headers = args[0];
429
+ }
430
+ if (!headers["Content-Type"]) {
431
+ if (typeof body === "string") {
432
+ headers["Content-Type"] = "text/plain;";
433
+ } else if (typeof body === "object" && body !== null) {
434
+ headers["Content-Type"] = "application/json;";
435
+ body = JSON.stringify(body);
436
+ } else {
437
+ headers["Content-Type"] = "application/octet-stream";
438
+ }
439
+ }
440
+ return new Response(body, {
441
+ status,
442
+ headers
443
+ });
444
+ }
445
+ /**
446
+ * Redirects to a given URL.
447
+ * @param url - The target URL.
448
+ * @param status - (Optional) HTTP status code (default: 302).
449
+ * @param headers - (Optional) Additional headers.
450
+ * @returns Response object with redirect.
451
+ */
452
+ static redirect(url, status = 302, headers) {
453
+ return new Response(null, {
454
+ status,
455
+ headers: { Location: url }
456
+ });
457
+ }
458
+ /**
459
+ * Handles file downloads.
460
+ * @param filePath - The path to the file.
461
+ * @param fileName - The name of the downloaded file.
462
+ * @returns Response object for file download.
463
+ */
464
+ static async download(filePath, fileName) {
465
+ try {
466
+ let fileExists = false;
467
+ const runtime = EnvironmentDetector.getEnvironment;
468
+ if (runtime === "node") {
469
+ const { existsSync } = await import('fs');
470
+ fileExists = existsSync(filePath);
471
+ } else if (runtime === "bun") {
472
+ fileExists = Bun.file(filePath).exists();
473
+ } else if (runtime === "deno") {
474
+ try {
475
+ await Deno.stat(filePath);
476
+ fileExists = true;
477
+ } catch {
478
+ fileExists = false;
479
+ }
480
+ }
481
+ if (!fileExists) {
482
+ throw Error("File not found");
483
+ }
484
+ let fileBuffer;
485
+ if (runtime === "node") {
486
+ const { readFileSync } = await import('fs');
487
+ fileBuffer = await readFileSync(filePath);
488
+ } else if (runtime === "bun") {
489
+ fileBuffer = await Bun.file(filePath).arrayBuffer().then((buf) => new Uint8Array(buf));
490
+ } else if (runtime === "deno") {
491
+ fileBuffer = await Deno.readFile(filePath);
492
+ }
493
+ return new Response(fileBuffer, {
494
+ status: 200,
495
+ headers: {
496
+ "Content-Disposition": `attachment; filename="${fileName}"`,
497
+ "Content-Type": "application/octet-stream",
498
+ "Content-Length": fileBuffer.byteLength.toString()
499
+ }
500
+ });
501
+ } catch (error) {
502
+ throw Error("Internal Server Error" + error?.message);
503
+ }
504
+ }
505
+ static async sendFile(filePath, ...args) {
506
+ try {
507
+ const runtime = EnvironmentDetector.getEnvironment;
508
+ const resolvedPath = filePath;
509
+ let fileExists = false;
510
+ if (runtime === "node") {
511
+ const { existsSync } = await import('fs');
512
+ fileExists = existsSync(resolvedPath);
513
+ } else if (runtime === "bun") {
514
+ fileExists = Bun.file(resolvedPath).exists();
515
+ } else if (runtime === "deno") {
516
+ try {
517
+ await Deno.stat(resolvedPath);
518
+ fileExists = true;
519
+ } catch {
520
+ fileExists = false;
521
+ }
522
+ }
523
+ if (!fileExists) {
524
+ throw Error("File not found");
525
+ }
526
+ let fileSize = 0;
527
+ if (runtime === "node") {
528
+ const { statSync } = await import('fs');
529
+ fileSize = statSync(resolvedPath).size;
530
+ } else if (runtime === "bun") {
531
+ fileSize = (await Bun.file(resolvedPath).arrayBuffer()).byteLength;
532
+ } else if (runtime === "deno") {
533
+ const fileInfo = await Deno.stat(resolvedPath);
534
+ fileSize = fileInfo.size;
535
+ }
536
+ const ext = filePath.split(".").pop()?.toLowerCase() || "";
537
+ const mimeType = mimeTypes[ext] || defaultMimeType;
538
+ let fileStream;
539
+ if (runtime === "node") {
540
+ const { createReadStream } = await import('fs');
541
+ fileStream = createReadStream(resolvedPath);
542
+ } else if (runtime === "bun") {
543
+ fileStream = Bun.file(resolvedPath).stream();
544
+ } else if (runtime === "deno") {
545
+ const file = await Deno.open(resolvedPath, { read: true });
546
+ fileStream = file.readable;
547
+ }
548
+ let headers = {
549
+ "Content-Type": mimeType,
550
+ "Content-Length": fileSize.toString()
551
+ };
552
+ let fileName = "";
553
+ if (typeof args[0] === "string") {
554
+ fileName = args[0];
555
+ if (typeof args[1] === "object") {
556
+ headers = { ...headers, ...args[1] };
557
+ }
558
+ } else if (typeof args[0] === "object") {
559
+ headers = { ...headers, ...args[0] };
560
+ }
561
+ if (fileName) {
562
+ headers["Content-Disposition"] = `attachment; filename="${fileName}"`;
563
+ }
564
+ return new Response(fileStream, {
565
+ status: 200,
566
+ headers
567
+ });
568
+ } catch (error) {
569
+ throw Error("Internal Server Error" + error?.message);
570
+ }
571
+ }
572
+ }
573
+
574
+ class CommonHandler {
575
+ /**
576
+ * Register a custom 404 handler for missing routes
577
+ * @param {Callback} callback - Handler function to execute when no route matches
578
+ * @returns {this} - Returns current instance for chaining
579
+ *
580
+ * @example
581
+ * // Register a custom not-found handler
582
+ * app.notFound((ctx) => {
583
+ * ctx.status(404).text('Custom not found message');
584
+ * });
585
+ */
586
+ notFound(callback) {
587
+ GlobalConfig.notFound = callback;
588
+ return this;
589
+ }
590
+ onError(callback) {
591
+ GlobalConfig.onError = callback;
592
+ return this;
593
+ }
594
+ }
595
+
596
+ function sanitizePathSplit(basePath, path) {
597
+ const parts = `${basePath}/${path}`.replace(/\\/g, "")?.split("/").filter(Boolean);
598
+ return parts;
599
+ }
600
+ function urlParse(url) {
601
+ const urlPattern = /^(?:(\w+):\/\/)?(?:([^:@]+)?(?::([^@]+))?@)?([^:/?#]+)?(?::(\d+))?(\/[^?#]*)?(?:\?([^#]*))?(?:#(.*))?$/;
602
+ let matches = url.match(urlPattern);
603
+ const [
604
+ _,
605
+ protocol,
606
+ username,
607
+ password,
608
+ hostname,
609
+ port,
610
+ path,
611
+ queryString,
612
+ hash
613
+ ] = matches;
614
+ let origin = hostname;
615
+ if (protocol) {
616
+ origin = protocol + "://" + hostname;
617
+ }
618
+ if (port) {
619
+ origin = origin + ":" + port;
620
+ }
621
+ let p = path;
622
+ if (p?.endsWith("/")) p.slice(0, -1);
623
+ function query() {
624
+ if (queryString) {
625
+ const queryPart = decodeURIComponent(queryString);
626
+ const keyValuePairs = queryPart.split("&");
627
+ const paramsObj = keyValuePairs?.map(
628
+ (keyValue) => {
629
+ const [key, value] = keyValue.split("=");
630
+ return {
631
+ [key]: value
632
+ };
633
+ }
634
+ );
635
+ return paramsObj.reduce(function(total, value) {
636
+ return { ...total, ...value };
637
+ }, {});
638
+ } else {
639
+ return {};
640
+ }
641
+ }
642
+ return {
643
+ pathname: p,
644
+ hash,
645
+ protocol,
646
+ origin,
647
+ username,
648
+ password,
649
+ hostname,
650
+ href: url,
651
+ port,
652
+ query: query()
653
+ };
654
+ }
655
+
656
+ class TriMiddleware {
657
+ children = /* @__PURE__ */ new Map();
658
+ middlewares = /* @__PURE__ */ new Set();
659
+ isOptional = false;
660
+ pathname;
661
+ constructor(pathname = "/") {
662
+ this.pathname = pathname;
663
+ if (GlobalConfig.allowDuplicateMw) {
664
+ this.middlewares = [];
665
+ } else {
666
+ this.middlewares = /* @__PURE__ */ new Set();
667
+ }
668
+ }
669
+ }
670
+ class MiddlewareConfigure extends CommonHandler {
671
+ triMiddlewares = new TriMiddleware();
672
+ basePath;
673
+ constructor(basePath = "/") {
674
+ super();
675
+ this.basePath = basePath;
676
+ }
677
+ addMiddleware(pathname, middlewares) {
678
+ const parts = sanitizePathSplit(this.basePath, pathname);
679
+ let node = this.triMiddlewares;
680
+ for (const part of parts) {
681
+ if (part.startsWith("*")) {
682
+ if (!node.children.has("*")) {
683
+ node.children.set("*", new TriMiddleware());
684
+ }
685
+ node = node.children.get("*");
686
+ } else if (part.startsWith(":")) {
687
+ const isOptional = part?.endsWith("?");
688
+ if (isOptional) {
689
+ node.isOptional = isOptional;
690
+ continue;
691
+ }
692
+ if (!node.children.has(":")) {
693
+ node.children.set(":", new TriMiddleware());
694
+ }
695
+ node = node.children.get(":");
696
+ } else {
697
+ if (!node.children.has(part)) {
698
+ node.children.set(part, new TriMiddleware());
699
+ }
700
+ node = node.children.get(part);
701
+ }
702
+ }
703
+ if (GlobalConfig.allowDuplicateMw) {
704
+ node.middlewares.push(...middlewares);
705
+ } else {
706
+ for (const middleware of middlewares) {
707
+ node.middlewares.add(middleware);
708
+ }
709
+ }
710
+ }
711
+ }
712
+
713
+ class TrieRouter {
714
+ children = /* @__PURE__ */ new Map();
715
+ // handlers: Map<HTTPMethod, Callback<any>> = new Map();
716
+ handlers = /* @__PURE__ */ new Map();
717
+ pathname;
718
+ // isWildcard: boolean = false;
719
+ paramName;
720
+ isParam = false;
721
+ constructor(pathname = "/") {
722
+ this.children = /* @__PURE__ */ new Map();
723
+ this.pathname = pathname;
724
+ }
725
+ }
726
+ class Router extends MiddlewareConfigure {
727
+ routers = /* @__PURE__ */ new Map();
728
+ env = {};
729
+ triRouter;
730
+ constructor({ basePath = "/", env = {} } = {}) {
731
+ super(basePath);
732
+ this.basePath = basePath;
733
+ this.env = { ...env };
734
+ this.triRouter = new TrieRouter(basePath);
735
+ this.get.bind(this);
736
+ this.post.bind(this);
737
+ this.put.bind(this);
738
+ this.delete.bind(this);
739
+ this.all.bind(this);
740
+ this.#routeAddTriNode.bind(this);
741
+ this.addRouter.bind(this);
742
+ this.group.bind(this);
743
+ }
744
+ static(...args) {
745
+ let route = "";
746
+ let dir;
747
+ let options = {};
748
+ switch (args.length) {
749
+ case 3:
750
+ [route, dir, options] = args;
751
+ break;
752
+ case 2:
753
+ if (typeof args[1] === "object") {
754
+ [dir, options] = args;
755
+ } else {
756
+ [route, dir] = args;
757
+ }
758
+ break;
759
+ case 1:
760
+ [dir] = args;
761
+ break;
762
+ default:
763
+ throw new Error(
764
+ `\x1B[1;31m404 Not Found\x1B[0m \x1B[1;32mInvalid arguments\x1B[0m`
765
+ );
766
+ }
767
+ getFiles(dir, route, this, options);
768
+ return this;
769
+ }
770
+ get(path, ...args) {
771
+ this.#registerRoute("GET", path, ...args);
772
+ return this;
773
+ }
774
+ post(path, ...args) {
775
+ this.#registerRoute("POST", path, ...args);
776
+ return this;
777
+ }
778
+ put(path, ...args) {
779
+ this.#registerRoute("PUT", path, ...args);
780
+ return this;
781
+ }
782
+ patch(path, ...args) {
783
+ this.#registerRoute("PATCH", path, ...args);
784
+ return this;
785
+ }
786
+ delete(path, ...args) {
787
+ this.#registerRoute("DELETE", path, ...args);
788
+ return this;
789
+ }
790
+ options(path, ...args) {
791
+ this.#registerRoute("OPTIONS", path, ...args);
792
+ return this;
793
+ }
794
+ head(path, ...args) {
795
+ this.#registerRoute("HEAD", path, ...args);
796
+ return this;
797
+ }
798
+ all(path, ...args) {
799
+ this.#registerRoute("ALL", path, ...args);
800
+ return this;
801
+ }
802
+ addRoute(method, path, ...args) {
803
+ this.#registerRoute(method, path, ...args);
804
+ return this;
805
+ }
806
+ /**
807
+ * Mount a sub-router at specific path prefix
808
+ * @param path - Base path for the sub-router
809
+ * @param router - Router instance to mount
810
+ * @returns Current instance for chaining
811
+ *
812
+ * @example
813
+ * const apiRouter = new Router();
814
+ * apiRouter.get('/users', () => { ... });
815
+ * server.addRouter('/api', apiRouter);
816
+ */
817
+ addRouter(path, router) {
818
+ return this.#routeAddTriNode(path, router);
819
+ }
820
+ /**
821
+ * Create route group with shared path prefix
822
+ * @param prefix - Path prefix for the group
823
+ * @param callback - Function that receives group-specific router
824
+ * @returns Current router instance for chaining
825
+ *
826
+ * @example
827
+ * app.group('/v1', (group) => {
828
+ * group.get('/users', v1UserHandler);
829
+ * });
830
+ */
831
+ group(prefix, callback) {
832
+ const router = new Router({
833
+ basePath: prefix
834
+ // env: this.env
835
+ });
836
+ callback(router);
837
+ this.#routeAddTriNode("/", router);
838
+ return this;
839
+ }
840
+ use(...args) {
841
+ let path = "/";
842
+ let middlewares = [];
843
+ let router;
844
+ if (typeof args[0] === "string") {
845
+ path = args[0];
846
+ if (Array.isArray(args[1])) {
847
+ middlewares = args[1];
848
+ router = args[2];
849
+ } else if (typeof args[1] === "function") {
850
+ middlewares = [args[1]];
851
+ router = args[2];
852
+ } else {
853
+ router = args[1];
854
+ }
855
+ } else if (typeof args[0] === "function") {
856
+ if (args.length === 1) {
857
+ middlewares = [args[0]];
858
+ } else {
859
+ middlewares = [args[0]];
860
+ router = args[1];
861
+ }
862
+ } else if (Array.isArray(args[0])) {
863
+ middlewares = args[0];
864
+ router = args[1];
865
+ } else if (args[0] instanceof Router) {
866
+ router = args[0];
867
+ }
868
+ this.#addRouteMiddleware(path, middlewares);
869
+ if (router && router instanceof Router) {
870
+ this.addRouter(path, router);
871
+ }
872
+ return this;
873
+ }
874
+ // Other HTTP methods (PUT, DELETE, etc.) can be added similarly
875
+ #registerRoute(method, path, ...args) {
876
+ if (args.length === 0) {
877
+ throw new Error("At least one handler is required.");
878
+ }
879
+ let middlewares = [];
880
+ let callback;
881
+ if (args.length > 1) {
882
+ if (Array.isArray(args[0])) {
883
+ middlewares = args[0];
884
+ } else if (typeof args[0] === "function") {
885
+ middlewares = [args[0]];
886
+ }
887
+ callback = args[args.length - 1];
888
+ } else {
889
+ callback = args[0];
890
+ }
891
+ if (typeof callback !== "function") {
892
+ throw new Error("Route callback function is missing or invalid.");
893
+ }
894
+ if (!middlewares.every((middleware) => typeof middleware === "function")) {
895
+ throw new Error(
896
+ "Middleware must be a function or an array of functions."
897
+ );
898
+ }
899
+ this.#addRoute(method, path, callback, middlewares);
900
+ }
901
+ #addRoute(method, path, callback, middlewares) {
902
+ const parts = sanitizePathSplit(this.basePath, path);
903
+ let finalMiddleware = middlewares;
904
+ if (!GlobalConfig.allowDuplicateMw) {
905
+ finalMiddleware = new Set(middlewares);
906
+ }
907
+ let p = parts.join("/");
908
+ if (/(\/\*|\?)/.test(p)) {
909
+ let handler = this.routers.get(p);
910
+ if (!handler) {
911
+ handler = /* @__PURE__ */ new Map();
912
+ handler.set(method, {
913
+ callback,
914
+ middlewares: finalMiddleware
915
+ });
916
+ return this.routers.set(p, handler);
917
+ }
918
+ if (!GlobalConfig.overwriteMethod && handler.has(method)) return;
919
+ return handler.set(method, { callback, middlewares: finalMiddleware });
920
+ }
921
+ let node = this.triRouter;
922
+ for (const part of parts) {
923
+ if (part.startsWith(":")) {
924
+ if (!node.children.has(":")) {
925
+ node.children.set(":", new TrieRouter());
926
+ }
927
+ node = node.children.get(":");
928
+ node.isParam = true;
929
+ if (!node.paramName) {
930
+ node.paramName = part.slice(1);
931
+ }
932
+ } else {
933
+ if (!node.children.has(part)) {
934
+ node.children.set(part, new TrieRouter());
935
+ }
936
+ node = node.children.get(part);
937
+ }
938
+ }
939
+ if (!GlobalConfig.overwriteMethod && node.handlers.has(method)) return;
940
+ node.handlers.set(method, {
941
+ callback,
942
+ middlewares: finalMiddleware
943
+ });
944
+ node.pathname = path;
945
+ }
946
+ #addRouteMiddleware(path, middlewareFunctions) {
947
+ this.addMiddleware(path, middlewareFunctions);
948
+ }
949
+ #routeAddTriNode(path, router) {
950
+ this.env = { ...this.env, ...router.env };
951
+ if (!(router instanceof Router)) {
952
+ throw new Error("Router instance is required.");
953
+ }
954
+ const parts = sanitizePathSplit(this.basePath, path);
955
+ if (router.routers.size) {
956
+ for (const [segment, handlers] of router.routers) {
957
+ let path2 = parts.length ? parts.join("/") + "/" + segment : segment;
958
+ if (this.routers.has(path2)) {
959
+ const baseRouter = this.routers.get(path2);
960
+ for (const [method, handler] of handlers) {
961
+ if (!GlobalConfig.overwriteMethod && baseRouter.has(method)) return;
962
+ baseRouter.set(method, handler);
963
+ }
964
+ } else {
965
+ this.routers.set(path2, new Map(handlers));
966
+ }
967
+ }
968
+ }
969
+ let rootNode = this.triRouter;
970
+ let rootMiddlewares = this.triMiddlewares;
971
+ if (parts.length == 0) {
972
+ this.#addMiddlewareHandlerIDsTriNode(rootNode, rootMiddlewares, router);
973
+ } else {
974
+ for (const part of parts) {
975
+ if (part.startsWith(":")) {
976
+ if (!rootNode.children.has(":")) {
977
+ rootNode.children.set(":", new TrieRouter());
978
+ }
979
+ rootNode = rootNode.children.get(":");
980
+ rootNode.isParam = true;
981
+ if (!rootNode.paramName) {
982
+ rootNode.paramName = part.slice(1);
983
+ }
984
+ } else {
985
+ if (!rootNode.children.has(part)) {
986
+ rootNode.children.set(part, new TrieRouter());
987
+ }
988
+ rootNode = rootNode.children.get(part);
989
+ }
990
+ }
991
+ for (const part of parts) {
992
+ if (part.startsWith("*")) {
993
+ if (!rootMiddlewares.children.has("*")) {
994
+ rootMiddlewares.children.set("*", new TriMiddleware());
995
+ }
996
+ rootMiddlewares = rootMiddlewares.children.get("*");
997
+ } else if (part.startsWith(":")) {
998
+ const isOptional = part?.endsWith("?");
999
+ if (isOptional) {
1000
+ rootMiddlewares.isOptional = isOptional;
1001
+ continue;
1002
+ }
1003
+ if (!rootMiddlewares.children.has(":")) {
1004
+ rootMiddlewares.children.set(":", new TriMiddleware());
1005
+ }
1006
+ rootMiddlewares = rootMiddlewares.children.get(":");
1007
+ } else {
1008
+ if (!rootMiddlewares.children.has(part)) {
1009
+ rootMiddlewares.children.set(part, new TriMiddleware());
1010
+ }
1011
+ rootMiddlewares = rootMiddlewares.children.get(part);
1012
+ }
1013
+ }
1014
+ this.#addMiddlewareHandlerIDsTriNode(rootNode, rootMiddlewares, router);
1015
+ }
1016
+ }
1017
+ #addMiddlewareHandlerIDsTriNode(rootNode, rootMiddlewares, router) {
1018
+ function addSubRouter(children, node) {
1019
+ let rtN = node;
1020
+ for (const element of children) {
1021
+ const pathSegment = element[0];
1022
+ const subRouter = element[1];
1023
+ if (rtN.children.has(pathSegment)) {
1024
+ let findNode = rtN.children.get(pathSegment);
1025
+ for (const [method, handlers] of subRouter.handlers) {
1026
+ if (!GlobalConfig.overwriteMethod && node.handlers.has(method))
1027
+ return;
1028
+ findNode.handlers.set(method, handlers);
1029
+ }
1030
+ if (subRouter.children.size) {
1031
+ addSubRouter(subRouter.children, findNode);
1032
+ }
1033
+ } else {
1034
+ rtN.children.set(pathSegment, subRouter);
1035
+ }
1036
+ }
1037
+ }
1038
+ let routerNode = router.triRouter;
1039
+ const routerMiddlewares = router.triMiddlewares;
1040
+ for (const [method, handlers] of routerNode.handlers) {
1041
+ if (!GlobalConfig.overwriteMethod) {
1042
+ rootNode.handlers.set(method, handlers);
1043
+ continue;
1044
+ }
1045
+ if (!rootNode.handlers.has(method)) {
1046
+ rootNode.handlers.set(method, handlers);
1047
+ }
1048
+ }
1049
+ if (routerNode.children.size > 0) {
1050
+ addSubRouter(routerNode.children, rootNode);
1051
+ }
1052
+ function addMiddleware(children, node) {
1053
+ let n = node;
1054
+ for (const [path, middlewareNode] of children) {
1055
+ if (n.children.has(path)) {
1056
+ let findNode = n.children.get(path);
1057
+ if (GlobalConfig.allowDuplicateMw) {
1058
+ findNode.middlewares.push(
1059
+ ...middlewareNode.middlewares
1060
+ );
1061
+ } else {
1062
+ for (const mw of middlewareNode.middlewares) {
1063
+ if (findNode.middlewares.has(mw)) {
1064
+ middlewareNode.middlewares.delete(mw);
1065
+ }
1066
+ findNode.middlewares.add(mw);
1067
+ }
1068
+ }
1069
+ if (middlewareNode.children.size) {
1070
+ addMiddleware(middlewareNode.children, findNode);
1071
+ }
1072
+ } else {
1073
+ n.children.set(path, middlewareNode);
1074
+ }
1075
+ }
1076
+ }
1077
+ if (GlobalConfig.allowDuplicateMw) {
1078
+ rootMiddlewares.middlewares.push(
1079
+ ...routerMiddlewares.middlewares
1080
+ );
1081
+ } else {
1082
+ for (const mw of routerMiddlewares.middlewares) {
1083
+ if (rootMiddlewares.middlewares.has(mw)) {
1084
+ routerMiddlewares.middlewares.delete(mw);
1085
+ }
1086
+ rootMiddlewares.middlewares.add(mw);
1087
+ }
1088
+ }
1089
+ if (routerMiddlewares.children.size > 0) {
1090
+ addMiddleware(routerMiddlewares.children, rootMiddlewares);
1091
+ }
1092
+ }
1093
+ }
1094
+
1095
+ class HeadersParser {
1096
+ headers = /* @__PURE__ */ new Map();
1097
+ // Lowercase keys for case-insensitivity
1098
+ constructor(init) {
1099
+ if (init) {
1100
+ this.add(init);
1101
+ }
1102
+ }
1103
+ /**
1104
+ * Adds multiple headers to the parser.
1105
+ * @param headers - Headers as an array of tuples or a record object.
1106
+ */
1107
+ add(headers) {
1108
+ if (Array.isArray(headers)) {
1109
+ for (const [key, value] of headers) {
1110
+ this.set(key, value);
1111
+ }
1112
+ } else if (typeof Headers !== "undefined" && headers instanceof Headers) {
1113
+ for (const [key, value] of headers.entries()) {
1114
+ this.set(key, value);
1115
+ }
1116
+ } else if (typeof headers === "object") {
1117
+ for (const key in headers) {
1118
+ if (Object.prototype.hasOwnProperty.call(headers, key)) {
1119
+ this.set(key, headers[key]);
1120
+ }
1121
+ }
1122
+ }
1123
+ return this;
1124
+ }
1125
+ /**
1126
+ * Sets a header value.
1127
+ * @param key - Header name.
1128
+ * @param value - Header value(s).
1129
+ */
1130
+ set(key, value) {
1131
+ this.headers.set(key.toLowerCase(), Array.isArray(value) ? value : [value]);
1132
+ return this;
1133
+ }
1134
+ /**
1135
+ * Retrieves the first value of a header.
1136
+ * @param key - Header name.
1137
+ * @returns The first header value or undefined if not found.
1138
+ */
1139
+ get(key) {
1140
+ const values = this.headers.get(key.toLowerCase());
1141
+ return values ? values[0] : void 0;
1142
+ }
1143
+ /**
1144
+ * Retrieves all values of a header.
1145
+ * @param key - Header name.
1146
+ * @returns An array of header values.
1147
+ */
1148
+ getAll(key) {
1149
+ return this.headers.get(key.toLowerCase()) || [];
1150
+ }
1151
+ /**
1152
+ * Checks if a header exists.
1153
+ * @param key - Header name.
1154
+ * @returns True if the header exists, false otherwise.
1155
+ */
1156
+ has(key) {
1157
+ return this.headers.has(key.toLowerCase());
1158
+ }
1159
+ /**
1160
+ * Deletes a header.
1161
+ * @param key - Header name.
1162
+ * @returns True if deleted successfully, false otherwise.
1163
+ */
1164
+ delete(key) {
1165
+ return this.headers.delete(key.toLowerCase());
1166
+ }
1167
+ /**
1168
+ * Appends a value to an existing header or creates a new one.
1169
+ * @param key - Header name.
1170
+ * @param value - Value to append.
1171
+ */
1172
+ append(key, value) {
1173
+ const lowerKey = key.toLowerCase();
1174
+ if (this.headers.has(lowerKey)) {
1175
+ this.headers.get(lowerKey).push(value);
1176
+ } else {
1177
+ this.headers.set(lowerKey, [value]);
1178
+ }
1179
+ return this;
1180
+ }
1181
+ /**
1182
+ * Returns an iterator over header entries.
1183
+ * @returns IterableIterator of header key-value pairs.
1184
+ */
1185
+ entries() {
1186
+ return this.headers.entries();
1187
+ }
1188
+ /**
1189
+ * Returns an iterator over header keys.
1190
+ * @returns IterableIterator of header names.
1191
+ */
1192
+ keys() {
1193
+ return this.headers.keys();
1194
+ }
1195
+ /**
1196
+ * Returns an iterator over header values.
1197
+ * @returns IterableIterator of header values arrays.
1198
+ */
1199
+ values() {
1200
+ return this.headers.values();
1201
+ }
1202
+ /**
1203
+ * Iterates over headers and executes a callback function.
1204
+ * @param callback - Function to execute for each header.
1205
+ */
1206
+ forEach(callback) {
1207
+ for (const [key, value] of this.headers) {
1208
+ callback(value, key);
1209
+ }
1210
+ }
1211
+ /**
1212
+ * Converts headers into a plain object.
1213
+ * @returns A record of headers where single-value headers are returned as a string.
1214
+ */
1215
+ toObject() {
1216
+ const obj = {};
1217
+ for (const [key, value] of this.headers.entries()) {
1218
+ obj[key] = value.length > 1 ? value : value[0];
1219
+ }
1220
+ return obj;
1221
+ }
1222
+ }
1223
+ Object.defineProperty(HeadersParser, "name", { value: "Headers" });
1224
+
1225
+ async function parseJsonBody(req) {
1226
+ const runtime = EnvironmentDetector.getEnvironment;
1227
+ if (runtime === "node") {
1228
+ return new Promise((resolve, reject) => {
1229
+ let body = "";
1230
+ req.on("data", (chunk) => {
1231
+ body += chunk.toString();
1232
+ });
1233
+ req.on("end", () => {
1234
+ try {
1235
+ resolve(JSON.parse(body));
1236
+ } catch (error) {
1237
+ reject(new Error("Invalid JSON format"));
1238
+ }
1239
+ });
1240
+ });
1241
+ } else if (runtime === "deno" || runtime === "bun") {
1242
+ return await req.json();
1243
+ } else {
1244
+ throw new Error("Unsupported environment for multipart parsing");
1245
+ }
1246
+ }
1247
+ async function parseTextBody(req) {
1248
+ const runtime = EnvironmentDetector.getEnvironment;
1249
+ if (runtime === "node") {
1250
+ return new Promise((resolve, reject) => {
1251
+ let body = "";
1252
+ req.on("data", (chunk) => {
1253
+ body += chunk.toString();
1254
+ });
1255
+ req.on("end", () => {
1256
+ try {
1257
+ resolve(body);
1258
+ } catch (error) {
1259
+ reject(new Error("Invalid JSON format"));
1260
+ }
1261
+ });
1262
+ });
1263
+ } else if (runtime === "deno" || runtime === "bun") {
1264
+ return await req.text();
1265
+ } else {
1266
+ throw new Error("Unsupported environment for multipart parsing");
1267
+ }
1268
+ }
1269
+ async function parseUrlEncodedBody(req) {
1270
+ const runtime = EnvironmentDetector.getEnvironment;
1271
+ if (runtime === "node") {
1272
+ return new Promise((resolve, reject) => {
1273
+ let body = "";
1274
+ req.on("data", (chunk) => {
1275
+ body += chunk.toString("binary");
1276
+ });
1277
+ req.on("end", () => {
1278
+ try {
1279
+ const pairs = body.split("&");
1280
+ const formData = {};
1281
+ pairs.forEach((pair) => {
1282
+ const [key, value] = pair.split("=");
1283
+ formData[decodeURIComponent(key)] = decodeURIComponent(value || "");
1284
+ });
1285
+ resolve(formData);
1286
+ } catch {
1287
+ reject(new Error("Invalid x-www-form-urlencoded format"));
1288
+ }
1289
+ });
1290
+ });
1291
+ } else if (runtime === "deno" || runtime === "bun") {
1292
+ const formData = await req.formData();
1293
+ const result = {};
1294
+ for (const [key, value] of formData.entries()) {
1295
+ result[key] = value;
1296
+ }
1297
+ return result;
1298
+ } else {
1299
+ throw new Error("Unsupported environment for multipart parsing");
1300
+ }
1301
+ }
1302
+ async function parseMultipartBody(req, boundary, options) {
1303
+ const runtime = EnvironmentDetector.getEnvironment;
1304
+ options?.sanitized;
1305
+ if (runtime === "node") {
1306
+ return new Promise((resolve, reject) => {
1307
+ let body = "";
1308
+ req.on("data", (chunk) => {
1309
+ body += chunk.toString("binary");
1310
+ });
1311
+ req.on("end", () => {
1312
+ try {
1313
+ const formDataField = {};
1314
+ const formDataFieldParts = body.split("----------------------------");
1315
+ formDataFieldParts.forEach((part) => {
1316
+ const match = part.match(/name="(.*)"\r\n\r\n(.*)\r\n/);
1317
+ if (match && match.length === 3) {
1318
+ const name = match[1];
1319
+ const value = match[2];
1320
+ formDataField[name] = value;
1321
+ }
1322
+ });
1323
+ const parts = body.split(`--${boundary}`);
1324
+ for (const part of parts) {
1325
+ if (part.includes("filename")) {
1326
+ const filenameMatch = part.match(/filename="([^"]+)"/);
1327
+ const fieldNameMatch = part.match(/name="([^"]+)"/);
1328
+ const contentTypeMatch = part.match(/Content-Type: ([^\r\n]+)/);
1329
+ if (filenameMatch && fieldNameMatch && contentTypeMatch) {
1330
+ let filename = filenameMatch[1];
1331
+ const fieldName = fieldNameMatch[1];
1332
+ const contentType = contentTypeMatch[1];
1333
+ if (options?.sanitized) {
1334
+ filename = `${Date.now()}-${filename.replace(/\s+/g, "")?.replace(/[^a-zA-Z0-9.-]/g, "-")}`?.toLowerCase();
1335
+ }
1336
+ if (Array.isArray(options?.allowedTypes) && !options.allowedTypes?.includes(contentType)) {
1337
+ reject(
1338
+ `Invalid file type: "${contentType}". Allowed types: ${options.allowedTypes.join(", ")}`
1339
+ );
1340
+ }
1341
+ const fileContentStartIndex = part.indexOf("\r\n\r\n") + 4;
1342
+ const fileContent = Buffer.from(
1343
+ part.substring(fileContentStartIndex),
1344
+ "binary"
1345
+ );
1346
+ const arrayBuffer = fileContent.buffer.slice(
1347
+ fileContent.byteOffset,
1348
+ fileContent.byteOffset + fileContent.byteLength
1349
+ );
1350
+ if (typeof options?.maxSize !== "undefined" && fileContent.byteLength > options.maxSize) {
1351
+ reject(
1352
+ `File size exceeds the limit: ${fileContent.byteLength} bytes (Max: ${options.maxSize} bytes)`
1353
+ );
1354
+ }
1355
+ const file = new File([arrayBuffer], filename, {
1356
+ type: contentType
1357
+ });
1358
+ if (typeof options?.maxFiles != "undefined" && options.maxFiles == 0) {
1359
+ reject(
1360
+ `Field "${fieldName}" exceeds the maximum allowed file count of ${options.maxFiles}.`
1361
+ );
1362
+ }
1363
+ if (formDataField[fieldName]) {
1364
+ if (Array.isArray(formDataField[fieldName])) {
1365
+ if (typeof options?.maxFiles != "undefined" && formDataField[fieldName]?.length >= options.maxFiles) {
1366
+ reject(
1367
+ `Field "${fieldName}" exceeds the maximum allowed file count of ${options.maxFiles}.`
1368
+ );
1369
+ }
1370
+ formDataField[fieldName].push(file);
1371
+ } else {
1372
+ formDataField[fieldName] = [formDataField[fieldName], file];
1373
+ }
1374
+ } else {
1375
+ formDataField[fieldName] = file;
1376
+ }
1377
+ }
1378
+ }
1379
+ }
1380
+ resolve(formDataField);
1381
+ } catch {
1382
+ }
1383
+ });
1384
+ });
1385
+ } else if (runtime === "deno" || runtime === "bun") {
1386
+ const formData = await req.formData();
1387
+ const result = {};
1388
+ for (const [key, value] of formData.entries()) {
1389
+ let val = value;
1390
+ if (val instanceof File && typeof options == "object") {
1391
+ let filename = val.name;
1392
+ if (options?.sanitized) {
1393
+ filename = `${Date.now()}-${filename.replace(/\s+/g, "")?.replace(/[^a-zA-Z0-9.-]/g, "-")}`?.toLowerCase();
1394
+ }
1395
+ if (Array.isArray(options?.allowedTypes) && !options.allowedTypes?.includes(val.type)) {
1396
+ throw new Error(
1397
+ `Invalid file type: "${val.type}". Allowed types: ${options.allowedTypes.join(", ")}`
1398
+ );
1399
+ }
1400
+ if (typeof options?.maxSize !== "undefined" && val.size > options.maxSize) {
1401
+ throw new Error(
1402
+ `File size exceeds the limit: ${val.size} bytes (Max: ${options.maxSize} bytes)`
1403
+ );
1404
+ }
1405
+ if (typeof options?.maxFiles != "undefined" && options.maxFiles == 0) {
1406
+ throw new Error(
1407
+ `Field "${key}" exceeds the maximum allowed file count of ${options.maxFiles}.`
1408
+ );
1409
+ }
1410
+ val = new File([await val.arrayBuffer()], filename, {
1411
+ type: val.type
1412
+ });
1413
+ }
1414
+ if (result[key]) {
1415
+ if (Array.isArray(result[key])) {
1416
+ if (val instanceof File && typeof options?.maxFiles != "undefined" && result[key]?.length >= options.maxFiles) {
1417
+ throw new Error(
1418
+ `Field "${key}" exceeds the maximum allowed file count of ${options.maxFiles}.`
1419
+ );
1420
+ }
1421
+ result[key].push(val);
1422
+ } else {
1423
+ result[key] = [result[key], val];
1424
+ }
1425
+ } else {
1426
+ result[key] = val;
1427
+ }
1428
+ }
1429
+ return result;
1430
+ } else {
1431
+ throw new Error("Unsupported environment for multipart parsing");
1432
+ }
1433
+ }
1434
+
1435
+ class Request {
1436
+ headers = new HeadersParser();
1437
+ /**
1438
+ * Full request URL including protocol and query string
1439
+ * @type {string}
1440
+ */
1441
+ url;
1442
+ /**
1443
+ * HTTP request method (GET, POST, PUT, DELETE, etc.)
1444
+ * @type {HTTPMethod}
1445
+ */
1446
+ method;
1447
+ /** Parsed URL reference containing components like query parameters, pathname, etc. */
1448
+ urlRef = {
1449
+ hash: void 0,
1450
+ protocol: void 0,
1451
+ origin: void 0,
1452
+ username: void 0,
1453
+ password: void 0,
1454
+ hostname: void 0,
1455
+ port: void 0,
1456
+ href: void 0,
1457
+ query: {},
1458
+ pathname: "/"
1459
+ };
1460
+ /** Query parameters extracted from the URL */
1461
+ query;
1462
+ #request;
1463
+ /**
1464
+ * Retrieve a parameter by name.
1465
+ * @param name - The parameter name.
1466
+ * @returns The parameter value if found, or undefined.
1467
+ */
1468
+ params = {};
1469
+ // static statusText: string;
1470
+ // static bodyUsed: boolean;
1471
+ constructor(req, params) {
1472
+ this.headers = new HeadersParser(req?.headers);
1473
+ this.method = req?.method?.toUpperCase();
1474
+ this.params = params;
1475
+ this.#request = req;
1476
+ if (EnvironmentDetector.getEnvironment == "node") {
1477
+ const protocol = EnvironmentDetector.detectProtocol(req);
1478
+ const host = EnvironmentDetector.getHost(this.headers);
1479
+ this.url = `${protocol}://${host}${req.url}`;
1480
+ } else {
1481
+ this.url = req.url;
1482
+ }
1483
+ this.urlRef = urlParse(this.url);
1484
+ this.query = this.urlRef.query;
1485
+ }
1486
+ /**
1487
+ * Parses the request body as plain text.
1488
+ * @returns {Promise<string>} The text content of the request body.
1489
+ */
1490
+ async text() {
1491
+ return await parseTextBody(this.#request);
1492
+ }
1493
+ /**
1494
+ * Parses the request body as JSON.
1495
+ * @returns {Promise<Record<string, any>>} The parsed JSON object.
1496
+ * If the Content-Type is not 'application/json', it returns an empty object.
1497
+ */
1498
+ async json() {
1499
+ const contentType = this.headers.get("content-type") || "";
1500
+ if (contentType.includes("application/json")) {
1501
+ return await parseJsonBody(this.#request);
1502
+ } else {
1503
+ return {};
1504
+ }
1505
+ }
1506
+ /**
1507
+ * Parses the request body based on Content-Type.
1508
+ * Supports:
1509
+ * - application/json → JSON parsing
1510
+ * - application/x-www-form-urlencoded → URL-encoded form parsing
1511
+ * - multipart/form-data → Multipart form-data parsing (for file uploads)
1512
+ * @returns {Promise<Record<string, any>>} The parsed form data as an object.
1513
+ * @throws {Error} If the Content-Type is missing or invalid.
1514
+ */
1515
+ async formData(options) {
1516
+ const contentType = this.headers.get("content-type") || "";
1517
+ if (!contentType) {
1518
+ throw Error("Invalid Content-Type");
1519
+ }
1520
+ if (contentType.includes("application/json")) {
1521
+ return await parseJsonBody(this.#request);
1522
+ } else if (contentType.includes("application/x-www-form-urlencoded")) {
1523
+ return parseUrlEncodedBody(this.#request);
1524
+ } else if (contentType.includes("multipart/form-data")) {
1525
+ const boundary = contentType?.split("; ")?.[1]?.split("=")?.[1];
1526
+ if (!boundary) {
1527
+ throw Error("Boundary not found");
1528
+ }
1529
+ return await parseMultipartBody(this.#request, boundary, options);
1530
+ } else {
1531
+ return {};
1532
+ }
1533
+ }
1534
+ }
1535
+
1536
+ class State {
1537
+ state;
1538
+ constructor() {
1539
+ this.state = /* @__PURE__ */ new Map();
1540
+ }
1541
+ /**
1542
+ * Store a value with a specific key.
1543
+ * @param key - The key for the value.
1544
+ * @param value - The value to be stored.
1545
+ */
1546
+ set(key, value) {
1547
+ this.state.set(key, value);
1548
+ }
1549
+ /**
1550
+ * Retrieve a value by key.
1551
+ * @param key - The key of the value to retrieve.
1552
+ * @returns The stored value or undefined if not found.
1553
+ */
1554
+ get(key) {
1555
+ return this.state.get(key);
1556
+ }
1557
+ /**
1558
+ * Delete a key from storage.
1559
+ * @param key - The key to remove.
1560
+ * @returns True if the key was deleted, false otherwise.
1561
+ */
1562
+ delete(key) {
1563
+ return this.state.delete(key);
1564
+ }
1565
+ /**
1566
+ * Check if a key exists in the storage.
1567
+ * @param key - The key to check.
1568
+ * @returns True if the key exists, false otherwise.
1569
+ */
1570
+ has(key) {
1571
+ return this.state.has(key);
1572
+ }
1573
+ /**
1574
+ * Get an array of all stored keys.
1575
+ * @returns An array of keys.
1576
+ */
1577
+ keys() {
1578
+ return Array.from(this.state.keys());
1579
+ }
1580
+ /**
1581
+ * Get an array of all stored values.
1582
+ * @returns An array of values.
1583
+ */
1584
+ values() {
1585
+ return Array.from(this.state.values());
1586
+ }
1587
+ /**
1588
+ * Get an array of all key-value pairs.
1589
+ * @returns An array of [key, value] tuples.
1590
+ */
1591
+ entries() {
1592
+ return Array.from(this.state.entries());
1593
+ }
1594
+ /**
1595
+ * Remove all entries from storage.
1596
+ */
1597
+ clear() {
1598
+ this.state.clear();
1599
+ }
1600
+ }
1601
+
1602
+ const httpStatusMap = {
1603
+ 100: "Continue",
1604
+ 101: "Switching Protocols",
1605
+ 102: "Processing",
1606
+ 103: "Early Hints",
1607
+ 200: "OK",
1608
+ 201: "Created",
1609
+ 202: "Accepted",
1610
+ 203: "Non-Authoritative Information",
1611
+ 204: "No Content",
1612
+ 205: "Reset Content",
1613
+ 206: "Partial Content",
1614
+ 207: "Multi-Status",
1615
+ 208: "Already Reported",
1616
+ 226: "IM Used",
1617
+ 300: "Multiple Choices",
1618
+ 301: "Moved Permanently",
1619
+ 302: "Found",
1620
+ 303: "See Other",
1621
+ 304: "Not Modified",
1622
+ 305: "Use Proxy",
1623
+ 306: "Switch Proxy",
1624
+ 307: "Temporary Redirect",
1625
+ 308: "Permanent Redirect",
1626
+ 400: "Bad Request",
1627
+ 401: "Unauthorized",
1628
+ 402: "Payment Required",
1629
+ 403: "Forbidden",
1630
+ 404: "Not Found",
1631
+ 405: "Method Not Allowed",
1632
+ 406: "Not Acceptable",
1633
+ 407: "Proxy Authentication Required",
1634
+ 408: "Request Timeout",
1635
+ 409: "Conflict",
1636
+ 410: "Gone",
1637
+ 411: "Length Required",
1638
+ 412: "Precondition Failed",
1639
+ 413: "Payload Too Large",
1640
+ 414: "URI Too Long",
1641
+ 415: "Unsupported Media Type",
1642
+ 416: "Range Not Satisfiable",
1643
+ 417: "Expectation Failed",
1644
+ 418: "I'm a Teapot",
1645
+ 421: "Misdirected Request",
1646
+ 422: "Unprocessable Entity",
1647
+ 423: "Locked",
1648
+ 424: "Failed Dependency",
1649
+ 425: "Too Early",
1650
+ 426: "Upgrade Required",
1651
+ 428: "Precondition Required",
1652
+ 429: "Too Many Requests",
1653
+ 431: "Request Header Fields Too Large",
1654
+ 451: "Unavailable For Legal Reasons",
1655
+ 500: "Internal Server Error",
1656
+ 501: "Not Implemented",
1657
+ 502: "Bad Gateway",
1658
+ 503: "Service Unavailable",
1659
+ 504: "Gateway Timeout",
1660
+ 505: "HTTP Version Not Supported",
1661
+ 506: "Variant Also Negotiates",
1662
+ 507: "Insufficient Storage",
1663
+ 508: "Loop Detected",
1664
+ 510: "Not Extended",
1665
+ 511: "Network Authentication Required"
1666
+ };
1667
+ class Context {
1668
+ #rawRequest;
1669
+ /**
1670
+ * Environment variables and configuration
1671
+ * @type {object}
1672
+ */
1673
+ env = {};
1674
+ /**
1675
+ * Parser for handling and manipulating HTTP headers
1676
+ * @type {HeadersParser}
1677
+ */
1678
+ headers = new HeadersParser();
1679
+ // /**
1680
+ // * Parser for handling and manipulating HTTP response(Read Only)
1681
+ // * @type {Response}
1682
+ // */
1683
+ // public readonly res: Response = new Response();
1684
+ /**
1685
+ * Request path without query parameters
1686
+ * @type {string}
1687
+ */
1688
+ pathname;
1689
+ /**
1690
+ * Full request URL including protocol and query string
1691
+ * @type {string}
1692
+ */
1693
+ url;
1694
+ /**
1695
+ * HTTP request method (GET, POST, PUT, DELETE, etc.)
1696
+ * @type {HTTPMethod}
1697
+ */
1698
+ method;
1699
+ #status = 200;
1700
+ /**
1701
+ * Public state container for application data
1702
+ * state storage for middleware and plugins
1703
+ * @type {State}
1704
+ */
1705
+ state = new State();
1706
+ /**
1707
+ * URL parameters extracted from route
1708
+ * @private
1709
+ * @type {Record<string, any>}
1710
+ */
1711
+ #params = {};
1712
+ // /**
1713
+ // * WebSocket connection instance (null until upgraded)
1714
+ // * @type {WebSocket | null}
1715
+ // */
1716
+ // ws: WebSocket | null = null;
1717
+ /**
1718
+ * Generic variable storage for internal framework use
1719
+ * @private
1720
+ * @type {any}
1721
+ */
1722
+ #var;
1723
+ /**
1724
+ * Flag indicating if the request processing is complete
1725
+ * @type {boolean}
1726
+ */
1727
+ finalized = false;
1728
+ /**
1729
+ * HTTP response status code
1730
+ * @private
1731
+ * @type {number}
1732
+ */
1733
+ /**
1734
+ * Execution context reference
1735
+ * @private
1736
+ * @type {any}
1737
+ */
1738
+ #executionCtx;
1739
+ /**
1740
+ * Internal headers storage
1741
+ * @private
1742
+ * @type {any}
1743
+ */
1744
+ #headers;
1745
+ /**
1746
+ * Processed headers ready for sending
1747
+ * @private
1748
+ * @type {any}
1749
+ */
1750
+ #preparedHeaders;
1751
+ /**
1752
+ * Native response object reference
1753
+ * @private
1754
+ * @type {any}
1755
+ */
1756
+ #res;
1757
+ /**
1758
+ * Flag indicating if the response is fresh/unmodified
1759
+ * @private
1760
+ * @type {boolean}
1761
+ */
1762
+ #isFresh = true;
1763
+ /**
1764
+ * Active layout template reference
1765
+ * @private
1766
+ * @type {any}
1767
+ */
1768
+ #layout;
1769
+ /**
1770
+ * Template renderer instance
1771
+ * @private
1772
+ * @type {any}
1773
+ */
1774
+ #renderer;
1775
+ /**
1776
+ * Custom 404 handler reference
1777
+ * @private
1778
+ * @type {any}
1779
+ */
1780
+ #notFoundHandler;
1781
+ /**
1782
+ * Route matching results
1783
+ * @private
1784
+ * @type {any}
1785
+ */
1786
+ #matchResult;
1787
+ /**
1788
+ * Processed path information
1789
+ * @private
1790
+ * @type {any}
1791
+ */
1792
+ #path;
1793
+ constructor(req) {
1794
+ this.#rawRequest = req;
1795
+ this.method = req?.method?.toUpperCase();
1796
+ this.pathname = this.req.urlRef.pathname;
1797
+ this.url = this.req.url;
1798
+ }
1799
+ /**
1800
+ * Cookie handling utility with get/set/delete operations
1801
+ * @returns {{
1802
+ * get: (name: string) => string | undefined,
1803
+ * all: () => Record<string, string>,
1804
+ * delete: (name: string, options?: CookieOptions) => void,
1805
+ * set: (name: string, value: string, options?: CookieOptions) => void
1806
+ * }} Cookie handling interface
1807
+ */
1808
+ get cookies() {
1809
+ const c = this.headers.getAll("cookie");
1810
+ let cookies = {};
1811
+ if (Array.isArray(c) && c.length != 0) {
1812
+ const cookieHeader = c.join("; ").split(";");
1813
+ for (const pair of cookieHeader) {
1814
+ const [key, value] = pair?.trim()?.split("=");
1815
+ cookies[key] = decodeURIComponent(value);
1816
+ }
1817
+ } else if (typeof c == "string") {
1818
+ const cookieHeader = c.split(";");
1819
+ for (const pair of cookieHeader) {
1820
+ const [key, value] = pair?.trim()?.split("=");
1821
+ cookies[key] = decodeURIComponent(value);
1822
+ }
1823
+ }
1824
+ return {
1825
+ /**
1826
+ * Get a specific cookie by name.
1827
+ * @param {string} cookie - The name of the cookie to retrieve.
1828
+ * @returns {string | undefined} - The cookie value or undefined if not found.
1829
+ */
1830
+ get: (cookie) => {
1831
+ return cookies?.[cookie];
1832
+ },
1833
+ /**
1834
+ * Get all cookies as an object.
1835
+ * @returns {Record<string, string>} - An object containing all cookies.
1836
+ */
1837
+ all: () => {
1838
+ return cookies;
1839
+ },
1840
+ /**
1841
+ * Delete a cookie by setting its expiration to the past.
1842
+ * @param {string} name - The name of the cookie to delete.
1843
+ * @param {CookieOptions} [options] - Additional cookie options.
1844
+ */
1845
+ delete: (name, options) => {
1846
+ const value = "";
1847
+ const cookieOptions = {
1848
+ ...options,
1849
+ expires: /* @__PURE__ */ new Date(0)
1850
+ // Set expiration time to the past
1851
+ };
1852
+ const cookieHeader = `${name}=${value};${serializeOptions(cookieOptions)}`;
1853
+ this.headers.set("Set-Cookie", cookieHeader);
1854
+ },
1855
+ /**
1856
+ * Set a new cookie with the given name, value, and options.
1857
+ * @param {string} name - The name of the cookie.
1858
+ * @param {string} value - The value of the cookie.
1859
+ * @param {CookieOptions} [options] - Additional options like expiration.
1860
+ */
1861
+ set: (name, value, options) => {
1862
+ const cookieHeader = `${name}=${value};${serializeOptions(options || {})}`;
1863
+ this.headers.set("Set-Cookie", cookieHeader);
1864
+ }
1865
+ };
1866
+ }
1867
+ json(body, ...args) {
1868
+ let status = this.#status;
1869
+ let headers = {
1870
+ "Content-Type": "application/json; charset=utf-8"
1871
+ };
1872
+ if (typeof args[0] === "number") {
1873
+ status = args[0];
1874
+ if (typeof args[1] === "object") {
1875
+ headers = { ...headers, ...args[1] };
1876
+ }
1877
+ } else if (typeof args[0] === "object") {
1878
+ headers = { ...headers, ...args[0] };
1879
+ }
1880
+ return new Response(JSON.stringify(body), {
1881
+ status,
1882
+ headers
1883
+ });
1884
+ }
1885
+ send(body, ...args) {
1886
+ let status = this.#status;
1887
+ let headers = {};
1888
+ if (typeof args[0] === "number") {
1889
+ status = args[0];
1890
+ if (typeof args[1] === "object") {
1891
+ headers = args[1];
1892
+ }
1893
+ } else if (typeof args[0] === "object") {
1894
+ headers = args[0];
1895
+ }
1896
+ if (!headers["Content-Type"]) {
1897
+ if (typeof body === "string") {
1898
+ headers["Content-Type"] = "text/plain;";
1899
+ } else if (typeof body === "object" && body !== null) {
1900
+ headers["Content-Type"] = "application/json;";
1901
+ body = JSON.stringify(body);
1902
+ } else {
1903
+ headers["Content-Type"] = "application/octet-stream";
1904
+ }
1905
+ }
1906
+ return new Response(body, {
1907
+ status,
1908
+ headers
1909
+ });
1910
+ }
1911
+ html(data, ...args) {
1912
+ let status = this.#status;
1913
+ let headers = {
1914
+ "Content-Type": "text/html; charset=utf-8"
1915
+ };
1916
+ if (typeof args[0] === "number") {
1917
+ status = args[0];
1918
+ if (typeof args[1] === "object") {
1919
+ headers = { ...headers, ...args[1] };
1920
+ }
1921
+ } else if (typeof args[0] === "object") {
1922
+ headers = { ...headers, ...args[0] };
1923
+ }
1924
+ return new Response(data, {
1925
+ status,
1926
+ headers
1927
+ });
1928
+ }
1929
+ text(data, ...args) {
1930
+ let status = this.#status;
1931
+ let headers = {
1932
+ "Content-Type": "text/plain; charset=utf-8"
1933
+ };
1934
+ if (typeof args[0] === "number") {
1935
+ status = args[0];
1936
+ if (typeof args[1] === "object") {
1937
+ headers = { ...headers, ...args[1] };
1938
+ }
1939
+ } else if (typeof args[0] === "object") {
1940
+ headers = { ...headers, ...args[0] };
1941
+ }
1942
+ return new Response(data, {
1943
+ status,
1944
+ headers
1945
+ });
1946
+ }
1947
+ xml(data, ...args) {
1948
+ let status = this.#status;
1949
+ let headers = {
1950
+ "Content-Type": "application/xml; charset=utf-8"
1951
+ };
1952
+ if (typeof args[0] === "number") {
1953
+ status = args[0];
1954
+ if (typeof args[1] === "object") {
1955
+ headers = { ...headers, ...args[1] };
1956
+ }
1957
+ } else if (typeof args[0] === "object") {
1958
+ headers = { ...headers, ...args[0] };
1959
+ }
1960
+ return new Response(data, {
1961
+ status,
1962
+ headers
1963
+ });
1964
+ }
1965
+ /**
1966
+ * HTTP status code..
1967
+ * @param status - number.
1968
+ * @returns Response object with context all method.
1969
+ */
1970
+ status = (status) => {
1971
+ this.#status = status;
1972
+ return this;
1973
+ };
1974
+ /**
1975
+ * Redirects to a given URL.
1976
+ * @param url - The target URL.
1977
+ * @param status - (Optional) HTTP status code (default: 302).
1978
+ * @param headers - (Optional) Additional headers.
1979
+ * @returns Response object with redirect.
1980
+ */
1981
+ redirect(url, status = 302, headers) {
1982
+ return TezResponse.redirect(url, status, headers);
1983
+ }
1984
+ /**
1985
+ * Handles file downloads.
1986
+ * @param filePath - The path to the file.
1987
+ * @param fileName - The name of the downloaded file.
1988
+ * @returns Response object for file download.
1989
+ */
1990
+ async download(filePath, fileName) {
1991
+ return await TezResponse.download(filePath, fileName);
1992
+ }
1993
+ async sendFile(filePath, ...args) {
1994
+ return await TezResponse.sendFile(filePath, ...args);
1995
+ }
1996
+ /**
1997
+ * Getter that creates a standardized Request object from internal state
1998
+ * @returns {Request} - Normalized request object combining:
1999
+ * - Raw platform-specific request
2000
+ * - Parsed headers
2001
+ * - Route parameters
2002
+ *
2003
+ * @example
2004
+ * // Get standardized request
2005
+ * const request = ctx.req;
2006
+ * // Access route params
2007
+ * const id = request.params.get('id');
2008
+ */
2009
+ get req() {
2010
+ return new Request(this.#rawRequest, this.params);
2011
+ }
2012
+ // attachWebSocket(ws) {
2013
+ // this.ws = ws;
2014
+ // }
2015
+ set params(params) {
2016
+ this.#params = params;
2017
+ }
2018
+ get params() {
2019
+ return this.#params;
2020
+ }
2021
+ }
2022
+ function serializeOptions(options) {
2023
+ const parts = [];
2024
+ if (options.maxAge) {
2025
+ parts.push(`Max-Age=${options.maxAge}`);
2026
+ }
2027
+ if (options.expires) {
2028
+ parts.push(`Expires=${options.expires.toUTCString()}`);
2029
+ }
2030
+ if (options.path) {
2031
+ parts.push(`Path=${options.path}`);
2032
+ }
2033
+ if (options.domain) {
2034
+ parts.push(`Domain=${options.domain}`);
2035
+ }
2036
+ if (options.secure) {
2037
+ parts.push(`Secure`);
2038
+ }
2039
+ if (options.httpOnly) {
2040
+ parts.push(`HttpOnly`);
2041
+ }
2042
+ if (options.sameSite) {
2043
+ parts.push(`SameSite=${options.sameSite}`);
2044
+ }
2045
+ return parts.join("; ");
2046
+ }
2047
+
2048
+ function useParams({
2049
+ path,
2050
+ urlPattern
2051
+ }) {
2052
+ let params = {};
2053
+ path = path.replace(/^\/+|\/+$/g, "");
2054
+ urlPattern = urlPattern.replace(/^\/+|\/+$/g, "");
2055
+ const pathSegments = path ? path.split("/") : [];
2056
+ const patternSegments = urlPattern ? urlPattern.split("/") : [];
2057
+ const pathLength = pathSegments.length;
2058
+ const patternLength = patternSegments.length;
2059
+ if (pathLength > patternLength && !urlPattern.includes("*")) {
2060
+ return { success: false, params: {} };
2061
+ }
2062
+ let pathIndex = 0;
2063
+ for (let i = 0; i < patternLength; i++) {
2064
+ const patternSegment = patternSegments[i];
2065
+ if (patternSegment?.startsWith("*")) {
2066
+ const trailingPatterns = patternSegments.slice(i + 1);
2067
+ let paramName = patternSegment.length == 1 ? "*" : patternSegment?.slice(1);
2068
+ if (trailingPatterns.length > 0) {
2069
+ const expectedTrailing = trailingPatterns.join("/");
2070
+ const actualTrailing = pathSegments.slice(pathLength - trailingPatterns.length).join("/");
2071
+ const wildcardPath = pathSegments.slice(pathIndex, pathLength - trailingPatterns.length).join("/");
2072
+ if (expectedTrailing !== actualTrailing || !wildcardPath) {
2073
+ return { success: false, params: {} };
2074
+ }
2075
+ params[paramName] = wildcardPath;
2076
+ return { success: true, params };
2077
+ } else {
2078
+ const wildcardPath = pathSegments.slice(pathIndex).join("/");
2079
+ if (!wildcardPath) {
2080
+ return { success: false, params: {} };
2081
+ }
2082
+ params[paramName] = wildcardPath;
2083
+ return { success: true, params };
2084
+ }
2085
+ }
2086
+ if (patternSegment.startsWith(":") && patternSegment.endsWith("?")) {
2087
+ const paramName = patternSegment.slice(1, -1);
2088
+ const nextPattern = patternSegments[i + 1];
2089
+ if (nextPattern && !nextPattern.startsWith(":") && nextPattern !== "*" && pathIndex < pathLength && // !/test == /:user?/test
2090
+ // বর্তমান পথ যদি পরবর্তী প্যাটার্ন মানে স্ট্যাটিক পথ এর সাথে মাইল তাহলে
2091
+ pathSegments[pathIndex] === nextPattern) {
2092
+ params[paramName] = null;
2093
+ continue;
2094
+ }
2095
+ const remainingPatterns = patternSegments.slice(i + 1);
2096
+ const requiredCount = remainingPatterns.filter(
2097
+ (seg) => !(seg.startsWith(":") && seg.endsWith("?"))
2098
+ ).length;
2099
+ const remainingPath = pathLength - pathIndex;
2100
+ if (remainingPath === requiredCount) {
2101
+ params[paramName] = null;
2102
+ } else if (pathIndex < pathLength) {
2103
+ params[paramName] = pathSegments[pathIndex];
2104
+ pathIndex++;
2105
+ } else {
2106
+ params[paramName] = null;
2107
+ }
2108
+ continue;
2109
+ }
2110
+ if (patternSegment.startsWith(":")) {
2111
+ const paramName = patternSegment.slice(1);
2112
+ if (!/^[a-zA-Z0-9_]+$/.test(paramName)) {
2113
+ return { success: false, params: {} };
2114
+ }
2115
+ if (pathIndex < pathLength) {
2116
+ params[paramName] = pathSegments[pathIndex];
2117
+ pathIndex++;
2118
+ } else {
2119
+ return { success: false, params: {} };
2120
+ }
2121
+ continue;
2122
+ }
2123
+ const pathSegment = pathSegments[pathIndex];
2124
+ if (patternSegment !== pathSegment) {
2125
+ return { success: false, params: {} };
2126
+ }
2127
+ pathIndex++;
2128
+ }
2129
+ if (pathIndex < pathLength) {
2130
+ return { success: false, params: {} };
2131
+ }
2132
+ return { success: true, params };
2133
+ }
2134
+
2135
+ class TezX extends Router {
2136
+ constructor({
2137
+ basePath = "/",
2138
+ env = {},
2139
+ logger = void 0,
2140
+ allowDuplicateMw = false,
2141
+ overwriteMethod = true
2142
+ } = {}) {
2143
+ GlobalConfig.allowDuplicateMw = allowDuplicateMw;
2144
+ GlobalConfig.overwriteMethod = overwriteMethod;
2145
+ if (logger) {
2146
+ GlobalConfig.loggerFn = logger;
2147
+ GlobalConfig.enableLogger = true;
2148
+ }
2149
+ super({ basePath, env });
2150
+ this.serve = this.serve.bind(this);
2151
+ }
2152
+ #hashRouter(method, pathname) {
2153
+ const routers = this.routers;
2154
+ for (let pattern of this.routers.keys()) {
2155
+ const { success, params } = useParams({
2156
+ path: pathname,
2157
+ urlPattern: pattern
2158
+ });
2159
+ const handlers = routers.get(pattern)?.get(method) || routers.get(pattern)?.get("ALL");
2160
+ if (success && handlers) {
2161
+ return {
2162
+ callback: handlers.callback,
2163
+ middlewares: handlers.middlewares,
2164
+ params
2165
+ };
2166
+ }
2167
+ }
2168
+ return null;
2169
+ }
2170
+ #triRouter(method, pathname) {
2171
+ const parts = pathname.split("/").filter(Boolean);
2172
+ const params = {};
2173
+ let node = this.triRouter;
2174
+ for (let part of parts) {
2175
+ if (node.children.has(part)) {
2176
+ node = node.children.get(part);
2177
+ } else if (node.children.has(":")) {
2178
+ node = node.children.get(":");
2179
+ if (node.paramName) params[node.paramName] = part;
2180
+ } else {
2181
+ return null;
2182
+ }
2183
+ }
2184
+ if (node?.handlers?.size && node?.pathname) {
2185
+ const handlers = node.handlers.get(method) || node.handlers.get("ALL");
2186
+ if (handlers) {
2187
+ return {
2188
+ middlewares: handlers.middlewares,
2189
+ callback: handlers.callback,
2190
+ params
2191
+ };
2192
+ }
2193
+ return null;
2194
+ }
2195
+ return null;
2196
+ }
2197
+ findRoute(method, pathname) {
2198
+ const route = this.#triRouter(method, pathname) || this.#hashRouter(method, pathname);
2199
+ if (route) {
2200
+ return {
2201
+ ...route,
2202
+ middlewares: [...route.middlewares]
2203
+ };
2204
+ }
2205
+ return null;
2206
+ }
2207
+ #createHandler(middlewares, finalCallback) {
2208
+ return async (ctx) => {
2209
+ let index = 0;
2210
+ const next = async () => {
2211
+ if (index < middlewares.length) {
2212
+ return middlewares[index++](ctx, next);
2213
+ } else {
2214
+ const response = await finalCallback(ctx);
2215
+ return response;
2216
+ }
2217
+ };
2218
+ return await next();
2219
+ };
2220
+ }
2221
+ #findMiddleware(pathname) {
2222
+ const parts = pathname.split("/").filter(Boolean);
2223
+ let middlewares = [];
2224
+ let node = this.triMiddlewares;
2225
+ for (let part of parts) {
2226
+ if (node.children.has(part)) {
2227
+ node = node.children.get(part);
2228
+ } else if (node.children.has("*")) {
2229
+ node = node.children.get("*");
2230
+ } else if (node.children.has(":")) {
2231
+ node = node.children.get(":");
2232
+ } else {
2233
+ break;
2234
+ }
2235
+ middlewares.push(...node.middlewares);
2236
+ }
2237
+ return middlewares;
2238
+ }
2239
+ async #handleRequest(req) {
2240
+ let ctx = new Context(req);
2241
+ const urlRef = ctx.req.urlRef;
2242
+ const { pathname } = urlRef;
2243
+ let middlewares = this.#findMiddleware(pathname);
2244
+ ctx.env = this.env;
2245
+ const logger = GlobalConfig.loggerFn();
2246
+ if (logger.request) {
2247
+ logger.request(ctx.method, ctx.pathname);
2248
+ }
2249
+ try {
2250
+ return await this.#createHandler(
2251
+ [...this.triMiddlewares.middlewares, ...middlewares],
2252
+ async (ctx2) => {
2253
+ const find = this.findRoute(ctx2.req.method, pathname);
2254
+ if (find?.callback) {
2255
+ ctx2.params = find.params;
2256
+ const callback = find.callback;
2257
+ let middlewares2 = find.middlewares;
2258
+ const response = await this.#createHandler(
2259
+ middlewares2,
2260
+ callback
2261
+ )(ctx2);
2262
+ if (response?.headers) {
2263
+ ctx2.headers.add(response.headers);
2264
+ }
2265
+ const statusText = response?.statusText || httpStatusMap[response?.status] || "";
2266
+ const status = response.status || 200;
2267
+ let headers = ctx2.headers.toObject();
2268
+ if (logger.response) {
2269
+ logger.response(ctx2.method, ctx2.pathname, status);
2270
+ }
2271
+ if (response instanceof Response) {
2272
+ return new Response(response.body, {
2273
+ status,
2274
+ statusText,
2275
+ headers
2276
+ });
2277
+ }
2278
+ return new Response(response.body, {
2279
+ status,
2280
+ statusText,
2281
+ headers
2282
+ });
2283
+ } else {
2284
+ if (logger.response) {
2285
+ logger.response(ctx2.method, ctx2.pathname, 404);
2286
+ }
2287
+ return GlobalConfig.notFound(ctx2);
2288
+ }
2289
+ }
2290
+ )(ctx);
2291
+ } catch (err) {
2292
+ let error = err;
2293
+ if (err instanceof Error) {
2294
+ error = err.stack;
2295
+ }
2296
+ if (logger.error) {
2297
+ logger.error(`${httpStatusMap[500]}: ${error} `);
2298
+ }
2299
+ return GlobalConfig.onError(error, ctx);
2300
+ }
2301
+ }
2302
+ async serve(req) {
2303
+ return this.#handleRequest(req);
2304
+ }
2305
+ }
2306
+
2307
+ function parseEnvFile(filePath, result) {
2308
+ try {
2309
+ let fileExists = false;
2310
+ let runtime = EnvironmentDetector.getEnvironment;
2311
+ if (runtime === "node" || runtime === "bun") {
2312
+ const { existsSync } = require("fs");
2313
+ fileExists = existsSync(filePath);
2314
+ } else if (runtime === "deno") {
2315
+ try {
2316
+ Deno.statSync(filePath);
2317
+ fileExists = true;
2318
+ } catch {
2319
+ fileExists = false;
2320
+ }
2321
+ }
2322
+ if (!fileExists) {
2323
+ return;
2324
+ }
2325
+ let fileContent = "";
2326
+ if (runtime === "node" || runtime === "bun") {
2327
+ const { readFileSync } = require("fs");
2328
+ fileContent = readFileSync(filePath, "utf8");
2329
+ } else if (runtime === "deno") {
2330
+ fileContent = new TextDecoder("utf-8").decode(
2331
+ Deno.readFileSync(filePath)
2332
+ );
2333
+ }
2334
+ const lines = fileContent.split("\n");
2335
+ for (const line of lines) {
2336
+ const trimmedLine = line.trim();
2337
+ if (!trimmedLine || trimmedLine.startsWith("#")) continue;
2338
+ const [key, value] = trimmedLine.split("=", 2).map((part) => part.trim());
2339
+ if (key && value) {
2340
+ const parsedValue = value.replace(/^"(.*)"$/, "$1").replace(/^'(.*)'$/, "$1");
2341
+ result[key] = parsedValue;
2342
+ if (runtime === "node" || runtime === "bun") {
2343
+ process.env[key] = parsedValue;
2344
+ } else if (runtime === "deno") {
2345
+ Deno.env.set(key, parsedValue);
2346
+ }
2347
+ }
2348
+ }
2349
+ } catch (error) {
2350
+ console.error(`[dotenv] Error parsing file: ${filePath}`, error);
2351
+ }
2352
+ }
2353
+ function loadEnv(basePath = "./") {
2354
+ const result = {};
2355
+ const envFiles = [
2356
+ ".env",
2357
+ ".env.local",
2358
+ `.env.${process?.env?.NODE_ENV || "development"}`,
2359
+ // Supports NODE_ENV (e.g., .env.development, .env.production)
2360
+ `.env.${process?.env?.NODE_ENV || "development"}.local`
2361
+ ];
2362
+ for (const envFile of envFiles) {
2363
+ parseEnvFile(`${basePath}${envFile}`, result);
2364
+ }
2365
+ return result;
2366
+ }
2367
+
2368
+ const COLORS = {
2369
+ reset: "\x1B[0m",
2370
+ bold: "\x1B[1m",
2371
+ gray: "\x1B[90m",
2372
+ red: "\x1B[31m",
2373
+ green: "\x1B[32m",
2374
+ yellow: "\x1B[33m",
2375
+ blue: "\x1B[34m",
2376
+ magenta: "\x1B[35m",
2377
+ cyan: "\x1B[36m",
2378
+ bgBlue: "\x1B[44m",
2379
+ bgMagenta: "\x1B[45m"};
2380
+ const loggerOutput = (level, message, ...args) => {
2381
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
2382
+ const LEVEL_COLORS = {
2383
+ info: COLORS.blue,
2384
+ warn: COLORS.yellow,
2385
+ error: COLORS.red,
2386
+ debug: COLORS.cyan,
2387
+ success: COLORS.green
2388
+ };
2389
+ const prefix = `${COLORS.gray}[${timestamp}]${COLORS.reset}`;
2390
+ const levelText = `${LEVEL_COLORS[level]}[${level.toUpperCase()}]${COLORS.reset}`;
2391
+ console.log(`${prefix} ${levelText} ${message}`, ...args?.flat());
2392
+ };
2393
+ function logger() {
2394
+ const startTime = performance.now();
2395
+ if (GlobalConfig.enableLogger) {
2396
+ return {
2397
+ request: (method, pathname) => {
2398
+ console.log(
2399
+ `${COLORS.bold}<-- ${COLORS.reset}${COLORS.bgMagenta} ${method} ${COLORS.reset} ${pathname}`
2400
+ );
2401
+ },
2402
+ response: (method, pathname, status) => {
2403
+ const elapsed = performance.now() - startTime;
2404
+ console.log(
2405
+ `${COLORS.bold}--> ${COLORS.reset}${COLORS.bgBlue} ${method} ${COLORS.reset} ${pathname} ${COLORS.yellow}${status}${COLORS.reset} ${COLORS.magenta}${elapsed.toFixed(2)}ms${COLORS.reset}`
2406
+ );
2407
+ },
2408
+ info: (msg, ...args) => loggerOutput("info", msg, ...args),
2409
+ warn: (msg, ...args) => loggerOutput("warn", msg, ...args),
2410
+ error: (msg, ...args) => loggerOutput("error", msg, ...args),
2411
+ debug: (msg, ...args) => loggerOutput("debug", msg, ...args),
2412
+ success: (msg, ...args) => loggerOutput("success", msg, ...args)
2413
+ };
2414
+ }
2415
+ return {
2416
+ request: (method, pathname) => {
2417
+ },
2418
+ response: (method, pathname, status) => {
2419
+ },
2420
+ info: (msg, ...args) => {
2421
+ },
2422
+ warn: (msg, ...args) => {
2423
+ },
2424
+ error: (msg, ...args) => {
2425
+ },
2426
+ debug: (msg, ...args) => {
2427
+ },
2428
+ success: (msg, ...args) => {
2429
+ }
2430
+ };
2431
+ }
2432
+
2433
+ function cors(option = {}) {
2434
+ const {
2435
+ methods,
2436
+ allowedHeaders,
2437
+ credentials,
2438
+ exposedHeaders,
2439
+ maxAge,
2440
+ origin
2441
+ } = option;
2442
+ return async (ctx, next) => {
2443
+ const reqOrigin = ctx.req.headers.get("origin") || "";
2444
+ let allowOrigin = "*";
2445
+ if (typeof origin === "string") {
2446
+ allowOrigin = origin;
2447
+ } else if (origin instanceof RegExp) {
2448
+ allowOrigin = origin.test(reqOrigin) ? reqOrigin : "";
2449
+ } else if (Array.isArray(origin)) {
2450
+ const isAllowed = origin.some((item) => {
2451
+ if (typeof item === "string") {
2452
+ return item === reqOrigin;
2453
+ } else if (item instanceof RegExp) {
2454
+ return item.test(reqOrigin);
2455
+ }
2456
+ });
2457
+ allowOrigin = isAllowed ? reqOrigin : "";
2458
+ } else if (typeof origin === "function") {
2459
+ allowOrigin = origin(reqOrigin) ? reqOrigin : "";
2460
+ }
2461
+ ctx.headers.set("Access-Control-Allow-Origin", allowOrigin);
2462
+ ctx.headers.set(
2463
+ "Access-Control-Allow-Methods",
2464
+ (methods || ["GET", "POST", "PUT", "DELETE"]).join(", ")
2465
+ );
2466
+ ctx.headers.set(
2467
+ "Access-Control-Allow-Headers",
2468
+ (allowedHeaders || ["Content-Type", "Authorization"]).join(", ")
2469
+ );
2470
+ if (exposedHeaders) {
2471
+ ctx.headers.set(
2472
+ "Access-Control-Expose-Headers",
2473
+ exposedHeaders.join(", ")
2474
+ );
2475
+ }
2476
+ if (credentials) {
2477
+ ctx.headers.set("Access-Control-Allow-Credentials", "true");
2478
+ }
2479
+ if (maxAge) {
2480
+ ctx.headers.set("Access-Control-Max-Age", maxAge.toString());
2481
+ }
2482
+ if (ctx.req.method === "OPTIONS") {
2483
+ return new Response(null, {
2484
+ status: 204,
2485
+ headers: ctx.headers.toObject()
2486
+ });
2487
+ }
2488
+ return await next();
2489
+ };
2490
+ }
2491
+
2492
+ export { Router, TezResponse, TezX, bunAdapter, cors, denoAdapter, loadEnv, logger, nodeAdapter, useParams };