@nodefony/http 10.0.0-alpha.8 → 10.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -0
- package/dist/_virtual/{_@oxc-project_runtime@0.150.0 → _@oxc-project_runtime@0.151.0}/helpers/esm/decorate.js +1 -1
- package/dist/_virtual/{_@oxc-project_runtime@0.150.0 → _@oxc-project_runtime@0.151.0}/helpers/esm/decorateMetadata.js +1 -1
- package/dist/_virtual/{_@oxc-project_runtime@0.150.0 → _@oxc-project_runtime@0.151.0}/helpers/esm/decorateParam.js +1 -1
- package/dist/index.js +6 -4
- package/dist/nodefony/command/assetsPublishCommand.js +1 -1
- package/dist/nodefony/command/certificatesCommand.js +1 -1
- package/dist/nodefony/command/networkCommand.js +1 -1
- package/dist/nodefony/command/proxyGenerateCommand.js +1 -1
- package/dist/nodefony/config/config.js +22 -1
- package/dist/nodefony/interfaces/IRouting.js +1 -0
- package/dist/nodefony/interfaces/ISecurity.js +1 -0
- package/dist/nodefony/service/ProfilerAdminApi.js +2 -1
- package/dist/nodefony/service/audit-logger.js +16 -13
- package/dist/nodefony/service/certificates.js +25 -13
- package/dist/nodefony/service/error-renderer.js +118 -5
- package/dist/nodefony/service/http-kernel.js +342 -165
- package/dist/nodefony/service/pretty-request-logger.js +3 -10
- package/dist/nodefony/service/servers/clientError.js +2 -2
- package/dist/nodefony/service/servers/server-http.js +23 -23
- package/dist/nodefony/service/servers/server-https.js +41 -42
- package/dist/nodefony/service/servers/server-static.js +13 -17
- package/dist/nodefony/service/servers/server-websocket-secure.js +11 -10
- package/dist/nodefony/service/servers/server-websocket.js +11 -10
- package/dist/nodefony/service/servers/wsHeartbeat.js +2 -2
- package/dist/nodefony/service/sessions/sessions-service.js +25 -17
- package/dist/nodefony/service/trace.js +1 -1
- package/dist/nodefony/service/upload/upload-service.js +11 -10
- package/dist/nodefony/src/assets/prebuiltUi.js +1 -1
- package/dist/nodefony/src/context/Context.js +34 -19
- package/dist/nodefony/src/context/forwarded.js +4 -4
- package/dist/nodefony/src/context/http/HttpContext.js +133 -88
- package/dist/nodefony/src/context/http/Request.js +93 -44
- package/dist/nodefony/src/context/http/Response.js +107 -51
- package/dist/nodefony/src/context/http/parser.js +9 -10
- package/dist/nodefony/src/context/http/urlFastPath.js +1 -2
- package/dist/nodefony/src/context/http2/Response.js +53 -25
- package/dist/nodefony/src/context/metaData.js +1 -1
- package/dist/nodefony/src/context/trustProxy.js +4 -3
- package/dist/nodefony/src/context/websocket/Response.js +13 -6
- package/dist/nodefony/src/context/websocket/WebsocketContext.js +59 -26
- package/dist/nodefony/src/context/websocket/wsCloseReason.js +41 -0
- package/dist/nodefony/src/cookies/cookie.js +3 -3
- package/dist/nodefony/src/errors/httpError.js +6 -6
- package/dist/nodefony/src/errors/thrownMessage.js +27 -0
- package/dist/nodefony/src/profiler/FrameProfile.js +4 -3
- package/dist/nodefony/src/profiler/Profiler.js +4 -4
- package/dist/nodefony/src/servers/kernelServers.js +29 -0
- package/dist/nodefony/src/servers/portBinder.js +8 -21
- package/dist/nodefony/src/session/session.js +18 -10
- package/dist/nodefony/src/session/sessionStoreFailure.js +2 -1
- package/dist/nodefony/src/session/storage/RevocationGuardStorage.js +24 -9
- package/dist/types/index.d.ts +16 -0
- package/dist/types/nodefony/config/config.d.ts +22 -0
- package/dist/types/nodefony/interfaces/IContext.d.ts +24 -7
- package/dist/types/nodefony/interfaces/ICookie.d.ts +18 -18
- package/dist/types/nodefony/interfaces/IHttpKernel.d.ts +10 -4
- package/dist/types/nodefony/interfaces/IResponse.d.ts +1 -1
- package/dist/types/nodefony/interfaces/IRouting.d.ts +87 -0
- package/dist/types/nodefony/interfaces/ISecurity.d.ts +45 -0
- package/dist/types/nodefony/interfaces/ISession.d.ts +8 -8
- package/dist/types/nodefony/interfaces/IUpload.d.ts +9 -9
- package/dist/types/nodefony/interfaces/index.d.ts +2 -0
- package/dist/types/nodefony/service/audit-logger.d.ts +14 -10
- package/dist/types/nodefony/service/certificates.d.ts +10 -10
- package/dist/types/nodefony/service/error-renderer.d.ts +14 -0
- package/dist/types/nodefony/service/http-kernel.d.ts +192 -42
- package/dist/types/nodefony/service/servers/server-http.d.ts +4 -1
- package/dist/types/nodefony/service/servers/server-https.d.ts +4 -1
- package/dist/types/nodefony/service/servers/server-websocket-secure.d.ts +4 -1
- package/dist/types/nodefony/service/servers/server-websocket.d.ts +4 -1
- package/dist/types/nodefony/service/sessions/sessions-service.d.ts +6 -2
- package/dist/types/nodefony/service/upload/upload-service.d.ts +1 -1
- package/dist/types/nodefony/src/context/Context.d.ts +21 -10
- package/dist/types/nodefony/src/context/forwarded.d.ts +3 -3
- package/dist/types/nodefony/src/context/http/HttpContext.d.ts +75 -18
- package/dist/types/nodefony/src/context/http/Request.d.ts +39 -2
- package/dist/types/nodefony/src/context/http/Response.d.ts +47 -7
- package/dist/types/nodefony/src/context/http/parser.d.ts +1 -1
- package/dist/types/nodefony/src/context/http2/Response.d.ts +32 -2
- package/dist/types/nodefony/src/context/websocket/Response.d.ts +4 -4
- package/dist/types/nodefony/src/context/websocket/WebsocketContext.d.ts +11 -2
- package/dist/types/nodefony/src/context/websocket/wsCloseReason.d.ts +21 -0
- package/dist/types/nodefony/src/cookies/cookie.d.ts +9 -9
- package/dist/types/nodefony/src/errors/httpError.d.ts +7 -7
- package/dist/types/nodefony/src/errors/thrownMessage.d.ts +12 -0
- package/dist/types/nodefony/src/profiler/Profiler.d.ts +28 -28
- package/dist/types/nodefony/src/servers/kernelServers.d.ts +20 -0
- package/dist/types/nodefony/src/servers/portBinder.d.ts +6 -19
- package/dist/types/nodefony/src/session/session.d.ts +12 -12
- package/dist/types/nodefony/src/session/storage/RevocationGuardStorage.d.ts +1 -1
- package/docs/cookies.md +25 -25
- package/docs/observabilite.md +30 -30
- package/docs/rate-limit.md +22 -22
- package/docs/servers.md +61 -61
- package/docs/session.md +82 -77
- package/docs/upload.md +43 -37
- package/package.json +11 -11
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ServerType, SchemeType } from "../../../service/http-kernel.js";
|
|
2
2
|
import Context, { HTTPMethod } from "../Context.js";
|
|
3
3
|
import { Container, Scope } from "nodefony";
|
|
4
|
-
import {
|
|
4
|
+
import type { MaybePromise } from "nodefony";
|
|
5
5
|
import HttpRequest from "./Request.js";
|
|
6
6
|
import HttpResponse from "./Response.js";
|
|
7
7
|
import Http2Request from "../http2/Request.js";
|
|
@@ -20,28 +20,26 @@ import uploadService from "../../../service/upload/upload-service.js";
|
|
|
20
20
|
* (logs, prédicat « derrière un proxy »).
|
|
21
21
|
*/
|
|
22
22
|
export interface ProxyType {
|
|
23
|
-
proxyServer?: string;
|
|
24
|
-
proxyProto?: string;
|
|
25
|
-
proxyScheme?: SchemeType;
|
|
26
|
-
proxyPort?: string;
|
|
27
|
-
proxyFor?: string;
|
|
28
|
-
proxyHost?: string;
|
|
29
|
-
proxyUri?: string;
|
|
30
|
-
proxyRealIp?: string;
|
|
31
|
-
proxyVia?: string;
|
|
23
|
+
proxyServer?: string | undefined;
|
|
24
|
+
proxyProto?: string | undefined;
|
|
25
|
+
proxyScheme?: SchemeType | undefined;
|
|
26
|
+
proxyPort?: string | undefined;
|
|
27
|
+
proxyFor?: string | undefined;
|
|
28
|
+
proxyHost?: string | undefined;
|
|
29
|
+
proxyUri?: string | undefined;
|
|
30
|
+
proxyRealIp?: string | undefined;
|
|
31
|
+
proxyVia?: string | undefined;
|
|
32
32
|
}
|
|
33
33
|
export type HttpRequestType = Http2Request | HttpRequest;
|
|
34
34
|
export type HttpRsponseType = Http2Response | HttpResponse;
|
|
35
35
|
import type { IHttpContext as IHttpContextInterface } from "../../../interfaces/IContext.js";
|
|
36
36
|
declare class HttpContext extends Context implements IHttpContextInterface {
|
|
37
|
-
#private;
|
|
38
37
|
proxy: ProxyType | null;
|
|
39
38
|
isRedirect: boolean;
|
|
40
39
|
sended: boolean;
|
|
41
40
|
request: HttpRequestType;
|
|
42
41
|
response: HttpRsponseType;
|
|
43
42
|
uploadService: uploadService | null;
|
|
44
|
-
csrf?: Csrf;
|
|
45
43
|
constructor(container: Container | Scope, request: http.IncomingMessage | http2.Http2ServerRequest, response: http.ServerResponse | http2.Http2ServerResponse, type: ServerType);
|
|
46
44
|
/**
|
|
47
45
|
* URL d'origine effective, construite À LA DEMANDE (1ʳᵉ lecture, puis
|
|
@@ -59,15 +57,74 @@ declare class HttpContext extends Context implements IHttpContextInterface {
|
|
|
59
57
|
*/
|
|
60
58
|
_onTimeout(): void;
|
|
61
59
|
setScheme(): SchemeType;
|
|
62
|
-
|
|
60
|
+
/**
|
|
61
|
+
* Sert la requête : délai de réponse, hooks `onRequest`, puis l'action
|
|
62
|
+
* résolue et son rendu (`resolver.callController()`).
|
|
63
|
+
*
|
|
64
|
+
* Pas `async` : synchrone quand l'action et son rendu le sont, rien n'y est
|
|
65
|
+
* alors attendu (#505).
|
|
66
|
+
*
|
|
67
|
+
* @returns ce que rend `callController()` — le résultat du rendu, pas le
|
|
68
|
+
* contexte (comportement historique, conservé) —, ou sa promesse. Sur une
|
|
69
|
+
* redirection déjà posée : le contexte, une fois l'envoi fait.
|
|
70
|
+
* @throws HttpError 404, de façon SYNCHRONE, quand aucune route ne résout.
|
|
71
|
+
*/
|
|
72
|
+
handle(): MaybePromise<this>;
|
|
63
73
|
setTimeout(): void;
|
|
64
|
-
|
|
74
|
+
/**
|
|
75
|
+
* Sérialise la donnée selon son type (JSON, HTML, texte), pose statut et
|
|
76
|
+
* en-têtes, puis l'envoie ({@link send}). Synchrone quand l'envoi l'est (#505).
|
|
77
|
+
*
|
|
78
|
+
* @returns la réponse, ou sa promesse.
|
|
79
|
+
* @throws de façon SYNCHRONE ce que lèvent la sérialisation ou l'envoi.
|
|
80
|
+
*/
|
|
81
|
+
render(chunk: unknown, encoding?: BufferEncoding, status?: string | number, headers?: Record<string, string | number>): MaybePromise<Http2Response | HttpResponse>;
|
|
65
82
|
end(): Promise<Http2Response | HttpResponse>;
|
|
66
|
-
|
|
83
|
+
/**
|
|
84
|
+
* Envoie la réponse : session sauvée, hook `onSend`, en-têtes, corps, puis
|
|
85
|
+
* fin de la réponse.
|
|
86
|
+
*
|
|
87
|
+
* Synchrone dans le cas nominal — aucune session ouverte, aucun écouteur
|
|
88
|
+
* `onSend`, réponse unique : rien n'y est à attendre (#505). Une promesse
|
|
89
|
+
* seulement quand une étape attend réellement (écriture du store de session,
|
|
90
|
+
* hook asynchrone, streaming chunké, flux HTTP/2).
|
|
91
|
+
*
|
|
92
|
+
* @param chunk - le corps ; absent, le corps déjà posé sur la réponse.
|
|
93
|
+
* @param encoding - l'encodage d'un corps texte.
|
|
94
|
+
* @returns la réponse, ou sa promesse.
|
|
95
|
+
* @throws de façon SYNCHRONE `Response Already sended` quand la réponse est
|
|
96
|
+
* déjà partie, et ce que lève une étape synchrone de l'envoi.
|
|
97
|
+
*/
|
|
98
|
+
send(chunk?: unknown, encoding?: BufferEncoding): MaybePromise<Http2Response | HttpResponse>;
|
|
99
|
+
/**
|
|
100
|
+
* Le travail de {@link send}, journalisé en ERROR quand il échoue — de façon
|
|
101
|
+
* synchrone ou par rejet, selon l'étape qui échoue.
|
|
102
|
+
*/
|
|
103
|
+
private doSend;
|
|
104
|
+
/** Session, puis hook `onSend`, puis en-têtes et corps — chacun attendu seulement s'il attend. */
|
|
105
|
+
private sendSteps;
|
|
106
|
+
/** Hook `onSend` (attendu seulement s'il a un écouteur), puis en-têtes et corps. */
|
|
107
|
+
private emitAndWrite;
|
|
108
|
+
/** En-têtes, puis corps — ou la seule fin de réponse pour une redirection. */
|
|
109
|
+
private writeHeadAndBody;
|
|
67
110
|
writeHead(statusCode?: number, headers?: http.OutgoingHttpHeaders | http.OutgoingHttpHeader[]): void;
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
111
|
+
/**
|
|
112
|
+
* Écrit le corps, puis termine la requête ({@link close}). Synchrone pour une
|
|
113
|
+
* réponse unique (#505).
|
|
114
|
+
*
|
|
115
|
+
* @returns la réponse, ou sa promesse quand l'écriture attend.
|
|
116
|
+
*/
|
|
117
|
+
write(chunk: unknown, encoding?: BufferEncoding, _flush?: boolean): MaybePromise<Http2Response | HttpResponse>;
|
|
118
|
+
flush(chunk: unknown, encoding: BufferEncoding): MaybePromise<HttpResponse>;
|
|
119
|
+
/**
|
|
120
|
+
* Termine la requête : hook `onClose`, puis fin de la réponse si l'envoi ne
|
|
121
|
+
* l'a pas déjà faite. Synchrone sans écouteur `onClose` (#505).
|
|
122
|
+
*
|
|
123
|
+
* @returns la réponse, ou sa promesse quand le hook attend.
|
|
124
|
+
*/
|
|
125
|
+
close(): MaybePromise<Http2Response | HttpResponse>;
|
|
126
|
+
/** Fin de la réponse, sauf si l'envoi l'a déjà terminée. */
|
|
127
|
+
private endResponse;
|
|
71
128
|
redirect(Url: string, status?: number | string, headers?: Record<string, string | number>): HttpResponse;
|
|
72
129
|
redirectHttps(status?: number | string, headers?: Record<string, string | number>): HttpResponse;
|
|
73
130
|
redirectHttp(status?: number | string, headers?: Record<string, string | number>): HttpResponse;
|
|
@@ -39,7 +39,7 @@ declare class HttpRequest {
|
|
|
39
39
|
host: string | undefined;
|
|
40
40
|
method: HTTPMethod;
|
|
41
41
|
contentType: string | null;
|
|
42
|
-
rawContentType: Record<string, string>;
|
|
42
|
+
rawContentType: Record<string, string | undefined>;
|
|
43
43
|
domain: string;
|
|
44
44
|
remoteAddress: string | null | undefined;
|
|
45
45
|
hostname: string;
|
|
@@ -116,7 +116,37 @@ declare class HttpRequest {
|
|
|
116
116
|
* `body` dans tout le framework, celui de l'écosystème et d'`IAdminRequest`.
|
|
117
117
|
*/
|
|
118
118
|
private fireRequestEnd;
|
|
119
|
-
|
|
119
|
+
/**
|
|
120
|
+
* Lit le corps de la requête, s'il y en a un, puis émet `onRequestEnd`.
|
|
121
|
+
*
|
|
122
|
+
* Le contrat de retour dit ce qui reste à ATTENDRE :
|
|
123
|
+
* - `undefined` — la méthode ne porte pas de corps (GET, HEAD, OPTIONS…) et
|
|
124
|
+
* aucun écouteur `onRequestEnd` ne rend de promesse : tout est fait, de
|
|
125
|
+
* façon SYNCHRONE ;
|
|
126
|
+
* - une `Promise` — le corps arrive du socket (POST, PUT, PATCH, DELETE), ou
|
|
127
|
+
* un écouteur `onRequestEnd` est à attendre. Sa valeur n'est consommée par
|
|
128
|
+
* personne : elle ne sert qu'au séquençage.
|
|
129
|
+
*
|
|
130
|
+
* L'appelant n'attend donc que ce qui attend vraiment
|
|
131
|
+
* (`const pending = request.initialize(); if (pending) await pending;`) : un
|
|
132
|
+
* `await` inconditionnel reportait le pipeline d'une micro-tâche, et la
|
|
133
|
+
* chaîne de promesses coûtait ~6 évènements asynchrones à un GET qui n'avait
|
|
134
|
+
* rien à lire (#505).
|
|
135
|
+
*
|
|
136
|
+
* Ne lève jamais de façon synchrone : un corps refusé (413) ou illisible rompt
|
|
137
|
+
* la promesse rendue, comme avant.
|
|
138
|
+
*
|
|
139
|
+
* @returns `undefined` quand tout est fait, sinon la promesse à attendre.
|
|
140
|
+
*/
|
|
141
|
+
initialize(): Promise<unknown> | undefined;
|
|
142
|
+
/**
|
|
143
|
+
* Fin d'une requête SANS corps à lire : la marque terminée et émet
|
|
144
|
+
* `onRequestEnd`. Synchrone — ne rend une promesse que lorsqu'un écouteur
|
|
145
|
+
* `onRequestEnd` est à attendre, ou quand l'émission lève (celle d'`onError`).
|
|
146
|
+
*
|
|
147
|
+
* @returns `undefined` quand tout est fait, sinon la promesse à attendre.
|
|
148
|
+
*/
|
|
149
|
+
private endWithoutBody;
|
|
120
150
|
/**
|
|
121
151
|
* B1 — Pré-contrôle de taille du corps via l'en-tête `Content-Length` :
|
|
122
152
|
* rejette en 413 (RFC 9110 §15.5.14 « Content Too Large ») AVANT toute lecture
|
|
@@ -126,6 +156,13 @@ declare class HttpRequest {
|
|
|
126
156
|
*
|
|
127
157
|
* @throws {HttpError} 413 si `Content-Length` dépasse `maxBodySize`.
|
|
128
158
|
*/
|
|
159
|
+
/**
|
|
160
|
+
* Lit le plafond du corps et les limites d'envoi tels que les voit CETTE
|
|
161
|
+
* requête : la configuration http, surchargée par le calque que la requête a
|
|
162
|
+
* pu poser avant la lecture du corps (`overlayConfig`, #494). Hors pipeline
|
|
163
|
+
* (aucun scope ouvert), la configuration du module telle quelle.
|
|
164
|
+
*/
|
|
165
|
+
private readBodyLimits;
|
|
129
166
|
private enforceBodyLimit;
|
|
130
167
|
parseRequest(): Promise<ParserType | null>;
|
|
131
168
|
/**
|
|
@@ -2,6 +2,7 @@ import http, { OutgoingHttpHeaders } 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
|
+
import type { MaybePromise } from "nodefony";
|
|
5
6
|
import Cookie from "../../cookies/cookie.js";
|
|
6
7
|
declare class HttpResponse {
|
|
7
8
|
#private;
|
|
@@ -11,10 +12,9 @@ declare class HttpResponse {
|
|
|
11
12
|
statusMessage: string;
|
|
12
13
|
flushing: boolean;
|
|
13
14
|
encoding: BufferEncoding;
|
|
14
|
-
body: Buffer | null;
|
|
15
15
|
contentType: string;
|
|
16
16
|
headers: http.OutgoingHttpHeaders;
|
|
17
|
-
timeout?: number;
|
|
17
|
+
timeout?: number | undefined;
|
|
18
18
|
cookies: Record<string, Cookie>;
|
|
19
19
|
constructor(response: http.ServerResponse | http2.Http2ServerResponse, context: HttpContext);
|
|
20
20
|
/**
|
|
@@ -24,6 +24,20 @@ declare class HttpResponse {
|
|
|
24
24
|
* l'ancienne pose au constructeur, sans le ping-pong set/remove/re-set.
|
|
25
25
|
*/
|
|
26
26
|
protected ensureContentTypeHeader(): void;
|
|
27
|
+
/**
|
|
28
|
+
* Corps de la réponse en octets. Un corps posé en texte n'est encodé qu'à la
|
|
29
|
+
* première lecture de cette propriété — l'envoi, lui, écrit le texte tel quel.
|
|
30
|
+
*/
|
|
31
|
+
get body(): Buffer | null;
|
|
32
|
+
set body(value: Buffer | null);
|
|
33
|
+
/**
|
|
34
|
+
* Corps tel qu'il part sur le fil : le texte s'il n'a jamais été encodé, sinon
|
|
35
|
+
* les octets — vide légal si rien n'a été posé (`write(null)` jetterait
|
|
36
|
+
* ERR_STREAM_NULL_VALUES).
|
|
37
|
+
*/
|
|
38
|
+
protected get payload(): string | Buffer;
|
|
39
|
+
/** Encodage à passer avec {@link payload} (ignoré par Node pour des octets). */
|
|
40
|
+
protected get payloadEncoding(): BufferEncoding;
|
|
27
41
|
clean(): void;
|
|
28
42
|
isHeaderSent(): boolean;
|
|
29
43
|
isHtml(): boolean;
|
|
@@ -50,15 +64,41 @@ declare class HttpResponse {
|
|
|
50
64
|
};
|
|
51
65
|
getStatusCode(): number;
|
|
52
66
|
getStatusMessage(code?: number | string): string;
|
|
53
|
-
|
|
67
|
+
/**
|
|
68
|
+
* Pose le corps de la réponse : texte gardé tel quel, octets copiés sur leur
|
|
69
|
+
* seule fenêtre, tout autre valeur sérialisée en JSON.
|
|
70
|
+
*
|
|
71
|
+
* @param ele - corps à envoyer.
|
|
72
|
+
* @param encoding - encodage d'un corps texte (défaut : `this.encoding`).
|
|
73
|
+
*/
|
|
74
|
+
setBody(ele: unknown, encoding?: BufferEncoding): void;
|
|
54
75
|
setLength(body?: string | NodeJS.ArrayBufferView | ArrayBuffer | SharedArrayBuffer): number;
|
|
55
76
|
writeHead(statusCode?: number, headers?: http.OutgoingHttpHeaders | http.OutgoingHttpHeader[]): void;
|
|
56
77
|
addTrailers(headers: http.OutgoingHttpHeaders): void;
|
|
57
|
-
flush(chunk: unknown, encoding: BufferEncoding):
|
|
58
|
-
|
|
59
|
-
|
|
78
|
+
flush(chunk: unknown, encoding: BufferEncoding): MaybePromise<HttpResponse>;
|
|
79
|
+
/**
|
|
80
|
+
* Écrit le corps sur le flux et, pour une réponse unique, la termine.
|
|
81
|
+
*
|
|
82
|
+
* Synchrone pour une réponse unique ou une redirection : `end(corps)` est un
|
|
83
|
+
* appel synchrone de Node, rien n'y est à attendre (#505). Une promesse
|
|
84
|
+
* seulement en streaming chunké (`flush()`), réglée quand le flux accepte
|
|
85
|
+
* l'écriture suivante (`drain`) — c'est la contre-pression.
|
|
86
|
+
*
|
|
87
|
+
* @param chunk - le corps (posé par `setBody`) ; absent, le corps déjà posé.
|
|
88
|
+
* @param encoding - l'encodage d'un corps texte.
|
|
89
|
+
* @returns la réponse, ou sa promesse en streaming chunké.
|
|
90
|
+
* @throws de façon SYNCHRONE quand la réponse Node n'existe plus.
|
|
91
|
+
*/
|
|
92
|
+
send(chunk?: unknown, encoding?: BufferEncoding, _flush?: boolean): MaybePromise<HttpResponse>;
|
|
93
|
+
write(chunk?: unknown, encoding?: BufferEncoding): MaybePromise<HttpResponse>;
|
|
60
94
|
writeContinue(): void | undefined;
|
|
61
|
-
|
|
95
|
+
/**
|
|
96
|
+
* Termine la réponse Node — un appel synchrone, rien n'y est à attendre (#505).
|
|
97
|
+
*
|
|
98
|
+
* @returns le flux terminé (valeur de `ServerResponse.end`).
|
|
99
|
+
* @throws de façon SYNCHRONE quand la réponse Node n'existe plus.
|
|
100
|
+
*/
|
|
101
|
+
end(chunk?: string | Buffer, encoding?: BufferEncoding): MaybePromise<http.ServerResponse | http2.ServerHttp2Stream>;
|
|
62
102
|
getHeader(name: string): string | number | string[] | undefined;
|
|
63
103
|
hasHeader(name: string): boolean;
|
|
64
104
|
getHeaders(): http.OutgoingHttpHeaders;
|
|
@@ -58,7 +58,7 @@ declare class ParserJson extends Parser {
|
|
|
58
58
|
type AcceptEntry = {
|
|
59
59
|
type: RegExp;
|
|
60
60
|
subtype: RegExp;
|
|
61
|
-
q?: number;
|
|
61
|
+
q?: number | undefined;
|
|
62
62
|
[key: string]: RegExp | number | string | undefined;
|
|
63
63
|
};
|
|
64
64
|
declare const acceptParser: (acc?: string) => AcceptEntry[];
|
|
@@ -1,7 +1,24 @@
|
|
|
1
1
|
import http2 from "node:http2";
|
|
2
|
+
import type { MaybePromise } from "nodefony";
|
|
2
3
|
import http from "node:http";
|
|
3
4
|
import HttpContext from "../http/HttpContext.js";
|
|
4
5
|
import HttpResponse from "../http/Response.js";
|
|
6
|
+
/**
|
|
7
|
+
* Compose les en-têtes d'une réponse HTTP/2 : ceux posés sur la réponse, puis
|
|
8
|
+
* ceux passés à `writeHead`, qui gagnent.
|
|
9
|
+
*
|
|
10
|
+
* Les clés sont ramenées en MINUSCULES : `getHeaders()` rend `content-type`,
|
|
11
|
+
* un contrôleur passe `Content-Type` — fusionnées telles quelles, les deux
|
|
12
|
+
* clés partaient ensemble et `stream.respond()` refusait la réponse
|
|
13
|
+
* (`ERR_HTTP2_HEADER_SINGLE_VALUE`), soit une 500 sur tout média servi en
|
|
14
|
+
* HTTP/2. HTTP/2 n'a de toute façon que des noms en minuscules (RFC 9113 §8.2.1).
|
|
15
|
+
*
|
|
16
|
+
* @param statusMessage - message de statut, recopié en `x-status-message`
|
|
17
|
+
* @param current - en-têtes déjà posés sur la réponse
|
|
18
|
+
* @param extra - en-têtes passés à `writeHead` (objet, ou liste plate clé/valeur)
|
|
19
|
+
* @returns les en-têtes à transmettre à `respond()`
|
|
20
|
+
*/
|
|
21
|
+
export declare function mergeResponseHeaders(statusMessage: string, current: http.OutgoingHttpHeaders, extra?: http.OutgoingHttpHeaders | http.OutgoingHttpHeader[]): http.OutgoingHttpHeaders;
|
|
5
22
|
declare class Http2Response extends HttpResponse {
|
|
6
23
|
statusCode: number;
|
|
7
24
|
stream: http2.ServerHttp2Stream | null;
|
|
@@ -9,8 +26,21 @@ declare class Http2Response extends HttpResponse {
|
|
|
9
26
|
constructor(response: http2.Http2ServerResponse, context: HttpContext);
|
|
10
27
|
isHeaderSent(): boolean;
|
|
11
28
|
writeHead(statusCode?: number, headers?: http.OutgoingHttpHeaders | http.OutgoingHttpHeader[]): void;
|
|
12
|
-
|
|
13
|
-
|
|
29
|
+
/**
|
|
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).
|
|
33
|
+
*
|
|
34
|
+
* @returns la réponse, ou sa promesse.
|
|
35
|
+
*/
|
|
36
|
+
send(chunk?: unknown, encoding?: BufferEncoding, _flush?: boolean): MaybePromise<Http2Response>;
|
|
37
|
+
/**
|
|
38
|
+
* Termine le flux HTTP/2 (ou la réponse de repli) — synchrone (#505).
|
|
39
|
+
*
|
|
40
|
+
* @returns le flux terminé.
|
|
41
|
+
* @throws de façon SYNCHRONE ce que lève la fin du flux.
|
|
42
|
+
*/
|
|
43
|
+
end(chunk?: string | Buffer, encoding?: BufferEncoding): MaybePromise<http.ServerResponse | http2.ServerHttp2Stream>;
|
|
14
44
|
getStatusMessage(code?: number | string): string;
|
|
15
45
|
getStatus(): {
|
|
16
46
|
code: number;
|
|
@@ -11,13 +11,13 @@ export type { IWsCookie } from "../../../interfaces/ICookie.js";
|
|
|
11
11
|
*/
|
|
12
12
|
export declare function isPeerGoneError(error: unknown): boolean;
|
|
13
13
|
declare class WebsocketResponse {
|
|
14
|
-
private context;
|
|
14
|
+
private readonly context;
|
|
15
15
|
statusCode: number;
|
|
16
16
|
body: Buffer | null;
|
|
17
17
|
encoding: BufferEncoding;
|
|
18
18
|
connection: Ws | null;
|
|
19
19
|
statusMessage: string;
|
|
20
|
-
webSocketVersion?: number;
|
|
20
|
+
webSocketVersion?: number | undefined;
|
|
21
21
|
cookies: Record<string, Cookie>;
|
|
22
22
|
constructor(connection: Ws | null, context: WebsocketContext);
|
|
23
23
|
log(pci: Pci, severity?: Severity, msgid?: Msgid, msg?: Message): import("nodefony").Pdu | undefined;
|
|
@@ -30,8 +30,8 @@ declare class WebsocketResponse {
|
|
|
30
30
|
*/
|
|
31
31
|
private logFirstDrop;
|
|
32
32
|
setBody(ele: string | NodeJS.ArrayBufferView | ArrayBuffer | SharedArrayBuffer, encoding?: BufferEncoding): Buffer<ArrayBufferLike> | null;
|
|
33
|
-
drop(reasonCode
|
|
34
|
-
close(reasonCode
|
|
33
|
+
drop(reasonCode?: number, description?: string): void;
|
|
34
|
+
close(reasonCode?: number, description?: string): void;
|
|
35
35
|
getStatus(): {
|
|
36
36
|
code: number;
|
|
37
37
|
message: string;
|
|
@@ -40,7 +40,7 @@ export default class WebsocketContext extends Context implements IWebsocketConte
|
|
|
40
40
|
#private;
|
|
41
41
|
request: WsIncomingMessage | null;
|
|
42
42
|
response: WebsocketResponse | null;
|
|
43
|
-
acceptedProtocol?: string;
|
|
43
|
+
acceptedProtocol?: string | undefined;
|
|
44
44
|
port: number | string;
|
|
45
45
|
rejected: boolean;
|
|
46
46
|
teardownWired: boolean;
|
|
@@ -59,7 +59,7 @@ export default class WebsocketContext extends Context implements IWebsocketConte
|
|
|
59
59
|
handle(data?: unknown[]): Promise<this>;
|
|
60
60
|
render(chunk: unknown, encoding?: BufferEncoding): Promise<WebsocketResponse>;
|
|
61
61
|
send(data?: string | Buffer | null, encoding?: BufferEncoding): Promise<WebsocketResponse>;
|
|
62
|
-
broadcast(data?: string | Buffer | null, encoding?: BufferEncoding):
|
|
62
|
+
broadcast(data?: string | Buffer | null, encoding?: BufferEncoding): null | undefined;
|
|
63
63
|
/**
|
|
64
64
|
* Logge le CONTENU d'un message WS (corrélé `requestId` via l'override `log`),
|
|
65
65
|
* gaté hors prod et borné — le Suivi de requête (Studio) le surface alors par
|
|
@@ -121,5 +121,14 @@ export default class WebsocketContext extends Context implements IWebsocketConte
|
|
|
121
121
|
clean(): void;
|
|
122
122
|
close(reasonCode: number | undefined | null, description: string): void;
|
|
123
123
|
drop(reasonCode: number, description: string): void;
|
|
124
|
+
/**
|
|
125
|
+
* Relit `rejected` sans le rétrécissement de TypeScript : après la garde
|
|
126
|
+
* d'entrée de {@link handle}, le compilateur le croit `false` pour toute la
|
|
127
|
+
* méthode, alors qu'un écouteur `onRequest` (pare-feu) ou le `match` du
|
|
128
|
+
* resolver peut avoir rejeté entre-temps.
|
|
129
|
+
*
|
|
130
|
+
* @returns `true` si la connexion a été rejetée.
|
|
131
|
+
*/
|
|
132
|
+
private isRejected;
|
|
124
133
|
reject(code: number | string | undefined, message?: string): void;
|
|
125
134
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Taille maximale, en octets UTF-8, de la raison d'une trame Close (RFC 6455
|
|
3
|
+
* §5.5 : charge d'une trame de contrôle ≤ 125 octets, dont 2 pour le code).
|
|
4
|
+
*/
|
|
5
|
+
export declare const MAX_WS_CLOSE_REASON_BYTES = 123;
|
|
6
|
+
/**
|
|
7
|
+
* Borne la raison d'une fermeture WebSocket à 123 octets UTF-8, coupée sur une
|
|
8
|
+
* frontière de caractère.
|
|
9
|
+
*
|
|
10
|
+
* `ws.close(code, reason)` LÈVE une `RangeError` au-delà de 123 octets, et la
|
|
11
|
+
* connexion n'est alors PAS fermée : jusqu'en `ws` 8.21 elle restait en
|
|
12
|
+
* `CLOSING` sans trame Close ni minuterie — hors de portée de toute garde
|
|
13
|
+
* `readyState === OPEN` et du heartbeat, donc ouverte jusqu'à la mort TCP ;
|
|
14
|
+
* depuis 8.22 elle reste `OPEN`. Or la raison porte souvent un message
|
|
15
|
+
* d'erreur, dont rien ne borne la longueur.
|
|
16
|
+
*
|
|
17
|
+
* @param reason - raison candidate (message d'erreur, libellé…)
|
|
18
|
+
* @returns la raison telle quelle si elle tient, sinon tronquée et terminée
|
|
19
|
+
* par « … » ; chaîne vide si elle n'est pas une chaîne.
|
|
20
|
+
*/
|
|
21
|
+
export declare function toWsCloseReason(reason: string | undefined | null): string;
|
|
@@ -24,17 +24,17 @@ declare function cookiesParser(context: ContextType): void;
|
|
|
24
24
|
declare class Cookie implements ICookieInterface {
|
|
25
25
|
options: CookieOptionsType;
|
|
26
26
|
name: string;
|
|
27
|
-
signed?: boolean;
|
|
27
|
+
signed?: boolean | undefined;
|
|
28
28
|
value: unknown;
|
|
29
|
-
originalMaxAge?: number;
|
|
30
|
-
expires?: Date;
|
|
31
|
-
maxAge?: number;
|
|
32
|
-
path?: string;
|
|
29
|
+
originalMaxAge?: number | undefined;
|
|
30
|
+
expires?: Date | undefined;
|
|
31
|
+
maxAge?: number | undefined;
|
|
32
|
+
path?: string | undefined;
|
|
33
33
|
domain: string | undefined;
|
|
34
|
-
httpOnly?: boolean;
|
|
35
|
-
secure?: boolean;
|
|
36
|
-
sameSite?: SameSiteType;
|
|
37
|
-
priority?: string;
|
|
34
|
+
httpOnly?: boolean | undefined;
|
|
35
|
+
secure?: boolean | undefined;
|
|
36
|
+
sameSite?: SameSiteType | undefined;
|
|
37
|
+
priority?: string | undefined;
|
|
38
38
|
constructor(cookies: Cookie);
|
|
39
39
|
constructor(name: string, value: unknown, options?: CookieOptionsType);
|
|
40
40
|
clearCookie(): void;
|
|
@@ -2,13 +2,13 @@ import { nodefonyError as NodefonyError } from "nodefony";
|
|
|
2
2
|
import { ContextType } from "../../service/http-kernel.js";
|
|
3
3
|
import { HttpRequestType, HttpRsponseType } from "../context/http/HttpContext.js";
|
|
4
4
|
declare class HttpError extends NodefonyError {
|
|
5
|
-
context?: ContextType;
|
|
6
|
-
response?: HttpRsponseType;
|
|
7
|
-
request?: HttpRequestType;
|
|
8
|
-
url?: string;
|
|
9
|
-
controller?: string;
|
|
10
|
-
action?: string;
|
|
11
|
-
jsonResponse?: string;
|
|
5
|
+
context?: ContextType | undefined;
|
|
6
|
+
response?: HttpRsponseType | undefined;
|
|
7
|
+
request?: HttpRequestType | undefined;
|
|
8
|
+
url?: string | undefined;
|
|
9
|
+
controller?: string | undefined;
|
|
10
|
+
action?: string | undefined;
|
|
11
|
+
jsonResponse?: string | undefined;
|
|
12
12
|
constructor(message?: unknown, code?: number, context?: ContextType);
|
|
13
13
|
toString(): string;
|
|
14
14
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Message lisible d'une valeur LEVÉE (`catch`, rejet) dont on ignore le type.
|
|
3
|
+
*
|
|
4
|
+
* Même rendu que `String(value)` pour une `Error` (son `message`) et pour les
|
|
5
|
+
* primitives ; un objet quelconque rend son étiquette (`[object Object]`) sans
|
|
6
|
+
* appeler un `toString` arbitraire ni sérialiser son contenu — ce texte peut
|
|
7
|
+
* finir dans une réponse ou un journal, il ne doit rien divulguer.
|
|
8
|
+
*
|
|
9
|
+
* @param value - la valeur levée.
|
|
10
|
+
* @returns un texte court, jamais vide pour une valeur définie.
|
|
11
|
+
*/
|
|
12
|
+
export declare function thrownMessage(value: unknown): string;
|
|
@@ -38,13 +38,13 @@ export interface ProfileQuery {
|
|
|
38
38
|
/** Requête (SQL ou commande NoSQL), tronquée si volumineuse. */
|
|
39
39
|
sql: string;
|
|
40
40
|
/** Début relatif (`performance.now()`) — même horloge que les phases. */
|
|
41
|
-
startMs?: number;
|
|
41
|
+
startMs?: number | undefined;
|
|
42
42
|
/** Durée d'exécution en ms. */
|
|
43
43
|
durationMs: number;
|
|
44
44
|
/** Lignes affectées/retournées, si connu. */
|
|
45
|
-
rows?: number;
|
|
45
|
+
rows?: number | undefined;
|
|
46
46
|
/** Connecteur émetteur (`drizzle`, `mongoose`…). */
|
|
47
|
-
connector?: string;
|
|
47
|
+
connector?: string | undefined;
|
|
48
48
|
}
|
|
49
49
|
/**
|
|
50
50
|
* Traversée du firewall par cette requête — **ce qui était possible** (la zone :
|
|
@@ -97,9 +97,9 @@ export interface ProfileEntry {
|
|
|
97
97
|
error: string | null;
|
|
98
98
|
phases: ProfilePhase[];
|
|
99
99
|
/** Requêtes ORM (SEAM futur — `undefined` tant qu'aucun adapter ne pushe). */
|
|
100
|
-
queries?: ProfileQuery[];
|
|
100
|
+
queries?: ProfileQuery[] | undefined;
|
|
101
101
|
/** Traversée du firewall — `undefined` si la requête n'a croisé aucune zone. */
|
|
102
|
-
security?: ProfileSecurity;
|
|
102
|
+
security?: ProfileSecurity | undefined;
|
|
103
103
|
}
|
|
104
104
|
/** Résumé léger d'un profil pour la liste `recent` (sans les phases). */
|
|
105
105
|
export interface ProfileSummary {
|
|
@@ -115,49 +115,49 @@ export interface ProfileSummary {
|
|
|
115
115
|
}
|
|
116
116
|
/** Forme structurelle minimale lue sur un `Context` (lecture défensive). */
|
|
117
117
|
interface ProfilableContext {
|
|
118
|
-
requestId?: string;
|
|
119
|
-
type?: string;
|
|
120
|
-
scheme?: string;
|
|
121
|
-
method?: string | null;
|
|
122
|
-
url?: string;
|
|
123
|
-
remoteAddress?: string | null;
|
|
124
|
-
traceparent?: string | null;
|
|
118
|
+
requestId?: string | undefined;
|
|
119
|
+
type?: string | undefined;
|
|
120
|
+
scheme?: string | undefined;
|
|
121
|
+
method?: string | null | undefined;
|
|
122
|
+
url?: string | undefined;
|
|
123
|
+
remoteAddress?: string | null | undefined;
|
|
124
|
+
traceparent?: string | null | undefined;
|
|
125
125
|
error?: {
|
|
126
126
|
message?: string;
|
|
127
|
-
} | null;
|
|
127
|
+
} | null | undefined;
|
|
128
128
|
response?: {
|
|
129
129
|
statusCode?: number;
|
|
130
|
-
} | null;
|
|
130
|
+
} | null | undefined;
|
|
131
131
|
phases?: ReadonlyArray<{
|
|
132
132
|
name: string;
|
|
133
133
|
startMs: number;
|
|
134
|
-
durationMs?: number;
|
|
135
|
-
}
|
|
134
|
+
durationMs?: number | undefined;
|
|
135
|
+
}> | undefined;
|
|
136
136
|
resolver?: {
|
|
137
137
|
route?: {
|
|
138
|
-
name?: string;
|
|
138
|
+
name?: string | undefined;
|
|
139
139
|
} | null;
|
|
140
140
|
controller?: {
|
|
141
|
-
name?: string;
|
|
142
|
-
} | null;
|
|
143
|
-
actionName?: string;
|
|
144
|
-
} | null;
|
|
141
|
+
name?: string | undefined;
|
|
142
|
+
} | null | undefined;
|
|
143
|
+
actionName?: string | undefined;
|
|
144
|
+
} | null | undefined;
|
|
145
145
|
/**
|
|
146
146
|
* Buffer de requêtes ORM rempli pendant la requête (dev-only). Même tableau
|
|
147
147
|
* que la payload ALS — les adapters ORM y poussent via `RequestContext`.
|
|
148
148
|
* `null`/absent hors profiling.
|
|
149
149
|
*/
|
|
150
|
-
profilerQueries?: ProfileQuery[] | null;
|
|
150
|
+
profilerQueries?: ProfileQuery[] | null | undefined;
|
|
151
151
|
/**
|
|
152
152
|
* Zone firewall capturée (`SecuredArea`, posée par `Firewall.isSecure`). Lue
|
|
153
153
|
* en structurel : `@nodefony/http` ne peut pas importer `@nodefony/security`.
|
|
154
154
|
*/
|
|
155
155
|
security?: {
|
|
156
|
-
name?: string;
|
|
157
|
-
security?: boolean;
|
|
158
|
-
mode?: string;
|
|
159
|
-
authenticators?: readonly string[];
|
|
160
|
-
} | null;
|
|
156
|
+
name?: string | undefined;
|
|
157
|
+
security?: boolean | undefined;
|
|
158
|
+
mode?: string | undefined;
|
|
159
|
+
authenticators?: readonly string[] | undefined;
|
|
160
|
+
} | null | undefined;
|
|
161
161
|
/** Décision du firewall sur cette requête (dev-only, cf `ISecurityTrace`). */
|
|
162
162
|
securityTrace?: {
|
|
163
163
|
authenticator: string | null;
|
|
@@ -165,7 +165,7 @@ interface ProfilableContext {
|
|
|
165
165
|
reason: string | null;
|
|
166
166
|
user: string | null;
|
|
167
167
|
roles: string[] | null;
|
|
168
|
-
} | null;
|
|
168
|
+
} | null | undefined;
|
|
169
169
|
}
|
|
170
170
|
export declare class Profiler {
|
|
171
171
|
private readonly _buf;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ServersConfig } from "nodefony";
|
|
2
|
+
/**
|
|
3
|
+
* Rétrécit la section `servers` de la configuration du kernel (lue dans le sac
|
|
4
|
+
* de config non typé du cœur) en {@link ServersConfig}, sans propager `any`.
|
|
5
|
+
*
|
|
6
|
+
* Seule lecture de `kernel.options.servers` dans `@nodefony/http` : les serveurs
|
|
7
|
+
* et le `HttpKernel` passent tous par ici.
|
|
8
|
+
*
|
|
9
|
+
* @param servers - la valeur brute de `kernel.options.servers`.
|
|
10
|
+
* @returns la section typée, ou `undefined` si elle est absente ou n'est pas un objet.
|
|
11
|
+
*/
|
|
12
|
+
export declare function asServersConfig(servers: unknown): ServersConfig | undefined;
|
|
13
|
+
/**
|
|
14
|
+
* Port DEMANDÉ pour un serveur (`servers.<type>.port`), ou `undefined` si le
|
|
15
|
+
* serveur est désactivé, absent, ou sans port numérique.
|
|
16
|
+
*
|
|
17
|
+
* @param servers - section `servers` déjà rétrécie ({@link asServersConfig}).
|
|
18
|
+
* @param type - le serveur visé.
|
|
19
|
+
*/
|
|
20
|
+
export declare function configuredServerPort(servers: ServersConfig | undefined, type: "http" | "https"): number | undefined;
|