@fluojs/http 1.0.0-beta.1 → 1.0.0-beta.3

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.
Files changed (66) hide show
  1. package/README.ko.md +11 -4
  2. package/README.md +11 -4
  3. package/dist/adapter.d.ts +31 -0
  4. package/dist/adapter.d.ts.map +1 -1
  5. package/dist/adapter.js +37 -0
  6. package/dist/adapters/binding.d.ts +6 -0
  7. package/dist/adapters/binding.d.ts.map +1 -1
  8. package/dist/adapters/binding.js +8 -0
  9. package/dist/adapters/dto-validation-adapter.d.ts +3 -0
  10. package/dist/adapters/dto-validation-adapter.d.ts.map +1 -1
  11. package/dist/adapters/dto-validation-adapter.js +3 -0
  12. package/dist/context/sse.d.ts +38 -0
  13. package/dist/context/sse.d.ts.map +1 -1
  14. package/dist/context/sse.js +50 -2
  15. package/dist/decorators.d.ts.map +1 -1
  16. package/dist/decorators.js +2 -2
  17. package/dist/dispatch/dispatch-content-negotiation.d.ts +17 -0
  18. package/dist/dispatch/dispatch-content-negotiation.d.ts.map +1 -1
  19. package/dist/dispatch/dispatch-content-negotiation.js +21 -0
  20. package/dist/dispatch/dispatch-error-policy.d.ts +8 -0
  21. package/dist/dispatch/dispatch-error-policy.d.ts.map +1 -1
  22. package/dist/dispatch/dispatch-error-policy.js +9 -0
  23. package/dist/dispatch/dispatch-handler-policy.d.ts +8 -0
  24. package/dist/dispatch/dispatch-handler-policy.d.ts.map +1 -1
  25. package/dist/dispatch/dispatch-handler-policy.js +9 -0
  26. package/dist/dispatch/dispatch-response-policy.d.ts +10 -0
  27. package/dist/dispatch/dispatch-response-policy.d.ts.map +1 -1
  28. package/dist/dispatch/dispatch-response-policy.js +11 -0
  29. package/dist/dispatch/dispatch-routing-policy.d.ts +13 -0
  30. package/dist/dispatch/dispatch-routing-policy.d.ts.map +1 -1
  31. package/dist/dispatch/dispatch-routing-policy.js +14 -0
  32. package/dist/dispatch/dispatcher.d.ts.map +1 -1
  33. package/dist/dispatch/dispatcher.js +55 -16
  34. package/dist/errors.d.ts +3 -0
  35. package/dist/errors.d.ts.map +1 -1
  36. package/dist/errors.js +4 -0
  37. package/dist/guards.d.ts +7 -0
  38. package/dist/guards.d.ts.map +1 -1
  39. package/dist/guards.js +11 -0
  40. package/dist/input-error-detail.d.ts +9 -0
  41. package/dist/input-error-detail.d.ts.map +1 -1
  42. package/dist/input-error-detail.js +10 -0
  43. package/dist/interceptors.d.ts +8 -0
  44. package/dist/interceptors.d.ts.map +1 -1
  45. package/dist/interceptors.js +14 -1
  46. package/dist/mapping.d.ts +7 -0
  47. package/dist/mapping.d.ts.map +1 -1
  48. package/dist/mapping.js +93 -11
  49. package/dist/middleware/correlation.d.ts +5 -0
  50. package/dist/middleware/correlation.d.ts.map +1 -1
  51. package/dist/middleware/correlation.js +6 -0
  52. package/dist/middleware/cors.d.ts +9 -0
  53. package/dist/middleware/cors.d.ts.map +1 -1
  54. package/dist/middleware/cors.js +11 -0
  55. package/dist/middleware/middleware.d.ts +34 -0
  56. package/dist/middleware/middleware.d.ts.map +1 -1
  57. package/dist/middleware/middleware.js +47 -0
  58. package/dist/middleware/security-headers.d.ts +9 -0
  59. package/dist/middleware/security-headers.d.ts.map +1 -1
  60. package/dist/middleware/security-headers.js +11 -0
  61. package/dist/route-path.d.ts +41 -0
  62. package/dist/route-path.d.ts.map +1 -1
  63. package/dist/route-path.js +50 -0
  64. package/dist/types.d.ts +5 -0
  65. package/dist/types.d.ts.map +1 -1
  66. package/package.json +4 -4
