@nodefony/http 10.0.0-beta.5 → 10.0.0-beta.7

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 (130) hide show
  1. package/README.md +24 -0
  2. package/dist/_virtual/{_@oxc-project_runtime@0.155.0 → _@oxc-project_runtime@0.158.0}/helpers/esm/decorate.js +1 -1
  3. package/dist/_virtual/{_@oxc-project_runtime@0.155.0 → _@oxc-project_runtime@0.158.0}/helpers/esm/decorateParam.js +1 -1
  4. package/dist/index.js +30 -26
  5. package/dist/nodefony/command/proxyGenerateCommand.js +2 -2
  6. package/dist/nodefony/config/config.js +29 -4
  7. package/dist/nodefony/grpc/GrpcCall.js +298 -0
  8. package/dist/nodefony/grpc/GrpcEndpoint.js +528 -0
  9. package/dist/nodefony/grpc/index.js +4 -0
  10. package/dist/nodefony/interfaces/IRpcCall.js +1 -0
  11. package/dist/nodefony/service/ProfilerAdminApi.js +5 -2
  12. package/dist/nodefony/service/audit-logger.js +52 -6
  13. package/dist/nodefony/service/error-renderer.js +47 -13
  14. package/dist/nodefony/service/http-kernel.js +306 -49
  15. package/dist/nodefony/service/pretty-request-logger.js +5 -3
  16. package/dist/nodefony/service/request-logger.js +21 -6
  17. package/dist/nodefony/service/reverse-proxy.js +8 -3
  18. package/dist/nodefony/service/servers/clientError.js +53 -4
  19. package/dist/nodefony/service/servers/server-h2c.js +6 -6
  20. package/dist/nodefony/service/servers/server-http.js +6 -4
  21. package/dist/nodefony/service/servers/server-https.js +14 -7
  22. package/dist/nodefony/service/servers/server-static.js +1 -6
  23. package/dist/nodefony/service/servers/server-websocket-secure.js +7 -11
  24. package/dist/nodefony/service/servers/server-websocket.js +7 -11
  25. package/dist/nodefony/service/servers/serverShutdown.js +43 -6
  26. package/dist/nodefony/service/sessions/sessions-service.js +7 -7
  27. package/dist/nodefony/service/upload/upload-service.js +2 -2
  28. package/dist/nodefony/src/assets/prebuiltUi.js +23 -5
  29. package/dist/nodefony/src/context/Context.js +12 -1
  30. package/dist/nodefony/src/context/http/ByteStream.js +364 -0
  31. package/dist/nodefony/src/context/http/HttpContext.js +139 -32
  32. package/dist/nodefony/src/context/http/Request.js +111 -22
  33. package/dist/nodefony/src/context/http/Response.js +459 -37
  34. package/dist/nodefony/src/context/http/SseStream.js +83 -148
  35. package/dist/nodefony/src/context/http/StreamLifecycle.js +582 -0
  36. package/dist/nodefony/src/context/http/parser.js +29 -11
  37. package/dist/nodefony/src/context/http/urlFastPath.js +80 -1
  38. package/dist/nodefony/src/context/http/webResponse.js +56 -0
  39. package/dist/nodefony/src/context/http2/Request.js +1 -1
  40. package/dist/nodefony/src/context/http2/Response.js +55 -12
  41. package/dist/nodefony/src/context/requestTrace.js +6 -2
  42. package/dist/nodefony/src/context/rpcOutcome.js +20 -0
  43. package/dist/nodefony/src/context/transport.js +20 -1
  44. package/dist/nodefony/src/context/websocket/Response.js +15 -3
  45. package/dist/nodefony/src/context/websocket/WebsocketContext.js +86 -18
  46. package/dist/nodefony/src/context/websocket/websocketUrl.js +7 -0
  47. package/dist/nodefony/src/context/websocket/wsBackpressure.js +15 -15
  48. package/dist/nodefony/src/context/websocket/wsFrameRate.js +71 -0
  49. package/dist/nodefony/src/context/websocket/wsLogContent.js +55 -17
  50. package/dist/nodefony/src/cookies/cookie.js +57 -14
  51. package/dist/nodefony/src/errors/httpError.js +58 -25
  52. package/dist/nodefony/src/grpc/cors.js +59 -0
  53. package/dist/nodefony/src/grpc/limits.js +16 -0
  54. package/dist/nodefony/src/grpc/refusal.js +271 -0
  55. package/dist/nodefony/src/profiler/Profiler.js +14 -1
  56. package/dist/nodefony/src/profiler/aggregate.js +2 -2
  57. package/dist/nodefony/src/proxy/forward.js +109 -9
  58. package/dist/nodefony/src/proxy/generateProxyConfig.js +97 -17
  59. package/dist/nodefony/src/proxy/rules.js +29 -14
  60. package/dist/nodefony/src/servers/http2Goaway.js +76 -0
  61. package/dist/nodefony/src/servers/http2Limits.js +41 -15
  62. package/dist/nodefony/src/servers/http2StreamGrace.js +100 -0
  63. package/dist/nodefony/src/servers/receiveDeadline.js +177 -0
  64. package/dist/nodefony/src/servers/upgradeDispatch.js +62 -4
  65. package/dist/types/index.d.ts +11 -2
  66. package/dist/types/nodefony/config/config.d.ts +14 -0
  67. package/dist/types/nodefony/grpc/GrpcCall.d.ts +142 -0
  68. package/dist/types/nodefony/grpc/GrpcEndpoint.d.ts +98 -0
  69. package/dist/types/nodefony/grpc/index.d.ts +15 -0
  70. package/dist/types/nodefony/interfaces/IContext.d.ts +9 -0
  71. package/dist/types/nodefony/interfaces/IErrorRenderer.d.ts +14 -0
  72. package/dist/types/nodefony/interfaces/IRequest.d.ts +2 -1
  73. package/dist/types/nodefony/interfaces/IRequestTrace.d.ts +10 -0
  74. package/dist/types/nodefony/interfaces/IRouting.d.ts +19 -0
  75. package/dist/types/nodefony/interfaces/IRpcCall.d.ts +83 -0
  76. package/dist/types/nodefony/interfaces/ISecurity.d.ts +27 -2
  77. package/dist/types/nodefony/interfaces/IUpload.d.ts +51 -4
  78. package/dist/types/nodefony/interfaces/index.d.ts +2 -1
  79. package/dist/types/nodefony/service/ProfilerAdminApi.d.ts +2 -1
  80. package/dist/types/nodefony/service/audit-logger.d.ts +33 -3
  81. package/dist/types/nodefony/service/error-renderer.d.ts +27 -5
  82. package/dist/types/nodefony/service/http-kernel.d.ts +36 -3
  83. package/dist/types/nodefony/service/request-logger.d.ts +10 -0
  84. package/dist/types/nodefony/service/servers/clientError.d.ts +3 -2
  85. package/dist/types/nodefony/service/servers/serverShutdown.d.ts +7 -5
  86. package/dist/types/nodefony/src/assets/prebuiltUi.d.ts +9 -4
  87. package/dist/types/nodefony/src/context/Context.d.ts +9 -1
  88. package/dist/types/nodefony/src/context/http/ByteStream.d.ts +109 -0
  89. package/dist/types/nodefony/src/context/http/HttpContext.d.ts +99 -3
  90. package/dist/types/nodefony/src/context/http/Request.d.ts +46 -9
  91. package/dist/types/nodefony/src/context/http/Response.d.ts +188 -8
  92. package/dist/types/nodefony/src/context/http/SseStream.d.ts +33 -8
  93. package/dist/types/nodefony/src/context/http/StreamLifecycle.d.ts +106 -0
  94. package/dist/types/nodefony/src/context/http/parser.d.ts +17 -3
  95. package/dist/types/nodefony/src/context/http/urlFastPath.d.ts +40 -0
  96. package/dist/types/nodefony/src/context/http/webResponse.d.ts +31 -0
  97. package/dist/types/nodefony/src/context/http2/Response.d.ts +40 -5
  98. package/dist/types/nodefony/src/context/requestTrace.d.ts +3 -1
  99. package/dist/types/nodefony/src/context/rpcOutcome.d.ts +11 -0
  100. package/dist/types/nodefony/src/context/transport.d.ts +17 -0
  101. package/dist/types/nodefony/src/context/websocket/Response.d.ts +6 -1
  102. package/dist/types/nodefony/src/context/websocket/WebsocketContext.d.ts +48 -0
  103. package/dist/types/nodefony/src/context/websocket/websocketUrl.d.ts +4 -0
  104. package/dist/types/nodefony/src/context/websocket/wsBackpressure.d.ts +12 -2
  105. package/dist/types/nodefony/src/context/websocket/wsFrameRate.d.ts +69 -0
  106. package/dist/types/nodefony/src/context/websocket/wsLogContent.d.ts +16 -8
  107. package/dist/types/nodefony/src/cookies/cookie.d.ts +20 -2
  108. package/dist/types/nodefony/src/errors/httpError.d.ts +29 -4
  109. package/dist/types/nodefony/src/grpc/cors.d.ts +32 -0
  110. package/dist/types/nodefony/src/grpc/limits.d.ts +14 -0
  111. package/dist/types/nodefony/src/grpc/refusal.d.ts +136 -0
  112. package/dist/types/nodefony/src/profiler/Profiler.d.ts +11 -1
  113. package/dist/types/nodefony/src/proxy/forward.d.ts +37 -2
  114. package/dist/types/nodefony/src/proxy/generateProxyConfig.d.ts +15 -2
  115. package/dist/types/nodefony/src/proxy/rules.d.ts +20 -0
  116. package/dist/types/nodefony/src/servers/http2Goaway.d.ts +41 -0
  117. package/dist/types/nodefony/src/servers/http2Limits.d.ts +27 -14
  118. package/dist/types/nodefony/src/servers/http2StreamGrace.d.ts +34 -0
  119. package/dist/types/nodefony/src/servers/receiveDeadline.d.ts +77 -0
  120. package/dist/types/nodefony/src/servers/upgradeDispatch.d.ts +41 -1
  121. package/docs/byte-stream.md +406 -0
  122. package/docs/cookies.md +13 -3
  123. package/docs/diagnostics-channel.md +45 -1
  124. package/docs/index.md +8 -0
  125. package/docs/reverse-proxy.md +15 -3
  126. package/docs/servers.md +67 -43
  127. package/docs/session.md +3 -3
  128. package/docs/sse.md +27 -20
  129. package/docs/upload.md +43 -17
  130. package/package.json +38 -18
