bun-router 0.7.4-experimental.8 → 0.7.4-experimental.9
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/examples/static.ts +1 -1
- package/lib/http/status.ts +64 -64
- package/lib/logger/logger.ts +1 -1
- package/lib/router/routeTree.ts +27 -3
- package/lib/router/router.ts +22 -9
- package/package.json +1 -1
- package/tests/router.test.ts +21 -20
package/examples/static.ts
CHANGED
package/lib/http/status.ts
CHANGED
@@ -1,66 +1,66 @@
|
|
1
1
|
const httpStatusCodes: { [key: number]: string } = {
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
2
|
+
100: 'Continue',
|
3
|
+
101: 'Switching Protocols',
|
4
|
+
102: 'Processing',
|
5
|
+
103: 'Early Hints',
|
6
|
+
200: 'OK',
|
7
|
+
201: 'Created',
|
8
|
+
202: 'Accepted',
|
9
|
+
203: 'Non-Authoritative Information',
|
10
|
+
204: 'No Content',
|
11
|
+
205: 'Reset Content',
|
12
|
+
206: 'Partial Content',
|
13
|
+
207: 'Multi-Status',
|
14
|
+
208: 'Already Reported',
|
15
|
+
226: 'IM Used',
|
16
|
+
300: 'Multiple Choices',
|
17
|
+
301: 'Moved Permanently',
|
18
|
+
302: 'Found',
|
19
|
+
303: 'See Other',
|
20
|
+
304: 'Not Modified',
|
21
|
+
305: 'Use Proxy',
|
22
|
+
307: 'Temporary Redirect',
|
23
|
+
308: 'Permanent Redirect',
|
24
|
+
400: 'Bad Request',
|
25
|
+
401: 'Unauthorized',
|
26
|
+
402: 'Payment Required',
|
27
|
+
403: 'Forbidden',
|
28
|
+
404: 'Not Found',
|
29
|
+
405: 'Method Not Allowed',
|
30
|
+
406: 'Not Acceptable',
|
31
|
+
407: 'Proxy Authentication Required',
|
32
|
+
408: 'Request Timeout',
|
33
|
+
409: 'Conflict',
|
34
|
+
410: 'Gone',
|
35
|
+
411: 'Length Required',
|
36
|
+
412: 'Precondition Failed',
|
37
|
+
413: 'Payload Too Large',
|
38
|
+
414: 'URI Too Long',
|
39
|
+
415: 'Unsupported Media Type',
|
40
|
+
416: 'Range Not Satisfiable',
|
41
|
+
417: 'Expectation Failed',
|
42
|
+
418: 'I\'m a Teapot',
|
43
|
+
421: 'Misdirected Request',
|
44
|
+
422: 'Unprocessable Entity',
|
45
|
+
423: 'Locked',
|
46
|
+
424: 'Failed Dependency',
|
47
|
+
425: 'Too Early',
|
48
|
+
426: 'Upgrade Required',
|
49
|
+
428: 'Precondition Required',
|
50
|
+
429: 'Too Many Requests',
|
51
|
+
431: 'Request Header Fields Too Large',
|
52
|
+
451: 'Unavailable For Legal Reasons',
|
53
|
+
500: 'Internal Server Error',
|
54
|
+
501: 'Not Implemented',
|
55
|
+
502: 'Bad Gateway',
|
56
|
+
503: 'Service Unavailable',
|
57
|
+
504: 'Gateway Timeout',
|
58
|
+
505: 'HTTP Version Not Supported',
|
59
|
+
506: 'Variant Also Negotiates',
|
60
|
+
507: 'Insufficient Storage',
|
61
|
+
508: 'Loop Detected',
|
62
|
+
510: 'Not Extended',
|
63
|
+
511: 'Network Authentication Required',
|
64
|
+
};
|
65
65
|
|
66
|
-
|
66
|
+
export { httpStatusCodes };
|
package/lib/logger/logger.ts
CHANGED
@@ -9,7 +9,7 @@ _ _
|
|
9
9
|
|___|___|_|_| |_| |___|___|_| |___|_|
|
10
10
|
|
11
11
|
`;
|
12
|
-
const VERSION = '0.7.4-experimental.
|
12
|
+
const VERSION = '0.7.4-experimental.9';
|
13
13
|
const Logger = (): BunLogger => {
|
14
14
|
return {
|
15
15
|
info: async (statusCode: number, routePath: string, method: string, message?: string) => {
|
package/lib/router/routeTree.ts
CHANGED
@@ -18,7 +18,7 @@ const createRoute = (path: string, method: string, handler: HttpHandler): Route
|
|
18
18
|
const RouteTree = () => {
|
19
19
|
const root = createRoute('', 'GET', () => http.notFound());
|
20
20
|
|
21
|
-
|
21
|
+
function addRoute (pattern: string, method: string, handler: HttpHandler){
|
22
22
|
const pathParts = pattern.split('/');
|
23
23
|
let current = root;
|
24
24
|
|
@@ -36,7 +36,7 @@ const RouteTree = () => {
|
|
36
36
|
current.handler = handler;
|
37
37
|
current.isLast = true;
|
38
38
|
current.path = pattern;
|
39
|
-
}
|
39
|
+
}
|
40
40
|
|
41
41
|
function findRoute(pathname: string): Route | undefined {
|
42
42
|
const pathParts = pathname.split('/');
|
@@ -54,7 +54,31 @@ const RouteTree = () => {
|
|
54
54
|
return current;
|
55
55
|
}
|
56
56
|
|
57
|
-
|
57
|
+
function size() {
|
58
|
+
let count = 0;
|
59
|
+
function traverse(route: Route) {
|
60
|
+
count++;
|
61
|
+
for (const child of route.children.values()) {
|
62
|
+
traverse(child);
|
63
|
+
}
|
64
|
+
}
|
65
|
+
traverse(root);
|
66
|
+
return count;
|
67
|
+
}
|
68
|
+
|
69
|
+
function list() {
|
70
|
+
const routes: Route[] = [];
|
71
|
+
function traverse(route: Route) {
|
72
|
+
routes.push(route);
|
73
|
+
for (const child of route.children.values()) {
|
74
|
+
traverse(child);
|
75
|
+
}
|
76
|
+
}
|
77
|
+
traverse(root);
|
78
|
+
return routes;
|
79
|
+
}
|
80
|
+
|
81
|
+
return { addRoute, findRoute, size, list };
|
58
82
|
|
59
83
|
};
|
60
84
|
|
package/lib/router/router.ts
CHANGED
@@ -2,14 +2,14 @@ import path from 'path';
|
|
2
2
|
import { Database } from 'bun:sqlite';
|
3
3
|
import { Route, BunRouter, RouterOptions, Options, HttpHandler } from './router.d';
|
4
4
|
import { httpStatusCodes } from '../http/status';
|
5
|
-
import { readDir
|
5
|
+
import { readDir } from '../fs/fsys';
|
6
6
|
import { Logger, startMessage } from '../logger/logger';
|
7
7
|
import { http } from '../http/http';
|
8
8
|
import { RouteTree } from './routeTree';
|
9
9
|
import { createContext } from './context';
|
10
10
|
|
11
11
|
const Router: BunRouter = (port?: number | string, options?: RouterOptions<Options>) => {
|
12
|
-
const { addRoute, findRoute } = RouteTree();
|
12
|
+
const { addRoute, findRoute, list } = RouteTree();
|
13
13
|
const logger = Logger();
|
14
14
|
|
15
15
|
async function loadComponent(root: string, name: string) {
|
@@ -17,9 +17,9 @@ const Router: BunRouter = (port?: number | string, options?: RouterOptions<Optio
|
|
17
17
|
return module.default;
|
18
18
|
}
|
19
19
|
|
20
|
-
function
|
20
|
+
function extractPathExtBase(pattern: string, pathname: string) {
|
21
21
|
const extension = path.extname(pathname);
|
22
|
-
let base = path.basename(pathname);
|
22
|
+
let base = encodeURIComponent(path.basename(pathname));
|
23
23
|
|
24
24
|
if (extension === '.html' || extension === '.tsx') base = base.replace(extension, '');
|
25
25
|
|
@@ -27,9 +27,14 @@ const Router: BunRouter = (port?: number | string, options?: RouterOptions<Optio
|
|
27
27
|
|
28
28
|
if (base === 'index') patternPath = pattern;
|
29
29
|
|
30
|
-
return { patternPath, extension, base }
|
30
|
+
return { patternPath, extension, base };
|
31
31
|
}
|
32
32
|
|
33
|
+
async function exists(fp: string) {
|
34
|
+
const f = Bun.file(fp);
|
35
|
+
return await f.exists();
|
36
|
+
}
|
37
|
+
|
33
38
|
return {
|
34
39
|
// add a route to the router tree
|
35
40
|
add: (pattern, method, callback) => { addRoute(pattern, method, callback); },
|
@@ -43,15 +48,15 @@ const Router: BunRouter = (port?: number | string, options?: RouterOptions<Optio
|
|
43
48
|
// all other file extensions are served as files
|
44
49
|
// the root directory is traversed recursively
|
45
50
|
static: async (pattern: string, root: string) => {
|
46
|
-
if (!exists(root)) console.
|
51
|
+
if (!exists(root)) return console.error(`Directory not found: ${root}`);
|
47
52
|
await readDir(root, async (fp) => {
|
48
|
-
const { patternPath, extension, base } =
|
53
|
+
const { patternPath, extension, base } = extractPathExtBase(pattern, fp);
|
49
54
|
|
50
55
|
const route: Route = {
|
51
56
|
children: new Map(),
|
52
57
|
dynamicPath: '',
|
53
58
|
isLast: true,
|
54
|
-
path: patternPath.slice(1), // remove the leading '/'
|
59
|
+
path: patternPath.startsWith('//') ? patternPath.slice(1) : patternPath, // remove the leading '/' if it exists
|
55
60
|
method: 'GET',
|
56
61
|
handler: async () => {
|
57
62
|
if (extension === '.tsx') {
|
@@ -65,6 +70,9 @@ const Router: BunRouter = (port?: number | string, options?: RouterOptions<Optio
|
|
65
70
|
|
66
71
|
addRoute(route.path, 'GET', route.handler);
|
67
72
|
});
|
73
|
+
|
74
|
+
console.log(list());
|
75
|
+
|
68
76
|
},
|
69
77
|
// start the server
|
70
78
|
serve: () => {
|
@@ -102,11 +110,16 @@ const Router: BunRouter = (port?: number | string, options?: RouterOptions<Optio
|
|
102
110
|
return Promise.resolve(response);
|
103
111
|
}
|
104
112
|
|
105
|
-
// if no route is found, return 404
|
113
|
+
// if no route is found, return 404
|
106
114
|
const response = await http.notFound();
|
107
115
|
|
108
116
|
logger.info(response.status, url.pathname, req.method, httpStatusCodes[response.status]);
|
109
117
|
return Promise.resolve(http.notFound());
|
118
|
+
},
|
119
|
+
error(error) {
|
120
|
+
return new Response(`<pre>${error}\n${error.stack}</pre>`, {
|
121
|
+
headers: { 'Content-Type': 'text/html' },
|
122
|
+
});
|
110
123
|
}
|
111
124
|
});
|
112
125
|
},
|
package/package.json
CHANGED
package/tests/router.test.ts
CHANGED
@@ -1,35 +1,36 @@
|
|
1
1
|
import { describe, test, expect } from 'bun:test';
|
2
2
|
|
3
3
|
describe('Router', () => {
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
4
|
+
test('Serve', async () => {
|
5
|
+
const proc = Bun.spawn(['./tests/serve.test.sh'], {
|
6
|
+
onExit: (_proc, _exitCode, _signalCode , error) => {
|
7
|
+
if (error) console.error(error);
|
8
|
+
},
|
9
|
+
});
|
10
10
|
|
11
|
-
|
11
|
+
const text = await new Response(proc.stdout).text();
|
12
12
|
|
13
|
-
|
13
|
+
const hasFailed = text.includes('Failed');
|
14
14
|
|
15
|
-
|
15
|
+
if (hasFailed) console.log(text);
|
16
16
|
|
17
|
-
|
17
|
+
expect(hasFailed).toBe(false);
|
18
18
|
|
19
|
-
|
20
|
-
|
19
|
+
proc.kill(0);
|
20
|
+
});
|
21
21
|
|
22
|
-
|
23
|
-
|
22
|
+
test('Static', async() => {
|
23
|
+
const proc = Bun.spawn(['./tests/static.test.sh']);
|
24
24
|
|
25
|
-
|
25
|
+
const text = await new Response(proc.stdout).text();
|
26
26
|
|
27
|
-
|
28
|
-
|
27
|
+
const hasFailed = text.includes('Failed');
|
28
|
+
if (hasFailed) console.log(text);
|
29
29
|
|
30
|
-
|
30
|
+
expect(hasFailed).toBe(false);
|
31
31
|
|
32
|
-
|
33
|
-
|
32
|
+
proc.kill(0);
|
33
|
+
});
|
34
34
|
});
|
35
35
|
|
36
|
+
|