package/README.ko.md CHANGED
@@ -10,6 +10,7 @@
10
10
  - [사용 시점](#사용-시점)
11
11
  - [빠른 시작](#빠른-시작)
12
12
  - [주요 패턴](#주요-패턴)
13
+ - [요청 정리와 런타임 이식성](#요청-정리와-런타임-이식성)
13
14
  - [공개 API](#공개-api)
14
15
  - [관련 패키지](#관련-패키지)
15
16
  - [예제 소스](#예제-소스)
@@ -112,14 +113,20 @@ stream(_input: undefined, ctx: RequestContext) {
112
113
  }
113
114
  ```
114
115
 
116
+ ## 요청 정리와 런타임 이식성
117
+
118
+ 디스패처는 활성 dispatch 동안에만 `AsyncLocalStorage`로 `RequestContext`를 바인딩하고, 요청 observer가 끝난 뒤 `finally` 경로에서 request-scoped DI 컨테이너를 dispose합니다. 이 동작은 정상 성공, 처리된 오류, 중단된 요청 경로에서 request-scoped provider가 다음 요청으로 새지 않게 합니다.
119
+
120
+ 어댑터는 플랫폼이 제공한다면 `FrameworkRequest.signal`에 `AbortSignal`을 전달해야 합니다. SSE에서는 가능하면 `FrameworkResponse.stream.onClose(...)`도 노출해야 합니다. `SseResponse`는 request abort와 raw stream close를 모두 구독하고, 멱등하게 닫히며, 어느 쪽이 먼저 종료되더라도 등록한 listener를 제거합니다.
121
+
115
122
  ## 공개 API
116
123
 
117
- - **라우팅 데코레이터**: `Controller`, `Get`, `Post`, `Put`, `Patch`, `Delete`, `All`
118
- - **바인딩 데코레이터**: `FromBody`, `FromQuery`, `FromPath`, `FromHeader`, `FromCookie`, `RequestDto`
119
- - **실행 데코레이터**: `UseGuards`, `UseInterceptors`, `HttpCode`, `Version`, `Header`, `Redirect`
124
+ - **라우팅 데코레이터**: `Controller`, `Get`, `Post`, `Put`, `Patch`, `Delete`, `All`, `Options`, `Head`
125
+ - **바인딩 데코레이터**: `FromBody`, `FromQuery`, `FromPath`, `FromHeader`, `FromCookie`, `RequestDto`, `Optional`, `Convert`
126
+ - **실행 데코레이터**: `UseGuards`, `UseInterceptors`, `HttpCode`, `Version`, `Header`, `Redirect`, `Produces`
120
127
  - **핵심 런타임 타입**: `RequestContext`, `FrameworkRequest`, `FrameworkResponse`, `SseResponse`
121
128
  - **예외**: `BadRequestException`, `UnauthorizedException`, `ForbiddenException`, `NotFoundException`, `InternalServerErrorException`, `PayloadTooLargeException`
122
- - **헬퍼**: `createHandlerMapping`, `createDispatcher`, `createCorsMiddleware`, `createRateLimitMiddleware`, `getCurrentRequestContext`
129
+ - **헬퍼**: `createHandlerMapping`, `createDispatcher`, `forRoutes`, `normalizeRoutePattern`, `matchRoutePattern`, `isMiddlewareRouteConfig`, `createCorrelationMiddleware`, `createCorsMiddleware`, `createRateLimitMiddleware`, `createSecurityHeadersMiddleware`, `getCurrentRequestContext`, `encodeSseComment`, `encodeSseMessage`
123
130
 
124
131
  ## 내부 서브경로 (`@fluojs/http/internal`)
125
132
 
package/README.md CHANGED
@@ -10,6 +10,7 @@ The HTTP execution layer that turns route metadata into a request pipeline with
10
10
  - [When to Use](#when-to-use)
11
11
  - [Quick Start](#quick-start)
12
12
  - [Common Patterns](#common-patterns)
13
+ - [Request Cleanup and Portability](#request-cleanup-and-portability)
13
14
  - [Public API](#public-api)
14
15
  - [Related Packages](#related-packages)
15
16
  - [Example Sources](#example-sources)
@@ -114,14 +115,20 @@ stream(_input: undefined, ctx: RequestContext) {
114
115
  }
115
116
  ```
116
117
 
118
+ ## Request Cleanup and Portability
119
+
120
+ The dispatcher binds `RequestContext` with `AsyncLocalStorage` for the active dispatch only and disposes the request-scoped DI container from its `finally` path after request observers finish. This keeps per-request providers from leaking across normal success, handled error, and aborted request paths.
121
+
122
+ Adapters should pass an `AbortSignal` on `FrameworkRequest.signal` when the platform exposes one. For SSE, adapters should also expose `FrameworkResponse.stream.onClose(...)` when possible; `SseResponse` listens to both request abort and raw stream close, closes idempotently, and removes registered listeners when either side terminates first.
123
+
117
124
  ## Public API
118
125
 
119
- - **Routing decorators**: `Controller`, `Get`, `Post`, `Put`, `Patch`, `Delete`, `All`
120
- - **Binding decorators**: `FromBody`, `FromQuery`, `FromPath`, `FromHeader`, `FromCookie`, `RequestDto`
121
- - **Execution decorators**: `UseGuards`, `UseInterceptors`, `HttpCode`, `Version`, `Header`, `Redirect`
126
+ - **Routing decorators**: `Controller`, `Get`, `Post`, `Put`, `Patch`, `Delete`, `All`, `Options`, `Head`
127
+ - **Binding decorators**: `FromBody`, `FromQuery`, `FromPath`, `FromHeader`, `FromCookie`, `RequestDto`, `Optional`, `Convert`
128
+ - **Execution decorators**: `UseGuards`, `UseInterceptors`, `HttpCode`, `Version`, `Header`, `Redirect`, `Produces`
122
129
  - **Core runtime types**: `RequestContext`, `FrameworkRequest`, `FrameworkResponse`, `SseResponse`
123
130
  - **Exceptions**: `BadRequestException`, `UnauthorizedException`, `ForbiddenException`, `NotFoundException`, `InternalServerErrorException`, `PayloadTooLargeException`
124
- - **Helpers**: `createHandlerMapping`, `createDispatcher`, `createCorsMiddleware`, `createRateLimitMiddleware`, `getCurrentRequestContext`
131
+ - **Helpers**: `createHandlerMapping`, `createDispatcher`, `forRoutes`, `normalizeRoutePattern`, `matchRoutePattern`, `isMiddlewareRouteConfig`, `createCorrelationMiddleware`, `createCorsMiddleware`, `createRateLimitMiddleware`, `createSecurityHeadersMiddleware`, `getCurrentRequestContext`, `encodeSseComment`, `encodeSseMessage`
125
132
 
126
133
  ## Internal Subpath (`@fluojs/http/internal`)
127
134
 
package/dist/adapter.d.ts CHANGED
@@ -1,14 +1,23 @@
1
1
  import type { MaybePromise } from '@fluojs/core';
2
2
  import type { Dispatcher } from './types.js';
3
+ /**
4
+ * Describes the server backed http adapter realtime capability contract.
5
+ */
3
6
  export interface ServerBackedHttpAdapterRealtimeCapability {
4
7
  kind: 'server-backed';
5
8
  server: unknown;
6
9
  }
10
+ /**
11
+ * Describes the unsupported http adapter realtime capability contract.
12
+ */
7
13
  export interface UnsupportedHttpAdapterRealtimeCapability {
8
14
  kind: 'unsupported';
9
15
  mode: 'no-op';
10
16
  reason: string;
11
17
  }
18
+ /**
19
+ * Describes the fetch style http adapter realtime capability contract.
20
+ */
12
21
  export interface FetchStyleHttpAdapterRealtimeCapability {
13
22
  contract: 'raw-websocket-expansion';
14
23
  kind: 'fetch-style';
@@ -17,9 +26,31 @@ export interface FetchStyleHttpAdapterRealtimeCapability {
17
26
  support: 'contract-only' | 'supported';
18
27
  version: 1;
19
28
  }
29
+ /**
30
+ * Defines the http adapter realtime capability type.
31
+ */
20
32
  export type HttpAdapterRealtimeCapability = ServerBackedHttpAdapterRealtimeCapability | FetchStyleHttpAdapterRealtimeCapability | UnsupportedHttpAdapterRealtimeCapability;
33
+ /**
34
+ * Create server backed http adapter realtime capability.
35
+ *
36
+ * @param server The server.
37
+ * @returns The create server backed http adapter realtime capability result.
38
+ */
21
39
  export declare function createServerBackedHttpAdapterRealtimeCapability(server: unknown): ServerBackedHttpAdapterRealtimeCapability;
40
+ /**
41
+ * Create unsupported http adapter realtime capability.
42
+ *
43
+ * @param reason The reason.
44
+ * @returns The create unsupported http adapter realtime capability result.
45
+ */
22
46
  export declare function createUnsupportedHttpAdapterRealtimeCapability(reason: string): UnsupportedHttpAdapterRealtimeCapability;
47
+ /**
48
+ * Create fetch style http adapter realtime capability.
49
+ *
50
+ * @param reason The reason.
51
+ * @param options The options.
52
+ * @returns The create fetch style http adapter realtime capability result.
53
+ */
23
54
  export declare function createFetchStyleHttpAdapterRealtimeCapability(reason: string, options?: {
24
55
  support?: FetchStyleHttpAdapterRealtimeCapability['support'];
25
56
  }): FetchStyleHttpAdapterRealtimeCapability;
@@ -1 +1 @@
1
- {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEjD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,MAAM,WAAW,yCAAyC;IACxD,IAAI,EAAE,eAAe,CAAC;IACtB,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,wCAAwC;IACvD,IAAI,EAAE,aAAa,CAAC;IACpB,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,uCAAuC;IACtD,QAAQ,EAAE,yBAAyB,CAAC;IACpC,IAAI,EAAE,aAAa,CAAC;IACpB,IAAI,EAAE,iBAAiB,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,eAAe,GAAG,WAAW,CAAC;IACvC,OAAO,EAAE,CAAC,CAAC;CACZ;AAED,MAAM,MAAM,6BAA6B,GACrC,yCAAyC,GACzC,uCAAuC,GACvC,wCAAwC,CAAC;AAE7C,wBAAgB,+CAA+C,CAC7D,MAAM,EAAE,OAAO,GACd,yCAAyC,CAK3C;AAED,wBAAgB,8CAA8C,CAC5D,MAAM,EAAE,MAAM,GACb,wCAAwC,CAM1C;AAED,wBAAgB,6CAA6C,CAC3D,MAAM,EAAE,MAAM,EACd,OAAO,GAAE;IACP,OAAO,CAAC,EAAE,uCAAuC,CAAC,SAAS,CAAC,CAAC;CACzD,GACL,uCAAuC,CASzC;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC;;;;OAIG;IACH,SAAS,CAAC,IAAI,OAAO,CAAC;IAEtB,qBAAqB,CAAC,IAAI,6BAA6B,CAAC;IAExD;;;;;OAKG;IACH,MAAM,CAAC,UAAU,EAAE,UAAU,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IAEnD;;;;;OAKG;IACH,KAAK,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;CAC5C;AAED;;;;GAIG;AACH,wBAAgB,gCAAgC,IAAI,sBAAsB,CAUzE"}
1
+ {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEjD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C;;GAEG;AACH,MAAM,WAAW,yCAAyC;IACxD,IAAI,EAAE,eAAe,CAAC;IACtB,MAAM,EAAE,OAAO,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,wCAAwC;IACvD,IAAI,EAAE,aAAa,CAAC;IACpB,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,uCAAuC;IACtD,QAAQ,EAAE,yBAAyB,CAAC;IACpC,IAAI,EAAE,aAAa,CAAC;IACpB,IAAI,EAAE,iBAAiB,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,eAAe,GAAG,WAAW,CAAC;IACvC,OAAO,EAAE,CAAC,CAAC;CACZ;AAED;;GAEG;AACH,MAAM,MAAM,6BAA6B,GACrC,yCAAyC,GACzC,uCAAuC,GACvC,wCAAwC,CAAC;AAE7C;;;;;GAKG;AACH,wBAAgB,+CAA+C,CAC7D,MAAM,EAAE,OAAO,GACd,yCAAyC,CAK3C;AAED;;;;;GAKG;AACH,wBAAgB,8CAA8C,CAC5D,MAAM,EAAE,MAAM,GACb,wCAAwC,CAM1C;AAED;;;;;;GAMG;AACH,wBAAgB,6CAA6C,CAC3D,MAAM,EAAE,MAAM,EACd,OAAO,GAAE;IACP,OAAO,CAAC,EAAE,uCAAuC,CAAC,SAAS,CAAC,CAAC;CACzD,GACL,uCAAuC,CASzC;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC;;;;OAIG;IACH,SAAS,CAAC,IAAI,OAAO,CAAC;IAEtB,qBAAqB,CAAC,IAAI,6BAA6B,CAAC;IAExD;;;;;OAKG;IACH,MAAM,CAAC,UAAU,EAAE,UAAU,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IAEnD;;;;;OAKG;IACH,KAAK,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;CAC5C;AAED;;;;GAIG;AACH,wBAAgB,gCAAgC,IAAI,sBAAsB,CAUzE"}
package/dist/adapter.js CHANGED
@@ -1,9 +1,38 @@
1
+ /**
2
+ * Describes the server backed http adapter realtime capability contract.
3
+ */
4
+
5
+ /**
6
+ * Describes the unsupported http adapter realtime capability contract.
7
+ */
8
+
9
+ /**
10
+ * Describes the fetch style http adapter realtime capability contract.
11
+ */
12
+
13
+ /**
14
+ * Defines the http adapter realtime capability type.
15
+ */
16
+
17
+ /**
18
+ * Create server backed http adapter realtime capability.
19
+ *
20
+ * @param server The server.
21
+ * @returns The create server backed http adapter realtime capability result.
22
+ */
1
23
  export function createServerBackedHttpAdapterRealtimeCapability(server) {
2
24
  return {
3
25
  kind: 'server-backed',
4
26
  server
5
27
  };
6
28
  }
29
+
30
+ /**
31
+ * Create unsupported http adapter realtime capability.
32
+ *
33
+ * @param reason The reason.
34
+ * @returns The create unsupported http adapter realtime capability result.
35
+ */
7
36
  export function createUnsupportedHttpAdapterRealtimeCapability(reason) {
8
37
  return {
9
38
  kind: 'unsupported',
@@ -11,6 +40,14 @@ export function createUnsupportedHttpAdapterRealtimeCapability(reason) {
11
40
  reason
12
41
  };
13
42
  }
43
+
44
+ /**
45
+ * Create fetch style http adapter realtime capability.
46
+ *
47
+ * @param reason The reason.
48
+ * @param options The options.
49
+ * @returns The create fetch style http adapter realtime capability result.
50
+ */
14
51
  export function createFetchStyleHttpAdapterRealtimeCapability(reason, options = {}) {
15
52
  return {
16
53
  contract: 'raw-websocket-expansion',
@@ -1,8 +1,14 @@
1
1
  import { type Constructor } from '@fluojs/core';
2
2
  import type { ArgumentResolverContext, Binder, Converter, ConverterLike, ConverterTarget } from '../types.js';
3
+ /**
4
+ * Represents the default converter.
5
+ */
3
6
  export declare class DefaultConverter implements Converter {
4
7
  convert(value: unknown, _target: ConverterTarget): unknown;
5
8
  }
9
+ /**
10
+ * Represents the default binder.
11
+ */
6
12
  export declare class DefaultBinder implements Binder {
7
13
  private readonly converters;
8
14
  constructor(converters?: readonly ConverterLike[]);
@@ -1 +1 @@
1
- {"version":3,"file":"binding.d.ts","sourceRoot":"","sources":["../../src/adapters/binding.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,WAAW,EAA6D,MAAM,cAAc,CAAC;AAK3H,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,EAAE,SAAS,EAAE,aAAa,EAAE,eAAe,EAAoB,MAAM,aAAa,CAAC;AA4FhI,qBAAa,gBAAiB,YAAW,SAAS;IAChD,OAAO,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,eAAe,GAAG,OAAO;CAG3D;AAyDD,qBAAa,aAAc,YAAW,MAAM;IAC9B,OAAO,CAAC,QAAQ,CAAC,UAAU;gBAAV,UAAU,GAAE,SAAS,aAAa,EAAO;IAEhE,IAAI,CAAC,GAAG,EAAE,WAAW,EAAE,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,OAAO,CAAC;CA0EjF"}
1
+ {"version":3,"file":"binding.d.ts","sourceRoot":"","sources":["../../src/adapters/binding.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,WAAW,EAA6D,MAAM,cAAc,CAAC;AAK3H,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,EAAE,SAAS,EAAE,aAAa,EAAE,eAAe,EAAoB,MAAM,aAAa,CAAC;AA4FhI;;GAEG;AACH,qBAAa,gBAAiB,YAAW,SAAS;IAChD,OAAO,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,eAAe,GAAG,OAAO;CAG3D;AAyDD;;GAEG;AACH,qBAAa,aAAc,YAAW,MAAM;IAC9B,OAAO,CAAC,QAAQ,CAAC,UAAU;gBAAV,UAAU,GAAE,SAAS,aAAa,EAAO;IAEhE,IAAI,CAAC,GAAG,EAAE,WAAW,EAAE,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,OAAO,CAAC;CA0EjF"}
@@ -87,6 +87,10 @@ function validateBodyKeys(request, bodyKeys) {
87
87
  });
88
88
  }
89
89
  }
90
+
91
+ /**
92
+ * Represents the default converter.
93
+ */
90
94
  export class DefaultConverter {
91
95
  convert(value, _target) {
92
96
  return value;
@@ -131,6 +135,10 @@ async function resolveConverter(value, context, cache) {
131
135
  throw error;
132
136
  }
133
137
  }
138
+
139
+ /**
140
+ * Represents the default binder.
141
+ */
134
142
  export class DefaultBinder {
135
143
  constructor(converters = []) {
136
144
  this.converters = converters;
@@ -1,5 +1,8 @@
1
1
  import { type Constructor } from '@fluojs/core';
2
2
  import type { Validator } from '../types.js';
3
+ /**
4
+ * Represents the http dto validation adapter.
5
+ */
3
6
  export declare class HttpDtoValidationAdapter implements Validator {
4
7
  private readonly validator;
5
8
  private throwBadRequestForValidationError;
@@ -1 +1 @@
1
- {"version":3,"file":"dto-validation-adapter.d.ts","sourceRoot":"","sources":["../../src/adapters/dto-validation-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAMhD,OAAO,KAAK,EAAmB,SAAS,EAAE,MAAM,aAAa,CAAC;AAE9D,qBAAa,wBAAyB,YAAW,SAAS;IACxD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA8B;IAExD,OAAO,CAAC,iCAAiC;IAMzC,OAAO,CAAC,6BAA6B;IAiB/B,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAa5D,WAAW,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;CAWzE"}
1
+ {"version":3,"file":"dto-validation-adapter.d.ts","sourceRoot":"","sources":["../../src/adapters/dto-validation-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAMhD,OAAO,KAAK,EAAmB,SAAS,EAAE,MAAM,aAAa,CAAC;AAE9D;;GAEG;AACH,qBAAa,wBAAyB,YAAW,SAAS;IACxD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA8B;IAExD,OAAO,CAAC,iCAAiC;IAMzC,OAAO,CAAC,6BAA6B;IAiB/B,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAa5D,WAAW,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;CAWzE"}
@@ -2,6 +2,9 @@ import { getDtoBindingSchema } from '@fluojs/core/internal';
2
2
  import { DefaultValidator as BaseDefaultValidator, DtoValidationError } from '@fluojs/validation';
3
3
  import { BadRequestException } from '../exceptions.js';
4
4
  import { toInputErrorDetail } from '../input-error-detail.js';
5
+ /**
6
+ * Represents the http dto validation adapter.
7
+ */
5
8
  export class HttpDtoValidationAdapter {
6
9
  validator = new BaseDefaultValidator();
7
10
  throwBadRequestForValidationError(error) {
@@ -1,11 +1,35 @@
1
1
  import type { RequestContext } from '../types.js';
2
+ /** Options that customize the fields emitted for one server-sent event frame. */
2
3
  export interface SseSendOptions {
4
+ /** Optional SSE event name. Newline characters are stripped before writing. */
3
5
  event?: string;
6
+ /** Optional SSE event id. Newline characters are stripped before writing. */
4
7
  id?: string | number;
8
+ /** Optional client retry delay in milliseconds. Non-finite or negative values are ignored. */
5
9
  retry?: number;
6
10
  }
11
+ /**
12
+ * Encodes a comment as a canonical server-sent event comment frame.
13
+ *
14
+ * @param comment Comment text to split into SSE comment lines.
15
+ * @returns A complete SSE comment frame ending in a blank line.
16
+ */
7
17
  export declare function encodeSseComment(comment: string): string;
18
+ /**
19
+ * Encodes data and optional event fields as a server-sent event message frame.
20
+ *
21
+ * @param data Payload to write. Strings are sent as-is; other values are JSON serialized.
22
+ * @param options Optional event metadata fields.
23
+ * @returns A complete SSE message frame ending in a blank line.
24
+ * @throws {TypeError} When `data` cannot be represented as an SSE data field.
25
+ */
8
26
  export declare function encodeSseMessage(data: unknown, options?: SseSendOptions): string;
27
+ /**
28
+ * Response helper for server-sent event streams backed by an adapter-provided response stream.
29
+ *
30
+ * The helper commits SSE headers immediately, closes idempotently on request abort
31
+ * or raw stream close, and removes all registered close/abort listeners during cleanup.
32
+ */
9
33
  export declare class SseResponse {
10
34
  private readonly context;
11
35
  private closed;
@@ -13,8 +37,22 @@ export declare class SseResponse {
13
37
  private removeCloseListener?;
14
38
  private readonly onAbort;
15
39
  constructor(context: RequestContext);
40
+ /**
41
+ * Writes one SSE data message when the stream is still open.
42
+ *
43
+ * @param data Payload to encode into `data:` lines.
44
+ * @param options Optional event metadata fields.
45
+ * @returns `true` when the underlying stream accepted the frame without backpressure.
46
+ */
16
47
  send(data: unknown, options?: SseSendOptions): boolean;
48
+ /**
49
+ * Writes one SSE comment frame when the stream is still open.
50
+ *
51
+ * @param comment Comment text to encode.
52
+ * @returns `true` when the underlying stream accepted the frame without backpressure.
53
+ */
17
54
  comment(comment: string): boolean;
55
+ /** Closes the SSE stream and removes registered abort/close listeners exactly once. */
18
56
  close(): void;
19
57
  private writeFrame;
20
58
  }
@@ -1 +1 @@
1
- {"version":3,"file":"sse.d.ts","sourceRoot":"","sources":["../../src/context/sse.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAA8C,cAAc,EAAE,MAAM,aAAa,CAAC;AAE9F,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAoCD,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAKxD;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,GAAE,cAAmB,GAAG,MAAM,CAoBpF;AAED,qBAAa,WAAW;IASV,OAAO,CAAC,QAAQ,CAAC,OAAO;IARpC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA0B;IACjD,OAAO,CAAC,mBAAmB,CAAC,CAAa;IAEzC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAEtB;gBAE2B,OAAO,EAAE,cAAc;IA0BpD,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,GAAE,cAAmB,GAAG,OAAO;IAI1D,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAIjC,KAAK,IAAI,IAAI;IAiBb,OAAO,CAAC,UAAU;CAYnB"}
1
+ {"version":3,"file":"sse.d.ts","sourceRoot":"","sources":["../../src/context/sse.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAA8C,cAAc,EAAE,MAAM,aAAa,CAAC;AAE9F,iFAAiF;AACjF,MAAM,WAAW,cAAc;IAC7B,+EAA+E;IAC/E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6EAA6E;IAC7E,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACrB,8FAA8F;IAC9F,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAoCD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAKxD;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,GAAE,cAAmB,GAAG,MAAM,CAoBpF;AAED;;;;;GAKG;AACH,qBAAa,WAAW;IASV,OAAO,CAAC,QAAQ,CAAC,OAAO;IARpC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA0B;IACjD,OAAO,CAAC,mBAAmB,CAAC,CAAa;IAEzC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAEtB;gBAE2B,OAAO,EAAE,cAAc;IAmCpD;;;;;;OAMG;IACH,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,GAAE,cAAmB,GAAG,OAAO;IAI1D;;;;;OAKG;IACH,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAIjC,uFAAuF;IACvF,KAAK,IAAI,IAAI;IAiBb,OAAO,CAAC,UAAU;CAYnB"}
@@ -1,3 +1,5 @@
1
+ /** Options that customize the fields emitted for one server-sent event frame. */
2
+
1
3
  function sanitizeSseField(value) {
2
4
  return value.replace(/\r/g, '').replace(/\n/g, '');
3
5
  }
@@ -23,11 +25,27 @@ function resolveSseStream(response) {
23
25
  }
24
26
  return response.stream;
25
27
  }
28
+
29
+ /**
30
+ * Encodes a comment as a canonical server-sent event comment frame.
31
+ *
32
+ * @param comment Comment text to split into SSE comment lines.
33
+ * @returns A complete SSE comment frame ending in a blank line.
34
+ */
26
35
  export function encodeSseComment(comment) {
27
36
  const lines = splitSseLines(comment);
28
37
  const encoded = lines.map(line => line.length === 0 ? ':' : `: ${line}`);
29
38
  return `${encoded.join('\n')}\n\n`;
30
39
  }
40
+
41
+ /**
42
+ * Encodes data and optional event fields as a server-sent event message frame.
43
+ *
44
+ * @param data Payload to write. Strings are sent as-is; other values are JSON serialized.
45
+ * @param options Optional event metadata fields.
46
+ * @returns A complete SSE message frame ending in a blank line.
47
+ * @throws {TypeError} When `data` cannot be represented as an SSE data field.
48
+ */
31
49
  export function encodeSseMessage(data, options = {}) {
32
50
  const lines = [];
33
51
  if (options.event !== undefined) {
@@ -44,6 +62,13 @@ export function encodeSseMessage(data, options = {}) {
44
62
  }
45
63
  return `${lines.join('\n')}\n\n`;
46
64
  }
65
+
66
+ /**
67
+ * Response helper for server-sent event streams backed by an adapter-provided response stream.
68
+ *
69
+ * The helper commits SSE headers immediately, closes idempotently on request abort
70
+ * or raw stream close, and removes all registered close/abort listeners during cleanup.
71
+ */
47
72
  export class SseResponse {
48
73
  closed = false;
49
74
  stream;
@@ -70,16 +95,39 @@ export class SseResponse {
70
95
  context.request.signal?.addEventListener('abort', this.onAbort, {
71
96
  once: true
72
97
  });
73
- if (context.request.signal === undefined) {
74
- this.removeCloseListener = this.stream.onClose?.(this.onAbort) ?? undefined;
98
+ const removeCloseListener = this.stream.onClose?.(this.onAbort) ?? undefined;
99
+ if (this.closed) {
100
+ removeCloseListener?.();
101
+ return;
102
+ }
103
+ this.removeCloseListener = removeCloseListener;
104
+ if (this.stream.closed) {
105
+ this.close();
75
106
  }
76
107
  }
108
+
109
+ /**
110
+ * Writes one SSE data message when the stream is still open.
111
+ *
112
+ * @param data Payload to encode into `data:` lines.
113
+ * @param options Optional event metadata fields.
114
+ * @returns `true` when the underlying stream accepted the frame without backpressure.
115
+ */
77
116
  send(data, options = {}) {
78
117
  return this.writeFrame(encodeSseMessage(data, options));
79
118
  }
119
+
120
+ /**
121
+ * Writes one SSE comment frame when the stream is still open.
122
+ *
123
+ * @param comment Comment text to encode.
124
+ * @returns `true` when the underlying stream accepted the frame without backpressure.
125
+ */
80
126
  comment(comment) {
81
127
  return this.writeFrame(encodeSseComment(comment));
82
128
  }
129
+
130
+ /** Closes the SSE stream and removes registered abort/close listeners exactly once. */
83
131
  close() {
84
132
  if (this.closed) {
85
133
  return;
@@ -1 +1 @@
1
- {"version":3,"file":"decorators.d.ts","sourceRoot":"","sources":["../src/decorators.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"decorators.d.ts","sourceRoot":"","sources":["../src/decorators.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,mBAAmB,EAEzB,MAAM,cAAc,CAAC;AAStB,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAc,eAAe,EAAE,MAAM,YAAY,CAAC;AAGxF,KAAK,wBAAwB,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,qBAAqB,KAAK,IAAI,CAAC;AAC1F,KAAK,yBAAyB,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,2BAA2B,KAAK,IAAI,CAAC;AACjG,KAAK,wBAAwB,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,0BAA0B,CAAC,IAAI,EAAE,KAAK,CAAC,KAAK,IAAI,CAAC;AAC1H,KAAK,kBAAkB,GAAG,wBAAwB,CAAC;AACnD,KAAK,mBAAmB,GAAG,yBAAyB,CAAC;AACrD,KAAK,0BAA0B,GAAG,wBAAwB,GAAG,yBAAyB,CAAC;AACvF,KAAK,kBAAkB,GAAG,wBAAwB,CAAC;AAyJnD;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,QAAQ,SAAK,GAAG,kBAAkB,CAQ5D;AAED;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,0BAA0B,CAWnE;AAED;;;;;GAKG;AACH,eAAO,MAAM,GAAG,SA7EA,MAAM,KAAG,mBA6EqB,CAAC;AAC/C;;;;;GAKG;AACH,eAAO,MAAM,IAAI,SApFD,MAAM,KAAG,mBAoFuB,CAAC;AACjD;;;;;GAKG;AACH,eAAO,MAAM,GAAG,SA3FA,MAAM,KAAG,mBA2FqB,CAAC;AAC/C;;;;;GAKG;AACH,eAAO,MAAM,KAAK,SAlGF,MAAM,KAAG,mBAkGyB,CAAC;AACnD;;;;;GAKG;AACH,eAAO,MAAM,MAAM,SAzGH,MAAM,KAAG,mBAyG2B,CAAC;AACrD;;;;;GAKG;AACH,eAAO,MAAM,OAAO,SAhHJ,MAAM,KAAG,mBAgH6B,CAAC;AACvD;;;;;GAKG;AACH,eAAO,MAAM,IAAI,SAvHD,MAAM,KAAG,mBAuHuB,CAAC;AACjD;;;;;GAKG;AACH,eAAO,MAAM,GAAG,SA9HA,MAAM,KAAG,mBA8HqB,CAAC;AAE/C;;;;;GAKG;AACH,eAAO,MAAM,UAAU,0BAxHF,mBA0HnB,CAAC;AAEH;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,GAAG,UAAU,EAAE,MAAM,EAAE,GAAG,mBAAmB,CAIrE;AAED;;;;;GAKG;AACH,eAAO,MAAM,QAAQ,qBA9IA,mBAgJnB,CAAC;AAEH;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,eAAe,EAAE,WAAW,EAAE,WAAW,EAAE,mBAAmB,GAAG,MAAM,EAAE,GAAG,SAAS,CAM7H;AAED;;;;;GAKG;AACH,eAAO,MAAM,QAAQ,SA7JL,MAAM,KAAG,kBA6J8B,CAAC;AACxD;;;;;GAKG;AACH,eAAO,MAAM,SAAS,SApKN,MAAM,KAAG,kBAoKgC,CAAC;AAC1D;;;;;GAKG;AACH,eAAO,MAAM,UAAU,SA3KP,MAAM,KAAG,kBA2KkC,CAAC;AAC5D;;;;;GAKG;AACH,eAAO,MAAM,UAAU,SAlLP,MAAM,KAAG,kBAkLkC,CAAC;AAC5D;;;;;GAKG;AACH,eAAO,MAAM,QAAQ,SAzLL,MAAM,KAAG,kBAyL8B,CAAC;AAExD;;;;GAIG;AACH,wBAAgB,QAAQ,IAAI,kBAAkB,CAM7C;AAED;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,SAAS,EAAE,aAAa,GAAG,kBAAkB,CAMpE;AAED;;;;;;GAMG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,mBAAmB,CAOvE;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,mBAAmB,CAM9E;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,GAAG,MAAM,EAAE,SAAS,EAAE,GAAG,0BAA0B,CAa5E;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,GAAG,YAAY,EAAE,eAAe,EAAE,GAAG,0BAA0B,CAa9F"}
@@ -1,4 +1,4 @@
1
- import { metadataSymbol } from '@fluojs/core/internal';
1
+ import { getStandardMetadataBag as readStandardMetadataBag, metadataSymbol } from '@fluojs/core/internal';
2
2
  import { validateRoutePath } from './route-path.js';
3
3
  const standardControllerMetadataKey = Symbol.for('fluo.standard.controller');
4
4
  const standardRouteMetadataKey = Symbol.for('fluo.standard.route');
@@ -233,7 +233,7 @@ export const HttpCode = createRouteValueDecorator((record, status) => {
233
233
  * @returns A defensive copy of declared media types, or `undefined` when not configured.
234
234
  */
235
235
  export function getRouteProducesMetadata(controllerToken, propertyKey) {
236
- const bag = controllerToken[metadataSymbol];
236
+ const bag = readStandardMetadataBag(controllerToken);
237
237
  const routeMap = bag?.[standardRouteMetadataKey];
238
238
  const produces = routeMap?.get(propertyKey)?.produces;
239
239
  return produces ? [...produces] : undefined;
@@ -1,9 +1,26 @@
1
1
  import type { ContentNegotiationOptions, FrameworkRequest, HandlerDescriptor, ResponseFormatter } from '../types.js';
2
+ /**
3
+ * Describes the resolved content negotiation contract.
4
+ */
2
5
  export interface ResolvedContentNegotiation {
3
6
  defaultFormatter: ResponseFormatter;
4
7
  formatters: ResponseFormatter[];
5
8
  normalizedMediaTypes: string[];
6
9
  }
10
+ /**
11
+ * Resolve content negotiation.
12
+ *
13
+ * @param options The options.
14
+ * @returns The resolve content negotiation result.
15
+ */
7
16
  export declare function resolveContentNegotiation(options: ContentNegotiationOptions | undefined): ResolvedContentNegotiation | undefined;
17
+ /**
18
+ * Select response formatter.
19
+ *
20
+ * @param handler The handler.
21
+ * @param request The request.
22
+ * @param contentNegotiation The content negotiation.
23
+ * @returns The select response formatter result.
24
+ */
8
25
  export declare function selectResponseFormatter(handler: HandlerDescriptor, request: FrameworkRequest, contentNegotiation: ResolvedContentNegotiation): ResponseFormatter;
9
26
  //# sourceMappingURL=dispatch-content-negotiation.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"dispatch-content-negotiation.d.ts","sourceRoot":"","sources":["../../src/dispatch/dispatch-content-negotiation.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,yBAAyB,EACzB,gBAAgB,EAChB,iBAAiB,EACjB,iBAAiB,EAClB,MAAM,aAAa,CAAC;AAQrB,MAAM,WAAW,0BAA0B;IACzC,gBAAgB,EAAE,iBAAiB,CAAC;IACpC,UAAU,EAAE,iBAAiB,EAAE,CAAC;IAChC,oBAAoB,EAAE,MAAM,EAAE,CAAC;CAChC;AA2GD,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,yBAAyB,GAAG,SAAS,GAAG,0BAA0B,GAAG,SAAS,CA+BhI;AAqCD,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,iBAAiB,EAC1B,OAAO,EAAE,gBAAgB,EACzB,kBAAkB,EAAE,0BAA0B,GAC7C,iBAAiB,CA2CnB"}
1
+ {"version":3,"file":"dispatch-content-negotiation.d.ts","sourceRoot":"","sources":["../../src/dispatch/dispatch-content-negotiation.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,yBAAyB,EACzB,gBAAgB,EAChB,iBAAiB,EACjB,iBAAiB,EAClB,MAAM,aAAa,CAAC;AAQrB;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACzC,gBAAgB,EAAE,iBAAiB,CAAC;IACpC,UAAU,EAAE,iBAAiB,EAAE,CAAC;IAChC,oBAAoB,EAAE,MAAM,EAAE,CAAC;CAChC;AA2GD;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,yBAAyB,GAAG,SAAS,GAAG,0BAA0B,GAAG,SAAS,CA+BhI;AAqCD;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,iBAAiB,EAC1B,OAAO,EAAE,gBAAgB,EACzB,kBAAkB,EAAE,0BAA0B,GAC7C,iBAAiB,CA2CnB"}
@@ -1,4 +1,9 @@
1
1
  import { NotAcceptableException } from '../exceptions.js';
2
+
3
+ /**
4
+ * Describes the resolved content negotiation contract.
5
+ */
6
+
2
7
  const NO_ACCEPTABLE_REPRESENTATION_MESSAGE = 'No acceptable response representation found.';
3
8
  function normalizeMediaType(value) {
4
9
  return value.split(';')[0]?.trim().toLowerCase() ?? '';
@@ -77,6 +82,13 @@ function matchesMediaRange(mediaRange, mediaType) {
77
82
  }
78
83
  return rangeSubtype === '*' || rangeSubtype === mediaTypeSubtype;
79
84
  }
85
+
86
+ /**
87
+ * Resolve content negotiation.
88
+ *
89
+ * @param options The options.
90
+ * @returns The resolve content negotiation result.
91
+ */
80
92
  export function resolveContentNegotiation(options) {
81
93
  if (!options?.formatters?.length) {
82
94
  return undefined;
@@ -128,6 +140,15 @@ function resolveDefaultFormatter(allowedFormatters, allowedNormalizedMediaTypes,
128
140
  const idx = allowedNormalizedMediaTypes.indexOf(defaultMediaType);
129
141
  return idx >= 0 ? allowedFormatters[idx] : allowedFormatters[0] ?? contentNegotiation.defaultFormatter;
130
142
  }
143
+
144
+ /**
145
+ * Select response formatter.
146
+ *
147
+ * @param handler The handler.
148
+ * @param request The request.
149
+ * @param contentNegotiation The content negotiation.
150
+ * @returns The select response formatter result.
151
+ */
131
152
  export function selectResponseFormatter(handler, request, contentNegotiation) {
132
153
  const {
133
154
  formatters: allowedFormatters,
@@ -1,3 +1,11 @@
1
1
  import type { FrameworkResponse } from '../types.js';
2
+ /**
3
+ * Write error response.
4
+ *
5
+ * @param error The error.
6
+ * @param response The response.
7
+ * @param requestId The request id.
8
+ * @returns The write error response result.
9
+ */
2
10
  export declare function writeErrorResponse(error: unknown, response: FrameworkResponse, requestId?: string): Promise<void>;
3
11
  //# sourceMappingURL=dispatch-error-policy.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"dispatch-error-policy.d.ts","sourceRoot":"","sources":["../../src/dispatch/dispatch-error-policy.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAiBrD,wBAAsB,kBAAkB,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAQvH"}
1
+ {"version":3,"file":"dispatch-error-policy.d.ts","sourceRoot":"","sources":["../../src/dispatch/dispatch-error-policy.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAiBrD;;;;;;;GAOG;AACH,wBAAsB,kBAAkB,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAQvH"}
@@ -14,6 +14,15 @@ function toHttpException(error) {
14
14
  cause: error
15
15
  });
16
16
  }
17
+
18
+ /**
19
+ * Write error response.
20
+ *
21
+ * @param error The error.
22
+ * @param response The response.
23
+ * @param requestId The request id.
24
+ * @returns The write error response result.
25
+ */
17
26
  export async function writeErrorResponse(error, response, requestId) {
18
27
  if (response.committed) {
19
28
  return;
@@ -1,3 +1,11 @@
1
1
  import type { Binder, HandlerDescriptor, RequestContext } from '../types.js';
2
+ /**
3
+ * Invoke controller handler.
4
+ *
5
+ * @param handler The handler.
6
+ * @param requestContext The request context.
7
+ * @param binder The binder.
8
+ * @returns The invoke controller handler result.
9
+ */
2
10
  export declare function invokeControllerHandler(handler: HandlerDescriptor, requestContext: RequestContext, binder?: Binder): Promise<unknown>;
3
11
  //# sourceMappingURL=dispatch-handler-policy.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"dispatch-handler-policy.d.ts","sourceRoot":"","sources":["../../src/dispatch/dispatch-handler-policy.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAA2B,MAAM,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAKtG,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,iBAAiB,EAC1B,cAAc,EAAE,cAAc,EAC9B,MAAM,GAAE,MAAsB,GAC7B,OAAO,CAAC,OAAO,CAAC,CAuBlB"}
1
+ {"version":3,"file":"dispatch-handler-policy.d.ts","sourceRoot":"","sources":["../../src/dispatch/dispatch-handler-policy.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAA2B,MAAM,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAKtG;;;;;;;GAOG;AACH,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,iBAAiB,EAC1B,cAAc,EAAE,cAAc,EAC9B,MAAM,GAAE,MAAsB,GAC7B,OAAO,CAAC,OAAO,CAAC,CAuBlB"}
@@ -3,6 +3,15 @@ import { DefaultBinder } from '../adapters/binding.js';
3
3
  import { HttpDtoValidationAdapter } from '../adapters/dto-validation-adapter.js';
4
4
  const defaultBinder = new DefaultBinder();
5
5
  const defaultValidator = new HttpDtoValidationAdapter();
6
+
7
+ /**
8
+ * Invoke controller handler.
9
+ *
10
+ * @param handler The handler.
11
+ * @param requestContext The request context.
12
+ * @param binder The binder.
13
+ * @returns The invoke controller handler result.
14
+ */
6
15
  export async function invokeControllerHandler(handler, requestContext, binder = defaultBinder) {
7
16
  const controller = await requestContext.container.resolve(handler.controllerToken);
8
17
  const method = controller[handler.methodName];
@@ -1,6 +1,16 @@
1
1
  import { resolveContentNegotiation, type ResolvedContentNegotiation } from './dispatch-content-negotiation.js';
2
2
  import { writeErrorResponse } from './dispatch-error-policy.js';
3
3
  import type { FrameworkRequest, FrameworkResponse, HandlerDescriptor } from '../types.js';
4
+ /**
5
+ * Write success response.
6
+ *
7
+ * @param handler The handler.
8
+ * @param request The request.
9
+ * @param response The response.
10
+ * @param value The value.
11
+ * @param contentNegotiation The content negotiation.
12
+ * @returns The write success response result.
13
+ */
4
14
  export declare function writeSuccessResponse(handler: HandlerDescriptor, request: FrameworkRequest, response: FrameworkResponse, value: unknown, contentNegotiation: ResolvedContentNegotiation | undefined): Promise<void>;
5
15
  export { resolveContentNegotiation, writeErrorResponse };
6
16
  export type { ResolvedContentNegotiation };
@@ -1 +1 @@
1
- {"version":3,"file":"dispatch-response-policy.d.ts","sourceRoot":"","sources":["../../src/dispatch/dispatch-response-policy.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,yBAAyB,EAEzB,KAAK,0BAA0B,EAChC,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,KAAK,EACV,gBAAgB,EAChB,iBAAiB,EACjB,iBAAiB,EAClB,MAAM,aAAa,CAAC;AAcrB,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,iBAAiB,EAC1B,OAAO,EAAE,gBAAgB,EACzB,QAAQ,EAAE,iBAAiB,EAC3B,KAAK,EAAE,OAAO,EACd,kBAAkB,EAAE,0BAA0B,GAAG,SAAS,GACzD,OAAO,CAAC,IAAI,CAAC,CAoCf;AAED,OAAO,EAAE,yBAAyB,EAAE,kBAAkB,EAAE,CAAC;AACzD,YAAY,EAAE,0BAA0B,EAAE,CAAC"}
1
+ {"version":3,"file":"dispatch-response-policy.d.ts","sourceRoot":"","sources":["../../src/dispatch/dispatch-response-policy.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,yBAAyB,EAEzB,KAAK,0BAA0B,EAChC,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,KAAK,EACV,gBAAgB,EAChB,iBAAiB,EACjB,iBAAiB,EAClB,MAAM,aAAa,CAAC;AAcrB;;;;;;;;;GASG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,iBAAiB,EAC1B,OAAO,EAAE,gBAAgB,EACzB,QAAQ,EAAE,iBAAiB,EAC3B,KAAK,EAAE,OAAO,EACd,kBAAkB,EAAE,0BAA0B,GAAG,SAAS,GACzD,OAAO,CAAC,IAAI,CAAC,CAoCf;AAED,OAAO,EAAE,yBAAyB,EAAE,kBAAkB,EAAE,CAAC;AACzD,YAAY,EAAE,0BAA0B,EAAE,CAAC"}
@@ -11,6 +11,17 @@ function resolveDefaultSuccessStatus(handler, value) {
11
11
  return 200;
12
12
  }
13
13
  }
14
+
15
+ /**
16
+ * Write success response.
17
+ *
18
+ * @param handler The handler.
19
+ * @param request The request.
20
+ * @param response The response.
21
+ * @param value The value.
22
+ * @param contentNegotiation The content negotiation.
23
+ * @returns The write success response result.
24
+ */
14
25
  export async function writeSuccessResponse(handler, request, response, value, contentNegotiation) {
15
26
  if (response.committed) {
16
27
  return;