bun-router 0.3.0 → 0.3.4
Sign up to get free protection for your applications and to get access to all the features.
- package/README.md +0 -2
- package/examples/logger.ts +16 -0
- package/httplocalhost3001vader.jpg +0 -0
- package/index.ts +2 -1
- package/lib/logger/color.ts +36 -0
- package/lib/logger/logger.d.ts +8 -0
- package/lib/logger/logger.ts +80 -0
- package/lib/router/router.ts +21 -7
- package/package.json +1 -1
- package/tests/router.test.ts +3 -1
- package/tests/static.test.sh +4 -1
package/README.md
CHANGED
@@ -0,0 +1,16 @@
|
|
1
|
+
import { router, logger, json, html } from '..';
|
2
|
+
|
3
|
+
const r = router();
|
4
|
+
const log = logger();
|
5
|
+
|
6
|
+
r.add('/:foo', 'GET', (ctx) => {
|
7
|
+
const url = new URL(ctx.request.url);
|
8
|
+
const foo = ctx.params.get('foo');
|
9
|
+
if (!foo) {
|
10
|
+
log.error(500, url.pathname, ctx.request.method, new Error('undefined'));
|
11
|
+
return json({status: 500, text: 'Foo is undefined'});
|
12
|
+
}
|
13
|
+
return html(`<h4 style='font-family: sans-serif;'>Oh hello, ${foo}</h4>`)
|
14
|
+
});
|
15
|
+
|
16
|
+
r.serve();
|
Binary file
|
package/index.ts
CHANGED
@@ -0,0 +1,36 @@
|
|
1
|
+
const Colors: Record<string,string> = {
|
2
|
+
reset: "\x1b[0m",
|
3
|
+
|
4
|
+
// foreground
|
5
|
+
black: "\x1b[30m",
|
6
|
+
red: "\x1b[31m",
|
7
|
+
green: "\x1b[32m",
|
8
|
+
yellow: "\x1b[33m",
|
9
|
+
blue: "\x1b[34m",
|
10
|
+
magenta: "\x1b[35m",
|
11
|
+
cyan: "\x1b[36m",
|
12
|
+
white: "\x1b[37m",
|
13
|
+
|
14
|
+
// background
|
15
|
+
bgBlack: "\x1b[40m",
|
16
|
+
bgRed: "\x1b[41m",
|
17
|
+
bgGreen: "\x1b[42m",
|
18
|
+
bgYellow: "\x1b[43m",
|
19
|
+
bgBlue: "\x1b[44m",
|
20
|
+
bgMagenta: "\x1b[45m",
|
21
|
+
bgCyan: "\x1b[46m",
|
22
|
+
bgWhite: "\x1b[47m",
|
23
|
+
};
|
24
|
+
|
25
|
+
|
26
|
+
const color = (c: string, bkg: string, msg: string) => {
|
27
|
+
const foreground = Colors[c];
|
28
|
+
const background = Colors[bkg];
|
29
|
+
const reset = Colors.reset;
|
30
|
+
|
31
|
+
return `${foreground}${background}${msg}${reset}`;
|
32
|
+
};
|
33
|
+
|
34
|
+
|
35
|
+
|
36
|
+
export { color }
|
@@ -0,0 +1,8 @@
|
|
1
|
+
type Logger = {
|
2
|
+
start: (port: number | string) => void,
|
3
|
+
info: (statusCode: number, routePath: string, method: string, message?: string) => void,
|
4
|
+
error: (statusCode: number, routePath: string, method: string, error: Error) => void,
|
5
|
+
warn: (msg: string) => void,
|
6
|
+
}
|
7
|
+
|
8
|
+
export { Logger }
|
@@ -0,0 +1,80 @@
|
|
1
|
+
import { color } from './color';
|
2
|
+
import {Logger} from './logger.d';
|
3
|
+
|
4
|
+
const pad = (n: number) => String(n).padStart(2, '0');
|
5
|
+
|
6
|
+
const timestamp = (date: Date) => {
|
7
|
+
const month = pad(date.getMonth());
|
8
|
+
const day = pad(date.getDate());
|
9
|
+
const hour = pad(date.getHours());
|
10
|
+
const minute = pad(date.getMinutes());
|
11
|
+
const seconds = pad(date.getSeconds());
|
12
|
+
const stamp = `${hour}:${minute}:${seconds}`;
|
13
|
+
|
14
|
+
return {month, day, hour, minute, stamp};
|
15
|
+
}
|
16
|
+
|
17
|
+
const colorCode = (n: number, text?:string): string => {
|
18
|
+
const s = ` [${String(n)}${text ?? ''}] `;
|
19
|
+
if (n < 100) return color('black', 'bgYellow', s);
|
20
|
+
else if (n >= 100 && n < 200) return color('black', 'bgCyan', s);
|
21
|
+
else if (n >= 200 && n < 300) return color('black', 'bgGreen', s);
|
22
|
+
else if (n >= 300 && n < 400) return color('black', 'bgRed', s);
|
23
|
+
else if (n >= 400 && n < 500) return color('black', 'bgRed', s);
|
24
|
+
else if (n >= 500) return color('white', 'bgRed', s);
|
25
|
+
return color('white', 'bgBlack', `[${s}]`).trim();
|
26
|
+
}
|
27
|
+
|
28
|
+
const clean = (s: string) => s.replace(/\x1B\[\d{1,2}(;\d{1,2}){0,2}m/g, '');
|
29
|
+
|
30
|
+
const format = (statusCode: number, routePath: string, method: string, message?: string): string => {
|
31
|
+
const { stamp } = timestamp((new Date(Date.now())));
|
32
|
+
const source = color('green', 'bgBlack', `[bun-router ${stamp}]`);
|
33
|
+
const rp = color('white', 'bgBlack', routePath);
|
34
|
+
|
35
|
+
return `${source} : ${colorCode(statusCode)} : ${rp} ${(method === 'GET') ? '->' : '<-'} ${method}\n`
|
36
|
+
}
|
37
|
+
|
38
|
+
const logger = (): Logger => {
|
39
|
+
const messages: string[] = [];
|
40
|
+
const errors: string[] = [];
|
41
|
+
return {
|
42
|
+
start: async (port: number | string) => {
|
43
|
+
const { stamp } = timestamp((new Date(Date.now())));
|
44
|
+
const source = color('green', 'bgBlack', `[bun-router ${stamp}]`)
|
45
|
+
const portColor = color('green', 'bgBlack', String(port));
|
46
|
+
const msg = `${source}: Starting Server on :${portColor}\n`;
|
47
|
+
|
48
|
+
await Bun.write(Bun.stdout, msg);
|
49
|
+
},
|
50
|
+
info: async (statusCode: number, routePath: string, method: string, message?: string) => {
|
51
|
+
const { stamp } = timestamp((new Date(Date.now())));
|
52
|
+
const source = color('green', 'bgBlack', `[bun-router ${stamp}]`);
|
53
|
+
const rp = color('white', 'bgBlack', routePath);
|
54
|
+
const msg = `${source}: ${colorCode(statusCode)}: ${rp} ${(method === 'GET') ? '->' : '<-'} ${method}\n`
|
55
|
+
|
56
|
+
await Bun.write(Bun.stdout, msg);
|
57
|
+
|
58
|
+
messages.push(clean(msg));
|
59
|
+
},
|
60
|
+
error: async (statusCode: number, routePath: string, method: string, error: Error) => {
|
61
|
+
const { stamp } = timestamp((new Date(Date.now())));
|
62
|
+
const source = color('black', 'bgRed', `[error ${stamp}]`);
|
63
|
+
const rp = color('white', 'bgBlack', routePath);
|
64
|
+
const msg = `${source}: ${colorCode(statusCode)}: ${rp} ${(method === 'GET') ? '->' : '<-'} ${error.message}\n`;
|
65
|
+
|
66
|
+
await Bun.write(Bun.stdout, msg);
|
67
|
+
|
68
|
+
errors.push(clean(msg));
|
69
|
+
},
|
70
|
+
warn: async (msg: string) => {
|
71
|
+
const { stamp } = timestamp((new Date(Date.now())));
|
72
|
+
const source = color('black', 'bgYellow', `[warning ${stamp}]`);
|
73
|
+
const msgColor = color('yellow', 'bgBlack', msg);
|
74
|
+
msg = `${source} : ${msgColor}\n`;
|
75
|
+
await Bun.write(Bun.stdout, msg);
|
76
|
+
}
|
77
|
+
}
|
78
|
+
}
|
79
|
+
|
80
|
+
export { logger }
|
package/lib/router/router.ts
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
import { Route, Router, Context, Options } from './router.d';
|
2
2
|
import { readDir } from '../fs/fsys';
|
3
|
+
import { logger } from '../logger/logger';
|
3
4
|
import path from 'path';
|
4
5
|
|
5
6
|
const notFound = async (): Promise<Response> => {
|
@@ -14,6 +15,17 @@ const notFound = async (): Promise<Response> => {
|
|
14
15
|
});
|
15
16
|
}
|
16
17
|
|
18
|
+
const noContent = async (): Promise<Response> => {
|
19
|
+
const response = new Response('no content', {
|
20
|
+
status: 204,
|
21
|
+
statusText: 'no content',
|
22
|
+
});
|
23
|
+
|
24
|
+
return new Promise((resolve) => {
|
25
|
+
resolve(response);
|
26
|
+
});
|
27
|
+
}
|
28
|
+
|
17
29
|
const file = async (filepath: string): Promise<Response> => {
|
18
30
|
const file = Bun.file(filepath);
|
19
31
|
const exists = await file.exists();
|
@@ -93,6 +105,7 @@ const match = (route: Route, ctx: Context): boolean => {
|
|
93
105
|
const router: Router = (port?: number | string, options?: Options) => {
|
94
106
|
const routes: Array<Route> = new Array();
|
95
107
|
const paths: { [key: string]: string } = {};
|
108
|
+
const lgr = logger();
|
96
109
|
|
97
110
|
return {
|
98
111
|
add: (pattern: string, method: string, callback: (ctx: Context) => Response | Promise<Response>) => {
|
@@ -114,15 +127,12 @@ const router: Router = (port?: number | string, options?: Options) => {
|
|
114
127
|
|
115
128
|
}
|
116
129
|
|
117
|
-
console.log((pattern[0] != '/'))
|
118
130
|
if (pattern[0] !== '/') pattern = '/' + pattern;
|
119
131
|
|
120
132
|
let patternPath = pattern + base;
|
121
133
|
|
122
134
|
if (base === 'index') patternPath = pattern;
|
123
135
|
|
124
|
-
console.log(patternPath);
|
125
|
-
|
126
136
|
const route: Route = {
|
127
137
|
pattern: patternPath,
|
128
138
|
method: 'GET',
|
@@ -130,15 +140,14 @@ const router: Router = (port?: number | string, options?: Options) => {
|
|
130
140
|
};
|
131
141
|
routes.push(route);
|
132
142
|
});
|
133
|
-
console.log(routes.length);
|
134
|
-
|
135
143
|
},
|
136
144
|
serve: () => {
|
137
|
-
|
145
|
+
lgr.start(port ?? 3000);
|
138
146
|
Bun.serve({
|
139
147
|
port: port ?? 3000,
|
140
148
|
...options,
|
141
149
|
fetch(req) {
|
150
|
+
const url = new URL(req.url);
|
142
151
|
for (const route of routes) {
|
143
152
|
const ctx: Context = {
|
144
153
|
request: req,
|
@@ -150,9 +159,14 @@ const router: Router = (port?: number | string, options?: Options) => {
|
|
150
159
|
|
151
160
|
extractor?.params();
|
152
161
|
|
153
|
-
if (
|
162
|
+
if (url.pathname === '/favicon.ico') return noContent();
|
163
|
+
|
164
|
+
if (match(route, ctx)) {
|
165
|
+
lgr.info(200, route.pattern, route.method)
|
154
166
|
return route.callback(ctx);
|
167
|
+
}
|
155
168
|
}
|
169
|
+
lgr.info(404, url.pathname, req.method, 'not found');
|
156
170
|
return new Response('not found');
|
157
171
|
}
|
158
172
|
});
|
package/package.json
CHANGED
package/tests/router.test.ts
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
import { describe, test, expect } from 'bun:test';
|
2
2
|
import { router, extract } from '..';
|
3
3
|
import { Context, Route } from '../lib/router/router.d';
|
4
|
+
import { logger } from '../lib/logger/logger';
|
5
|
+
import { color } from '../lib/logger/color';
|
4
6
|
|
5
7
|
describe('URL Params', () => {
|
6
8
|
test('/user/:name', () => {
|
@@ -98,4 +100,4 @@ describe('Router', () => {
|
|
98
100
|
|
99
101
|
proc.kill(0);
|
100
102
|
});
|
101
|
-
});
|
103
|
+
});
|