diesel-core 0.0.3 → 0.0.5
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/build.js +12 -0
- package/dist/ctx.js +1 -0
- package/dist/handleRequest.js +1 -0
- package/dist/router.js +1 -0
- package/dist/server.js +1 -0
- package/dist/trie.js +1 -0
- package/package.json +2 -2
- package/src/ctx.js +58 -34
- package/src/handleRequest.js +1 -2
- package/src/server.js +118 -107
- package/src/trie.js +7 -1
package/build.js
ADDED
package/dist/ctx.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
async function H(F){const G={};if(!F)return G;return F.split(";").forEach((L)=>{const[X,M]=L.trim().split("=");G[X]=M.split(" ")[0]}),G}async function K(F,G){const z={},L=F.split("/"),[X]=G.split("?"),M=X.split("/");if(L.length!==M.length)return null;return L.forEach((U,Y)=>{if(U.startsWith(":")){const Z=U.slice(1);z[Z]=M[Y]}}),z}async function W(F){const G=F.headers.get("Content-Type");if(G.includes("application/json"))try{return await F.json()}catch(z){return new Response({error:"Invalid JSON format"})}else if(G.startsWith("application/x-www-form-urlencoded")){const z=await F.text();return Object.fromEntries(new URLSearchParams(z))}else if(G.startsWith("multipart/form-data")){const z=await F.formData();return O(z)}else return new Response({error:"unknown request body"})}function O(F){const G={};for(let[z,L]of F.entries())G[z]=L;return G}function $(F,G){let z={},L={},X=!1,M=null,U=null,Y=null,Z=null,J=200;return{req:F,url:G,next:()=>{},status(w){return J=w,this},async body(){if(!Z)Z=await W(F);return Z},setHeader(w,E){return z[w]=E,this},set(w,E){return L[w]=E,this},get(w){return L[w]},setAuth(w){return X=w,this},getAuth(){return X},text(w,E){if(E)J=E;return new Response(w,{status:J,headers:z})},json(w,E){if(E)J=E;return new Response(JSON.stringify(w),{status:J,headers:{"Content-Type":"application/json",...z}})},html(w,E){if(E)J=E;return new Response(Bun.file(w),{status:J,headers:{...z}})},file(w,E){if(E)J=E;return new Response(Bun.file(w),{status:J,headers:{...z}})},redirect(w,E){if(E)J=E;return new Response(null,{status:J,headers:{Location:w,...z}})},async getParams(w){if(!Y)Y=await K(F.routePattern,G.pathname);return w?Y[w]:Y},getQuery(w){if(!M)M=Object.fromEntries(G.searchParams.entries());return w?M[w]:M},cookie(w,E,I={}){let R=`${encodeURIComponent(w)}=${encodeURIComponent(E)}`;if(I.maxAge)R+=`; Max-Age=${I.maxAge}`;if(I.expires)R+=`; Expires=${I.expires.toUTCString()}`;if(I.path)R+=`; Path=${I.path}`;if(I.domain)R+=`; Domain=${I.domain}`;if(I.secure)R+="; Secure";if(I.httpOnly)R+="; HttpOnly";if(I.sameSite)R+=`; SameSite=${I.sameSite}`;if(z["Set-Cookie"]){const _=Array.isArray(z["Set-Cookie"])?z["Set-Cookie"]:[z["Set-Cookie"]];_.push(R),z["Set-Cookie"]=_}else z["Set-Cookie"]=R;return this},async getCookie(w){if(!U)U=await H(F.headers.get("cookie"));return w?U[w]:U}}}export{$ as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
async function O(J){const L={};if(!J)return L;return J.split(";").forEach((X)=>{const[E,Y]=X.trim().split("=");L[E]=Y.split(" ")[0]}),L}async function R(J,L){const G={},X=J.split("/"),[E]=L.split("?"),Y=E.split("/");if(X.length!==Y.length)return null;return X.forEach(($,z)=>{if($.startsWith(":")){const K=$.slice(1);G[K]=Y[z]}}),G}async function V(J){const L=J.headers.get("Content-Type");if(L.includes("application/json"))try{return await J.json()}catch(G){return new Response({error:"Invalid JSON format"})}else if(L.startsWith("application/x-www-form-urlencoded")){const G=await J.text();return Object.fromEntries(new URLSearchParams(G))}else if(L.startsWith("multipart/form-data")){const G=await J.formData();return A(G)}else return new Response({error:"unknown request body"})}function A(J){const L={};for(let[G,X]of J.entries())L[G]=X;return L}function W(J,L){let G={},X={},E=!1,Y=null,$=null,z=null,K=null,_=200;return{req:J,url:L,next:()=>{},status(I){return _=I,this},async body(){if(!K)K=await V(J);return K},setHeader(I,U){return G[I]=U,this},set(I,U){return X[I]=U,this},get(I){return X[I]},setAuth(I){return E=I,this},getAuth(){return E},text(I,U){if(U)_=U;return new Response(I,{status:_,headers:G})},json(I,U){if(U)_=U;return new Response(JSON.stringify(I),{status:_,headers:{"Content-Type":"application/json",...G}})},html(I,U){if(U)_=U;return new Response(Bun.file(I),{status:_,headers:{...G}})},file(I,U){if(U)_=U;return new Response(Bun.file(I),{status:_,headers:{...G}})},redirect(I,U){if(U)_=U;return new Response(null,{status:_,headers:{Location:I,...G}})},async getParams(I){if(!z)z=await R(J.routePattern,L.pathname);return I?z[I]:z},getQuery(I){if(!Y)Y=Object.fromEntries(L.searchParams.entries());return I?Y[I]:Y},cookie(I,U,Z={}){let F=`${encodeURIComponent(I)}=${encodeURIComponent(U)}`;if(Z.maxAge)F+=`; Max-Age=${Z.maxAge}`;if(Z.expires)F+=`; Expires=${Z.expires.toUTCString()}`;if(Z.path)F+=`; Path=${Z.path}`;if(Z.domain)F+=`; Domain=${Z.domain}`;if(Z.secure)F+="; Secure";if(Z.httpOnly)F+="; HttpOnly";if(Z.sameSite)F+=`; SameSite=${Z.sameSite}`;if(G["Set-Cookie"]){const M=Array.isArray(G["Set-Cookie"])?G["Set-Cookie"]:[G["Set-Cookie"]];M.push(F),G["Set-Cookie"]=M}else G["Set-Cookie"]=F;return this},async getCookie(I){if(!$)$=await O(J.headers.get("cookie"));return I?$[I]:$}}}async function T(J,L){for(let G of J){const X=await G(L);if(X)return X}}function j(J){return new Response(`Route not found for ${J}`,{status:404})}function D(){return new Response("Method not allowed",{status:405})}function Q(){return new Response("No response from handler",{status:204})}function b(){return new Response("Internal Server Error",{status:500})}async function B(J,L,G){const{pathname:X}=L,{method:E}=J,Y=G.trie.search(X,E);if(!Y||!Y.handler)return j(X);if(Y.method!==E)return D();if(Y.isDynamic)J.routePattern=Y.path;const $=W(J,L);if(G.hasMiddleware){const z=[...G.globalMiddlewares,...G.middlewares.get(X)||[]],K=await T(z,$);if(K)return K}try{return await Y.handler($)??Q()}catch(z){return b()}}export{B as default};
|
package/dist/router.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
class M{constructor(){this.children={},this.isEndOfWord=!1,this.handler=[],this.isImportant=!1,this.isDynamic=!1,this.pattern="",this.path="",this.method=[],this.subMiddlewares=new Map}}class A{constructor(){this.root=new M}insert(L,G){let E=this.root;const U=L.split("/").filter(Boolean);if(L==="/"){E.isEndOfWord=!0,E.handler.push(G.handler),E.isImportant=G.isImportant,E.path=L,E.method.push(G.method);return}for(let J of U){let X=!1,Z=J;if(J.startsWith(":"))X=!0,Z=":";if(!E.children[Z])E.children[Z]=new M;E=E.children[Z],E.isDynamic=X,E.pattern=J}E.isEndOfWord=!0,E.method.push(G.method),E.handler.push(G.handler),E.isImportant=G.isImportant,E.path=L}insertMidl(L){if(!this.root.subMiddlewares.has(L))this.root.subMiddlewares.set(L)}search(L,G){let E=this.root;const U=L.split("/").filter(Boolean);for(let X of U){let Z=X;if(!E.children[Z])if(E.children[":"])E=E.children[":"];else return null;else E=E.children[Z]}let J=E.method.indexOf(G);if(J!==-1)return{path:E.path,handler:E.handler[J],isDynamic:E.isDynamic,pattern:E.pattern,method:E.method[J]};return{path:E.path,handler:E.handler,isDynamic:E.isDynamic,pattern:E.pattern,method:E.method[J]}}getAllRoutes(){const L=[],G=(E,U)=>{if(E.isEndOfWord)L.push({path:U,handler:E.handler,isImportant:E.isImportant,isDynamic:E.isDynamic,pattern:E.pattern});for(let J in E.children){const X=E.children[J],Z=U+(J===":"?"/:"+X.pattern:"/"+J);G(X,Z)}};return G(this.root,""),L}}async function j(L){const G={};if(!L)return G;return L.split(";").forEach((U)=>{const[J,X]=U.trim().split("=");G[J]=X.split(" ")[0]}),G}async function C(L,G){const E={},U=L.split("/"),[J]=G.split("?"),X=J.split("/");if(U.length!==X.length)return null;return U.forEach((Z,$)=>{if(Z.startsWith(":")){const W=Z.slice(1);E[W]=X[$]}}),E}async function O(L){const G=L.headers.get("Content-Type");if(G.includes("application/json"))try{return await L.json()}catch(E){return new Response({error:"Invalid JSON format"})}else if(G.startsWith("application/x-www-form-urlencoded")){const E=await L.text();return Object.fromEntries(new URLSearchParams(E))}else if(G.startsWith("multipart/form-data")){const E=await L.formData();return I(E)}else return new Response({error:"unknown request body"})}function I(L){const G={};for(let[E,U]of L.entries())G[E]=U;return G}function V(L,G){let E={},U={},J=!1,X=null,Z=null,$=null,W=null,F=200;return{req:L,url:G,next:()=>{},status(Y){return F=Y,this},async body(){if(!W)W=await O(L);return W},setHeader(Y,_){return E[Y]=_,this},set(Y,_){return U[Y]=_,this},get(Y){return U[Y]},setAuth(Y){return J=Y,this},getAuth(){return J},text(Y,_){if(_)F=_;return new Response(Y,{status:F,headers:E})},json(Y,_){if(_)F=_;return new Response(JSON.stringify(Y),{status:F,headers:{"Content-Type":"application/json",...E}})},html(Y,_){if(_)F=_;return new Response(Bun.file(Y),{status:F,headers:{...E}})},file(Y,_){if(_)F=_;return new Response(Bun.file(Y),{status:F,headers:{...E}})},redirect(Y,_){if(_)F=_;return new Response(null,{status:F,headers:{Location:Y,...E}})},async getParams(Y){if(!$)$=await C(L.routePattern,G.pathname);return Y?$[Y]:$},getQuery(Y){if(!X)X=Object.fromEntries(G.searchParams.entries());return Y?X[Y]:X},cookie(Y,_,z={}){let K=`${encodeURIComponent(Y)}=${encodeURIComponent(_)}`;if(z.maxAge)K+=`; Max-Age=${z.maxAge}`;if(z.expires)K+=`; Expires=${z.expires.toUTCString()}`;if(z.path)K+=`; Path=${z.path}`;if(z.domain)K+=`; Domain=${z.domain}`;if(z.secure)K+="; Secure";if(z.httpOnly)K+="; HttpOnly";if(z.sameSite)K+=`; SameSite=${z.sameSite}`;if(E["Set-Cookie"]){const Q=Array.isArray(E["Set-Cookie"])?E["Set-Cookie"]:[E["Set-Cookie"]];Q.push(K),E["Set-Cookie"]=Q}else E["Set-Cookie"]=K;return this},async getCookie(Y){if(!Z)Z=await j(L.headers.get("cookie"));return Y?Z[Y]:Z}}}async function v(L,G){for(let E of L){const U=await E(G);if(U)return U}}function N(L){return new Response(`Route not found for ${L}`,{status:404})}function f(){return new Response("Method not allowed",{status:405})}function w(){return new Response("No response from handler",{status:204})}function R(){return new Response("Internal Server Error",{status:500})}async function B(L,G,E){const{pathname:U}=G,{method:J}=L,X=E.trie.search(U,J);if(!X||!X.handler)return N(U);if(X.method!==J)return f();if(X.isDynamic)L.routePattern=X.path;const Z=V(L,G);if(E.hasMiddleware){const $=[...E.globalMiddlewares,...E.middlewares.get(U)||[]],W=await v($,Z);if(W)return W}try{return await X.handler(Z)??w()}catch($){return R()}}class T{constructor(){this.routes=new Map,this.globalMiddlewares=[],this.middlewares=new Map,this.trie=new A,this.hasMiddleware=!1}compile(){if(this.globalMiddlewares.length>0)this.hasMiddleware=!0;for(let[L,G]of this.middlewares.entries())if(G.length>0){this.hasMiddleware=!0;break}}listen(L,G){this.compile();const E=Bun.serve({port:L,fetch:async(U)=>{const J=new URL(U.url);try{return await B(U,J,this)}catch(X){return new Response("Internal Server Error",{status:500})}},onClose(){console.log("Server is shutting down...")}});if(typeof G==="function")return G();return console.log(`Server is running on http://localhost:${L}`),E}register(L,G){const E=Object.entries(G.trie.root.children);G.trie.root.subMiddlewares.forEach((U,J)=>{if(!this.middlewares.has(L+J))this.middlewares.set(L+J,[]);if(!this.middlewares.get(L+J).includes(...U))this.middlewares.get(L+J).push(...U)});for(let[U,J]of E){const X=L+J?.path,Z=J.handler[0],$=J.method[0];this.trie.insert(X,{handler:Z,method:$})}G.trie=new A}#E(L,G,E){const U=E.slice(0,-1);if(!this.middlewares.has(G))this.middlewares.set(G,[]);if(G==="/")U.forEach((X)=>{if(!this.globalMiddlewares.includes(X))this.globalMiddlewares.push(X)});else if(!this.middlewares.get(G).includes(...U))this.middlewares.get(G).push(...U);const J=E[E.length-1];this.trie.insert(G,{handler:J,method:L})}use(L,G){if(typeof L==="function"){if(!this.globalMiddlewares.includes(L))return this.globalMiddlewares.push(L)}const E=L;if(!this.middlewares.has(E))this.middlewares.set(E,[]);if(!this.middlewares.get(E).includes(G))this.middlewares.get(E).push(G)}get(L,...G){return this.#E("GET",L,G)}post(L,...G){return this.#E("POST",L,G)}put(L,...G){return this.#E("PUT",L,G)}patch(L,...G){if(G.length>0)return this.#E("PATCH",L,G)}delete(L,...G){return this.#E("DELETE",L,G)}}var D=T;class b extends D{constructor(){super()}#E(L,G,E){if(!this.trie.root.subMiddlewares.has(G))this.trie.root.subMiddlewares.set(G,[]);const U=E.slice(0,-1);if(!this.trie.root.subMiddlewares.get(G).includes(...U))this.trie.root.subMiddlewares.get(G).push(...U);const J=E[E.length-1];this.trie.insert(G,{handler:J,method:L})}get(L,...G){return this.#E("GET",L,G)}post(L,...G){return this.#E("POST",L,G)}put(L,...G){return this.#E("PUT",L,G)}patch(L,...G){if(G.length>0)return this.#E("PATCH",L,G)}delete(L,...G){return this.#E("DELETE",L,G)}}var m=b;export{m as default};
|
package/dist/server.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
class A{constructor(){this.children={},this.isEndOfWord=!1,this.handler=[],this.isImportant=!1,this.isDynamic=!1,this.pattern="",this.path="",this.method=[],this.subMiddlewares=new Map}}class V{constructor(){this.root=new A}insert(J,L){let G=this.root;const X=J.split("/").filter(Boolean);if(J==="/"){G.isEndOfWord=!0,G.handler.push(L.handler),G.isImportant=L.isImportant,G.path=J,G.method.push(L.method);return}for(let U of X){let Y=!1,_=U;if(U.startsWith(":"))Y=!0,_=":";if(!G.children[_])G.children[_]=new A;G=G.children[_],G.isDynamic=Y,G.pattern=U}G.isEndOfWord=!0,G.method.push(L.method),G.handler.push(L.handler),G.isImportant=L.isImportant,G.path=J}insertMidl(J){if(!this.root.subMiddlewares.has(J))this.root.subMiddlewares.set(J)}search(J,L){let G=this.root;const X=J.split("/").filter(Boolean);for(let Y of X){let _=Y;if(!G.children[_])if(G.children[":"])G=G.children[":"];else return null;else G=G.children[_]}let U=G.method.indexOf(L);if(U!==-1)return{path:G.path,handler:G.handler[U],isDynamic:G.isDynamic,pattern:G.pattern,method:G.method[U]};return{path:G.path,handler:G.handler,isDynamic:G.isDynamic,pattern:G.pattern,method:G.method[U]}}getAllRoutes(){const J=[],L=(G,X)=>{if(G.isEndOfWord)J.push({path:X,handler:G.handler,isImportant:G.isImportant,isDynamic:G.isDynamic,pattern:G.pattern});for(let U in G.children){const Y=G.children[U],_=X+(U===":"?"/:"+Y.pattern:"/"+U);L(Y,_)}};return L(this.root,""),J}}async function M(J){const L={};if(!J)return L;return J.split(";").forEach((X)=>{const[U,Y]=X.trim().split("=");L[U]=Y.split(" ")[0]}),L}async function C(J,L){const G={},X=J.split("/"),[U]=L.split("?"),Y=U.split("/");if(X.length!==Y.length)return null;return X.forEach((_,z)=>{if(_.startsWith(":")){const E=_.slice(1);G[E]=Y[z]}}),G}async function O(J){const L=J.headers.get("Content-Type");if(L.includes("application/json"))try{return await J.json()}catch(G){return new Response({error:"Invalid JSON format"})}else if(L.startsWith("application/x-www-form-urlencoded")){const G=await J.text();return Object.fromEntries(new URLSearchParams(G))}else if(L.startsWith("multipart/form-data")){const G=await J.formData();return T(G)}else return new Response({error:"unknown request body"})}function T(J){const L={};for(let[G,X]of J.entries())L[G]=X;return L}function B(J,L){let G={},X={},U=!1,Y=null,_=null,z=null,E=null,K=200;return{req:J,url:L,next:()=>{},status(Z){return K=Z,this},async body(){if(!E)E=await O(J);return E},setHeader(Z,$){return G[Z]=$,this},set(Z,$){return X[Z]=$,this},get(Z){return X[Z]},setAuth(Z){return U=Z,this},getAuth(){return U},text(Z,$){if($)K=$;return new Response(Z,{status:K,headers:G})},json(Z,$){if($)K=$;return new Response(JSON.stringify(Z),{status:K,headers:{"Content-Type":"application/json",...G}})},html(Z,$){if($)K=$;return new Response(Bun.file(Z),{status:K,headers:{...G}})},file(Z,$){if($)K=$;return new Response(Bun.file(Z),{status:K,headers:{...G}})},redirect(Z,$){if($)K=$;return new Response(null,{status:K,headers:{Location:Z,...G}})},async getParams(Z){if(!z)z=await C(J.routePattern,L.pathname);return Z?z[Z]:z},getQuery(Z){if(!Y)Y=Object.fromEntries(L.searchParams.entries());return Z?Y[Z]:Y},cookie(Z,$,F={}){let W=`${encodeURIComponent(Z)}=${encodeURIComponent($)}`;if(F.maxAge)W+=`; Max-Age=${F.maxAge}`;if(F.expires)W+=`; Expires=${F.expires.toUTCString()}`;if(F.path)W+=`; Path=${F.path}`;if(F.domain)W+=`; Domain=${F.domain}`;if(F.secure)W+="; Secure";if(F.httpOnly)W+="; HttpOnly";if(F.sameSite)W+=`; SameSite=${F.sameSite}`;if(G["Set-Cookie"]){const j=Array.isArray(G["Set-Cookie"])?G["Set-Cookie"]:[G["Set-Cookie"]];j.push(W),G["Set-Cookie"]=j}else G["Set-Cookie"]=W;return this},async getCookie(Z){if(!_)_=await M(J.headers.get("cookie"));return Z?_[Z]:_}}}async function b(J,L){for(let G of J){const X=await G(L);if(X)return X}}function I(J){return new Response(`Route not found for ${J}`,{status:404})}function v(){return new Response("Method not allowed",{status:405})}function N(){return new Response("No response from handler",{status:204})}function R(){return new Response("Internal Server Error",{status:500})}async function Q(J,L,G){const{pathname:X}=L,{method:U}=J,Y=G.trie.search(X,U);if(!Y||!Y.handler)return I(X);if(Y.method!==U)return v();if(Y.isDynamic)J.routePattern=Y.path;const _=B(J,L);if(G.hasMiddleware){const z=[...G.globalMiddlewares,...G.middlewares.get(X)||[]],E=await b(z,_);if(E)return E}try{return await Y.handler(_)??N()}catch(z){return R()}}class D{constructor(){this.routes=new Map,this.globalMiddlewares=[],this.middlewares=new Map,this.trie=new V,this.hasMiddleware=!1}compile(){if(this.globalMiddlewares.length>0)this.hasMiddleware=!0;for(let[J,L]of this.middlewares.entries())if(L.length>0){this.hasMiddleware=!0;break}}listen(J,L){this.compile();const G=Bun.serve({port:J,fetch:async(X)=>{const U=new URL(X.url);try{return await Q(X,U,this)}catch(Y){return new Response("Internal Server Error",{status:500})}},onClose(){console.log("Server is shutting down...")}});if(typeof L==="function")return L();return console.log(`Server is running on http://localhost:${J}`),G}register(J,L){const G=Object.entries(L.trie.root.children);L.trie.root.subMiddlewares.forEach((X,U)=>{if(!this.middlewares.has(J+U))this.middlewares.set(J+U,[]);if(!this.middlewares.get(J+U).includes(...X))this.middlewares.get(J+U).push(...X)});for(let[X,U]of G){const Y=J+U?.path,_=U.handler[0],z=U.method[0];this.trie.insert(Y,{handler:_,method:z})}L.trie=new V}#G(J,L,G){const X=G.slice(0,-1);if(!this.middlewares.has(L))this.middlewares.set(L,[]);if(L==="/")X.forEach((Y)=>{if(!this.globalMiddlewares.includes(Y))this.globalMiddlewares.push(Y)});else if(!this.middlewares.get(L).includes(...X))this.middlewares.get(L).push(...X);const U=G[G.length-1];this.trie.insert(L,{handler:U,method:J})}use(J,L){if(typeof J==="function"){if(!this.globalMiddlewares.includes(J))return this.globalMiddlewares.push(J)}const G=J;if(!this.middlewares.has(G))this.middlewares.set(G,[]);if(!this.middlewares.get(G).includes(L))this.middlewares.get(G).push(L)}get(J,...L){return this.#G("GET",J,L)}post(J,...L){return this.#G("POST",J,L)}put(J,...L){return this.#G("PUT",J,L)}patch(J,...L){if(L.length>0)return this.#G("PATCH",J,L)}delete(J,...L){return this.#G("DELETE",J,L)}}var S=D;export{S as default};
|
package/dist/trie.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
class E{constructor(){this.children={},this.isEndOfWord=!1,this.handler=[],this.isImportant=!1,this.isDynamic=!1,this.pattern="",this.path="",this.method=[],this.subMiddlewares=new Map}}class F{constructor(){this.root=new E}insert(j,z){let b=this.root;const C=j.split("/").filter(Boolean);if(j==="/"){b.isEndOfWord=!0,b.handler.push(z.handler),b.isImportant=z.isImportant,b.path=j,b.method.push(z.method);return}for(let q of C){let B=!1,A=q;if(q.startsWith(":"))B=!0,A=":";if(!b.children[A])b.children[A]=new E;b=b.children[A],b.isDynamic=B,b.pattern=q}b.isEndOfWord=!0,b.method.push(z.method),b.handler.push(z.handler),b.isImportant=z.isImportant,b.path=j}insertMidl(j){if(!this.root.subMiddlewares.has(j))this.root.subMiddlewares.set(j)}search(j,z){let b=this.root;const C=j.split("/").filter(Boolean);for(let B of C){let A=B;if(!b.children[A])if(b.children[":"])b=b.children[":"];else return null;else b=b.children[A]}let q=b.method.indexOf(z);if(q!==-1)return{path:b.path,handler:b.handler[q],isDynamic:b.isDynamic,pattern:b.pattern,method:b.method[q]};return{path:b.path,handler:b.handler,isDynamic:b.isDynamic,pattern:b.pattern,method:b.method[q]}}getAllRoutes(){const j=[],z=(b,C)=>{if(b.isEndOfWord)j.push({path:C,handler:b.handler,isImportant:b.isImportant,isDynamic:b.isDynamic,pattern:b.pattern});for(let q in b.children){const B=b.children[q],A=C+(q===":"?"/:"+B.pattern:"/"+q);z(B,A)}};return z(this.root,""),j}}export{F as default};
|
package/package.json
CHANGED
package/src/ctx.js
CHANGED
|
@@ -5,26 +5,35 @@ export default function createCtx(req, url) {
|
|
|
5
5
|
let parsedQuery = null;
|
|
6
6
|
let parsedCookie = null;
|
|
7
7
|
let parsedParams = null;
|
|
8
|
-
let parsedBody= null
|
|
8
|
+
let parsedBody = null;
|
|
9
|
+
let responseStatus = 200; // Default status
|
|
9
10
|
|
|
10
11
|
return {
|
|
11
12
|
req,
|
|
12
13
|
url,
|
|
13
14
|
next: () => {},
|
|
14
15
|
|
|
16
|
+
// Set response status for chaining
|
|
17
|
+
status(status) {
|
|
18
|
+
responseStatus = status;
|
|
19
|
+
return this;
|
|
20
|
+
},
|
|
21
|
+
|
|
15
22
|
async body() {
|
|
16
23
|
if (!parsedBody) {
|
|
17
|
-
parsedBody = await parseBody(req)
|
|
18
|
-
return parsedBody;
|
|
24
|
+
parsedBody = await parseBody(req);
|
|
19
25
|
}
|
|
20
26
|
return parsedBody;
|
|
21
27
|
},
|
|
28
|
+
|
|
22
29
|
setHeader(key, value) {
|
|
23
30
|
headers[key] = value;
|
|
31
|
+
return this;
|
|
24
32
|
},
|
|
25
33
|
|
|
26
34
|
set(key, value) {
|
|
27
35
|
settedValue[key] = value;
|
|
36
|
+
return this;
|
|
28
37
|
},
|
|
29
38
|
|
|
30
39
|
get(key) {
|
|
@@ -33,22 +42,30 @@ export default function createCtx(req, url) {
|
|
|
33
42
|
|
|
34
43
|
setAuth(authStatus) {
|
|
35
44
|
isAuthenticated = authStatus;
|
|
45
|
+
return this;
|
|
36
46
|
},
|
|
37
47
|
|
|
38
48
|
getAuth() {
|
|
39
49
|
return isAuthenticated;
|
|
40
50
|
},
|
|
41
51
|
|
|
42
|
-
|
|
52
|
+
// Response methods with optional status
|
|
53
|
+
text(data, status) {
|
|
54
|
+
if (status) {
|
|
55
|
+
responseStatus = status;
|
|
56
|
+
}
|
|
43
57
|
return new Response(data, {
|
|
44
|
-
status,
|
|
58
|
+
status: responseStatus,
|
|
45
59
|
headers: headers,
|
|
46
60
|
});
|
|
47
61
|
},
|
|
48
62
|
|
|
49
|
-
json(data, status
|
|
63
|
+
json(data, status) {
|
|
64
|
+
if (status) {
|
|
65
|
+
responseStatus = status;
|
|
66
|
+
}
|
|
50
67
|
return new Response(JSON.stringify(data), {
|
|
51
|
-
status,
|
|
68
|
+
status: responseStatus,
|
|
52
69
|
headers: {
|
|
53
70
|
"Content-Type": "application/json",
|
|
54
71
|
...headers,
|
|
@@ -56,26 +73,36 @@ export default function createCtx(req, url) {
|
|
|
56
73
|
});
|
|
57
74
|
},
|
|
58
75
|
|
|
59
|
-
html(filepath) {
|
|
76
|
+
html(filepath, status) {
|
|
77
|
+
if (status) {
|
|
78
|
+
responseStatus = status;
|
|
79
|
+
}
|
|
60
80
|
return new Response(Bun.file(filepath), {
|
|
61
|
-
status:
|
|
81
|
+
status: responseStatus,
|
|
62
82
|
headers: {
|
|
63
83
|
...headers,
|
|
64
84
|
},
|
|
65
85
|
});
|
|
66
86
|
},
|
|
67
|
-
|
|
87
|
+
|
|
88
|
+
file(filePath, status) {
|
|
89
|
+
if (status) {
|
|
90
|
+
responseStatus = status;
|
|
91
|
+
}
|
|
68
92
|
return new Response(Bun.file(filePath), {
|
|
69
|
-
status:
|
|
93
|
+
status: responseStatus,
|
|
70
94
|
headers: {
|
|
71
95
|
...headers,
|
|
72
96
|
},
|
|
73
97
|
});
|
|
74
98
|
},
|
|
75
99
|
|
|
76
|
-
redirect(path, status
|
|
100
|
+
redirect(path, status) {
|
|
101
|
+
if (status) {
|
|
102
|
+
responseStatus = status;
|
|
103
|
+
}
|
|
77
104
|
return new Response(null, {
|
|
78
|
-
status,
|
|
105
|
+
status: responseStatus,
|
|
79
106
|
headers: {
|
|
80
107
|
Location: path,
|
|
81
108
|
...headers,
|
|
@@ -83,9 +110,9 @@ export default function createCtx(req, url) {
|
|
|
83
110
|
});
|
|
84
111
|
},
|
|
85
112
|
|
|
86
|
-
getParams(props) {
|
|
113
|
+
async getParams(props) {
|
|
87
114
|
if (!parsedParams) {
|
|
88
|
-
parsedParams = extractDynamicParams(req.routePattern, url.pathname);
|
|
115
|
+
parsedParams = await extractDynamicParams(req.routePattern, url.pathname);
|
|
89
116
|
}
|
|
90
117
|
return props ? parsedParams[props] : parsedParams;
|
|
91
118
|
},
|
|
@@ -97,7 +124,7 @@ export default function createCtx(req, url) {
|
|
|
97
124
|
return props ? parsedQuery[props] : parsedQuery;
|
|
98
125
|
},
|
|
99
126
|
|
|
100
|
-
cookie(name, value, options = {}) {
|
|
127
|
+
async cookie(name, value, options = {}) {
|
|
101
128
|
let cookieString = `${encodeURIComponent(name)}=${encodeURIComponent(value)}`;
|
|
102
129
|
|
|
103
130
|
// Add options to cookie string (e.g., expiration, path, HttpOnly, etc.)
|
|
@@ -110,59 +137,56 @@ export default function createCtx(req, url) {
|
|
|
110
137
|
if (options.sameSite) cookieString += `; SameSite=${options.sameSite}`;
|
|
111
138
|
|
|
112
139
|
if (headers["Set-Cookie"]) {
|
|
113
|
-
// If it's already an array, push the new cookie, otherwise convert to array
|
|
114
140
|
const existingCookies = Array.isArray(headers["Set-Cookie"]) ? headers["Set-Cookie"] : [headers["Set-Cookie"]];
|
|
115
|
-
|
|
116
|
-
// Add the new cookie string to the array
|
|
117
141
|
existingCookies.push(cookieString);
|
|
118
|
-
|
|
119
|
-
// Update Set-Cookie header
|
|
120
142
|
headers["Set-Cookie"] = existingCookies;
|
|
121
143
|
} else {
|
|
122
|
-
// If no cookies exist, initialize the header
|
|
123
144
|
headers["Set-Cookie"] = cookieString;
|
|
124
145
|
}
|
|
146
|
+
return this;
|
|
125
147
|
},
|
|
126
|
-
|
|
148
|
+
|
|
149
|
+
async getCookie(cookieName) {
|
|
127
150
|
if (!parsedCookie) {
|
|
128
|
-
parsedCookie = parseCookie(req.headers.get("cookie"));
|
|
151
|
+
parsedCookie = await parseCookie(req.headers.get("cookie"));
|
|
129
152
|
}
|
|
130
153
|
return cookieName ? parsedCookie[cookieName] : parsedCookie;
|
|
131
154
|
},
|
|
132
155
|
};
|
|
133
156
|
}
|
|
134
157
|
|
|
135
|
-
|
|
158
|
+
|
|
159
|
+
async function parseCookie(header) {
|
|
136
160
|
const cookies = {};
|
|
137
161
|
if (!header) return cookies;
|
|
138
162
|
|
|
139
163
|
const cookieArray = header.split(";");
|
|
140
164
|
cookieArray.forEach((cookie) => {
|
|
141
|
-
const [cookieName,
|
|
142
|
-
cookies[cookieName] =
|
|
165
|
+
const [cookieName, cookieValue] = cookie.trim().split("=");
|
|
166
|
+
cookies[cookieName] = cookieValue.split(" ")[0];
|
|
143
167
|
});
|
|
144
168
|
return cookies;
|
|
145
169
|
}
|
|
146
170
|
|
|
147
|
-
|
|
171
|
+
async function extractDynamicParams(routePattern, path) {
|
|
148
172
|
const object = {};
|
|
149
173
|
const routeSegments = routePattern.split("/");
|
|
150
|
-
const [pathWithoutQuery] = path.split("?");
|
|
151
|
-
const pathSegments = pathWithoutQuery.split("/");
|
|
174
|
+
const [pathWithoutQuery] = path.split("?");
|
|
175
|
+
const pathSegments = pathWithoutQuery.split("/");
|
|
152
176
|
|
|
153
177
|
if (routeSegments.length !== pathSegments.length) {
|
|
154
|
-
return null;
|
|
178
|
+
return null;
|
|
155
179
|
}
|
|
156
180
|
|
|
157
181
|
routeSegments.forEach((segment, index) => {
|
|
158
182
|
if (segment.startsWith(":")) {
|
|
159
|
-
const dynamicKey = segment.slice(1);
|
|
160
|
-
object[dynamicKey] = pathSegments[index];
|
|
183
|
+
const dynamicKey = segment.slice(1);
|
|
184
|
+
object[dynamicKey] = pathSegments[index];
|
|
161
185
|
}
|
|
162
186
|
});
|
|
163
187
|
|
|
164
188
|
return object;
|
|
165
|
-
}
|
|
189
|
+
}
|
|
166
190
|
|
|
167
191
|
async function parseBody(req) {
|
|
168
192
|
const contentType = req.headers.get("Content-Type");
|
package/src/handleRequest.js
CHANGED
|
@@ -10,7 +10,6 @@ export default async function handleRequest(req, url, diesel) {
|
|
|
10
10
|
// Early return if route or method is not found
|
|
11
11
|
if (!routeHandler || !routeHandler.handler) return responseNotFound(pathname);
|
|
12
12
|
if (routeHandler.method !== method) return responseMethodNotAllowed();
|
|
13
|
-
|
|
14
13
|
// If the route is dynamic, we only set routePattern if necessary
|
|
15
14
|
if (routeHandler.isDynamic) req.routePattern = routeHandler.path;
|
|
16
15
|
|
|
@@ -19,7 +18,7 @@ export default async function handleRequest(req, url, diesel) {
|
|
|
19
18
|
if (diesel.hasMiddleware) {
|
|
20
19
|
const middlewares = [
|
|
21
20
|
...diesel.globalMiddlewares,
|
|
22
|
-
...
|
|
21
|
+
...diesel.middlewares.get(pathname) || []
|
|
23
22
|
];
|
|
24
23
|
|
|
25
24
|
const middlewareResult = await executeMiddleware(middlewares, ctx);
|
package/src/server.js
CHANGED
|
@@ -1,132 +1,143 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import handleRequest from './handleRequest.js'
|
|
1
|
+
import Trie from "./trie.js";
|
|
2
|
+
import handleRequest from "./handleRequest.js";
|
|
4
3
|
|
|
5
4
|
class diesel {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
5
|
+
constructor() {
|
|
6
|
+
this.routes = new Map();
|
|
7
|
+
this.globalMiddlewares = [];
|
|
8
|
+
this.middlewares = new Map();
|
|
9
|
+
this.trie = new Trie();
|
|
10
|
+
this.hasMiddleware = false;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
compile() {
|
|
14
|
+
if (this.globalMiddlewares.length > 0) {
|
|
15
|
+
this.hasMiddleware = true;
|
|
12
16
|
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
17
|
+
for (const [path, middlewares] of this.middlewares.entries()) {
|
|
18
|
+
if (middlewares.length > 0) {
|
|
19
|
+
this.hasMiddleware = true;
|
|
20
|
+
break;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
listen(port, { sslCert = null, sslKey = null } = {}, callback) {
|
|
26
|
+
this.compile();
|
|
27
|
+
const options = {
|
|
28
|
+
port,
|
|
29
|
+
fetch: async (req) => {
|
|
30
|
+
const url = new URL(req.url);
|
|
31
|
+
try {
|
|
32
|
+
return await handleRequest(req, url, this);
|
|
33
|
+
} catch (error) {
|
|
34
|
+
return new Response("Internal Server Error", { status: 500 });
|
|
23
35
|
}
|
|
36
|
+
},
|
|
37
|
+
onClose() {
|
|
38
|
+
console.log("Server is shutting down...");
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
if (sslCert && sslKey) {
|
|
43
|
+
options.certFile = sslCert;
|
|
44
|
+
options.keyFile = sslKey;
|
|
45
|
+
}
|
|
46
|
+
const server = Bun.serve(options);
|
|
47
|
+
|
|
48
|
+
if (typeof callback === "function") {
|
|
49
|
+
return callback();
|
|
24
50
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
fetch: (req) => {
|
|
31
|
-
const url = new URL(req.url)
|
|
32
|
-
return handleRequest(req,url,this)
|
|
33
|
-
},
|
|
34
|
-
onClose() {
|
|
35
|
-
console.log("Server is shutting down...");
|
|
36
|
-
}
|
|
37
|
-
});
|
|
38
|
-
if (typeof callback === 'function') {
|
|
39
|
-
return callback();
|
|
40
|
-
}
|
|
41
|
-
console.log(`Server is running on http://localhost:${port}`);
|
|
42
|
-
return server;
|
|
51
|
+
|
|
52
|
+
if (sslCert && sslKey) {
|
|
53
|
+
console.log(`HTTPS server is running on https://localhost:${port}`);
|
|
54
|
+
} else {
|
|
55
|
+
console.log(`HTTP server is running on http://localhost:${port}`);
|
|
43
56
|
}
|
|
44
57
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
58
|
+
return server;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
register(pathPrefix, handlerInstance) {
|
|
62
|
+
const routeEntries = Object.entries(handlerInstance.trie.root.children);
|
|
63
|
+
// console.log(handlerInstance.trie.root);
|
|
64
|
+
handlerInstance.trie.root.subMiddlewares.forEach((middleware, path) => {
|
|
65
|
+
if (!this.middlewares.has(pathPrefix + path)) {
|
|
66
|
+
this.middlewares.set(pathPrefix + path, []);
|
|
67
|
+
}
|
|
68
|
+
if (!this.middlewares.get(pathPrefix + path).includes(...middleware)) {
|
|
69
|
+
this.middlewares.get(pathPrefix + path).push(...middleware);
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
for (const [routeKey, routeNode] of routeEntries) {
|
|
73
|
+
const fullpath = pathPrefix + routeNode?.path;
|
|
74
|
+
const routeHandler = routeNode.handler[0];
|
|
75
|
+
const httpMethod = routeNode.method[0];
|
|
76
|
+
this.trie.insert(fullpath, { handler: routeHandler, method: httpMethod });
|
|
63
77
|
}
|
|
78
|
+
handlerInstance.trie = new Trie();
|
|
79
|
+
}
|
|
64
80
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
const middlewareHandlers = handlers.slice(0, -1);
|
|
81
|
+
#addRoute(method, path, handlers) {
|
|
82
|
+
const middlewareHandlers = handlers.slice(0, -1);
|
|
68
83
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
}
|
|
77
|
-
})
|
|
78
|
-
} else {
|
|
79
|
-
if (!this.middlewares.get(path).includes(...middlewareHandlers)) {
|
|
80
|
-
this.middlewares.get(path).push(...middlewareHandlers);
|
|
81
|
-
}
|
|
84
|
+
if (!this.middlewares.has(path)) {
|
|
85
|
+
this.middlewares.set(path, []);
|
|
86
|
+
}
|
|
87
|
+
if (path === "/") {
|
|
88
|
+
middlewareHandlers.forEach((midlleware) => {
|
|
89
|
+
if (!this.globalMiddlewares.includes(midlleware)) {
|
|
90
|
+
this.globalMiddlewares.push(midlleware);
|
|
82
91
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
92
|
+
});
|
|
93
|
+
} else {
|
|
94
|
+
if (!this.middlewares.get(path).includes(...middlewareHandlers)) {
|
|
95
|
+
this.middlewares.get(path).push(...middlewareHandlers);
|
|
96
|
+
}
|
|
87
97
|
}
|
|
88
98
|
|
|
99
|
+
const handler = handlers[handlers.length - 1];
|
|
100
|
+
this.trie.insert(path, { handler, method });
|
|
101
|
+
}
|
|
89
102
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
}
|
|
96
|
-
// now it means it is path midl
|
|
97
|
-
const path = pathORHandler
|
|
98
|
-
if (!this.middlewares.has(path)) {
|
|
99
|
-
this.middlewares.set(path,[])
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
if(!this.middlewares.get(path).includes(handler)){
|
|
103
|
-
this.middlewares.get(path).push(handler)
|
|
104
|
-
}
|
|
103
|
+
use(pathORHandler, handler) {
|
|
104
|
+
if (typeof pathORHandler === "function") {
|
|
105
|
+
if (!this.globalMiddlewares.includes(pathORHandler)) {
|
|
106
|
+
return this.globalMiddlewares.push(pathORHandler);
|
|
107
|
+
}
|
|
105
108
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
+
// now it means it is path midl
|
|
110
|
+
const path = pathORHandler;
|
|
111
|
+
if (!this.middlewares.has(path)) {
|
|
112
|
+
this.middlewares.set(path, []);
|
|
109
113
|
}
|
|
110
114
|
|
|
111
|
-
|
|
112
|
-
|
|
115
|
+
if (!this.middlewares.get(path).includes(handler)) {
|
|
116
|
+
this.middlewares.get(path).push(handler);
|
|
113
117
|
}
|
|
118
|
+
}
|
|
114
119
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
120
|
+
get(path, ...handlers) {
|
|
121
|
+
return this.#addRoute("GET", path, handlers);
|
|
122
|
+
}
|
|
118
123
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
+
post(path, ...handlers) {
|
|
125
|
+
return this.#addRoute("POST", path, handlers);
|
|
126
|
+
}
|
|
124
127
|
|
|
125
|
-
|
|
126
|
-
|
|
128
|
+
put(path, ...handlers) {
|
|
129
|
+
return this.#addRoute("PUT", path, handlers);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
patch(path, ...handlers) {
|
|
133
|
+
if (handlers.length > 0) {
|
|
134
|
+
return this.#addRoute("PATCH", path, handlers);
|
|
127
135
|
}
|
|
136
|
+
}
|
|
128
137
|
|
|
138
|
+
delete(path, ...handlers) {
|
|
139
|
+
return this.#addRoute("DELETE", path, handlers);
|
|
140
|
+
}
|
|
129
141
|
}
|
|
130
142
|
|
|
131
|
-
|
|
132
|
-
export default diesel;
|
|
143
|
+
export default diesel;
|
package/src/trie.js
CHANGED
|
@@ -98,7 +98,13 @@ class TrieNode {
|
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
// Fallback if method is not found
|
|
101
|
-
return
|
|
101
|
+
return {
|
|
102
|
+
path: node.path,
|
|
103
|
+
handler: node.handler,
|
|
104
|
+
isDynamic: node.isDynamic,
|
|
105
|
+
pattern: node.pattern,
|
|
106
|
+
method: node.method[routeMethodIndex]
|
|
107
|
+
};
|
|
102
108
|
}
|
|
103
109
|
|
|
104
110
|
|