diesel-core 0.0.13 → 0.0.15
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 +91 -7
- package/build.js +10 -8
- package/dist/main.d.ts +4 -2
- package/dist/route.d.ts +11 -0
- package/dist/types.d.ts +4 -1
- package/example/bun.lockb +0 -0
- package/example/main.ts +21 -19
- package/example/package.json +1 -1
- package/example/route.js +2 -2
- package/example/tester.js +3 -1
- package/package.json +1 -1
- package/src/ctx.ts +15 -4
- package/src/handleRequest.ts +19 -20
- package/src/main.ts +22 -19
- package/src/route.ts +56 -0
- package/src/trie.ts +5 -3
- package/src/types.ts +4 -1
- package/tsconfig.json +3 -2
- package/src/router.ts +0 -55
package/CONTRIBUTING.md
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
if you changes code OR fixing bugs so after doing make sure to run bun build.js
|
|
1
|
+
if you changes code OR fixing bugs so after doing make sure to run tsc and bun build.js
|
package/README.md
CHANGED
|
@@ -19,13 +19,13 @@ bun add diesel-core
|
|
|
19
19
|
|
|
20
20
|
### Code Example
|
|
21
21
|
```javascript
|
|
22
|
-
import
|
|
22
|
+
import Diesel from "diesel-core"
|
|
23
23
|
|
|
24
24
|
const app = new Diesel()
|
|
25
25
|
const port = 3000
|
|
26
26
|
|
|
27
|
-
app.get("/", async (
|
|
28
|
-
return
|
|
27
|
+
app.get("/", async (ctx:ContextType) => {
|
|
28
|
+
return ctx.status(200).text("Hello world...!")
|
|
29
29
|
// OR
|
|
30
30
|
// return xl.text("Hello world!")
|
|
31
31
|
// OR
|
|
@@ -38,11 +38,95 @@ app.listen(port, () => {
|
|
|
38
38
|
})
|
|
39
39
|
|
|
40
40
|
```
|
|
41
|
+
## Filter and Route Security
|
|
42
|
+
**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
|
+
|
|
44
|
+
### How to Use the Filter
|
|
45
|
+
The **filter()** method allows you to secure certain endpoints while keeping others public. You can specify routes that should be publicly accessible using permitAll(), and apply authentication or other middleware to the remaining routes with require().
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
### Example Usage
|
|
49
|
+
```javascript
|
|
50
|
+
import Diesel from "diesel-core";
|
|
51
|
+
import jwt from 'jsonwebtoken';
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
const app = new Diesel();
|
|
55
|
+
|
|
56
|
+
async function authJwt (xl:ContextType, server?:Server): Promise<void | Response> {
|
|
57
|
+
const token = await xl.getCookie("accessToken"); // Retrieve the JWT token from cookies
|
|
58
|
+
if (!token) {
|
|
59
|
+
return xl.status(401).json({ message: "Authentication token missing" });
|
|
60
|
+
}
|
|
61
|
+
try {
|
|
62
|
+
// Verify the JWT token using a secret key
|
|
63
|
+
const user = jwt.verify(token, secret); // Replace with your JWT secret
|
|
64
|
+
// Set the user data in context
|
|
65
|
+
xl.setUser(user);
|
|
66
|
+
|
|
67
|
+
// Proceed to the next middleware/route handler
|
|
68
|
+
return xl.next();
|
|
69
|
+
} catch (error) {
|
|
70
|
+
return xl.status(403).json({ message: "Invalid token" });
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Define routes and apply filter
|
|
75
|
+
app
|
|
76
|
+
.filter()
|
|
77
|
+
.routeMatcher('/api/user/register', '/api/user/login', '/test/:id', '/cookie') // Define public routes
|
|
78
|
+
.permitAll() // Mark these routes as public (no auth required)
|
|
79
|
+
.require(authJwt); // Apply the authJwt middleware to all other routes
|
|
80
|
+
|
|
81
|
+
// Example public route (no auth required)
|
|
82
|
+
app.get("/api/user/register", async (xl) => {
|
|
83
|
+
return xl.json({ msg: "This is a public route. No authentication needed." });
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
// Example protected route (requires auth)
|
|
87
|
+
app.get("/api/user/profile", async (xl) => {
|
|
88
|
+
// This route is protected, so the auth middleware will run before this handler
|
|
89
|
+
const user = xl.getUser()
|
|
90
|
+
return xl.json({
|
|
91
|
+
msg: "You are authenticated!" ,
|
|
92
|
+
user
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
// Start the server
|
|
97
|
+
const port = 3000;
|
|
98
|
+
app.listen(port, () => {
|
|
99
|
+
console.log(`Diesel is running on port ${port}`);
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
```
|
|
103
|
+
## Filter Methods
|
|
104
|
+
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
|
+
|
|
106
|
+
```javascript
|
|
107
|
+
.routeMatcher('/api/user/register', '/api/user/login', '/test/:id')
|
|
108
|
+
```
|
|
109
|
+
1. **permitAll()** : Marks the routes specified in routeMatcher() as publicly accessible, meaning no middleware (like authentication) will be required for these routes.
|
|
110
|
+
|
|
111
|
+
```javascript
|
|
112
|
+
.permitAll()
|
|
113
|
+
```
|
|
114
|
+
1. **require(fnc?: middlewareFunc)** :Means that defined routes in ***routeMatcher*** is public & All endpoints needs authentication.
|
|
115
|
+
|
|
116
|
+
*Note* : If you don't pass a middleware function to require(), DieselJS will throw an "Unauthorized" error by default. Ensure that you implement and pass a valid authentication function
|
|
117
|
+
```javascript
|
|
118
|
+
.require(authJwt)
|
|
119
|
+
```
|
|
120
|
+
## Use Case
|
|
121
|
+
* **Public Routes** : Some routes ***(like /api/user/register or /api/user/login)*** are often open to all users without authentication. These routes can be specified with permitAll().
|
|
122
|
+
|
|
123
|
+
* **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.
|
|
41
124
|
|
|
42
125
|
## Using Hooks in DieselJS
|
|
43
126
|
|
|
44
127
|
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
128
|
|
|
129
|
+
|
|
46
130
|
### Available Hooks
|
|
47
131
|
|
|
48
132
|
1. **onRequest**: Triggered when a request is received.
|
|
@@ -65,19 +149,19 @@ app.addHooks("onRequest",(xl) =>{
|
|
|
65
149
|
// Define a preHandler hook
|
|
66
150
|
app.addHooks("preHandler",(xl) =>{
|
|
67
151
|
// Check for authentication token
|
|
68
|
-
const authToken =
|
|
152
|
+
const authToken = xl.req.headers.get("Authorization");
|
|
69
153
|
if (!authToken) {
|
|
70
154
|
return new Response("Unauthorized", { status: 401 });
|
|
71
155
|
}
|
|
72
156
|
})
|
|
73
157
|
|
|
74
158
|
// Define a postHandler hook
|
|
75
|
-
app.addHooks('postHandler', async (
|
|
76
|
-
console.log(`Response sent for: ${
|
|
159
|
+
app.addHooks('postHandler', async (xl) => {
|
|
160
|
+
console.log(`Response sent for: ${xl.req.url}`);
|
|
77
161
|
});
|
|
78
162
|
|
|
79
163
|
// Define an onSend hook
|
|
80
|
-
app.addHooks('onSend',async (
|
|
164
|
+
app.addHooks('onSend',async (xl, result) => {
|
|
81
165
|
console.log(`Sending response with status: ${result.status}`);
|
|
82
166
|
return result; // You can modify the response here if needed
|
|
83
167
|
});
|
package/build.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
//
|
|
2
|
-
|
|
1
|
+
// tsc will create main folder
|
|
2
|
+
Bun.build({
|
|
3
3
|
entrypoints: [
|
|
4
|
-
'./
|
|
5
|
-
'./
|
|
6
|
-
'./
|
|
7
|
-
'./
|
|
8
|
-
'./
|
|
4
|
+
'./main/main.ts',
|
|
5
|
+
'./main/ctx.ts',
|
|
6
|
+
'./main/handleRequest.ts',
|
|
7
|
+
'./main/trie.ts',
|
|
8
|
+
'./main/router.ts'
|
|
9
9
|
],
|
|
10
10
|
outdir: './dist',
|
|
11
11
|
minify: true, // Enable minification
|
|
12
|
-
})
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
await Bun.spawn(['rm', '-rf', './main']);
|
package/dist/main.d.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import Trie from "./trie.js";
|
|
2
2
|
import rateLimit from "./utils.js";
|
|
3
|
-
import { corsT, FilterMethods, HookFunction, HookType, middlewareFunc, type handlerFunction, type Hooks, type listenCalllBackType } from "./types.js";
|
|
3
|
+
import { corsT, FilterMethods, HookFunction, HookType, middlewareFunc, type handlerFunction, type Hooks, type HttpMethod, type listenCalllBackType } from "./types.js";
|
|
4
4
|
import { Server } from "bun";
|
|
5
5
|
export default class Diesel {
|
|
6
|
-
#private;
|
|
7
6
|
routes: string[] | undefined;
|
|
8
7
|
globalMiddlewares: middlewareFunc[];
|
|
9
8
|
middlewares: Map<string, middlewareFunc[]>;
|
|
@@ -17,6 +16,8 @@ export default class Diesel {
|
|
|
17
16
|
corsConfig: corsT;
|
|
18
17
|
filters: string[];
|
|
19
18
|
filterFunction: middlewareFunc | null;
|
|
19
|
+
hasFilterEnabled: boolean;
|
|
20
|
+
wss: WebSocket | null | undefined;
|
|
20
21
|
constructor();
|
|
21
22
|
filter(): FilterMethods;
|
|
22
23
|
cors(corsConfig: corsT): void;
|
|
@@ -24,6 +25,7 @@ export default class Diesel {
|
|
|
24
25
|
compile(): void;
|
|
25
26
|
listen(port: number, callback?: listenCalllBackType, { sslCert, sslKey }?: any): Server | void;
|
|
26
27
|
register(pathPrefix: string, handlerInstance: any): void;
|
|
28
|
+
addRoute(method: HttpMethod, path: string, handlers: handlerFunction[]): void;
|
|
27
29
|
use(pathORHandler?: string | middlewareFunc, handler?: middlewareFunc): void;
|
|
28
30
|
get(path: string, ...handlers: handlerFunction[]): this;
|
|
29
31
|
post(path: string, ...handlers: handlerFunction[]): this;
|
package/dist/route.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import Diesel from "./main";
|
|
2
|
+
import type { handlerFunction } from "./types";
|
|
3
|
+
declare class Router extends Diesel {
|
|
4
|
+
constructor();
|
|
5
|
+
get(path: string, ...handlers: handlerFunction[]): this;
|
|
6
|
+
post(path: string, ...handlers: handlerFunction[]): this;
|
|
7
|
+
put(path: string, ...handlers: handlerFunction[]): this;
|
|
8
|
+
patch(path: string, ...handlers: handlerFunction[]): this;
|
|
9
|
+
delete(path: string, ...handlers: handlerFunction[]): this;
|
|
10
|
+
}
|
|
11
|
+
export default Router;
|
package/dist/types.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
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
|
-
export type middlewareFunc = (ctx: ContextType, server?: Server) => void | Response | Promise<Response>;
|
|
4
|
+
export type middlewareFunc = (ctx: ContextType, server?: Server | undefined) => void | Response | Promise<Response>;
|
|
5
5
|
export type HookFunction = (ctx: ContextType, result?: Response | null | void, server?: Server) => Response | Promise<Response | null | void>;
|
|
6
6
|
export type HttpMethod = "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "OPTIONS" | "HEAD";
|
|
7
7
|
export declare enum HookType {
|
|
@@ -25,6 +25,8 @@ export interface ContextType {
|
|
|
25
25
|
server: Server;
|
|
26
26
|
url: URL;
|
|
27
27
|
next: () => void;
|
|
28
|
+
setUser: (data?: any) => void;
|
|
29
|
+
getUser: () => any;
|
|
28
30
|
status: (status: number) => this;
|
|
29
31
|
getIP: () => any;
|
|
30
32
|
body: () => Promise<any>;
|
|
@@ -76,6 +78,7 @@ export interface DieselT {
|
|
|
76
78
|
onSend: ((ctx?: ContextType, result?: Response | null | void, serer?: Server) => Promise<Response | void | null>) | null;
|
|
77
79
|
};
|
|
78
80
|
filters: string[];
|
|
81
|
+
hasFilterEnabled: boolean;
|
|
79
82
|
filterFunction: (ctx: ContextType, serer?: Server) => void | Response | Promise<Response | void>;
|
|
80
83
|
corsConfig: corsT | null;
|
|
81
84
|
globalMiddlewares: Array<(ctx: ContextType, serer?: Server) => void | Promise<Response | null | void>>;
|
package/example/bun.lockb
CHANGED
|
Binary file
|
package/example/main.ts
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Server } from "bun";
|
|
2
|
+
import Diesel ,{rateLimit} from "../src/main";
|
|
3
|
+
import { ContextType, CookieOptions, middlewareFunc } from "../dist/types";
|
|
2
4
|
import jwt from 'jsonwebtoken'
|
|
3
5
|
|
|
4
6
|
const app = new Diesel()
|
|
5
|
-
const secret = '
|
|
7
|
+
const secret = 'pradeep'
|
|
6
8
|
// app.cors({
|
|
7
9
|
// origin: ['http://localhost:5173','*'],
|
|
8
10
|
// methods: 'GET,POST,PUT,DELETE',
|
|
9
11
|
// allowedHeaders: 'Content-Type,Authorization'
|
|
10
12
|
// })
|
|
11
13
|
|
|
12
|
-
async function authJwt(ctx:
|
|
14
|
+
async function authJwt (ctx:ContextType, server?:Server): Promise<void | Response> {
|
|
13
15
|
const token = await ctx.getCookie("accessToken"); // Retrieve the JWT token from cookies
|
|
14
16
|
if (!token) {
|
|
15
17
|
return ctx.status(401).json({ message: "Authentication token missing" });
|
|
@@ -17,9 +19,8 @@ async function authJwt(ctx:any, server:any) {
|
|
|
17
19
|
try {
|
|
18
20
|
// Verify the JWT token using a secret key
|
|
19
21
|
const user = jwt.verify(token, secret); // Replace with your JWT secret
|
|
20
|
-
console.log(user)
|
|
21
22
|
// Set the user data in context
|
|
22
|
-
ctx.
|
|
23
|
+
ctx.setUser(user);
|
|
23
24
|
|
|
24
25
|
// Proceed to the next middleware/route handler
|
|
25
26
|
return ctx.next();
|
|
@@ -36,23 +37,22 @@ const limiter = rateLimit({
|
|
|
36
37
|
// app.use(h)
|
|
37
38
|
// app.use(limiter)
|
|
38
39
|
|
|
39
|
-
app
|
|
40
|
-
.filter()
|
|
41
|
-
.routeMatcher('/api/user/register','/api/user/login','/test/:id','/cookie')
|
|
42
|
-
.permitAll()
|
|
43
|
-
.require(authJwt)
|
|
40
|
+
// app
|
|
41
|
+
// .filter()
|
|
42
|
+
// .routeMatcher('/api/user/register','/api/user/login','/test/:id','/cookie')
|
|
43
|
+
// .permitAll()
|
|
44
|
+
// .require(authJwt as middlewareFunc)
|
|
45
|
+
|
|
46
|
+
// app.use(authJwt)
|
|
44
47
|
|
|
45
48
|
// .require(you can pass jwt auth parser)
|
|
46
49
|
|
|
47
50
|
app.get("/", async(xl) => {
|
|
48
|
-
// const ip = xl.req
|
|
49
|
-
// console.log(ip)
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
app: 'Express App',
|
|
54
|
-
features: ['Fast', 'Flexible', 'Lightweight']
|
|
55
|
-
});
|
|
51
|
+
// // const ip = xl.req
|
|
52
|
+
// // console.log(ip)
|
|
53
|
+
// const user = xl.getUser()
|
|
54
|
+
// return xl.json({user:user});
|
|
55
|
+
return xl.status(200).text("hello world")
|
|
56
56
|
});
|
|
57
57
|
|
|
58
58
|
app.get("/test/:id", async (xl) => {
|
|
@@ -73,7 +73,7 @@ app.get("/test/:id", async (xl) => {
|
|
|
73
73
|
|
|
74
74
|
const accessToken = jwt.sign(user, secret, { expiresIn: "1d" });
|
|
75
75
|
const refreshToken = jwt.sign(user, secret, { expiresIn: "10d" });
|
|
76
|
-
const options = {
|
|
76
|
+
const options : CookieOptions= {
|
|
77
77
|
httpOnly: true, // Makes cookie accessible only by the web server (not JS)
|
|
78
78
|
secure: true, // Ensures the cookie is sent over HTTPS
|
|
79
79
|
maxAge: 24 * 60 * 60 * 1000, // 1 day in milliseconds
|
|
@@ -87,4 +87,6 @@ app.get("/test/:id", async (xl) => {
|
|
|
87
87
|
return xl.json({msg:"setting cookies"})
|
|
88
88
|
});
|
|
89
89
|
|
|
90
|
+
|
|
91
|
+
|
|
90
92
|
app.listen(3000)
|
package/example/package.json
CHANGED
package/example/route.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import Router from "../src/
|
|
1
|
+
import Router from "../src/route";
|
|
2
2
|
|
|
3
3
|
const route = new Router();
|
|
4
4
|
|
|
@@ -10,7 +10,7 @@ const s = () =>{
|
|
|
10
10
|
console.log('s')
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
route.get("/register", h,(xl) => {
|
|
13
|
+
route.get("/register/:id", h,(xl) => {
|
|
14
14
|
return xl.text("from register user");
|
|
15
15
|
})
|
|
16
16
|
|
package/example/tester.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import
|
|
1
|
+
import Diesel from "../dist/main";
|
|
2
2
|
import jwt from "jsonwebtoken";
|
|
3
3
|
|
|
4
4
|
const app = new Diesel();
|
|
5
5
|
const secret = "secret";
|
|
6
6
|
|
|
7
|
+
// app.filter().permitAll().require()
|
|
8
|
+
|
|
7
9
|
app.get("/r", (xl) => {
|
|
8
10
|
return xl.html(`${import.meta.dir}/index.html`);
|
|
9
11
|
});
|
package/package.json
CHANGED
package/src/ctx.ts
CHANGED
|
@@ -5,11 +5,12 @@ export default function createCtx(req: Request, server:Server ,url: URL): Contex
|
|
|
5
5
|
let headers: Headers = new Headers()
|
|
6
6
|
let settedValue: Record<string, string> = {};
|
|
7
7
|
let isAuthenticated: boolean = false;
|
|
8
|
-
let parsedQuery: any =
|
|
9
|
-
let parsedCookie: any =
|
|
10
|
-
let parsedParams: any =
|
|
8
|
+
let parsedQuery: any = {};
|
|
9
|
+
let parsedCookie: any = {}
|
|
10
|
+
let parsedParams: any = {};
|
|
11
11
|
let parsedBody: ParseBodyResult | null;
|
|
12
12
|
let responseStatus: number = 200;
|
|
13
|
+
let user : any = {}
|
|
13
14
|
|
|
14
15
|
return {
|
|
15
16
|
req,
|
|
@@ -17,6 +18,16 @@ export default function createCtx(req: Request, server:Server ,url: URL): Contex
|
|
|
17
18
|
url,
|
|
18
19
|
next: () => { },
|
|
19
20
|
|
|
21
|
+
getUser(){
|
|
22
|
+
return user
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
setUser(data?:any){
|
|
26
|
+
if (data) {
|
|
27
|
+
user = data
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
|
|
20
31
|
// Set response status for chaining
|
|
21
32
|
status(status: number): ContextType {
|
|
22
33
|
responseStatus = status;
|
|
@@ -135,7 +146,7 @@ export default function createCtx(req: Request, server:Server ,url: URL): Contex
|
|
|
135
146
|
async getCookie(cookieName?: string)
|
|
136
147
|
: Promise<string | Record<string, string> | null> {
|
|
137
148
|
if (!parsedCookie) {
|
|
138
|
-
const cookieHeader = req.headers
|
|
149
|
+
const cookieHeader = req.headers?.get("cookie")
|
|
139
150
|
if (cookieHeader) {
|
|
140
151
|
parsedCookie = await parseCookie(cookieHeader);
|
|
141
152
|
}
|
package/src/handleRequest.ts
CHANGED
|
@@ -1,23 +1,14 @@
|
|
|
1
1
|
import { Server } from "bun";
|
|
2
2
|
import createCtx from "./ctx";
|
|
3
|
-
import type { ContextType, corsT, DieselT,
|
|
4
|
-
import { binaryS } from "./utils";
|
|
5
|
-
|
|
6
|
-
// const routeCache:RouteCache = {}
|
|
3
|
+
import type { ContextType, corsT, DieselT, middlewareFunc, RouteHandlerT } from "./types";
|
|
7
4
|
|
|
8
5
|
export default async function handleRequest(req: Request, server: Server, url: URL, diesel: DieselT): Promise<Response> {
|
|
9
6
|
|
|
10
|
-
const ctx: ContextType = createCtx(req, server, url);
|
|
11
7
|
|
|
12
|
-
// Try to find the route handler in the trie
|
|
13
|
-
let routeHandler: RouteHandlerT | undefined = diesel.trie.search(url.pathname, req.method);;
|
|
14
|
-
// if(routeCache[url.pathname+req.method]) {
|
|
15
|
-
// routeHandler = routeCache[url.pathname+req.method]
|
|
16
|
-
// } else {
|
|
17
|
-
// routeHandler = diesel.trie.search(url.pathname, req.method);
|
|
18
|
-
// routeCache[url.pathname+req.method]=routeHandler
|
|
19
|
-
// }
|
|
20
8
|
|
|
9
|
+
// Try to find the route handler in the trie
|
|
10
|
+
const routeHandler: RouteHandlerT | undefined = diesel.trie.search(url.pathname, req.method);
|
|
11
|
+
|
|
21
12
|
// Early return if route or method is not found
|
|
22
13
|
if (!routeHandler || routeHandler.method !== req.method) {
|
|
23
14
|
return new Response(routeHandler ? "Method not allowed" : `Route not found for ${url.pathname}`, {
|
|
@@ -28,27 +19,35 @@ export default async function handleRequest(req: Request, server: Server, url: U
|
|
|
28
19
|
// If the route is dynamic, we only set routePattern if necessary
|
|
29
20
|
if (routeHandler.isDynamic) req.routePattern = routeHandler.path;
|
|
30
21
|
|
|
22
|
+
// create the context which contains the methods Req,Res, many more
|
|
23
|
+
const ctx: ContextType = createCtx(req, server, url);
|
|
24
|
+
|
|
31
25
|
// cors execution
|
|
32
26
|
if (diesel.corsConfig) {
|
|
33
27
|
const corsResult = await applyCors(req, ctx, diesel.corsConfig)
|
|
34
|
-
if(corsResult) return corsResult;
|
|
28
|
+
if (corsResult) return corsResult;
|
|
35
29
|
}
|
|
36
30
|
|
|
37
31
|
// OnReq hook 1
|
|
38
32
|
if (diesel.hasOnReqHook && diesel.hooks.onRequest) diesel.hooks.onRequest(ctx, server)
|
|
39
33
|
|
|
40
34
|
// filter applying
|
|
41
|
-
if (diesel.
|
|
35
|
+
if (diesel.hasFilterEnabled) {
|
|
42
36
|
|
|
43
37
|
const path = req.routePattern ?? url.pathname
|
|
44
38
|
const hasRoute = diesel.filters.includes(path)
|
|
45
|
-
|
|
46
39
|
if (hasRoute === false) {
|
|
47
40
|
if (diesel.filterFunction) {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
41
|
+
try {
|
|
42
|
+
const filterResult = await diesel.filterFunction(ctx, server)
|
|
43
|
+
if (filterResult) return filterResult
|
|
44
|
+
} catch (error) {
|
|
45
|
+
console.error("Error in filterFunction:", error);
|
|
46
|
+
return new Response(JSON.stringify({
|
|
47
|
+
message: "Internal Server Error"
|
|
48
|
+
}), { status: 500 });
|
|
49
|
+
}
|
|
50
|
+
} else {
|
|
52
51
|
return new Response(JSON.stringify({
|
|
53
52
|
message: "Authentication required"
|
|
54
53
|
}), { status: 400 })
|
package/src/main.ts
CHANGED
|
@@ -3,6 +3,7 @@ import handleRequest from "./handleRequest.js";
|
|
|
3
3
|
import rateLimit from "./utils.js";
|
|
4
4
|
import {
|
|
5
5
|
corsT,
|
|
6
|
+
DieselT,
|
|
6
7
|
FilterMethods,
|
|
7
8
|
HookFunction,
|
|
8
9
|
HookType,
|
|
@@ -17,6 +18,7 @@ import { Server } from "bun";
|
|
|
17
18
|
|
|
18
19
|
|
|
19
20
|
export default class Diesel {
|
|
21
|
+
|
|
20
22
|
routes : string[] | undefined
|
|
21
23
|
globalMiddlewares: middlewareFunc[]
|
|
22
24
|
middlewares: Map<string, middlewareFunc[]>;
|
|
@@ -30,11 +32,11 @@ export default class Diesel {
|
|
|
30
32
|
corsConfig: corsT
|
|
31
33
|
filters: string[]
|
|
32
34
|
filterFunction : middlewareFunc | null
|
|
35
|
+
hasFilterEnabled: boolean
|
|
36
|
+
wss : WebSocket | null | undefined
|
|
33
37
|
|
|
34
38
|
constructor() {
|
|
35
39
|
this.routes = []
|
|
36
|
-
this.filters = []
|
|
37
|
-
this.filterFunction = null
|
|
38
40
|
this.globalMiddlewares = [];
|
|
39
41
|
this.middlewares = new Map();
|
|
40
42
|
this.trie = new Trie();
|
|
@@ -52,10 +54,15 @@ export default class Diesel {
|
|
|
52
54
|
onError: null,
|
|
53
55
|
onClose: null
|
|
54
56
|
}
|
|
57
|
+
this.filters = []
|
|
58
|
+
this.filterFunction = null
|
|
59
|
+
this.hasFilterEnabled = false
|
|
60
|
+
this.wss = null
|
|
55
61
|
}
|
|
56
62
|
|
|
57
63
|
|
|
58
64
|
filter() :FilterMethods {
|
|
65
|
+
this.hasFilterEnabled = true
|
|
59
66
|
|
|
60
67
|
return {
|
|
61
68
|
routeMatcher: (...routes:string[]) => {
|
|
@@ -67,17 +74,13 @@ export default class Diesel {
|
|
|
67
74
|
for(const route of this?.routes!){
|
|
68
75
|
this.filters.push(route)
|
|
69
76
|
}
|
|
70
|
-
// this.routes = []
|
|
71
77
|
return this.filter()
|
|
72
78
|
},
|
|
73
79
|
|
|
74
80
|
require: (fnc?:middlewareFunc) => {
|
|
75
|
-
if(
|
|
76
|
-
|
|
77
|
-
message:"Authentication required"
|
|
78
|
-
}),{status:400})
|
|
81
|
+
if (fnc) {
|
|
82
|
+
this.filterFunction = fnc
|
|
79
83
|
}
|
|
80
|
-
this.filterFunction = fnc
|
|
81
84
|
}
|
|
82
85
|
};
|
|
83
86
|
}
|
|
@@ -138,13 +141,13 @@ export default class Diesel {
|
|
|
138
141
|
}
|
|
139
142
|
|
|
140
143
|
this.compile();
|
|
141
|
-
|
|
144
|
+
|
|
142
145
|
const options: any = {
|
|
143
146
|
port,
|
|
144
147
|
fetch: async (req: Request, server: Server) => {
|
|
145
148
|
const url = new URL(req.url);
|
|
146
149
|
try {
|
|
147
|
-
return await handleRequest(req, server, url, this);
|
|
150
|
+
return await handleRequest(req, server, url, this as DieselT);
|
|
148
151
|
} catch (error) {
|
|
149
152
|
return new Response("Internal Server Error", { status: 500 });
|
|
150
153
|
}
|
|
@@ -160,7 +163,7 @@ export default class Diesel {
|
|
|
160
163
|
}
|
|
161
164
|
const server = Bun.serve(options);
|
|
162
165
|
|
|
163
|
-
|
|
166
|
+
Bun?.gc(false)
|
|
164
167
|
|
|
165
168
|
if (typeof callback === "function") {
|
|
166
169
|
return callback();
|
|
@@ -186,7 +189,7 @@ export default class Diesel {
|
|
|
186
189
|
throw new Error("handler parameter should be a instance of router object", handlerInstance)
|
|
187
190
|
}
|
|
188
191
|
const routeEntries: [string, RouteNodeType][] = Object.entries(handlerInstance.trie.root.children) as [string, RouteNodeType][];
|
|
189
|
-
|
|
192
|
+
|
|
190
193
|
handlerInstance.trie.root.subMiddlewares.forEach((middleware: middlewareFunc[], path: string) => {
|
|
191
194
|
if (!this.middlewares.has(pathPrefix + path)) {
|
|
192
195
|
this.middlewares.set(pathPrefix + path, []);
|
|
@@ -208,7 +211,7 @@ export default class Diesel {
|
|
|
208
211
|
handlerInstance.trie = new Trie();
|
|
209
212
|
}
|
|
210
213
|
|
|
211
|
-
|
|
214
|
+
addRoute(
|
|
212
215
|
method: HttpMethod,
|
|
213
216
|
path: string,
|
|
214
217
|
handlers: handlerFunction[]
|
|
@@ -252,7 +255,7 @@ export default class Diesel {
|
|
|
252
255
|
}
|
|
253
256
|
return
|
|
254
257
|
}
|
|
255
|
-
|
|
258
|
+
|
|
256
259
|
const path: string = pathORHandler as string;
|
|
257
260
|
|
|
258
261
|
if (!this.middlewares.has(path)) {
|
|
@@ -270,7 +273,7 @@ export default class Diesel {
|
|
|
270
273
|
path: string,
|
|
271
274
|
...handlers: handlerFunction[]
|
|
272
275
|
) : this {
|
|
273
|
-
this
|
|
276
|
+
this.addRoute("GET", path, handlers);
|
|
274
277
|
return this
|
|
275
278
|
}
|
|
276
279
|
|
|
@@ -278,12 +281,12 @@ export default class Diesel {
|
|
|
278
281
|
path: string,
|
|
279
282
|
...handlers: handlerFunction[]
|
|
280
283
|
): this {
|
|
281
|
-
this
|
|
284
|
+
this.addRoute("POST", path, handlers);
|
|
282
285
|
return this
|
|
283
286
|
}
|
|
284
287
|
|
|
285
288
|
put(path: string, ...handlers: handlerFunction[]) : this{
|
|
286
|
-
this
|
|
289
|
+
this.addRoute("PUT", path, handlers);
|
|
287
290
|
return this
|
|
288
291
|
}
|
|
289
292
|
|
|
@@ -291,7 +294,7 @@ export default class Diesel {
|
|
|
291
294
|
path: string,
|
|
292
295
|
...handlers: handlerFunction[]
|
|
293
296
|
) : this {
|
|
294
|
-
this
|
|
297
|
+
this.addRoute("PATCH", path, handlers);
|
|
295
298
|
return this
|
|
296
299
|
}
|
|
297
300
|
|
|
@@ -299,7 +302,7 @@ export default class Diesel {
|
|
|
299
302
|
path: any,
|
|
300
303
|
...handlers: handlerFunction[]
|
|
301
304
|
) : this {
|
|
302
|
-
this
|
|
305
|
+
this.addRoute("DELETE", path, handlers);
|
|
303
306
|
return this;
|
|
304
307
|
}
|
|
305
308
|
}
|
package/src/route.ts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import Diesel from "./main";
|
|
2
|
+
import type { handlerFunction, HttpMethod } from "./types";
|
|
3
|
+
|
|
4
|
+
class Router extends Diesel {
|
|
5
|
+
constructor() {
|
|
6
|
+
super();
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
// #addRoute(method:HttpMethod, path:string, handlers:handlerFunction[]) {
|
|
10
|
+
// if (!this.trie.root.subMiddlewares.has(path)) {
|
|
11
|
+
// this.trie.root.subMiddlewares.set(path,[])
|
|
12
|
+
// }
|
|
13
|
+
// const middlewareHandlers : handlerFunction[]= handlers.slice(0, -1);
|
|
14
|
+
|
|
15
|
+
// const currentMiddlewares = this.trie.root.subMiddlewares.get(path)
|
|
16
|
+
|
|
17
|
+
// middlewareHandlers.forEach((midl:handlerFunction) => {
|
|
18
|
+
// if (!currentMiddlewares?.includes(midl)) {
|
|
19
|
+
// currentMiddlewares?.push(midl)
|
|
20
|
+
// }
|
|
21
|
+
// })
|
|
22
|
+
|
|
23
|
+
// // if (!this.trie.root.subMiddlewares.get(path).includes(...middlewareHandlers)) {
|
|
24
|
+
// // this.trie.root.subMiddlewares.get(path).push(...middlewareHandlers)
|
|
25
|
+
// // }
|
|
26
|
+
|
|
27
|
+
// const handler : handlerFunction = handlers[handlers.length - 1];
|
|
28
|
+
// this.trie.insert(path, { handler, method });
|
|
29
|
+
// }
|
|
30
|
+
get(path:string, ...handlers:handlerFunction[]) {
|
|
31
|
+
this.addRoute("GET", path, handlers);
|
|
32
|
+
return this
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
post(path:string, ...handlers:handlerFunction[]) {
|
|
36
|
+
this.addRoute("POST", path, handlers);
|
|
37
|
+
return this;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
put(path:string, ...handlers:handlerFunction[]) {
|
|
41
|
+
this.addRoute("PUT", path, handlers);
|
|
42
|
+
return this
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
patch(path:string, ...handlers:handlerFunction[]) {
|
|
46
|
+
this.addRoute("PATCH", path, handlers);
|
|
47
|
+
return this
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
delete(path:string, ...handlers:handlerFunction[]) {
|
|
51
|
+
this.addRoute("DELETE", path, handlers);
|
|
52
|
+
return this;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export default Router;
|
package/src/trie.ts
CHANGED
|
@@ -59,9 +59,11 @@ class TrieNode {
|
|
|
59
59
|
node = node.children[key];
|
|
60
60
|
// Set dynamic route information if applicable
|
|
61
61
|
node.isDynamic = isDynamic;
|
|
62
|
-
node.pattern = segment;
|
|
62
|
+
node.pattern = segment;
|
|
63
|
+
node.method.push(route.method)
|
|
64
|
+
node.handler.push(route.handler)
|
|
65
|
+
node.path = path; // Store the actual pattern like ':id'
|
|
63
66
|
}
|
|
64
|
-
|
|
65
67
|
// After looping through the entire path, assign route details
|
|
66
68
|
node.isEndOfWord = true;
|
|
67
69
|
node.method.push(route.method);
|
|
@@ -95,7 +97,7 @@ class TrieNode {
|
|
|
95
97
|
node = node.children[key];
|
|
96
98
|
}
|
|
97
99
|
}
|
|
98
|
-
|
|
100
|
+
|
|
99
101
|
// Method matching
|
|
100
102
|
let routeMethodIndex = node.method.indexOf(method); // More efficient method match
|
|
101
103
|
if (routeMethodIndex !== -1) {
|
package/src/types.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { Server } from "bun";
|
|
|
2
2
|
|
|
3
3
|
export type listenCalllBackType = () => void;
|
|
4
4
|
export type handlerFunction = (ctx: ContextType, server?: Server) => Response | Promise<Response | null | void>;
|
|
5
|
-
export type middlewareFunc = (ctx:ContextType,server?:Server) => void | Response | Promise<Response>
|
|
5
|
+
export type middlewareFunc = (ctx:ContextType,server?:Server | undefined) => void | Response | Promise<Response>
|
|
6
6
|
export type HookFunction = (ctx: ContextType, result?: Response | null | void, server?: Server) => Response | Promise<Response | null | void>
|
|
7
7
|
// export type onSendHookFunc = (result?: Response | null | void, ctx?:ContextType) => Response | Promise<Response | null | void>
|
|
8
8
|
export type HttpMethod = "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "OPTIONS" | "HEAD";
|
|
@@ -30,6 +30,8 @@ export interface ContextType {
|
|
|
30
30
|
server: Server;
|
|
31
31
|
url: URL;
|
|
32
32
|
next: () => void;
|
|
33
|
+
setUser: (data?:any) => void
|
|
34
|
+
getUser: () => any
|
|
33
35
|
status: (status: number) => this;
|
|
34
36
|
getIP: () => any;
|
|
35
37
|
body: () => Promise<any>;
|
|
@@ -86,6 +88,7 @@ export interface DieselT {
|
|
|
86
88
|
onSend: ((ctx?: ContextType, result?: Response | null | void, serer?: Server) => Promise<Response | void | null>) | null;
|
|
87
89
|
};
|
|
88
90
|
filters: string[]
|
|
91
|
+
hasFilterEnabled:boolean
|
|
89
92
|
filterFunction: (ctx:ContextType,serer?:Server) => void | Response | Promise<Response|void>
|
|
90
93
|
corsConfig: corsT | null
|
|
91
94
|
globalMiddlewares: Array<(ctx: ContextType, serer?: Server) => void | Promise<Response | null | void>>
|
package/tsconfig.json
CHANGED
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
"compilerOptions": {
|
|
3
3
|
"target": "ES6", // Specify ECMAScript target version
|
|
4
4
|
"module": "ESNext", // Specify module code generation
|
|
5
|
-
"outDir": "./
|
|
5
|
+
"outDir": "./main", // Redirect output structure to the 'dist' directory
|
|
6
6
|
"rootDir": "./src",
|
|
7
7
|
"declaration": true,
|
|
8
|
-
"
|
|
8
|
+
"declarationDir": "./dist",
|
|
9
|
+
"emitDeclarationOnly": false, // Specify the root directory of input files
|
|
9
10
|
"strict": true, // Enable all strict type-checking options
|
|
10
11
|
"esModuleInterop": true, // Enables emit interoperability between CommonJS and ES Modules
|
|
11
12
|
"skipLibCheck": true, // Skip type checking of declaration files
|
package/src/router.ts
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import Diesel from "./main";
|
|
2
|
-
import type { handlerFunction, HttpMethod } from "./types";
|
|
3
|
-
|
|
4
|
-
class Router extends Diesel {
|
|
5
|
-
constructor() {
|
|
6
|
-
super();
|
|
7
|
-
}
|
|
8
|
-
#addRoute(method:HttpMethod, path:string, handlers:handlerFunction[]) {
|
|
9
|
-
if (!this.trie.root.subMiddlewares.has(path)) {
|
|
10
|
-
this.trie.root.subMiddlewares.set(path,[])
|
|
11
|
-
}
|
|
12
|
-
const middlewareHandlers : handlerFunction[]= handlers.slice(0, -1);
|
|
13
|
-
|
|
14
|
-
const currentMiddlewares = this.trie.root.subMiddlewares.get(path)
|
|
15
|
-
|
|
16
|
-
middlewareHandlers.forEach((midl:handlerFunction) => {
|
|
17
|
-
if (!currentMiddlewares?.includes(midl)) {
|
|
18
|
-
currentMiddlewares?.push(midl)
|
|
19
|
-
}
|
|
20
|
-
})
|
|
21
|
-
|
|
22
|
-
// if (!this.trie.root.subMiddlewares.get(path).includes(...middlewareHandlers)) {
|
|
23
|
-
// this.trie.root.subMiddlewares.get(path).push(...middlewareHandlers)
|
|
24
|
-
// }
|
|
25
|
-
|
|
26
|
-
const handler : handlerFunction = handlers[handlers.length - 1];
|
|
27
|
-
this.trie.insert(path, { handler, method });
|
|
28
|
-
}
|
|
29
|
-
get(path:string, ...handlers:handlerFunction[]) {
|
|
30
|
-
this.#addRoute("GET", path, handlers);
|
|
31
|
-
return this
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
post(path:string, ...handlers:handlerFunction[]) {
|
|
35
|
-
this.#addRoute("POST", path, handlers);
|
|
36
|
-
return this;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
put(path:string, ...handlers:handlerFunction[]) {
|
|
40
|
-
this.#addRoute("PUT", path, handlers);
|
|
41
|
-
return this
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
patch(path:string, ...handlers:handlerFunction[]) {
|
|
45
|
-
this.#addRoute("PATCH", path, handlers);
|
|
46
|
-
return this
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
delete(path : string, ...handlers:handlerFunction[]) {
|
|
50
|
-
this.#addRoute("DELETE", path, handlers);
|
|
51
|
-
return this;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
export default Router;
|