@e22m4u/js-trie-router 0.5.0 → 0.5.1
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/dist/cjs/index.cjs +1 -0
- package/eslint.config.js +1 -0
- package/package.json +15 -9
- package/src/debuggable-service.d.ts +6 -0
- package/src/hooks/hook-invoker.d.ts +25 -0
- package/src/hooks/hook-registry.d.ts +93 -0
- package/src/hooks/index.d.ts +2 -0
- package/src/index.d.ts +9 -0
- package/src/parsers/body-parser.d.ts +52 -0
- package/src/parsers/cookies-parser.d.ts +15 -0
- package/src/parsers/index.d.ts +4 -0
- package/src/parsers/query-parser.d.ts +21 -0
- package/src/parsers/request-parser.d.ts +34 -0
- package/src/request-context.d.ts +101 -0
- package/src/route-registry.d.ts +39 -0
- package/src/route.d.ts +100 -0
- package/src/router-options.d.ts +18 -0
- package/src/senders/data-sender.d.ts +15 -0
- package/src/senders/error-sender.d.ts +30 -0
- package/src/senders/index.d.ts +2 -0
- package/src/trie-router.d.ts +104 -0
- package/src/types.d.ts +19 -0
- package/src/utils/clone-deep.d.ts +6 -0
- package/src/utils/create-cookies-string.d.ts +6 -0
- package/src/utils/create-debugger.d.ts +11 -0
- package/src/utils/create-error.d.ts +14 -0
- package/src/utils/create-request-mock.d.ts +27 -0
- package/src/utils/create-response-mock.d.ts +17 -0
- package/src/utils/create-route-mock.d.ts +18 -0
- package/src/utils/fetch-request-body.d.ts +26 -0
- package/src/utils/get-request-pathname.d.ts +8 -0
- package/src/utils/index.d.ts +16 -0
- package/src/utils/is-promise.d.ts +10 -0
- package/src/utils/is-readable-stream.d.ts +9 -0
- package/src/utils/is-response-sent.d.ts +8 -0
- package/src/utils/is-writable-stream.d.ts +9 -0
- package/src/utils/parse-content-type.d.ts +15 -0
- package/src/utils/parse-cookies.d.ts +19 -0
- package/src/utils/to-camel-case.d.ts +6 -0
- package/tsconfig.json +14 -0
- package/jsconfig.json +0 -7
package/dist/cjs/index.cjs
CHANGED
package/eslint.config.js
CHANGED
|
@@ -28,6 +28,7 @@ export default [{
|
|
|
28
28
|
...eslintChaiExpectPlugin.configs['recommended-flat'].rules,
|
|
29
29
|
...eslintJsdocPlugin.configs['flat/recommended-error'].rules,
|
|
30
30
|
'no-duplicate-imports': 'error',
|
|
31
|
+
'import/export': 0,
|
|
31
32
|
'jsdoc/reject-any-type': 0,
|
|
32
33
|
'jsdoc/reject-function-type': 0,
|
|
33
34
|
'jsdoc/require-param-description': 0,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@e22m4u/js-trie-router",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"description": "HTTP маршрутизатор для Node.js на основе префиксного дерева",
|
|
5
5
|
"author": "Mikhail Evstropov <e22m4u@yandex.ru>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -17,9 +17,11 @@
|
|
|
17
17
|
"url": "git+https://gitrepos.ru/e22m4u/js-trie-router.git"
|
|
18
18
|
},
|
|
19
19
|
"type": "module",
|
|
20
|
+
"types": "./src/index.d.ts",
|
|
20
21
|
"module": "./src/index.js",
|
|
21
22
|
"main": "./dist/cjs/index.cjs",
|
|
22
23
|
"exports": {
|
|
24
|
+
"types": "./src/index.d.ts",
|
|
23
25
|
"import": "./src/index.js",
|
|
24
26
|
"require": "./dist/cjs/index.cjs"
|
|
25
27
|
},
|
|
@@ -27,8 +29,8 @@
|
|
|
27
29
|
"node": ">=16"
|
|
28
30
|
},
|
|
29
31
|
"scripts": {
|
|
30
|
-
"lint": "eslint ./src",
|
|
31
|
-
"lint:fix": "eslint ./src --fix",
|
|
32
|
+
"lint": "tsc && eslint ./src",
|
|
33
|
+
"lint:fix": "tsc && eslint ./src --fix",
|
|
32
34
|
"format": "prettier --write \"./src/**/*.{js,ts}\"",
|
|
33
35
|
"test": "npm run lint && c8 --reporter=text-summary mocha --bail",
|
|
34
36
|
"test:coverage": "npm run lint && c8 --reporter=text mocha",
|
|
@@ -36,10 +38,10 @@
|
|
|
36
38
|
"prepare": "husky"
|
|
37
39
|
},
|
|
38
40
|
"dependencies": {
|
|
39
|
-
"@e22m4u/js-debug": "~0.4.
|
|
40
|
-
"@e22m4u/js-format": "~0.3.
|
|
41
|
-
"@e22m4u/js-path-trie": "~0.1.
|
|
42
|
-
"@e22m4u/js-service": "~0.5.
|
|
41
|
+
"@e22m4u/js-debug": "~0.4.1",
|
|
42
|
+
"@e22m4u/js-format": "~0.3.1",
|
|
43
|
+
"@e22m4u/js-path-trie": "~0.1.1",
|
|
44
|
+
"@e22m4u/js-service": "~0.5.1",
|
|
43
45
|
"debug": "~4.4.3",
|
|
44
46
|
"http-errors": "~2.0.1",
|
|
45
47
|
"statuses": "~2.0.2"
|
|
@@ -48,6 +50,9 @@
|
|
|
48
50
|
"@commitlint/cli": "~20.1.0",
|
|
49
51
|
"@commitlint/config-conventional": "~20.0.0",
|
|
50
52
|
"@eslint/js": "~9.39.1",
|
|
53
|
+
"@types/chai": "~5.2.3",
|
|
54
|
+
"@types/chai-as-promised": "~8.0.2",
|
|
55
|
+
"@types/mocha": "~10.0.10",
|
|
51
56
|
"c8": "~10.1.3",
|
|
52
57
|
"chai": "~6.2.1",
|
|
53
58
|
"chai-as-promised": "~8.0.2",
|
|
@@ -61,7 +66,8 @@
|
|
|
61
66
|
"globals": "~16.5.0",
|
|
62
67
|
"husky": "~9.1.7",
|
|
63
68
|
"mocha": "~11.7.5",
|
|
64
|
-
"prettier": "~3.7.
|
|
65
|
-
"rimraf": "~6.1.2"
|
|
69
|
+
"prettier": "~3.7.4",
|
|
70
|
+
"rimraf": "~6.1.2",
|
|
71
|
+
"typescript": "~5.9.3"
|
|
66
72
|
}
|
|
67
73
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import {Route} from '../route.js';
|
|
2
|
+
import {ServerResponse} from 'http';
|
|
3
|
+
import {ValueOrPromise} from '../types.js';
|
|
4
|
+
import {RouterHookType} from './hook-registry.js';
|
|
5
|
+
import {DebuggableService} from '../debuggable-service.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Hook invoker.
|
|
9
|
+
*/
|
|
10
|
+
export declare class HookInvoker extends DebuggableService {
|
|
11
|
+
/**
|
|
12
|
+
* Invoke and continue until value received.
|
|
13
|
+
*
|
|
14
|
+
* @param route
|
|
15
|
+
* @param hookType
|
|
16
|
+
* @param response
|
|
17
|
+
* @param args
|
|
18
|
+
*/
|
|
19
|
+
invokeAndContinueUntilValueReceived(
|
|
20
|
+
route: Route,
|
|
21
|
+
hookType: RouterHookType,
|
|
22
|
+
response: ServerResponse,
|
|
23
|
+
...args: unknown[]
|
|
24
|
+
): ValueOrPromise<unknown>;
|
|
25
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import {Callable} from '../types.js';
|
|
2
|
+
import {RequestContext} from '../request-context.js';
|
|
3
|
+
import {DebuggableService} from '../debuggable-service.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Hook type.
|
|
7
|
+
*/
|
|
8
|
+
export declare const RouterHookType: {
|
|
9
|
+
PRE_HANDLER: 'preHandler';
|
|
10
|
+
POST_HANDLER: 'postHandler';
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Type of RouterHookType.
|
|
15
|
+
*/
|
|
16
|
+
export type RouterHookType =
|
|
17
|
+
(typeof RouterHookType)[keyof typeof RouterHookType];
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Router hook.
|
|
21
|
+
*/
|
|
22
|
+
export type RouterHook = Callable;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Pre handler hook.
|
|
26
|
+
*/
|
|
27
|
+
export type PreHandlerHook = (ctx: RequestContext) => unknown;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Post handler hook.
|
|
31
|
+
*/
|
|
32
|
+
export type PostHandlerHook = (ctx: RequestContext, data: unknown) => unknown;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Hook registry.
|
|
36
|
+
*/
|
|
37
|
+
export declare class HookRegistry extends DebuggableService {
|
|
38
|
+
/**
|
|
39
|
+
* Add hook.
|
|
40
|
+
*
|
|
41
|
+
* @param type
|
|
42
|
+
* @param hook
|
|
43
|
+
*/
|
|
44
|
+
addHook(type: typeof RouterHookType.PRE_HANDLER, hook: PreHandlerHook): this;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Add hook.
|
|
48
|
+
*
|
|
49
|
+
* @param type
|
|
50
|
+
* @param hook
|
|
51
|
+
*/
|
|
52
|
+
addHook(
|
|
53
|
+
type: typeof RouterHookType.POST_HANDLER,
|
|
54
|
+
hook: PostHandlerHook,
|
|
55
|
+
): this;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Add hook.
|
|
59
|
+
*
|
|
60
|
+
* @param type
|
|
61
|
+
* @param hook
|
|
62
|
+
*/
|
|
63
|
+
addHook(type: RouterHookType, hook: RouterHook): this;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Has hook.
|
|
67
|
+
*
|
|
68
|
+
* @param type
|
|
69
|
+
* @param hook
|
|
70
|
+
*/
|
|
71
|
+
hasHook(type: RouterHookType, hook: RouterHook): boolean;
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Get hooks.
|
|
75
|
+
*
|
|
76
|
+
* @param type
|
|
77
|
+
*/
|
|
78
|
+
getHooks(type: typeof RouterHookType.PRE_HANDLER): PreHandlerHook[];
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Get hooks.
|
|
82
|
+
*
|
|
83
|
+
* @param type
|
|
84
|
+
*/
|
|
85
|
+
getHooks(type: typeof RouterHookType.POST_HANDLER): PostHandlerHook[];
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Get hooks.
|
|
89
|
+
*
|
|
90
|
+
* @param type
|
|
91
|
+
*/
|
|
92
|
+
getHooks(type: RouterHookType): RouterHook[];
|
|
93
|
+
}
|
package/src/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export * from './route.js';
|
|
2
|
+
export * from './utils/index.js';
|
|
3
|
+
export * from './hooks/index.js';
|
|
4
|
+
export * from './trie-router.js';
|
|
5
|
+
export * from './parsers/index.js';
|
|
6
|
+
export * from './senders/index.js';
|
|
7
|
+
export * from './route-registry.js';
|
|
8
|
+
export * from './router-options.js';
|
|
9
|
+
export * from './request-context.js';
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import {IncomingMessage} from 'http';
|
|
2
|
+
import {ValueOrPromise} from '../types.js';
|
|
3
|
+
import {DebuggableService} from '../debuggable-service.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Method names to be parsed.
|
|
7
|
+
*/
|
|
8
|
+
export type METHODS_WITH_BODY = string[];
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Unparsable media types.
|
|
12
|
+
*/
|
|
13
|
+
export type UNPARSABLE_MEDIA_TYPES = string[];
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Body parser function.
|
|
17
|
+
*/
|
|
18
|
+
export type BodyParserFunction = <T = unknown>(input: string) => T;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Body parser.
|
|
22
|
+
*/
|
|
23
|
+
export declare class BodyParser extends DebuggableService {
|
|
24
|
+
/**
|
|
25
|
+
* Define parser.
|
|
26
|
+
*
|
|
27
|
+
* @param mediaType
|
|
28
|
+
* @param parser
|
|
29
|
+
*/
|
|
30
|
+
defineParser(mediaType: string, parser: BodyParserFunction): this;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Has parser.
|
|
34
|
+
*
|
|
35
|
+
* @param mediaType
|
|
36
|
+
*/
|
|
37
|
+
hasParser(mediaType: string): boolean;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Delete parser.
|
|
41
|
+
*
|
|
42
|
+
* @param mediaType
|
|
43
|
+
*/
|
|
44
|
+
deleteParser(mediaType: string): this;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Parse.
|
|
48
|
+
*
|
|
49
|
+
* @param request
|
|
50
|
+
*/
|
|
51
|
+
parse<T = unknown>(request: IncomingMessage): ValueOrPromise<T>;
|
|
52
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import {IncomingMessage} from 'http';
|
|
2
|
+
import {ParsedCookies} from '../utils/index.js';
|
|
3
|
+
import {DebuggableService} from '../debuggable-service.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Cookies parser.
|
|
7
|
+
*/
|
|
8
|
+
export declare class CookiesParser extends DebuggableService {
|
|
9
|
+
/**
|
|
10
|
+
* Parse.
|
|
11
|
+
*
|
|
12
|
+
* @param request
|
|
13
|
+
*/
|
|
14
|
+
parse(request: IncomingMessage): ParsedCookies;
|
|
15
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import {IncomingMessage} from 'http';
|
|
2
|
+
import {DebuggableService} from '../debuggable-service.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Parsed query.
|
|
6
|
+
*/
|
|
7
|
+
export type ParsedQuery = {
|
|
8
|
+
[key: string]: string | undefined;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Query parser.
|
|
13
|
+
*/
|
|
14
|
+
export declare class QueryParser extends DebuggableService {
|
|
15
|
+
/**
|
|
16
|
+
* Parse.
|
|
17
|
+
*
|
|
18
|
+
* @param request
|
|
19
|
+
*/
|
|
20
|
+
parse(request: IncomingMessage): ParsedQuery;
|
|
21
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import {IncomingMessage} from 'http';
|
|
2
|
+
import {ValueOrPromise} from '../types.js';
|
|
3
|
+
import {ParsedQuery} from './query-parser.js';
|
|
4
|
+
import {ParsedCookies} from '../utils/index.js';
|
|
5
|
+
import {DebuggableService} from '../debuggable-service.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Parsed headers.
|
|
9
|
+
*/
|
|
10
|
+
export type ParsedHeaders = {
|
|
11
|
+
[key: string]: string | undefined;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Parsed request.
|
|
16
|
+
*/
|
|
17
|
+
type ParsedRequestData = {
|
|
18
|
+
query: ParsedQuery;
|
|
19
|
+
cookies: ParsedCookies;
|
|
20
|
+
body: unknown;
|
|
21
|
+
headers: ParsedHeaders;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Request parser.
|
|
26
|
+
*/
|
|
27
|
+
export declare class RequestParser extends DebuggableService {
|
|
28
|
+
/**
|
|
29
|
+
* Parse.
|
|
30
|
+
*
|
|
31
|
+
* @param request
|
|
32
|
+
*/
|
|
33
|
+
parse(request: IncomingMessage): ValueOrPromise<ParsedRequestData>;
|
|
34
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import {Route, RouteMeta} from './route.js';
|
|
2
|
+
import {ParsedCookies} from './utils/index.js';
|
|
3
|
+
import {ServiceContainer} from '@e22m4u/js-service';
|
|
4
|
+
import {IncomingMessage, ServerResponse} from 'http';
|
|
5
|
+
import {ParsedQuery, ParsedHeaders} from './parsers/index.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Parsed params.
|
|
9
|
+
*/
|
|
10
|
+
export type ParsedParams = {
|
|
11
|
+
[key: string]: string | undefined;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Request context.
|
|
16
|
+
*/
|
|
17
|
+
export declare class RequestContext {
|
|
18
|
+
/**
|
|
19
|
+
* Container.
|
|
20
|
+
*/
|
|
21
|
+
get container(): ServiceContainer;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Request.
|
|
25
|
+
*/
|
|
26
|
+
get request(): IncomingMessage;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Response.
|
|
30
|
+
*/
|
|
31
|
+
get response(): ServerResponse;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Route.
|
|
35
|
+
*/
|
|
36
|
+
get route(): Route;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Query.
|
|
40
|
+
*/
|
|
41
|
+
query: ParsedQuery;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Params.
|
|
45
|
+
*/
|
|
46
|
+
params: ParsedParams;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Headers.
|
|
50
|
+
*/
|
|
51
|
+
headers: ParsedHeaders;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Cookies.
|
|
55
|
+
*/
|
|
56
|
+
cookies: ParsedCookies;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Body.
|
|
60
|
+
*/
|
|
61
|
+
body: unknown;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* State.
|
|
65
|
+
*/
|
|
66
|
+
state: Record<string, any>;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Route meta.
|
|
70
|
+
*/
|
|
71
|
+
get meta(): RouteMeta;
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Method.
|
|
75
|
+
*/
|
|
76
|
+
get method(): string;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Path.
|
|
80
|
+
*/
|
|
81
|
+
get path(): string;
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Pathname.
|
|
85
|
+
*/
|
|
86
|
+
get pathname(): string;
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Constructor.
|
|
90
|
+
*
|
|
91
|
+
* @param container
|
|
92
|
+
* @param request
|
|
93
|
+
* @param response
|
|
94
|
+
*/
|
|
95
|
+
constructor(
|
|
96
|
+
container: ServiceContainer,
|
|
97
|
+
request: IncomingMessage,
|
|
98
|
+
response: ServerResponse,
|
|
99
|
+
route: Route,
|
|
100
|
+
);
|
|
101
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import {Route} from './route.js';
|
|
2
|
+
import {IncomingMessage} from 'http';
|
|
3
|
+
import {RouteDefinition} from './route.js';
|
|
4
|
+
import {ServiceContainer} from '@e22m4u/js-service';
|
|
5
|
+
import {DebuggableService} from './debuggable-service.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Resolved route.
|
|
9
|
+
*/
|
|
10
|
+
export type ResolvedRoute = {
|
|
11
|
+
route: Route;
|
|
12
|
+
params: {[key: string]: string | undefined};
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Route registry.
|
|
17
|
+
*/
|
|
18
|
+
export declare class RouteRegistry extends DebuggableService {
|
|
19
|
+
/**
|
|
20
|
+
* Constructor.
|
|
21
|
+
*
|
|
22
|
+
* @param container
|
|
23
|
+
*/
|
|
24
|
+
constructor(container: ServiceContainer);
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Define route.
|
|
28
|
+
*
|
|
29
|
+
* @param routeDef
|
|
30
|
+
*/
|
|
31
|
+
defineRoute(routeDef: RouteDefinition): Route;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Match route by request.
|
|
35
|
+
*
|
|
36
|
+
* @param request
|
|
37
|
+
*/
|
|
38
|
+
matchRouteByRequest(request: IncomingMessage): ResolvedRoute | undefined;
|
|
39
|
+
}
|
package/src/route.d.ts
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import {ValueOrPromise} from './types.js';
|
|
2
|
+
import {HookRegistry} from './hooks/index.js';
|
|
3
|
+
import {RequestContext} from './request-context.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Http method.
|
|
7
|
+
*/
|
|
8
|
+
export declare const HttpMethod: {
|
|
9
|
+
GET: 'GET';
|
|
10
|
+
POST: 'POST';
|
|
11
|
+
PUT: 'PUT';
|
|
12
|
+
PATCH: 'PATCH';
|
|
13
|
+
DELETE: 'DELETE';
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Type of HttpMethod.
|
|
18
|
+
*/
|
|
19
|
+
export type HttpMethod = (typeof HttpMethod)[keyof typeof HttpMethod];
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Route handler.
|
|
23
|
+
*/
|
|
24
|
+
export type RouteHandler = (ctx: RequestContext) => ValueOrPromise<unknown>;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Route pre-handler.
|
|
28
|
+
*/
|
|
29
|
+
export type RoutePreHandler = RouteHandler;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Route post-handler.
|
|
33
|
+
*/
|
|
34
|
+
export type RoutePostHandler<T = unknown, U = unknown> = (
|
|
35
|
+
ctx: RequestContext,
|
|
36
|
+
data: T,
|
|
37
|
+
) => ValueOrPromise<U>;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Route meta.
|
|
41
|
+
*/
|
|
42
|
+
export type RouteMeta = {
|
|
43
|
+
[key: string]: unknown;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Route definition.
|
|
48
|
+
*/
|
|
49
|
+
export type RouteDefinition = {
|
|
50
|
+
method: string;
|
|
51
|
+
path: string;
|
|
52
|
+
handler: RouteHandler;
|
|
53
|
+
preHandler?: RoutePreHandler | RoutePreHandler[];
|
|
54
|
+
postHandler?: RoutePostHandler | RoutePostHandler[];
|
|
55
|
+
meta?: RouteMeta;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Route.
|
|
60
|
+
*/
|
|
61
|
+
export declare class Route {
|
|
62
|
+
/**
|
|
63
|
+
* Method.
|
|
64
|
+
*/
|
|
65
|
+
get method(): string;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Path.
|
|
69
|
+
*/
|
|
70
|
+
get path(): string;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Meta.
|
|
74
|
+
*/
|
|
75
|
+
get meta(): RouteMeta;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Handler.
|
|
79
|
+
*/
|
|
80
|
+
get handler(): RouteHandler;
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Hook registry.
|
|
84
|
+
*/
|
|
85
|
+
get hookRegistry(): HookRegistry;
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Constructor.
|
|
89
|
+
*
|
|
90
|
+
* @param routeDef
|
|
91
|
+
*/
|
|
92
|
+
constructor(routeDef: RouteDefinition);
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Handle.
|
|
96
|
+
*
|
|
97
|
+
* @param context
|
|
98
|
+
*/
|
|
99
|
+
handle(context: RequestContext): ValueOrPromise<unknown>;
|
|
100
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import {DebuggableService} from './debuggable-service.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Router options.
|
|
5
|
+
*/
|
|
6
|
+
export declare class RouterOptions extends DebuggableService {
|
|
7
|
+
/**
|
|
8
|
+
* Request body bytes limit.
|
|
9
|
+
*/
|
|
10
|
+
get requestBodyBytesLimit(): number;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Set request body bytes limit.
|
|
14
|
+
*
|
|
15
|
+
* @param input
|
|
16
|
+
*/
|
|
17
|
+
setRequestBodyBytesLimit(input: number): this;
|
|
18
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import {ServerResponse} from 'http';
|
|
2
|
+
import {DebuggableService} from '../debuggable-service.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Data sender.
|
|
6
|
+
*/
|
|
7
|
+
export declare class DataSender extends DebuggableService {
|
|
8
|
+
/**
|
|
9
|
+
* Send.
|
|
10
|
+
*
|
|
11
|
+
* @param response
|
|
12
|
+
* @param data
|
|
13
|
+
*/
|
|
14
|
+
send(response: ServerResponse, data: unknown): void;
|
|
15
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import {ServerResponse} from 'http';
|
|
2
|
+
import {IncomingMessage} from 'http';
|
|
3
|
+
import {DebuggableService} from '../debuggable-service.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Exposed error properties.
|
|
7
|
+
*/
|
|
8
|
+
export const EXPOSED_ERROR_PROPERTIES: ['code', 'details'];
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Error sender.
|
|
12
|
+
*/
|
|
13
|
+
export declare class ErrorSender extends DebuggableService {
|
|
14
|
+
/**
|
|
15
|
+
* Send.
|
|
16
|
+
*
|
|
17
|
+
* @param request
|
|
18
|
+
* @param response
|
|
19
|
+
* @param error
|
|
20
|
+
*/
|
|
21
|
+
send(request: IncomingMessage, response: ServerResponse, error: Error): void;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Send 404.
|
|
25
|
+
*
|
|
26
|
+
* @param request
|
|
27
|
+
* @param response
|
|
28
|
+
*/
|
|
29
|
+
send404(request: IncomingMessage, response: ServerResponse): void;
|
|
30
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import {Route} from './route.js';
|
|
2
|
+
import {RequestListener} from 'http';
|
|
3
|
+
import {RouteDefinition} from './route.js';
|
|
4
|
+
import {DebuggableService} from './debuggable-service.js';
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
RouterHook,
|
|
8
|
+
RouterHookType,
|
|
9
|
+
PostHandlerHook,
|
|
10
|
+
PreHandlerHook,
|
|
11
|
+
} from './hooks/index.js';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Trie router.
|
|
15
|
+
*/
|
|
16
|
+
export declare class TrieRouter extends DebuggableService {
|
|
17
|
+
/**
|
|
18
|
+
* Define route.
|
|
19
|
+
*
|
|
20
|
+
* Example 1:
|
|
21
|
+
* ```
|
|
22
|
+
* const router = new TrieRouter();
|
|
23
|
+
* router.defineRoute({
|
|
24
|
+
* method: HttpMethod.GET, // Request method.
|
|
25
|
+
* path: '/', // Path template.
|
|
26
|
+
* handler: ctx => 'Hello world!', // Request handler.
|
|
27
|
+
* });
|
|
28
|
+
* ```
|
|
29
|
+
*
|
|
30
|
+
* Example 2:
|
|
31
|
+
* ```
|
|
32
|
+
* const router = new TrieRouter();
|
|
33
|
+
* router.defineRoute({
|
|
34
|
+
* method: HttpMethod.POST, // Request method.
|
|
35
|
+
* path: '/users/:id', // The path template may have parameters.
|
|
36
|
+
* preHandler(ctx) { ... }, // The "preHandler" is executed before a route handler.
|
|
37
|
+
* handler(ctx) { ... }, // Request handler function.
|
|
38
|
+
* postHandler(ctx, data) { ... }, // The "postHandler" is executed after a route handler
|
|
39
|
+
* });
|
|
40
|
+
* ```
|
|
41
|
+
*
|
|
42
|
+
* @param routeDef
|
|
43
|
+
*/
|
|
44
|
+
defineRoute(routeDef: RouteDefinition): Route;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Request listener.
|
|
48
|
+
*
|
|
49
|
+
* Example:
|
|
50
|
+
* ```
|
|
51
|
+
* import http from 'http';
|
|
52
|
+
* import {TrieRouter} from '@e22m4u/js-trie-router';
|
|
53
|
+
*
|
|
54
|
+
* const router = new TrieRouter();
|
|
55
|
+
* const server = new http.Server();
|
|
56
|
+
* server.on('request', router.requestListener); // Sets the request listener.
|
|
57
|
+
* server.listen(3000); // Starts listening for connections.
|
|
58
|
+
* ```
|
|
59
|
+
*
|
|
60
|
+
* @returns {Function}
|
|
61
|
+
*/
|
|
62
|
+
get requestListener(): RequestListener;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Add hook.
|
|
66
|
+
*
|
|
67
|
+
* @param type
|
|
68
|
+
* @param hook
|
|
69
|
+
*/
|
|
70
|
+
addHook(type: typeof RouterHookType.PRE_HANDLER, hook: PreHandlerHook): this;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Add hook.
|
|
74
|
+
*
|
|
75
|
+
* @param type
|
|
76
|
+
* @param hook
|
|
77
|
+
*/
|
|
78
|
+
addHook(
|
|
79
|
+
type: typeof RouterHookType.POST_HANDLER,
|
|
80
|
+
hook: PostHandlerHook,
|
|
81
|
+
): this;
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Add hook.
|
|
85
|
+
*
|
|
86
|
+
* @param type
|
|
87
|
+
* @param hook
|
|
88
|
+
*/
|
|
89
|
+
addHook(type: RouterHookType, hook: RouterHook): this;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Add pre-handler hook.
|
|
93
|
+
*
|
|
94
|
+
* @param hook
|
|
95
|
+
*/
|
|
96
|
+
addPreHandler(hook: PreHandlerHook): this;
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Add post-handler hook.
|
|
100
|
+
*
|
|
101
|
+
* @param hook
|
|
102
|
+
*/
|
|
103
|
+
addPostHandler(hook: PostHandlerHook): this;
|
|
104
|
+
}
|
package/src/types.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A callable type with the "new" operator
|
|
3
|
+
* allows class and constructor.
|
|
4
|
+
*/
|
|
5
|
+
export interface Constructor<T = unknown> {
|
|
6
|
+
new (...args: any[]): T;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* A function type without class and constructor.
|
|
11
|
+
*/
|
|
12
|
+
export type Callable<T = unknown> = (...args: any[]) => T;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Representing a value or promise. This type is used
|
|
16
|
+
* to represent results of synchronous/asynchronous
|
|
17
|
+
* resolution of values.
|
|
18
|
+
*/
|
|
19
|
+
export type ValueOrPromise<T> = T | PromiseLike<T>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import {Constructor} from '../types.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Create error.
|
|
5
|
+
*
|
|
6
|
+
* @param errorCtor
|
|
7
|
+
* @param message
|
|
8
|
+
* @param args
|
|
9
|
+
*/
|
|
10
|
+
export declare function createError<T>(
|
|
11
|
+
errorCtor: Constructor<T>,
|
|
12
|
+
message: string,
|
|
13
|
+
...args: unknown[]
|
|
14
|
+
): T;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import {Readable} from 'stream';
|
|
2
|
+
import {IncomingMessage} from 'http';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Request patch.
|
|
6
|
+
*/
|
|
7
|
+
type RequestPatch = {
|
|
8
|
+
host?: string;
|
|
9
|
+
method?: string;
|
|
10
|
+
secure?: boolean;
|
|
11
|
+
path?: string;
|
|
12
|
+
query?: object;
|
|
13
|
+
cookies?: object;
|
|
14
|
+
headers?: object;
|
|
15
|
+
body?: string;
|
|
16
|
+
stream?: Readable;
|
|
17
|
+
encoding?: BufferEncoding;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Create request mock.
|
|
22
|
+
*
|
|
23
|
+
* @param patch
|
|
24
|
+
*/
|
|
25
|
+
export declare function createRequestMock(
|
|
26
|
+
patch?: RequestPatch,
|
|
27
|
+
): IncomingMessage;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import {ServerResponse} from 'http';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Server response mock.
|
|
5
|
+
*/
|
|
6
|
+
export type ServerResponseMock = ServerResponse & {
|
|
7
|
+
_headersSent: boolean;
|
|
8
|
+
_headers: {[name: string]: string | undefined};
|
|
9
|
+
setEncoding(encoding: string): ServerResponseMock;
|
|
10
|
+
getEncoding(): string | undefined;
|
|
11
|
+
getBody(): Promise<string>;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Create response mock.
|
|
16
|
+
*/
|
|
17
|
+
export declare function createResponseMock(): ServerResponseMock;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import {Route, HttpMethod} from '../route.js';
|
|
2
|
+
import type {RouteHandler} from '../route.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Route mock options.
|
|
6
|
+
*/
|
|
7
|
+
type RouteMockOptions = {
|
|
8
|
+
method?: HttpMethod;
|
|
9
|
+
path?: string;
|
|
10
|
+
handler?: RouteHandler;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Create route mock.
|
|
15
|
+
*
|
|
16
|
+
* @param options
|
|
17
|
+
*/
|
|
18
|
+
export function createRouteMock(options?: RouteMockOptions): Route;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import {IncomingMessage} from 'http';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Character encoding list.
|
|
5
|
+
*/
|
|
6
|
+
export const CHARACTER_ENCODING_LIST: (
|
|
7
|
+
| 'ascii'
|
|
8
|
+
| 'utf8'
|
|
9
|
+
| 'utf-8'
|
|
10
|
+
| 'utf16le'
|
|
11
|
+
| 'utf-16le'
|
|
12
|
+
| 'ucs2'
|
|
13
|
+
| 'ucs-2'
|
|
14
|
+
| 'latin1'
|
|
15
|
+
)[];
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Fetch request body.
|
|
19
|
+
*
|
|
20
|
+
* @param request
|
|
21
|
+
* @param bodyBytesLimit
|
|
22
|
+
*/
|
|
23
|
+
export declare function fetchRequestBody(
|
|
24
|
+
request: IncomingMessage,
|
|
25
|
+
bodyBytesLimit?: number,
|
|
26
|
+
): Promise<string>;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export * from './clone-deep.js';
|
|
2
|
+
export * from './is-promise.js';
|
|
3
|
+
export * from './create-error.js';
|
|
4
|
+
export * from './parse-cookies.js';
|
|
5
|
+
export * from './to-camel-case.js';
|
|
6
|
+
export * from './create-debugger.js';
|
|
7
|
+
export * from './is-response-sent.js';
|
|
8
|
+
export * from './create-route-mock.js';
|
|
9
|
+
export * from './is-readable-stream.js';
|
|
10
|
+
export * from './parse-content-type.js';
|
|
11
|
+
export * from './is-writable-stream.js';
|
|
12
|
+
export * from './fetch-request-body.js';
|
|
13
|
+
export * from './create-request-mock.js';
|
|
14
|
+
export * from './create-response-mock.js';
|
|
15
|
+
export * from './create-cookies-string.js';
|
|
16
|
+
export * from './get-request-pathname.js';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parsed content type.
|
|
3
|
+
*/
|
|
4
|
+
export type ParsedContentType = {
|
|
5
|
+
boundary: string | undefined;
|
|
6
|
+
charset: string | undefined;
|
|
7
|
+
mediaType: string | undefined;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Parse content type.
|
|
12
|
+
*
|
|
13
|
+
* @param input
|
|
14
|
+
*/
|
|
15
|
+
export declare function parseContentType(input: string): ParsedContentType;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parsed cookies.
|
|
3
|
+
*/
|
|
4
|
+
type ParsedCookies = {
|
|
5
|
+
[key: string]: string | undefined;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Parse cookies.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* parseCookies('pkg=math; equation=E%3Dmc%5E2');
|
|
14
|
+
* // {pkg: 'math', equation: 'E=mc^2'}
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* @param input
|
|
18
|
+
*/
|
|
19
|
+
export declare function parseCookies(input: string): ParsedCookies;
|
package/tsconfig.json
ADDED