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

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 (138) hide show
  1. package/dist/_virtual/{_@oxc-project_runtime@0.153.0 → _@oxc-project_runtime@0.155.0}/helpers/esm/decorate.js +1 -2
  2. package/dist/_virtual/{_@oxc-project_runtime@0.153.0 → _@oxc-project_runtime@0.155.0}/helpers/esm/decorateParam.js +1 -2
  3. package/dist/index.js +13 -10
  4. package/dist/nodefony/command/assetsPublishCommand.js +5 -3
  5. package/dist/nodefony/command/certificatesCommand.js +5 -3
  6. package/dist/nodefony/command/networkCommand.js +5 -3
  7. package/dist/nodefony/command/proxyGenerateCommand.js +8 -3
  8. package/dist/nodefony/config/config.js +3 -3
  9. package/dist/nodefony/config/defineModuleConfig.js +1 -2
  10. package/dist/nodefony/interfaces/IRequestTrace.js +1 -0
  11. package/dist/nodefony/service/HttpAdminApi.js +2 -2
  12. package/dist/nodefony/service/ProfilerAdminApi.js +13 -3
  13. package/dist/nodefony/service/audit-logger.js +23 -30
  14. package/dist/nodefony/service/certificates.js +97 -13
  15. package/dist/nodefony/service/error-renderer.js +29 -12
  16. package/dist/nodefony/service/http-kernel.js +198 -50
  17. package/dist/nodefony/service/pretty-request-logger.js +15 -13
  18. package/dist/nodefony/service/request-logger.js +24 -16
  19. package/dist/nodefony/service/reverse-proxy.js +3 -3
  20. package/dist/nodefony/service/servers/clientError.js +22 -3
  21. package/dist/nodefony/service/servers/server-h2c.js +126 -0
  22. package/dist/nodefony/service/servers/server-http.js +5 -8
  23. package/dist/nodefony/service/servers/server-https.js +12 -24
  24. package/dist/nodefony/service/servers/server-static.js +3 -3
  25. package/dist/nodefony/service/servers/server-websocket-secure.js +10 -18
  26. package/dist/nodefony/service/servers/server-websocket.js +10 -18
  27. package/dist/nodefony/service/servers/serverShutdown.js +78 -18
  28. package/dist/nodefony/service/servers/wsHeartbeat.js +1 -2
  29. package/dist/nodefony/service/sessions/sessions-service.js +7 -14
  30. package/dist/nodefony/service/trace.js +1 -2
  31. package/dist/nodefony/service/upload/upload-service.js +5 -8
  32. package/dist/nodefony/service/x509.js +1 -2
  33. package/dist/nodefony/src/assets/collectAssets.js +1 -2
  34. package/dist/nodefony/src/assets/prebuiltUi.js +1 -2
  35. package/dist/nodefony/src/context/Context.js +78 -43
  36. package/dist/nodefony/src/context/domainMatcher.js +1 -2
  37. package/dist/nodefony/src/context/forwarded.js +1 -2
  38. package/dist/nodefony/src/context/http/HttpContext.js +28 -6
  39. package/dist/nodefony/src/context/http/Request.js +33 -29
  40. package/dist/nodefony/src/context/http/Response.js +23 -6
  41. package/dist/nodefony/src/context/http/SseStream.js +1 -2
  42. package/dist/nodefony/src/context/http/parser.js +36 -10
  43. package/dist/nodefony/src/context/http/urlFastPath.js +1 -2
  44. package/dist/nodefony/src/context/http2/Request.js +4 -8
  45. package/dist/nodefony/src/context/http2/Response.js +41 -9
  46. package/dist/nodefony/src/context/metaData.js +1 -2
  47. package/dist/nodefony/src/context/requestId.js +1 -2
  48. package/dist/nodefony/src/context/requestTrace.js +104 -0
  49. package/dist/nodefony/src/context/responseEnded.js +1 -2
  50. package/dist/nodefony/src/context/timingMode.js +21 -0
  51. package/dist/nodefony/src/context/transport.js +45 -0
  52. package/dist/nodefony/src/context/trustProxy.js +1 -2
  53. package/dist/nodefony/src/context/unsentResponse.js +30 -0
  54. package/dist/nodefony/src/context/websocket/Response.js +33 -6
  55. package/dist/nodefony/src/context/websocket/WebsocketContext.js +104 -25
  56. package/dist/nodefony/src/context/websocket/isWebsocketContext.js +17 -0
  57. package/dist/nodefony/src/context/websocket/websocketUrl.js +1 -2
  58. package/dist/nodefony/src/context/websocket/wsBackpressure.js +1 -2
  59. package/dist/nodefony/src/context/websocket/wsCloseReason.js +1 -2
  60. package/dist/nodefony/src/context/websocket/wsLogContent.js +1 -2
  61. package/dist/nodefony/src/cookies/cookie.js +3 -7
  62. package/dist/nodefony/src/errors/httpError.js +1 -2
  63. package/dist/nodefony/src/errors/thrownMessage.js +1 -2
  64. package/dist/nodefony/src/profiler/FrameProfile.js +23 -2
  65. package/dist/nodefony/src/profiler/Profiler.js +104 -32
  66. package/dist/nodefony/src/profiler/aggregate.js +442 -0
  67. package/dist/nodefony/src/proxy/forward.js +29 -5
  68. package/dist/nodefony/src/proxy/generateProxyConfig.js +14 -6
  69. package/dist/nodefony/src/proxy/rules.js +12 -6
  70. package/dist/nodefony/src/rateLimit/MemoryRateLimitStore.js +1 -2
  71. package/dist/nodefony/src/rateLimit/WsConnectionCounter.js +1 -2
  72. package/dist/nodefony/src/rateLimit/rateLimitFilters.js +1 -2
  73. package/dist/nodefony/src/servers/http2Limits.js +50 -0
  74. package/dist/nodefony/src/servers/kernelServers.js +12 -3
  75. package/dist/nodefony/src/servers/portBinder.js +41 -10
  76. package/dist/nodefony/src/servers/upgradeDispatch.js +86 -7
  77. package/dist/nodefony/src/session/session.js +2 -3
  78. package/dist/nodefony/src/session/sessionStoreFailure.js +1 -2
  79. package/dist/nodefony/src/session/storage/MemorySessionStorage.js +1 -2
  80. package/dist/nodefony/src/session/storage/RevocationGuardStorage.js +1 -2
  81. package/dist/nodefony/src/session/storage/sessionFilters.js +1 -2
  82. package/dist/nodefony/src/session/storage/sessionSort.js +1 -2
  83. package/dist/types/index.d.ts +9 -3
  84. package/dist/types/nodefony/config/config.d.ts +4 -0
  85. package/dist/types/nodefony/interfaces/IContext.d.ts +72 -4
  86. package/dist/types/nodefony/interfaces/IRequest.d.ts +9 -4
  87. package/dist/types/nodefony/interfaces/IRequestTrace.d.ts +56 -0
  88. package/dist/types/nodefony/interfaces/IReverseProxy.d.ts +8 -0
  89. package/dist/types/nodefony/interfaces/IRouting.d.ts +26 -0
  90. package/dist/types/nodefony/interfaces/index.d.ts +3 -2
  91. package/dist/types/nodefony/service/ProfilerAdminApi.d.ts +3 -0
  92. package/dist/types/nodefony/service/audit-logger.d.ts +3 -11
  93. package/dist/types/nodefony/service/certificates.d.ts +55 -4
  94. package/dist/types/nodefony/service/error-renderer.d.ts +31 -0
  95. package/dist/types/nodefony/service/http-kernel.d.ts +96 -10
  96. package/dist/types/nodefony/service/servers/clientError.d.ts +16 -0
  97. package/dist/types/nodefony/service/servers/server-h2c.d.ts +51 -0
  98. package/dist/types/nodefony/service/servers/server-http.d.ts +3 -3
  99. package/dist/types/nodefony/service/servers/server-https.d.ts +4 -4
  100. package/dist/types/nodefony/service/servers/server-websocket-secure.d.ts +1 -3
  101. package/dist/types/nodefony/service/servers/server-websocket.d.ts +1 -3
  102. package/dist/types/nodefony/service/servers/serverShutdown.d.ts +30 -16
  103. package/dist/types/nodefony/src/context/Context.d.ts +38 -5
  104. package/dist/types/nodefony/src/context/http/HttpContext.d.ts +16 -2
  105. package/dist/types/nodefony/src/context/http/Request.d.ts +20 -15
  106. package/dist/types/nodefony/src/context/http/Response.d.ts +11 -0
  107. package/dist/types/nodefony/src/context/http/parser.d.ts +18 -2
  108. package/dist/types/nodefony/src/context/http2/Request.d.ts +1 -1
  109. package/dist/types/nodefony/src/context/http2/Response.d.ts +27 -5
  110. package/dist/types/nodefony/src/context/requestTrace.d.ts +64 -0
  111. package/dist/types/nodefony/src/context/timingMode.d.ts +23 -0
  112. package/dist/types/nodefony/src/context/transport.d.ts +53 -0
  113. package/dist/types/nodefony/src/context/unsentResponse.d.ts +16 -0
  114. package/dist/types/nodefony/src/context/websocket/Response.d.ts +18 -2
  115. package/dist/types/nodefony/src/context/websocket/WebsocketContext.d.ts +58 -8
  116. package/dist/types/nodefony/src/context/websocket/isWebsocketContext.d.ts +15 -0
  117. package/dist/types/nodefony/src/profiler/FrameProfile.d.ts +28 -12
  118. package/dist/types/nodefony/src/profiler/Profiler.d.ts +79 -111
  119. package/dist/types/nodefony/src/profiler/aggregate.d.ts +132 -0
  120. package/dist/types/nodefony/src/proxy/forward.d.ts +14 -2
  121. package/dist/types/nodefony/src/proxy/generateProxyConfig.d.ts +16 -0
  122. package/dist/types/nodefony/src/proxy/rules.d.ts +3 -0
  123. package/dist/types/nodefony/src/servers/http2Limits.d.ts +37 -0
  124. package/dist/types/nodefony/src/servers/kernelServers.d.ts +10 -1
  125. package/dist/types/nodefony/src/servers/portBinder.d.ts +29 -5
  126. package/dist/types/nodefony/src/servers/upgradeDispatch.d.ts +33 -3
  127. package/docs/cookies.md +85 -78
  128. package/docs/diagnostics-channel.md +303 -0
  129. package/docs/index.md +6 -1
  130. package/docs/observabilite.md +159 -81
  131. package/docs/rate-limit.md +83 -83
  132. package/docs/reverse-proxy.md +72 -70
  133. package/docs/servers.md +338 -224
  134. package/docs/session.md +179 -179
  135. package/docs/sse.md +24 -20
  136. package/docs/upload.md +120 -117
  137. package/package.json +8 -9
  138. package/dist/_virtual/_@oxc-project_runtime@0.153.0/helpers/esm/decorateMetadata.js +0 -6
