@e22m4u/ts-rest-router 0.6.6 → 0.6.8

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 CHANGED
@@ -1,53 +1,31 @@
1
1
  # @e22m4u/ts-rest-router
2
2
 
3
- **REST-маршрутизатор на основе контроллеров и TypeScript декораторов.**
4
-
5
- Модуль `@e22m4u/ts-rest-router` позволяет создавать структурированное
6
- и масштабируемое REST API. В его основе лежит декларативный подход
7
- с использованием TypeScript декораторов для определения маршрутов,
8
- обработки входящих данных и управления жизненным циклом запроса.
9
-
10
- ### Особенности
11
-
12
- - **Декларативная маршрутизация**
13
- Определение маршрутов непосредственно над методами контроллера с помощью
14
- декораторов (`@getAction`, `@postAction` и т.д.).
15
- - **Типобезопасная обработка данных**
16
- Автоматическое извлечение, преобразование и валидация данных из `body`,
17
- `query`, `params`, `headers` и `cookie` с привязкой к типизированным
18
- аргументам методов.
19
- - **Встроенная валидация**
20
- Использование схем данных из
21
- [@e22m4u/js-data-schema](https://www.npmjs.com/package/@e22m4u/js-data-schema)
22
- для описания сложных правил проверки.
23
- - **Хуки (`@beforeAction`, `@afterAction`)**
24
- Поддержка хуков для выполнения сквозной логики (например, аутентификация
25
- или логирование) на уровне контроллера и отдельных методов.
26
- - **Изоляция запросов**
27
- Обработка каждого запроса в отдельном DI-контейнере, что гарантирует
28
- отсутствие конфликтов состояний и повышает надежность приложения.
29
- - **Производительность и гибкая архитектура**
30
- Основан на
31
- [@e22m4u/js-trie-router](https://www.npmjs.com/package/@e22m4u/js-trie-router)
32
- для маршрутизации на базе *префиксного дерева* и
33
- [@e22m4u/js-service](https://www.npmjs.com/package/@e22m4u/js-service)
34
- для внедрения зависимостей.
3
+ ![npm version](https://badge.fury.io/js/@e22m4u%2Fts-rest-router.svg)
4
+ ![license](https://img.shields.io/badge/license-mit-blue.svg)
5
+
6
+ REST-маршрутизатор на основе контроллеров и TypeScript декораторов.
7
+
8
+ Данный модуль позволяет создавать структурированное и масштабируемое REST API.
9
+ В его основе лежит декларативный подход с использованием TypeScript декораторов
10
+ для определения маршрутов, обработки входящих данных и управления жизненным
11
+ циклом запроса.
35
12
 
36
13
  ## Содержание
37
14
 
38
15
  - [Установка](#установка)
39
- - [Быстрый старт: Пример сервера](#быстрый-старт-пример-сервера)
40
- - [Обработка данных запроса](#обработка-данных-запроса)
41
- - [URL-параметры (`@requestParam`)](#url-параметры-requestparam)
42
- - [Query-параметры (`@requestQuery`)](#query-параметры-requestquery)
43
- - [Тело запроса (`@requestBody`, `@requestField`)](#тело-запроса-requestbody-requestfield)
44
- - [Заголовки и Cookies](#заголовки-и-cookies)
45
- - [Контекст запроса (`@requestContext`)](#контекст-запроса-requestcontext)
46
- - [Валидация и схемы данных](#валидация-и-схемы-данных)
47
- - [Хуки (`@beforeAction`, `@afterAction`)](#хуки-beforeaction-afteraction)
48
- - [Архитектура: Жизненный цикл контроллера и DI](#архитектура-жизненный-цикл-контроллера-и-di)
49
- - [Производительность: Префиксное дерево](#производительность-префиксное-дерево)
50
- - [Полный список декораторов](#полный-список-декораторов)
16
+ - [Базовый пример](#базовый-пример)
17
+ - [Данные запроса](#данные-запроса)
18
+ - [URL-параметры](#url-параметры)
19
+ - [Query-параметры](#query-параметры)
20
+ - [Тело запроса](#тело-запроса)
21
+ - [Заголовки](#заголовки)
22
+ - [Cookies](#cookies)
23
+ - [Контекст запроса](#контекст-запроса)
24
+ - [Валидация данных](#валидация-данных)
25
+ - [Хуки](#хуки)
26
+ - [Архитектура](#архитектура)
27
+ - [Производительность](#производительность)
28
+ - [Декораторы](#декораторы)
51
29
  - [Отладка](#отладка)
52
30
  - [Тесты](#тесты)
53
31
  - [Лицензия](#лицензия)
@@ -70,7 +48,7 @@ npm install @e22m4u/ts-rest-router
70
48
  }
71
49
  ```
72
50
 
73
- ## Быстрый старт: Пример сервера
51
+ ## Базовый пример
74
52
 
75
53
  Пример создания простого сервера для управления списком пользователей.
76
54
 
@@ -78,42 +56,40 @@ npm install @e22m4u/ts-rest-router
78
56
 
79
57
  ```ts
80
58
  import {
81
- restController,
59
+ DataType,
82
60
  getAction,
83
61
  postAction,
84
62
  requestBody,
85
- DataType,
63
+ restController,
86
64
  } from '@e22m4u/ts-rest-router';
87
65
 
88
- // Временное хранилище данных
89
- const users = [
90
- {id: 1, name: 'John Doe'},
91
- ];
66
+ // временное хранилище данных
67
+ const users = [{id: 1, name: 'John Doe'}];
92
68
 
93
- // 1. Декоратор @restController определяет класс как контроллер
94
- // и устанавливает базовый путь для всех его маршрутов.
69
+ // декоратор @restController определяет класс как контроллер
70
+ // и устанавливает базовый путь для всех его маршрутов
95
71
  @restController('users')
96
72
  export class UserController {
97
- // 2. Декоратор @getAction создает маршрут для GET-запросов.
98
- // Полный путь: GET /users
73
+ // декоратор @getAction создает маршрут для GET-запросов,
74
+ // полный путь: GET /users
99
75
  @getAction()
100
76
  getAllUsers() {
101
- // Результат автоматически сериализуется в JSON
77
+ // результат автоматически сериализуется в JSON
102
78
  return users;
103
79
  }
104
80
 
105
- // 3. Декоратор @postAction создает маршрут для POST-запросов.
106
- // Полный путь: POST /users
81
+ // декоратор @postAction создает маршрут для POST-запросов,
82
+ // полный путь: POST /users
107
83
  @postAction()
108
84
  createUser(
109
- // 4. Декоратор @requestBody извлекает тело запроса,
110
- // проверяет его по схеме и передает в аргумент `newUser`.
85
+ // декоратор @requestBody извлекает тело запроса,
86
+ // проверяет его по схеме и передает в аргумент `newUser`
111
87
  @requestBody({
112
88
  type: DataType.OBJECT,
113
89
  properties: {
114
90
  name: {
115
91
  type: DataType.STRING,
116
- required: true
92
+ required: true,
117
93
  },
118
94
  },
119
95
  })
@@ -121,7 +97,7 @@ export class UserController {
121
97
  ) {
122
98
  const user = {id: users.length + 1, ...newUser};
123
99
  users.push(user);
124
- // Возвращаемый объект будет отправлен клиенту как JSON.
100
+ // возвращаемый объект будет отправлен клиенту как JSON
125
101
  return user;
126
102
  }
127
103
  }
@@ -135,20 +111,19 @@ import {UserController} from './user.controller';
135
111
  import {RestRouter} from '@e22m4u/ts-rest-router';
136
112
 
137
113
  async function bootstrap() {
138
- // Создание экземпляра роутера
114
+ // создание экземпляра роутера
139
115
  const router = new RestRouter();
140
- // Регистрация контроллера
116
+ // регистрация контроллера
141
117
  router.addController(UserController);
142
-
143
- // Создание HTTP-сервера с обработчиком запросов из роутера
118
+ // создание HTTP-сервера с обработчиком запросов из роутера
144
119
  const server = http.createServer(router.requestListener);
145
120
 
146
- // Запуск сервера
121
+ // запуск сервера
147
122
  server.listen(3000, () => {
148
123
  console.log('Server is running on http://localhost:3000');
149
124
  console.log('Try GET http://localhost:3000/users');
150
125
  console.log(
151
- 'Try POST http://localhost:3000/users with body {"name": "Jane Doe"}'
126
+ 'Try POST http://localhost:3000/users with body {"name": "Jane Doe"}',
152
127
  );
153
128
  });
154
129
  }
@@ -156,50 +131,74 @@ async function bootstrap() {
156
131
  bootstrap();
157
132
  ```
158
133
 
159
- ## Обработка данных запроса
134
+ ## Данные запроса
135
+
136
+ Модуль предоставляет TypeScript декораторы для инъекции данных входящего
137
+ запроса через аргументы метода контроллера.
138
+
139
+ ### URL-параметры
140
+
141
+ Извлечение динамических частей URL (например, `:id`).
142
+
143
+ Декораторы:
160
144
 
161
- Модуль предоставляет удобные и типобезопасные механизмы для доступа
162
- к данным входящего запроса.
145
+ - `@requestParam(name, schema)`
146
+ \- извлечение одного параметра;
163
147
 
164
- ### URL-параметры (`@requestParam`)
148
+ - `@requestParams(schema)`
149
+ \- извлечение всех URL-параметров в виде объекта;
165
150
 
166
- Используются для извлечения динамических частей URL (например, `:id`).
151
+ Пример:
167
152
 
168
153
  ```ts
169
- import {getAction, requestParam, DataType} from '@e22m4u/ts-rest-router';
154
+ import {
155
+ DataType,
156
+ getAction,
157
+ requestParam,
158
+ restController,
159
+ } from '@e22m4u/ts-rest-router';
170
160
 
171
161
  @restController('articles')
172
162
  class ArticleController {
173
- // Маршрут: GET /articles/42
163
+ // GET /articles/42
174
164
  @getAction(':id')
175
165
  getArticleById(
176
- // Извлечение параметра 'id' с проверкой на соответствие
177
- // типу "number"
166
+ // извлечение параметра 'id' с проверкой
167
+ // на соответствие типу "number"
178
168
  @requestParam('id', DataType.NUMBER) id: number,
179
169
  ) {
180
- // Если id не является числом, фреймворк вернет ошибку
181
- // 400 Bad Request
170
+ // если id не является числом,
171
+ // то выбрасывается ошибка 400 Bad Request
182
172
  return {articleId: id, content: '...'};
183
173
  }
184
174
  }
185
175
  ```
186
176
 
187
- **Декораторы:**
177
+ ### Query-параметры
178
+
179
+ Извлечение параметров из строки запроса (например, `?sort=desc`).
188
180
 
189
- - `@requestParam(name, schema)` - извлечение одного параметра;
190
- - `@requestParams(schema)` - извлечение всех URL-параметров в виде объекта;
181
+ Декораторы:
191
182
 
192
- ### Query-параметры (`@requestQuery`)
183
+ - `@requestQuery(name, schema)`
184
+ \- извлечение одного query-параметра;
193
185
 
194
- Применяются для извлечения параметров из строки запроса
195
- (например, `?sort=desc`).
186
+ - `@requestQueries(schema)`
187
+ \- извлечение всех query-параметров в виде объекта;
188
+
189
+ Пример:
196
190
 
197
191
  ```ts
198
- import {getAction, requestQuery, DataType} from '@e22m4u/ts-rest-router';
192
+ import {
193
+ DataType,
194
+ getAction,
195
+ requestQuery,
196
+ restController,
197
+ } from '@e22m4u/ts-rest-router';
199
198
 
200
199
  @restController('products')
201
200
  class ProductController {
202
- // Маршрут: GET /products/search?q=phone&limit=10
201
+ // GET /products/search?q=phone&limit=10
203
202
  @getAction('search')
204
203
  searchProducts(
205
204
  @requestQuery('q', {
@@ -213,19 +212,14 @@ class ProductController {
213
212
  })
214
213
  limit: number,
215
214
  ) {
216
- // searchTerm будет 'phone', limit будет 10.
217
- // При отсутствии 'q' будет ошибка. При отсутствии 'limit'
218
- // будет использовано значение по умолчанию 20.
215
+ // searchTerm будет 'phone', limit будет 10;
216
+ // при отсутствии 'q' будет ошибка;
217
+ // при отсутствии 'limit' будет использовано значение по умолчанию 20;
219
218
  return {results: [], query: {searchTerm, limit}};
220
219
  }
221
220
  }
222
221
  ```
223
222
 
224
- **Декораторы:**
225
-
226
- - `@requestQuery(name, schema)` - извлечение одного query-параметра;
227
- - `@requestQueries(schema)` - извлечение всех query-параметров в виде объекта;
228
-
229
223
  **Именование Query-декораторов**
230
224
 
231
225
  Разделение на декораторы в единственном `@requestQuery` и множественном
@@ -235,21 +229,32 @@ class ProductController {
235
229
  извлечения и валидации отдельных значений, в то время как множественное число
236
230
  служит для получения всех данных в виде единого объекта.
237
231
 
238
- ### Тело запроса (`@requestBody`, `@requestField`)
232
+ ### Тело запроса
233
+
234
+ Извлечение тела запроса POST, PUT, PATCH методов.
235
+
236
+ Декораторы:
237
+
238
+ - `@requestBody(schema)`
239
+ \- извлечение тела запроса;
240
+
241
+ - `@requestField(name, schema)`
242
+ \- извлечение отдельного поля из тела запроса;
239
243
 
240
- Для работы с данными, отправленными в теле POST, PUT, PATCH запросов.
244
+ Пример:
241
245
 
242
246
  ```ts
243
247
  import {
248
+ DataType,
244
249
  postAction,
245
250
  requestBody,
246
251
  requestField,
247
- DataType,
252
+ restController,
248
253
  } from '@e22m4u/ts-rest-router';
249
254
 
250
255
  @restController('users')
251
256
  class UserController {
252
- // Пример с @requestBody: получение и валидация всего тела запроса
257
+ // пример с @requestBody: получение и валидация всего тела запроса
253
258
  @postAction()
254
259
  createUser(
255
260
  @requestBody({
@@ -265,12 +270,15 @@ class UserController {
265
270
  },
266
271
  },
267
272
  })
268
- body: {username: string; email: string},
273
+ body: {
274
+ username: string;
275
+ email: string;
276
+ },
269
277
  ) {
270
278
  return {id: 1, ...body};
271
279
  }
272
280
 
273
- // Пример с @requestField: получение только одного поля из тела
281
+ // пример с @requestField: получение только одного поля из тела
274
282
  @postAction('login')
275
283
  login(
276
284
  @requestField('username', DataType.STRING) username: string,
@@ -282,19 +290,89 @@ class UserController {
282
290
  }
283
291
  ```
284
292
 
285
- **Декораторы:**
293
+ ### Заголовки
294
+
295
+ Извлечение HTTP-заголовков запроса.
296
+
297
+ Декораторы:
298
+
299
+ - `@requestHeader(name, schema)`
300
+ \- извлечение отдельного заголовка;
301
+
302
+ - `@requestHeaders(schema)`
303
+ \- извлечение всех заголовков;
304
+
305
+ Пример:
306
+
307
+ ```ts
308
+ import {
309
+ DataType,
310
+ getAction,
311
+ requestHeader,
312
+ } from '@e22m4u/ts-rest-router';
313
+
314
+ @restController('content')
315
+ class ContentController {
316
+ // GET /content
317
+ @getAction()
318
+ getContentForLanguage(
319
+ // извлечение заголовка 'Accept-Language'
320
+ // со значением по умолчанию 'en'
321
+ @requestHeader('Accept-Language', {
322
+ type: DataType.STRING,
323
+ default: 'en',
324
+ })
325
+ lang: string,
326
+ ) {
327
+ // lang будет 'en', если заголовок отсутствует,
328
+ // или будет содержать значение заголовка, например 'ru-RU'
329
+ return {content: `Content in ${lang} language`};
330
+ }
331
+ }
332
+ ```
333
+
334
+ ### Cookies
286
335
 
287
- - `@requestBody(schema)` - извлечение тела запроса;
288
- - `@requestField(name, schema)` - извлечение отдельного поля из тела запроса;
336
+ Извлечение разобранного заголовка Cookies входящего запроса.
289
337
 
290
- ### Заголовки и Cookies
338
+ Декораторы:
291
339
 
292
- Работа с заголовками и cookies осуществляется аналогичным образом:
340
+ - `@requestCookie(name, schema)`
341
+ \- извлечение отдельного Cookie по ключу;
342
+
343
+ - `@requestCookies(schema)`
344
+ \- извлечение всех Cookies;
345
+
346
+ Пример:
347
+
348
+ ```ts
349
+ import {
350
+ DataType,
351
+ getAction,
352
+ requestCookie,
353
+ } from '@e22m4u/ts-rest-router';
293
354
 
294
- - `@requestHeader(name, schema)` / `@requestHeaders(schema)`
295
- - `@requestCookie(name, schema)` / `@requestCookies(schema)`
355
+ @restController('session')
356
+ class SessionController {
357
+ // GET /session/info
358
+ @getAction('info')
359
+ getSessionInfo(
360
+ // извлечение cookie с именем 'sessionId'
361
+ // и проверка, что значение является строкой
362
+ @requestCookie('sessionId', {
363
+ type: DataType.STRING,
364
+ required: true,
365
+ })
366
+ sessionId: string,
367
+ ) {
368
+ // если cookie 'sessionId' отсутствует,
369
+ // будет выброшена ошибка 400 Bad Request
370
+ return {sessionId, info: 'User session data...'};
371
+ }
372
+ }
373
+ ```
296
374
 
297
- ### Контекст запроса (`@requestContext`)
375
+ ### Контекст запроса
298
376
 
299
377
  Для доступа к "сырым" объектам запроса/ответа Node.js или другим частям
300
378
  контекста используются следующие декораторы:
@@ -303,11 +381,14 @@ class UserController {
303
381
  - `@requestContext('req')` - инъекция нативного `IncomingMessage`;
304
382
  - `@requestContext('res')` - инъекция нативного `ServerResponse`;
305
383
  - `@requestContext('container')` - инъекция DI-контейнера запроса;
306
- - **Алиасы:** `@httpRequest()`, `@httpResponse()`, `@requestContainer()`;
384
+ - Псевдонимы: `@httpRequest()`, `@httpResponse()`, `@requestContainer()`;
307
385
 
308
386
  ```ts
309
- import {getAction, requestContext} from '@e22m4u/ts-rest-router';
310
- import {RequestContext} from '@e22m4u/js-trie-router';
387
+ import {
388
+ getAction,
389
+ requestContext,
390
+ RequestContext,
391
+ } from '@e22m4u/ts-rest-router';
311
392
 
312
393
  @restController('system')
313
394
  class SystemController {
@@ -323,14 +404,14 @@ class SystemController {
323
404
  }
324
405
  ```
325
406
 
326
- ## Валидация и схемы данных
407
+ ## Валидация данных
327
408
 
328
409
  Модуль интегрирован с
329
410
  [@e22m4u/js-data-schema](https://www.npmjs.com/package/@e22m4u/js-data-schema)
330
411
  для гибкой проверки данных. Это дает возможность определять типы данных
331
412
  и сложные правила.
332
413
 
333
- **Базовые типы `DataType`:**
414
+ Базовые типы:
334
415
 
335
416
  - `DataType.ANY`
336
417
  - `DataType.STRING`
@@ -339,23 +420,28 @@ class SystemController {
339
420
  - `DataType.ARRAY`
340
421
  - `DataType.OBJECT`
341
422
 
342
- Для более сложных проверок используется объект `DataSchema`:
423
+ Для более сложных проверок используется объект схемы:
343
424
 
344
425
  ```ts
345
426
  type DataSchema = {
346
- type: DataType; // Обязательное поле
347
- required?: boolean; // Значение не может быть null или undefined
348
- default?: unknown; // Значение по умолчанию, если `required: false`
349
- items?: DataSchema; // Схема для элементов массива (для type: DataType.ARRAY)
350
- properties?: {[key: string]: DataSchema}; // Схема для свойств объекта
351
- validate?: (value: any) => boolean | string; // Пользовательская функция
352
- }
427
+ type: DataType; // обязательное поле
428
+ required?: boolean; // значение не может быть null или undefined
429
+ default?: unknown; // значение по умолчанию, если `required: false`
430
+ items?: DataSchema; // схема для элементов массива (для type: DataType.ARRAY)
431
+ properties?: {[key: string]: DataSchema}; // схема для свойств объекта
432
+ validate?: (value: any) => boolean | string; // пользовательская функция
433
+ };
353
434
  ```
354
435
 
355
- **Пример сложной валидации:**
436
+ Пример сложной валидации:
356
437
 
357
438
  ```ts
358
- import {postAction, requestBody, DataType} from '@e22m4u/ts-rest-router';
439
+ import {
440
+ DataType,
441
+ postAction,
442
+ requestBody,
443
+ restController,
444
+ } from '@e22m4u/ts-rest-router';
359
445
 
360
446
  @restController('orders')
361
447
  class OrderController {
@@ -371,68 +457,74 @@ class OrderController {
371
457
  products: {
372
458
  type: DataType.ARRAY,
373
459
  required: true,
374
- // Описание схемы для каждого элемента массива:
460
+ // описание схемы для каждого элемента массива
375
461
  items: {
376
462
  type: DataType.OBJECT,
377
463
  properties: {
378
464
  id: {
379
465
  type: DataType.NUMBER,
380
- required: true
466
+ required: true,
381
467
  },
382
468
  quantity: {
383
469
  type: DataType.NUMBER,
384
470
  required: true,
385
- // Валидатор: количество должно быть больше 0
386
- validate: (qty) => qty > 0 || 'Quantity must be positive',
471
+ // валидатор: количество должно быть больше 0
472
+ validate: qty => qty > 0 || 'Quantity must be positive',
387
473
  },
388
474
  },
389
475
  },
390
476
  },
391
477
  },
392
478
  })
393
- orderData: { /* ... */ },
479
+ orderData: {
480
+ /* ... */
481
+ },
394
482
  ) {
395
483
  // ...
396
484
  }
397
485
  }
398
486
  ```
399
487
 
400
- ## Хуки (`@beforeAction`, `@afterAction`)
488
+ ## Хуки
489
+
490
+ Функции, выполняющиеся до или после основного метода контроллера именуются
491
+ «Хуками». Они предназначены для сквозной логики, такой как аутентификация,
492
+ логирование или модификация ответа. Применение хуков возможно как ко всему
493
+ контроллеру, так и к отдельному методу.
401
494
 
402
- Хуки - это функции, выполняющиеся до (`@beforeAction`) или после
403
- (`@afterAction`) основного метода контроллера. Они предназначены для
404
- сквозной логики, такой как аутентификация, логирование или модификация
405
- ответа.
495
+ Декораторы:
406
496
 
407
- Применение хуков возможно как ко всему контроллеру, так и к отдельному
408
- методу.
497
+ - `@beforeAction(preHandler)` - выполняется перед методом контроллера;
498
+ - `@afterAction(postHandler)` - выполняется после метода контроллера;
499
+
500
+ Пример:
409
501
 
410
502
  ```ts
411
- import {RequestContext} from '@e22m4u/js-trie-router';
412
503
  import createError from 'http-errors';
504
+ import {RequestContext} from '@e22m4u/ts-rest-router';
413
505
 
414
- // Хук для проверки аутентификации
506
+ // хук для проверки аутентификации
415
507
  async function authHook(ctx: RequestContext) {
416
508
  const token = ctx.headers.authorization;
417
509
  if (!token /* || !isValidToken(token) */) {
418
- // Выброс ошибки прерывает выполнение и отправляет клиенту
419
- // соответствующий HTTP-статус.
510
+ // выброс ошибки прерывает выполнение и отправляет
511
+ // клиенту соответствующий HTTP-статус
420
512
  throw createError(401, 'Unauthorized');
421
513
  }
422
514
  }
423
515
 
424
- // Хук для логирования и модификации ответа
516
+ // хук для логирования и модификации ответа
425
517
  async function loggerHook(ctx: RequestContext, data: any) {
426
518
  console.log(`Response for ${ctx.pathname}:`, data);
427
- // Хуки @afterAction могут модифицировать ответ
519
+ // хуки @afterAction могут модифицировать ответ
428
520
  return {...data, timestamp: new Date()};
429
521
  }
430
522
 
431
- @beforeAction(authHook) // Применение ко всем методам контроллера
523
+ @beforeAction(authHook) // применение ко всем методам контроллера
432
524
  @restController('profile')
433
525
  class ProfileController {
434
526
  @getAction('me')
435
- @afterAction(loggerHook) // Применение только к этому методу
527
+ @afterAction(loggerHook) // применение только к этому методу
436
528
  getMyProfile() {
437
529
  return {id: 1, name: 'Current User'};
438
530
  }
@@ -444,23 +536,23 @@ class ProfileController {
444
536
  }
445
537
  ```
446
538
 
447
- ## Архитектура: Жизненный цикл контроллера и DI
539
+ ## Архитектура
448
540
 
449
541
  Понимание архитектурных принципов `ts-rest-router` является ключом
450
542
  к созданию надежных и масштабируемых приложений. Модуль построен на
451
543
  базе библиотеки `@e22m4u/js-service`, реализующей паттерн
452
544
  Service Locator / Dependency Injection.
453
545
 
454
- #### Принцип №1: Изоляция запросов
546
+ #### Изоляция запросов
455
547
 
456
- Для **каждого** входящего HTTP-запроса создается **новый, изолированный
457
- экземпляр контроллера**. Этот фундаментальный принцип гарантирует, что
548
+ Для каждого входящего HTTP-запроса создается новый, изолированный
549
+ экземпляр контроллера. Этот фундаментальный принцип гарантирует, что
458
550
  состояние одного запроса (например, данные аутентифицированного
459
551
  пользователя) никогда не будет разделено с другим, одновременно
460
552
  обрабатываемым запросом. Это устраняет целый класс потенциальных
461
553
  ошибок, связанных с состоянием гонки.
462
554
 
463
- #### Принцип №2: Request-Scoped Service Container
555
+ #### Внедрение зависимостей
464
556
 
465
557
  Каждый экземпляр контроллера создается с помощью своего собственного
466
558
  DI-контейнера, который существует только в рамках одного запроса. Чтобы
@@ -471,31 +563,31 @@ DI-контейнера, который существует только в р
471
563
 
472
564
  **Практический пример с сервисом аутентификации:**
473
565
 
474
- **Шаг 1: Создание хука для подготовки сервиса**
566
+ 1\. Создание хука для подготовки сервиса.
475
567
 
476
- Хуки - идеальное место для подготовки сервисов, специфичных для запроса.
477
- В этом примере хук `@beforeAction` создает экземпляр `AuthService`,
568
+ С помощью хука можно подготовить сервис, специфичный для каждого запроса.
569
+ В данном примере хук `@beforeAction` создает экземпляр `AuthService`,
478
570
  выполняет аутентификацию и регистрирует его в контейнере запроса.
479
571
 
480
572
  ```ts
481
573
  // src/auth.hook.ts
482
574
  import {AuthService} from './auth.service';
483
- import {RequestContext} from '@e22m4u/js-trie-router';
575
+ import {RequestContext} from '@e22m4u/ts-rest-router';
484
576
 
485
577
  export async function authHook(context: RequestContext) {
486
578
  const requestContainer = context.container;
487
- // Создание сервиса с передачей ему контейнера запроса
579
+ // создание сервиса с передачей ему контейнера запроса
488
580
  const authService = new AuthService(requestContainer);
489
- // Регистрация созданного экземпляра в контейнере.
490
- // Теперь любой другой сервис в рамках этого запроса
491
- // сможет получить этот конкретный экземпляр.
581
+ // регистрация созданного экземпляра в контейнере
582
+ // (теперь любой другой сервис в рамках текущего
583
+ // запроса сможет получить данный экземпляр)
492
584
  requestContainer.set(AuthService, authService);
493
- // Выполнение логики аутентификации
585
+ // выполнение логики аутентификации
494
586
  await authService.authenticate(context.headers.authorization);
495
587
  }
496
588
  ```
497
589
 
498
- **Шаг 2: Создание `AuthService`**
590
+ 2\. Создание `AuthService`.
499
591
 
500
592
  `AuthService` наследуется от `Service`, что позволяет ему запрашивать другие
501
593
  зависимости (например, `this.getService(DatabaseService)`).
@@ -505,18 +597,19 @@ export async function authHook(context: RequestContext) {
505
597
  import {Service} from '@e22m4u/js-service';
506
598
 
507
599
  export class AuthService extends Service {
508
- public currentUser?: {id: number; name: string;};
600
+ public currentUser?: {id: number; name: string};
509
601
 
510
602
  async authenticate(token?: string) {
511
- // Логика проверки токена и поиска пользователя в БД...
603
+ // логика проверки токена и поиска
604
+ // пользователя в базе данных...
512
605
  if (token === 'valid-token') {
513
- this.currentUser = { id: 1, name: 'John Doe' };
606
+ this.currentUser = {id: 1, name: 'John Doe'};
514
607
  }
515
608
  }
516
609
  }
517
610
  ```
518
611
 
519
- **Шаг 3: Использование сервиса в контроллере**
612
+ 3\. Использование сервиса в контроллере.
520
613
 
521
614
  Контроллер, унаследованный от `Service`, теперь может получить
522
615
  доступ к предварительно настроенному экземпляру `AuthService`
@@ -528,24 +621,21 @@ import {authHook} from './auth.hook';
528
621
  import createError from 'http-errors';
529
622
  import {Service} from '@e22m4u/js-service';
530
623
  import {AuthService} from './auth.service';
531
- import {
532
- getAction,
533
- restController,
534
- beforeAction,
535
- } from '@e22m4u/ts-rest-router';
624
+ import {getAction, beforeAction, restController} from '@e22m4u/ts-rest-router';
536
625
 
537
626
  @beforeAction(authHook)
538
627
  @restController('profile')
539
628
  export class ProfileController extends Service {
540
629
  @getAction('me')
541
630
  getProfile() {
542
- // Получение request-scoped экземпляра AuthService,
543
- // который был создан и зарегистрирован в хуке.
631
+ // получение request-scoped экземпляра AuthService,
632
+ // который был создан и зарегистрирован в хуке
544
633
  const authService = this.getService(AuthService);
545
634
 
546
- if (!authService.currentUser)
635
+ if (!authService.currentUser) {
547
636
  throw createError(401, 'Unauthorized');
548
-
637
+ }
638
+
549
639
  return authService.currentUser;
550
640
  }
551
641
  }
@@ -555,12 +645,12 @@ export class ProfileController extends Service {
555
645
  и контроллером, позволяя безопасно передавать состояние, изолированное
556
646
  в рамках одного HTTP-запроса.
557
647
 
558
- ## Производительность: Префиксное дерево
648
+ ## Производительность
559
649
 
560
650
  В основе данного модуля лежит
561
651
  [@e22m4u/js-trie-router](https://www.npmjs.com/package/@e22m4u/js-trie-router),
562
652
  который использует структуру данных
563
- **префиксного дерева** ([Trie](https://en.wikipedia.org/wiki/Trie))
653
+ *префиксного дерева ([Trie](https://en.wikipedia.org/wiki/Trie))*
564
654
  для хранения маршрутов и их сопоставления. Такое архитектурное решение
565
655
  обеспечивает высокую производительность, особенно в приложениях
566
656
  с большим количеством маршрутов.
@@ -576,41 +666,39 @@ export class ProfileController extends Service {
576
666
  маршрутизатор не перебирает все существующие маршруты. Вместо этого
577
667
  он последовательно спускается по дереву:
578
668
 
579
- 1. Находит корневой узел для метода `GET`.
580
- 2. От него переходит к дочернему узлу `users`.
581
- 3. Далее, не найдя статического узла `123`, он ищет динамический
582
- узел (`:id`) и сопоставляет его, сохраняя `123` как значение
583
- параметра `id`.
584
- 4. Наконец, он переходит к узлу `posts` и находит совпадение.
585
-
586
- #### Преимущества для производительности
587
-
588
- 1. **Эффективный поиск (O(k))**
589
- Самое главное преимущество скорость поиска. Вместо того чтобы
590
- перебирать массив из `N` маршрутов и проверять каждый с помощью
591
- регулярного выражения (сложность `O(N)`), префиксное дерево
592
- находит совпадение за время, пропорциональное количеству сегментов
593
- `k` в URL-пути (сложность `O(k)`). Это означает, что производительность
594
- поиска **не падает** с ростом общего числа маршрутов в приложении.
595
-
596
- 2. **Быстрая обработка 404 (ранний выход)**
597
- Если приходит запрос на несуществующий путь, например
598
- `/users/123/comments`, поиск по дереву прекратится сразу после
599
- того, как маршрутизатор не найдет дочерний узел `comments`
600
- у узла `:id`. Ему не нужно проверять остальные сотни маршрутов,
601
- чтобы убедиться, что совпадений нет. Это делает обработку
602
- ненайденных маршрутов (404) почти мгновенной.
603
-
604
- 3. **Оптимизация для статических и динамических маршрутов**
605
- При поиске маршрутизатор всегда отдает приоритет статическим
606
- сегментам перед динамическими. Маршрут `/users/me` всегда будет
607
- найден раньше и быстрее, чем `/users/:id` при запросе `/users/me`,
608
- поскольку не требуется проверка на соответствие шаблону.
609
-
610
- Этот подход делает `ts-rest-router` производительным решением для крупных
611
- приложений с большим количеством маршрутов.
612
-
613
- ## Полный список декораторов
669
+ 1. Находит корневой узел для метода `GET`.
670
+ 2. От него переходит к дочернему узлу `users`.
671
+ 3. Далее, не найдя статического узла `123`, он ищет динамический
672
+ узел (`:id`) и сопоставляет его, сохраняя `123` как значение
673
+ параметра `id`.
674
+ 4. Наконец, он переходит к узлу `posts` и находит совпадение.
675
+
676
+ **Эффективный поиск маршрута O(k)**
677
+
678
+ Самое главное преимущество - скорость поиска. Вместо того чтобы
679
+ перебирать массив из `N` маршрутов и проверять каждый с помощью
680
+ регулярного выражения (сложность `O(N)`), префиксное дерево
681
+ находит совпадение за время, пропорциональное количеству сегментов
682
+ `K` в URL-пути (сложность `O(K)`). Это означает, что производительность
683
+ поиска не падает с ростом общего числа маршрутов в приложении.
684
+
685
+ **Быстрая обработка 404 (ранний выход)**
686
+
687
+ Если приходит запрос на несуществующий путь, например
688
+ `/users/123/comments`, поиск по дереву прекратится сразу после
689
+ того, как маршрутизатор не найдет дочерний узел `comments`
690
+ у узла `:id`. Ему не нужно проверять остальные сотни маршрутов,
691
+ чтобы убедиться, что совпадений нет. Это делает обработку
692
+ неопределенных маршрутов (404) почти мгновенной.
693
+
694
+ **Оптимизация для статических и динамических маршрутов**
695
+
696
+ При поиске маршрутизатор всегда отдает приоритет статическим
697
+ сегментам перед динамическими. Маршрут `/users/me` всегда будет
698
+ найден раньше и быстрее, чем `/users/:id` при запросе `/users/me`,
699
+ поскольку не требуется проверка на соответствие шаблону.
700
+
701
+ ## Декораторы
614
702
 
615
703
  #### Контроллер и методы:
616
704
 
@@ -667,4 +755,4 @@ npm run test
667
755
 
668
756
  ## Лицензия
669
757
 
670
- MIT
758
+ MIT
@@ -32,7 +32,7 @@ __export(index_exports, {
32
32
  RESPONSE_BODY_METADATA_KEY: () => RESPONSE_BODY_METADATA_KEY,
33
33
  REST_ACTIONS_METADATA_KEY: () => REST_ACTIONS_METADATA_KEY,
34
34
  REST_CONTROLLER_METADATA_KEY: () => REST_CONTROLLER_METADATA_KEY,
35
- RequestContext: () => import_js_trie_router4.RequestContext,
35
+ RequestContext: () => import_js_trie_router5.RequestContext,
36
36
  RequestContextReflector: () => RequestContextReflector,
37
37
  RequestDataReflector: () => RequestDataReflector,
38
38
  RequestDataSource: () => RequestDataSource,
@@ -40,6 +40,7 @@ __export(index_exports, {
40
40
  RestActionReflector: () => RestActionReflector,
41
41
  RestControllerReflector: () => RestControllerReflector,
42
42
  RestRouter: () => RestRouter,
43
+ RouterHookType: () => import_js_trie_router4.RouterHookType,
43
44
  afterAction: () => afterAction,
44
45
  beforeAction: () => beforeAction,
45
46
  deleteAction: () => deleteAction,
@@ -204,7 +205,7 @@ var RequestDataSource;
204
205
  RequestDataSource2["PARAMS"] = "params";
205
206
  RequestDataSource2["QUERY"] = "query";
206
207
  RequestDataSource2["HEADERS"] = "headers";
207
- RequestDataSource2["COOKIE"] = "cookie";
208
+ RequestDataSource2["COOKIES"] = "cookies";
208
209
  RequestDataSource2["BODY"] = "body";
209
210
  })(RequestDataSource || (RequestDataSource = {}));
210
211
  var REQUEST_DATA_METADATA_KEY = new import_ts_reflector5.MetadataKey("requestDataMetadataKey");
@@ -304,8 +305,8 @@ var requestQueries = createRequestDataDecoratorWithSource(RequestDataSource.QUER
304
305
  var requestQuery = createRequestDataPropertyDecoratorWithSource(RequestDataSource.QUERY);
305
306
  var requestHeaders = createRequestDataDecoratorWithSource(RequestDataSource.HEADERS);
306
307
  var requestHeader = createRequestDataPropertyDecoratorWithSource(RequestDataSource.HEADERS);
307
- var requestCookies = createRequestDataDecoratorWithSource(RequestDataSource.COOKIE);
308
- var requestCookie = createRequestDataPropertyDecoratorWithSource(RequestDataSource.COOKIE);
308
+ var requestCookies = createRequestDataDecoratorWithSource(RequestDataSource.COOKIES);
309
+ var requestCookie = createRequestDataPropertyDecoratorWithSource(RequestDataSource.COOKIES);
309
310
  var requestBody = createRequestDataDecoratorWithSource(RequestDataSource.BODY);
310
311
  var requestField = createRequestDataPropertyDecoratorWithSource(RequestDataSource.BODY);
311
312
 
@@ -895,7 +896,7 @@ var _ControllerRegistry = class _ControllerRegistry extends DebuggableService {
895
896
  case RequestDataSource.HEADERS:
896
897
  data = requestContext2.headers;
897
898
  break;
898
- case RequestDataSource.COOKIE:
899
+ case RequestDataSource.COOKIES:
899
900
  data = requestContext2.cookies;
900
901
  break;
901
902
  case RequestDataSource.BODY:
@@ -980,6 +981,7 @@ var RestRouter = _RestRouter;
980
981
 
981
982
  // dist/esm/index.js
982
983
  var import_js_trie_router4 = require("@e22m4u/js-trie-router");
984
+ var import_js_trie_router5 = require("@e22m4u/js-trie-router");
983
985
  // Annotate the CommonJS export names for ESM import in node:
984
986
  0 && (module.exports = {
985
987
  AFTER_ACTION_METADATA_KEY,
@@ -1001,6 +1003,7 @@ var import_js_trie_router4 = require("@e22m4u/js-trie-router");
1001
1003
  RestActionReflector,
1002
1004
  RestControllerReflector,
1003
1005
  RestRouter,
1006
+ RouterHookType,
1004
1007
  afterAction,
1005
1008
  beforeAction,
1006
1009
  deleteAction,
@@ -372,7 +372,7 @@ export class ControllerRegistry extends DebuggableService {
372
372
  case RequestDataSource.HEADERS:
373
373
  data = requestContext.headers;
374
374
  break;
375
- case RequestDataSource.COOKIE:
375
+ case RequestDataSource.COOKIES:
376
376
  data = requestContext.cookies;
377
377
  break;
378
378
  case RequestDataSource.BODY:
@@ -82,7 +82,7 @@ export const requestQueries = createRequestDataDecoratorWithSource(RequestDataSo
82
82
  export const requestQuery = createRequestDataPropertyDecoratorWithSource(RequestDataSource.QUERY);
83
83
  export const requestHeaders = createRequestDataDecoratorWithSource(RequestDataSource.HEADERS);
84
84
  export const requestHeader = createRequestDataPropertyDecoratorWithSource(RequestDataSource.HEADERS);
85
- export const requestCookies = createRequestDataDecoratorWithSource(RequestDataSource.COOKIE);
86
- export const requestCookie = createRequestDataPropertyDecoratorWithSource(RequestDataSource.COOKIE);
85
+ export const requestCookies = createRequestDataDecoratorWithSource(RequestDataSource.COOKIES);
86
+ export const requestCookie = createRequestDataPropertyDecoratorWithSource(RequestDataSource.COOKIES);
87
87
  export const requestBody = createRequestDataDecoratorWithSource(RequestDataSource.BODY);
88
88
  export const requestField = createRequestDataPropertyDecoratorWithSource(RequestDataSource.BODY);
@@ -126,7 +126,7 @@ describe('requestData', function () {
126
126
  ], Target.prototype, "myMethod", null);
127
127
  const res = RequestDataReflector.getMetadata(Target, 'myMethod');
128
128
  expect(res.get(0)).to.be.eql({
129
- source: RequestDataSource.COOKIE,
129
+ source: RequestDataSource.COOKIES,
130
130
  schema: { type: DataType.ANY },
131
131
  });
132
132
  });
@@ -554,7 +554,7 @@ describe('requestData', function () {
554
554
  ], Target.prototype, "myMethod", null);
555
555
  const res = RequestDataReflector.getMetadata(Target, 'myMethod');
556
556
  expect(res.get(0)).to.be.eql({
557
- source: RequestDataSource.COOKIE,
557
+ source: RequestDataSource.COOKIES,
558
558
  schema: {
559
559
  type: DataType.OBJECT,
560
560
  properties: {
@@ -580,7 +580,7 @@ describe('requestData', function () {
580
580
  ], Target.prototype, "myMethod", null);
581
581
  const res = RequestDataReflector.getMetadata(Target, 'myMethod');
582
582
  expect(res.get(0)).to.be.eql({
583
- source: RequestDataSource.COOKIE,
583
+ source: RequestDataSource.COOKIES,
584
584
  schema: {
585
585
  type: DataType.OBJECT,
586
586
  properties: {
@@ -609,7 +609,7 @@ describe('requestData', function () {
609
609
  ], Target.prototype, "myMethod", null);
610
610
  const res = RequestDataReflector.getMetadata(Target, 'myMethod');
611
611
  expect(res.get(0)).to.be.eql({
612
- source: RequestDataSource.COOKIE,
612
+ source: RequestDataSource.COOKIES,
613
613
  schema: {
614
614
  type: DataType.OBJECT,
615
615
  properties: {
@@ -637,7 +637,7 @@ describe('requestData', function () {
637
637
  ], Target.prototype, "myMethod", null);
638
638
  const mdMap = RequestDataReflector.getMetadata(Target, 'myMethod');
639
639
  const md = mdMap.get(0);
640
- expect(md.source).to.be.eq(RequestDataSource.COOKIE);
640
+ expect(md.source).to.be.eq(RequestDataSource.COOKIES);
641
641
  expect(md.schema).to.be.a('function');
642
642
  expect(md.property).to.be.eq(propertyKey);
643
643
  const res1 = md.schema;
@@ -7,7 +7,7 @@ export declare enum RequestDataSource {
7
7
  PARAMS = "params",
8
8
  QUERY = "query",
9
9
  HEADERS = "headers",
10
- COOKIE = "cookie",
10
+ COOKIES = "cookies",
11
11
  BODY = "body"
12
12
  }
13
13
  /**
@@ -7,7 +7,7 @@ export var RequestDataSource;
7
7
  RequestDataSource["PARAMS"] = "params";
8
8
  RequestDataSource["QUERY"] = "query";
9
9
  RequestDataSource["HEADERS"] = "headers";
10
- RequestDataSource["COOKIE"] = "cookie";
10
+ RequestDataSource["COOKIES"] = "cookies";
11
11
  RequestDataSource["BODY"] = "body";
12
12
  })(RequestDataSource || (RequestDataSource = {}));
13
13
  /**
@@ -4,6 +4,7 @@ export * from './decorators/index.js';
4
4
  export * from './data-schema-types.js';
5
5
  export * from './controller-registry.js';
6
6
  export { RouteHandler } from '@e22m4u/js-trie-router';
7
+ export { RouterHookType } from '@e22m4u/js-trie-router';
7
8
  export { RequestContext } from '@e22m4u/js-trie-router';
8
9
  export { RoutePreHandler } from '@e22m4u/js-trie-router';
9
10
  export { RoutePostHandler } from '@e22m4u/js-trie-router';
package/dist/esm/index.js CHANGED
@@ -3,4 +3,5 @@ export * from './errors/index.js';
3
3
  export * from './decorators/index.js';
4
4
  export * from './data-schema-types.js';
5
5
  export * from './controller-registry.js';
6
+ export { RouterHookType } from '@e22m4u/js-trie-router';
6
7
  export { RequestContext } from '@e22m4u/js-trie-router';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@e22m4u/ts-rest-router",
3
- "version": "0.6.6",
3
+ "version": "0.6.8",
4
4
  "description": "Декларативный REST-маршрутизатор на основе контроллеров для TypeScript",
5
5
  "author": "Mikhail Evstropov <e22m4u@yandex.ru>",
6
6
  "license": "MIT",
@@ -44,7 +44,7 @@
44
44
  "@e22m4u/js-data-schema": "~0.4.6",
45
45
  "@e22m4u/js-debug": "~0.3.2",
46
46
  "@e22m4u/js-format": "~0.2.0",
47
- "@e22m4u/js-service": "~0.4.4",
47
+ "@e22m4u/js-service": "~0.4.5",
48
48
  "@e22m4u/js-trie-router": "~0.3.4",
49
49
  "@e22m4u/ts-reflector": "~0.1.8",
50
50
  "http-errors": "~2.0.0"
@@ -52,25 +52,25 @@
52
52
  "devDependencies": {
53
53
  "@commitlint/cli": "~20.1.0",
54
54
  "@commitlint/config-conventional": "~20.0.0",
55
- "@eslint/js": "~9.38.0",
55
+ "@eslint/js": "~9.39.1",
56
56
  "@types/chai": "~5.2.3",
57
57
  "@types/debug": "~4.1.12",
58
58
  "@types/http-errors": "~2.0.5",
59
59
  "@types/mocha": "~10.0.10",
60
- "@types/node": "~24.9.2",
60
+ "@types/node": "~24.10.0",
61
61
  "c8": "~10.1.3",
62
62
  "chai": "~6.2.0",
63
- "esbuild": "~0.25.11",
64
- "eslint": "~9.38.0",
63
+ "esbuild": "~0.25.12",
64
+ "eslint": "~9.39.1",
65
65
  "eslint-config-prettier": "~10.1.8",
66
66
  "eslint-plugin-chai-expect": "~3.1.0",
67
67
  "eslint-plugin-mocha": "~11.2.0",
68
68
  "husky": "~9.1.7",
69
- "mocha": "~11.7.4",
69
+ "mocha": "~11.7.5",
70
70
  "prettier": "~3.6.2",
71
- "rimraf": "~6.0.1",
71
+ "rimraf": "~6.1.0",
72
72
  "tsx": "~4.20.6",
73
73
  "typescript": "~5.9.3",
74
- "typescript-eslint": "~8.46.2"
74
+ "typescript-eslint": "~8.46.3"
75
75
  }
76
76
  }
@@ -450,7 +450,7 @@ export class ControllerRegistry extends DebuggableService {
450
450
  case RequestDataSource.HEADERS:
451
451
  data = requestContext.headers;
452
452
  break;
453
- case RequestDataSource.COOKIE:
453
+ case RequestDataSource.COOKIES:
454
454
  data = requestContext.cookies;
455
455
  break;
456
456
  case RequestDataSource.BODY:
@@ -108,7 +108,7 @@ describe('requestData', function () {
108
108
  }
109
109
  const res = RequestDataReflector.getMetadata(Target, 'myMethod');
110
110
  expect(res.get(0)).to.be.eql({
111
- source: RequestDataSource.COOKIE,
111
+ source: RequestDataSource.COOKIES,
112
112
  schema: {type: DataType.ANY},
113
113
  });
114
114
  });
@@ -502,7 +502,7 @@ describe('requestData', function () {
502
502
  }
503
503
  const res = RequestDataReflector.getMetadata(Target, 'myMethod');
504
504
  expect(res.get(0)).to.be.eql({
505
- source: RequestDataSource.COOKIE,
505
+ source: RequestDataSource.COOKIES,
506
506
  schema: {
507
507
  type: DataType.OBJECT,
508
508
  properties: {
@@ -526,7 +526,7 @@ describe('requestData', function () {
526
526
  }
527
527
  const res = RequestDataReflector.getMetadata(Target, 'myMethod');
528
528
  expect(res.get(0)).to.be.eql({
529
- source: RequestDataSource.COOKIE,
529
+ source: RequestDataSource.COOKIES,
530
530
  schema: {
531
531
  type: DataType.OBJECT,
532
532
  properties: {
@@ -553,7 +553,7 @@ describe('requestData', function () {
553
553
  }
554
554
  const res = RequestDataReflector.getMetadata(Target, 'myMethod');
555
555
  expect(res.get(0)).to.be.eql({
556
- source: RequestDataSource.COOKIE,
556
+ source: RequestDataSource.COOKIES,
557
557
  schema: {
558
558
  type: DataType.OBJECT,
559
559
  properties: {
@@ -579,7 +579,7 @@ describe('requestData', function () {
579
579
  }
580
580
  const mdMap = RequestDataReflector.getMetadata(Target, 'myMethod');
581
581
  const md = mdMap.get(0) as RequestDataMetadata;
582
- expect(md.source).to.be.eq(RequestDataSource.COOKIE);
582
+ expect(md.source).to.be.eq(RequestDataSource.COOKIES);
583
583
  expect(md.schema).to.be.a('function');
584
584
  expect(md.property).to.be.eq(propertyKey);
585
585
  const res1 = md.schema as DataSchemaFactory;
@@ -118,10 +118,10 @@ export const requestHeader = createRequestDataPropertyDecoratorWithSource(
118
118
  RequestDataSource.HEADERS,
119
119
  );
120
120
  export const requestCookies = createRequestDataDecoratorWithSource(
121
- RequestDataSource.COOKIE,
121
+ RequestDataSource.COOKIES,
122
122
  );
123
123
  export const requestCookie = createRequestDataPropertyDecoratorWithSource(
124
- RequestDataSource.COOKIE,
124
+ RequestDataSource.COOKIES,
125
125
  );
126
126
  export const requestBody = createRequestDataDecoratorWithSource(
127
127
  RequestDataSource.BODY,
@@ -8,7 +8,7 @@ export enum RequestDataSource {
8
8
  PARAMS = 'params',
9
9
  QUERY = 'query',
10
10
  HEADERS = 'headers',
11
- COOKIE = 'cookie',
11
+ COOKIES = 'cookies',
12
12
  BODY = 'body',
13
13
  }
14
14
 
package/src/index.ts CHANGED
@@ -5,6 +5,7 @@ export * from './data-schema-types.js';
5
5
  export * from './controller-registry.js';
6
6
 
7
7
  export {RouteHandler} from '@e22m4u/js-trie-router';
8
+ export {RouterHookType} from '@e22m4u/js-trie-router';
8
9
  export {RequestContext} from '@e22m4u/js-trie-router';
9
10
  export {RoutePreHandler} from '@e22m4u/js-trie-router';
10
11
  export {RoutePostHandler} from '@e22m4u/js-trie-router';