@e22m4u/js-trie-router 0.5.12 → 0.5.13
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 +31 -8
- package/dist/cjs/index.cjs +32 -40
- package/eslint.config.js +1 -1
- package/package.json +6 -6
- package/src/hooks/router-hook-invoker.spec.js +51 -51
- package/src/hooks/router-hook-registry.d.ts +9 -33
- package/src/hooks/router-hook-registry.js +2 -0
- package/src/hooks/router-hook-registry.spec.js +35 -35
- package/src/parsers/request-parser.spec.js +14 -14
- package/src/route-registry.js +35 -0
- package/src/route-registry.spec.js +88 -10
- package/src/router-options.spec.js +13 -13
- package/src/senders/data-sender.spec.js +18 -18
- package/src/senders/error-sender.spec.js +6 -6
- package/src/trie-router.d.ts +7 -19
- package/src/trie-router.js +10 -41
- package/src/trie-router.spec.js +12 -32
package/README.md
CHANGED
|
@@ -16,7 +16,8 @@ HTTP маршрутизатор для Node.js на основе
|
|
|
16
16
|
## Содержание
|
|
17
17
|
|
|
18
18
|
- [Установка](#установка)
|
|
19
|
-
- [
|
|
19
|
+
- [Расширения](#расширения)
|
|
20
|
+
- [Использование](#использование)
|
|
20
21
|
- [Контекст запроса](#контекст-запроса)
|
|
21
22
|
- [Отправка ответа](#отправка-ответа)
|
|
22
23
|
- [Хуки маршрута](#хуки-маршрута)
|
|
@@ -53,7 +54,7 @@ import {TrieRouter} from '@e22m4u/js-trie-router';
|
|
|
53
54
|
const {TrieRouter} = require('@e22m4u/js-trie-router');
|
|
54
55
|
```
|
|
55
56
|
|
|
56
|
-
##
|
|
57
|
+
## Использование
|
|
57
58
|
|
|
58
59
|
Базовый пример создания экземпляра роутера, объявления маршрута
|
|
59
60
|
и передачи слушателя запросов HTTP серверу.
|
|
@@ -255,16 +256,28 @@ router.defineRoute({
|
|
|
255
256
|
|
|
256
257
|
- `preHandler` выполняется перед вызовом обработчика каждого маршрута;
|
|
257
258
|
- `postHandler` выполняется после вызова обработчика каждого маршрута;
|
|
259
|
+
- `onDefineRoute` выполняется в момент регистрации маршрута;
|
|
258
260
|
|
|
259
261
|
Добавить глобальные хуки можно методами экземпляра `TrieRouter`.
|
|
260
262
|
|
|
261
263
|
```js
|
|
262
|
-
|
|
264
|
+
import {RouterHookType} form '@e22m4u/js-trie-router';
|
|
265
|
+
|
|
266
|
+
router.addHook(RouterHookType.PRE_HANDLER, (ctx) => {
|
|
263
267
|
// перед обработчиком маршрута
|
|
264
268
|
});
|
|
265
|
-
|
|
269
|
+
|
|
270
|
+
router.addHook(RouterHookType.POST_HANDLER, (ctx, data) => {
|
|
266
271
|
// после обработчика маршрута
|
|
267
272
|
});
|
|
273
|
+
|
|
274
|
+
router.addHook(RouterHookType.ON_DEFINE_ROUTE, (routeDef) => {
|
|
275
|
+
// позволяет модифицировать определение
|
|
276
|
+
// маршрута в момент регистрации
|
|
277
|
+
routeDef.method = HttpMethod.POST;
|
|
278
|
+
routeDef.path = '/myPath';
|
|
279
|
+
routeDef.handler = () => 'OK';
|
|
280
|
+
});
|
|
268
281
|
```
|
|
269
282
|
|
|
270
283
|
Аналогично хукам маршрута, если глобальный хук возвращает значение
|
|
@@ -284,14 +297,19 @@ router.addPostHandler((ctx, data) => {
|
|
|
284
297
|
|
|
285
298
|
```js
|
|
286
299
|
import http from 'http';
|
|
287
|
-
|
|
300
|
+
|
|
301
|
+
import {
|
|
302
|
+
TrieRouter,
|
|
303
|
+
HttpMethod,
|
|
304
|
+
RouterHookType,
|
|
305
|
+
} from '@e22m4u/js-trie-router';
|
|
288
306
|
|
|
289
307
|
const server = new http.Server();
|
|
290
308
|
const router = new TrieRouter();
|
|
291
309
|
|
|
292
310
|
// глобальный pre-handler хук, который срабатывает
|
|
293
311
|
// перед основным обработчиком каждого маршрута
|
|
294
|
-
router.
|
|
312
|
+
router.addHook(RouterHookType.PRE_HANDLER, (ctx) => {
|
|
295
313
|
// доступ к метаданным текущего маршрута
|
|
296
314
|
console.log(ctx.meta); // {foo: 'bar'}
|
|
297
315
|
});
|
|
@@ -318,12 +336,17 @@ server.listen(3000, 'localhost');
|
|
|
318
336
|
|
|
319
337
|
```js
|
|
320
338
|
import http from 'http';
|
|
321
|
-
|
|
339
|
+
|
|
340
|
+
import {
|
|
341
|
+
TrieRouter,
|
|
342
|
+
HttpMethod,
|
|
343
|
+
RouterHookType,
|
|
344
|
+
} from '@e22m4u/js-trie-router';
|
|
322
345
|
|
|
323
346
|
const router = new TrieRouter();
|
|
324
347
|
|
|
325
348
|
// глобальный хук авторизации
|
|
326
|
-
router.
|
|
349
|
+
router.addHook(RouterHookType.PRE_HANDLER, (ctx) => {
|
|
327
350
|
// логика получения пользователя (например, из заголовков)
|
|
328
351
|
const user = {id: 1, name: 'John', role: 'admin'};
|
|
329
352
|
// сохранение данных в state
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -794,7 +794,8 @@ var import_js_format11 = require("@e22m4u/js-format");
|
|
|
794
794
|
var import_js_format10 = require("@e22m4u/js-format");
|
|
795
795
|
var RouterHookType = {
|
|
796
796
|
PRE_HANDLER: "preHandler",
|
|
797
|
-
POST_HANDLER: "postHandler"
|
|
797
|
+
POST_HANDLER: "postHandler",
|
|
798
|
+
ON_DEFINE_ROUTE: "onDefineRoute"
|
|
798
799
|
};
|
|
799
800
|
var ROUTER_HOOK_TYPES = Object.values(RouterHookType);
|
|
800
801
|
var _RouterHookRegistry = class _RouterHookRegistry {
|
|
@@ -1500,6 +1501,26 @@ var _RouteRegistry = class _RouteRegistry extends DebuggableService {
|
|
|
1500
1501
|
routeDef
|
|
1501
1502
|
);
|
|
1502
1503
|
}
|
|
1504
|
+
const hookRegistry = this.getService(RouterHookRegistry);
|
|
1505
|
+
const onDefineRouteHooks = hookRegistry.getHooks(
|
|
1506
|
+
RouterHookType.ON_DEFINE_ROUTE
|
|
1507
|
+
);
|
|
1508
|
+
if (onDefineRouteHooks.length) {
|
|
1509
|
+
debug('Invoking %v "onDefineRoute" hook(s).', onDefineRouteHooks.length);
|
|
1510
|
+
for (const hook of onDefineRouteHooks) {
|
|
1511
|
+
const hookResult = hook({ ...routeDef });
|
|
1512
|
+
if (hookResult !== void 0 && !(hookResult !== null && typeof hookResult === "object" && !Array.isArray(hookResult))) {
|
|
1513
|
+
throw new import_js_format16.InvalidArgumentError(
|
|
1514
|
+
'Hook "onDefineRoute" must return an Object or undefined, but %v was given.',
|
|
1515
|
+
hookResult
|
|
1516
|
+
);
|
|
1517
|
+
}
|
|
1518
|
+
if (hookResult !== void 0) {
|
|
1519
|
+
routeDef = hookResult;
|
|
1520
|
+
}
|
|
1521
|
+
}
|
|
1522
|
+
debug("Hooks invoked.");
|
|
1523
|
+
}
|
|
1503
1524
|
const route = new Route(routeDef);
|
|
1504
1525
|
const triePath = `${route.method}/${route.path}`;
|
|
1505
1526
|
this._trie.add(triePath, route);
|
|
@@ -2250,54 +2271,25 @@ var _TrieRouter = class _TrieRouter extends DebuggableService {
|
|
|
2250
2271
|
}
|
|
2251
2272
|
}
|
|
2252
2273
|
/**
|
|
2253
|
-
* Add
|
|
2254
|
-
*
|
|
2255
|
-
* @param {import('./hooks/index.js').PreHandlerHook} hook
|
|
2256
|
-
* @returns {this}
|
|
2257
|
-
*/
|
|
2258
|
-
addPreHandler(hook) {
|
|
2259
|
-
this.getService(RouterHookRegistry).addHook(
|
|
2260
|
-
RouterHookType.PRE_HANDLER,
|
|
2261
|
-
hook
|
|
2262
|
-
);
|
|
2263
|
-
return this;
|
|
2264
|
-
}
|
|
2265
|
-
/**
|
|
2266
|
-
* Has pre-handler hook.
|
|
2267
|
-
*
|
|
2268
|
-
* @param {import('./hooks/index.js').PreHandlerHook} hook
|
|
2269
|
-
* @returns {boolean}
|
|
2270
|
-
*/
|
|
2271
|
-
hasPreHandler(hook) {
|
|
2272
|
-
return this.getService(RouterHookRegistry).hasHook(
|
|
2273
|
-
RouterHookType.PRE_HANDLER,
|
|
2274
|
-
hook
|
|
2275
|
-
);
|
|
2276
|
-
}
|
|
2277
|
-
/**
|
|
2278
|
-
* Add post-handler hook.
|
|
2274
|
+
* Add hook.
|
|
2279
2275
|
*
|
|
2280
|
-
* @param {import('./hooks/index.js').
|
|
2276
|
+
* @param {import('./hooks/index.js').RouterHookType} type
|
|
2277
|
+
* @param {import('./hooks/index.js').RouterHook} hook
|
|
2281
2278
|
* @returns {this}
|
|
2282
2279
|
*/
|
|
2283
|
-
|
|
2284
|
-
this.getService(RouterHookRegistry).addHook(
|
|
2285
|
-
RouterHookType.POST_HANDLER,
|
|
2286
|
-
hook
|
|
2287
|
-
);
|
|
2280
|
+
addHook(type, hook) {
|
|
2281
|
+
this.getService(RouterHookRegistry).addHook(type, hook);
|
|
2288
2282
|
return this;
|
|
2289
2283
|
}
|
|
2290
2284
|
/**
|
|
2291
|
-
* Has
|
|
2285
|
+
* Has hook.
|
|
2292
2286
|
*
|
|
2293
|
-
* @param {import('./hooks/index.js').
|
|
2287
|
+
* @param {import('./hooks/index.js').RouterHookType} type
|
|
2288
|
+
* @param {import('./hooks/index.js').RouterHook} hook
|
|
2294
2289
|
* @returns {boolean}
|
|
2295
2290
|
*/
|
|
2296
|
-
|
|
2297
|
-
return this.getService(RouterHookRegistry).hasHook(
|
|
2298
|
-
RouterHookType.POST_HANDLER,
|
|
2299
|
-
hook
|
|
2300
|
-
);
|
|
2291
|
+
hasHook(type, hook) {
|
|
2292
|
+
return this.getService(RouterHookRegistry).hasHook(type, hook);
|
|
2301
2293
|
}
|
|
2302
2294
|
};
|
|
2303
2295
|
__name(_TrieRouter, "TrieRouter");
|
package/eslint.config.js
CHANGED
|
@@ -27,7 +27,7 @@ export default [{
|
|
|
27
27
|
...eslintMochaPlugin.configs.recommended.rules,
|
|
28
28
|
...eslintChaiExpectPlugin.configs['recommended-flat'].rules,
|
|
29
29
|
...eslintJsdocPlugin.configs['flat/recommended-error'].rules,
|
|
30
|
-
|
|
30
|
+
'curly': 'error',
|
|
31
31
|
'no-duplicate-imports': 'error',
|
|
32
32
|
'import/export': 0,
|
|
33
33
|
'jsdoc/reject-any-type': 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.13",
|
|
4
4
|
"description": "HTTP маршрутизатор для Node.js на основе префиксного дерева",
|
|
5
5
|
"author": "Mikhail Evstropov <e22m4u@yandex.ru>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -47,8 +47,8 @@
|
|
|
47
47
|
"statuses": "~2.0.2"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
|
-
"@commitlint/cli": "~20.
|
|
51
|
-
"@commitlint/config-conventional": "~20.
|
|
50
|
+
"@commitlint/cli": "~20.4.1",
|
|
51
|
+
"@commitlint/config-conventional": "~20.4.1",
|
|
52
52
|
"@eslint/js": "~9.39.2",
|
|
53
53
|
"@types/chai": "~5.2.3",
|
|
54
54
|
"@types/chai-as-promised": "~8.0.2",
|
|
@@ -61,12 +61,12 @@
|
|
|
61
61
|
"eslint-config-prettier": "~10.1.8",
|
|
62
62
|
"eslint-plugin-chai-expect": "~3.1.0",
|
|
63
63
|
"eslint-plugin-import": "~2.32.0",
|
|
64
|
-
"eslint-plugin-jsdoc": "~
|
|
64
|
+
"eslint-plugin-jsdoc": "~62.5.2",
|
|
65
65
|
"eslint-plugin-mocha": "~11.2.0",
|
|
66
|
-
"globals": "~17.
|
|
66
|
+
"globals": "~17.3.0",
|
|
67
67
|
"husky": "~9.1.7",
|
|
68
68
|
"mocha": "~11.7.5",
|
|
69
|
-
"prettier": "~3.
|
|
69
|
+
"prettier": "~3.8.1",
|
|
70
70
|
"rimraf": "~6.1.2",
|
|
71
71
|
"typescript": "~5.9.3"
|
|
72
72
|
}
|
|
@@ -9,10 +9,10 @@ import {RouterHookRegistry, RouterHookType} from './router-hook-registry.js';
|
|
|
9
9
|
describe('RouterHookInvoker', function () {
|
|
10
10
|
describe('invokeAndContinueUntilValueReceived', function () {
|
|
11
11
|
it('requires the parameter "route" to be a Route instance', function () {
|
|
12
|
-
const
|
|
12
|
+
const S = new RouterHookInvoker();
|
|
13
13
|
const res = createResponseMock();
|
|
14
14
|
const throwable = v => () =>
|
|
15
|
-
|
|
15
|
+
S.invokeAndContinueUntilValueReceived(
|
|
16
16
|
v,
|
|
17
17
|
RouterHookType.PRE_HANDLER,
|
|
18
18
|
res,
|
|
@@ -42,7 +42,7 @@ describe('RouterHookInvoker', function () {
|
|
|
42
42
|
});
|
|
43
43
|
|
|
44
44
|
it('requires the parameter "hookType" to be a non-empty String', function () {
|
|
45
|
-
const
|
|
45
|
+
const S = new RouterHookInvoker();
|
|
46
46
|
const route = new Route({
|
|
47
47
|
method: HttpMethod.GET,
|
|
48
48
|
path: ROOT_PATH,
|
|
@@ -50,7 +50,7 @@ describe('RouterHookInvoker', function () {
|
|
|
50
50
|
});
|
|
51
51
|
const res = createResponseMock();
|
|
52
52
|
const throwable = v => () =>
|
|
53
|
-
|
|
53
|
+
S.invokeAndContinueUntilValueReceived(route, v, res);
|
|
54
54
|
const error = v =>
|
|
55
55
|
format(
|
|
56
56
|
'Parameter "hookType" must be a non-empty String, but %s was given.',
|
|
@@ -69,7 +69,7 @@ describe('RouterHookInvoker', function () {
|
|
|
69
69
|
});
|
|
70
70
|
|
|
71
71
|
it('requires the parameter "hookType" to be a supported hook', function () {
|
|
72
|
-
const
|
|
72
|
+
const S = new RouterHookInvoker();
|
|
73
73
|
const route = new Route({
|
|
74
74
|
method: HttpMethod.GET,
|
|
75
75
|
path: ROOT_PATH,
|
|
@@ -77,22 +77,22 @@ describe('RouterHookInvoker', function () {
|
|
|
77
77
|
});
|
|
78
78
|
const res = createResponseMock();
|
|
79
79
|
Object.values(RouterHookType).forEach(type =>
|
|
80
|
-
|
|
80
|
+
S.invokeAndContinueUntilValueReceived(route, type, res),
|
|
81
81
|
);
|
|
82
82
|
const throwable = () =>
|
|
83
|
-
|
|
83
|
+
S.invokeAndContinueUntilValueReceived(route, 'unknown', res);
|
|
84
84
|
expect(throwable).to.throw('Hook type "unknown" is not supported.');
|
|
85
85
|
});
|
|
86
86
|
|
|
87
87
|
it('requires the parameter "response" to be an instance of ServerResponse', function () {
|
|
88
|
-
const
|
|
88
|
+
const S = new RouterHookInvoker();
|
|
89
89
|
const route = new Route({
|
|
90
90
|
method: HttpMethod.GET,
|
|
91
91
|
path: ROOT_PATH,
|
|
92
92
|
handler: () => undefined,
|
|
93
93
|
});
|
|
94
94
|
const throwable = v => () =>
|
|
95
|
-
|
|
95
|
+
S.invokeAndContinueUntilValueReceived(
|
|
96
96
|
route,
|
|
97
97
|
RouterHookType.PRE_HANDLER,
|
|
98
98
|
v,
|
|
@@ -117,15 +117,15 @@ describe('RouterHookInvoker', function () {
|
|
|
117
117
|
});
|
|
118
118
|
|
|
119
119
|
it('invokes global hooks in priority', function () {
|
|
120
|
-
const
|
|
120
|
+
const S = new RouterHookInvoker();
|
|
121
121
|
const order = [];
|
|
122
|
-
|
|
122
|
+
S.getService(RouterHookRegistry).addHook(
|
|
123
123
|
RouterHookType.PRE_HANDLER,
|
|
124
124
|
() => {
|
|
125
125
|
order.push('globalHook1');
|
|
126
126
|
},
|
|
127
127
|
);
|
|
128
|
-
|
|
128
|
+
S.getService(RouterHookRegistry).addHook(
|
|
129
129
|
RouterHookType.PRE_HANDLER,
|
|
130
130
|
() => {
|
|
131
131
|
order.push('globalHook2');
|
|
@@ -144,7 +144,7 @@ describe('RouterHookInvoker', function () {
|
|
|
144
144
|
],
|
|
145
145
|
handler: () => undefined,
|
|
146
146
|
});
|
|
147
|
-
|
|
147
|
+
S.invokeAndContinueUntilValueReceived(
|
|
148
148
|
route,
|
|
149
149
|
RouterHookType.PRE_HANDLER,
|
|
150
150
|
createResponseMock(),
|
|
@@ -158,23 +158,23 @@ describe('RouterHookInvoker', function () {
|
|
|
158
158
|
});
|
|
159
159
|
|
|
160
160
|
it('stops global hooks invocation if any of them returns a value', function () {
|
|
161
|
-
const
|
|
161
|
+
const S = new RouterHookInvoker();
|
|
162
162
|
const order = [];
|
|
163
163
|
const ret = 'OK';
|
|
164
|
-
|
|
164
|
+
S.getService(RouterHookRegistry).addHook(
|
|
165
165
|
RouterHookType.PRE_HANDLER,
|
|
166
166
|
() => {
|
|
167
167
|
order.push('globalHook1');
|
|
168
168
|
},
|
|
169
169
|
);
|
|
170
|
-
|
|
170
|
+
S.getService(RouterHookRegistry).addHook(
|
|
171
171
|
RouterHookType.PRE_HANDLER,
|
|
172
172
|
() => {
|
|
173
173
|
order.push('globalHook2');
|
|
174
174
|
return ret;
|
|
175
175
|
},
|
|
176
176
|
);
|
|
177
|
-
|
|
177
|
+
S.getService(RouterHookRegistry).addHook(
|
|
178
178
|
RouterHookType.PRE_HANDLER,
|
|
179
179
|
() => {
|
|
180
180
|
order.push('globalHook3');
|
|
@@ -193,7 +193,7 @@ describe('RouterHookInvoker', function () {
|
|
|
193
193
|
],
|
|
194
194
|
handler: () => undefined,
|
|
195
195
|
});
|
|
196
|
-
const result =
|
|
196
|
+
const result = S.invokeAndContinueUntilValueReceived(
|
|
197
197
|
route,
|
|
198
198
|
RouterHookType.PRE_HANDLER,
|
|
199
199
|
createResponseMock(),
|
|
@@ -203,16 +203,16 @@ describe('RouterHookInvoker', function () {
|
|
|
203
203
|
});
|
|
204
204
|
|
|
205
205
|
it('stops route hooks invocation if any of them returns a value', function () {
|
|
206
|
-
const
|
|
206
|
+
const S = new RouterHookInvoker();
|
|
207
207
|
const order = [];
|
|
208
208
|
const ret = 'OK';
|
|
209
|
-
|
|
209
|
+
S.getService(RouterHookRegistry).addHook(
|
|
210
210
|
RouterHookType.PRE_HANDLER,
|
|
211
211
|
() => {
|
|
212
212
|
order.push('globalHook1');
|
|
213
213
|
},
|
|
214
214
|
);
|
|
215
|
-
|
|
215
|
+
S.getService(RouterHookRegistry).addHook(
|
|
216
216
|
RouterHookType.PRE_HANDLER,
|
|
217
217
|
() => {
|
|
218
218
|
order.push('globalHook2');
|
|
@@ -235,7 +235,7 @@ describe('RouterHookInvoker', function () {
|
|
|
235
235
|
],
|
|
236
236
|
handler: () => undefined,
|
|
237
237
|
});
|
|
238
|
-
const result =
|
|
238
|
+
const result = S.invokeAndContinueUntilValueReceived(
|
|
239
239
|
route,
|
|
240
240
|
RouterHookType.PRE_HANDLER,
|
|
241
241
|
createResponseMock(),
|
|
@@ -250,10 +250,10 @@ describe('RouterHookInvoker', function () {
|
|
|
250
250
|
});
|
|
251
251
|
|
|
252
252
|
it('returns the given response and should not call hooks if the response is already sent', function () {
|
|
253
|
-
const
|
|
253
|
+
const S = new RouterHookInvoker();
|
|
254
254
|
const res = createResponseMock();
|
|
255
255
|
res._headersSent = true;
|
|
256
|
-
|
|
256
|
+
S.getService(RouterHookRegistry).addHook(
|
|
257
257
|
RouterHookType.PRE_HANDLER,
|
|
258
258
|
() => {
|
|
259
259
|
throw new Error('Should not be called');
|
|
@@ -269,7 +269,7 @@ describe('RouterHookInvoker', function () {
|
|
|
269
269
|
],
|
|
270
270
|
handler: () => undefined,
|
|
271
271
|
});
|
|
272
|
-
const result =
|
|
272
|
+
const result = S.invokeAndContinueUntilValueReceived(
|
|
273
273
|
route,
|
|
274
274
|
RouterHookType.PRE_HANDLER,
|
|
275
275
|
res,
|
|
@@ -278,23 +278,23 @@ describe('RouterHookInvoker', function () {
|
|
|
278
278
|
});
|
|
279
279
|
|
|
280
280
|
it('stops global hooks invocation and returns the given response if it is already sent', function () {
|
|
281
|
-
const
|
|
281
|
+
const S = new RouterHookInvoker();
|
|
282
282
|
const order = [];
|
|
283
283
|
const res = createResponseMock();
|
|
284
|
-
|
|
284
|
+
S.getService(RouterHookRegistry).addHook(
|
|
285
285
|
RouterHookType.PRE_HANDLER,
|
|
286
286
|
() => {
|
|
287
287
|
order.push('globalHook1');
|
|
288
288
|
},
|
|
289
289
|
);
|
|
290
|
-
|
|
290
|
+
S.getService(RouterHookRegistry).addHook(
|
|
291
291
|
RouterHookType.PRE_HANDLER,
|
|
292
292
|
() => {
|
|
293
293
|
order.push('globalHook2');
|
|
294
294
|
res._headersSent = true;
|
|
295
295
|
},
|
|
296
296
|
);
|
|
297
|
-
|
|
297
|
+
S.getService(RouterHookRegistry).addHook(
|
|
298
298
|
RouterHookType.PRE_HANDLER,
|
|
299
299
|
() => {
|
|
300
300
|
order.push('globalHook3');
|
|
@@ -313,7 +313,7 @@ describe('RouterHookInvoker', function () {
|
|
|
313
313
|
],
|
|
314
314
|
handler: () => undefined,
|
|
315
315
|
});
|
|
316
|
-
const result =
|
|
316
|
+
const result = S.invokeAndContinueUntilValueReceived(
|
|
317
317
|
route,
|
|
318
318
|
RouterHookType.PRE_HANDLER,
|
|
319
319
|
res,
|
|
@@ -323,16 +323,16 @@ describe('RouterHookInvoker', function () {
|
|
|
323
323
|
});
|
|
324
324
|
|
|
325
325
|
it('stops route hooks invocation and returns the given response if it is already sent', function () {
|
|
326
|
-
const
|
|
326
|
+
const S = new RouterHookInvoker();
|
|
327
327
|
const order = [];
|
|
328
328
|
const res = createResponseMock();
|
|
329
|
-
|
|
329
|
+
S.getService(RouterHookRegistry).addHook(
|
|
330
330
|
RouterHookType.PRE_HANDLER,
|
|
331
331
|
() => {
|
|
332
332
|
order.push('globalHook1');
|
|
333
333
|
},
|
|
334
334
|
);
|
|
335
|
-
|
|
335
|
+
S.getService(RouterHookRegistry).addHook(
|
|
336
336
|
RouterHookType.PRE_HANDLER,
|
|
337
337
|
() => {
|
|
338
338
|
order.push('globalHook2');
|
|
@@ -355,7 +355,7 @@ describe('RouterHookInvoker', function () {
|
|
|
355
355
|
],
|
|
356
356
|
handler: () => undefined,
|
|
357
357
|
});
|
|
358
|
-
const result =
|
|
358
|
+
const result = S.invokeAndContinueUntilValueReceived(
|
|
359
359
|
route,
|
|
360
360
|
RouterHookType.PRE_HANDLER,
|
|
361
361
|
res,
|
|
@@ -370,21 +370,21 @@ describe('RouterHookInvoker', function () {
|
|
|
370
370
|
});
|
|
371
371
|
|
|
372
372
|
it('returns a Promise if any global hook is asynchronous', async function () {
|
|
373
|
-
const
|
|
373
|
+
const S = new RouterHookInvoker();
|
|
374
374
|
const order = [];
|
|
375
|
-
|
|
375
|
+
S.getService(RouterHookRegistry).addHook(
|
|
376
376
|
RouterHookType.PRE_HANDLER,
|
|
377
377
|
() => {
|
|
378
378
|
order.push('globalHook1');
|
|
379
379
|
},
|
|
380
380
|
);
|
|
381
|
-
|
|
381
|
+
S.getService(RouterHookRegistry).addHook(
|
|
382
382
|
RouterHookType.PRE_HANDLER,
|
|
383
383
|
async () => {
|
|
384
384
|
order.push('globalHook2');
|
|
385
385
|
},
|
|
386
386
|
);
|
|
387
|
-
|
|
387
|
+
S.getService(RouterHookRegistry).addHook(
|
|
388
388
|
RouterHookType.PRE_HANDLER,
|
|
389
389
|
() => {
|
|
390
390
|
order.push('globalHook3');
|
|
@@ -403,7 +403,7 @@ describe('RouterHookInvoker', function () {
|
|
|
403
403
|
],
|
|
404
404
|
handler: () => undefined,
|
|
405
405
|
});
|
|
406
|
-
const promise =
|
|
406
|
+
const promise = S.invokeAndContinueUntilValueReceived(
|
|
407
407
|
route,
|
|
408
408
|
RouterHookType.PRE_HANDLER,
|
|
409
409
|
createResponseMock(),
|
|
@@ -420,15 +420,15 @@ describe('RouterHookInvoker', function () {
|
|
|
420
420
|
});
|
|
421
421
|
|
|
422
422
|
it('returns a Promise if entire global hooks are asynchronous', async function () {
|
|
423
|
-
const
|
|
423
|
+
const S = new RouterHookInvoker();
|
|
424
424
|
const order = [];
|
|
425
|
-
|
|
425
|
+
S.getService(RouterHookRegistry).addHook(
|
|
426
426
|
RouterHookType.PRE_HANDLER,
|
|
427
427
|
async () => {
|
|
428
428
|
order.push('globalHook1');
|
|
429
429
|
},
|
|
430
430
|
);
|
|
431
|
-
|
|
431
|
+
S.getService(RouterHookRegistry).addHook(
|
|
432
432
|
RouterHookType.PRE_HANDLER,
|
|
433
433
|
async () => {
|
|
434
434
|
order.push('globalHook2');
|
|
@@ -447,7 +447,7 @@ describe('RouterHookInvoker', function () {
|
|
|
447
447
|
],
|
|
448
448
|
handler: () => undefined,
|
|
449
449
|
});
|
|
450
|
-
const promise =
|
|
450
|
+
const promise = S.invokeAndContinueUntilValueReceived(
|
|
451
451
|
route,
|
|
452
452
|
RouterHookType.PRE_HANDLER,
|
|
453
453
|
createResponseMock(),
|
|
@@ -463,15 +463,15 @@ describe('RouterHookInvoker', function () {
|
|
|
463
463
|
});
|
|
464
464
|
|
|
465
465
|
it('returns a Promise if any route hook is asynchronous', async function () {
|
|
466
|
-
const
|
|
466
|
+
const S = new RouterHookInvoker();
|
|
467
467
|
const order = [];
|
|
468
|
-
|
|
468
|
+
S.getService(RouterHookRegistry).addHook(
|
|
469
469
|
RouterHookType.PRE_HANDLER,
|
|
470
470
|
() => {
|
|
471
471
|
order.push('globalHook1');
|
|
472
472
|
},
|
|
473
473
|
);
|
|
474
|
-
|
|
474
|
+
S.getService(RouterHookRegistry).addHook(
|
|
475
475
|
RouterHookType.PRE_HANDLER,
|
|
476
476
|
() => {
|
|
477
477
|
order.push('globalHook2');
|
|
@@ -493,7 +493,7 @@ describe('RouterHookInvoker', function () {
|
|
|
493
493
|
],
|
|
494
494
|
handler: () => undefined,
|
|
495
495
|
});
|
|
496
|
-
const promise =
|
|
496
|
+
const promise = S.invokeAndContinueUntilValueReceived(
|
|
497
497
|
route,
|
|
498
498
|
RouterHookType.PRE_HANDLER,
|
|
499
499
|
createResponseMock(),
|
|
@@ -510,15 +510,15 @@ describe('RouterHookInvoker', function () {
|
|
|
510
510
|
});
|
|
511
511
|
|
|
512
512
|
it('returns a Promise if entire route hooks are asynchronous', async function () {
|
|
513
|
-
const
|
|
513
|
+
const S = new RouterHookInvoker();
|
|
514
514
|
const order = [];
|
|
515
|
-
|
|
515
|
+
S.getService(RouterHookRegistry).addHook(
|
|
516
516
|
RouterHookType.PRE_HANDLER,
|
|
517
517
|
() => {
|
|
518
518
|
order.push('globalHook1');
|
|
519
519
|
},
|
|
520
520
|
);
|
|
521
|
-
|
|
521
|
+
S.getService(RouterHookRegistry).addHook(
|
|
522
522
|
RouterHookType.PRE_HANDLER,
|
|
523
523
|
() => {
|
|
524
524
|
order.push('globalHook2');
|
|
@@ -537,7 +537,7 @@ describe('RouterHookInvoker', function () {
|
|
|
537
537
|
],
|
|
538
538
|
handler: () => undefined,
|
|
539
539
|
});
|
|
540
|
-
const promise =
|
|
540
|
+
const promise = S.invokeAndContinueUntilValueReceived(
|
|
541
541
|
route,
|
|
542
542
|
RouterHookType.PRE_HANDLER,
|
|
543
543
|
createResponseMock(),
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {Callable} from '../types.js';
|
|
2
|
+
import {RouteDefinition} from '../route/index.js';
|
|
2
3
|
import {RequestContext} from '../request-context.js';
|
|
3
4
|
import {DebuggableService} from '../debuggable-service.js';
|
|
4
5
|
|
|
@@ -8,6 +9,7 @@ import {DebuggableService} from '../debuggable-service.js';
|
|
|
8
9
|
export declare const RouterHookType: {
|
|
9
10
|
PRE_HANDLER: 'preHandler';
|
|
10
11
|
POST_HANDLER: 'postHandler';
|
|
12
|
+
ON_DEFINE_ROUTE: 'onDefineRoute';
|
|
11
13
|
};
|
|
12
14
|
|
|
13
15
|
/**
|
|
@@ -36,29 +38,17 @@ export type PreHandlerHook = (ctx: RequestContext) => unknown;
|
|
|
36
38
|
*/
|
|
37
39
|
export type PostHandlerHook = (ctx: RequestContext, data: unknown) => unknown;
|
|
38
40
|
|
|
41
|
+
/**
|
|
42
|
+
* On defined route hook.
|
|
43
|
+
*/
|
|
44
|
+
export type OnDefineRouteHook = (
|
|
45
|
+
routeDef: RouteDefinition,
|
|
46
|
+
) => RouteDefinition | undefined;
|
|
47
|
+
|
|
39
48
|
/**
|
|
40
49
|
* Router hook registry.
|
|
41
50
|
*/
|
|
42
51
|
export declare class RouterHookRegistry extends DebuggableService {
|
|
43
|
-
/**
|
|
44
|
-
* Add hook.
|
|
45
|
-
*
|
|
46
|
-
* @param type
|
|
47
|
-
* @param hook
|
|
48
|
-
*/
|
|
49
|
-
addHook(type: typeof RouterHookType.PRE_HANDLER, hook: PreHandlerHook): this;
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Add hook.
|
|
53
|
-
*
|
|
54
|
-
* @param type
|
|
55
|
-
* @param hook
|
|
56
|
-
*/
|
|
57
|
-
addHook(
|
|
58
|
-
type: typeof RouterHookType.POST_HANDLER,
|
|
59
|
-
hook: PostHandlerHook,
|
|
60
|
-
): this;
|
|
61
|
-
|
|
62
52
|
/**
|
|
63
53
|
* Add hook.
|
|
64
54
|
*
|
|
@@ -75,20 +65,6 @@ export declare class RouterHookRegistry extends DebuggableService {
|
|
|
75
65
|
*/
|
|
76
66
|
hasHook(type: RouterHookType, hook: RouterHook): boolean;
|
|
77
67
|
|
|
78
|
-
/**
|
|
79
|
-
* Get hooks.
|
|
80
|
-
*
|
|
81
|
-
* @param type
|
|
82
|
-
*/
|
|
83
|
-
getHooks(type: typeof RouterHookType.PRE_HANDLER): PreHandlerHook[];
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Get hooks.
|
|
87
|
-
*
|
|
88
|
-
* @param type
|
|
89
|
-
*/
|
|
90
|
-
getHooks(type: typeof RouterHookType.POST_HANDLER): PostHandlerHook[];
|
|
91
|
-
|
|
92
68
|
/**
|
|
93
69
|
* Get hooks.
|
|
94
70
|
*
|
|
@@ -6,11 +6,13 @@ import {InvalidArgumentError} from '@e22m4u/js-format';
|
|
|
6
6
|
* @type {{
|
|
7
7
|
* PRE_HANDLER: 'preHandler',
|
|
8
8
|
* POST_HANDLER: 'postHandler',
|
|
9
|
+
* ON_DEFINE_ROUTE: 'onDefineRoute',
|
|
9
10
|
* }}
|
|
10
11
|
*/
|
|
11
12
|
export const RouterHookType = {
|
|
12
13
|
PRE_HANDLER: 'preHandler',
|
|
13
14
|
POST_HANDLER: 'postHandler',
|
|
15
|
+
ON_DEFINE_ROUTE: 'onDefineRoute',
|
|
14
16
|
};
|
|
15
17
|
|
|
16
18
|
/**
|