@@ -7,6 +7,7 @@ import http2 from "node:http2";
7
7
  import http from "node:http";
8
8
  import https from "node:https";
9
9
  import HttpKernel, { ServerType, Data, SchemeType } from "../../service/http-kernel.js";
10
+ import type { AlpnProtocol, ProtocolName } from "../../interfaces/IContext.js";
10
11
  import HttpResponse from "./http/Response.js";
11
12
  import Http2Response from "./http2/Response.js";
12
13
  import WebsocketResponse from "./websocket/Response.js";
@@ -50,7 +51,15 @@ declare class Context extends Service implements IContextInterface {
50
51
  requested: boolean;
51
52
  sessionStarting: boolean;
52
53
  domain: string;
53
- type: ServerType;
54
+ /** Famille traitée (`network.protocol.name` d'OpenTelemetry) — union ouverte. */
55
+ type: ProtocolName;
56
+ /** Serveur qui a reçu la requête — choisit la configuration par serveur. */
57
+ serverType: ServerType;
58
+ /**
59
+ * Protocole du saut local (registre IANA ALPN) — union ouverte. Une connexion
60
+ * WebSocket naît d'un upgrade HTTP/1.1 ; `HttpContext` le constate sur la requête.
61
+ */
62
+ alpnProtocol: AlpnProtocol;
54
63
  server?: WebSocketServer | http.Server | https.Server | http2.Http2SecureServer | null | undefined;
55
64
  httpKernel: HttpKernel | null;
56
65
  request: contextRequest | null;
@@ -88,6 +97,12 @@ declare class Context extends Service implements IContextInterface {
88
97
  crossDomain: boolean;
89
98
  router: IRequestRouter | null;
90
99
  resolver: IRouteResolver | null;
100
+ /**
101
+ * Module qui signe les lignes de CETTE requête : la ligne d'accès et les
102
+ * lignes du contrôleur. `null` = le module de la route (sans route : le
103
+ * journal du noyau). Un contrôleur le change : `this.context.logModule = "billing"`.
104
+ */
105
+ logModule: string | null;
91
106
  /**
92
107
  * Intent de session de la route courante (posé par le Resolver depuis
93
108
  * `@UseSession` / paramètre `@Session`). Pilote le point d'activation unique
@@ -119,6 +134,9 @@ declare class Context extends Service implements IContextInterface {
119
134
  securityTrace: ISecurityTrace | null;
120
135
  private readonly _timingEnabled;
121
136
  private readonly _timingVerbose;
137
+ private readonly _clockEnabled;
138
+ private readonly _clockStartMs;
139
+ private _durationMs;
122
140
  readonly phases: PhaseTiming[];
123
141
  private _phaseIndex;
124
142
  private _afterResponseFns;
@@ -128,7 +146,7 @@ declare class Context extends Service implements IContextInterface {
128
146
  metaData: Data;
129
147
  scheme: SchemeType;
130
148
  webSocketState: WebSocketState;
131
- constructor(container: Container | Scope, type: ServerType);
149
+ constructor(container: Container | Scope, serverType: ServerType);
132
150
  /**
133
151
  * Assemble l'enveloppe `metaData` de la requête (`nodefony.*` + `route`
134
152
  * snapshot per-requête + overrides appelant). Délègue au builder monomorphe
@@ -152,6 +170,21 @@ declare class Context extends Service implements IContextInterface {
152
170
  get timingEnabled(): boolean;
153
171
  phaseStart(name: PhaseName): void;
154
172
  phaseEnd(name: PhaseName): void;
173
+ /**
174
+ * Arrête l'horloge de la requête et rend sa durée, en millisecondes.
175
+ *
176
+ * La durée court de la construction du contexte au PREMIER appel : le
177
+ * démontage HTTP (`close` de la réponse, dernier octet remis — la mesure
178
+ * d'OpenTelemetry et du `$request_time` de nginx), la ligne d'accès pour un
179
+ * handshake WebSocket. Les appels suivants rendent la même valeur : journal
180
+ * d'accès, profiler et trace verbose lisent UNE durée, jamais trois.
181
+ *
182
+ * Active par défaut dans tous les environnements, production comprise :
183
+ * seul `timing.enabled: false` la coupe (cf `resolveTimingMode`).
184
+ *
185
+ * @returns la durée, ou `null` si `timing.enabled` vaut `false`
186
+ */
187
+ stopClock(): number | null;
155
188
  onAfterResponse(fn: AfterResponseHandler): void;
156
189
  /**
157
190
  * Exécute les hooks `onAfterResponse`, une seule fois, dans l'ordre
@@ -167,7 +200,7 @@ declare class Context extends Service implements IContextInterface {
167
200
  private runAfterResponseHooks;
168
201
  get signal(): AbortSignal;
169
202
  _abortIfPending(reason?: string): void;
170
- log(pci: Pci, severity?: Severity, msgid?: Msgid, msg?: Message): Pdu;
203
+ log(pci: Pci, severity?: Severity, msgid?: Msgid, msg?: Message, moduleName?: string): Pdu;
171
204
  /**
172
205
  * Confie au contexte le magasin `RequestContext` de son unité de travail
173
206
  * (requête HTTP, connexion WebSocket), pour qu'il le VIDE à son nettoyage.
@@ -183,8 +216,8 @@ declare class Context extends Service implements IContextInterface {
183
216
  clean(): void;
184
217
  /**
185
218
  * Log d'un event du cycle de vie — gate boot-time (V2.1) : en production le
186
- * Pdu n'est PAS construit (return avant toute allocation). Hors prod, jalon
187
- * notable → INFO (EVENT_SEVERITY), event technique → DEBUG.
219
+ * Pdu n'est PAS construit (return avant toute allocation). Hors prod : DEBUG,
220
+ * pour le Suivi de requête de Studio — la ligne `req` porte le bilan.
188
221
  */
189
222
  private logEvent;
190
223
  fire(event: KernelEventsType, ...args: unknown[]): boolean;
@@ -1,6 +1,7 @@
1
1
  import { ServerType, SchemeType } from "../../../service/http-kernel.js";
2
+ import HttpError from "../../errors/httpError.js";
2
3
  import Context, { HTTPMethod } from "../Context.js";
3
- import { Container, Scope } from "nodefony";
4
+ import { Container, Scope, nodefonyError } from "nodefony";
4
5
  import type { MaybePromise } from "nodefony";
5
6
  import HttpRequest from "./Request.js";
6
7
  import HttpResponse from "./Response.js";
@@ -50,10 +51,15 @@ declare class HttpContext extends Context implements IHttpContextInterface {
50
51
  private activeSocket;
51
52
  isRedirect: boolean;
52
53
  sended: boolean;
54
+ /**
55
+ * Requête relayée par le proxy inverse : la politique de ligne d'accès de
56
+ * son montage. `null` = servie par l'application (cas de toute requête).
57
+ */
58
+ relayAccessLog: "all" | "errors" | null;
53
59
  request: HttpRequestType;
54
60
  response: HttpRsponseType;
55
61
  uploadService: uploadService | null;
56
- constructor(container: Container | Scope, request: http.IncomingMessage | http2.Http2ServerRequest, response: http.ServerResponse | http2.Http2ServerResponse, type: ServerType);
62
+ constructor(container: Container | Scope, request: http.IncomingMessage | http2.Http2ServerRequest, response: http.ServerResponse | http2.Http2ServerResponse, serverType: ServerType);
57
63
  /**
58
64
  * URL d'origine effective, construite À LA DEMANDE (1ʳᵉ lecture, puis
59
65
  * mémoïsée). `Origin` invalide ou `null` (RFC 6454) → repli sur l'URL de la
@@ -84,6 +90,14 @@ declare class HttpContext extends Context implements IHttpContextInterface {
84
90
  */
85
91
  handle(): MaybePromise<this>;
86
92
  setTimeout(): void;
93
+ /**
94
+ * Ligne d'accès — pour une requête RELAYÉE, avec le statut que l'amont a
95
+ * réellement rendu (le relais écrit la réponse brute, pas celle du
96
+ * contexte) ; un montage `accessLog: "errors"` ne l'écrit qu'en échec.
97
+ *
98
+ * @param httpError - l'erreur de la requête, s'il y en a une
99
+ */
100
+ logRequest(httpError?: Error | HttpError | nodefonyError | null): import("nodefony").Pdu | undefined;
87
101
  /**
88
102
  * Nettoie le contexte, et le DÉTACHE de sa socket h1 : la connexion
89
103
  * persistante survit à la requête, et l'entrée de `socketActiveContext`
@@ -5,6 +5,7 @@ import { URL } from "node:url";
5
5
  import { HTTPMethod, Cookies } from "../Context.js";
6
6
  import QS from "qs";
7
7
  import { ParserXml, ParserQs, Parser, acceptParser } from "./parser.js";
8
+ import type { RequestBody } from "../../../interfaces/IRequest.js";
8
9
  import { UploadedFile } from "../../../service/upload/upload-service.js";
9
10
  import type { IParsedUploadFile, IUploadOptions } from "../../../interfaces/IUpload.js";
10
11
  import { Pci, Pdu, Message, Severity, Msgid } from "nodefony";
@@ -75,22 +76,24 @@ declare class HttpRequest {
75
76
  get url(): URL;
76
77
  set url(u: URL);
77
78
  parser: ParserType | null;
78
- queryPost: Record<string, unknown>;
79
- queryGet: Record<string, unknown>;
80
- queryFile: UploadedFile[];
81
- query: Record<string, unknown>;
82
79
  /**
83
- * Le CORPS de la requête, parsé — nom universel de l'écosystème (Express,
84
- * Fastify, NestJS), alias de {@link queryPost}.
85
- *
86
- * Ne pas confondre avec {@link query}, qui FUSIONNE la query string et le
87
- * corps : `body` ne rend jamais un paramètre d'URL. Le data plane admin
88
- * expose déjà cette sémantique (`IAdminRequest.body`) ; ce getter la rend
89
- * disponible partout.
80
+ * Le CORPS de la requête, parsé (JSON, urlencoded, XML, champs multipart) —
81
+ * nom universel de l'écosystème (Express, Fastify, NestJS) et celui
82
+ * d'`IAdminRequest.body`. Jamais un paramètre d'URL : ceux-là sont dans
83
+ * {@link query}, et les deux ne fusionnent pas.
84
+ */
85
+ body: RequestBody;
86
+ /**
87
+ * Les fichiers reçus dans un corps multipart, déjà écrits dans le répertoire
88
+ * temporaire — lus par `@UploadedFile()` / `@UploadedFiles()`. Les champs
89
+ * texte du même corps sont dans {@link body}.
90
90
  *
91
- * Getter (aucune allocation) : `queryPost` reste la source unique.
91
+ * Lecture seule : une requête sans upload rend un vide partagé et gelé,
92
+ * aucune allocation.
92
93
  */
93
- get body(): Record<string, unknown>;
94
+ get files(): readonly UploadedFile[];
95
+ /** Les paramètres d'URL, seuls — jamais un champ du corps ({@link body}). */
96
+ query: Record<string, unknown>;
94
97
  queryStringOptions: (QS.IParseOptions & {
95
98
  decoder?: undefined;
96
99
  }) | undefined;
@@ -112,7 +115,7 @@ declare class HttpRequest {
112
115
  * remplace le `once("onRequestEnd")` du ctor qui allouait 1 onceWrapper +
113
116
  * 1 closure à CHAQUE requête.
114
117
  *
115
- * Il porte le CORPS (`queryPost`), pas la fusion `query` : un seul sens de
118
+ * Il porte le CORPS (`body`), jamais les paramètres d'URL : un seul sens de
116
119
  * `body` dans tout le framework, celui de l'écosystème et d'`IAdminRequest`.
117
120
  */
118
121
  private fireRequestEnd;
@@ -228,7 +231,9 @@ declare class HttpRequest {
228
231
  /**
229
232
  * Scheme effectif côté client : `Forwarded`/`X-Forwarded-*` résolu de façon
230
233
  * canonique (this.forwarded, gated proxy de confiance) ; sinon le transport
231
- * réel. HTTP/2 remplace la lecture du socket par le pseudo-header `:scheme`.
234
+ * réel. Vaut pour HTTP/2 aussi : le pseudo-en-tête `:scheme` vient du client
235
+ * (RFC 9113 §8.3.1) et n'est jamais cru — sur h2c, `:scheme: https` ferait
236
+ * passer une connexion claire pour chiffrée.
232
237
  */
233
238
  protected resolveScheme(request: http.IncomingMessage | http2.Http2ServerRequest): string;
234
239
  getFullUrl(request?: http.IncomingMessage | http2.Http2ServerRequest): string;
@@ -50,6 +50,17 @@ declare class HttpResponse {
50
50
  deleteCookieByName(name: string): boolean;
51
51
  setCookies(): void | http.ServerResponse<http.IncomingMessage>;
52
52
  setCookie(cookie: Cookie): void | http.ServerResponse<http.IncomingMessage>;
53
+ /**
54
+ * Journalise en DEBUG un cookie posé, sa VALEUR MASQUÉE : nom et attributs
55
+ * seulement. Le journal de développement se lit par le plan d'administration
56
+ * — un identifiant de session y entrerait chez quiconque le consulte.
57
+ * La ligne n'est construite que si DEBUG passe le gate du syslog pour ce
58
+ * `msgid` (debug ciblé compris) : rien n'est alloué en production.
59
+ *
60
+ * @param cookie - le cookie posé.
61
+ * @param serialized - sa forme `Set-Cookie`, déjà calculée pour l'en-tête.
62
+ */
63
+ private logCookie;
53
64
  setHeader(name: string, value: number | string | readonly string[]): void | http.ServerResponse<http.IncomingMessage>;
54
65
  setHeaders(obj: OutgoingHttpHeaders): OutgoingHttpHeaders;
55
66
  setContentType(type?: string, encoding?: BufferEncoding): void | http.ServerResponse<http.IncomingMessage>;
@@ -22,6 +22,22 @@ declare class Parser {
22
22
  protected ended(): Promise<void>;
23
23
  parse(): Promise<this>;
24
24
  }
25
+ /**
26
+ * Corps d'un type que le framework ne décode pas : livré TEL QU'IL EST REÇU,
27
+ * jamais remplacé par un objet vide qui mentirait.
28
+ *
29
+ * - `text/*` → une chaîne, décodée au `charset` du `Content-Type` (UTF-8 par
30
+ * défaut) — comme une trame texte RFC 6455 ;
31
+ * - tout autre type, et un corps sans `Content-Type` (RFC 9110 §8.3 : supposé
32
+ * `application/octet-stream`) → les OCTETS : le `Buffer` déjà assemblé dans
33
+ * `request.data`, sans copie — donc un `Uint8Array`, le type d'octets que
34
+ * la socket livrera aussi (#618). Un même schéma passe par les deux portes.
35
+ *
36
+ * Un corps VIDE laisse `body` tel quel : une requête sans charge ne change pas.
37
+ */
38
+ declare class ParserRaw extends Parser {
39
+ parse(): Promise<this>;
40
+ }
25
41
  declare class ParserQs extends Parser {
26
42
  parserOptions: QS.IParseOptions;
27
43
  charset: BufferEncoding;
@@ -35,7 +51,7 @@ declare class ParserXml extends Parser {
35
51
  parse(): Promise<this>;
36
52
  }
37
53
  /**
38
- * Parse un corps `application/json` (ou `*+json`) en objet → `queryPost`
54
+ * Parse un corps `application/json` (ou `*+json`) en objet → `body`
39
55
  * (source lue par le décorateur `@Body`). Reprend le rôle de l'ancien plugin
40
56
  * `json` de formidable, supprimé avec le passage à busboy (multipart seul).
41
57
  * Lenient : un corps JSON malformé est ignoré (pas de throw — `parse()` est
@@ -62,4 +78,4 @@ type AcceptEntry = {
62
78
  [key: string]: RegExp | number | string | undefined;
63
79
  };
64
80
  declare const acceptParser: (acc?: string) => AcceptEntry[];
65
- export { Parser, ParserXml, ParserQs, ParserJson, acceptParser };
81
+ export { Parser, ParserRaw, ParserXml, ParserQs, ParserJson, acceptParser };
@@ -5,10 +5,10 @@ import { HTTPMethod } from "../Context.js";
5
5
  declare class Http2Request extends HttpRequest {
6
6
  request: http2.Http2ServerRequest;
7
7
  constructor(request: http2.Http2ServerRequest, context: HttpContext);
8
+ /** `:authority`, sinon `Host` — cf `requestAuthority` (RFC 9113 §8.3.1). */
8
9
  getHost(): string | undefined;
9
10
  getUserAgent(): string | undefined;
10
11
  getMethod(): HTTPMethod;
11
12
  getRawTarget(): string | undefined;
12
- protected resolveScheme(): string;
13
13
  }
14
14
  export default Http2Request;
@@ -3,6 +3,11 @@ import type { MaybePromise } from "nodefony";
3
3
  import http from "node:http";
4
4
  import HttpContext from "../http/HttpContext.js";
5
5
  import HttpResponse from "../http/Response.js";
6
+ /** Ce que la fusion lit d'une réponse Node : ses en-têtes posés, nom par nom. */
7
+ interface IHeaderSource {
8
+ getHeaderNames(): string[];
9
+ getHeader(name: string): http.OutgoingHttpHeader | undefined;
10
+ }
6
11
  /**
7
12
  * Compose les en-têtes d'une réponse HTTP/2 : ceux posés sur la réponse, puis
8
13
  * ceux passés à `writeHead`, qui gagnent.
@@ -13,12 +18,17 @@ import HttpResponse from "../http/Response.js";
13
18
  * (`ERR_HTTP2_HEADER_SINGLE_VALUE`), soit une 500 sur tout média servi en
14
19
  * HTTP/2. HTTP/2 n'a de toute façon que des noms en minuscules (RFC 9113 §8.2.1).
15
20
  *
21
+ * Les en-têtes posés se lisent nom par nom (`getHeaderNames`, déjà en
22
+ * minuscules) : `getHeaders()` les recopiait d'abord dans un objet sans
23
+ * prototype, avant cette fusion — 3,8 µs par réponse pour 12 en-têtes,
24
+ * contre 1,1 µs en une passe.
25
+ *
16
26
  * @param statusMessage - message de statut, recopié en `x-status-message`
17
- * @param current - en-têtes déjà posés sur la réponse
27
+ * @param current - la réponse Node qui porte les en-têtes déjà posés
18
28
  * @param extra - en-têtes passés à `writeHead` (objet, ou liste plate clé/valeur)
19
29
  * @returns les en-têtes à transmettre à `respond()`
20
30
  */
21
- export declare function mergeResponseHeaders(statusMessage: string, current: http.OutgoingHttpHeaders, extra?: http.OutgoingHttpHeaders | http.OutgoingHttpHeader[]): http.OutgoingHttpHeaders;
31
+ export declare function mergeResponseHeaders(statusMessage: string, current: IHeaderSource, extra?: http.OutgoingHttpHeaders | http.OutgoingHttpHeader[]): http.OutgoingHttpHeaders;
22
32
  declare class Http2Response extends HttpResponse {
23
33
  statusCode: number;
24
34
  stream: http2.ServerHttp2Stream | null;
@@ -27,9 +37,9 @@ declare class Http2Response extends HttpResponse {
27
37
  isHeaderSent(): boolean;
28
38
  writeHead(statusCode?: number, headers?: http.OutgoingHttpHeaders | http.OutgoingHttpHeader[]): void;
29
39
  /**
30
- * Écrit le corps sur le flux HTTP/2. Synchrone pour une redirection, un flux
31
- * fermé ou le repli HTTP/1 ; une promesse quand le corps est écrit sur le
32
- * flux, réglée par le rappel d'écriture (#505).
40
+ * Écrit le corps sur le flux HTTP/2 et, pour une réponse unique, le termine
41
+ * d'un seul `end(corps)`. Synchrone, sauf en streaming (`flush()`) : une
42
+ * promesse réglée par le rappel d'écriture, la contre-pression (#505).
33
43
  *
34
44
  * @returns la réponse, ou sa promesse.
35
45
  */
@@ -41,6 +51,18 @@ declare class Http2Response extends HttpResponse {
41
51
  * @throws de façon SYNCHRONE ce que lève la fin du flux.
42
52
  */
43
53
  end(chunk?: string | Buffer, encoding?: BufferEncoding): MaybePromise<http.ServerResponse | http2.ServerHttp2Stream>;
54
+ /**
55
+ * Termine la réponse de compatibilité d'un HEAD, dont Node a clos le flux de
56
+ * lui-même au `respond()`.
57
+ *
58
+ * Sans ce geste, `Http2ServerResponse` n'émet ni `finish` ni `close` : le
59
+ * démontage de la requête, branché sur ce `close` (ligne d'accès, profil,
60
+ * hooks d'après-réponse, libération du scope DI), n'a jamais lieu. Les statuts
61
+ * que Node termine aussi d'office (204, 205, 304) émettent leur `close` seuls,
62
+ * et un flux détruit (client parti) aussi : ils ne sont pas touchés. Hors du
63
+ * chemin servi — appelé seulement quand le flux est déjà clos.
64
+ */
65
+ private settleHeadResponse;
44
66
  getStatusMessage(code?: number | string): string;
45
67
  getStatus(): {
46
68
  code: number;
@@ -0,0 +1,64 @@
1
+ import type { IRequestTrace, RequestTraceProtocol } from "../../interfaces/IRequestTrace.js";
2
+ import type Context from "./Context.js";
3
+ /**
4
+ * Nom du `TracingChannel` qui encadre chaque requête HTTP et chaque handshake
5
+ * WebSocket — forme `module.fonction` recommandée par la documentation de
6
+ * `node:diagnostics_channel` ; les sous-canaux sont
7
+ * `tracing:nodefony.http.request:start`, `:end`, `:asyncStart`, `:asyncEnd`,
8
+ * `:error`.
9
+ */
10
+ export declare const REQUEST_TRACE_CHANNEL = "nodefony.http.request";
11
+ /**
12
+ * Le message tel que Nodefony le remplit au fil de la requête : la vue
13
+ * modifiable d'{@link IRequestTrace}, qui reste en lecture seule pour
14
+ * l'abonné.
15
+ */
16
+ export type RequestTraceRecord = {
17
+ -readonly [K in keyof IRequestTrace]: IRequestTrace[K];
18
+ };
19
+ /**
20
+ * Dit si quelqu'un écoute le canal — LA garde du chemin chaud : ~1,6 ns
21
+ * mesurées, aucune allocation. Lue une seule fois, au début de la requête :
22
+ * un abonné arrivé ensuite ne voit que les requêtes suivantes (règle des
23
+ * `TracingChannel`, qui interdit une fin sans début).
24
+ *
25
+ * @returns `true` si au moins un sous-canal a un abonné
26
+ */
27
+ export declare function hasRequestTraceSubscribers(): boolean;
28
+ /**
29
+ * Crée le message de la requête et le range sur son contexte. À n'appeler
30
+ * que sous {@link hasRequestTraceSubscribers} : c'est la seule allocation
31
+ * du canal, et elle n'a lieu que si quelqu'un écoute.
32
+ *
33
+ * @param context - le contexte qui vient d'être construit
34
+ * @param protocol - requête HTTP ou handshake WebSocket
35
+ * @returns le message, de forme fixe, dont les champs de résultat valent `null`
36
+ */
37
+ export declare function openRequestTrace(context: Context, protocol: RequestTraceProtocol): RequestTraceRecord;
38
+ /**
39
+ * Exécute la partie synchrone du traitement sous `start.runStores` puis
40
+ * publie `end` — la séquence de `TracingChannel.tracePromise`. Les stores
41
+ * liés au canal (`bindStore`, ce que fait un agent APM) restent actifs pour
42
+ * toute la suite asynchrone de la requête.
43
+ *
44
+ * @param trace - le message de la requête
45
+ * @param fn - la fonction qui sert la requête
46
+ * @param thisArg - le receveur de `fn`
47
+ * @param args - les arguments de `fn`
48
+ * @returns ce que rend `fn` — un contexte ou sa promesse
49
+ */
50
+ export declare function runTraced<ThisArg, Args extends unknown[], Result>(trace: RequestTraceRecord, fn: (this: ThisArg, ...args: Args) => Result, thisArg: ThisArg, ...args: Args): Result;
51
+ /**
52
+ * Termine la trace de la requête : remplit les champs de résultat puis
53
+ * publie `error` (s'il y a une exception), `asyncStart` et `asyncEnd`.
54
+ * Idempotent — le premier appel gagne, les suivants ne font rien : un
55
+ * handshake WebSocket a plusieurs sorties, une seule publie la fin.
56
+ *
57
+ * La durée est celle de l'horloge unique du contexte (`stopClock`), la même
58
+ * que celle de la ligne d'accès : le canal n'en mesure aucune.
59
+ *
60
+ * @param context - le contexte de la requête
61
+ * @param statusCode - le statut rendu au client, `null` s'il n'y en a pas eu
62
+ * @param error - l'exception attrapée par le pipeline, `null` ou `undefined` sinon
63
+ */
64
+ export declare function closeRequestTrace(context: Context, statusCode: number | null, error: unknown): void;
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Ce que le chronométrage mesure sur une requête :
3
+ *
4
+ * - `"off"` — rien : ni horloge, ni phases ; la ligne d'accès sort sans durée ;
5
+ * - `"clock"` — la durée seule : une lecture d'horloge à l'entrée, une à la fin ;
6
+ * - `"phases"` — la durée ET le détail par phase (resolve, firewall, action…).
7
+ */
8
+ export type TimingMode = "off" | "clock" | "phases";
9
+ /**
10
+ * Résout le mode de chronométrage d'une requête depuis `timing.enabled` et
11
+ * l'environnement — la SEULE règle, appelée par le constructeur du `Context`.
12
+ *
13
+ * Défaut (`null`, pas d'avis) : la durée partout, les phases hors production.
14
+ * La durée coûte deux lectures d'horloge, l'équivalent de quelques pourcents
15
+ * de la ligne d'accès qu'elle complète ; les phases coûtent une lecture par
16
+ * phase, un tableau et un index par requête — réservées au développement, ou
17
+ * à un diagnostic à chaud (`true`). `false` coupe tout, durée comprise.
18
+ *
19
+ * @param enabled - valeur de `timing.enabled` (`true`, `false`, `null`)
20
+ * @param environment - environnement normalisé du noyau (`"production"`…)
21
+ * @returns le mode de la requête — une chaîne littérale, rien d'alloué
22
+ */
23
+ export declare function resolveTimingMode(enabled: unknown, environment: string | undefined): TimingMode;
@@ -0,0 +1,53 @@
1
+ import type { AlpnProtocol, ProtocolName, ServerType } from "../../interfaces/IContext.js";
2
+ /**
3
+ * Famille du protocole traité par un contexte, déduite du serveur qui l'a
4
+ * reçu. Règle UNIQUE : `Context` la pose à la construction.
5
+ *
6
+ * @param serverType - identité du serveur (`http`, `https`, `ws`, `wss`)
7
+ * @returns `"websocket"` pour `ws`/`wss`, `"http"` sinon
8
+ */
9
+ export declare function protocolNameOf(serverType: ServerType): ProtocolName;
10
+ /**
11
+ * Ce que la détection lit d'une requête Node, et rien d'autre : `http.IncomingMessage`
12
+ * (HTTP/1.1) et `http2.Http2ServerRequest` (h2, h2c) le satisfont par leur forme, sans
13
+ * transtypage — et une doublure de test s'écrit en littéral.
14
+ */
15
+ export interface IAlpnSource {
16
+ readonly httpVersionMajor: number;
17
+ readonly stream?: {
18
+ readonly session?: {
19
+ readonly alpnProtocol?: string | undefined;
20
+ } | undefined;
21
+ } | undefined;
22
+ }
23
+ /**
24
+ * Protocole du saut qui a porté cette requête jusqu'au processus, au sens du
25
+ * registre IANA des identifiants ALPN. Règle UNIQUE : `HttpContext` la lit pour
26
+ * choisir ses classes de requête et de réponse.
27
+ *
28
+ * La valeur se CONSTATE sur la requête, elle ne se déduit pas du serveur : un
29
+ * même serveur TLS reçoit HTTP/1.1 et h2 (`allowHTTP1`). Pour h2, c'est la
30
+ * session de Node qui tranche — `Http2Session.alpnProtocol` vaut `"h2c"` sur
31
+ * une session en clair, l'ALPN négocié (`"h2"`) sur une session TLS.
32
+ *
33
+ * @param request - la requête Node reçue par le serveur
34
+ * @returns `"http/1.1"`, `"h2"` ou `"h2c"`
35
+ */
36
+ export declare function alpnProtocolOf(request: IAlpnSource): AlpnProtocol;
37
+ /**
38
+ * Autorité (hôte et port) d'une requête, HTTP/1.1 comme HTTP/2. Règle UNIQUE
39
+ * des lecteurs du serveur.
40
+ *
41
+ * `:authority` d'abord, puis `Host` (RFC 9113 §8.3.1). Le repli n'est pas un
42
+ * confort : un intermédiaire qui convertit une requête HTTP/1.1 de forme origine
43
+ * (`GET /chemin`) en HTTP/2 ne DOIT PAS fabriquer `:authority` — il garde
44
+ * `Host`. C'est ce que fait HAProxy `proto h2` vers un port h2c : sans ce repli,
45
+ * l'hôte est introuvable et la requête part en 421.
46
+ *
47
+ * @param headers - en-têtes de la requête Node (`IncomingMessage` ou `Http2ServerRequest`).
48
+ * @returns l'autorité, ou `undefined` si la requête n'en porte aucune.
49
+ */
50
+ export declare function requestAuthority(headers: {
51
+ host?: string | undefined;
52
+ ":authority"?: string | undefined;
53
+ }): string | undefined;
@@ -0,0 +1,16 @@
1
+ import type { IRouteResolver } from "../../interfaces/IRouting.js";
2
+ /**
3
+ * Rédige l'avertissement de développement d'une requête restée sans réponse :
4
+ * l'action a rendu une valeur que le framework ne sait pas envoyer, et la
5
+ * requête a attendu son délai d'expiration.
6
+ *
7
+ * Le message nomme l'action fautive, ce qu'elle a rendu, et le geste qui
8
+ * convient à ce cas — `null` est presque toujours une entité absente, qui
9
+ * appelle un 404.
10
+ *
11
+ * @param resolver - le resolver de la requête (route, controller, action,
12
+ * valeur non rendue), `null` si aucune route n'a été résolue.
13
+ * @param url - l'URL de la requête, repli quand aucune route n'est connue.
14
+ * @returns le texte de l'avertissement.
15
+ */
16
+ export declare function unsentResponseWarning(resolver: IRouteResolver | null | undefined, url: string): string;
@@ -1,3 +1,4 @@
1
+ import type { OutgoingHttpHeaders } from "node:http";
1
2
  import Cookie from "../../cookies/cookie.js";
2
3
  import { Message, Msgid, Pci, Severity } from "nodefony";
3
4
  import WebsocketContext from "./WebsocketContext.js";
@@ -44,8 +45,23 @@ declare class WebsocketResponse {
44
45
  };
45
46
  clean(): void;
46
47
  setEncoding(encoding: BufferEncoding): BufferEncoding;
47
- setHeader(): boolean;
48
- setHeaders(): boolean;
48
+ /**
49
+ * En-têtes de la réponse au handshake, retenus tant que la socket n'est pas
50
+ * acceptée : ils ne partent que dans un REFUS (`refuseHandshake`) — le `101`
51
+ * de `ws` ne les porte pas. `null` tant que personne n'en pose (le cas
52
+ * nominal : aucune allocation).
53
+ */
54
+ handshakeHeaders: Record<string, string | number> | null;
55
+ /**
56
+ * Retient un en-tête du handshake (cf {@link handshakeHeaders}) ; sans effet
57
+ * une fois la socket ouverte, où il n'y a plus de réponse HTTP.
58
+ *
59
+ * @param name - nom de l'en-tête
60
+ * @param value - valeur
61
+ * @returns toujours `true`
62
+ */
63
+ setHeader(name: string, value: number | string | readonly string[]): boolean;
64
+ setHeaders(obj: OutgoingHttpHeaders): boolean;
49
65
  addCookie(cookie: Cookie): void;
50
66
  setCookies(): void;
51
67
  setCookie(_cookie: Cookie): void;
@@ -4,21 +4,21 @@ import { Severity, Msgid, Message, nodefonyError, Scope } from "nodefony";
4
4
  import Ws from "ws";
5
5
  import type { IncomingMessage } from "node:http";
6
6
  import WebsocketResponse from "./Response.js";
7
+ import type { IUpgradeAdmission } from "../../servers/upgradeDispatch.js";
7
8
  import { URL } from "node:url";
8
9
  import { HTTPMethod } from "../Context.js";
9
10
  import HttpError from "../../errors/httpError.js";
10
11
  import { FrameProfile } from "../../profiler/FrameProfile.js";
11
- import type { PhaseName } from "../../../interfaces/IContext.js";
12
+ import type { PhaseName, IWebsocketContext } from "../../../interfaces/IContext.js";
12
13
  import { ProxyType } from "../http/HttpContext.js";
13
14
  import { type ResolvedProxy } from "../forwarded.js";
14
15
  export interface IWsRequestExtension {
15
16
  url: URL;
16
17
  query: Record<string, string>;
17
- queryGet: Record<string, string>;
18
18
  path: string;
19
19
  }
20
20
  export type WsIncomingMessage = IncomingMessage & IWsRequestExtension;
21
- import type { IWebsocketContext as IWebsocketContextInterface } from "../../../interfaces/IContext.js";
21
+ import type { IWebsocketContext as IWebsocketContextInterface, IWebsocketConnectionState } from "../../../interfaces/IContext.js";
22
22
  /**
23
23
  * Coerce un code (applicatif / HTTP / WS) en code de fermeture WebSocket VALIDE
24
24
  * et conforme RFC 6455 §7.4, en PRÉFÉRANT les codes standard §7.4.1 quand le
@@ -36,7 +36,36 @@ import type { IWebsocketContext as IWebsocketContextInterface } from "../../../i
36
36
  * @returns un code de fermeture WS valide.
37
37
  */
38
38
  export declare function toWsCloseCode(code: number | undefined | null): number;
39
- export default class WebsocketContext extends Context implements IWebsocketContextInterface {
39
+ /**
40
+ * Statut HTTP d'un handshake REFUSÉ avant le `101` (RFC 6455 §4.2.2) — la
41
+ * réciproque de {@link toWsCloseCode} : une erreur levée pendant la décision
42
+ * porte un code HTTP (pare-feu, garde) ou, par héritage, un code de fermeture
43
+ * WS (origine `1008`, protocole `1002`, introuvable `4004`) ; le client qui
44
+ * lit le statut doit y reconnaître le même sens.
45
+ *
46
+ * @param code - code porté par l'erreur
47
+ * @returns un statut HTTP 4xx/5xx
48
+ */
49
+ export declare function toHandshakeStatus(code: number | undefined | null): number;
50
+ /**
51
+ * Statut HTTP que reçoit le client d'un handshake refusé — ou `null` si la
52
+ * connexion était déjà acceptée.
53
+ *
54
+ * La ligne de journal d'un refus s'écrit AVANT `refuseHandshake` : sans ce
55
+ * calcul, elle affichait le code de fermeture par défaut (`1000`) en ERROR,
56
+ * pour un `400` que le client reçoit. Même conversion que le refus
57
+ * ({@link toHandshakeStatus}), donc même chiffre. Chemin d'ERREUR seulement :
58
+ * 1 comparaison et 1 `typeof`, aucune allocation.
59
+ *
60
+ * @param context - le contexte WS de la ligne
61
+ * @param error - l'erreur qui a interrompu le handshake
62
+ * @returns le statut HTTP du refus, ou `null` après l'acceptation
63
+ */
64
+ export declare function handshakeRefusalStatus(context: IWebsocketContext, error: Error): number | null;
65
+ interface WebsocketContext extends IWebsocketConnectionState {
66
+ }
67
+ export { WebsocketContext as default };
68
+ declare class WebsocketContext extends Context implements IWebsocketContextInterface {
40
69
  #private;
41
70
  request: WsIncomingMessage | null;
42
71
  response: WebsocketResponse | null;
@@ -45,16 +74,37 @@ export default class WebsocketContext extends Context implements IWebsocketConte
45
74
  rejected: boolean;
46
75
  teardownWired: boolean;
47
76
  connection: Ws | null;
77
+ /**
78
+ * Le verdict du handshake encore à rendre : posé par le noyau tant que le
79
+ * pipeline décide (pare-feu, garde de l'action), `null` dès que la socket
80
+ * est acceptée ou refusée. Tant qu'il est là, AUCUN `101` n'est parti.
81
+ */
82
+ admission: IUpgradeAdmission | null;
48
83
  origin: string;
49
84
  proxy: ProxyType | null;
50
85
  forwarded: ResolvedProxy | null;
51
86
  wsUrl: URL | null;
52
- queryGet: Record<string, string>;
53
- queryRequest: Record<string, string>;
87
+ query: Record<string, string>;
54
88
  wsPath: string;
55
- constructor(scope: Scope, req: IncomingMessage, ws: Ws, type: ServerType);
56
- log(pci: unknown, severity?: Severity, msgid?: Msgid, msg?: Message): import("nodefony").Pdu;
89
+ constructor(scope: Scope, req: IncomingMessage, ws: Ws | null, serverType: ServerType);
90
+ log(pci: unknown, severity?: Severity, msgid?: Msgid, msg?: Message, moduleName?: string): import("nodefony").Pdu;
57
91
  logRequest(httpError?: Error | HttpError | nodefonyError | null, acceptedProtocol?: string | null): import("nodefony").Pdu | undefined;
92
+ /**
93
+ * Rattache la socket que le handshake vient d'ouvrir (`101` envoyé) : le
94
+ * contexte a été construit et jugé AVANT, sans elle.
95
+ *
96
+ * @param ws - la socket acceptée
97
+ */
98
+ acceptConnection(ws: Ws): void;
99
+ /**
100
+ * Refuse le handshake par un statut HTTP, avant tout `101` (RFC 6455
101
+ * §4.2.2) — avec les en-têtes posés pendant la décision (`WWW-Authenticate`
102
+ * du pare-feu, `Retry-After`).
103
+ *
104
+ * @param status - statut HTTP du refus
105
+ * @returns `false` si le verdict était déjà rendu (rien n'est écrit)
106
+ */
107
+ refuseHandshake(status: number): boolean;
58
108
  connect(): Promise<Ws>;
59
109
  handle(data?: unknown[]): Promise<this>;
60
110
  render(chunk: unknown, encoding?: BufferEncoding): Promise<WebsocketResponse>;
@@ -0,0 +1,15 @@
1
+ import type { ContextType } from "../../../service/http-kernel.js";
2
+ import type WebsocketContext from "./WebsocketContext.js";
3
+ /**
4
+ * Dit si un contexte sert une connexion WebSocket — la garde qui rétrécit
5
+ * `ContextType` à `WebsocketContext` sans conversion.
6
+ *
7
+ * Elle lit la famille (`type`) posée à la construction du contexte, jamais
8
+ * `instanceof` : deux copies installées de `@nodefony/http` font échouer
9
+ * `instanceof` en silence, quand ce champ dit vrai pour les deux. Deux
10
+ * Une comparaison de chaînes, aucune allocation.
11
+ *
12
+ * @param context - le contexte à éprouver.
13
+ * @returns `true` si le contexte traite une connexion WebSocket (`ws` ou `wss`).
14
+ */
15
+ export declare function isWebsocketContext(context: ContextType): context is WebsocketContext;