@@ -10,9 +10,20 @@ import { UploadedFile } from "../../../service/upload/upload-service.js";
10
10
  import type { IParsedUploadFile, IUploadOptions } from "../../../interfaces/IUpload.js";
11
11
  import { Pci, Pdu, Message, Severity, Msgid } from "nodefony";
12
12
  import Session from "../../session/session.js";
13
+ import HttpError from "../../errors/httpError.js";
13
14
  import { type ResolvedProxy } from "../forwarded.js";
14
15
  declare class BodyHandled {
15
16
  }
17
+ /**
18
+ * Une réception multipart EN COURS, interruptible de l'extérieur : `fail` rompt
19
+ * la lecture comme le ferait un dépassement de limite (temporaires nettoyés).
20
+ * Posée dans `request.parser` le temps de la lecture seulement — l'allocation
21
+ * est réservée au multipart, déjà lourd.
22
+ */
23
+ declare class MultipartReception {
24
+ readonly fail: (error: HttpError) => boolean;
25
+ constructor(fail: (error: HttpError) => boolean);
26
+ }
16
27
  declare module "url" {
17
28
  interface URL {
18
29
  query: QS.ParsedQs;
@@ -31,7 +42,7 @@ declare module "http2" {
31
42
  session: Session;
32
43
  }
33
44
  }
34
- type ParserType = ParserXml | ParserQs | Parser | BodyHandled;
45
+ type ParserType = ParserXml | ParserQs | Parser | BodyHandled | MultipartReception;
35
46
  declare class HttpRequest {
36
47
  #private;
37
48
  context: HttpContext;
@@ -88,6 +99,9 @@ declare class HttpRequest {
88
99
  * temporaire — lus par `@UploadedFile()` / `@UploadedFiles()`. Les champs
89
100
  * texte du même corps sont dans {@link body}.
90
101
  *
102
+ * Ces temporaires sont EFFACÉS à la fin de la requête : pour garder un
103
+ * fichier, l'action le déplace (`moveAsync`) avant de répondre.
104
+ *
91
105
  * Lecture seule : une requête sans upload rend un vide partagé et gelé,
92
106
  * aucune allocation.
93
107
  */
@@ -150,6 +164,16 @@ declare class HttpRequest {
150
164
  * @returns `undefined` quand tout est fait, sinon la promesse à attendre.
151
165
  */
152
166
  private endWithoutBody;
167
+ /**
168
+ * Lit le plafond du corps et les limites d'envoi tels que les voit CETTE
169
+ * requête : la configuration http, surchargée par le calque que la requête a
170
+ * pu poser avant la lecture du corps (`overlayConfig`, #494), puis par les
171
+ * bornes que la route déclare pour elle-même (option de route `upload`). La
172
+ * route est déjà résolue à ce moment : une route sans bornes propres
173
+ * n'alloue rien. Hors pipeline (aucun scope ouvert), la configuration du
174
+ * module telle quelle.
175
+ */
176
+ private readBodyLimits;
153
177
  /**
154
178
  * B1 — Pré-contrôle de taille du corps via l'en-tête `Content-Length` :
155
179
  * rejette en 413 (RFC 9110 §15.5.14 « Content Too Large ») AVANT toute lecture
@@ -159,13 +183,6 @@ declare class HttpRequest {
159
183
  *
160
184
  * @throws {HttpError} 413 si `Content-Length` dépasse `maxBodySize`.
161
185
  */
162
- /**
163
- * Lit le plafond du corps et les limites d'envoi tels que les voit CETTE
164
- * requête : la configuration http, surchargée par le calque que la requête a
165
- * pu poser avant la lecture du corps (`overlayConfig`, #494). Hors pipeline
166
- * (aucun scope ouvert), la configuration du module telle quelle.
167
- */
168
- private readBodyLimits;
169
186
  private enforceBodyLimit;
170
187
  parseRequest(): Promise<ParserType | null>;
171
188
  /**
@@ -200,6 +217,19 @@ declare class HttpRequest {
200
217
  * déjà posés — à la moindre erreur ou dépassement de limite.
201
218
  */
202
219
  private streamMultipart;
220
+ /**
221
+ * Interrompt la réception du corps en cours : la promesse de `initialize()`
222
+ * rejette avec `error`, rendue par le chemin d'erreur habituel — comme un
223
+ * corps qui dépasse sa limite (413).
224
+ *
225
+ * Sert le délai de réception HTTP/2 (`requestTimeout`), que `node:http2` ne
226
+ * borne pas. Sans effet hors réception : corps déjà reçu, lu en flux par
227
+ * l'action (`bodyStream`), ou méthode sans corps.
228
+ *
229
+ * @param error - la cause rendue au client (408 au délai dépassé)
230
+ * @returns vrai si une réception en cours a été interrompue
231
+ */
232
+ abortBody(error: HttpError): boolean;
203
233
  /**
204
234
  * Accumule un champ texte multipart. `foo[]` (ou répétition de `foo`) →
205
235
  * tableau ; sinon valeur scalaire. (Anciennement délégué à formidable.)
@@ -220,12 +250,19 @@ declare class HttpRequest {
220
250
  getDomain(): string;
221
251
  getUserAgent(): string | undefined;
222
252
  getHostName(host?: string): string;
253
+ /**
254
+ * L'autorité de la requête : celle de la cible en forme absolue, sinon
255
+ * l'en-tête `Host` (RFC 9112 §3.2.2 — le serveur DOIT alors ignorer `Host`).
256
+ * HTTP/2 lit `:authority` (override).
257
+ */
223
258
  getHost(): string | undefined;
224
259
  getRemoteAddress(): string | null;
225
260
  /**
226
261
  * Request-target brut (origin-form) tel que reçu du transport — SOURCE
227
262
  * UNIQUE partagée par la concaténation de {@link getFullUrl} et la découpe
228
- * fast-path du ctor. HTTP/2 lit le pseudo-header `:path` (override).
263
+ * fast-path du ctor. Une cible en forme absolue est ramenée à sa forme
264
+ * origine, son autorité passant par {@link getHost}. HTTP/2 lit le
265
+ * pseudo-header `:path` (override).
229
266
  */
230
267
  getRawTarget(): string | undefined;
231
268
  /**
@@ -1,9 +1,35 @@
1
- import http, { OutgoingHttpHeaders } from "node:http";
1
+ import http, { OutgoingHttpHeaders, OutgoingHttpHeader } from "node:http";
2
2
  import http2 from "node:http2";
3
3
  import HttpContext from "../http/HttpContext.js";
4
4
  import { Pci, Pdu, Message, Severity, Msgid } from "nodefony";
5
5
  import type { MaybePromise } from "nodefony";
6
6
  import Cookie from "../../cookies/cookie.js";
7
+ import type { IFirewallGate } from "../../../interfaces/ISecurity.js";
8
+ /**
9
+ * Plafond, en octets, d'un corps de requête HTTP/1.1 non lu que le serveur
10
+ * accepte de vider pour garder la connexion réutilisable — 256 Kio, le geste du
11
+ * serveur HTTP de Go que Connect reprend (ADR-0026, D5). Au-delà, la réponse
12
+ * ferme la connexion.
13
+ */
14
+ export declare const UNREAD_BODY_DRAIN_LIMIT: number;
15
+ /**
16
+ * Silence, en millisecondes, au bout duquel une connexion HTTP/1.1 fermée sur
17
+ * un corps non lu est détruite — 5 s, le `lingering_timeout` par défaut de
18
+ * nginx. La durée TOTALE reste bornée par le délai de réception de Node
19
+ * (`requestTimeout`), qui court tant que le corps n'est pas fini.
20
+ */
21
+ export declare const UNREAD_BODY_LINGER_MS = 5000;
22
+ /**
23
+ * Vrai pour un statut dont la réponse n'a, par définition, aucun contenu —
24
+ * 204, 205 et 304 (RFC 9110 §15.3.5, §15.3.6, §15.4.5).
25
+ *
26
+ * Seule source de cette liste : la réponse s'en sert pour ne jamais écrire de
27
+ * corps, le résolveur pour terminer une action qui ne rend rien.
28
+ *
29
+ * @param status - le code de statut de la réponse.
30
+ * @returns `true` quand aucun corps ne doit partir.
31
+ */
32
+ export declare function isContentlessStatus(status: number): boolean;
7
33
  declare class HttpResponse {
8
34
  #private;
9
35
  context: HttpContext;
@@ -16,6 +42,13 @@ declare class HttpResponse {
16
42
  headers: http.OutgoingHttpHeaders;
17
43
  timeout?: number | undefined;
18
44
  cookies: Record<string, Cookie>;
45
+ /**
46
+ * Pare-feu qui posera les en-têtes de sécurité applicatifs juste avant
47
+ * l'émission des en-têtes, une fois le type de la réponse fixé : la politique
48
+ * suit ce type (ADR-0024 §C11). Armé par le noyau HTTP au routage, consommé
49
+ * une fois ; `null` sans module de sécurité.
50
+ */
51
+ headerPolicy: IFirewallGate | null;
19
52
  constructor(response: http.ServerResponse | http2.Http2ServerResponse, context: HttpContext);
20
53
  /**
21
54
  * Filet posé juste avant l'émission des en-têtes : si aucun `Content-Type`
@@ -36,7 +69,9 @@ declare class HttpResponse {
36
69
  /**
37
70
  * Corps tel qu'il part sur le fil : le texte s'il n'a jamais été encodé, sinon
38
71
  * les octets — vide légal si rien n'a été posé (`write(null)` jetterait
39
- * ERR_STREAM_NULL_VALUES).
72
+ * ERR_STREAM_NULL_VALUES). Vide aussi sous un statut sans contenu : un corps
73
+ * posé par l'application sous un 205 ne part pas (RFC 9110 §15.3.6) — Node
74
+ * ne l'écarte de lui-même que pour 204 et 304.
40
75
  */
41
76
  protected get payload(): string | Buffer;
42
77
  /** Encodage à passer avec {@link payload} (ignoré par Node pour des octets). */
@@ -48,8 +83,8 @@ declare class HttpResponse {
48
83
  addCookie(cookie: Cookie): Cookie;
49
84
  deleteCookie(cookie: Cookie): boolean;
50
85
  deleteCookieByName(name: string): boolean;
51
- setCookies(): void | http.ServerResponse<http.IncomingMessage>;
52
- setCookie(cookie: Cookie): void | http.ServerResponse<http.IncomingMessage>;
86
+ setCookies(): void;
87
+ setCookie(cookie: Cookie): void;
53
88
  /**
54
89
  * Journalise en DEBUG un cookie posé, sa VALEUR MASQUÉE : nom et attributs
55
90
  * seulement. Le journal de développement se lit par le plan d'administration
@@ -61,11 +96,110 @@ declare class HttpResponse {
61
96
  * @param serialized - sa forme `Set-Cookie`, déjà calculée pour l'en-tête.
62
97
  */
63
98
  private logCookie;
64
- setHeader(name: string, value: number | string | readonly string[]): void | http.ServerResponse<http.IncomingMessage>;
99
+ /**
100
+ * Pose un en-tête de la réponse ; en flux chunké déjà ouvert, le range en
101
+ * trailer. Le nom et la valeur sont VALIDÉS ici, comme le ferait Node : une
102
+ * valeur invalide (saut de ligne…) lève tout de suite et n'entre jamais dans
103
+ * la réserve — sinon elle lèverait au `writeHead`, et la page d'erreur
104
+ * rejouerait le même en-tête.
105
+ *
106
+ * @param name - nom de l'en-tête (casse indifférente).
107
+ * @param value - valeur ; une liste émet une ligne par élément (`Set-Cookie`).
108
+ * @throws TypeError `ERR_INVALID_HTTP_TOKEN` / `ERR_INVALID_CHAR` sur un nom
109
+ * ou une valeur qu'un en-tête HTTP ne peut pas porter.
110
+ */
111
+ setHeader(name: string, value: number | string | readonly string[]): void;
112
+ /**
113
+ * Pose un en-tête dont la valeur a DÉJÀ été validée par l'appelant — une
114
+ * table figée et contrôlée au démarrage (en-têtes de sécurité). Node la
115
+ * validera une fois, au `writeHead` ; la revalider ici effaçait le gain de
116
+ * l'écriture groupée (`micro-write-head.mjs`, ligne « plat validé »).
117
+ *
118
+ * ⚠️ Jamais pour une valeur venue d'une requête : elle passe par {@link setHeader}.
119
+ *
120
+ * @param name - nom de l'en-tête (casse indifférente).
121
+ * @param value - valeur contrôlée au démarrage.
122
+ */
123
+ setValidatedHeader(name: string, value: string): void;
124
+ /**
125
+ * Pose un en-tête validé au démarrage SAUF si la réponse en porte déjà un :
126
+ * la valeur du framework est un défaut, celle que l'application a écrite
127
+ * gagne. Même coût que {@link setValidatedHeader} — le rangement cherche
128
+ * l'en-tête de toute façon.
129
+ *
130
+ * @param name - nom de l'en-tête (casse indifférente).
131
+ * @param value - valeur contrôlée au démarrage.
132
+ */
133
+ setDefaultHeader(name: string, value: string): void;
134
+ /**
135
+ * Pose les en-têtes de la politique armée ({@link headerPolicy}) pour une
136
+ * réponse de type `contentType` — une fois, juste avant l'émission.
137
+ *
138
+ * Un `304` n'en reçoit aucun : ses en-têtes REMPLACENT ceux de la
139
+ * représentation en cache (RFC 9111 §4.3.4). Une politique courte y
140
+ * réduirait la page gardée, un nonce neuf la désaccorderait de ses balises.
141
+ *
142
+ * @param contentType - type de la réponse ; `null` = sans contenu ; `undefined`
143
+ * = inconnu (politique complète).
144
+ * @param servedAsFile - corps écrit par un tiers (fichier statique, relais),
145
+ * qui ne peut pas porter de nonce.
146
+ */
147
+ protected applyHeaderPolicy(contentType: string | null | undefined, servedAsFile?: boolean): void;
148
+ /**
149
+ * Type qui choisit la politique : `null` pour une réponse sans contenu (204,
150
+ * corps vide) — même si un `Content-Type` y a été posé, rien n'y sera rendu ;
151
+ * sinon le `Content-Type` posé.
152
+ */
153
+ protected contentTypeForPolicy(): string | null;
154
+ /**
155
+ * Range les en-têtes de corrélation du contexte — `X-Request-Id` et le
156
+ * `traceparent` W3C — que toute réponse renvoie, quel qu'en soit l'émetteur.
157
+ * Validés par Node à la remise, comme le reste de la réserve.
158
+ */
159
+ protected putCorrelationHeaders(): void;
160
+ /**
161
+ * Recopie la réserve sur la réponse Node, pour un émetteur qui écrit sans
162
+ * passer par {@link writeHead} — fichier statique, relais vers un amont,
163
+ * adaptateur RPC. La réserve se vide ; ce qui se pose ensuite y retourne, et
164
+ * Node fusionne les deux au `writeHead` (l'émetteur l'emporte, nom par nom).
165
+ *
166
+ * @param contentType - type de la réponse que l'émetteur écrira, quand il
167
+ * est connu d'avance (adaptateur RPC). Omis : il se lit à l'extension du
168
+ * chemin, comme le serveur statique le fera.
169
+ */
170
+ commitHeaders(contentType?: string): void;
171
+ /**
172
+ * Recopie la réserve sur la réponse Node au PREMIER `setHeader` qu'un tiers
173
+ * y fera — fichier statique servi, redirection de dossier — et seulement
174
+ * alors : un raté du repli statique (la 404 d'une route inconnue) ne recopie
175
+ * rien, sa réponse part ensuite en un seul `writeHead`. À désarmer par
176
+ * {@link disarmNativeWrite} quand le tiers rend la main sans avoir écrit.
177
+ *
178
+ * L'interception est une propriété PROPRE de la réponse, posée une fois avec
179
+ * des attributs constants — toutes les réponses interceptées partagent donc
180
+ * la même forme — et désarmée en lui RÉAFFECTANT la méthode native, jamais
181
+ * en la supprimant : un `delete` fait basculer la réponse Node en mode
182
+ * dictionnaire (constaté par `%HasFastProperties` sur Node 26, 200 réponses
183
+ * sur 200), et chaque accès suivant de `node:http` le paie — mesuré in situ
184
+ * sur un 404 : `writeHead` +1,1 µs, `end` +4,3 µs.
185
+ */
186
+ commitBeforeNativeWrite(): void;
187
+ /**
188
+ * Retire l'interception posée par {@link commitBeforeNativeWrite} : la
189
+ * propriété propre reçoit la méthode native — la forme de l'objet ne change
190
+ * pas, la réponse reste en mode rapide pour V8.
191
+ */
192
+ disarmNativeWrite(): void;
193
+ /**
194
+ * Retire un en-tête, de la réserve comme de la réponse Node.
195
+ *
196
+ * @param name - nom de l'en-tête (casse indifférente).
197
+ */
198
+ removeHeader(name: string): void;
65
199
  setHeaders(obj: OutgoingHttpHeaders): OutgoingHttpHeaders;
66
- setContentType(type?: string, encoding?: BufferEncoding): void | http.ServerResponse<http.IncomingMessage>;
67
- setFileMimeType(type: string, encoding?: BufferEncoding): void | http.ServerResponse<http.IncomingMessage>;
68
- setContentTypeByExtension(extention: string): void | http.ServerResponse<http.IncomingMessage>;
200
+ setContentType(type?: string, encoding?: BufferEncoding): void;
201
+ setFileMimeType(type: string, encoding?: BufferEncoding): void;
202
+ setContentTypeByExtension(extention: string): void;
69
203
  getMimeType(filenameOrExt: string): string | false;
70
204
  setEncoding(encoding: BufferEncoding): BufferEncoding;
71
205
  setStatusCode(status: number | string, message?: string): {
@@ -88,7 +222,25 @@ declare class HttpResponse {
88
222
  setBody(ele: unknown, encoding?: BufferEncoding): void;
89
223
  setLength(body?: string | NodeJS.ArrayBufferView | ArrayBuffer | SharedArrayBuffer): number;
90
224
  writeHead(statusCode?: number, headers?: http.OutgoingHttpHeaders | http.OutgoingHttpHeader[]): void;
225
+ /** La réserve amorcée — pour une remise sous une autre forme (HTTP/2). */
226
+ protected headerList(): readonly OutgoingHttpHeader[];
91
227
  addTrailers(headers: http.OutgoingHttpHeaders): void;
228
+ /**
229
+ * Écrit un morceau d'une réponse en flux, sans la terminer — c'est `end()`
230
+ * qui la clôt après le dernier.
231
+ *
232
+ * Au premier morceau, les en-têtes partent SANS longueur ni corps posé (le
233
+ * patron de `SseStream`), et le cadrage revient à Node : `chunked` pour un
234
+ * client HTTP/1.1, fermeture de connexion pour un HTTP/1.0 (RFC 9112 §6.1 —
235
+ * pas de `Transfer-Encoding` à qui ne le connaît pas), trames DATA en HTTP/2
236
+ * où l'en-tête est interdit (RFC 9113 §8.2.2). Ne JAMAIS le poser à la main :
237
+ * une fois `flushing` levé, `setHeader` range en trailer, et un
238
+ * `Transfer-Encoding` en trailer est un message malformé (RFC 9110 §6.5.1).
239
+ *
240
+ * @param chunk - le morceau à écrire.
241
+ * @param encoding - l'encodage d'un morceau texte.
242
+ * @returns la promesse réglée quand le flux accepte l'écriture suivante.
243
+ */
92
244
  flush(chunk: unknown, encoding: BufferEncoding): MaybePromise<HttpResponse>;
93
245
  /**
94
246
  * Écrit le corps sur le flux et, pour une réponse unique, la termine.
@@ -113,8 +265,36 @@ declare class HttpResponse {
113
265
  * @throws de façon SYNCHRONE quand la réponse Node n'existe plus.
114
266
  */
115
267
  end(chunk?: string | Buffer, encoding?: BufferEncoding): MaybePromise<http.ServerResponse | http2.ServerHttp2Stream>;
268
+ /**
269
+ * Règle le sort d'un corps de requête resté NON LU au moment de répondre —
270
+ * route inconnue (404, 405), refus avant l'action, 408, 413. À appeler AVANT
271
+ * l'écriture des en-têtes ; sans effet si le corps est entièrement reçu.
272
+ *
273
+ * HTTP/1.1 : Node vide lui-même un corps non consommé une fois la réponse
274
+ * écrite, pour réutiliser la connexion — sans borne. On ne le laisse faire
275
+ * que pour un corps DÉCLARÉ d'au plus {@link UNREAD_BODY_DRAIN_LIMIT}
276
+ * octets ; au-delà, ou sans longueur déclarée (`transfer-encoding`), la
277
+ * réponse part avec `connection: close` (RFC 9112 §9.6) et la connexion
278
+ * n'est pas réutilisée — fermée par étapes ({@link lingerBeforeClose}),
279
+ * pour que le client qui écrit encore lise la réponse. La décision se prend
280
+ * sur la longueur ANNONCÉE, sans attendre un octet : la réponse n'est jamais
281
+ * retardée par le corps.
282
+ *
283
+ * HTTP/2 surcharge cette méthode (`Http2Response`) : fermeture du flux en
284
+ * `NO_ERROR` une fois la réponse écrite. Une seule entrée pour les deux
285
+ * protocoles, partagée par tout refus qui laisse un corps non lu (ADR-0026,
286
+ * D5).
287
+ */
288
+ closeUnfinishedRequest(): void;
289
+ /**
290
+ * Valeur d'un en-tête posé — dans la réserve, sinon sur la réponse Node (ce
291
+ * qu'un tiers y a écrit directement : `send`, quota).
292
+ *
293
+ * @param name - nom de l'en-tête (casse indifférente).
294
+ */
116
295
  getHeader(name: string): string | number | string[] | undefined;
117
296
  hasHeader(name: string): boolean;
297
+ /** Tous les en-têtes posés, noms en minuscules — une copie, à chaque appel. */
118
298
  getHeaders(): http.OutgoingHttpHeaders;
119
299
  redirect(url: string, status?: number | string, headers?: Record<string, string | number>): this;
120
300
  log(pci: Pci, severity?: Severity, msgid?: Msgid, msg?: Message): Pdu;
@@ -1,4 +1,5 @@
1
1
  import type HttpContext from "./HttpContext.js";
2
+ import type { DefaultEventsMap, EventNames, EventsMap } from "nodefony";
2
3
  /**
3
4
  * Le flux d'événements serveur (SSE) d'une réponse HTTP — `text/event-stream`.
4
5
  *
@@ -56,27 +57,49 @@ export interface ISseStreamOptions {
56
57
  */
57
58
  maxDuration?: number | false | undefined;
58
59
  }
59
- /** Ce qu'un événement porte en plus de ses données. */
60
- export interface ISseSendOptions {
60
+ /**
61
+ * Ce qu'un événement porte en plus de ses données.
62
+ *
63
+ * @typeParam K - nom de l'événement : un canal du contrat quand le flux en a un.
64
+ */
65
+ export interface ISseSendOptions<K extends string = string> {
61
66
  /** Type de l'événement (champ `event:`) — absent : `message`. */
62
- event?: string | undefined;
67
+ event?: K | undefined;
63
68
  /** Identifiant (champ `id:`) que le client renverra en `Last-Event-ID`. */
64
69
  id?: string | undefined;
65
70
  }
66
71
  /** Battement de cœur par défaut, en ms (§9.2.7 : « every 15 seconds or so »). */
67
72
  export declare const SSE_HEARTBEAT_MS = 15000;
68
- /** Délai de blocage d'écriture par défaut, en ms. */
73
+ /** Délai de blocage d'écriture par défaut, en ms — celui de tout flux. */
69
74
  export declare const SSE_STALL_TIMEOUT_MS = 30000;
70
75
  /** Taille maximale d'un événement par défaut, en octets (1 Mio). */
71
76
  export declare const SSE_MAX_EVENT_BYTES = 1048576;
77
+ /**
78
+ * Charge d'un événement SSE : celle du canal nommé par `event`, ou — sans
79
+ * `event` (« un flux = un canal ») — l'une de celles de la carte. Carte non
80
+ * déclarée : `unknown`.
81
+ */
82
+ export type SseEventData<Events extends EventsMap, K extends string> = [
83
+ K
84
+ ] extends [never] ? Events[EventNames<Events>] : Events[K];
72
85
  /**
73
86
  * Un flux `text/event-stream` ouvert sur une réponse.
74
87
  *
75
88
  * Il s'obtient par {@link openSseStream} (ou `this.renderSse()` dans un
76
89
  * contrôleur), jamais par `new` : l'ouverture écrit les en-têtes, et un flux
77
90
  * sans en-têtes ne se rattrape pas.
91
+ *
92
+ * Typé par une carte d'événements (`ContractServerEmit<C>` : le MÊME contrat
93
+ * que la socket temps réel) : `event:` est un canal de la carte et la charge est
94
+ * celle du canal. Deux formes se lisent sur la même carte — **multiplexé**
95
+ * (`send(data, { event: canal })`, plusieurs canaux sur une connexion) ou **un
96
+ * flux = un canal** (carte d'un seul canal, `send(data)` sans `event`). Sans
97
+ * carte, le flux reste libre (porte MCP, flux hors contrat). Le type n'est pas
98
+ * une validation, et ne coûte rien à l'exécution.
99
+ *
100
+ * @typeParam Events - carte des événements du flux.
78
101
  */
79
- export declare class SseStream {
102
+ export declare class SseStream<Events extends EventsMap = DefaultEventsMap> {
80
103
  #private;
81
104
  /** Le flux est-il fermé — par le serveur (`close()`) ou par le client parti ? */
82
105
  get closed(): boolean;
@@ -89,10 +112,12 @@ export declare class SseStream {
89
112
  * @returns rien quand l'écriture est acceptée ; une promesse réglée au
90
113
  * `drain` quand le client lit moins vite qu'on écrit — l'attendre borne la
91
114
  * mémoire du serveur. Sans effet une fois le flux fermé.
92
- * @throws TypeError quand `event` ou `id` contient une fin de ligne.
115
+ * @throws TypeError quand `event` ou `id` contient une fin de ligne, ou
116
+ * quand `data` est fait d'octets (`Uint8Array`, `Buffer`, `ArrayBuffer`) :
117
+ * un flux SSE ne porte que du texte, les encoder soi-même (base64).
93
118
  * @throws RangeError quand l'événement dépasse `maxEventBytes`.
94
119
  */
95
- send(data: unknown, options?: ISseSendOptions): Promise<void> | undefined;
120
+ send<K extends EventNames<Events> = never>(data: SseEventData<Events, K>, options?: ISseSendOptions<K>): Promise<void> | undefined;
96
121
  /**
97
122
  * Envoie un commentaire — ignoré par le client, utile pour garder une
98
123
  * connexion vivante ou marquer le flux à la lecture.
@@ -152,4 +177,4 @@ export declare function acceptsEventStream(accept: string | string[] | undefined
152
177
  * @throws RangeError quand un délai n'est ni `false` ni un entier entre 1 et
153
178
  * 2^31-1, ou que `maxEventBytes` n'est pas un entier positif.
154
179
  */
155
- export declare function openSseStream(context: HttpContext, options?: ISseStreamOptions): SseStream | Promise<SseStream>;
180
+ export declare function openSseStream<Events extends EventsMap = DefaultEventsMap>(context: HttpContext, options?: ISseStreamOptions): SseStream<Events> | Promise<SseStream<Events>>;
@@ -0,0 +1,106 @@
1
+ import http from "node:http";
2
+ import type http2 from "node:http2";
3
+ /**
4
+ * Cycle de vie d'une réponse en flux — la brique commune au flux d'événements
5
+ * (`SseStream`) et au flux d'octets, NON exportée.
6
+ *
7
+ * Elle porte ce qu'un flux doit à la requête qui l'ouvre, quel que soit son
8
+ * format :
9
+ * - la PRISE de la réponse (`sended`), avant toute attente : le noyau ne peut
10
+ * plus répondre par-dessus, et l'avertissement « réponse non envoyée » se tait ;
11
+ * - la session sauvée AVANT les en-têtes — ses cookies partent avec eux ;
12
+ * - la fermeture lue sur la RÉPONSE, écouteur posé de façon SYNCHRONE à
13
+ * l'ouverture : un client parti pendant la sauvegarde de la session est vu ;
14
+ * - le délai d'inactivité de la requête désarmé, remplacé par les gardes du
15
+ * flux : coupure d'un client qui ne lit plus (`stallTimeout`), durée de vie
16
+ * maximale (`maxDuration`) ;
17
+ * - le plafond de connexions longues par IP (`wsMaxConnectionsPerIp`, le budget
18
+ * des sockets WebSocket) et la fermeture à la révocation de l'identité ;
19
+ * - une fin unique, et des écouteurs de fin liés au contexte asynchrone.
20
+ *
21
+ * Le FORMAT (en-têtes, écriture, battement de cœur) appartient au flux qui la
22
+ * porte.
23
+ */
24
+ /**
25
+ * Plus long délai qu'un minuteur sait tenir (2^31-1 ms). Au-delà, Node le
26
+ * ramène à 1 ms : un délai qui le dépasse ferait battre ou couper le flux
27
+ * mille fois par seconde.
28
+ */
29
+ export declare const MAX_TIMER_MS = 2147483647;
30
+ /**
31
+ * Délai de blocage par défaut d'un flux, en ms : un client qui ne lit plus
32
+ * depuis ce délai est coupé. Valeur commune aux flux d'événements, d'octets et
33
+ * aux flux RPC.
34
+ */
35
+ export declare const STREAM_STALL_TIMEOUT_MS = 30000;
36
+ /**
37
+ * Période du balayage de blocage ({@link StallSweep}) : la moitié du délai de
38
+ * blocage. Un client bloqué est coupé entre `stallTimeout` et
39
+ * `stallTimeout + période` après la première contre-pression vue — jamais
40
+ * avant le délai réglé.
41
+ */
42
+ export declare const STALL_SWEEP_PERIOD_MS: number;
43
+ /**
44
+ * Attente maximale, à l'arrêt du serveur, des flux longs qu'on vient de
45
+ * terminer (`HttpKernel.shutdownStreams`), avant le drain des connexions.
46
+ *
47
+ * Un flux qui écoute son signal se ferme en quelques millisecondes : l'attente
48
+ * finit avec lui. Elle ne dure jusqu'à son terme que pour un gestionnaire qui
49
+ * n'écoute rien — et ce temps s'AJOUTE au drain (`shutdownTimeout`), d'où une
50
+ * borne courte, celle de l'annonce du GOAWAY.
51
+ */
52
+ export declare const SHUTDOWN_STREAMS_WAIT_MS = 1000;
53
+ /**
54
+ * Qui a fermé le flux, quand ce n'est pas le client : le serveur (`close()` —
55
+ * fin demandée, durée de vie, révocation), ou la coupure d'un client qui ne lit
56
+ * plus. `null` : le client est parti, ou le flux est encore ouvert.
57
+ */
58
+ export type StreamLifecycleCause = "server" | "stall" | null;
59
+ /** Ce sur quoi on écrit : la réponse HTTP/1.1, ou le flux HTTP/2. */
60
+ export type StreamTarget = http.ServerResponse | http2.ServerHttp2Stream;
61
+ /** Gardes et identité d'un flux, options résolues. */
62
+ export interface IStreamLifecycleSettings {
63
+ stallTimeout: number | false;
64
+ maxDuration: number | false;
65
+ /** Revalidateur de l'identité du flux — `null` pour un anonyme. */
66
+ revalidate: (() => Promise<boolean>) | null;
67
+ /** Identifiant de connexion de l'identité qui ouvre le flux — `null` anonyme. */
68
+ identifier: string | null;
69
+ /**
70
+ * Les écritures appartiennent à un tiers (adaptateur RPC) : la brique ne les
71
+ * voit pas. Le blocage s'observe alors par le balayage du noyau
72
+ * ({@link StallSweep}), et la fermeture par le serveur détruit le transport
73
+ * au lieu de terminer la réponse — jamais un second écrivain.
74
+ */
75
+ foreignWriter: boolean;
76
+ /**
77
+ * Le flux n'a pas de fin à lui (SSE, flux RPC, sortie d'un processus) : à
78
+ * l'arrêt du serveur, le noyau le termine AVANT le drain des connexions
79
+ * ({@link StreamLifecycle.shutdown}), au lieu de le laisser détruire sans un
80
+ * mot à `shutdownTimeout`. `false` pour une source FINIE (une archive) : elle
81
+ * a le drain pour finir, comme toute réponse en vol.
82
+ */
83
+ endsAtShutdown: boolean;
84
+ }
85
+ /** Ce que l'ouverture reçoit de l'appelant. */
86
+ export interface IOpenStreamLifecycle {
87
+ /** Préfixe des messages d'erreur (`SSE`, `Flux`). */
88
+ label: string;
89
+ stallTimeout: number | false;
90
+ maxDuration: number | false;
91
+ /**
92
+ * Un tiers tient les écritures (adaptateur RPC) — cf
93
+ * {@link IStreamLifecycleSettings.foreignWriter}. Défaut `false`.
94
+ */
95
+ foreignWriter?: boolean;
96
+ /**
97
+ * Terminé par le noyau à l'arrêt du serveur — cf
98
+ * {@link IStreamLifecycleSettings.endsAtShutdown}. Défaut `true`.
99
+ */
100
+ endsAtShutdown?: boolean;
101
+ }
102
+ /** Ce que le registre de l'arrêt retient d'un flux : de quoi le terminer. */
103
+ export interface IShutdownStream {
104
+ /** Le serveur s'arrête : le flux prend fin (cf {@link StreamLifecycle.shutdown}). */
105
+ shutdown(): unknown;
106
+ }
@@ -2,22 +2,36 @@ import HttpRequest from "./Request.js";
2
2
  import Http2Request from "../http2/Request.js";
3
3
  import QS from "qs";
4
4
  import xml2js from "xml2js";
5
+ import HttpError from "../../errors/httpError.js";
5
6
  declare class Parser {
6
7
  request: HttpRequest | Http2Request;
7
8
  chunks: Buffer[];
8
9
  private received;
9
10
  private aborted;
10
- private overflow;
11
- private onOverflow;
11
+ private failure;
12
+ private onFailure;
12
13
  constructor(request: HttpRequest | Http2Request);
13
14
  write(buffer: Buffer): Buffer;
15
+ /**
16
+ * Interrompt la réception du corps : `parse()` rejette avec `error`, que
17
+ * l'interruption survienne avant ou pendant l'attente de la fin du flux.
18
+ *
19
+ * La RAM déjà bufferisée est libérée et la lecture du flux suspendue ; la
20
+ * réponse d'erreur peut encore partir. Sans effet si le corps est déjà
21
+ * entièrement reçu, ou déjà interrompu.
22
+ *
23
+ * @param error - la cause rendue au client (413 dépassement, 408 délai)
24
+ * @returns vrai si la réception a été interrompue
25
+ */
26
+ fail(error: HttpError): boolean;
14
27
  /**
15
28
  * Résout quand le flux requête est **entièrement reçu** (`end`). No-op si déjà
16
29
  * terminé (corps vide / déjà drainé) → pas de hang d'un `once("end")` tardif.
17
30
  * Indispensable avant de concaténer les chunks pour un corps à décoder
18
31
  * (JSON…) : sinon on lit un buffer encore incomplet. (formidable drainait via
19
32
  * son `await form.parse()` ; ses remplaçants doivent drainer explicitement.)
20
- * Rejette en 413 si le corps dépasse `maxBodySize` (avant ou pendant l'attente).
33
+ * Rejette avec la cause de {@link Parser.fail} (413 dépassement de
34
+ * `maxBodySize`, 408 délai de réception), avant ou pendant l'attente.
21
35
  */
22
36
  protected ended(): Promise<void>;
23
37
  parse(): Promise<this>;
@@ -36,6 +36,46 @@ export interface ISplitTarget {
36
36
  * @returns les composants découpés, ou `null` (bail-out → vrai `new URL`).
37
37
  */
38
38
  export declare function splitTarget(target: unknown): ISplitTarget | null;
39
+ /** Un request-target en forme absolue, découpé en autorité et forme origine. */
40
+ export interface IAbsoluteTarget {
41
+ /** `hôte[:port]` de la cible — l'hôte de la requête (RFC 9112 §3.2.2). */
42
+ authority: string;
43
+ /** La forme origine (`/chemin[?query]`), `/` quand la cible n'a pas de chemin. */
44
+ target: string;
45
+ }
46
+ /**
47
+ * Découpe un request-target en forme absolue (`http://hôte:port/chemin?q`) :
48
+ * la forme qu'un client envoie à un proxy, et qu'un serveur d'origine DOIT
49
+ * accepter (RFC 9112 §3.2.2). Il DOIT alors ignorer l'en-tête `Host` et prendre
50
+ * l'hôte de la cible — le recoller à `Host` fabriquait un hôte qui n'existe pas.
51
+ *
52
+ * Seuls `http` et `https` sont reconnus (RFC 6455 §4.2.1 vaut aussi pour un
53
+ * handshake WebSocket) ; le schéma de la cible ne remplace jamais celui de la
54
+ * connexion. Une autorité porteuse d'identifiants (`user@hôte`, interdite par
55
+ * RFC 9110 §4.2.4) n'est pas reconnue : `Host` garde la main.
56
+ *
57
+ * Chemin de chaque requête : un seul test de caractère pour la forme origine,
58
+ * aucune allocation.
59
+ *
60
+ * @param target - le request-target brut, tel que reçu.
61
+ * @returns l'autorité et la forme origine, ou `null` pour toute autre forme.
62
+ */
63
+ export declare function splitAbsoluteForm(target: string | undefined): IAbsoluteTarget | null;
64
+ /**
65
+ * Analyse un request-target origin-form (`/chemin[?query]`) dans la forme
66
+ * NORMALISÉE que la porte HTTP donne au routeur (`HttpRequest`) : découpe exacte
67
+ * quand le parse WHATWG serait l'identité ({@link splitTarget}), vrai parse
68
+ * WHATWG sinon — dot-segments résolus, `\` replié, percent-encoding posé.
69
+ *
70
+ * Pour qui reçoit un chemin hors d'une requête HTTP — le pont WebSocket
71
+ * `api.request` — et doit router exactement comme HTTP : la même chaîne, deux
72
+ * transports, une seule forme.
73
+ *
74
+ * @param target - le chemin reçu ; il doit commencer par `/`.
75
+ * @returns pathname et search normalisés, ou `null` si `target` n'est pas un
76
+ * chemin origin-form analysable.
77
+ */
78
+ export declare function parseRequestTarget(target: string): ISplitTarget | null;
39
79
  /**
40
80
  * L'autorité (`host[:port]` brut de l'en-tête `Host` / `:authority`) est-elle
41
81
  * déjà sous la forme exacte que le parseur WHATWG rendrait ?
@@ -0,0 +1,31 @@
1
+ import type http from "node:http";
2
+ import type { ByteStreamSource } from "./ByteStream.js";
3
+ /** Ce qu'une `Response` Web devient pour le flux d'octets de Nodefony. */
4
+ export interface IWebResponseParts {
5
+ /** Statut de la réponse. */
6
+ status: number;
7
+ /** En-têtes à poser, filtrés (voir {@link webResponseParts}). */
8
+ headers: http.OutgoingHttpHeaders;
9
+ /** Corps, Web ou vide — jamais `null`. */
10
+ source: ByteStreamSource;
11
+ }
12
+ /**
13
+ * Traduit une `Response` Web standard en statut, en-têtes et corps pour le flux
14
+ * d'octets — sans la lire : le corps reste un flux.
15
+ *
16
+ * Deux origines, deux règles, que `response.type` distingue :
17
+ * - **construite par l'application** (`new Response(…)`, `Response.json(…)`,
18
+ * `Response.redirect(…)` — `type === "default"`) : ses en-têtes sont les
19
+ * siens, cookies compris (`getSetCookie()`), et partent tels quels ;
20
+ * - **relayée** (issue de `fetch` — `"basic"`, `"cors"`…) : `content-encoding`,
21
+ * `content-length` et `set-cookie` de l'amont sont écartés (voir
22
+ * `UPSTREAM_ONLY`).
23
+ *
24
+ * Les en-têtes de connexion (RFC 9110 §7.6.1 — la liste du relais,
25
+ * `HOP_BY_HOP`) ne partent jamais : ils décrivent un saut, et HTTP/2 les
26
+ * refuse.
27
+ *
28
+ * @param response - une `Response` dont le corps n'a pas été consommé.
29
+ * @returns statut, en-têtes filtrés et corps.
30
+ */
31
+ export declare function webResponseParts(response: Response): IWebResponseParts;