diesel-core 0.0.10 → 0.0.12
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/README.md +123 -30
- package/dist/ctx.d.ts +3 -0
- package/dist/ctx.js +1 -1
- package/dist/handleRequest.d.ts +3 -0
- package/dist/handleRequest.js +1 -1
- package/dist/main.d.ts +34 -0
- package/dist/main.js +1 -1
- package/dist/router.d.ts +12 -0
- package/dist/router.js +1 -1
- package/dist/trie.d.ts +31 -0
- package/dist/trie.js +1 -1
- package/dist/types.d.ts +117 -0
- package/dist/utils.d.ts +7 -0
- package/example/main.ts +52 -0
- package/example/package.json +1 -1
- package/example/tester.js +4 -3
- package/example/tsconfig.json +16 -0
- package/package.json +3 -2
- package/src/ctx.ts +24 -20
- package/src/handleRequest.ts +110 -36
- package/src/main.ts +164 -69
- package/src/router.ts +2 -2
- package/src/types.ts +53 -30
- package/src/utils.ts +73 -0
- package/test/README.md +15 -0
- package/test/bun.lockb +0 -0
- package/test/index.ts +5 -0
- package/test/package.json +14 -0
- package/test/tsconfig.json +27 -0
- package/tsconfig.json +4 -2
package/README.md
CHANGED
|
@@ -1,56 +1,149 @@
|
|
|
1
1
|
# DieselJS
|
|
2
2
|
|
|
3
|
-
**
|
|
3
|
+
**made only for bun***
|
|
4
4
|
|
|
5
|
+
**Diesel** is a simple and lightweight HTTP server library for Bun.js that provides you with complete control over your API routes and middleware. It is designed to be intuitive and efficient, allowing you to quickly set up a server, define routes, and optimize important paths for faster response times.
|
|
6
|
+
|
|
7
|
+
With built-in support for TypeScript, DieselJS ensures type safety and improved developer experience, making it easier to catch errors during development. Whether you are building a small application or a large API, DieselJS helps you manage your routes and middleware seamlessly.
|
|
5
8
|
|
|
6
|
-
## Installation
|
|
7
9
|
|
|
8
|
-
|
|
10
|
+
## Installation
|
|
11
|
+
Install diesel-core via bun | npm | yarn | pnpm
|
|
9
12
|
|
|
10
13
|
```bash
|
|
11
14
|
npm install diesel-core
|
|
15
|
+
```
|
|
16
|
+
```bash
|
|
17
|
+
bun add diesel-core
|
|
18
|
+
```
|
|
12
19
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const maya = new diesel();
|
|
17
|
-
const port = 3000;
|
|
18
|
-
|
|
19
|
-
// Middleware example
|
|
20
|
-
app.use(hello);
|
|
20
|
+
### Code Example
|
|
21
|
+
```javascript
|
|
22
|
+
import { Diesel } from "diesel-core"
|
|
21
23
|
|
|
24
|
+
const app = new Diesel()
|
|
25
|
+
const port = 3000
|
|
22
26
|
|
|
23
27
|
app.get("/", async (xl) => {
|
|
24
28
|
return xl.status(200).text("Hello world...!")
|
|
25
|
-
OR
|
|
26
|
-
return xl.text("Hello world!")
|
|
27
|
-
OR
|
|
28
|
-
return new Response("Hello world")
|
|
29
|
-
})
|
|
29
|
+
// OR
|
|
30
|
+
// return xl.text("Hello world!")
|
|
31
|
+
// OR
|
|
32
|
+
// return new Response("Hello world")
|
|
33
|
+
})
|
|
30
34
|
|
|
31
|
-
//
|
|
32
|
-
app.
|
|
33
|
-
|
|
35
|
+
// Start the server
|
|
36
|
+
app.listen(port, () => {
|
|
37
|
+
console.log(`diesel is running on port ${port}`)
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Using Hooks in DieselJS
|
|
43
|
+
|
|
44
|
+
DieselJS allows you to enhance your request handling by utilizing hooks at various stages of the request lifecycle. This gives you the flexibility to execute custom logic for logging, authentication, data manipulation, and more.
|
|
45
|
+
|
|
46
|
+
### Available Hooks
|
|
47
|
+
|
|
48
|
+
1. **onRequest**: Triggered when a request is received.
|
|
49
|
+
2. **preHandler**: Invoked just before the request handler executes.
|
|
50
|
+
3. **postHandler**: Executed after the request handler completes but before sending the response.
|
|
51
|
+
4. **onSend**: Called just before the response is sent to the client.
|
|
52
|
+
|
|
53
|
+
### How to Define Hooks
|
|
54
|
+
|
|
55
|
+
To define hooks in your DieselJS application, you can add them directly to your `Diesel` instance. Here's how to set up and use each hook:
|
|
56
|
+
|
|
57
|
+
### Example Usage
|
|
58
|
+
|
|
59
|
+
```javascript
|
|
60
|
+
// Define an onRequest hook
|
|
61
|
+
app.addHooks("onRequest",(xl) =>{
|
|
62
|
+
console.log(`Request received: ${xl.req.method} ${xl.req.url}`);
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
// Define a preHandler hook
|
|
66
|
+
app.addHooks("preHandler",(xl) =>{
|
|
67
|
+
// Check for authentication token
|
|
68
|
+
const authToken = ctx.req.headers.get("Authorization");
|
|
69
|
+
if (!authToken) {
|
|
70
|
+
return new Response("Unauthorized", { status: 401 });
|
|
71
|
+
}
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
// Define a postHandler hook
|
|
75
|
+
app.addHooks('postHandler', async (ctx) => {
|
|
76
|
+
console.log(`Response sent for: ${ctx.req.url}`);
|
|
34
77
|
});
|
|
35
78
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
79
|
+
// Define an onSend hook
|
|
80
|
+
app.addHooks('onSend',async (ctx, result) => {
|
|
81
|
+
console.log(`Sending response with status: ${result.status}`);
|
|
82
|
+
return result; // You can modify the response here if needed
|
|
39
83
|
});
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
# Middleware example
|
|
87
|
+
|
|
88
|
+
```javascript
|
|
89
|
+
function h (xl) => {
|
|
90
|
+
return xl.status(200).text("hi im from middleware")
|
|
91
|
+
}
|
|
92
|
+
app.use(hello)
|
|
93
|
+
|
|
94
|
+
// path middleware example
|
|
95
|
+
app.use("/user",authJWT)
|
|
96
|
+
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
# set cookies
|
|
100
|
+
|
|
101
|
+
```javascript
|
|
102
|
+
app.get("/set-cookie", async(xl) => {
|
|
103
|
+
const user = {
|
|
104
|
+
name: "pk",
|
|
105
|
+
age: 22,
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const accessToken = jwt.sign(user, secret, { expiresIn: "1d" })
|
|
109
|
+
|
|
110
|
+
const refreshToken = jwt.sign(user, secret ,{ expiresIn: "10d" })
|
|
111
|
+
|
|
112
|
+
const options = {
|
|
113
|
+
httpOnly: true,
|
|
114
|
+
secure: true,
|
|
115
|
+
maxAge: 24 * 60 * 60 * 1000,
|
|
116
|
+
sameSite: "Strict",
|
|
117
|
+
path: "/",
|
|
118
|
+
}
|
|
40
119
|
|
|
120
|
+
await xl.cookie("accessToken", accessToken, options)
|
|
41
121
|
|
|
122
|
+
await xl.cookie("refreshToken", refreshToken, options)
|
|
123
|
+
|
|
124
|
+
return xl.json({msg:"setting cookies"})
|
|
125
|
+
})
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
# Render a HTML page
|
|
129
|
+
```javascript
|
|
130
|
+
app.get("/render",async (xl) => {
|
|
131
|
+
return xl.html(`${import.meta.dir}/index.html`)
|
|
132
|
+
})
|
|
133
|
+
```
|
|
134
|
+
# redirect
|
|
135
|
+
```javascript
|
|
42
136
|
app.get("/redirect",(xl) => {
|
|
43
137
|
return xl.redirect("/");
|
|
44
|
-
})
|
|
45
|
-
|
|
138
|
+
})
|
|
139
|
+
```
|
|
140
|
+
# get params
|
|
141
|
+
```javascript
|
|
46
142
|
app.get("/hello/:id",(xl) => {
|
|
47
143
|
const id = xl.getParams("id")
|
|
144
|
+
const query = xl.getQuery() // you can pass query name also , you wanna get
|
|
48
145
|
return xl.json({ msg: "Hello", id });
|
|
49
|
-
})
|
|
50
|
-
|
|
146
|
+
})
|
|
147
|
+
```
|
|
51
148
|
|
|
52
|
-
// Start the server
|
|
53
|
-
app.listen(port, () => {
|
|
54
|
-
console.log(`diesel is running on port ${port}`);
|
|
55
|
-
});
|
|
56
149
|
|
package/dist/ctx.d.ts
ADDED
package/dist/ctx.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
function $(E,F,I){let G=new Headers,R={},L=!1,U=null,X=null,Y=null,Z,_=200;return{req:E,server:F,url:I,next:()=>{},status(w){return _=w,this},getIP(){return this.server.requestIP(this.req)},async body(){if(!Z)Z=await O(E);if(Z.error)return new Response(JSON.stringify({error:Z.error}),{status:400});return Z},setHeader(w,z){return G.set(w,z),this},set(w,z){return R[w]=z,this},get(w){return R[w]||null},setAuth(w){return L=w,this},getAuth(){return L},text(w,z){return new Response(w,{status:z??_,headers:G})},json(w,z){return new Response(JSON.stringify(w),{status:z??_,headers:G})},html(w,z){return new Response(Bun.file(w),{status:z??_,headers:G})},file(w,z){return new Response(Bun.file(w),{status:z??_,headers:G})},redirect(w,z){return G.set("Location",w),new Response(null,{status:z??302,headers:G})},getParams(w){if(!Y)Y=W(E?.routePattern,I?.pathname);return w?Y[w]||null:Y},getQuery(w){if(!U)U=Object.fromEntries(I.searchParams);return w?U[w]||null:U},async cookie(w,z,J={}){let M=`${encodeURIComponent(w)}=${encodeURIComponent(z)}`;if(J.maxAge)M+=`; Max-Age=${J.maxAge}`;if(J.expires)M+=`; Expires=${J.expires.toUTCString()}`;if(J.path)M+=`; Path=${J.path}`;if(J.domain)M+=`; Domain=${J.domain}`;if(J.secure)M+="; Secure";if(J.httpOnly)M+="; HttpOnly";if(J.sameSite)M+=`; SameSite=${J.sameSite}`;return G?.append("Set-Cookie",M),this},async getCookie(w){if(!X){let z=E.headers.get("cookie");if(z)X=await K(z)}return w?X[w]||null:X}}}async function K(E){let F={};if(!E)return F;return E.split(";").forEach((G)=>{let[R,L]=G?.trim()?.split("=");if(R&&L)F[R.trim()]=L.split(" ")[0].trim()}),F}function W(E,F){let I={},G=E.split("/"),[R]=F.split("?"),L=R.split("/");if(G.length!==L.length)return null;return G.forEach((U,X)=>{if(U.startsWith(":")){let Y=U.slice(1);I[Y]=L[X]}}),I}async function O(E){let F=E.headers.get("Content-Type")||"";if(!F)return{};try{if(F.startsWith("application/json"))return await E.json();if(F.startsWith("application/x-www-form-urlencoded")){let I=await E.text();return Object.fromEntries(new URLSearchParams(I))}if(F.startsWith("multipart/form-data")){let I=await E.formData();return A(I)}return{error:"Unknown request body type"}}catch(I){return{error:"Invalid request body format"}}}function A(E){let F={};for(let[I,G]of E.entries())F[I]=G;return F}export{$ as default};
|
package/dist/handleRequest.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
function W(G,E,I){let z=new Headers,J={},X=!1,L=null,Z=null,Y=null,K,M=200;return{req:G,server:E,url:I,next:()=>{},status(F){return M=F,this},getIP(){return this.server.requestIP(this.req)},async body(){if(!K)K=await j(G);if(K.error)return new Response(JSON.stringify({error:K.error}),{status:400});return K},setHeader(F,U){return z.set(F,U),this},set(F,U){return J[F]=U,this},get(F){return J[F]||null},setAuth(F){return X=F,this},getAuth(){return X},text(F,U){return new Response(F,{status:U??M,headers:z})},json(F,U){return new Response(JSON.stringify(F),{status:U??M,headers:z})},html(F,U){return new Response(Bun.file(F),{status:U??M,headers:z})},file(F,U){return new Response(Bun.file(F),{status:U??M,headers:z})},redirect(F,U){return z.set("Location",F),new Response(null,{status:U??302,headers:z})},getParams(F){if(!Y)Y=V(G?.routePattern,I?.pathname);return F?Y[F]||null:Y},getQuery(F){if(!L)L=Object.fromEntries(I.searchParams);return F?L[F]||null:L},async cookie(F,U,_={}){let $=`${encodeURIComponent(F)}=${encodeURIComponent(U)}`;if(_.maxAge)$+=`; Max-Age=${_.maxAge}`;if(_.expires)$+=`; Expires=${_.expires.toUTCString()}`;if(_.path)$+=`; Path=${_.path}`;if(_.domain)$+=`; Domain=${_.domain}`;if(_.secure)$+="; Secure";if(_.httpOnly)$+="; HttpOnly";if(_.sameSite)$+=`; SameSite=${_.sameSite}`;return z?.append("Set-Cookie",$),this},async getCookie(F){if(!Z){let U=G.headers.get("cookie");if(U)Z=await A(U)}return F?Z[F]||null:Z}}}async function A(G){let E={};if(!G)return E;return G.split(";").forEach((z)=>{let[J,X]=z?.trim()?.split("=");if(J&&X)E[J.trim()]=X.split(" ")[0].trim()}),E}function V(G,E){let I={},z=G.split("/"),[J]=E.split("?"),X=J.split("/");if(z.length!==X.length)return null;return z.forEach((L,Z)=>{if(L.startsWith(":")){let Y=L.slice(1);I[Y]=X[Z]}}),I}async function j(G){let E=G.headers.get("Content-Type")||"";if(!E)return{};try{if(E.startsWith("application/json"))return await G.json();if(E.startsWith("application/x-www-form-urlencoded")){let I=await G.text();return Object.fromEntries(new URLSearchParams(I))}if(E.startsWith("multipart/form-data")){let I=await G.formData();return D(I)}return{error:"Unknown request body type"}}catch(I){return{error:"Invalid request body format"}}}function D(G){let E={};for(let[I,z]of G.entries())E[I]=z;return E}async function Q(G,E,I,z){let J=W(G,E,I),X=z.trie.search(I.pathname,G.method);if(!X||!X.handler)return new Response(`Route not found for ${I.pathname}`,{status:404});if(X.method!==G.method)return new Response("Method not allowed",{status:405});if(X.isDynamic)G.routePattern=X.path;if(z.corsConfig){let L=await T(G,J,z.corsConfig);if(L)return L}if(z.hasOnReqHook&&z.hooks.onRequest)z.hooks.onRequest(J,E);if(z.filters.length>0){let L=G.routePattern??I.pathname;if(z.filters.includes(L)===!1)if(z.filterFunction){let Y=await z?.filterFunction(J);if(Y)return Y}else return new Response(JSON.stringify({message:"Authentication required"}),{status:400})}if(z.hasMiddleware){let L=[...z.globalMiddlewares,...z.middlewares.get(I.pathname)||[]];for(let Z of L){let Y=await Z(J,E);if(Y)return Y}}if(z.hasPreHandlerHook&&z.hooks.preHandler){let L=await z.hooks.preHandler(J);if(L)return L}try{let L=await X.handler(J);if(z.hasPostHandlerHook&&z.hooks.postHandler)await z.hooks.postHandler(J);if(z.hasOnSendHook&&z.hooks.onSend){let Z=await z.hooks.onSend(J,L);if(Z)return Z}return L??new Response("No response from handler",{status:204})}catch(L){return new Response("Internal Server Error",{status:500})}}async function T(G,E,I={}){let z=G.headers.get("origin")??"*",J=I?.origin,X=I?.allowedHeaders??["Content-Type","Authorization"],L=I?.methods??["GET","POST","PUT","DELETE","OPTIONS"],Z=I?.credentials??!1,Y=I?.exposedHeaders??[];if(E.setHeader("Access-Control-Allow-Methods",L),E.setHeader("Access-Control-Allow-Headers",X),E.setHeader("Access-Control-Allow-Credentials",Z),Y.length)E.setHeader("Access-Control-Expose-Headers",Y);if(J==="*")E.setHeader("Access-Control-Allow-Origin","*");else if(Array.isArray(J))if(z&&J.includes(z))E.setHeader("Access-Control-Allow-Origin",z);else if(J.includes("*"))E.setHeader("Access-Control-Allow-Origin","*");else return E.status(403).json({message:"CORS not allowed"});else if(typeof J==="string")if(z===J)E.setHeader("Access-Control-Allow-Origin",z);else return E.status(403).json({message:"CORS not allowed"});else return E.status(403).json({message:"CORS not allowed"});if(E.setHeader("Access-Control-Allow-Origin",z),G.method==="OPTIONS")return E.setHeader("Access-Control-Max-Age","86400"),E.status(204).text("");return null}export{Q as default};
|
package/dist/main.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import Trie from "./trie.js";
|
|
2
|
+
import rateLimit from "./utils.js";
|
|
3
|
+
import { corsT, FilterMethods, HookFunction, HookType, middlewareFunc, type handlerFunction, type Hooks, type listenCalllBackType } from "./types.js";
|
|
4
|
+
import { Server } from "bun";
|
|
5
|
+
declare class Diesel {
|
|
6
|
+
#private;
|
|
7
|
+
routes: string[] | undefined;
|
|
8
|
+
globalMiddlewares: middlewareFunc[];
|
|
9
|
+
middlewares: Map<string, middlewareFunc[]>;
|
|
10
|
+
trie: Trie;
|
|
11
|
+
hasOnReqHook: boolean;
|
|
12
|
+
hasMiddleware: boolean;
|
|
13
|
+
hasPreHandlerHook: boolean;
|
|
14
|
+
hasPostHandlerHook: boolean;
|
|
15
|
+
hasOnSendHook: boolean;
|
|
16
|
+
hooks: Hooks;
|
|
17
|
+
corsConfig: corsT;
|
|
18
|
+
filters: string[];
|
|
19
|
+
filterFunction: middlewareFunc | null;
|
|
20
|
+
constructor();
|
|
21
|
+
filter(): FilterMethods;
|
|
22
|
+
cors(corsConfig: corsT): void;
|
|
23
|
+
addHooks(typeOfHook: HookType, fnc: HookFunction): void;
|
|
24
|
+
compile(): void;
|
|
25
|
+
listen(port: number, callback?: listenCalllBackType, { sslCert, sslKey }?: any): Server | void;
|
|
26
|
+
register(pathPrefix: string, handlerInstance: any): void;
|
|
27
|
+
use(pathORHandler?: string | middlewareFunc, handler?: middlewareFunc): void;
|
|
28
|
+
get(path: string, ...handlers: handlerFunction[]): this;
|
|
29
|
+
post(path: string, ...handlers: handlerFunction[]): this;
|
|
30
|
+
put(path: string, ...handlers: handlerFunction[]): this;
|
|
31
|
+
patch(path: string, ...handlers: handlerFunction[]): this;
|
|
32
|
+
delete(path: any, ...handlers: handlerFunction[]): this;
|
|
33
|
+
}
|
|
34
|
+
export { Diesel, rateLimit, };
|
package/dist/main.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
class
|
|
1
|
+
class K{children;isEndOfWord;handler;isDynamic;pattern;path;method;subMiddlewares;constructor(){this.children={},this.isEndOfWord=!1,this.handler=[],this.isDynamic=!1,this.pattern="",this.path="",this.method=[],this.subMiddlewares=new Map}}class Q{root;constructor(){this.root=new K}insert(z,F){let G=this.root,J=z.split("/").filter(Boolean);if(z==="/"){G.isEndOfWord=!0,G.handler.push(F.handler),G.path=z,G.method.push(F.method);return}for(let U of J){let X=!1,Y=U;if(U.startsWith(":"))X=!0,Y=":";if(!G.children[Y])G.children[Y]=new K;G=G.children[Y],G.isDynamic=X,G.pattern=U}G.isEndOfWord=!0,G.method.push(F.method),G.handler.push(F.handler),G.path=z}search(z,F){let G=this.root,J=z.split("/").filter(Boolean);for(let X of J){let Y=X;if(!G.children[Y])if(G.children[":"])G=G.children[":"];else return null;else G=G.children[Y]}let U=G.method.indexOf(F);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]}}}function M(z,F,G){let J=new Headers,U={},X=!1,Y=null,$=null,_=null,A,V=200;return{req:z,server:F,url:G,next:()=>{},status(Z){return V=Z,this},getIP(){return this.server.requestIP(this.req)},async body(){if(!A)A=await T(z);if(A.error)return new Response(JSON.stringify({error:A.error}),{status:400});return A},setHeader(Z,E){return J.set(Z,E),this},set(Z,E){return U[Z]=E,this},get(Z){return U[Z]||null},setAuth(Z){return X=Z,this},getAuth(){return X},text(Z,E){return new Response(Z,{status:E??V,headers:J})},json(Z,E){return new Response(JSON.stringify(Z),{status:E??V,headers:J})},html(Z,E){return new Response(Bun.file(Z),{status:E??V,headers:J})},file(Z,E){return new Response(Bun.file(Z),{status:E??V,headers:J})},redirect(Z,E){return J.set("Location",Z),new Response(null,{status:E??302,headers:J})},getParams(Z){if(!_)_=N(z?.routePattern,G?.pathname);return Z?_[Z]||null:_},getQuery(Z){if(!Y)Y=Object.fromEntries(G.searchParams);return Z?Y[Z]||null:Y},async cookie(Z,E,L={}){let W=`${encodeURIComponent(Z)}=${encodeURIComponent(E)}`;if(L.maxAge)W+=`; Max-Age=${L.maxAge}`;if(L.expires)W+=`; Expires=${L.expires.toUTCString()}`;if(L.path)W+=`; Path=${L.path}`;if(L.domain)W+=`; Domain=${L.domain}`;if(L.secure)W+="; Secure";if(L.httpOnly)W+="; HttpOnly";if(L.sameSite)W+=`; SameSite=${L.sameSite}`;return J?.append("Set-Cookie",W),this},async getCookie(Z){if(!$){let E=z.headers.get("cookie");if(E)$=await D(E)}return Z?$[Z]||null:$}}}async function D(z){let F={};if(!z)return F;return z.split(";").forEach((J)=>{let[U,X]=J?.trim()?.split("=");if(U&&X)F[U.trim()]=X.split(" ")[0].trim()}),F}function N(z,F){let G={},J=z.split("/"),[U]=F.split("?"),X=U.split("/");if(J.length!==X.length)return null;return J.forEach((Y,$)=>{if(Y.startsWith(":")){let _=Y.slice(1);G[_]=X[$]}}),G}async function T(z){let F=z.headers.get("Content-Type")||"";if(!F)return{};try{if(F.startsWith("application/json"))return await z.json();if(F.startsWith("application/x-www-form-urlencoded")){let G=await z.text();return Object.fromEntries(new URLSearchParams(G))}if(F.startsWith("multipart/form-data")){let G=await z.formData();return b(G)}return{error:"Unknown request body type"}}catch(G){return{error:"Invalid request body format"}}}function b(z){let F={};for(let[G,J]of z.entries())F[G]=J;return F}async function B(z,F,G,J){let U=M(z,F,G),X=J.trie.search(G.pathname,z.method);if(!X||!X.handler)return new Response(`Route not found for ${G.pathname}`,{status:404});if(X.method!==z.method)return new Response("Method not allowed",{status:405});if(X.isDynamic)z.routePattern=X.path;if(J.corsConfig){let Y=await C(z,U,J.corsConfig);if(Y)return Y}if(J.hasOnReqHook&&J.hooks.onRequest)J.hooks.onRequest(U,F);if(J.filters.length>0){let Y=z.routePattern??G.pathname;if(J.filters.includes(Y)===!1)if(J.filterFunction){let _=await J?.filterFunction(U);if(_)return _}else return new Response(JSON.stringify({message:"Authentication required"}),{status:400})}if(J.hasMiddleware){let Y=[...J.globalMiddlewares,...J.middlewares.get(G.pathname)||[]];for(let $ of Y){let _=await $(U,F);if(_)return _}}if(J.hasPreHandlerHook&&J.hooks.preHandler){let Y=await J.hooks.preHandler(U);if(Y)return Y}try{let Y=await X.handler(U);if(J.hasPostHandlerHook&&J.hooks.postHandler)await J.hooks.postHandler(U);if(J.hasOnSendHook&&J.hooks.onSend){let $=await J.hooks.onSend(U,Y);if($)return $}return Y??new Response("No response from handler",{status:204})}catch(Y){return new Response("Internal Server Error",{status:500})}}async function C(z,F,G={}){let J=z.headers.get("origin")??"*",U=G?.origin,X=G?.allowedHeaders??["Content-Type","Authorization"],Y=G?.methods??["GET","POST","PUT","DELETE","OPTIONS"],$=G?.credentials??!1,_=G?.exposedHeaders??[];if(F.setHeader("Access-Control-Allow-Methods",Y),F.setHeader("Access-Control-Allow-Headers",X),F.setHeader("Access-Control-Allow-Credentials",$),_.length)F.setHeader("Access-Control-Expose-Headers",_);if(U==="*")F.setHeader("Access-Control-Allow-Origin","*");else if(Array.isArray(U))if(J&&U.includes(J))F.setHeader("Access-Control-Allow-Origin",J);else if(U.includes("*"))F.setHeader("Access-Control-Allow-Origin","*");else return F.status(403).json({message:"CORS not allowed"});else if(typeof U==="string")if(J===U)F.setHeader("Access-Control-Allow-Origin",J);else return F.status(403).json({message:"CORS not allowed"});else return F.status(403).json({message:"CORS not allowed"});if(F.setHeader("Access-Control-Allow-Origin",J),z.method==="OPTIONS")return F.setHeader("Access-Control-Max-Age","86400"),F.status(204).text("");return null}function j(z){let{time:F=60000,max:G=100,message:J="Rate limit exceeded. Please try again later."}=z,U=new Map;return(X)=>{let Y=new Date,$=X.getIP().address;if(!U.has($))U.set($,{count:0,startTime:Y});let _=U.get($);if(_)if(Y-_.startTime>F)_.count=1,_.startTime=Y;else _.count++;if(_&&_.count>G)return X.status(429).json({error:J});X.next()}}class v{routes;globalMiddlewares;middlewares;trie;hasOnReqHook;hasMiddleware;hasPreHandlerHook;hasPostHandlerHook;hasOnSendHook;hooks;corsConfig;filters;filterFunction;constructor(){this.routes=[],this.filters=[],this.filterFunction=null,this.globalMiddlewares=[],this.middlewares=new Map,this.trie=new Q,this.corsConfig=null,this.hasMiddleware=!1,this.hasOnReqHook=!1,this.hasPreHandlerHook=!1,this.hasPostHandlerHook=!1,this.hasOnSendHook=!1,this.hooks={onRequest:null,preHandler:null,postHandler:null,onSend:null,onError:null,onClose:null}}filter(){return{routeMatcher:(...z)=>{return this.routes=z.sort(),this.filter()},permitAll:()=>{for(let z of this?.routes)this.filters.push(z);return this.filter()},require:(z)=>{if(!z||typeof z!=="function")return new Response(JSON.stringify({message:"Authentication required"}),{status:400});this.filterFunction=z}}}cors(z){this.corsConfig=z}addHooks(z,F){if(typeof z!=="string")throw new Error("hookName must be a string");if(typeof F!=="function")throw new Error("callback must be a instance of function");if(this.hooks.hasOwnProperty(z))this.hooks[z]=F;else throw new Error(`Unknown hook type: ${z}`)}compile(){if(this.globalMiddlewares.length>0)this.hasMiddleware=!0;for(let[z,F]of this.middlewares.entries())if(F.length>0){this.hasMiddleware=!0;break}if(this.hooks.onRequest)this.hasOnReqHook=!0;if(this.hooks.preHandler)this.hasPreHandlerHook=!0;if(this.hooks.postHandler)this.hasPostHandlerHook=!0;if(this.hooks.onSend)this.hasOnSendHook=!0}listen(z,F,{sslCert:G=null,sslKey:J=null}={}){if(typeof Bun==="undefined")throw new Error(".listen() is designed to run on Bun only...");if(typeof z!=="number")throw new Error("Port must be a numeric value");this.compile();let U=this,X={port:z,fetch:async($,_)=>{let A=new URL($.url);try{return await B($,_,A,this)}catch(V){return new Response("Internal Server Error",{status:500})}},onClose(){console.log("Server is shutting down...")}};if(G&&J)X.certFile=G,X.keyFile=J;let Y=Bun.serve(X);if(typeof F==="function")return F();if(G&&J)console.log(`HTTPS server is running on https://localhost:${z}`);else console.log(`HTTP server is running on http://localhost:${z}`);return Y}register(z,F){if(typeof z!=="string")throw new Error("path must be a string");if(typeof F!=="object")throw new Error("handler parameter should be a instance of router object",F);let G=Object.entries(F.trie.root.children);F.trie.root.subMiddlewares.forEach((J,U)=>{if(!this.middlewares.has(z+U))this.middlewares.set(z+U,[]);J?.forEach((X)=>{if(!this.middlewares.get(z+U)?.includes(X))this.middlewares.get(z+U)?.push(X)})});for(let[J,U]of G){let X=z+U?.path,Y=U.handler[0],$=U.method[0];this.trie.insert(X,{handler:Y,method:$})}F.trie=new Q}#z(z,F,G){if(typeof F!=="string")throw new Error("Path must be a string type");if(typeof z!=="string")throw new Error("method must be a string type");let J=G.slice(0,-1),U=G[G.length-1];if(!this.middlewares.has(F))this.middlewares.set(F,[]);J.forEach((X)=>{if(F==="/"){if(!this.globalMiddlewares.includes(X))this.globalMiddlewares.push(X)}else if(!this.middlewares.get(F)?.includes(X))this.middlewares.get(F)?.push(X)}),this.trie.insert(F,{handler:U,method:z})}use(z,F){if(typeof z==="function"){if(!this.globalMiddlewares.includes(z))this.globalMiddlewares.push(z);return}let G=z;if(!this.middlewares.has(G))this.middlewares.set(G,[]);if(F){if(!this.middlewares.get(G)?.includes(F))this.middlewares.get(G)?.push(F)}}get(z,...F){return this.#z("GET",z,F),this}post(z,...F){return this.#z("POST",z,F),this}put(z,...F){return this.#z("PUT",z,F),this}patch(z,...F){return this.#z("PATCH",z,F),this}delete(z,...F){return this.#z("DELETE",z,F),this}}export{j as rateLimit,v as Diesel};
|
package/dist/router.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Diesel } from "./main";
|
|
2
|
+
import type { handlerFunction } from "./types";
|
|
3
|
+
declare class Router extends Diesel {
|
|
4
|
+
#private;
|
|
5
|
+
constructor();
|
|
6
|
+
get(path: string, ...handlers: handlerFunction[]): this;
|
|
7
|
+
post(path: string, ...handlers: handlerFunction[]): this;
|
|
8
|
+
put(path: string, ...handlers: handlerFunction[]): this;
|
|
9
|
+
patch(path: string, ...handlers: handlerFunction[]): this;
|
|
10
|
+
delete(path: string, ...handlers: handlerFunction[]): this;
|
|
11
|
+
}
|
|
12
|
+
export default Router;
|
package/dist/router.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
class Q{children;isEndOfWord;handler;isDynamic;pattern;path;method;subMiddlewares;constructor(){this.children={},this.isEndOfWord=!1,this.handler=[],this.isDynamic=!1,this.pattern="",this.path="",this.method=[],this.subMiddlewares=new Map}}class V{root;constructor(){this.root=new Q}insert(G,F){let z=this.root;const U=G.split("/").filter(Boolean);if(G==="/"){z.isEndOfWord=!0,z.handler.push(F.handler),z.path=G,z.method.push(F.method);return}for(let J of U){let L=!1,Y=J;if(J.startsWith(":"))L=!0,Y=":";if(!z.children[Y])z.children[Y]=new Q;z=z.children[Y],z.isDynamic=L,z.pattern=J}z.isEndOfWord=!0,z.method.push(F.method),z.handler.push(F.handler),z.path=G}search(G,F){let z=this.root;const U=G.split("/").filter(Boolean);for(let L of U){let Y=L;if(!z.children[Y])if(z.children[":"])z=z.children[":"];else return null;else z=z.children[Y]}let J=z.method.indexOf(F);if(J!==-1)return{path:z.path,handler:z.handler[J],isDynamic:z.isDynamic,pattern:z.pattern,method:z.method[J]};return{path:z.path,handler:z.handler,isDynamic:z.isDynamic,pattern:z.pattern,method:z.method[J]}}}async function T(G){const F={};if(!G)return F;return G.split(";").forEach((U)=>{const[J,L]=U?.trim()?.split("=");if(J&&L)F[J.trim()]=L.split(" ")[0].trim()}),F}function b(G,F){const z={},U=G.split("/"),[J]=F.split("?"),L=J.split("/");if(U.length!==L.length)return null;return U.forEach((Y,$)=>{if(Y.startsWith(":")){const W=Y.slice(1);z[W]=L[$]}}),z}async function N(G){const F=G.headers.get("Content-Type")||"";if(!F)return{};try{if(F.startsWith("application/json"))return await G.json();if(F.startsWith("application/x-www-form-urlencoded")){const z=await G.text();return Object.fromEntries(new URLSearchParams(z))}if(F.startsWith("multipart/form-data")){const z=await G.formData();return I(z)}return{error:"Unknown request body type"}}catch(z){return{error:"Invalid request body format"}}}function I(G){const F={};for(let[z,U]of G.entries())F[z]=U;return F}function B(G,F){let z=new Headers,U={},J=!1,L=null,Y=null,$=null,W,E=200;return{req:G,url:F,next:()=>{},status(X){return E=X,this},async body(){if(!W)W=await N(G);if(W.error)return new Response(JSON.stringify({error:W.error}),{status:400});return W},setHeader(X,Z){return z.set(X,Z),this},set(X,Z){return U[X]=Z,this},get(X){return U[X]||null},setAuth(X){return J=X,this},getAuth(){return J},text(X,Z){return new Response(X,{status:Z??E,headers:z})},json(X,Z){return new Response(JSON.stringify(X),{status:Z??E,headers:z})},html(X,Z){return new Response(Bun.file(X),{status:Z??E,headers:z})},file(X,Z){return new Response(Bun.file(X),{status:Z??E,headers:z})},redirect(X,Z){return z.set("Location",X),new Response(null,{status:Z??302,headers:z})},getParams(X){if(!$)$=b(G?.routePattern,F?.pathname);return X?$[X]||null:$},getQuery(X){if(!L)L=Object.fromEntries(F.searchParams);return X?L[X]||null:L},async cookie(X,Z,_={}){let A=`${encodeURIComponent(X)}=${encodeURIComponent(Z)}`;if(_.maxAge)A+=`; Max-Age=${_.maxAge}`;if(_.expires)A+=`; Expires=${_.expires.toUTCString()}`;if(_.path)A+=`; Path=${_.path}`;if(_.domain)A+=`; Domain=${_.domain}`;if(_.secure)A+="; Secure";if(_.httpOnly)A+="; HttpOnly";if(_.sameSite)A+=`; SameSite=${_.sameSite}`;return z?.append("Set-Cookie",A),this},async getCookie(X){if(!Y){const Z=G.headers.get("cookie");if(Z)Y=await T(Z)}return X?Y[X]||null:Y}}}async function C(G,F){for(let z of G){const U=await z(F);if(U)return U}}var K={};async function j(G,F,z){const U=B(G,F);if(z.hasOnReqHook)await z.hooks.onRequest(U);if(z.hasMiddleware){const L=[...z.globalMiddlewares,...z.middlewares.get(F.pathname)||[]],Y=await C(L,U);if(Y)return Y}let J;if(K[F.pathname+G.method])J=K[F.pathname+G.method];else J=z.trie.search(F.pathname,G.method),K[F.pathname+G.method]=J;if(!J||!J.handler)return new Response(`Route not found for ${F.pathname}`,{status:404});if(J.method!==G.method)return new Response("Method not allowed",{status:405});if(J.isDynamic)G.routePattern=J.path;if(z.hasPreHandlerHook){const L=await z.hooks.preHandler(U);if(L)return L}try{const L=await J.handler(U);if(z.hasPostHandlerHook)await z.hooks.postHandler(U);if(z.hasOnSendHook){const Y=await z.hooks.onSend(L,U);if(Y)return Y}return L??new Response("No response from handler",{status:204})}catch(L){return new Response("Internal Server Error",{status:500})}}class D{routes;globalMiddlewares;middlewares;trie;hasOnReqHook;hasMiddleware;hasPreHandlerHook;hasPostHandlerHook;hasOnSendHook;hooks;constructor(){this.routes=new Map,this.globalMiddlewares=[],this.middlewares=new Map,this.trie=new V,this.hasMiddleware=!1,this.hasOnReqHook=!1,this.hasPreHandlerHook=!1,this.hasPostHandlerHook=!1,this.hasOnSendHook=!1,this.hooks={onRequest:null,preHandler:null,postHandler:null,onSend:null,onError:null,onClose:null}}addHooks(G,F){if(typeof G!=="string")throw new Error("hookName must be a string");if(typeof F!=="function")throw new Error("callback must be a instance of function");if(this.hooks.hasOwnProperty(G))this.hooks[G]=F;else throw new Error(`Unknown hook type: ${G}`)}compile(){if(this.globalMiddlewares.length>0)this.hasMiddleware=!0;for(let[G,F]of this.middlewares.entries())if(F.length>0){this.hasMiddleware=!0;break}if(this.hooks.onRequest)this.hasOnReqHook=!0;if(this.hooks.preHandler)this.hasPreHandlerHook=!0;if(this.hooks.postHandler)this.hasPostHandlerHook=!0;if(this.hooks.onSend)this.hasOnSendHook=!0}listen(G,F,{sslCert:z=null,sslKey:U=null}={}){if(typeof Bun==="undefined")throw new Error(".listen() is designed to run on Bun only...");if(typeof G!=="number")throw new Error("Port must be a numeric value");this.compile();const J={port:G,fetch:async(Y)=>{const $=new URL(Y.url);try{return await j(Y,$,this)}catch(W){return new Response("Internal Server Error",{status:500})}},onClose(){console.log("Server is shutting down...")}};if(z&&U)J.certFile=z,J.keyFile=U;const L=Bun.serve(J);if(typeof F==="function")return F();if(z&&U)console.log(`HTTPS server is running on https://localhost:${G}`);else console.log(`HTTP server is running on http://localhost:${G}`);return L}register(G,F){if(typeof G!=="string")throw new Error("path must be a string");if(typeof F!=="object")throw new Error("handler parameter should be a instance of router object",F);const z=Object.entries(F.trie.root.children);F.trie.root.subMiddlewares.forEach((U,J)=>{if(!this.middlewares.has(G+J))this.middlewares.set(G+J,[]);U?.forEach((L)=>{if(!this.middlewares.get(G+J)?.includes(L))this.middlewares.get(G+J)?.push(L)})});for(let[U,J]of z){const L=G+J?.path,Y=J.handler[0],$=J.method[0];this.trie.insert(L,{handler:Y,method:$})}F.trie=new V}#z(G,F,z){if(typeof F!=="string")throw new Error("Path must be a string type");if(typeof G!=="string")throw new Error("method must be a string type");const U=z.slice(0,-1),J=z[z.length-1];if(!this.middlewares.has(F))this.middlewares.set(F,[]);U.forEach((L)=>{if(F==="/"){if(!this.globalMiddlewares.includes(L))this.globalMiddlewares.push(L)}else if(!this.middlewares.get(F)?.includes(L))this.middlewares.get(F)?.push(L)}),this.trie.insert(F,{handler:J,method:G})}use(G,F){if(typeof G==="function"){if(!this.globalMiddlewares.includes(G))return this.globalMiddlewares.push(G)}const z=G;if(!this.middlewares.has(z))this.middlewares.set(z,[]);if(!this.middlewares.get(z)?.includes(F))this.middlewares.get(z)?.push(F)}get(G,...F){return this.#z("GET",G,F),this}post(G,...F){return this.#z("POST",G,F),this}put(G,...F){return this.#z("PUT",G,F),this}patch(G,...F){return this.#z("PATCH",G,F),this}delete(G,...F){return this.#z("DELETE",G,F),this}}var M=D;class v extends M{constructor(){super()}#z(G,F,z){if(!this.trie.root.subMiddlewares.has(F))this.trie.root.subMiddlewares.set(F,[]);const U=z.slice(0,-1),J=this.trie.root.subMiddlewares.get(F);U.forEach((Y)=>{if(!J?.includes(Y))J?.push(Y)});const L=z[z.length-1];this.trie.insert(F,{handler:L,method:G})}get(G,...F){return this.#z("GET",G,F),this}post(G,...F){return this.#z("POST",G,F),this}put(G,...F){return this.#z("PUT",G,F),this}patch(G,...F){return this.#z("PATCH",G,F),this}delete(G,...F){return this.#z("DELETE",G,F),this}}var f=v;export{f as default};
|
|
1
|
+
class K{children;isEndOfWord;handler;isDynamic;pattern;path;method;subMiddlewares;constructor(){this.children={},this.isEndOfWord=!1,this.handler=[],this.isDynamic=!1,this.pattern="",this.path="",this.method=[],this.subMiddlewares=new Map}}class Q{root;constructor(){this.root=new K}insert(F,z){let G=this.root,J=F.split("/").filter(Boolean);if(F==="/"){G.isEndOfWord=!0,G.handler.push(z.handler),G.path=F,G.method.push(z.method);return}for(let U of J){let X=!1,Y=U;if(U.startsWith(":"))X=!0,Y=":";if(!G.children[Y])G.children[Y]=new K;G=G.children[Y],G.isDynamic=X,G.pattern=U}G.isEndOfWord=!0,G.method.push(z.method),G.handler.push(z.handler),G.path=F}search(F,z){let G=this.root,J=F.split("/").filter(Boolean);for(let X of J){let Y=X;if(!G.children[Y])if(G.children[":"])G=G.children[":"];else return null;else G=G.children[Y]}let U=G.method.indexOf(z);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]}}}function B(F,z,G){let J=new Headers,U={},X=!1,Y=null,$=null,_=null,A,V=200;return{req:F,server:z,url:G,next:()=>{},status(Z){return V=Z,this},getIP(){return this.server.requestIP(this.req)},async body(){if(!A)A=await b(F);if(A.error)return new Response(JSON.stringify({error:A.error}),{status:400});return A},setHeader(Z,E){return J.set(Z,E),this},set(Z,E){return U[Z]=E,this},get(Z){return U[Z]||null},setAuth(Z){return X=Z,this},getAuth(){return X},text(Z,E){return new Response(Z,{status:E??V,headers:J})},json(Z,E){return new Response(JSON.stringify(Z),{status:E??V,headers:J})},html(Z,E){return new Response(Bun.file(Z),{status:E??V,headers:J})},file(Z,E){return new Response(Bun.file(Z),{status:E??V,headers:J})},redirect(Z,E){return J.set("Location",Z),new Response(null,{status:E??302,headers:J})},getParams(Z){if(!_)_=C(F?.routePattern,G?.pathname);return Z?_[Z]||null:_},getQuery(Z){if(!Y)Y=Object.fromEntries(G.searchParams);return Z?Y[Z]||null:Y},async cookie(Z,E,L={}){let W=`${encodeURIComponent(Z)}=${encodeURIComponent(E)}`;if(L.maxAge)W+=`; Max-Age=${L.maxAge}`;if(L.expires)W+=`; Expires=${L.expires.toUTCString()}`;if(L.path)W+=`; Path=${L.path}`;if(L.domain)W+=`; Domain=${L.domain}`;if(L.secure)W+="; Secure";if(L.httpOnly)W+="; HttpOnly";if(L.sameSite)W+=`; SameSite=${L.sameSite}`;return J?.append("Set-Cookie",W),this},async getCookie(Z){if(!$){let E=F.headers.get("cookie");if(E)$=await T(E)}return Z?$[Z]||null:$}}}async function T(F){let z={};if(!F)return z;return F.split(";").forEach((J)=>{let[U,X]=J?.trim()?.split("=");if(U&&X)z[U.trim()]=X.split(" ")[0].trim()}),z}function C(F,z){let G={},J=F.split("/"),[U]=z.split("?"),X=U.split("/");if(J.length!==X.length)return null;return J.forEach((Y,$)=>{if(Y.startsWith(":")){let _=Y.slice(1);G[_]=X[$]}}),G}async function b(F){let z=F.headers.get("Content-Type")||"";if(!z)return{};try{if(z.startsWith("application/json"))return await F.json();if(z.startsWith("application/x-www-form-urlencoded")){let G=await F.text();return Object.fromEntries(new URLSearchParams(G))}if(z.startsWith("multipart/form-data")){let G=await F.formData();return v(G)}return{error:"Unknown request body type"}}catch(G){return{error:"Invalid request body format"}}}function v(F){let z={};for(let[G,J]of F.entries())z[G]=J;return z}async function j(F,z,G,J){let U=B(F,z,G),X=J.trie.search(G.pathname,F.method);if(!X||!X.handler)return new Response(`Route not found for ${G.pathname}`,{status:404});if(X.method!==F.method)return new Response("Method not allowed",{status:405});if(X.isDynamic)F.routePattern=X.path;if(J.corsConfig){let Y=await I(F,U,J.corsConfig);if(Y)return Y}if(J.hasOnReqHook&&J.hooks.onRequest)J.hooks.onRequest(U,z);if(J.filters.length>0){let Y=F.routePattern??G.pathname;if(J.filters.includes(Y)===!1)if(J.filterFunction){let _=await J?.filterFunction(U);if(_)return _}else return new Response(JSON.stringify({message:"Authentication required"}),{status:400})}if(J.hasMiddleware){let Y=[...J.globalMiddlewares,...J.middlewares.get(G.pathname)||[]];for(let $ of Y){let _=await $(U,z);if(_)return _}}if(J.hasPreHandlerHook&&J.hooks.preHandler){let Y=await J.hooks.preHandler(U);if(Y)return Y}try{let Y=await X.handler(U);if(J.hasPostHandlerHook&&J.hooks.postHandler)await J.hooks.postHandler(U);if(J.hasOnSendHook&&J.hooks.onSend){let $=await J.hooks.onSend(U,Y);if($)return $}return Y??new Response("No response from handler",{status:204})}catch(Y){return new Response("Internal Server Error",{status:500})}}async function I(F,z,G={}){let J=F.headers.get("origin")??"*",U=G?.origin,X=G?.allowedHeaders??["Content-Type","Authorization"],Y=G?.methods??["GET","POST","PUT","DELETE","OPTIONS"],$=G?.credentials??!1,_=G?.exposedHeaders??[];if(z.setHeader("Access-Control-Allow-Methods",Y),z.setHeader("Access-Control-Allow-Headers",X),z.setHeader("Access-Control-Allow-Credentials",$),_.length)z.setHeader("Access-Control-Expose-Headers",_);if(U==="*")z.setHeader("Access-Control-Allow-Origin","*");else if(Array.isArray(U))if(J&&U.includes(J))z.setHeader("Access-Control-Allow-Origin",J);else if(U.includes("*"))z.setHeader("Access-Control-Allow-Origin","*");else return z.status(403).json({message:"CORS not allowed"});else if(typeof U==="string")if(J===U)z.setHeader("Access-Control-Allow-Origin",J);else return z.status(403).json({message:"CORS not allowed"});else return z.status(403).json({message:"CORS not allowed"});if(z.setHeader("Access-Control-Allow-Origin",J),F.method==="OPTIONS")return z.setHeader("Access-Control-Max-Age","86400"),z.status(204).text("");return null}function M(F){let{time:z=60000,max:G=100,message:J="Rate limit exceeded. Please try again later."}=F,U=new Map;return(X)=>{let Y=new Date,$=X.getIP().address;if(!U.has($))U.set($,{count:0,startTime:Y});let _=U.get($);if(_)if(Y-_.startTime>z)_.count=1,_.startTime=Y;else _.count++;if(_&&_.count>G)return X.status(429).json({error:J});X.next()}}class D{routes;globalMiddlewares;middlewares;trie;hasOnReqHook;hasMiddleware;hasPreHandlerHook;hasPostHandlerHook;hasOnSendHook;hooks;corsConfig;filters;filterFunction;constructor(){this.routes=[],this.filters=[],this.filterFunction=null,this.globalMiddlewares=[],this.middlewares=new Map,this.trie=new Q,this.corsConfig=null,this.hasMiddleware=!1,this.hasOnReqHook=!1,this.hasPreHandlerHook=!1,this.hasPostHandlerHook=!1,this.hasOnSendHook=!1,this.hooks={onRequest:null,preHandler:null,postHandler:null,onSend:null,onError:null,onClose:null}}filter(){return{routeMatcher:(...F)=>{return this.routes=F.sort(),this.filter()},permitAll:()=>{for(let F of this?.routes)this.filters.push(F);return this.filter()},require:(F)=>{if(!F||typeof F!=="function")return new Response(JSON.stringify({message:"Authentication required"}),{status:400});this.filterFunction=F}}}cors(F){this.corsConfig=F}addHooks(F,z){if(typeof F!=="string")throw new Error("hookName must be a string");if(typeof z!=="function")throw new Error("callback must be a instance of function");if(this.hooks.hasOwnProperty(F))this.hooks[F]=z;else throw new Error(`Unknown hook type: ${F}`)}compile(){if(this.globalMiddlewares.length>0)this.hasMiddleware=!0;for(let[F,z]of this.middlewares.entries())if(z.length>0){this.hasMiddleware=!0;break}if(this.hooks.onRequest)this.hasOnReqHook=!0;if(this.hooks.preHandler)this.hasPreHandlerHook=!0;if(this.hooks.postHandler)this.hasPostHandlerHook=!0;if(this.hooks.onSend)this.hasOnSendHook=!0}listen(F,z,{sslCert:G=null,sslKey:J=null}={}){if(typeof Bun==="undefined")throw new Error(".listen() is designed to run on Bun only...");if(typeof F!=="number")throw new Error("Port must be a numeric value");this.compile();let U=this,X={port:F,fetch:async($,_)=>{let A=new URL($.url);try{return await j($,_,A,this)}catch(V){return new Response("Internal Server Error",{status:500})}},onClose(){console.log("Server is shutting down...")}};if(G&&J)X.certFile=G,X.keyFile=J;let Y=Bun.serve(X);if(typeof z==="function")return z();if(G&&J)console.log(`HTTPS server is running on https://localhost:${F}`);else console.log(`HTTP server is running on http://localhost:${F}`);return Y}register(F,z){if(typeof F!=="string")throw new Error("path must be a string");if(typeof z!=="object")throw new Error("handler parameter should be a instance of router object",z);let G=Object.entries(z.trie.root.children);z.trie.root.subMiddlewares.forEach((J,U)=>{if(!this.middlewares.has(F+U))this.middlewares.set(F+U,[]);J?.forEach((X)=>{if(!this.middlewares.get(F+U)?.includes(X))this.middlewares.get(F+U)?.push(X)})});for(let[J,U]of G){let X=F+U?.path,Y=U.handler[0],$=U.method[0];this.trie.insert(X,{handler:Y,method:$})}z.trie=new Q}#z(F,z,G){if(typeof z!=="string")throw new Error("Path must be a string type");if(typeof F!=="string")throw new Error("method must be a string type");let J=G.slice(0,-1),U=G[G.length-1];if(!this.middlewares.has(z))this.middlewares.set(z,[]);J.forEach((X)=>{if(z==="/"){if(!this.globalMiddlewares.includes(X))this.globalMiddlewares.push(X)}else if(!this.middlewares.get(z)?.includes(X))this.middlewares.get(z)?.push(X)}),this.trie.insert(z,{handler:U,method:F})}use(F,z){if(typeof F==="function"){if(!this.globalMiddlewares.includes(F))this.globalMiddlewares.push(F);return}let G=F;if(!this.middlewares.has(G))this.middlewares.set(G,[]);if(z){if(!this.middlewares.get(G)?.includes(z))this.middlewares.get(G)?.push(z)}}get(F,...z){return this.#z("GET",F,z),this}post(F,...z){return this.#z("POST",F,z),this}put(F,...z){return this.#z("PUT",F,z),this}patch(F,...z){return this.#z("PATCH",F,z),this}delete(F,...z){return this.#z("DELETE",F,z),this}}class N extends D{constructor(){super()}#z(F,z,G){if(!this.trie.root.subMiddlewares.has(z))this.trie.root.subMiddlewares.set(z,[]);let J=G.slice(0,-1),U=this.trie.root.subMiddlewares.get(z);J.forEach((Y)=>{if(!U?.includes(Y))U?.push(Y)});let X=G[G.length-1];this.trie.insert(z,{handler:X,method:F})}get(F,...z){return this.#z("GET",F,z),this}post(F,...z){return this.#z("POST",F,z),this}put(F,...z){return this.#z("PUT",F,z),this}patch(F,...z){return this.#z("PATCH",F,z),this}delete(F,...z){return this.#z("DELETE",F,z),this}}var x=N;export{x as default};
|
package/dist/trie.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { handlerFunction, HttpMethod, RouteT } from "./types";
|
|
2
|
+
declare class TrieNode {
|
|
3
|
+
children: Record<string, TrieNode>;
|
|
4
|
+
isEndOfWord: boolean;
|
|
5
|
+
handler: handlerFunction[];
|
|
6
|
+
isDynamic: boolean;
|
|
7
|
+
pattern: string;
|
|
8
|
+
path: string;
|
|
9
|
+
method: string[];
|
|
10
|
+
subMiddlewares: Map<string, handlerFunction[]>;
|
|
11
|
+
constructor();
|
|
12
|
+
}
|
|
13
|
+
export default class Trie {
|
|
14
|
+
root: TrieNode;
|
|
15
|
+
constructor();
|
|
16
|
+
insert(path: string, route: RouteT): void;
|
|
17
|
+
search(path: string, method: HttpMethod): {
|
|
18
|
+
path: string;
|
|
19
|
+
handler: handlerFunction;
|
|
20
|
+
isDynamic: boolean;
|
|
21
|
+
pattern: string;
|
|
22
|
+
method: string;
|
|
23
|
+
} | {
|
|
24
|
+
path: string;
|
|
25
|
+
handler: handlerFunction[];
|
|
26
|
+
isDynamic: boolean;
|
|
27
|
+
pattern: string;
|
|
28
|
+
method: string;
|
|
29
|
+
} | null;
|
|
30
|
+
}
|
|
31
|
+
export {};
|
package/dist/trie.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
class C{children;isEndOfWord;handler;isDynamic;pattern;path;method;subMiddlewares;constructor(){this.children={},this.isEndOfWord=!1,this.handler=[],this.isDynamic=!1,this.pattern="",this.path="",this.method=[],this.subMiddlewares=new Map}}class E{root;constructor(){this.root=new C}insert(w,z){let b=this.root
|
|
1
|
+
class C{children;isEndOfWord;handler;isDynamic;pattern;path;method;subMiddlewares;constructor(){this.children={},this.isEndOfWord=!1,this.handler=[],this.isDynamic=!1,this.pattern="",this.path="",this.method=[],this.subMiddlewares=new Map}}class E{root;constructor(){this.root=new C}insert(w,z){let b=this.root,B=w.split("/").filter(Boolean);if(w==="/"){b.isEndOfWord=!0,b.handler.push(z.handler),b.path=w,b.method.push(z.method);return}for(let j of B){let A=!1,q=j;if(j.startsWith(":"))A=!0,q=":";if(!b.children[q])b.children[q]=new C;b=b.children[q],b.isDynamic=A,b.pattern=j}b.isEndOfWord=!0,b.method.push(z.method),b.handler.push(z.handler),b.path=w}search(w,z){let b=this.root,B=w.split("/").filter(Boolean);for(let A of B){let q=A;if(!b.children[q])if(b.children[":"])b=b.children[":"];else return null;else b=b.children[q]}let j=b.method.indexOf(z);if(j!==-1)return{path:b.path,handler:b.handler[j],isDynamic:b.isDynamic,pattern:b.pattern,method:b.method[j]};return{path:b.path,handler:b.handler,isDynamic:b.isDynamic,pattern:b.pattern,method:b.method[j]}}}export{E as default};
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { Server } from "bun";
|
|
2
|
+
export type listenCalllBackType = () => void;
|
|
3
|
+
export type handlerFunction = (ctx: ContextType, server?: Server) => Response | Promise<Response | null | void>;
|
|
4
|
+
export type middlewareFunc = (ctx: ContextType, server?: Server) => void | Response | Promise<Response>;
|
|
5
|
+
export type HookFunction = (ctx: ContextType, result?: Response | null | void, server?: Server) => Response | Promise<Response | null | void>;
|
|
6
|
+
export type HttpMethod = "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "OPTIONS" | "HEAD";
|
|
7
|
+
export declare enum HookType {
|
|
8
|
+
onRequest = "onRequest",
|
|
9
|
+
preHandler = "preHandler",
|
|
10
|
+
postHandler = "postHandler",
|
|
11
|
+
onSend = "onSend",
|
|
12
|
+
onError = "onError",
|
|
13
|
+
onClose = "onClose"
|
|
14
|
+
}
|
|
15
|
+
export interface Hooks {
|
|
16
|
+
onRequest: HookFunction | null;
|
|
17
|
+
preHandler: HookFunction | null;
|
|
18
|
+
postHandler: HookFunction | null;
|
|
19
|
+
onSend: HookFunction | null;
|
|
20
|
+
onError: HookFunction | null;
|
|
21
|
+
onClose: HookFunction | null;
|
|
22
|
+
}
|
|
23
|
+
export interface ContextType {
|
|
24
|
+
req: Request;
|
|
25
|
+
server: Server;
|
|
26
|
+
url: URL;
|
|
27
|
+
next: () => void;
|
|
28
|
+
status: (status: number) => this;
|
|
29
|
+
getIP: () => any;
|
|
30
|
+
body: () => Promise<any>;
|
|
31
|
+
setHeader: (key: string, value: any) => this;
|
|
32
|
+
set: (key: string, value: any) => this;
|
|
33
|
+
get: (key: string) => any;
|
|
34
|
+
setAuth: (authStatus: boolean) => this;
|
|
35
|
+
getAuth: () => boolean;
|
|
36
|
+
json: (data: Object, status?: number) => Response;
|
|
37
|
+
text: (data: string, status?: number) => Response;
|
|
38
|
+
html: (filePath: string, status?: number) => Response;
|
|
39
|
+
file: (filePath: string, status?: number) => Response;
|
|
40
|
+
redirect: (path: string, status?: number) => Response;
|
|
41
|
+
getParams: (props?: any) => any;
|
|
42
|
+
getQuery: (props?: any) => any;
|
|
43
|
+
cookie: (name: string, value: string, options?: CookieOptions) => Promise<this>;
|
|
44
|
+
getCookie: (cookieName?: string) => Promise<any>;
|
|
45
|
+
}
|
|
46
|
+
export interface CookieOptions {
|
|
47
|
+
maxAge?: number;
|
|
48
|
+
expires?: Date;
|
|
49
|
+
path?: string;
|
|
50
|
+
domain?: string;
|
|
51
|
+
secure?: boolean;
|
|
52
|
+
httpOnly?: boolean;
|
|
53
|
+
sameSite?: "Strict" | "Lax" | "None";
|
|
54
|
+
}
|
|
55
|
+
export interface RouteNodeType {
|
|
56
|
+
path: string;
|
|
57
|
+
handler: Function[];
|
|
58
|
+
method: string[];
|
|
59
|
+
}
|
|
60
|
+
export interface RouteHandlerT {
|
|
61
|
+
method: string;
|
|
62
|
+
handler: (ctx: ContextType) => Promise<Response | null | void>;
|
|
63
|
+
isDynamic?: boolean;
|
|
64
|
+
path?: string;
|
|
65
|
+
}
|
|
66
|
+
export interface DieselT {
|
|
67
|
+
hasOnReqHook: boolean;
|
|
68
|
+
hasMiddleware: boolean;
|
|
69
|
+
hasPreHandlerHook: boolean;
|
|
70
|
+
hasPostHandlerHook: boolean;
|
|
71
|
+
hasOnSendHook: boolean;
|
|
72
|
+
hooks: {
|
|
73
|
+
onRequest: ((ctx: ContextType, serer?: Server) => void) | null;
|
|
74
|
+
preHandler: ((ctx: ContextType, serer?: Server) => Promise<Response | void | null>) | null;
|
|
75
|
+
postHandler: ((ctx: ContextType, serer?: Server) => Promise<Response | void | null>) | null;
|
|
76
|
+
onSend: ((ctx?: ContextType, result?: Response | null | void, serer?: Server) => Promise<Response | void | null>) | null;
|
|
77
|
+
};
|
|
78
|
+
filters: string[];
|
|
79
|
+
filterFunction: (ctx: ContextType) => void | Response | Promise<Response | void>;
|
|
80
|
+
corsConfig: corsT | null;
|
|
81
|
+
globalMiddlewares: Array<(ctx: ContextType, serer?: Server) => void | Promise<Response | null | void>>;
|
|
82
|
+
middlewares: Map<string, Array<(ctx: ContextType, serer?: Server) => void | Promise<Response | null | void>>>;
|
|
83
|
+
trie: {
|
|
84
|
+
search: (pathname: string, method: string) => RouteHandlerT | undefined;
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
export interface RouteCache {
|
|
88
|
+
[key: string]: RouteHandlerT | undefined;
|
|
89
|
+
}
|
|
90
|
+
declare global {
|
|
91
|
+
interface Request {
|
|
92
|
+
routePattern?: string;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
export interface ParseBodyResult {
|
|
96
|
+
error?: string;
|
|
97
|
+
data?: any;
|
|
98
|
+
}
|
|
99
|
+
export interface RouteT {
|
|
100
|
+
method: string;
|
|
101
|
+
handler: handlerFunction;
|
|
102
|
+
}
|
|
103
|
+
export type corsT = {
|
|
104
|
+
origin?: string | string[] | null;
|
|
105
|
+
methods?: string | string[] | null;
|
|
106
|
+
allowedHeaders?: string | string[] | null;
|
|
107
|
+
exposedHeaders?: string | string[] | null;
|
|
108
|
+
credentials?: boolean | null;
|
|
109
|
+
maxAge?: number;
|
|
110
|
+
preflightContinue?: boolean;
|
|
111
|
+
optionsSuccessStatus?: number;
|
|
112
|
+
} | null;
|
|
113
|
+
export interface FilterMethods {
|
|
114
|
+
routeMatcher: (...routes: string[]) => FilterMethods;
|
|
115
|
+
permitAll: () => FilterMethods;
|
|
116
|
+
require: (fnc?: middlewareFunc) => Response | void;
|
|
117
|
+
}
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { ContextType } from "./types";
|
|
2
|
+
export default function rateLimit(props: {
|
|
3
|
+
time?: number;
|
|
4
|
+
max?: number;
|
|
5
|
+
message?: string;
|
|
6
|
+
}): (ctx: ContextType) => void | Response;
|
|
7
|
+
export declare const binaryS: (arr: string[], target: string, start: number, end: number) => boolean;
|
package/example/main.ts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import {Diesel, rateLimit} from "../src/main";
|
|
2
|
+
|
|
3
|
+
const app = new Diesel()
|
|
4
|
+
|
|
5
|
+
// app.cors({
|
|
6
|
+
// origin: ['http://localhost:5173','*'],
|
|
7
|
+
// methods: 'GET,POST,PUT,DELETE',
|
|
8
|
+
// allowedHeaders: 'Content-Type,Authorization'
|
|
9
|
+
// })
|
|
10
|
+
|
|
11
|
+
function h() {
|
|
12
|
+
return new Response("hello world")
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const limiter = rateLimit({
|
|
16
|
+
time: 60000, // Time window in milliseconds (e.g., 1 minute)
|
|
17
|
+
max: 10, // Maximum number of requests allowed in the time window
|
|
18
|
+
message: "Rate limit exceeded. Please try again later." // Custom error message
|
|
19
|
+
});
|
|
20
|
+
// app.use(h)
|
|
21
|
+
// app.use(limiter)
|
|
22
|
+
|
|
23
|
+
app
|
|
24
|
+
.filter()
|
|
25
|
+
.routeMatcher('/api/user/register','/api/user/login','/test/:id','/')
|
|
26
|
+
.permitAll()
|
|
27
|
+
.require()
|
|
28
|
+
|
|
29
|
+
// .require(you can pass jwt auth parser)
|
|
30
|
+
|
|
31
|
+
app.get("/", async(xl) => {
|
|
32
|
+
// const ip = xl.req
|
|
33
|
+
// console.log(ip)
|
|
34
|
+
return xl.json({
|
|
35
|
+
message: 'Hello from Express!',
|
|
36
|
+
author: 'Pradeep',
|
|
37
|
+
app: 'Express App',
|
|
38
|
+
features: ['Fast', 'Flexible', 'Lightweight']
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
app.get("/test/:id", async (xl) => {
|
|
43
|
+
const q = xl.getQuery();
|
|
44
|
+
const params = xl.getParams('id');
|
|
45
|
+
return new Response(JSON.stringify({ msg: "hello world", q, params }));
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
app.get("/ok",(xl)=>{
|
|
49
|
+
return xl.status(200).text("kaise ho??")
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
app.listen(3000)
|