bun-router 0.3.1 → 0.3.4

Sign up to get free protection for your applications and to get access to all the features.
package/README.md CHANGED
@@ -29,8 +29,6 @@ import {router, html, json } from 'bun-router';
29
29
 
30
30
  const r = router(3001);
31
31
 
32
- r.static('/assets', './assets');
33
-
34
32
  r.add('/', (ctx) => html('<h1>Hello World</h1>'));
35
33
 
36
34
  r.add('/greeting/:name', 'GET', (ctx) => {
@@ -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
@@ -1,2 +1,3 @@
1
1
  export * from './lib/router/router';
2
- export * from './lib/fs/fsys';
2
+ export * from './lib/fs/fsys';
3
+ export * from './lib/logger/logger';
@@ -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 }
@@ -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
- console.log(`[bun-router]: Listening on port -> :${port ?? 3000}`)
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 (match(route, ctx))
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
@@ -8,5 +8,5 @@
8
8
  "peerDependencies": {
9
9
  "typescript": "^5.0.0"
10
10
  },
11
- "version": "0.3.1"
11
+ "version": "0.3.4"
12
12
  }
@@ -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
+ });
@@ -46,7 +46,10 @@ function run_test() {
46
46
  echo "Failed: $url returned $actual | expected: $expected"
47
47
  fi
48
48
 
49
- rm "$name"
49
+ if does_exist "$name"; then
50
+ rm "$name"
51
+ fi
52
+
50
53
  }
51
54
 
52
55
  for expected in "${!test_cases[@]}"; do