bun-router 0.3.1 → 0.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +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 -2
- 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>) => {
|
|
@@ -129,11 +142,12 @@ const router: Router = (port?: number | string, options?: Options) => {
|
|
|
129
142
|
});
|
|
130
143
|
},
|
|
131
144
|
serve: () => {
|
|
132
|
-
|
|
145
|
+
lgr.start(port ?? 3000);
|
|
133
146
|
Bun.serve({
|
|
134
147
|
port: port ?? 3000,
|
|
135
148
|
...options,
|
|
136
149
|
fetch(req) {
|
|
150
|
+
const url = new URL(req.url);
|
|
137
151
|
for (const route of routes) {
|
|
138
152
|
const ctx: Context = {
|
|
139
153
|
request: req,
|
|
@@ -145,9 +159,14 @@ const router: Router = (port?: number | string, options?: Options) => {
|
|
|
145
159
|
|
|
146
160
|
extractor?.params();
|
|
147
161
|
|
|
148
|
-
if (
|
|
162
|
+
if (url.pathname === '/favicon.ico') return noContent();
|
|
163
|
+
|
|
164
|
+
if (match(route, ctx)) {
|
|
165
|
+
lgr.info(200, route.pattern, route.method)
|
|
149
166
|
return route.callback(ctx);
|
|
167
|
+
}
|
|
150
168
|
}
|
|
169
|
+
lgr.info(404, url.pathname, req.method, 'not found');
|
|
151
170
|
return new Response('not found');
|
|
152
171
|
}
|
|
153
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
|
+
});
|