@fluojs/http 1.1.2 → 3.0.0

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 (125) hide show
  1. package/README.ko.md +430 -15
  2. package/README.md +437 -15
  3. package/dist/access-log-observer.d.ts +77 -0
  4. package/dist/access-log-observer.d.ts.map +1 -0
  5. package/dist/access-log-observer.js +171 -0
  6. package/dist/adapter.d.ts +9 -0
  7. package/dist/adapter.d.ts.map +1 -1
  8. package/dist/adapter.js +15 -1
  9. package/dist/adapters/binding.d.ts.map +1 -1
  10. package/dist/adapters/binding.js +18 -16
  11. package/dist/adapters/dto-binding-plan.d.ts +2 -2
  12. package/dist/adapters/dto-binding-plan.d.ts.map +1 -1
  13. package/dist/adapters/dto-binding-plan.js +13 -4
  14. package/dist/adapters/dto-validation-adapter.d.ts +2 -1
  15. package/dist/adapters/dto-validation-adapter.d.ts.map +1 -1
  16. package/dist/adapters/dto-validation-adapter.js +2 -2
  17. package/dist/byte-range-response.d.ts +71 -0
  18. package/dist/byte-range-response.d.ts.map +1 -0
  19. package/dist/byte-range-response.js +347 -0
  20. package/dist/client-identity.d.ts +8 -4
  21. package/dist/client-identity.d.ts.map +1 -1
  22. package/dist/client-identity.js +12 -93
  23. package/dist/compiled-route-identity.d.ts +17 -0
  24. package/dist/compiled-route-identity.d.ts.map +1 -0
  25. package/dist/compiled-route-identity.js +29 -0
  26. package/dist/connection.d.ts +67 -0
  27. package/dist/connection.d.ts.map +1 -0
  28. package/dist/connection.js +480 -0
  29. package/dist/context/request-context-node-store.d.ts +6 -0
  30. package/dist/context/request-context-node-store.d.ts.map +1 -1
  31. package/dist/context/request-context-node-store.js +14 -0
  32. package/dist/context/request-context.d.ts +5 -5
  33. package/dist/context/request-context.d.ts.map +1 -1
  34. package/dist/context/request-context.js +8 -83
  35. package/dist/context/request-id.d.ts +10 -0
  36. package/dist/context/request-id.d.ts.map +1 -0
  37. package/dist/context/request-id.js +27 -0
  38. package/dist/context/sse.d.ts +13 -0
  39. package/dist/context/sse.d.ts.map +1 -1
  40. package/dist/context/sse.js +36 -6
  41. package/dist/cookie-helpers.d.ts +47 -0
  42. package/dist/cookie-helpers.d.ts.map +1 -0
  43. package/dist/cookie-helpers.js +166 -0
  44. package/dist/decorators.d.ts +52 -19
  45. package/dist/decorators.d.ts.map +1 -1
  46. package/dist/decorators.js +57 -10
  47. package/dist/dispatch/conditional-request-policy.d.ts +67 -0
  48. package/dist/dispatch/conditional-request-policy.d.ts.map +1 -0
  49. package/dist/dispatch/conditional-request-policy.js +297 -0
  50. package/dist/dispatch/dispatch-content-negotiation.d.ts +8 -0
  51. package/dist/dispatch/dispatch-content-negotiation.d.ts.map +1 -1
  52. package/dist/dispatch/dispatch-content-negotiation.js +89 -42
  53. package/dist/dispatch/dispatch-error-negotiation.d.ts +26 -0
  54. package/dist/dispatch/dispatch-error-negotiation.d.ts.map +1 -0
  55. package/dist/dispatch/dispatch-error-negotiation.js +110 -0
  56. package/dist/dispatch/dispatch-error-policy.d.ts +1 -10
  57. package/dist/dispatch/dispatch-error-policy.d.ts.map +1 -1
  58. package/dist/dispatch/dispatch-error-policy.js +1 -33
  59. package/dist/dispatch/dispatch-error-representation.d.ts +18 -0
  60. package/dist/dispatch/dispatch-error-representation.d.ts.map +1 -0
  61. package/dist/dispatch/dispatch-error-representation.js +125 -0
  62. package/dist/dispatch/dispatch-response-metadata.d.ts +10 -0
  63. package/dist/dispatch/dispatch-response-metadata.d.ts.map +1 -0
  64. package/dist/dispatch/dispatch-response-metadata.js +12 -0
  65. package/dist/dispatch/dispatch-response-policy.d.ts +33 -5
  66. package/dist/dispatch/dispatch-response-policy.d.ts.map +1 -1
  67. package/dist/dispatch/dispatch-response-policy.js +149 -18
  68. package/dist/dispatch/dispatcher.d.ts +5 -1
  69. package/dist/dispatch/dispatcher.d.ts.map +1 -1
  70. package/dist/dispatch/dispatcher.js +178 -107
  71. package/dist/dispatch/fast-path/debug-visibility.d.ts.map +1 -1
  72. package/dist/dispatch/fast-path/debug-visibility.js +6 -3
  73. package/dist/dispatch/fast-path/dispatcher-state.d.ts +10 -0
  74. package/dist/dispatch/fast-path/dispatcher-state.d.ts.map +1 -0
  75. package/dist/dispatch/fast-path/dispatcher-state.js +52 -0
  76. package/dist/dispatch/fast-path/eligibility-checker.d.ts.map +1 -1
  77. package/dist/dispatch/fast-path/eligibility-checker.js +27 -15
  78. package/dist/dispatch/fast-path/eligibility.d.ts +16 -10
  79. package/dist/dispatch/fast-path/eligibility.d.ts.map +1 -1
  80. package/dist/dispatch/fast-path/eligibility.js +10 -4
  81. package/dist/dispatch/fast-path/fast-path-executor.d.ts +14 -1
  82. package/dist/dispatch/fast-path/fast-path-executor.d.ts.map +1 -1
  83. package/dist/dispatch/fast-path/fast-path-executor.js +23 -6
  84. package/dist/dispatch/request-abort.d.ts +22 -0
  85. package/dist/dispatch/request-abort.d.ts.map +1 -0
  86. package/dist/dispatch/request-abort.js +30 -0
  87. package/dist/dispatch/response-integration.d.ts +55 -0
  88. package/dist/dispatch/response-integration.d.ts.map +1 -0
  89. package/dist/dispatch/response-integration.js +57 -0
  90. package/dist/errors.d.ts +10 -0
  91. package/dist/errors.d.ts.map +1 -1
  92. package/dist/errors.js +19 -0
  93. package/dist/guards.d.ts +1 -1
  94. package/dist/guards.d.ts.map +1 -1
  95. package/dist/header-helpers.d.ts +59 -0
  96. package/dist/header-helpers.d.ts.map +1 -0
  97. package/dist/header-helpers.js +185 -0
  98. package/dist/index.d.ts +1 -16
  99. package/dist/index.d.ts.map +1 -1
  100. package/dist/index.js +4 -15
  101. package/dist/index.portable.d.ts +25 -0
  102. package/dist/index.portable.d.ts.map +1 -0
  103. package/dist/index.portable.js +21 -0
  104. package/dist/internal.d.ts +3 -1
  105. package/dist/internal.d.ts.map +1 -1
  106. package/dist/internal.js +2 -0
  107. package/dist/mapping.d.ts.map +1 -1
  108. package/dist/mapping.js +100 -15
  109. package/dist/middleware/correlation.d.ts +9 -1
  110. package/dist/middleware/correlation.d.ts.map +1 -1
  111. package/dist/middleware/correlation.js +25 -14
  112. package/dist/middleware/cors.d.ts.map +1 -1
  113. package/dist/middleware/cors.js +7 -8
  114. package/dist/middleware/middleware.d.ts +3 -3
  115. package/dist/middleware/middleware.d.ts.map +1 -1
  116. package/dist/middleware/rate-limit.d.ts +13 -2
  117. package/dist/middleware/rate-limit.d.ts.map +1 -1
  118. package/dist/middleware/rate-limit.js +1 -0
  119. package/dist/static-assets.d.ts +77 -0
  120. package/dist/static-assets.d.ts.map +1 -0
  121. package/dist/static-assets.js +270 -0
  122. package/dist/types.d.ts +225 -17
  123. package/dist/types.d.ts.map +1 -1
  124. package/dist/types.js +71 -1
  125. package/package.json +19 -9
