@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.
- package/dist/_virtual/{_@oxc-project_runtime@0.153.0 → _@oxc-project_runtime@0.155.0}/helpers/esm/decorate.js +1 -2
- package/dist/_virtual/{_@oxc-project_runtime@0.153.0 → _@oxc-project_runtime@0.155.0}/helpers/esm/decorateParam.js +1 -2
- package/dist/index.js +13 -10
- package/dist/nodefony/command/assetsPublishCommand.js +5 -3
- package/dist/nodefony/command/certificatesCommand.js +5 -3
- package/dist/nodefony/command/networkCommand.js +5 -3
- package/dist/nodefony/command/proxyGenerateCommand.js +8 -3
- package/dist/nodefony/config/config.js +3 -3
- package/dist/nodefony/config/defineModuleConfig.js +1 -2
- package/dist/nodefony/interfaces/IRequestTrace.js +1 -0
- package/dist/nodefony/service/HttpAdminApi.js +2 -2
- package/dist/nodefony/service/ProfilerAdminApi.js +13 -3
- package/dist/nodefony/service/audit-logger.js +23 -30
- package/dist/nodefony/service/certificates.js +97 -13
- package/dist/nodefony/service/error-renderer.js +29 -12
- package/dist/nodefony/service/http-kernel.js +198 -50
- package/dist/nodefony/service/pretty-request-logger.js +15 -13
- package/dist/nodefony/service/request-logger.js +24 -16
- package/dist/nodefony/service/reverse-proxy.js +3 -3
- package/dist/nodefony/service/servers/clientError.js +22 -3
- package/dist/nodefony/service/servers/server-h2c.js +126 -0
- package/dist/nodefony/service/servers/server-http.js +5 -8
- package/dist/nodefony/service/servers/server-https.js +12 -24
- package/dist/nodefony/service/servers/server-static.js +3 -3
- package/dist/nodefony/service/servers/server-websocket-secure.js +10 -18
- package/dist/nodefony/service/servers/server-websocket.js +10 -18
- package/dist/nodefony/service/servers/serverShutdown.js +78 -18
- package/dist/nodefony/service/servers/wsHeartbeat.js +1 -2
- package/dist/nodefony/service/sessions/sessions-service.js +7 -14
- package/dist/nodefony/service/trace.js +1 -2
- package/dist/nodefony/service/upload/upload-service.js +5 -8
- package/dist/nodefony/service/x509.js +1 -2
- package/dist/nodefony/src/assets/collectAssets.js +1 -2
- package/dist/nodefony/src/assets/prebuiltUi.js +1 -2
- package/dist/nodefony/src/context/Context.js +78 -43
- package/dist/nodefony/src/context/domainMatcher.js +1 -2
- package/dist/nodefony/src/context/forwarded.js +1 -2
- package/dist/nodefony/src/context/http/HttpContext.js +28 -6
- package/dist/nodefony/src/context/http/Request.js +33 -29
- package/dist/nodefony/src/context/http/Response.js +23 -6
- package/dist/nodefony/src/context/http/SseStream.js +1 -2
- package/dist/nodefony/src/context/http/parser.js +36 -10
- package/dist/nodefony/src/context/http/urlFastPath.js +1 -2
- package/dist/nodefony/src/context/http2/Request.js +4 -8
- package/dist/nodefony/src/context/http2/Response.js +41 -9
- package/dist/nodefony/src/context/metaData.js +1 -2
- package/dist/nodefony/src/context/requestId.js +1 -2
- package/dist/nodefony/src/context/requestTrace.js +104 -0
- package/dist/nodefony/src/context/responseEnded.js +1 -2
- package/dist/nodefony/src/context/timingMode.js +21 -0
- package/dist/nodefony/src/context/transport.js +45 -0
- package/dist/nodefony/src/context/trustProxy.js +1 -2
- package/dist/nodefony/src/context/unsentResponse.js +30 -0
- package/dist/nodefony/src/context/websocket/Response.js +33 -6
- package/dist/nodefony/src/context/websocket/WebsocketContext.js +104 -25
- package/dist/nodefony/src/context/websocket/isWebsocketContext.js +17 -0
- package/dist/nodefony/src/context/websocket/websocketUrl.js +1 -2
- package/dist/nodefony/src/context/websocket/wsBackpressure.js +1 -2
- package/dist/nodefony/src/context/websocket/wsCloseReason.js +1 -2
- package/dist/nodefony/src/context/websocket/wsLogContent.js +1 -2
- package/dist/nodefony/src/cookies/cookie.js +3 -7
- package/dist/nodefony/src/errors/httpError.js +1 -2
- package/dist/nodefony/src/errors/thrownMessage.js +1 -2
- package/dist/nodefony/src/profiler/FrameProfile.js +23 -2
- package/dist/nodefony/src/profiler/Profiler.js +104 -32
- package/dist/nodefony/src/profiler/aggregate.js +442 -0
- package/dist/nodefony/src/proxy/forward.js +29 -5
- package/dist/nodefony/src/proxy/generateProxyConfig.js +14 -6
- package/dist/nodefony/src/proxy/rules.js +12 -6
- package/dist/nodefony/src/rateLimit/MemoryRateLimitStore.js +1 -2
- package/dist/nodefony/src/rateLimit/WsConnectionCounter.js +1 -2
- package/dist/nodefony/src/rateLimit/rateLimitFilters.js +1 -2
- package/dist/nodefony/src/servers/http2Limits.js +50 -0
- package/dist/nodefony/src/servers/kernelServers.js +12 -3
- package/dist/nodefony/src/servers/portBinder.js +41 -10
- package/dist/nodefony/src/servers/upgradeDispatch.js +86 -7
- package/dist/nodefony/src/session/session.js +2 -3
- package/dist/nodefony/src/session/sessionStoreFailure.js +1 -2
- package/dist/nodefony/src/session/storage/MemorySessionStorage.js +1 -2
- package/dist/nodefony/src/session/storage/RevocationGuardStorage.js +1 -2
- package/dist/nodefony/src/session/storage/sessionFilters.js +1 -2
- package/dist/nodefony/src/session/storage/sessionSort.js +1 -2
- package/dist/types/index.d.ts +9 -3
- package/dist/types/nodefony/config/config.d.ts +4 -0
- package/dist/types/nodefony/interfaces/IContext.d.ts +72 -4
- package/dist/types/nodefony/interfaces/IRequest.d.ts +9 -4
- package/dist/types/nodefony/interfaces/IRequestTrace.d.ts +56 -0
- package/dist/types/nodefony/interfaces/IReverseProxy.d.ts +8 -0
- package/dist/types/nodefony/interfaces/IRouting.d.ts +26 -0
- package/dist/types/nodefony/interfaces/index.d.ts +3 -2
- package/dist/types/nodefony/service/ProfilerAdminApi.d.ts +3 -0
- package/dist/types/nodefony/service/audit-logger.d.ts +3 -11
- package/dist/types/nodefony/service/certificates.d.ts +55 -4
- package/dist/types/nodefony/service/error-renderer.d.ts +31 -0
- package/dist/types/nodefony/service/http-kernel.d.ts +96 -10
- package/dist/types/nodefony/service/servers/clientError.d.ts +16 -0
- package/dist/types/nodefony/service/servers/server-h2c.d.ts +51 -0
- package/dist/types/nodefony/service/servers/server-http.d.ts +3 -3
- package/dist/types/nodefony/service/servers/server-https.d.ts +4 -4
- package/dist/types/nodefony/service/servers/server-websocket-secure.d.ts +1 -3
- package/dist/types/nodefony/service/servers/server-websocket.d.ts +1 -3
- package/dist/types/nodefony/service/servers/serverShutdown.d.ts +30 -16
- package/dist/types/nodefony/src/context/Context.d.ts +38 -5
- package/dist/types/nodefony/src/context/http/HttpContext.d.ts +16 -2
- package/dist/types/nodefony/src/context/http/Request.d.ts +20 -15
- package/dist/types/nodefony/src/context/http/Response.d.ts +11 -0
- package/dist/types/nodefony/src/context/http/parser.d.ts +18 -2
- package/dist/types/nodefony/src/context/http2/Request.d.ts +1 -1
- package/dist/types/nodefony/src/context/http2/Response.d.ts +27 -5
- package/dist/types/nodefony/src/context/requestTrace.d.ts +64 -0
- package/dist/types/nodefony/src/context/timingMode.d.ts +23 -0
- package/dist/types/nodefony/src/context/transport.d.ts +53 -0
- package/dist/types/nodefony/src/context/unsentResponse.d.ts +16 -0
- package/dist/types/nodefony/src/context/websocket/Response.d.ts +18 -2
- package/dist/types/nodefony/src/context/websocket/WebsocketContext.d.ts +58 -8
- package/dist/types/nodefony/src/context/websocket/isWebsocketContext.d.ts +15 -0
- package/dist/types/nodefony/src/profiler/FrameProfile.d.ts +28 -12
- package/dist/types/nodefony/src/profiler/Profiler.d.ts +79 -111
- package/dist/types/nodefony/src/profiler/aggregate.d.ts +132 -0
- package/dist/types/nodefony/src/proxy/forward.d.ts +14 -2
- package/dist/types/nodefony/src/proxy/generateProxyConfig.d.ts +16 -0
- package/dist/types/nodefony/src/proxy/rules.d.ts +3 -0
- package/dist/types/nodefony/src/servers/http2Limits.d.ts +37 -0
- package/dist/types/nodefony/src/servers/kernelServers.d.ts +10 -1
- package/dist/types/nodefony/src/servers/portBinder.d.ts +29 -5
- package/dist/types/nodefony/src/servers/upgradeDispatch.d.ts +33 -3
- package/docs/cookies.md +85 -78
- package/docs/diagnostics-channel.md +303 -0
- package/docs/index.md +6 -1
- package/docs/observabilite.md +159 -81
- package/docs/rate-limit.md +83 -83
- package/docs/reverse-proxy.md +72 -70
- package/docs/servers.md +338 -224
- package/docs/session.md +179 -179
- package/docs/sse.md +24 -20
- package/docs/upload.md +120 -117
- package/package.json +8 -9
- package/dist/_virtual/_@oxc-project_runtime@0.153.0/helpers/esm/decorateMetadata.js +0 -6
|
@@ -10,6 +10,9 @@ import type { Profiler } from "../src/profiler/Profiler.js";
|
|
|
10
10
|
*
|
|
11
11
|
* Endpoints :
|
|
12
12
|
* - `GET /nodefony/profiler/api/recent` → derniers profils (résumés, récent → ancien)
|
|
13
|
+
* `?connection=<requestId>` : les seules frames de cette socket WebSocket
|
|
14
|
+
* - `GET /nodefony/profiler/api/summary` → les profils de l'anneau agrégés par
|
|
15
|
+
* route (percentiles, phases, formes SQL, N+1, erreurs — `aggregateProfiles`)
|
|
13
16
|
* - `GET /nodefony/profiler/api/{id}` → profil complet (phases) d'un requestId
|
|
14
17
|
* - `DELETE /nodefony/profiler/api/recent` → vide le ring buffer
|
|
15
18
|
*
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Severity } from "nodefony";
|
|
2
2
|
import type { IRequestLogger, IRequestLogEntry } from "../interfaces/IRequestLogger.js";
|
|
3
|
-
import type { IHttpContext, IWebsocketContext
|
|
3
|
+
import type { IContext, IHttpContext, IWebsocketContext } from "../interfaces/IContext.js";
|
|
4
|
+
declare const statusOf: (context: IContext) => number | null;
|
|
4
5
|
/**
|
|
5
6
|
* Canonical audit log entry — 1 JSON PDU per request (P3.1).
|
|
6
7
|
*
|
|
@@ -52,15 +53,6 @@ export interface AuditErrorEntry {
|
|
|
52
53
|
/** Recursive — capped to depth 5 to avoid pathological cycles. */
|
|
53
54
|
cause?: AuditErrorEntry;
|
|
54
55
|
}
|
|
55
|
-
/**
|
|
56
|
-
* Durée totale de la requête, de la première phase (`startMs`) à maintenant.
|
|
57
|
-
* `null` si le chronométrage est coupé (aucune phase enregistrée). Partagée
|
|
58
|
-
* par le journal d'audit et le journal lisible — une seule définition.
|
|
59
|
-
*
|
|
60
|
-
* @param phases - phases chronométrées du contexte
|
|
61
|
-
* @returns durée en millisecondes, ou `null`
|
|
62
|
-
*/
|
|
63
|
-
declare function computeDurationMs(phases: PhaseTiming[]): number | null;
|
|
64
56
|
/**
|
|
65
57
|
* Severity derived from HTTP status code — RFC 9110 categories.
|
|
66
58
|
* 1xx/2xx/3xx → INFO ; 4xx → WARNING ; 5xx → ERROR.
|
|
@@ -145,4 +137,4 @@ declare class JsonAuditLogger implements IRequestLogger {
|
|
|
145
137
|
private serializeError;
|
|
146
138
|
}
|
|
147
139
|
export default JsonAuditLogger;
|
|
148
|
-
export {
|
|
140
|
+
export { severityFromStatus, statusOf };
|
|
@@ -61,27 +61,78 @@ export interface ICaFileTrust {
|
|
|
61
61
|
*
|
|
62
62
|
* @param file - chemin du fichier, absolu ou relatif à `root`
|
|
63
63
|
* @param root - racine de l'application
|
|
64
|
+
* Chaque refus dit le problème, d'où vient le chemin quand on le sait, puis le
|
|
65
|
+
* geste qui répare ({@link caFileRemedy}).
|
|
66
|
+
*
|
|
64
67
|
* @param store - accès aux ancres ; `node:tls` par défaut
|
|
68
|
+
* @param origin - phrase qui dit d'où vient le chemin (` Valeur venue de …`), insérée dans un refus
|
|
65
69
|
* @returns le bilan de l'ajout
|
|
66
70
|
* @throws BootConfigurationError - fichier illisible, sans certificat, ou Node
|
|
67
71
|
* incapable d'élargir ses ancres en cours d'exécution
|
|
68
72
|
*/
|
|
69
|
-
export declare function trustCaFile(file: string, root: string, store?: ITlsTrustStore): Promise<ICaFileTrust>;
|
|
73
|
+
export declare function trustCaFile(file: string, root: string, store?: ITlsTrustStore, origin?: string): Promise<ICaFileTrust>;
|
|
74
|
+
/**
|
|
75
|
+
* Le geste qui répare une autorité déclarée qu'on ne peut pas reconnaître.
|
|
76
|
+
*
|
|
77
|
+
* Un refus au démarrage qui ne dit que la cause envoie chercher ; celui-ci dit
|
|
78
|
+
* quoi faire. Pure : éprouvée cause par cause, y compris celles qu'une machine
|
|
79
|
+
* de test ne sait pas produire (un droit refusé ne l'est pas à `root`, ni
|
|
80
|
+
* sous Windows).
|
|
81
|
+
*
|
|
82
|
+
* @param cause - code système (`ENOENT`, `EACCES`, `EPERM`, `EISDIR`),
|
|
83
|
+
* `NOPEM` pour un fichier lu sans certificat, ou tout autre motif
|
|
84
|
+
* @returns la phrase du geste
|
|
85
|
+
*/
|
|
86
|
+
export declare function caFileRemedy(cause: string): string;
|
|
87
|
+
/**
|
|
88
|
+
* Dossier où Nodefony range les certificats qu'il fabrique en développement,
|
|
89
|
+
* relatif au répertoire courant.
|
|
90
|
+
*
|
|
91
|
+
* @returns le chemin absolu de `nodefony/config/certificates`
|
|
92
|
+
*/
|
|
93
|
+
export declare function certificatesDirectory(): string;
|
|
94
|
+
/**
|
|
95
|
+
* Chemin de l'autorité de DÉVELOPPEMENT : le certificat racine que Nodefony
|
|
96
|
+
* fabrique lui-même pour signer le certificat du serveur local. Généré, jamais
|
|
97
|
+
* versionné — une seule convention, que le service et la confiance sortante lisent.
|
|
98
|
+
*
|
|
99
|
+
* @param directory - dossier des certificats ; {@link certificatesDirectory} par défaut
|
|
100
|
+
* @returns le chemin absolu du fichier PEM de l'autorité
|
|
101
|
+
*/
|
|
102
|
+
export declare function developmentAuthorityPath(directory?: string): string;
|
|
103
|
+
/** Décor de {@link trustOutboundAuthorities} — injectable pour l'éprouver. */
|
|
104
|
+
export interface IOutboundTrustContext {
|
|
105
|
+
/** Vrai en développement : seul décor où l'autorité de dev absente est tolérée. */
|
|
106
|
+
readonly development?: boolean;
|
|
107
|
+
/** Chemin absolu de l'autorité de développement ; {@link developmentAuthorityPath} par défaut. */
|
|
108
|
+
readonly developmentAuthority?: string;
|
|
109
|
+
/** Environnement lu pour nommer la variable d'origine ; `process.env` par défaut. */
|
|
110
|
+
readonly env?: NodeJS.ProcessEnv;
|
|
111
|
+
/** Accès aux ancres ; `node:tls` par défaut. */
|
|
112
|
+
readonly store?: ITlsTrustStore;
|
|
113
|
+
}
|
|
70
114
|
/**
|
|
71
115
|
* Ajoute aux ancres TLS du processus les autorités déclarées
|
|
72
116
|
* (`certificates.extraCaFiles`), au plus tôt : appelé à l'enregistrement du
|
|
73
117
|
* module, avant tout service — toute requête sortante, commande console
|
|
74
118
|
* comprise, les trouve en place.
|
|
75
119
|
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
120
|
+
* L'autorité de DÉVELOPPEMENT déclarée mais pas encore engendrée est ignorée en
|
|
121
|
+
* développement, et le journal le dit : elle n'a signé aucun certificat, il n'y
|
|
122
|
+
* a donc rien à lui faire confiance, et le serveur de développement la pose
|
|
123
|
+
* lui-même quand il la fabrique ({@link Certificate.generateServerCertificates}).
|
|
124
|
+
* Rien n'est fabriqué ici : une commande console n'écrit pas de certificat.
|
|
125
|
+
* Une autre autorité absente, ou n'importe laquelle hors développement, reste
|
|
126
|
+
* un refus — qui nomme la variable d'origine et le geste qui répare
|
|
127
|
+
* ({@link caFileRemedy}).
|
|
78
128
|
*
|
|
79
129
|
* @param files - `certificates.extraCaFiles`
|
|
80
130
|
* @param root - racine de l'application
|
|
81
131
|
* @param log - journal du module
|
|
132
|
+
* @param context - décor (environnement, autorité de dev, ancres)
|
|
82
133
|
* @throws BootConfigurationError - cf {@link trustCaFile}
|
|
83
134
|
*/
|
|
84
|
-
export declare function trustOutboundAuthorities(files: readonly string[], root: string, log: (message: string, severity: "INFO") => void): Promise<void>;
|
|
135
|
+
export declare function trustOutboundAuthorities(files: readonly string[], root: string, log: (message: string, severity: "INFO") => void, context?: IOutboundTrustContext): Promise<void>;
|
|
85
136
|
/** Paire de clés RSA du certificat auto-signé. */
|
|
86
137
|
export interface IRsaKeyPair {
|
|
87
138
|
privateKey: KeyObject;
|
|
@@ -1,5 +1,36 @@
|
|
|
1
1
|
import type { IErrorRenderer, IErrorHttpResult, IErrorWebsocketResult } from "../interfaces/IErrorRenderer.js";
|
|
2
2
|
import type { IHttpContext, IWebsocketContext } from "../interfaces/IContext.js";
|
|
3
|
+
/** Champ fautif, tel qu'exposé au client dans le corps JSON (`error.fields`). */
|
|
4
|
+
export interface IValidationField {
|
|
5
|
+
/** Chemin pointé du champ (`"author.email"`). */
|
|
6
|
+
field: string;
|
|
7
|
+
/** Message lisible. */
|
|
8
|
+
message: string;
|
|
9
|
+
/** Contrôle qui a échoué (`too_small`…) — utile au client pour réagir finement. */
|
|
10
|
+
rule?: string | undefined;
|
|
11
|
+
/**
|
|
12
|
+
* Partie de l'entrée qui porte le champ (`body`, `query`, `params`,
|
|
13
|
+
* `headers`) — présente pour une route à schéma, où deux parties peuvent
|
|
14
|
+
* porter le même nom. `field` reste relatif à sa partie : un formulaire le
|
|
15
|
+
* relie à son champ de saisie sans rien retirer.
|
|
16
|
+
*/
|
|
17
|
+
in?: string | undefined;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Reconnaît une erreur de validation — `ZodError`, ou `SchemaValidationError`
|
|
21
|
+
* d'une route à schéma — et en extrait les champs fautifs.
|
|
22
|
+
*
|
|
23
|
+
* Reconnaissance **structurelle** (`name` + `issues`), pas `instanceof ZodError` :
|
|
24
|
+
* une application peut embarquer sa propre copie de zod (résolutions npm multiples),
|
|
25
|
+
* et `instanceof` échouerait alors en silence — la validation retomberait en 500.
|
|
26
|
+
* Même parti-pris que le duck-typing de `isPromise` dans le framework.
|
|
27
|
+
*
|
|
28
|
+
* Ne coûte rien au chemin nominal : ce code ne tourne que sur une erreur déjà levée.
|
|
29
|
+
*
|
|
30
|
+
* @param error - erreur remontée par le pipeline.
|
|
31
|
+
* @returns les champs fautifs, ou `null` si ce n'est pas une erreur de validation.
|
|
32
|
+
*/
|
|
33
|
+
export declare function toValidationFields(error: Error): IValidationField[] | null;
|
|
3
34
|
/**
|
|
4
35
|
* Reconnaît un identifiant MAL FORMÉ refusé par la base, et rend la valeur fautive.
|
|
5
36
|
*
|
|
@@ -11,11 +11,13 @@ import type { IncomingHttpHeaders, IncomingMessage } from "node:http";
|
|
|
11
11
|
import Ws from "ws";
|
|
12
12
|
import httpServer from "../service/servers/server-http.js";
|
|
13
13
|
import httpsServer from "../service/servers/server-https.js";
|
|
14
|
+
import h2cServer from "../service/servers/server-h2c.js";
|
|
14
15
|
import websocketServer from "../service/servers/server-websocket.js";
|
|
15
16
|
import websocketSecureServer from "../service/servers/server-websocket-secure.js";
|
|
16
17
|
import Statics from "./servers/server-static.js";
|
|
17
18
|
import type ReverseProxy from "./reverse-proxy.js";
|
|
18
19
|
import WebsocketContext from "../src/context/websocket/WebsocketContext.js";
|
|
20
|
+
import type { IUpgradeAdmission } from "../src/servers/upgradeDispatch.js";
|
|
19
21
|
import HttpContext from "../src/context/http/HttpContext.js";
|
|
20
22
|
import Context, { HTTPMethod, WebSocketState } from "../src/context/Context.js";
|
|
21
23
|
import Certicates from "./certificates.js";
|
|
@@ -42,9 +44,8 @@ export type httpRequest = http.IncomingMessage | http2.Http2ServerRequest;
|
|
|
42
44
|
export type httpResponse = http.ServerResponse | http2.Http2ServerResponse;
|
|
43
45
|
export { responseEnded } from "../src/context/responseEnded.js";
|
|
44
46
|
export type ContextType = WebsocketContext | HttpContext | Context;
|
|
45
|
-
export type ServerType
|
|
46
|
-
|
|
47
|
-
export type SchemeType = "http" | "https" | "ws" | "wss";
|
|
47
|
+
export type { ServerType, SchemeType } from "../interfaces/IContext.js";
|
|
48
|
+
import type { ServerType, SchemeType } from "../interfaces/IContext.js";
|
|
48
49
|
export interface WsMetaData {
|
|
49
50
|
type?: "message" | "handshake" | undefined;
|
|
50
51
|
state?: WebSocketState | undefined;
|
|
@@ -119,8 +120,6 @@ declare class HttpKernel extends Service implements IHttpKernelInterface {
|
|
|
119
120
|
responseTimeout: {
|
|
120
121
|
http: number;
|
|
121
122
|
https: number;
|
|
122
|
-
http2: number;
|
|
123
|
-
http3: number;
|
|
124
123
|
};
|
|
125
124
|
closeTimeOutWs: {
|
|
126
125
|
ws: number;
|
|
@@ -135,6 +134,8 @@ declare class HttpKernel extends Service implements IHttpKernelInterface {
|
|
|
135
134
|
private errorRenderer;
|
|
136
135
|
private requestLogger;
|
|
137
136
|
private profiler;
|
|
137
|
+
/** `timing.tooling` : profiler aussi l'outillage (lu une fois, à onReady). */
|
|
138
|
+
private profileTooling;
|
|
138
139
|
private _trustProxyChecker;
|
|
139
140
|
private _wsOriginPolicy;
|
|
140
141
|
private rateLimiter;
|
|
@@ -187,6 +188,32 @@ declare class HttpKernel extends Service implements IHttpKernelInterface {
|
|
|
187
188
|
* tel quel plutôt que d'inventer un état.
|
|
188
189
|
*/
|
|
189
190
|
get rateLimitStore(): IRateLimitStore | null;
|
|
191
|
+
/**
|
|
192
|
+
* Cette requête — ou cette frame du pont — se profile-t-elle ? Jamais sans
|
|
193
|
+
* profileur (production). L'outillage (console, profileur, journaux, Vite :
|
|
194
|
+
* `isProfiledUrl`, sur la règle `isConsolePath` du cœur) seulement sous
|
|
195
|
+
* `timing.tooling` — on ne
|
|
196
|
+
* mesure pas la façon dont on mesure : ni tampon SQL, ni instantané, ni place
|
|
197
|
+
* dans les anneaux du profileur.
|
|
198
|
+
*
|
|
199
|
+
* @param url - URL ou chemin de la requête
|
|
200
|
+
* @returns `true` quand le profil doit être pris
|
|
201
|
+
*/
|
|
202
|
+
shouldProfile(url: string): boolean;
|
|
203
|
+
/**
|
|
204
|
+
* En développement, signale une action qui a rendu une valeur que le
|
|
205
|
+
* Resolver ne sait pas envoyer (`null`, `undefined`, instance de classe)
|
|
206
|
+
* et n'a rien envoyé elle-même : la requête attend son délai d'expiration.
|
|
207
|
+
* Le message nomme l'action, ce qu'elle a rendu et le geste qui convient
|
|
208
|
+
* (`unsentResponseWarning`).
|
|
209
|
+
*
|
|
210
|
+
* Appelé au timeout, AVANT que le 504/408 parte — après, `sended` est vrai et
|
|
211
|
+
* plus rien ne se signalerait — et au démontage, pour un client parti avant.
|
|
212
|
+
* Gratuit en production : rien n'est lu au-delà de `waitAsync`.
|
|
213
|
+
*
|
|
214
|
+
* @param context - le contexte HTTP de la requête
|
|
215
|
+
*/
|
|
216
|
+
warnUnsentResponse(context: HttpContext): void;
|
|
190
217
|
private configureRateLimit;
|
|
191
218
|
/**
|
|
192
219
|
* (Re)configure le backstop OPT-IN de connexions WS concurrentes par IP (F6c)
|
|
@@ -383,7 +410,7 @@ declare class HttpKernel extends Service implements IHttpKernelInterface {
|
|
|
383
410
|
* pipeline.
|
|
384
411
|
*/
|
|
385
412
|
private dispatchHttpRequest;
|
|
386
|
-
initServers(): Promise<(httpServer | httpsServer | websocketServer | websocketSecureServer)[]>;
|
|
413
|
+
initServers(): Promise<(httpServer | httpsServer | h2cServer | websocketServer | websocketSecureServer)[]>;
|
|
387
414
|
/**
|
|
388
415
|
* Publie les ports EFFECTIFS du runtime (state file), une fois l'écoute établie.
|
|
389
416
|
*
|
|
@@ -475,6 +502,18 @@ declare class HttpKernel extends Service implements IHttpKernelInterface {
|
|
|
475
502
|
* @returns le contexte servi, ou sa promesse.
|
|
476
503
|
*/
|
|
477
504
|
handleHttp(scope: Scope, request: httpRequest, response: httpResponse, type: ServerType): MaybePromise<HttpContext>;
|
|
505
|
+
/**
|
|
506
|
+
* Sert un contexte HTTP fraîchement créé : le crochet `onCreateContext`
|
|
507
|
+
* s'il a des écouteurs, puis le pipeline.
|
|
508
|
+
*
|
|
509
|
+
* Hot path : `fireAsync` est une fonction async → 1 Promise + 1 microtask
|
|
510
|
+
* MÊME à 0 listener. En prod sans @nodefony/security ces seams
|
|
511
|
+
* (onCreateContext/beforeResolve/afterAuth) n'ont aucun listener → garde
|
|
512
|
+
* `listenerCount` (O(1), 0 alloc) pour ne RIEN planifier.
|
|
513
|
+
*
|
|
514
|
+
* @returns le contexte servi, ou sa promesse
|
|
515
|
+
*/
|
|
516
|
+
private dispatchHttpContext;
|
|
478
517
|
/**
|
|
479
518
|
* Traceparent, tampon du profileur, puis le pipeline dans la bulle ALS de la
|
|
480
519
|
* requête (`RequestContext.run`).
|
|
@@ -542,7 +581,7 @@ declare class HttpKernel extends Service implements IHttpKernelInterface {
|
|
|
542
581
|
* @throws (rejet) le refus du pare-feu, après `onAuthFailure`.
|
|
543
582
|
*/
|
|
544
583
|
private runFirewall;
|
|
545
|
-
createWebsocketContext(scope: Scope, req: IncomingMessage, ws: Ws, type: ServerType): WebsocketContext;
|
|
584
|
+
createWebsocketContext(scope: Scope, req: IncomingMessage, ws: Ws | null, type: ServerType): WebsocketContext;
|
|
546
585
|
/**
|
|
547
586
|
* Teardown d'une connexion WS à sa fermeture : signal d'abandon, hooks
|
|
548
587
|
* post-réponse, persistance de la session, puis libération du scope.
|
|
@@ -550,10 +589,57 @@ declare class HttpKernel extends Service implements IHttpKernelInterface {
|
|
|
550
589
|
* écouteur d'événement synchrone, qui n'attend rien).
|
|
551
590
|
*/
|
|
552
591
|
private finishWebsocket;
|
|
553
|
-
|
|
554
|
-
|
|
592
|
+
/**
|
|
593
|
+
* Point d'entrée d'un upgrade vers une route WebSocket de Nodefony, appelé
|
|
594
|
+
* par le répartiteur d'upgrade AVANT le `101` (#596) : rien ne s'ouvre tant
|
|
595
|
+
* que le pipeline n'a pas dit oui.
|
|
596
|
+
*
|
|
597
|
+
* Les bornes par IP passent en premier, avant tout scope, ALS ou pipeline
|
|
598
|
+
* (symétrie avec le 429 HTTP et avec le proxy inverse) : le vrai vecteur DoS
|
|
599
|
+
* est d'accumuler des sockets ouvertes. La place est rendue à la fermeture du
|
|
600
|
+
* socket du client — même règle que pour un tunnel relayé.
|
|
601
|
+
*
|
|
602
|
+
* @param req - requête d'upgrade
|
|
603
|
+
* @param admission - le verdict à rendre : accepter (`101`) ou refuser (HTTP)
|
|
604
|
+
* @param type - serveur qui a reçu l'upgrade
|
|
605
|
+
* @returns la promesse du traitement de la connexion
|
|
606
|
+
*/
|
|
607
|
+
onWebsocketUpgrade(req: IncomingMessage, admission: IUpgradeAdmission, type: ServerType): Promise<unknown>;
|
|
608
|
+
/**
|
|
609
|
+
* Pipeline d'un handshake WebSocket, dans la bulle ALS de la connexion :
|
|
610
|
+
* jugement (`onConnect`), pare-feu, gardes de l'action — PUIS seulement
|
|
611
|
+
* l'acceptation, la socket et l'action de handshake. Tout refus antérieur à
|
|
612
|
+
* l'acceptation part en statut HTTP (`onError` → `refuseHandshake`).
|
|
613
|
+
*
|
|
614
|
+
* @param scope - scope DI de la connexion
|
|
615
|
+
* @param req - requête d'upgrade
|
|
616
|
+
* @param admission - le verdict à rendre
|
|
617
|
+
* @param type - serveur qui a reçu l'upgrade
|
|
618
|
+
* @returns ce que rend l'action de handshake
|
|
619
|
+
*/
|
|
620
|
+
handleWebsocket(scope: Scope, req: IncomingMessage, admission: IUpgradeAdmission, type: ServerType): Promise<unknown>;
|
|
621
|
+
/**
|
|
622
|
+
* Fin du canal `nodefony.http.request` pour un handshake interrompu par une
|
|
623
|
+
* exception — sans effet si un refus l'a déjà publiée (`refuseHandshake`).
|
|
624
|
+
* Le statut est un fait, pas une déduction : une socket rattachée dit que
|
|
625
|
+
* le `101` est parti ; sinon c'est le `500` du filet qui a été rendu.
|
|
626
|
+
*
|
|
627
|
+
* @param context - le contexte du handshake, `null` s'il n'a pu être construit
|
|
628
|
+
* @param error - l'exception qui a interrompu le pipeline
|
|
629
|
+
*/
|
|
630
|
+
private closeFailedWebsocketTrace;
|
|
555
631
|
private releaseOrphanWsScope;
|
|
556
|
-
|
|
632
|
+
/**
|
|
633
|
+
* Juge un handshake WebSocket AVANT son acceptation : hôte, origine,
|
|
634
|
+
* `beforeResolve`, contrôleur (protocole négocié), session. N'ouvre rien —
|
|
635
|
+
* l'acceptation n'a lieu qu'après le pare-feu et les gardes de l'action
|
|
636
|
+
* (cf {@link handleWebsocket}).
|
|
637
|
+
*
|
|
638
|
+
* @param context - contexte du handshake, encore sans socket
|
|
639
|
+
* @param error - erreur levée à la construction du contexte, relancée telle quelle
|
|
640
|
+
* @throws la première erreur du jugement — rendue en statut HTTP par `onError`
|
|
641
|
+
*/
|
|
642
|
+
onConnect(context: WebsocketContext | null, error?: unknown): Promise<void>;
|
|
557
643
|
checkValidDomain(context: ContextType): number;
|
|
558
644
|
isValidDomain(context: ContextType): boolean;
|
|
559
645
|
/**
|
|
@@ -12,3 +12,19 @@ import type { Duplex } from "node:stream";
|
|
|
12
12
|
* @param socket - flux client brut (l'event `clientError` fournit un `Duplex`).
|
|
13
13
|
*/
|
|
14
14
|
export declare function handleClientError(error: NodeJS.ErrnoException, socket: Duplex): void;
|
|
15
|
+
/**
|
|
16
|
+
* Gère l'event `sessionError` d'un serveur HTTP/2 (h2c ou TLS) : un pair PARTI
|
|
17
|
+
* se tait, toute autre erreur est rapportée.
|
|
18
|
+
*
|
|
19
|
+
* Une session réinitialisée par le pair n'a rien à diagnostiquer. C'est la
|
|
20
|
+
* signature d'une sonde de port — `nodefony status`, `doctor`, le superviseur
|
|
21
|
+
* de développement, la sonde `tcpSocket` d'un orchestrateur — qui se connecte
|
|
22
|
+
* puis ferme sans lire le `SETTINGS` que le serveur envoie dès l'ouverture : le
|
|
23
|
+
* système ferme alors par un RST plutôt qu'un FIN, et Node lève `ECONNRESET`.
|
|
24
|
+
* La rapporter imprimait une pile entière par sonde. La règle « client parti »
|
|
25
|
+
* est celle des frames WebSocket ({@link isPeerGoneError}), pas une copie.
|
|
26
|
+
*
|
|
27
|
+
* @param error - erreur de session émise par `node:http2`
|
|
28
|
+
* @param report - rapporte une erreur réelle, à la sévérité choisie par le serveur
|
|
29
|
+
*/
|
|
30
|
+
export declare function handleSessionError(error: Error, report: (error: Error) => void): void;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { Service, type Module, FamilyType } from "nodefony";
|
|
2
|
+
import HttpKernel, { ProtocolType, ServerType, SchemeType } from "../http-kernel.js";
|
|
3
|
+
import http2 from "node:http2";
|
|
4
|
+
import { AddressInfo } from "node:net";
|
|
5
|
+
import { type IDrainTerminator } from "./serverShutdown.js";
|
|
6
|
+
import type { IHttpConfig } from "../../config/config.js";
|
|
7
|
+
import type { DefaultOptionsService } from "nodefony";
|
|
8
|
+
/**
|
|
9
|
+
* Serveur HTTP/2 en clair (h2c, connaissance préalable — RFC 9113 §3.3), sur un
|
|
10
|
+
* port DÉDIÉ (`servers.h2c`, 5153 par défaut), pour un proxy inverse qui parle
|
|
11
|
+
* HTTP/2 à ses amonts.
|
|
12
|
+
*
|
|
13
|
+
* Il partage le chemin HTTP/2 du 5152 — même `onHttpRequest`, mêmes limites
|
|
14
|
+
* anti-DoS (`http2ServerLimits`), même drain par GOAWAY — sans TLS : `serverType`
|
|
15
|
+
* vaut `"http"`, le schéma vient du transport ou d'un proxy de confiance, jamais
|
|
16
|
+
* du pseudo-en-tête `:scheme`. Le protocole du saut (`"h2c"`) se constate sur la
|
|
17
|
+
* requête (`transport.ts#alpnProtocolOf`).
|
|
18
|
+
*
|
|
19
|
+
* Hors de son périmètre, délibérément : HTTP/1.1 (refusé par la préface HTTP/2 —
|
|
20
|
+
* sondes et clients HTTP/1.1 restent sur le port HTTP), WebSocket (aucun CONNECT
|
|
21
|
+
* étendu, RFC 8441 : un proxy route `Upgrade: websocket` vers le port HTTP) et la
|
|
22
|
+
* bascule `Upgrade: h2c` (retirée par RFC 9113 §3.1).
|
|
23
|
+
*/
|
|
24
|
+
declare class ServerH2c extends Service {
|
|
25
|
+
private readonly httpKernel;
|
|
26
|
+
options: IHttpConfig["http"] & DefaultOptionsService;
|
|
27
|
+
module: Module<IHttpConfig>;
|
|
28
|
+
server: http2.Http2Server | null;
|
|
29
|
+
httpTerminator: IDrainTerminator | null;
|
|
30
|
+
port: number;
|
|
31
|
+
protocol: ProtocolType;
|
|
32
|
+
ready: boolean;
|
|
33
|
+
type: ServerType;
|
|
34
|
+
domain: string | null;
|
|
35
|
+
scheme: SchemeType;
|
|
36
|
+
address: string | null;
|
|
37
|
+
family: FamilyType | null;
|
|
38
|
+
active: boolean;
|
|
39
|
+
infos: AddressInfo | null;
|
|
40
|
+
constructor(module: Module<IHttpConfig>, httpKernel: HttpKernel);
|
|
41
|
+
/**
|
|
42
|
+
* Crée et met en écoute le serveur h2c.
|
|
43
|
+
*
|
|
44
|
+
* @returns le serveur à l'écoute
|
|
45
|
+
* @throws BootConfigurationError si `servers.h2c.port` est celui du serveur
|
|
46
|
+
* HTTP ou HTTPS — un port partagé n'est pas un conflit à contourner
|
|
47
|
+
*/
|
|
48
|
+
createServer(): Promise<http2.Http2Server>;
|
|
49
|
+
showBanner(): void;
|
|
50
|
+
}
|
|
51
|
+
export default ServerH2c;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { Service, Module, FamilyType } from "nodefony";
|
|
1
|
+
import { Service, type Module, FamilyType } from "nodefony";
|
|
2
2
|
import HttpKernel, { ProtocolType, ServerType, SchemeType } from "../http-kernel.js";
|
|
3
3
|
import http from "node:http";
|
|
4
4
|
import http2 from "node:http2";
|
|
5
5
|
import { AddressInfo } from "node:net";
|
|
6
|
-
import {
|
|
6
|
+
import { type IDrainTerminator } from "./serverShutdown.js";
|
|
7
7
|
import type { IHttpConfig } from "../../config/config.js";
|
|
8
8
|
import type { DefaultOptionsService } from "nodefony";
|
|
9
9
|
declare class ServerHttp extends Service {
|
|
@@ -11,7 +11,7 @@ declare class ServerHttp extends Service {
|
|
|
11
11
|
options: IHttpConfig["http"] & DefaultOptionsService;
|
|
12
12
|
module: Module;
|
|
13
13
|
server: http.Server | http2.Http2Server | null;
|
|
14
|
-
httpTerminator:
|
|
14
|
+
httpTerminator: IDrainTerminator | null;
|
|
15
15
|
port: number;
|
|
16
16
|
protocol: ProtocolType;
|
|
17
17
|
ready: boolean;
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import { Service, Module, FamilyType } from "nodefony";
|
|
1
|
+
import { Service, type Module, FamilyType } from "nodefony";
|
|
2
2
|
import HttpKernel, { ProtocolType, ServerType, SchemeType } from "../http-kernel.js";
|
|
3
3
|
import https from "node:https";
|
|
4
4
|
import http2 from "node:http2";
|
|
5
|
-
import {
|
|
5
|
+
import { type IDrainTerminator } from "./serverShutdown.js";
|
|
6
6
|
import { AddressInfo } from "node:net";
|
|
7
7
|
import type { IHttpConfig } from "../../config/config.js";
|
|
8
8
|
import type { DefaultOptionsService } from "nodefony";
|
|
9
9
|
declare class ServerHttps extends Service {
|
|
10
10
|
private readonly httpKernel;
|
|
11
11
|
options: IHttpConfig["https"] & DefaultOptionsService;
|
|
12
|
-
httpTerminator:
|
|
12
|
+
httpTerminator: IDrainTerminator | null;
|
|
13
13
|
module: Module;
|
|
14
14
|
server: https.Server | http2.Http2SecureServer | null;
|
|
15
15
|
port: number;
|
|
@@ -23,7 +23,7 @@ declare class ServerHttps extends Service {
|
|
|
23
23
|
active: boolean;
|
|
24
24
|
infos: AddressInfo | null;
|
|
25
25
|
constructor(module: Module, httpKernel: HttpKernel);
|
|
26
|
-
terminator():
|
|
26
|
+
terminator(): IDrainTerminator;
|
|
27
27
|
setPort(): number;
|
|
28
28
|
createServer(): Promise<https.Server | http2.Http2SecureServer>;
|
|
29
29
|
createServerH2(): Promise<http2.Http2SecureServer>;
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { WebSocketServer } from "ws";
|
|
2
2
|
import { Service, Module, FamilyType } from "nodefony";
|
|
3
3
|
import type { DefaultOptionsService } from "nodefony";
|
|
4
4
|
import type { IHttpConfig } from "../../config/config.js";
|
|
5
5
|
import HttpKernel, { ProtocolType, ServerType, SchemeType } from "../http-kernel.js";
|
|
6
6
|
import { AddressInfo } from "node:net";
|
|
7
|
-
import type { IncomingMessage } from "node:http";
|
|
8
7
|
import httpsServers from "./server-https.js";
|
|
9
8
|
declare class WebsocketSecure extends Service {
|
|
10
9
|
#private;
|
|
@@ -26,7 +25,6 @@ declare class WebsocketSecure extends Service {
|
|
|
26
25
|
constructor(module: Module, httpKernel: HttpKernel);
|
|
27
26
|
setPort(): number;
|
|
28
27
|
createServer(serverHttps: httpsServers): Promise<WebSocketServer>;
|
|
29
|
-
onConnection(ws: Ws, req: IncomingMessage): void;
|
|
30
28
|
terminate(): Promise<boolean>;
|
|
31
29
|
showBanner(): void;
|
|
32
30
|
}
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { WebSocketServer } from "ws";
|
|
2
2
|
import { Service, Module, FamilyType } from "nodefony";
|
|
3
3
|
import type { DefaultOptionsService } from "nodefony";
|
|
4
4
|
import type { IHttpConfig } from "../../config/config.js";
|
|
5
5
|
import HttpKernel, { ProtocolType, ServerType, SchemeType } from "../http-kernel.js";
|
|
6
6
|
import { AddressInfo } from "node:net";
|
|
7
|
-
import type { IncomingMessage } from "node:http";
|
|
8
7
|
import httpServer from "./server-http.js";
|
|
9
8
|
declare class Websocket extends Service {
|
|
10
9
|
#private;
|
|
@@ -26,7 +25,6 @@ declare class Websocket extends Service {
|
|
|
26
25
|
constructor(module: Module, httpKernel: HttpKernel);
|
|
27
26
|
setPort(): number;
|
|
28
27
|
createServer(serverHttp: httpServer): Promise<WebSocketServer>;
|
|
29
|
-
onConnection(ws: Ws, req: IncomingMessage): void;
|
|
30
28
|
terminate(): Promise<boolean>;
|
|
31
29
|
showBanner(): void;
|
|
32
30
|
}
|
|
@@ -1,27 +1,41 @@
|
|
|
1
|
-
import { HttpTerminator } from "http-terminator";
|
|
2
1
|
import type { Server as HttpServer } from "node:http";
|
|
3
2
|
import type { Server as HttpsServer } from "node:https";
|
|
4
|
-
import type { Http2SecureServer } from "node:http2";
|
|
3
|
+
import type { Http2SecureServer, Http2Server } from "node:http2";
|
|
4
|
+
/** Serveur que `createDrainTerminator` sait drainer. */
|
|
5
|
+
export type DrainableServer = HttpServer | HttpsServer | Http2Server | Http2SecureServer;
|
|
6
|
+
/** Arrêt gracieux d'un serveur, rendu par `createDrainTerminator`. */
|
|
7
|
+
export interface IDrainTerminator {
|
|
8
|
+
/**
|
|
9
|
+
* Draine puis ferme le serveur ; idempotent (le deuxième appel rend la même promesse).
|
|
10
|
+
*
|
|
11
|
+
* @returns une promesse résolue quand toutes les connexions sont fermées
|
|
12
|
+
*/
|
|
13
|
+
terminate(): Promise<void>;
|
|
14
|
+
}
|
|
5
15
|
/**
|
|
6
|
-
* Fabrique
|
|
16
|
+
* Fabrique l'arrêt gracieux d'un serveur HTTP/1.1, HTTPS, HTTP/2 sur TLS ou h2c.
|
|
7
17
|
*
|
|
8
|
-
* Au `terminate()` (
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
18
|
+
* Au `terminate()` (SIGTERM, `docker stop`), le serveur cesse d'accepter, puis :
|
|
19
|
+
* - **HTTP/2** : chaque session reçoit un GOAWAY (`session.close()`) — les flux
|
|
20
|
+
* en vol se terminent, les nouveaux sont refusés, et le client sait qu'il doit
|
|
21
|
+
* rouvrir ailleurs au lieu de constater une coupure ;
|
|
22
|
+
* - **HTTP/1.1** : la réponse en vol part avec `Connection: close`, la socket
|
|
23
|
+
* inactive est fermée tout de suite, une requête qui arrive encore sur une
|
|
24
|
+
* socket gardée ouverte reçoit aussi `Connection: close`.
|
|
25
|
+
*
|
|
26
|
+
* Ce qui reste après `shutdownTimeout` ms est détruit. `server.close()` est
|
|
27
|
+
* appelé ici : ne pas le rappeler derrière.
|
|
13
28
|
*
|
|
14
29
|
* ⚠️ Les sockets WebSocket upgradées (sans réponse HTTP en cours) sont détruites
|
|
15
|
-
* SANS frame Close
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* HTTP en `once`.
|
|
30
|
+
* SANS frame Close → les serveurs WS doivent fermer leurs clients (close 1001)
|
|
31
|
+
* AVANT ce drain. Garanti par l'ordre des listeners `onTerminate` : WS/WSS
|
|
32
|
+
* s'attachent en `prependOnceListener`, les serveurs HTTP en `once`.
|
|
19
33
|
*
|
|
20
|
-
* @param server - serveur Node à drainer (
|
|
34
|
+
* @param server - serveur Node à drainer, créé AVANT son `listen` (le suivi des
|
|
35
|
+
* connexions commence ici)
|
|
21
36
|
* @param shutdownTimeout - délai de drain en ms avant destruction forcée
|
|
22
|
-
* @returns
|
|
37
|
+
* @returns l'arrêt à invoquer au shutdown
|
|
23
38
|
*/
|
|
24
|
-
export declare function createDrainTerminator(server:
|
|
39
|
+
export declare function createDrainTerminator(server: DrainableServer, shutdownTimeout?: number): IDrainTerminator;
|
|
25
40
|
/** Drain par défaut (ms) — même valeur que le défaut Zod `servers.*.shutdownTimeout`. */
|
|
26
41
|
export declare const DEFAULT_SHUTDOWN_TIMEOUT = 5000;
|
|
27
|
-
export type { HttpTerminator };
|