diesel-core 0.0.17 → 0.0.19
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/CONTRIBUTING.md +1 -1
- package/README.md +40 -15
- package/build.js +15 -7
- package/dist/ctx.js +1 -1
- package/dist/handleRequest.js +1 -1
- package/dist/main.d.ts +7 -7
- package/dist/main.js +1 -1
- package/dist/trie.d.ts +0 -6
- package/dist/trie.js +1 -1
- package/dist/types.d.ts +19 -18
- package/dist/utils.js +1 -1
- package/example/main.ts +53 -42
- package/example/route.ts +40 -0
- package/index.d.ts +5 -0
- package/index.js +10 -0
- package/package.json +6 -3
- package/src/ctx.ts +100 -85
- package/src/handleRequest.ts +29 -29
- package/src/main.ts +160 -92
- package/src/trie.ts +30 -33
- package/src/types.ts +31 -18
- package/src/utils.ts +0 -2
- package/tsconfig.json +3 -3
- package/example/route.js +0 -21
package/CONTRIBUTING.md
CHANGED
package/README.md
CHANGED
|
@@ -19,26 +19,34 @@ bun add diesel-core
|
|
|
19
19
|
|
|
20
20
|
### Code Example
|
|
21
21
|
```javascript
|
|
22
|
-
import Diesel from "diesel-core"
|
|
22
|
+
import {Diesel} from "diesel-core"
|
|
23
23
|
|
|
24
24
|
const app = new Diesel()
|
|
25
25
|
const port = 3000
|
|
26
26
|
|
|
27
27
|
app.get("/", async (ctx:ContextType) => {
|
|
28
28
|
return ctx.status(200).text("Hello world...!")
|
|
29
|
-
// OR
|
|
30
|
-
// return xl.text("Hello world!")
|
|
31
|
-
// OR
|
|
32
|
-
// return new Response("Hello world")
|
|
33
29
|
})
|
|
34
30
|
|
|
35
31
|
// Start the server
|
|
36
32
|
app.listen(port, () => {
|
|
37
33
|
console.log(`diesel is running on port ${port}`)
|
|
38
34
|
})
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
# CORS
|
|
39
38
|
|
|
39
|
+
### Diesel supports cors out of the box
|
|
40
|
+
|
|
41
|
+
``` javascript
|
|
42
|
+
app.cors({
|
|
43
|
+
origin: ['http://localhost:5173','*'],
|
|
44
|
+
methods: 'GET,POST,PUT,DELETE',
|
|
45
|
+
allowedHeaders: 'Content-Type,Authorization'
|
|
46
|
+
})
|
|
40
47
|
```
|
|
41
|
-
|
|
48
|
+
|
|
49
|
+
# Filter and Route Security
|
|
42
50
|
**Diesel** provides a simple way to manage public and protected routes by using a filter() method. You can define specific routes to be publicly accessible, while others will require authentication or custom middleware functions.
|
|
43
51
|
|
|
44
52
|
### How to Use the Filter
|
|
@@ -47,7 +55,7 @@ The **filter()** method allows you to secure certain endpoints while keeping oth
|
|
|
47
55
|
|
|
48
56
|
### Example Usage
|
|
49
57
|
```javascript
|
|
50
|
-
import Diesel from "diesel-core";
|
|
58
|
+
import {Diesel} from "diesel-core";
|
|
51
59
|
import jwt from 'jsonwebtoken';
|
|
52
60
|
|
|
53
61
|
|
|
@@ -100,7 +108,7 @@ app.listen(port, () => {
|
|
|
100
108
|
})
|
|
101
109
|
|
|
102
110
|
```
|
|
103
|
-
|
|
111
|
+
# Filter Methods
|
|
104
112
|
1. **routeMatcher(...routes: string[])** : Passed endpoints in this routeMatcher will be ***Public*** means they don't need authentication, including those with dynamic parameters (e.g., /test/:id).
|
|
105
113
|
|
|
106
114
|
```javascript
|
|
@@ -122,7 +130,7 @@ app.listen(port, () => {
|
|
|
122
130
|
|
|
123
131
|
* **Protected Routes** : For other routes ***(like /api/user/profile)***, you'll want to require authentication or custom middleware. Use require(authJwt) to ensure that the user is authenticated before accessing these routes.
|
|
124
132
|
|
|
125
|
-
|
|
133
|
+
# Using Hooks in DieselJS
|
|
126
134
|
|
|
127
135
|
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.
|
|
128
136
|
|
|
@@ -133,6 +141,7 @@ DieselJS allows you to enhance your request handling by utilizing hooks at vario
|
|
|
133
141
|
2. **preHandler**: Invoked just before the request handler executes.
|
|
134
142
|
3. **postHandler**: Executed after the request handler completes but before sending the response.
|
|
135
143
|
4. **onSend**: Called just before the response is sent to the client.
|
|
144
|
+
5. **onError** : Executes if any error occurs
|
|
136
145
|
|
|
137
146
|
### How to Define Hooks
|
|
138
147
|
|
|
@@ -141,10 +150,19 @@ To define hooks in your DieselJS application, you can add them directly to your
|
|
|
141
150
|
### Example Usage
|
|
142
151
|
|
|
143
152
|
```javascript
|
|
153
|
+
|
|
154
|
+
// define and onError hook
|
|
155
|
+
|
|
156
|
+
app.addHooks("onError",(error,req,url,server) => {
|
|
157
|
+
console.log(`error occured ${error.message}`)
|
|
158
|
+
// retunr new Response(......)
|
|
159
|
+
})
|
|
160
|
+
|
|
144
161
|
// Define an onRequest hook
|
|
145
|
-
app.addHooks("onRequest",(
|
|
146
|
-
console.log(`Request received: ${
|
|
162
|
+
app.addHooks("onRequest",(req,url,server) =>{
|
|
163
|
+
console.log(`Request received: ${req.method} ${url}`);
|
|
147
164
|
})
|
|
165
|
+
// you get req,url & server instance in onReq
|
|
148
166
|
|
|
149
167
|
// Define a preHandler hook
|
|
150
168
|
app.addHooks("preHandler",(xl) =>{
|
|
@@ -218,9 +236,9 @@ app.get("/set-cookie", async(xl) => {
|
|
|
218
236
|
path: "/",
|
|
219
237
|
}
|
|
220
238
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
239
|
+
xl
|
|
240
|
+
.setCookie("accessToken", accessToken, options)
|
|
241
|
+
.setCookie("refreshToken", refreshToken, options)
|
|
224
242
|
|
|
225
243
|
return xl.json({msg:"setting cookies"})
|
|
226
244
|
})
|
|
@@ -239,8 +257,15 @@ app.get("/redirect",(xl) => {
|
|
|
239
257
|
})
|
|
240
258
|
```
|
|
241
259
|
# get params
|
|
260
|
+
|
|
261
|
+
**You can use set ***Multiparams***** , ***like this***
|
|
262
|
+
|
|
263
|
+
```javascript
|
|
264
|
+
app.get("/product/:productId/:productName)
|
|
265
|
+
```
|
|
266
|
+
|
|
242
267
|
```javascript
|
|
243
|
-
app.get("/hello/:id",(xl) => {
|
|
268
|
+
app.get("/hello/:id/",(xl) => {
|
|
244
269
|
const id = xl.getParams("id")
|
|
245
270
|
const query = xl.getQuery() // you can pass query name also , you wanna get
|
|
246
271
|
return xl.json({ msg: "Hello", id });
|
package/build.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
2
|
const entryPoints = [
|
|
3
|
-
'./
|
|
4
|
-
'./
|
|
5
|
-
'./
|
|
6
|
-
'./
|
|
7
|
-
'./
|
|
8
|
-
'./
|
|
3
|
+
'./src/main.ts',
|
|
4
|
+
'./src/ctx.ts',
|
|
5
|
+
'./src/handleRequest.ts',
|
|
6
|
+
'./src/trie.ts',
|
|
7
|
+
'./src/router.ts',
|
|
8
|
+
'./src/utils.ts'
|
|
9
9
|
];
|
|
10
10
|
|
|
11
11
|
entryPoints.forEach(entry => {
|
|
@@ -21,4 +21,12 @@ entryPoints.forEach(entry => {
|
|
|
21
21
|
}
|
|
22
22
|
});
|
|
23
23
|
|
|
24
|
-
// Bun.spawn(['rm','-rf','./main'])
|
|
24
|
+
// Bun.spawn(['rm','-rf','./main'])
|
|
25
|
+
|
|
26
|
+
// oha test
|
|
27
|
+
// oha -c 500 -n 100000 -H "Cookie: accessToken=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoicGsiLCJhZ2UiOjIyLCJpYXQiOjE3Mjk5MjQxOTQsImV4cCI6MTczMDAxMDU5NH0._dEjx5iUuOLoq15-xTPgXOemfzIPrg06Qmruiv-I5cc" http://localhost:3000/
|
|
28
|
+
|
|
29
|
+
// bombardier
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
// bombardier -c 500 -n 100000 -H "Cookie: accessToken=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoicGsiLCJhZ2UiOjIyLCJpYXQiOjE3Mjk5MjQxOTQsImV4cCI6MTczMDAxMDU5NH0._dEjx5iUuOLoq15-xTPgXOemfzIPrg06Qmruiv-I5cc" http://localhost:3000/
|
package/dist/ctx.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
function K(F,L,G){let z=new Headers,M={},U=!1,I,Z=null,$,_,Y=200,x={};return{req:F,server:L,url:G,getUser(){return x},setUser(w){if(w)x=w},status(w){return Y=w,this},getIP(){return this.server.requestIP(this.req)},async getBody(){if(!_)_=await W(F);if(_.error)return new Response(JSON.stringify({error:_.error}),{status:400});return _},setHeader(w,E){return z.set(w,E),this},set(w,E){return M[w]=E,this},get(w){return M[w]||null},setAuth(w){return U=w,this},getAuth(){return U},text(w,E){return new Response(w,{status:E??Y,headers:z})},send(w,E){return new Response(w,{status:E??Y,headers:z})},json(w,E){return new Response(JSON.stringify(w),{status:E??Y,headers:z})},html(w,E){return new Response(Bun.file(w),{status:E??Y,headers:z})},file(w,E){return new Response(Bun.file(w),{status:E??Y,headers:z})},redirect(w,E){return z.set("Location",w),new Response(null,{status:E??302,headers:z})},setCookie(w,E,J={}){let X=`${encodeURIComponent(w)}=${encodeURIComponent(E)}`;if(J.maxAge)X+=`; Max-Age=${J.maxAge}`;if(J.expires)X+=`; Expires=${J.expires.toUTCString()}`;if(J.path)X+=`; Path=${J.path}`;if(J.domain)X+=`; Domain=${J.domain}`;if(J.secure)X+="; Secure";if(J.httpOnly)X+="; HttpOnly";if(J.sameSite)X+=`; SameSite=${J.sameSite}`;return z?.append("Set-Cookie",X),this},getParams(w){if(!$&&F?.routePattern)$=R(F?.routePattern,G?.pathname);return w?$[w]||{}:$},getQuery(w){try{if(!I)I=Object.fromEntries(G.searchParams);return w?I[w]||{}:I}catch(E){return{}}},getCookie(w){if(!Z){let E=F.headers.get("cookie");if(E)Z=O(E);else return null}if(!Z)return null;if(w)return Z[w]??null;else return Z}}}function O(F){let L={},G=F?.split(";");for(let z=0;z<G?.length;z++){let[M,...U]=G[z].trim().split("="),I=U?.join("=").trim();if(M)L[M.trim()]=decodeURIComponent(I)}return L}function R(F,L){let G={},z=F.split("/"),[M]=L.split("?"),U=M.split("/");if(z.length!==U.length)return null;for(let I=0;I<z.length;I++)if(z[I].startsWith(":"))G[z[I].slice(1)]=U[I];return G}async function W(F){let L=F.headers.get("Content-Type")||"";if(!L)return{};try{if(L.startsWith("application/json"))return await F.json();if(L.startsWith("application/x-www-form-urlencoded")){let G=await F.text();return Object.fromEntries(new URLSearchParams(G))}if(L.startsWith("multipart/form-data")){let G=await F.formData(),z={};for(let[M,U]of G.entries())z[M]=U;return z}return{error:"Unknown request body type"}}catch(G){return{error:"Invalid request body format"}}}export{K as default};
|
package/dist/handleRequest.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
function D(I,F,G){let z=new Headers,J={},L=!1,Z,U=null,Y,_,$=200,A={};return{req:I,server:F,url:G,getUser(){return A},setUser(E){if(E)A=E},status(E){return $=E,this},getIP(){return this.server.requestIP(this.req)},async getBody(){if(!_)_=await j(I);if(_.error)return new Response(JSON.stringify({error:_.error}),{status:400});return _},setHeader(E,X){return z.set(E,X),this},set(E,X){return J[E]=X,this},get(E){return J[E]||null},setAuth(E){return L=E,this},getAuth(){return L},text(E,X){return new Response(E,{status:X??$,headers:z})},send(E,X){return new Response(E,{status:X??$,headers:z})},json(E,X){return new Response(JSON.stringify(E),{status:X??$,headers:z})},html(E,X){return new Response(Bun.file(E),{status:X??$,headers:z})},file(E,X){return new Response(Bun.file(E),{status:X??$,headers:z})},redirect(E,X){return z.set("Location",E),new Response(null,{status:X??302,headers:z})},setCookie(E,X,K={}){let W=`${encodeURIComponent(E)}=${encodeURIComponent(X)}`;if(K.maxAge)W+=`; Max-Age=${K.maxAge}`;if(K.expires)W+=`; Expires=${K.expires.toUTCString()}`;if(K.path)W+=`; Path=${K.path}`;if(K.domain)W+=`; Domain=${K.domain}`;if(K.secure)W+="; Secure";if(K.httpOnly)W+="; HttpOnly";if(K.sameSite)W+=`; SameSite=${K.sameSite}`;return z?.append("Set-Cookie",W),this},getParams(E){if(!Y&&I?.routePattern)Y=V(I?.routePattern,G?.pathname);return E?Y[E]||{}:Y},getQuery(E){try{if(!Z)Z=Object.fromEntries(G.searchParams);return E?Z[E]||{}:Z}catch(X){return{}}},getCookie(E){if(!U){let X=I.headers.get("cookie");if(X)U=T(X);else return null}if(!U)return null;if(E)return U[E]??null;else return U}}}function T(I){let F={},G=I?.split(";");for(let z=0;z<G?.length;z++){let[J,...L]=G[z].trim().split("="),Z=L?.join("=").trim();if(J)F[J.trim()]=decodeURIComponent(Z)}return F}function V(I,F){let G={},z=I.split("/"),[J]=F.split("?"),L=J.split("/");if(z.length!==L.length)return null;for(let Z=0;Z<z.length;Z++)if(z[Z].startsWith(":"))G[z[Z].slice(1)]=L[Z];return G}async function j(I){let F=I.headers.get("Content-Type")||"";if(!F)return{};try{if(F.startsWith("application/json"))return await I.json();if(F.startsWith("application/x-www-form-urlencoded")){let G=await I.text();return Object.fromEntries(new URLSearchParams(G))}if(F.startsWith("multipart/form-data")){let G=await I.formData(),z={};for(let[J,L]of G.entries())z[J]=L;return z}return{error:"Unknown request body type"}}catch(G){return{error:"Invalid request body format"}}}async function M(I,F,G,z){let J=z.trie.search(G.pathname,I.method);if(!J||J.method!==I.method){let U=J?"Method not allowed":`Route not found for ${G.pathname}`,Y=J?405:404;return new Response(JSON.stringify({message:U}),{status:Y})}if(J.isDynamic)I.routePattern=J.path;let L=D(I,F,G);if(z.corsConfig){let U=Q(I,L,z.corsConfig);if(U)return U}if(z.hasOnReqHook&&z.hooks.onRequest)z.hooks.onRequest(I,G,F);if(z.hasFilterEnabled){let U=I.routePattern??G.pathname;if(!z.filters.has(U))if(z.filterFunction)try{let Y=await z.filterFunction(L,F);if(Y)return Y}catch(Y){return console.error("Error in filterFunction:",Y),L.status(500).json({message:"Internal Server Error",error:Y.message})}else return L.status(400).json({message:"Authentication required"})}if(z.hasMiddleware){let U=z.globalMiddlewares;for(let _=0;_<U.length;_++){let $=await U[_](L,F);if($)return $}let Y=z.middlewares.get(G.pathname)||[];for(let _=0;_<Y.length;_++){let $=await Y[_](L,F);if($)return $}}if(z.hasPreHandlerHook&&z.hooks.preHandler){let U=await z.hooks.preHandler(L);if(U)return U}let Z=await J.handler(L);if(z.hasPostHandlerHook&&z.hooks.postHandler)await z.hooks.postHandler(L);if(z.hasOnSendHook&&z.hooks.onSend){let U=await z.hooks.onSend(L,Z);if(U)return U}return Z??L.status(204).json({message:"No response from this handler"})}function Q(I,F,G={}){let z=I.headers.get("origin")??"*",J=G?.origin,L=G?.allowedHeaders??["Content-Type","Authorization"],Z=G?.methods??["GET","POST","PUT","DELETE","OPTIONS"],U=G?.credentials??!1,Y=G?.exposedHeaders??[];if(F.setHeader("Access-Control-Allow-Methods",Z),F.setHeader("Access-Control-Allow-Headers",L),F.setHeader("Access-Control-Allow-Credentials",U),Y.length)F.setHeader("Access-Control-Expose-Headers",Y);if(J==="*")F.setHeader("Access-Control-Allow-Origin","*");else if(Array.isArray(J))if(z&&J.includes(z))F.setHeader("Access-Control-Allow-Origin",z);else if(J.includes("*"))F.setHeader("Access-Control-Allow-Origin","*");else return F.status(403).json({message:"CORS not allowed"});else if(typeof J==="string")if(z===J)F.setHeader("Access-Control-Allow-Origin",z);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",z),I.method==="OPTIONS")return F.setHeader("Access-Control-Max-Age","86400"),F.status(204).text("");return null}export{M as default};
|
package/dist/main.d.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import Trie from "./trie.js";
|
|
2
|
-
import
|
|
3
|
-
import { corsT, FilterMethods, HookFunction, HookType, middlewareFunc, type handlerFunction, type Hooks, type HttpMethod, type listenCalllBackType } from "./types.js";
|
|
2
|
+
import { corsT, FilterMethods, HookFunction, HookType, middlewareFunc, onError, onRequest, type handlerFunction, type Hooks, type HttpMethod, type listenCalllBackType } from "./types.js";
|
|
4
3
|
import { Server } from "bun";
|
|
5
4
|
export default class Diesel {
|
|
6
|
-
|
|
5
|
+
tempRoutes: Map<string, any>;
|
|
7
6
|
globalMiddlewares: middlewareFunc[];
|
|
8
7
|
middlewares: Map<string, middlewareFunc[]>;
|
|
9
8
|
trie: Trie;
|
|
@@ -12,18 +11,20 @@ export default class Diesel {
|
|
|
12
11
|
hasPreHandlerHook: boolean;
|
|
13
12
|
hasPostHandlerHook: boolean;
|
|
14
13
|
hasOnSendHook: boolean;
|
|
14
|
+
hasOnError: boolean;
|
|
15
15
|
hooks: Hooks;
|
|
16
16
|
corsConfig: corsT;
|
|
17
|
-
|
|
17
|
+
FilterRoutes: string[] | null | undefined;
|
|
18
|
+
filters: Set<string>;
|
|
18
19
|
filterFunction: middlewareFunc | null;
|
|
19
20
|
hasFilterEnabled: boolean;
|
|
20
|
-
wss: WebSocket | null | undefined;
|
|
21
21
|
constructor();
|
|
22
22
|
filter(): FilterMethods;
|
|
23
23
|
cors(corsConfig: corsT): void;
|
|
24
|
-
addHooks(typeOfHook: HookType, fnc: HookFunction): void;
|
|
24
|
+
addHooks(typeOfHook: HookType, fnc: HookFunction | onError | onRequest): void;
|
|
25
25
|
compile(): void;
|
|
26
26
|
listen(port: number, callback?: listenCalllBackType, { sslCert, sslKey }?: any): Server | void;
|
|
27
|
+
route(basePath: string, routerInstance: any): void;
|
|
27
28
|
register(pathPrefix: string, handlerInstance: any): void;
|
|
28
29
|
addRoute(method: HttpMethod, path: string, handlers: handlerFunction[]): void;
|
|
29
30
|
use(pathORHandler?: string | middlewareFunc, handler?: middlewareFunc): void;
|
|
@@ -33,4 +34,3 @@ export default class Diesel {
|
|
|
33
34
|
patch(path: string, ...handlers: handlerFunction[]): this;
|
|
34
35
|
delete(path: any, ...handlers: handlerFunction[]): this;
|
|
35
36
|
}
|
|
36
|
-
export { rateLimit, };
|
package/dist/main.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
class A{constructor(){this.children={},this.isEndOfWord=!1,this.handler=[],this.isDynamic=!1,this.pattern="",this.path="",this.method=[],this.subMiddlewares=new Map}}class K{constructor(){this.root=new A}insert(G,J){let z=this.root,U=G.split("/").filter(Boolean);if(G==="/"){z.isEndOfWord=!0,z.handler.push(J.handler),z.path=G,z.method.push(J.method);return}for(let Y of U){let Z=!1,X=Y;if(Y.startsWith(":"))Z=!0,X=":";if(!z.children[X])z.children[X]=new A;z=z.children[X],z.isDynamic=Z,z.pattern=Y,z.method.push(J.method),z.handler.push(J.handler),z.path=G}z.isEndOfWord=!0,z.method.push(J.method),z.handler.push(J.handler),z.path=G}search(G,J){let z=this.root,U=G.split("/").filter(Boolean);for(let Z of U){let X=Z;if(!z.children[X])if(z.children[":"])z=z.children[":"];else return null;else z=z.children[X]}let Y=z.method.indexOf(J);if(Y!==-1)return{path:z.path,handler:z.handler[Y],isDynamic:z.isDynamic,pattern:z.pattern,method:z.method[Y]};return{path:z.path,handler:z.handler,isDynamic:z.isDynamic,pattern:z.pattern,method:z.method[Y]}}}var N=function(G,J,z,U){function Y(Z){return Z instanceof z?Z:new z(function(X){X(Z)})}return new(z||(z=Promise))(function(Z,X){function F($){try{V(U.next($))}catch(Q){X(Q)}}function L($){try{V(U.throw($))}catch(Q){X(Q)}}function V($){$.done?Z($.value):Y($.value).then(F,L)}V((U=U.apply(G,J||[])).next())})};function M(G,J,z){let U=new Headers,Y={},Z=!1,X,F=null,L,V,$=200,Q={};return{req:G,server:J,url:z,next:()=>{},getUser(){return Q},setUser(E){if(E)Q=E},status(E){return $=E,this},getIP(){return this.server.requestIP(this.req)},body(){return N(this,void 0,void 0,function*(){if(!V)V=yield O(G);if(V.error)return new Response(JSON.stringify({error:V.error}),{status:400});return V})},setHeader(E,W){return U.set(E,W),this},set(E,W){return Y[E]=W,this},get(E){return Y[E]||null},setAuth(E){return Z=E,this},getAuth(){return Z},text(E,W){return new Response(E,{status:W!==null&&W!==void 0?W:$,headers:U})},json(E,W){return new Response(JSON.stringify(E),{status:W!==null&&W!==void 0?W:$,headers:U})},html(E,W){return new Response(Bun.file(E),{status:W!==null&&W!==void 0?W:$,headers:U})},file(E,W){return new Response(Bun.file(E),{status:W!==null&&W!==void 0?W:$,headers:U})},redirect(E,W){return U.set("Location",E),new Response(null,{status:W!==null&&W!==void 0?W:302,headers:U})},getParams(E){if(!L)L=I(G===null||G===void 0?void 0:G.routePattern,z===null||z===void 0?void 0:z.pathname);return E?L[E]||{}:L},getQuery(E){try{if(!X)X=Object.fromEntries(z.searchParams);return E?X[E]||{}:X}catch(W){return{}}},cookie(E,W,B={}){let D=`${encodeURIComponent(E)}=${encodeURIComponent(W)}`;if(B.maxAge)D+=`; Max-Age=${B.maxAge}`;if(B.expires)D+=`; Expires=${B.expires.toUTCString()}`;if(B.path)D+=`; Path=${B.path}`;if(B.domain)D+=`; Domain=${B.domain}`;if(B.secure)D+="; Secure";if(B.httpOnly)D+="; HttpOnly";if(B.sameSite)D+=`; SameSite=${B.sameSite}`;return U===null||U===void 0||U.append("Set-Cookie",D),this},getCookie(E){var W;if(!F||Object.keys(F).length===0){let B=(W=G.headers)===null||W===void 0?void 0:W.get("cookie");if(B)F=j(B);else return null}if(!F)return null;return E?F[E]!==void 0?F[E]:null:F}}}function j(G){let J={};if(!G)return J;return G.split(";").forEach((U)=>{var Y;let[Z,X]=(Y=U===null||U===void 0?void 0:U.trim())===null||Y===void 0?void 0:Y.split("=");if(Z&&X)J[Z.trim()]=X.split(" ")[0].trim()}),J}function I(G,J){let z={},U=G.split("/"),[Y]=J.split("?"),Z=Y.split("/");if(U.length!==Z.length)return null;return U.forEach((X,F)=>{if(X.startsWith(":")){let L=X.slice(1);z[L]=Z[F]}}),z}function O(G){return N(this,void 0,void 0,function*(){let J=G.headers.get("Content-Type")||"";if(!J)return{};try{if(J.startsWith("application/json"))return yield G.json();if(J.startsWith("application/x-www-form-urlencoded")){let z=yield G.text();return Object.fromEntries(new URLSearchParams(z))}if(J.startsWith("multipart/form-data")){let z=yield G.formData();return S(z)}return{error:"Unknown request body type"}}catch(z){return{error:"Invalid request body format"}}})}function S(G){let J={};for(let[z,U]of G.entries())J[z]=U;return J}var b=function(G,J,z,U){function Y(Z){return Z instanceof z?Z:new z(function(X){X(Z)})}return new(z||(z=Promise))(function(Z,X){function F($){try{V(U.next($))}catch(Q){X(Q)}}function L($){try{V(U.throw($))}catch(Q){X(Q)}}function V($){$.done?Z($.value):Y($.value).then(F,L)}V((U=U.apply(G,J||[])).next())})};function T(G,J,z,U){return b(this,void 0,void 0,function*(){var Y,Z,X;let F=U.trie.search(z.pathname,G.method);if(!F||F.method!==G.method)return new Response(F?"Method not allowed":`Route not found for ${z.pathname}`,{status:F?405:404});if(F.isDynamic)G.routePattern=F.path;let L=M(G,J,z);if(U.corsConfig){let $=w(G,L,U.corsConfig);if($)return $}if(U.hasOnReqHook&&U.hooks.onRequest)U.hooks.onRequest(L,J);if(U.hasFilterEnabled){let $=(Y=G.routePattern)!==null&&Y!==void 0?Y:z.pathname;if(U.filters.includes($)===!1)if(U.filterFunction)try{let E=yield U.filterFunction(L,J);if(E)return E}catch(E){return console.error("Error in filterFunction:",E),new Response(JSON.stringify({message:"Internal Server Error"}),{status:500})}else return new Response(JSON.stringify({message:"Authentication required"}),{status:400})}if(U.hasMiddleware){for(let Q of U.globalMiddlewares){let E=yield Q(L,J);if(E)return E}let $=U.middlewares.get(z.pathname)||[];for(let Q of $){let E=yield Q(L,J);if(E)return E}}if(U.hasPreHandlerHook&&U.hooks.preHandler){let $=yield U.hooks.preHandler(L);if($)return $}let V=U.hasPreHandlerHook?yield(X=(Z=U.hooks).preHandler)===null||X===void 0?void 0:X.call(Z,L):null;if(V)return V;try{let $=yield F.handler(L);if(U.hasPostHandlerHook&&U.hooks.postHandler)yield U.hooks.postHandler(L);if(U.hasOnSendHook&&U.hooks.onSend){let Q=yield U.hooks.onSend(L,$);if(Q)return Q}return $!==null&&$!==void 0?$:new Response("No response from handler",{status:204})}catch($){return new Response("Internal Server Error",{status:500})}})}function w(G,J,z={}){var U,Y,Z,X,F;let L=(U=G.headers.get("origin"))!==null&&U!==void 0?U:"*",V=z===null||z===void 0?void 0:z.origin,$=(Y=z===null||z===void 0?void 0:z.allowedHeaders)!==null&&Y!==void 0?Y:["Content-Type","Authorization"],Q=(Z=z===null||z===void 0?void 0:z.methods)!==null&&Z!==void 0?Z:["GET","POST","PUT","DELETE","OPTIONS"],E=(X=z===null||z===void 0?void 0:z.credentials)!==null&&X!==void 0?X:!1,W=(F=z===null||z===void 0?void 0:z.exposedHeaders)!==null&&F!==void 0?F:[];if(J.setHeader("Access-Control-Allow-Methods",Q),J.setHeader("Access-Control-Allow-Headers",$),J.setHeader("Access-Control-Allow-Credentials",E),W.length)J.setHeader("Access-Control-Expose-Headers",W);if(V==="*")J.setHeader("Access-Control-Allow-Origin","*");else if(Array.isArray(V))if(L&&V.includes(L))J.setHeader("Access-Control-Allow-Origin",L);else if(V.includes("*"))J.setHeader("Access-Control-Allow-Origin","*");else return J.status(403).json({message:"CORS not allowed"});else if(typeof V==="string")if(L===V)J.setHeader("Access-Control-Allow-Origin",L);else return J.status(403).json({message:"CORS not allowed"});else return J.status(403).json({message:"CORS not allowed"});if(J.setHeader("Access-Control-Allow-Origin",L),G.method==="OPTIONS")return J.setHeader("Access-Control-Max-Age","86400"),J.status(204).text("");return null}function C(G){let{time:J=60000,max:z=100,message:U="Rate limit exceeded. Please try again later."}=G,Y=new Map;return(Z)=>{let X=new Date,F=Z.getIP().address;if(!Y.has(F))Y.set(F,{count:0,startTime:X});let L=Y.get(F);if(L)if(X-L.startTime>J)L.count=1,L.startTime=X;else L.count++;if(L&&L.count>z)return Z.status(429).json({error:U});Z.next()}}var H=function(G,J,z,U){function Y(Z){return Z instanceof z?Z:new z(function(X){X(Z)})}return new(z||(z=Promise))(function(Z,X){function F($){try{V(U.next($))}catch(Q){X(Q)}}function L($){try{V(U.throw($))}catch(Q){X(Q)}}function V($){$.done?Z($.value):Y($.value).then(F,L)}V((U=U.apply(G,J||[])).next())})};class R{constructor(){this.routes=[],this.globalMiddlewares=[],this.middlewares=new Map,this.trie=new K,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},this.filters=[],this.filterFunction=null,this.hasFilterEnabled=!1,this.wss=null}filter(){return this.hasFilterEnabled=!0,{routeMatcher:(...G)=>{return this.routes=G.sort(),this.filter()},permitAll:()=>{for(let G of this===null||this===void 0?void 0:this.routes)this.filters.push(G);return this.filter()},require:(G)=>{if(G)this.filterFunction=G}}}cors(G){this.corsConfig=G}addHooks(G,J){if(typeof G!=="string")throw new Error("hookName must be a string");if(typeof J!=="function")throw new Error("callback must be a instance of function");if(this.hooks.hasOwnProperty(G))this.hooks[G]=J;else throw new Error(`Unknown hook type: ${G}`)}compile(){if(this.globalMiddlewares.length>0)this.hasMiddleware=!0;for(let[G,J]of this.middlewares.entries())if(J.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,J,{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();let Y={port:G,fetch:(X,F)=>H(this,void 0,void 0,function*(){let L=new URL(X.url);try{return yield T(X,F,L,this)}catch(V){return new Response("Internal Server Error",{status:500})}}),onClose(){console.log("Server is shutting down...")}};if(z&&U)Y.certFile=z,Y.keyFile=U;let Z=Bun.serve(Y);if(Bun===null||Bun===void 0||Bun.gc(!1),typeof J==="function")return J();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 Z}register(G,J){if(typeof G!=="string")throw new Error("path must be a string");if(typeof J!=="object")throw new Error("handler parameter should be a instance of router object",J);let z=Object.entries(J.trie.root.children);J.trie.root.subMiddlewares.forEach((U,Y)=>{if(!this.middlewares.has(G+Y))this.middlewares.set(G+Y,[]);U===null||U===void 0||U.forEach((Z)=>{var X,F;if(!((X=this.middlewares.get(G+Y))===null||X===void 0?void 0:X.includes(Z)))(F=this.middlewares.get(G+Y))===null||F===void 0||F.push(Z)})});for(let[U,Y]of z){let Z=G+(Y===null||Y===void 0?void 0:Y.path),X=Y.handler[0],F=Y.method[0];this.trie.insert(Z,{handler:X,method:F})}J.trie=new K}addRoute(G,J,z){if(typeof J!=="string")throw new Error("Path must be a string type");if(typeof G!=="string")throw new Error("method must be a string type");let U=z.slice(0,-1),Y=z[z.length-1];if(!this.middlewares.has(J))this.middlewares.set(J,[]);U.forEach((Z)=>{var X,F;if(J==="/"){if(!this.globalMiddlewares.includes(Z))this.globalMiddlewares.push(Z)}else if(!((X=this.middlewares.get(J))===null||X===void 0?void 0:X.includes(Z)))(F=this.middlewares.get(J))===null||F===void 0||F.push(Z)}),this.trie.insert(J,{handler:Y,method:G})}use(G,J){var z,U;if(typeof G==="function"){if(!this.globalMiddlewares.includes(G))this.globalMiddlewares.push(G);return}let Y=G;if(!this.middlewares.has(Y))this.middlewares.set(Y,[]);if(J){if(!((z=this.middlewares.get(Y))===null||z===void 0?void 0:z.includes(J)))(U=this.middlewares.get(Y))===null||U===void 0||U.push(J)}}get(G,...J){return this.addRoute("GET",G,J),this}post(G,...J){return this.addRoute("POST",G,J),this}put(G,...J){return this.addRoute("PUT",G,J),this}patch(G,...J){return this.addRoute("PATCH",G,J),this}delete(G,...J){return this.addRoute("DELETE",G,J),this}}export{C as rateLimit,R as default};
|
|
1
|
+
class B{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 A{root;constructor(){this.root=new B}insert(F,z){let G=this.root,J=F.split("/").filter(Boolean);if(F==="/"){G.isEndOfWord=!0,G.handler=[z.handler],G.path=F,G.method=[z.method];return}for(let L=0;L<J.length;L++){let U=J[L],Z=!1,X=U;if(U.startsWith(":"))Z=!0,X=":";if(!G.children[X])G.children[X]=new B;if(G=G.children[X],G.isDynamic=Z,G.pattern=U,L===J.length-1)G.handler=[z.handler],G.method=[z.method],G.isEndOfWord=!0,G.path=F}}search(F,z){let G=this.root,J=F.split("/").filter(Boolean);for(let U of J){let Z=U;if(!G.children[Z])if(G.children[":"])G=G.children[":"];else return null;else G=G.children[Z]}let L=G.method.indexOf(z);if(G.isEndOfWord&&L!==-1)return{path:G.path,handler:G.handler[L],isDynamic:G.isDynamic,pattern:G.pattern,method:G.method[L]};return null}}function K(F,z,G){let J=new Headers,L={},U=!1,Z,X=null,_,$,E=200,Q={};return{req:F,server:z,url:G,getUser(){return Q},setUser(Y){if(Y)Q=Y},status(Y){return E=Y,this},getIP(){return this.server.requestIP(this.req)},async getBody(){if(!$)$=await N(F);if($.error)return new Response(JSON.stringify({error:$.error}),{status:400});return $},setHeader(Y,W){return J.set(Y,W),this},set(Y,W){return L[Y]=W,this},get(Y){return L[Y]||null},setAuth(Y){return U=Y,this},getAuth(){return U},text(Y,W){return new Response(Y,{status:W??E,headers:J})},send(Y,W){return new Response(Y,{status:W??E,headers:J})},json(Y,W){return new Response(JSON.stringify(Y),{status:W??E,headers:J})},html(Y,W){return new Response(Bun.file(Y),{status:W??E,headers:J})},file(Y,W){return new Response(Bun.file(Y),{status:W??E,headers:J})},redirect(Y,W){return J.set("Location",Y),new Response(null,{status:W??302,headers:J})},setCookie(Y,W,D={}){let V=`${encodeURIComponent(Y)}=${encodeURIComponent(W)}`;if(D.maxAge)V+=`; Max-Age=${D.maxAge}`;if(D.expires)V+=`; Expires=${D.expires.toUTCString()}`;if(D.path)V+=`; Path=${D.path}`;if(D.domain)V+=`; Domain=${D.domain}`;if(D.secure)V+="; Secure";if(D.httpOnly)V+="; HttpOnly";if(D.sameSite)V+=`; SameSite=${D.sameSite}`;return J?.append("Set-Cookie",V),this},getParams(Y){if(!_&&F?.routePattern)_=T(F?.routePattern,G?.pathname);return Y?_[Y]||{}:_},getQuery(Y){try{if(!Z)Z=Object.fromEntries(G.searchParams);return Y?Z[Y]||{}:Z}catch(W){return{}}},getCookie(Y){if(!X){let W=F.headers.get("cookie");if(W)X=I(W);else return null}if(!X)return null;if(Y)return X[Y]??null;else return X}}}function I(F){let z={},G=F?.split(";");for(let J=0;J<G?.length;J++){let[L,...U]=G[J].trim().split("="),Z=U?.join("=").trim();if(L)z[L.trim()]=decodeURIComponent(Z)}return z}function T(F,z){let G={},J=F.split("/"),[L]=z.split("?"),U=L.split("/");if(J.length!==U.length)return null;for(let Z=0;Z<J.length;Z++)if(J[Z].startsWith(":"))G[J[Z].slice(1)]=U[Z];return G}async function N(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(),J={};for(let[L,U]of G.entries())J[L]=U;return J}return{error:"Unknown request body type"}}catch(G){return{error:"Invalid request body format"}}}async function j(F,z,G,J){let L=J.trie.search(G.pathname,F.method);if(!L||L.method!==F.method){let X=L?"Method not allowed":`Route not found for ${G.pathname}`,_=L?405:404;return new Response(JSON.stringify({message:X}),{status:_})}if(L.isDynamic)F.routePattern=L.path;let U=K(F,z,G);if(J.corsConfig){let X=C(F,U,J.corsConfig);if(X)return X}if(J.hasOnReqHook&&J.hooks.onRequest)J.hooks.onRequest(F,G,z);if(J.hasFilterEnabled){let X=F.routePattern??G.pathname;if(!J.filters.has(X))if(J.filterFunction)try{let _=await J.filterFunction(U,z);if(_)return _}catch(_){return console.error("Error in filterFunction:",_),U.status(500).json({message:"Internal Server Error",error:_.message})}else return U.status(400).json({message:"Authentication required"})}if(J.hasMiddleware){let X=J.globalMiddlewares;for(let $=0;$<X.length;$++){let E=await X[$](U,z);if(E)return E}let _=J.middlewares.get(G.pathname)||[];for(let $=0;$<_.length;$++){let E=await _[$](U,z);if(E)return E}}if(J.hasPreHandlerHook&&J.hooks.preHandler){let X=await J.hooks.preHandler(U);if(X)return X}let Z=await L.handler(U);if(J.hasPostHandlerHook&&J.hooks.postHandler)await J.hooks.postHandler(U);if(J.hasOnSendHook&&J.hooks.onSend){let X=await J.hooks.onSend(U,Z);if(X)return X}return Z??U.status(204).json({message:"No response from this handler"})}function C(F,z,G={}){let J=F.headers.get("origin")??"*",L=G?.origin,U=G?.allowedHeaders??["Content-Type","Authorization"],Z=G?.methods??["GET","POST","PUT","DELETE","OPTIONS"],X=G?.credentials??!1,_=G?.exposedHeaders??[];if(z.setHeader("Access-Control-Allow-Methods",Z),z.setHeader("Access-Control-Allow-Headers",U),z.setHeader("Access-Control-Allow-Credentials",X),_.length)z.setHeader("Access-Control-Expose-Headers",_);if(L==="*")z.setHeader("Access-Control-Allow-Origin","*");else if(Array.isArray(L))if(J&&L.includes(J))z.setHeader("Access-Control-Allow-Origin",J);else if(L.includes("*"))z.setHeader("Access-Control-Allow-Origin","*");else return z.status(403).json({message:"CORS not allowed"});else if(typeof L==="string")if(J===L)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}class M{tempRoutes;globalMiddlewares;middlewares;trie;hasOnReqHook;hasMiddleware;hasPreHandlerHook;hasPostHandlerHook;hasOnSendHook;hasOnError;hooks;corsConfig;FilterRoutes;filters;filterFunction;hasFilterEnabled;constructor(){this.tempRoutes=new Map,this.globalMiddlewares=[],this.middlewares=new Map,this.trie=new A,this.corsConfig=null,this.hasMiddleware=!1,this.hasOnReqHook=!1,this.hasPreHandlerHook=!1,this.hasPostHandlerHook=!1,this.hasOnSendHook=!1,this.hasOnError=!1,this.hooks={onRequest:null,preHandler:null,postHandler:null,onSend:null,onError:null,onClose:null},this.FilterRoutes=[],this.filters=new Set,this.filterFunction=null,this.hasFilterEnabled=!1}filter(){return this.hasFilterEnabled=!0,{routeMatcher:(...F)=>{return this.FilterRoutes=F,this.filter()},permitAll:()=>{for(let F of this?.FilterRoutes)this.filters.add(F);return this.FilterRoutes=null,this.filter()},require:(F)=>{if(F)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");switch(F){case"onRequest":this.hooks.onRequest=z,this.hasOnReqHook=!0;break;case"preHandler":this.hooks.preHandler=z,this.hasPreHandlerHook=!0;break;case"postHandler":this.hooks.postHandler=z,this.hasPostHandlerHook=!0;break;case"onSend":this.hooks.onSend=z,this.hasOnSendHook=!0;break;case"onError":this.hooks.onError=z,this.hasOnError=!0;break;case"onClose":this.hooks.onClose=z;break;default: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;if(this.hooks.onError)this.hasOnError=!0;this.tempRoutes=new Map}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 L={port:F,fetch:async(Z,X)=>{let _=new URL(Z.url);try{return await j(Z,X,_,this)}catch($){if(this.hasOnError&&this.hooks.onError){let E=await this.hooks.onError($,Z,_,X);if(E)return E}return new Response(JSON.stringify({message:"Internal Server Error",error:$.message}),{status:500})}}};if(G&&J)L.certFile=G,L.keyFile=J;let U=Bun?.serve(L);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 U}route(F,z){if(!F||typeof F!=="string")throw new Error("Path must be a string");let G=Object.fromEntries(z.tempRoutes),J=Object.entries(G);for(let L=0;L<J.length;L++){let[U,Z]=J[L],X=`${F}${U}`;if(!this.middlewares.has(X))this.middlewares.set(X,[]);Z.handlers.slice(0,-1).forEach((Q)=>{if(!this.middlewares.get(X)?.includes(Q))this.middlewares.get(X)?.push(Q)});let $=Z.handlers[Z.handlers.length-1],E=Z.method;try{this.trie.insert(X,{handler:$,method:E})}catch(Q){console.error(`Error inserting ${X}:`,Q)}}z=null}register(F,z){this.route(F,z)}addRoute(F,z,G){if(typeof z!=="string")throw new Error("Path must be a string");if(typeof F!=="string")throw new Error("Method must be a string");this.tempRoutes.set(z,{method:F,handlers:G});let J=G.slice(0,-1),L=G[G.length-1];if(!this.middlewares.has(z))this.middlewares.set(z,[]);J.forEach((U)=>{if(z==="/")this.globalMiddlewares=[...new Set([...this.globalMiddlewares,...J])];else if(!this.middlewares.get(z)?.includes(U))this.middlewares.get(z)?.push(U)});try{this.trie.insert(z,{handler:L,method:F})}catch(U){console.error(`Error inserting ${z}:`,U)}}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.addRoute("GET",F,z),this}post(F,...z){return this.addRoute("POST",F,z),this}put(F,...z){return this.addRoute("PUT",F,z),this}patch(F,...z){return this.addRoute("PATCH",F,z),this}delete(F,...z){return this.addRoute("DELETE",F,z),this}}export{M as default};
|
package/dist/trie.d.ts
CHANGED
package/dist/trie.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
class
|
|
1
|
+
class E{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 F{root;constructor(){this.root=new E}insert(q,w){let b=this.root,z=q.split("/").filter(Boolean);if(q==="/"){b.isEndOfWord=!0,b.handler=[w.handler],b.path=q,b.method=[w.method];return}for(let j=0;j<z.length;j++){let A=z[j],B=!1,C=A;if(A.startsWith(":"))B=!0,C=":";if(!b.children[C])b.children[C]=new E;if(b=b.children[C],b.isDynamic=B,b.pattern=A,j===z.length-1)b.handler=[w.handler],b.method=[w.method],b.isEndOfWord=!0,b.path=q}}search(q,w){let b=this.root,z=q.split("/").filter(Boolean);for(let A of z){let B=A;if(!b.children[B])if(b.children[":"])b=b.children[":"];else return null;else b=b.children[B]}let j=b.method.indexOf(w);if(b.isEndOfWord&&j!==-1)return{path:b.path,handler:b.handler[j],isDynamic:b.isDynamic,pattern:b.pattern,method:b.method[j]};return null}}export{F as default};
|
package/dist/types.d.ts
CHANGED
|
@@ -2,34 +2,32 @@ import { Server } from "bun";
|
|
|
2
2
|
export type listenCalllBackType = () => void;
|
|
3
3
|
export type handlerFunction = (ctx: ContextType, server?: Server) => Response | Promise<Response | null | void>;
|
|
4
4
|
export type middlewareFunc = (ctx: ContextType, server?: Server | undefined) => null | void | Response | Promise<Response | void | null>;
|
|
5
|
-
export type HookFunction = (ctx: ContextType, result?: Response | null | void, server?: Server) => Response | Promise<Response | null | void
|
|
5
|
+
export type HookFunction = (ctx: ContextType, result?: Response | null | void, server?: Server) => Response | Promise<Response | null | void> | void;
|
|
6
6
|
export type HttpMethod = "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "OPTIONS" | "HEAD";
|
|
7
|
-
export
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
onClose = "onClose"
|
|
7
|
+
export type HookType = 'onRequest' | 'preHandler' | 'postHandler' | 'onSend' | 'onError' | 'onClose';
|
|
8
|
+
export interface onError {
|
|
9
|
+
(error: Error, req: Request, url: URL, server: Server): void | null | Response | Promise<Response | null | void>;
|
|
10
|
+
}
|
|
11
|
+
export interface onRequest {
|
|
12
|
+
(req: Request, url: URL, server: Server): void | null | Response | Promise<Response | null | void>;
|
|
14
13
|
}
|
|
15
14
|
export interface Hooks {
|
|
16
|
-
onRequest:
|
|
15
|
+
onRequest: onRequest | null;
|
|
17
16
|
preHandler: HookFunction | null;
|
|
18
17
|
postHandler: HookFunction | null;
|
|
19
18
|
onSend: HookFunction | null;
|
|
20
|
-
onError:
|
|
19
|
+
onError: onError | null;
|
|
21
20
|
onClose: HookFunction | null;
|
|
22
21
|
}
|
|
23
22
|
export interface ContextType {
|
|
24
23
|
req: Request;
|
|
25
24
|
server: Server;
|
|
26
25
|
url: URL;
|
|
27
|
-
next: () => void;
|
|
28
26
|
setUser: (data?: any) => void;
|
|
29
27
|
getUser: () => any;
|
|
30
28
|
status: (status: number) => this;
|
|
31
29
|
getIP: () => any;
|
|
32
|
-
|
|
30
|
+
getBody: () => Promise<any>;
|
|
33
31
|
setHeader: (key: string, value: any) => this;
|
|
34
32
|
set: (key: string, value: any) => this;
|
|
35
33
|
get: (key: string) => any;
|
|
@@ -37,12 +35,13 @@ export interface ContextType {
|
|
|
37
35
|
getAuth: () => boolean;
|
|
38
36
|
json: (data: Object, status?: number) => Response;
|
|
39
37
|
text: (data: string, status?: number) => Response;
|
|
38
|
+
send: (data: string, status?: number) => Response;
|
|
40
39
|
html: (filePath: string, status?: number) => Response;
|
|
41
40
|
file: (filePath: string, status?: number) => Response;
|
|
42
41
|
redirect: (path: string, status?: number) => Response;
|
|
43
42
|
getParams: (props?: any) => any;
|
|
44
43
|
getQuery: (props?: any) => any;
|
|
45
|
-
|
|
44
|
+
setCookie: (name: string, value: string, options?: CookieOptions) => this;
|
|
46
45
|
getCookie: (cookieName?: string) => any;
|
|
47
46
|
}
|
|
48
47
|
export interface CookieOptions {
|
|
@@ -72,12 +71,13 @@ export interface DieselT {
|
|
|
72
71
|
hasPostHandlerHook: boolean;
|
|
73
72
|
hasOnSendHook: boolean;
|
|
74
73
|
hooks: {
|
|
75
|
-
onRequest: ((
|
|
76
|
-
preHandler: ((ctx: ContextType, serer?: Server) => Promise<Response | void | null>) | null;
|
|
77
|
-
postHandler: ((ctx: ContextType, serer?: Server) => Promise<Response | void | null>) | null;
|
|
78
|
-
onSend: ((ctx?: ContextType, result?: Response | null | void, serer?: Server) => Promise<Response | void | null>) | null;
|
|
74
|
+
onRequest: ((req: Request, url: URL, serer: Server) => void) | null;
|
|
75
|
+
preHandler: ((ctx: ContextType, serer?: Server) => Response | Promise<Response | void | null>) | null;
|
|
76
|
+
postHandler: ((ctx: ContextType, serer?: Server) => Response | Promise<Response | void | null>) | null;
|
|
77
|
+
onSend: ((ctx?: ContextType, result?: Response | null | void, serer?: Server) => Response | Promise<Response | void | null>) | null;
|
|
78
|
+
onError: ((error: Error, req: Request, url: URL, server?: Server) => void | Response | Promise<Response | null | void>) | null;
|
|
79
79
|
};
|
|
80
|
-
filters: string
|
|
80
|
+
filters: Set<string>;
|
|
81
81
|
hasFilterEnabled: boolean;
|
|
82
82
|
filterFunction: (ctx: ContextType, serer?: Server) => void | Response | Promise<Response | void | null>;
|
|
83
83
|
corsConfig: corsT | null;
|
|
@@ -93,6 +93,7 @@ export interface RouteCache {
|
|
|
93
93
|
declare global {
|
|
94
94
|
interface Request {
|
|
95
95
|
routePattern?: string;
|
|
96
|
+
[key: string]: any;
|
|
96
97
|
}
|
|
97
98
|
}
|
|
98
99
|
export interface ParseBodyResult {
|
package/dist/utils.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
function H(v){let{time:z=60000,max:A=100,message:C="Rate limit exceeded. Please try again later."}=v,j=new Map;return(
|
|
1
|
+
function H(v){let{time:z=60000,max:A=100,message:C="Rate limit exceeded. Please try again later."}=v,j=new Map;return(F)=>{let D=new Date,E=F.getIP().address;if(!j.has(E))j.set(E,{count:0,startTime:D});let l=j.get(E);if(l)if(D-l.startTime>z)l.count=1,l.startTime=D;else l.count++;if(l&&l.count>A)return F.status(429).json({error:C})}}var G=(v,z,A,C)=>{if(A>C)return!1;let j=A+(C-A)/2;if(v[j]==z)return!0;if(v[j]>z)return G(v,z,A,j-1);return G(v,z,j+1,C)};export{H as default,G as binaryS};
|
package/example/main.ts
CHANGED
|
@@ -1,69 +1,74 @@
|
|
|
1
|
+
import Diesel from "../src/main";
|
|
2
|
+
import jwt from "jsonwebtoken";
|
|
3
|
+
import { ContextType, CookieOptions, HookType, middlewareFunc } from "../src/types";
|
|
1
4
|
import { Server } from "bun";
|
|
2
|
-
import Diesel, { rateLimit } from "../dist/main";
|
|
3
|
-
import jwt from 'jsonwebtoken'
|
|
4
|
-
import { ContextType, CookieOptions, middlewareFunc } from "../dist/types";
|
|
5
5
|
|
|
6
6
|
const app = new Diesel()
|
|
7
|
-
const secret =
|
|
7
|
+
const secret = "linux";
|
|
8
|
+
|
|
8
9
|
// app.cors({
|
|
9
10
|
// origin: ['http://localhost:5173','*'],
|
|
10
11
|
// methods: 'GET,POST,PUT,DELETE',
|
|
11
12
|
// allowedHeaders: 'Content-Type,Authorization'
|
|
12
13
|
// })
|
|
13
14
|
|
|
14
|
-
async function authJwt(ctx: ContextType
|
|
15
|
-
|
|
15
|
+
export async function authJwt(ctx: ContextType): Promise<void | null | Response> {
|
|
16
|
+
|
|
17
|
+
const token = ctx.getCookie("accessToken");
|
|
18
|
+
if (!token) {
|
|
19
|
+
return ctx.status(401).json({ message: "Authentication token missing" });
|
|
20
|
+
}
|
|
16
21
|
try {
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
if (!token) {
|
|
20
|
-
return ctx.status(401).json({ message: "Authentication token missing" });
|
|
21
|
-
}
|
|
22
|
-
// Verify the JWT token using a secret key
|
|
23
|
-
const user = jwt.verify(token, secret); // Replace with your JWT secret
|
|
24
|
-
// Set the user data in context
|
|
25
|
-
ctx.setUser(user)
|
|
22
|
+
const user = await jwt.verify(token, secret); // Replace with your JWT secret
|
|
23
|
+
ctx.setUser(user);
|
|
26
24
|
} catch (error) {
|
|
27
25
|
return ctx.status(403).json({ message: "Invalid token" });
|
|
28
26
|
}
|
|
29
27
|
}
|
|
30
28
|
|
|
31
|
-
const limiter = rateLimit({
|
|
32
|
-
time: 60000, // Time window in milliseconds (e.g., 1 minute)
|
|
33
|
-
max: 10, // Maximum number of requests allowed in the time window
|
|
34
|
-
message: "Rate limit exceeded. Please try again later." // Custom error message
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
// app.use(limiter)
|
|
38
|
-
|
|
39
29
|
app
|
|
40
30
|
.filter()
|
|
41
|
-
.routeMatcher(
|
|
31
|
+
.routeMatcher("/cookie",'/api/user/login','api/user/register')
|
|
42
32
|
.permitAll()
|
|
43
|
-
.require(authJwt as middlewareFunc)
|
|
33
|
+
.require(authJwt as middlewareFunc);
|
|
34
|
+
|
|
44
35
|
|
|
45
|
-
|
|
36
|
+
app.addHooks('onError', (error: any, req: Request, url: URL, server: Server) => {
|
|
37
|
+
console.error(`Error occurred: ${error.message}`);
|
|
38
|
+
console.error(`Request Method: ${req.method}, Request URL: ${url}`);
|
|
39
|
+
// return new Response('Internal Server Error', { status: 500 }); // You can customize the response as needed
|
|
40
|
+
});
|
|
46
41
|
|
|
47
|
-
// .require(you can pass jwt auth parser)
|
|
48
42
|
|
|
49
|
-
app.get("/", async (
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
// const user = xl.get('user')
|
|
53
|
-
const q = xl.getUser()
|
|
43
|
+
app.get("/error", async () => {
|
|
44
|
+
throw new Error("This is a test error to demonstrate error handling");
|
|
45
|
+
});
|
|
54
46
|
|
|
55
|
-
|
|
47
|
+
app.get("/", async (xl) => {
|
|
48
|
+
const user = xl.getUser();
|
|
49
|
+
return xl.json({
|
|
50
|
+
user,
|
|
51
|
+
});
|
|
56
52
|
});
|
|
57
53
|
|
|
58
|
-
app.get("/
|
|
54
|
+
app.get("/api/user/u",(ctx) => {
|
|
55
|
+
return ctx.text("j")
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
// app.post("/",async (ctx) => {
|
|
59
|
+
// const body = await ctx.getBody()
|
|
60
|
+
// return ctx.json(body)
|
|
61
|
+
// })
|
|
62
|
+
|
|
63
|
+
app.get("/test/:id/:name", async (xl) => {
|
|
59
64
|
const q = xl.getQuery();
|
|
60
|
-
const params = xl.getParams(
|
|
65
|
+
const params = xl.getParams();
|
|
61
66
|
return new Response(JSON.stringify({ msg: "hello world", q, params }));
|
|
62
67
|
});
|
|
63
68
|
|
|
64
69
|
app.get("/ok", (xl) => {
|
|
65
|
-
return xl.status(200).text("kaise ho??")
|
|
66
|
-
})
|
|
70
|
+
return xl.status(200).text("kaise ho??");
|
|
71
|
+
});
|
|
67
72
|
|
|
68
73
|
app.get("/cookie", async (xl) => {
|
|
69
74
|
const user = {
|
|
@@ -80,12 +85,18 @@ app.get("/cookie", async (xl) => {
|
|
|
80
85
|
sameSite: "Strict", // Prevents CSRF (strict origin policy)
|
|
81
86
|
path: "/", // Cookie available for all routes
|
|
82
87
|
};
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
88
|
+
|
|
89
|
+
return (
|
|
90
|
+
xl
|
|
91
|
+
.setCookie("accessToken", accessToken, options)
|
|
92
|
+
.setCookie("refreshToken", refreshToken, options)
|
|
93
|
+
.json({ msg: "setting cookies" })
|
|
94
|
+
);
|
|
95
|
+
|
|
87
96
|
});
|
|
88
97
|
|
|
98
|
+
import {userRoute} from './route'
|
|
89
99
|
|
|
100
|
+
app.register("/api/user",userRoute)
|
|
90
101
|
|
|
91
|
-
app.listen(3000)
|
|
102
|
+
app.listen(3000);
|
package/example/route.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import Diesel from "../src/main";
|
|
2
|
+
import Router from "../src/route";
|
|
3
|
+
import { authJwt } from "./main";
|
|
4
|
+
|
|
5
|
+
const userRoute = new Router();
|
|
6
|
+
|
|
7
|
+
const h = () => {
|
|
8
|
+
console.log('object');
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const s = () =>{
|
|
12
|
+
console.log('s')
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
userRoute.get("/register/:id",(xl) => {
|
|
16
|
+
return xl.text("from register user");
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
userRoute.get("/login",(xl)=>{
|
|
20
|
+
return new Response("hello loin")
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
const newRoute = new Diesel()
|
|
24
|
+
|
|
25
|
+
newRoute.get("/login",(xl)=>{
|
|
26
|
+
return xl.json({message:"from login"})
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
newRoute.get("/tetet",(ctx) =>{
|
|
30
|
+
return ctx.text("from tetet")
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
newRoute.get("/register/:id",(xl) => {
|
|
34
|
+
const param = xl.getParams("id")
|
|
35
|
+
return xl.json({message:"from register",param})
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
export {
|
|
39
|
+
userRoute,newRoute
|
|
40
|
+
}
|