@@ -58,10 +58,10 @@ export function compileFastPathEligibility(handler, options, adapter) {
58
58
  const hasRequestScopedDI = determineRequestScopeRequirement(handler, options);
59
59
  const hasMiddleware = determineMiddlewareRequirement(handler, options.appMiddleware ?? []);
60
60
  const hasContentNegotiation = options.contentNegotiation?.formatters !== undefined && options.contentNegotiation.formatters.length > 0;
61
+ const hasConditionalRequest = options.conditionalRequest !== undefined;
61
62
  const isSseRoute = handler.route.produces?.some(mediaType => mediaType.toLowerCase().startsWith('text/event-stream')) === true;
62
- const eligibility = {
63
+ const eligibilityBase = {
63
64
  adapter,
64
- executionPath: 'full',
65
65
  hasAdapterPluginInfluence: false,
66
66
  hasCustomBodyParser: options.binder !== undefined,
67
67
  hasCustomErrorFilter: options.onError !== undefined,
@@ -74,39 +74,44 @@ export function compileFastPathEligibility(handler, options, adapter) {
74
74
  routeId
75
75
  };
76
76
  const blockingReasons = [];
77
- if (eligibility.hasGuard) {
77
+ if (eligibilityBase.hasGuard) {
78
78
  blockingReasons.push('guards');
79
79
  }
80
- if (eligibility.hasInterceptor) {
80
+ if (eligibilityBase.hasInterceptor) {
81
81
  blockingReasons.push('interceptors');
82
82
  }
83
- if (eligibility.hasRequestScopedDI) {
83
+ if (eligibilityBase.hasRequestScopedDI) {
84
84
  blockingReasons.push('request-scoped DI');
85
85
  }
86
- if (eligibility.hasMiddleware) {
86
+ if (eligibilityBase.hasMiddleware) {
87
87
  blockingReasons.push('middleware');
88
88
  }
89
- if (eligibility.hasGlobalHook) {
89
+ if (eligibilityBase.hasGlobalHook) {
90
90
  blockingReasons.push('request observers');
91
91
  }
92
- if (eligibility.hasCustomErrorFilter) {
92
+ if (eligibilityBase.hasCustomErrorFilter) {
93
93
  blockingReasons.push('custom error filter');
94
94
  }
95
- if (eligibility.hasCustomBodyParser) {
95
+ if (eligibilityBase.hasCustomBodyParser) {
96
96
  blockingReasons.push('custom binder');
97
97
  }
98
98
  if (hasContentNegotiation) {
99
99
  blockingReasons.push('content negotiation');
100
100
  }
101
+ if (hasConditionalRequest) {
102
+ blockingReasons.push('conditional requests');
103
+ }
101
104
  if (isSseRoute) {
102
105
  blockingReasons.push('SSE streaming');
103
106
  }
104
107
  const isEligible = blockingReasons.length === 0;
105
- if (!isEligible) {
106
- eligibility.fallbackReason = `Full path required due to: ${blockingReasons.join(', ')}`;
107
- } else {
108
- eligibility.executionPath = 'fast';
109
- }
108
+ const eligibility = Object.freeze({
109
+ ...eligibilityBase,
110
+ executionPath: isEligible ? 'fast' : 'full',
111
+ ...(isEligible ? {} : {
112
+ fallbackReason: `Full path required due to: ${blockingReasons.join(', ')}`
113
+ })
114
+ });
110
115
  return {
111
116
  eligibility,
112
117
  isEligible
@@ -130,7 +135,14 @@ export function getHandlerFastPathEligibility(handler) {
130
135
  * @param eligibility Eligibility metadata to expose through dispatcher observability.
131
136
  */
132
137
  export function setHandlerFastPathEligibility(handler, eligibility) {
133
- handler[FAST_PATH_ELIGIBILITY_SYMBOL] = eligibility;
138
+ Object.defineProperty(handler, FAST_PATH_ELIGIBILITY_SYMBOL, {
139
+ configurable: false,
140
+ enumerable: false,
141
+ value: Object.freeze({
142
+ ...eligibility
143
+ }),
144
+ writable: false
145
+ });
134
146
  }
135
147
 
136
148
  /** Options shared by fast-path executor helpers. */
@@ -31,31 +31,37 @@ export interface FastPathEligibility {
31
31
  /** Whether adapter-level plugin behavior may affect execution. */
32
32
  readonly hasAdapterPluginInfluence: boolean;
33
33
  /** Resolved execution path, either 'fast' or 'full'. */
34
- executionPath: 'fast' | 'full';
34
+ readonly executionPath: 'fast' | 'full';
35
35
  /** Explanation for full-path fallback when fast path is not selected. */
36
- fallbackReason?: string;
36
+ readonly fallbackReason?: string;
37
37
  }
38
38
  /**
39
39
  * Statistics collected about fast path decisions for observability.
40
40
  */
41
41
  export interface FastPathStats {
42
42
  /** Total number of routes analyzed. */
43
- totalRoutes: number;
43
+ readonly totalRoutes: number;
44
44
  /** Number of routes eligible for fast path. */
45
- fastPathRoutes: number;
45
+ readonly fastPathRoutes: number;
46
46
  /** Number of routes using full path. */
47
- fullPathRoutes: number;
47
+ readonly fullPathRoutes: number;
48
48
  /** Per-route eligibility details. */
49
- routes: ReadonlyArray<Readonly<FastPathEligibility>>;
49
+ readonly routes: readonly Readonly<FastPathEligibility>[];
50
50
  }
51
51
  /**
52
- * Symbol used to attach fast path eligibility metadata to handler descriptors.
53
- * @internal
52
+ * Public symbol key for fast path eligibility metadata attached to dispatcher route snapshots.
53
+ *
54
+ * @remarks
55
+ * Adapter and diagnostics integrations can use this key to inspect the route's
56
+ * frozen {@link FastPathEligibility} metadata without accessing dispatcher-owned state.
54
57
  */
55
58
  export declare const FAST_PATH_ELIGIBILITY_SYMBOL: unique symbol;
56
59
  /**
57
- * Symbol used to attach fast path execution stats to dispatcher.
58
- * @internal
60
+ * Public symbol key for fast path execution statistics attached to a dispatcher.
61
+ *
62
+ * @remarks
63
+ * Adapter and diagnostics integrations can use this key to read the same
64
+ * {@link FastPathStats} value exposed by `getDispatcherFastPathStats(...)`.
59
65
  */
60
66
  export declare const FAST_PATH_STATS_SYMBOL: unique symbol;
61
67
  //# sourceMappingURL=eligibility.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"eligibility.d.ts","sourceRoot":"","sources":["../../../src/dispatch/fast-path/eligibility.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,WAAW,mBAAmB;IAClC,sDAAsD;IACtD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAEzB,qDAAqD;IACrD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAEzB,+DAA+D;IAC/D,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAE3B,wDAAwD;IACxD,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAEhC,+CAA+C;IAC/C,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAEhC,gDAAgD;IAChD,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAE3B,6DAA6D;IAC7D,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAE1B,sDAAsD;IACtD,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;IAEjC,8DAA8D;IAC9D,QAAQ,CAAC,kBAAkB,EAAE,OAAO,CAAC;IAErC,yDAAyD;IACzD,QAAQ,CAAC,mBAAmB,EAAE,OAAO,CAAC;IAEtC,iDAAiD;IACjD,QAAQ,CAAC,oBAAoB,EAAE,OAAO,CAAC;IAEvC,kEAAkE;IAClE,QAAQ,CAAC,yBAAyB,EAAE,OAAO,CAAC;IAE5C,wDAAwD;IACxD,aAAa,EAAE,MAAM,GAAG,MAAM,CAAC;IAE/B,yEAAyE;IACzE,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,uCAAuC;IACvC,WAAW,EAAE,MAAM,CAAC;IAEpB,+CAA+C;IAC/C,cAAc,EAAE,MAAM,CAAC;IAEvB,wCAAwC;IACxC,cAAc,EAAE,MAAM,CAAC;IAEvB,qCAAqC;IACrC,MAAM,EAAE,aAAa,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC,CAAC;CACtD;AAED;;;GAGG;AACH,eAAO,MAAM,4BAA4B,eAAgC,CAAC;AAE1E;;;GAGG;AACH,eAAO,MAAM,sBAAsB,eAA0B,CAAC"}
1
+ {"version":3,"file":"eligibility.d.ts","sourceRoot":"","sources":["../../../src/dispatch/fast-path/eligibility.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,WAAW,mBAAmB;IAClC,sDAAsD;IACtD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAEzB,qDAAqD;IACrD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAEzB,+DAA+D;IAC/D,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAE3B,wDAAwD;IACxD,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAEhC,+CAA+C;IAC/C,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAEhC,gDAAgD;IAChD,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAE3B,6DAA6D;IAC7D,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAE1B,sDAAsD;IACtD,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;IAEjC,8DAA8D;IAC9D,QAAQ,CAAC,kBAAkB,EAAE,OAAO,CAAC;IAErC,yDAAyD;IACzD,QAAQ,CAAC,mBAAmB,EAAE,OAAO,CAAC;IAEtC,iDAAiD;IACjD,QAAQ,CAAC,oBAAoB,EAAE,OAAO,CAAC;IAEvC,kEAAkE;IAClE,QAAQ,CAAC,yBAAyB,EAAE,OAAO,CAAC;IAE5C,wDAAwD;IACxD,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAAC;IAExC,yEAAyE;IACzE,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;CAClC;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,uCAAuC;IACvC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAE7B,+CAA+C;IAC/C,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAEhC,wCAAwC;IACxC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAEhC,qCAAqC;IACrC,QAAQ,CAAC,MAAM,EAAE,SAAS,QAAQ,CAAC,mBAAmB,CAAC,EAAE,CAAC;CAC3D;AAED;;;;;;GAMG;AACH,eAAO,MAAM,4BAA4B,eAAgC,CAAC;AAE1E;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB,eAA0B,CAAC"}
@@ -11,13 +11,19 @@
11
11
  */
12
12
 
13
13
  /**
14
- * Symbol used to attach fast path eligibility metadata to handler descriptors.
15
- * @internal
14
+ * Public symbol key for fast path eligibility metadata attached to dispatcher route snapshots.
15
+ *
16
+ * @remarks
17
+ * Adapter and diagnostics integrations can use this key to inspect the route's
18
+ * frozen {@link FastPathEligibility} metadata without accessing dispatcher-owned state.
16
19
  */
17
20
  export const FAST_PATH_ELIGIBILITY_SYMBOL = Symbol('fastPathEligibility');
18
21
 
19
22
  /**
20
- * Symbol used to attach fast path execution stats to dispatcher.
21
- * @internal
23
+ * Public symbol key for fast path execution statistics attached to a dispatcher.
24
+ *
25
+ * @remarks
26
+ * Adapter and diagnostics integrations can use this key to read the same
27
+ * {@link FastPathStats} value exposed by `getDispatcherFastPathStats(...)`.
22
28
  */
23
29
  export const FAST_PATH_STATS_SYMBOL = Symbol('fastPathStats');
@@ -1,6 +1,6 @@
1
1
  import type { RequestScopeContainer } from '@fluojs/di';
2
- import { type ResolvedContentNegotiation } from '../dispatch-response-policy.js';
3
2
  import type { Binder, FrameworkRequest, FrameworkResponse, HandlerDescriptor, RequestContext } from '../../types.js';
3
+ import { type ResolvedContentNegotiation } from '../dispatch-response-policy.js';
4
4
  import type { FastPathExecutionResult } from './eligibility-checker.js';
5
5
  interface ExecuteFastPathOptions {
6
6
  binder?: Binder;
@@ -13,7 +13,20 @@ interface ExecuteFastPathOptions {
13
13
  requestContext: RequestContext;
14
14
  response: FrameworkResponse;
15
15
  }
16
+ /**
17
+ * Execute one handler through the compiled fast-path dispatcher plan.
18
+ *
19
+ * @param options Fast-path execution inputs for binding, handler invocation, and response writing.
20
+ * @returns The fast-path execution result, including a fallback error when the route cannot be executed safely.
21
+ */
16
22
  export declare function executeFastPath(options: ExecuteFastPathOptions): Promise<FastPathExecutionResult>;
23
+ /**
24
+ * Determine whether a request may use the precompiled fast-path execution plan.
25
+ *
26
+ * @param eligibility The handler fast-path eligibility state computed during dispatcher setup.
27
+ * @param request The active request whose abort state can disable fast-path execution.
28
+ * @returns `true` when the request can use the fast-path executor.
29
+ */
17
30
  export declare function shouldUseFastPathForRequest(eligibility: {
18
31
  executionPath: 'fast' | 'full';
19
32
  } | undefined, request: FrameworkRequest): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"fast-path-executor.d.ts","sourceRoot":"","sources":["../../../src/dispatch/fast-path/fast-path-executor.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAOxD,OAAO,EAAE,KAAK,0BAA0B,EAAwB,MAAM,gCAAgC,CAAC;AACvG,OAAO,KAAK,EACV,MAAM,EACN,gBAAgB,EAChB,iBAAiB,EACjB,iBAAiB,EACjB,cAAc,EACf,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AASxE,UAAU,sBAAsB;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kBAAkB,CAAC,EAAE,0BAA0B,CAAC;IAChD,mBAAmB,EAAE,qBAAqB,CAAC;IAC3C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,iBAAiB,CAAC;IAC3B,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,cAAc,KAAK,OAAO,CAAC;IACnF,OAAO,EAAE,gBAAgB,CAAC;IAC1B,cAAc,EAAE,cAAc,CAAC;IAC/B,QAAQ,EAAE,iBAAiB,CAAC;CAC7B;AAED,wBAAsB,eAAe,CACnC,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,uBAAuB,CAAC,CAoDlC;AASD,wBAAgB,2BAA2B,CACzC,WAAW,EAAE;IAAE,aAAa,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,GAAG,SAAS,EAC3D,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAWT"}
1
+ {"version":3,"file":"fast-path-executor.d.ts","sourceRoot":"","sources":["../../../src/dispatch/fast-path/fast-path-executor.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAOxD,OAAO,KAAK,EACV,MAAM,EACN,gBAAgB,EAChB,iBAAiB,EACjB,iBAAiB,EACjB,cAAc,EACf,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,KAAK,0BAA0B,EAEhC,MAAM,gCAAgC,CAAC;AAExC,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AASxE,UAAU,sBAAsB;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kBAAkB,CAAC,EAAE,0BAA0B,CAAC;IAChD,mBAAmB,EAAE,qBAAqB,CAAC;IAC3C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,iBAAiB,CAAC;IAC3B,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,cAAc,KAAK,OAAO,CAAC;IACnF,OAAO,EAAE,gBAAgB,CAAC;IAC1B,cAAc,EAAE,cAAc,CAAC;IAC/B,QAAQ,EAAE,iBAAiB,CAAC;CAC7B;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,uBAAuB,CAAC,CAyDlC;AASD;;;;;;GAMG;AACH,wBAAgB,2BAA2B,CACzC,WAAW,EAAE;IAAE,aAAa,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,GAAG,SAAS,EAC3D,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAWT"}
@@ -1,11 +1,18 @@
1
1
  import { DefaultBinder } from '../../adapters/binding.js';
2
2
  import { getCompiledDtoBindingPlan } from '../../adapters/dto-binding-plan.js';
3
3
  import { HttpDtoValidationAdapter } from '../../adapters/dto-validation-adapter.js';
4
- import { SseResponse } from '../../context/sse.js';
4
+ import { SseResponse, waitForSseResponseCompletion } from '../../context/sse.js';
5
5
  import { RequestAbortedError } from '../../errors.js';
6
6
  import { writeSuccessResponse } from '../dispatch-response-policy.js';
7
+ import { isRequestAborted } from '../request-abort.js';
7
8
  const defaultBinder = new DefaultBinder();
8
9
  const defaultValidator = new HttpDtoValidationAdapter();
10
+ /**
11
+ * Execute one handler through the compiled fast-path dispatcher plan.
12
+ *
13
+ * @param options Fast-path execution inputs for binding, handler invocation, and response writing.
14
+ * @returns The fast-path execution result, including a fallback error when the route cannot be executed safely.
15
+ */
9
16
  export async function executeFastPath(options) {
10
17
  const {
11
18
  binder,
@@ -43,8 +50,13 @@ export async function executeFastPath(options) {
43
50
  if (isRequestAborted(request)) {
44
51
  throw new RequestAbortedError();
45
52
  }
46
- if (!(result instanceof SseResponse) && !response.committed) {
47
- const writeResult = writeSuccessResponse(handler, request, response, result, contentNegotiation);
53
+ if (result instanceof SseResponse) {
54
+ await waitForSseResponseCompletion(result);
55
+ if (isRequestAborted(request)) {
56
+ throw new RequestAbortedError();
57
+ }
58
+ } else if (!response.committed) {
59
+ const writeResult = writeSuccessResponse(handler, request, response, result, contentNegotiation, requestContext);
48
60
  if (isThenable(writeResult)) {
49
61
  await writeResult;
50
62
  }
@@ -63,6 +75,14 @@ export async function executeFastPath(options) {
63
75
  function isThenable(value) {
64
76
  return typeof value === 'object' && value !== null && 'then' in value && typeof value.then === 'function';
65
77
  }
78
+
79
+ /**
80
+ * Determine whether a request may use the precompiled fast-path execution plan.
81
+ *
82
+ * @param eligibility The handler fast-path eligibility state computed during dispatcher setup.
83
+ * @param request The active request whose abort state can disable fast-path execution.
84
+ * @returns `true` when the request can use the fast-path executor.
85
+ */
66
86
  export function shouldUseFastPathForRequest(eligibility, request) {
67
87
  if (!eligibility) {
68
88
  return false;
@@ -74,7 +94,4 @@ export function shouldUseFastPathForRequest(eligibility, request) {
74
94
  return false;
75
95
  }
76
96
  return true;
77
- }
78
- function isRequestAborted(request) {
79
- return request.isAborted?.() ?? request.signal?.aborted === true;
80
97
  }
@@ -0,0 +1,22 @@
1
+ import type { FrameworkRequest, RequestContext } from '../types.js';
2
+ /**
3
+ * Reports whether the adapter-provided request abort probes have fired.
4
+ *
5
+ * @param request Adapter-normalized request to inspect.
6
+ * @returns Whether transport cancellation has been observed.
7
+ */
8
+ export declare function isRequestAborted(request: FrameworkRequest): boolean;
9
+ /**
10
+ * Reports whether a request context was cancelled by transport or response-stream closure.
11
+ *
12
+ * @param context Request context to inspect.
13
+ * @returns Whether cancellation has been observed.
14
+ */
15
+ export declare function isRequestContextAborted(context: RequestContext): boolean;
16
+ /**
17
+ * Marks a request context as cancelled by a response-stream disconnect.
18
+ *
19
+ * @param context Request context whose stream closed unexpectedly.
20
+ */
21
+ export declare function markRequestContextAborted(context: RequestContext): void;
22
+ //# sourceMappingURL=request-abort.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-abort.d.ts","sourceRoot":"","sources":["../../src/dispatch/request-abort.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAIpE;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAEnE;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAGxE;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI,CAEvE"}
@@ -0,0 +1,30 @@
1
+ const REQUEST_ABORTED_BY_RESPONSE_STREAM = Symbol('fluo.http.requestAbortedByResponseStream');
2
+
3
+ /**
4
+ * Reports whether the adapter-provided request abort probes have fired.
5
+ *
6
+ * @param request Adapter-normalized request to inspect.
7
+ * @returns Whether transport cancellation has been observed.
8
+ */
9
+ export function isRequestAborted(request) {
10
+ return request.isAborted?.() === true || request.signal?.aborted === true;
11
+ }
12
+
13
+ /**
14
+ * Reports whether a request context was cancelled by transport or response-stream closure.
15
+ *
16
+ * @param context Request context to inspect.
17
+ * @returns Whether cancellation has been observed.
18
+ */
19
+ export function isRequestContextAborted(context) {
20
+ return isRequestAborted(context.request) || context.metadata[REQUEST_ABORTED_BY_RESPONSE_STREAM] === true;
21
+ }
22
+
23
+ /**
24
+ * Marks a request context as cancelled by a response-stream disconnect.
25
+ *
26
+ * @param context Request context whose stream closed unexpectedly.
27
+ */
28
+ export function markRequestContextAborted(context) {
29
+ context.metadata[REQUEST_ABORTED_BY_RESPONSE_STREAM] = true;
30
+ }
@@ -0,0 +1,55 @@
1
+ import type { FrameworkRequest, FrameworkResponse, HandlerDescriptor, RequestContext, ResponseValidators } from '../types.js';
2
+ /** Shared response-entry brand recognized by the HTTP success-response policy. */
3
+ export declare const FRAMEWORK_RESPONSE_WRITER: unique symbol;
4
+ /** Request-local metadata key for response-value finalization before response writing. */
5
+ export declare const FRAMEWORK_RESPONSE_VALUE_FINALIZER: unique symbol;
6
+ /** Context supplied when an integration writes a successful framework response. */
7
+ export type FrameworkResponseWriterContext = {
8
+ readonly applySuccessResponseMetadata: () => void;
9
+ readonly handler: HandlerDescriptor;
10
+ readonly request: FrameworkRequest;
11
+ readonly requestContext: RequestContext;
12
+ readonly response: FrameworkResponse;
13
+ /** Validators resolved by the dispatcher before the handler executed. */
14
+ readonly validators: ResponseValidators | undefined;
15
+ /** Finalized handler value that owns this response writer. */
16
+ readonly value: unknown;
17
+ };
18
+ /** Writer installed by an HTTP integration on one response entry. */
19
+ export type FrameworkResponseWriter = (context: FrameworkResponseWriterContext) => ReturnType<FrameworkResponse['send']> | void;
20
+ /** Context supplied when an integration finalizes a handler result before response writing. */
21
+ export type FrameworkResponseValueFinalizerContext = {
22
+ readonly handler: HandlerDescriptor;
23
+ readonly request: FrameworkRequest;
24
+ readonly requestContext: RequestContext;
25
+ readonly response: FrameworkResponse;
26
+ readonly value: unknown;
27
+ };
28
+ /**
29
+ * Request-local transformation applied before the HTTP policy selects a response writer.
30
+ *
31
+ * Finalizers may resolve asynchronously. The dispatcher awaits their results and
32
+ * routes thrown errors and rejections through its normal error policy.
33
+ */
34
+ export type FrameworkResponseValueFinalizer = (context: FrameworkResponseValueFinalizerContext) => unknown | Promise<unknown>;
35
+ /**
36
+ * Brands a response entry with an integration-owned writer.
37
+ *
38
+ * @param entry Response entry returned by an HTTP handler.
39
+ * @param writer Writer invoked by the shared success-response policy.
40
+ * @returns The branded response entry.
41
+ */
42
+ export declare function registerFrameworkResponseWriter<Entry extends object>(entry: Entry, writer: FrameworkResponseWriter): Entry;
43
+ /**
44
+ * Registers a request-local handler-result finalizer for an HTTP integration.
45
+ *
46
+ * @param context Active request context whose metadata carries the finalizer.
47
+ * @param finalizer Transformation applied before response-writer selection.
48
+ *
49
+ * @remarks
50
+ * Multiple registrations compose in registration order. Each later finalizer
51
+ * receives the previous finalizer's resolved value, and any thrown error or
52
+ * rejection is handled by the dispatcher's existing error policy.
53
+ */
54
+ export declare function registerFrameworkResponseValueFinalizer(context: Pick<RequestContext, 'metadata'>, finalizer: FrameworkResponseValueFinalizer): void;
55
+ //# sourceMappingURL=response-integration.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"response-integration.d.ts","sourceRoot":"","sources":["../../src/dispatch/response-integration.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,gBAAgB,EAChB,iBAAiB,EACjB,iBAAiB,EACjB,cAAc,EACd,kBAAkB,EACnB,MAAM,aAAa,CAAC;AAErB,kFAAkF;AAClF,eAAO,MAAM,yBAAyB,eAAyC,CAAC;AAEhF,0FAA0F;AAC1F,eAAO,MAAM,kCAAkC,eAAiD,CAAC;AAEjG,mFAAmF;AACnF,MAAM,MAAM,8BAA8B,GAAG;IAC3C,QAAQ,CAAC,4BAA4B,EAAE,MAAM,IAAI,CAAC;IAClD,QAAQ,CAAC,OAAO,EAAE,iBAAiB,CAAC;IACpC,QAAQ,CAAC,OAAO,EAAE,gBAAgB,CAAC;IACnC,QAAQ,CAAC,cAAc,EAAE,cAAc,CAAC;IACxC,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAAC;IACrC,yEAAyE;IACzE,QAAQ,CAAC,UAAU,EAAE,kBAAkB,GAAG,SAAS,CAAC;IACpD,8DAA8D;IAC9D,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACzB,CAAC;AAEF,qEAAqE;AACrE,MAAM,MAAM,uBAAuB,GAAG,CACpC,OAAO,EAAE,8BAA8B,KACpC,UAAU,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC,GAAG,IAAI,CAAC;AAElD,+FAA+F;AAC/F,MAAM,MAAM,sCAAsC,GAAG;IACnD,QAAQ,CAAC,OAAO,EAAE,iBAAiB,CAAC;IACpC,QAAQ,CAAC,OAAO,EAAE,gBAAgB,CAAC;IACnC,QAAQ,CAAC,cAAc,EAAE,cAAc,CAAC;IACxC,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAAC;IACrC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACzB,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,+BAA+B,GAAG,CAC5C,OAAO,EAAE,sCAAsC,KAC5C,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;AAEhC;;;;;;GAMG;AACH,wBAAgB,+BAA+B,CAAC,KAAK,SAAS,MAAM,EAClE,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,uBAAuB,GAC9B,KAAK,CAOP;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,uCAAuC,CACrD,OAAO,EAAE,IAAI,CAAC,cAAc,EAAE,UAAU,CAAC,EACzC,SAAS,EAAE,+BAA+B,GACzC,IAAI,CAiBN"}
@@ -0,0 +1,57 @@
1
+ /** Shared response-entry brand recognized by the HTTP success-response policy. */
2
+ export const FRAMEWORK_RESPONSE_WRITER = Symbol.for('fluo.http.responseWriter');
3
+
4
+ /** Request-local metadata key for response-value finalization before response writing. */
5
+ export const FRAMEWORK_RESPONSE_VALUE_FINALIZER = Symbol.for('fluo.http.responseValueFinalizer');
6
+
7
+ /** Context supplied when an integration writes a successful framework response. */
8
+
9
+ /** Writer installed by an HTTP integration on one response entry. */
10
+
11
+ /** Context supplied when an integration finalizes a handler result before response writing. */
12
+
13
+ /**
14
+ * Request-local transformation applied before the HTTP policy selects a response writer.
15
+ *
16
+ * Finalizers may resolve asynchronously. The dispatcher awaits their results and
17
+ * routes thrown errors and rejections through its normal error policy.
18
+ */
19
+
20
+ /**
21
+ * Brands a response entry with an integration-owned writer.
22
+ *
23
+ * @param entry Response entry returned by an HTTP handler.
24
+ * @param writer Writer invoked by the shared success-response policy.
25
+ * @returns The branded response entry.
26
+ */
27
+ export function registerFrameworkResponseWriter(entry, writer) {
28
+ Object.defineProperty(entry, FRAMEWORK_RESPONSE_WRITER, {
29
+ enumerable: false,
30
+ value: writer
31
+ });
32
+ return entry;
33
+ }
34
+
35
+ /**
36
+ * Registers a request-local handler-result finalizer for an HTTP integration.
37
+ *
38
+ * @param context Active request context whose metadata carries the finalizer.
39
+ * @param finalizer Transformation applied before response-writer selection.
40
+ *
41
+ * @remarks
42
+ * Multiple registrations compose in registration order. Each later finalizer
43
+ * receives the previous finalizer's resolved value, and any thrown error or
44
+ * rejection is handled by the dispatcher's existing error policy.
45
+ */
46
+ export function registerFrameworkResponseValueFinalizer(context, finalizer) {
47
+ const existingFinalizer = context.metadata[FRAMEWORK_RESPONSE_VALUE_FINALIZER];
48
+ if (typeof existingFinalizer !== 'function') {
49
+ context.metadata[FRAMEWORK_RESPONSE_VALUE_FINALIZER] = finalizer;
50
+ return;
51
+ }
52
+ const previousFinalizer = existingFinalizer;
53
+ context.metadata[FRAMEWORK_RESPONSE_VALUE_FINALIZER] = async finalizerContext => finalizer({
54
+ ...finalizerContext,
55
+ value: await previousFinalizer(finalizerContext)
56
+ });
57
+ }
package/dist/errors.d.ts CHANGED
@@ -11,6 +11,10 @@ export declare class RouteConflictError extends FluoError {
11
11
  export declare class InvalidRoutePathError extends FluoError {
12
12
  constructor(message: string);
13
13
  }
14
+ /** Error thrown when a generic route method is not a valid HTTP token or uses the reserved `ALL` sentinel. */
15
+ export declare class InvalidHttpMethodError extends FluoError {
16
+ constructor(message: string);
17
+ }
14
18
  /**
15
19
  * Error thrown when no handler matches the incoming request path or method.
16
20
  */
@@ -23,4 +27,10 @@ export declare class HandlerNotFoundError extends FluoError {
23
27
  export declare class RequestAbortedError extends FluoError {
24
28
  constructor(message?: string);
25
29
  }
30
+ /** Error thrown when a supported adapter cannot emit one Early Hints response. */
31
+ export declare class EarlyHintsWriteError extends FluoError {
32
+ constructor(message?: string, options?: {
33
+ cause?: unknown;
34
+ });
35
+ }
26
36
  //# sourceMappingURL=errors.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC;;GAEG;AACH,qBAAa,kBAAmB,SAAQ,SAAS;gBACnC,OAAO,EAAE,MAAM;CAG5B;AAED;;GAEG;AACH,qBAAa,qBAAsB,SAAQ,SAAS;gBACtC,OAAO,EAAE,MAAM;CAG5B;AAED;;GAEG;AACH,qBAAa,oBAAqB,SAAQ,SAAS;gBACrC,OAAO,EAAE,MAAM;CAG5B;AAED;;GAEG;AACH,qBAAa,mBAAoB,SAAQ,SAAS;gBACpC,OAAO,SAA4C;CAGhE"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC;;GAEG;AACH,qBAAa,kBAAmB,SAAQ,SAAS;gBACnC,OAAO,EAAE,MAAM;CAG5B;AAED;;GAEG;AACH,qBAAa,qBAAsB,SAAQ,SAAS;gBACtC,OAAO,EAAE,MAAM;CAG5B;AAED,8GAA8G;AAC9G,qBAAa,sBAAuB,SAAQ,SAAS;gBACvC,OAAO,EAAE,MAAM;CAG5B;AAED;;GAEG;AACH,qBAAa,oBAAqB,SAAQ,SAAS;gBACrC,OAAO,EAAE,MAAM;CAG5B;AAED;;GAEG;AACH,qBAAa,mBAAoB,SAAQ,SAAS;gBACpC,OAAO,SAA4C;CAGhE;AAED,kFAAkF;AAClF,qBAAa,oBAAqB,SAAQ,SAAS;gBAE/C,OAAO,SAA0C,EACjD,OAAO,GAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAO;CAOpC"}
package/dist/errors.js CHANGED
@@ -22,6 +22,15 @@ export class InvalidRoutePathError extends FluoError {
22
22
  }
23
23
  }
24
24
 
25
+ /** Error thrown when a generic route method is not a valid HTTP token or uses the reserved `ALL` sentinel. */
26
+ export class InvalidHttpMethodError extends FluoError {
27
+ constructor(message) {
28
+ super(message, {
29
+ code: 'INVALID_HTTP_METHOD'
30
+ });
31
+ }
32
+ }
33
+
25
34
  /**
26
35
  * Error thrown when no handler matches the incoming request path or method.
27
36
  */
@@ -42,4 +51,14 @@ export class RequestAbortedError extends FluoError {
42
51
  code: 'REQUEST_ABORTED'
43
52
  });
44
53
  }
54
+ }
55
+
56
+ /** Error thrown when a supported adapter cannot emit one Early Hints response. */
57
+ export class EarlyHintsWriteError extends FluoError {
58
+ constructor(message = 'Failed to write HTTP 103 Early Hints.', options = {}) {
59
+ super(message, {
60
+ cause: options.cause,
61
+ code: 'EARLY_HINTS_WRITE_FAILED'
62
+ });
63
+ }
45
64
  }
package/dist/guards.d.ts CHANGED
@@ -6,5 +6,5 @@ import type { GuardContext, GuardLike } from './types.js';
6
6
  * @param context The context.
7
7
  * @returns The run guard chain result.
8
8
  */
9
- export declare function runGuardChain(definitions: GuardLike[], context: GuardContext): Promise<void>;
9
+ export declare function runGuardChain(definitions: readonly GuardLike[], context: GuardContext): Promise<void>;
10
10
  //# sourceMappingURL=guards.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"guards.d.ts","sourceRoot":"","sources":["../src/guards.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAS,YAAY,EAAE,SAAS,EAAkB,MAAM,YAAY,CAAC;AAcjF;;;;;;GAMG;AACH,wBAAsB,aAAa,CAAC,WAAW,EAAE,SAAS,EAAE,EAAE,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAalG"}
1
+ {"version":3,"file":"guards.d.ts","sourceRoot":"","sources":["../src/guards.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAS,YAAY,EAAE,SAAS,EAAkB,MAAM,YAAY,CAAC;AAcjF;;;;;;GAMG;AACH,wBAAsB,aAAa,CAAC,WAAW,EAAE,SAAS,SAAS,EAAE,EAAE,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAa3G"}
@@ -0,0 +1,59 @@
1
+ import type { FrameworkRequest, FrameworkResponse } from './types.js';
2
+ /**
3
+ * Reads one request header without flattening multi-value arrays.
4
+ *
5
+ * @param request Adapter-normalized request carrying the inbound headers map.
6
+ * @param name Header name to resolve case-insensitively.
7
+ * @returns The original scalar, array, or `undefined` stored on the request.
8
+ */
9
+ export declare function getRequestHeader(request: FrameworkRequest, name: string): string | string[] | undefined;
10
+ /**
11
+ * Reads one response header without flattening multi-value arrays.
12
+ *
13
+ * @param response Adapter-normalized response carrying the outbound headers map.
14
+ * @param name Header name to resolve case-insensitively.
15
+ * @returns The original scalar, array, or `undefined` stored on the response.
16
+ */
17
+ export declare function getResponseHeader(response: FrameworkResponse, name: string): string | string[] | undefined;
18
+ /**
19
+ * Checks whether one response header is present without mutating the response.
20
+ *
21
+ * @param response Adapter-normalized response carrying the outbound headers map.
22
+ * @param name Header name to resolve case-insensitively.
23
+ * @returns `true` when a matching response header has a value.
24
+ */
25
+ export declare function hasResponseHeader(response: FrameworkResponse, name: string): boolean;
26
+ /**
27
+ * Creates a portable Content-Disposition value with ASCII and UTF-8 filename parameters.
28
+ *
29
+ * @param disposition Whether the response is an `attachment` or rendered `inline`.
30
+ * @param filename Original filename to encode for a response header.
31
+ * @returns A Content-Disposition field value with escaped ASCII and RFC 8187 UTF-8 parameters.
32
+ * @throws {TypeError} When the disposition is unsupported or the filename contains CR or LF.
33
+ */
34
+ export declare function buildContentDisposition(disposition: 'attachment' | 'inline', filename: string): string;
35
+ /**
36
+ * Reads the first non-empty request header value across duplicate case variants.
37
+ *
38
+ * @param request Adapter-normalized request carrying the inbound headers map.
39
+ * @param name Header name to resolve case-insensitively.
40
+ * @returns The first trimmed scalar or joined array value that is not blank.
41
+ */
42
+ export declare function readFirstNonEmptyRequestHeaderValue(request: FrameworkRequest, name: string): string | undefined;
43
+ /**
44
+ * Reads and joins every non-empty request header field value in wire order.
45
+ *
46
+ * @param request Adapter-normalized request carrying the inbound headers map.
47
+ * @param name Header name to resolve case-insensitively.
48
+ * @returns Comma-delimited values from every matching field, or `undefined` when all are blank.
49
+ */
50
+ export declare function readJoinedNonEmptyRequestHeaderValues(request: FrameworkRequest, name: string): string | undefined;
51
+ /**
52
+ * Appends one or more fields to the response `Vary` header with case-insensitive deduplication.
53
+ *
54
+ * @param response Mutable framework response facade that owns the header map.
55
+ * @param fields Header field names or comma-delimited field lists to append.
56
+ * @returns Nothing. The helper updates the response header map in place when needed.
57
+ */
58
+ export declare function appendVaryHeader(response: FrameworkResponse, ...fields: string[]): void;
59
+ //# sourceMappingURL=header-helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"header-helpers.d.ts","sourceRoot":"","sources":["../src/header-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAmEtE;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,gBAAgB,EACzB,IAAI,EAAE,MAAM,GACX,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAE/B;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,iBAAiB,EAC3B,IAAI,EAAE,MAAM,GACX,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAE/B;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,iBAAiB,EAC3B,IAAI,EAAE,MAAM,GACX,OAAO,CAET;AAED;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CACrC,WAAW,EAAE,YAAY,GAAG,QAAQ,EACpC,QAAQ,EAAE,MAAM,GACf,MAAM,CAsCR;AAED;;;;;;GAMG;AACH,wBAAgB,mCAAmC,CACjD,OAAO,EAAE,gBAAgB,EACzB,IAAI,EAAE,MAAM,GACX,MAAM,GAAG,SAAS,CAmBpB;AAED;;;;;;GAMG;AACH,wBAAgB,qCAAqC,CACnD,OAAO,EAAE,gBAAgB,EACzB,IAAI,EAAE,MAAM,GACX,MAAM,GAAG,SAAS,CAqBpB;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,iBAAiB,EAC3B,GAAG,MAAM,EAAE,MAAM,EAAE,GAClB,IAAI,CA0CN"}