@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
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { IProfilerQuery } from "nodefony";
|
|
2
|
-
import type { ISecurityTrace, PhaseName, PhaseTiming } from "../../interfaces/IContext.js";
|
|
2
|
+
import type { ISecurityTrace, PhaseName, PhaseTiming, ProtocolName } from "../../interfaces/IContext.js";
|
|
3
|
+
import type { IResolvedRoute, IRouteResolver } from "../../interfaces/IRouting.js";
|
|
3
4
|
/**
|
|
4
5
|
* Zone firewall capturée sur le contexte (`SecuredArea`, lue en structurel :
|
|
5
6
|
* `@nodefony/http` ne peut pas importer `@nodefony/security`).
|
|
@@ -10,22 +11,22 @@ export interface ProfiledArea {
|
|
|
10
11
|
mode?: string;
|
|
11
12
|
authenticators?: readonly string[];
|
|
12
13
|
}
|
|
13
|
-
/**
|
|
14
|
+
/**
|
|
15
|
+
* Ce que le Profiler lit d'un Resolver (route/controller/action) — dérivé de
|
|
16
|
+
* {@link IRouteResolver}, en lecture seule : tout résolveur du contrat s'y range
|
|
17
|
+
* sans conversion, et les deux types ne peuvent plus diverger.
|
|
18
|
+
*/
|
|
14
19
|
export interface ProfiledResolver {
|
|
15
|
-
route?:
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
controller?: {
|
|
19
|
-
name?: string;
|
|
20
|
-
} | null;
|
|
21
|
-
actionName?: string;
|
|
20
|
+
readonly route?: Pick<IResolvedRoute, "name"> | null | undefined;
|
|
21
|
+
readonly controller?: IRouteResolver["controller"];
|
|
22
|
+
readonly actionName?: string | undefined;
|
|
22
23
|
}
|
|
23
24
|
/** Descripteur d'ouverture d'une invocation (ce que le pont connaît d'entrée). */
|
|
24
25
|
export interface FrameProfileInit {
|
|
25
26
|
/** Identifiant du profil — `<requestId de la connexion>.<n° de frame>`. */
|
|
26
27
|
requestId: string;
|
|
27
|
-
/**
|
|
28
|
-
type:
|
|
28
|
+
/** Famille du contexte porteur (`context.type` : `websocket`). */
|
|
29
|
+
type: ProtocolName;
|
|
29
30
|
scheme: string;
|
|
30
31
|
/** Méthode LOGIQUE de l'invocation (`GET`, `POST`…), pas le transport. */
|
|
31
32
|
method: string;
|
|
@@ -63,7 +64,7 @@ export interface FrameProfileInit {
|
|
|
63
64
|
*/
|
|
64
65
|
export declare class FrameProfile {
|
|
65
66
|
readonly requestId: string;
|
|
66
|
-
readonly type:
|
|
67
|
+
readonly type: ProtocolName;
|
|
67
68
|
readonly scheme: string;
|
|
68
69
|
readonly method: string;
|
|
69
70
|
readonly url: string;
|
|
@@ -79,6 +80,12 @@ export declare class FrameProfile {
|
|
|
79
80
|
* invocation, il redevient exact, et le SQL se replace dans le waterfall.
|
|
80
81
|
*/
|
|
81
82
|
readonly profilerQueries: IProfilerQuery[] | null;
|
|
83
|
+
/**
|
|
84
|
+
* Ce profil sera-t-il gardé par le Profiler ? Faux quand seul le timing
|
|
85
|
+
* l'a ouvert (chemin d'outillage) : son id ne désigne alors aucun profil
|
|
86
|
+
* lisible, et ne doit pas être annoncé au client.
|
|
87
|
+
*/
|
|
88
|
+
get profiled(): boolean;
|
|
82
89
|
/** Resolver de la frame — porte route / controller / action. */
|
|
83
90
|
resolver: ProfiledResolver | null;
|
|
84
91
|
/** Statut HTTP-équivalent de l'invocation (200, 403, 404…). */
|
|
@@ -89,7 +96,16 @@ export declare class FrameProfile {
|
|
|
89
96
|
message: string;
|
|
90
97
|
} | null;
|
|
91
98
|
private readonly timing;
|
|
99
|
+
private readonly clockStartMs;
|
|
100
|
+
private durationMs;
|
|
92
101
|
constructor(init: FrameProfileInit);
|
|
102
|
+
/**
|
|
103
|
+
* Arrête l'horloge de la frame (au premier appel) et rend sa durée en ms ;
|
|
104
|
+
* `null` si le timing est éteint. Contrat de `IContext.stopClock`.
|
|
105
|
+
*
|
|
106
|
+
* @returns la durée de l'invocation, ou `null`
|
|
107
|
+
*/
|
|
108
|
+
stopClock(): number | null;
|
|
93
109
|
/**
|
|
94
110
|
* Ouvre une phase. Contrairement au `Context`, l'index est un **scan arrière**
|
|
95
111
|
* (pas de `Map<nom, index>`) : une frame porte une poignée de phases, et une
|
|
@@ -18,106 +18,19 @@
|
|
|
18
18
|
* Multi-process : un profil vit sur le worker qui a traité l'appel (fetch même
|
|
19
19
|
* origine par requestId). Agrégat cluster = Redis (P13).
|
|
20
20
|
*/
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Une requête SQL/NoSQL exécutée pendant la requête HTTP (SEAM ORM — futur).
|
|
31
|
-
*
|
|
32
|
-
* Non collecté aujourd'hui : quand `@nodefony/orm-core` arrivera, les adapters
|
|
33
|
-
* pousseront leurs requêtes dans un buffer per-request dev-only (via l'ALS
|
|
34
|
-
* `RequestContext.getRequestId()`, déjà en place) que `collect()` lira ici.
|
|
35
|
-
* Le champ `queries` reste donc `undefined` tant qu'aucun ORM ne pushe → 0 coût.
|
|
36
|
-
*/
|
|
37
|
-
export interface ProfileQuery {
|
|
38
|
-
/** Requête (SQL ou commande NoSQL), tronquée si volumineuse. */
|
|
39
|
-
sql: string;
|
|
40
|
-
/** Début relatif (`performance.now()`) — même horloge que les phases. */
|
|
41
|
-
startMs?: number | undefined;
|
|
42
|
-
/** Durée d'exécution en ms. */
|
|
43
|
-
durationMs: number;
|
|
44
|
-
/** Lignes affectées/retournées, si connu. */
|
|
45
|
-
rows?: number | undefined;
|
|
46
|
-
/** Connecteur émetteur (`drizzle`, `mongoose`…). */
|
|
47
|
-
connector?: string | undefined;
|
|
48
|
-
}
|
|
49
|
-
/**
|
|
50
|
-
* Traversée du firewall par cette requête — **ce qui était possible** (la zone :
|
|
51
|
-
* son nom, si elle est protégée, quels authenticators elle accepte) croisé avec
|
|
52
|
-
* **ce qui s'est passé** (quel maillon a résolu l'identité, l'issue, le motif
|
|
53
|
-
* d'un refus).
|
|
54
|
-
*
|
|
55
|
-
* Sans cela, une requête qui PASSE est invisible côté sécurité : le chemin de
|
|
56
|
-
* succès n'émet aucun événement d'audit (choix délibéré — le volume nominal
|
|
57
|
-
* n'est pas un signal). `undefined` hors zone firewall.
|
|
58
|
-
*/
|
|
59
|
-
export interface ProfileSecurity {
|
|
60
|
-
/** Nom de la zone traversée. */
|
|
61
|
-
zone: string | null;
|
|
62
|
-
/** La zone exige-t-elle une identité (`security: true`) ? */
|
|
63
|
-
protected: boolean;
|
|
64
|
-
/** Chaîne d'authenticators : `first` = le premier qui supporte, `all` = MFA. */
|
|
65
|
-
mode: string | null;
|
|
66
|
-
/** Authenticators que la zone accepte (ce qui était POSSIBLE). */
|
|
67
|
-
candidates: string[];
|
|
68
|
-
/** Authenticator qui a RÉELLEMENT résolu l'identité. */
|
|
69
|
-
authenticator: string | null;
|
|
70
|
-
/** `granted` · `anonymous` · `denied` · `failure` · `throttled` · `bypass` · `public`. */
|
|
71
|
-
outcome: string | null;
|
|
72
|
-
/** Motif du refus (`no_credentials`, `invalid_credentials`…). */
|
|
73
|
-
reason: string | null;
|
|
74
|
-
/** Rôles du token résolu (l'axe autorisation). */
|
|
75
|
-
roles: string[] | null;
|
|
76
|
-
}
|
|
77
|
-
/** Profil complet d'une requête (HTTP ou message WS), exposé par `get`. */
|
|
78
|
-
export interface ProfileEntry {
|
|
79
|
-
requestId: string;
|
|
80
|
-
/** Horodatage de la collecte (`Date.now()`), pour le tri client. */
|
|
81
|
-
ts: number;
|
|
82
|
-
kind: "http" | "ws";
|
|
83
|
-
method: string | null;
|
|
84
|
-
url: string;
|
|
85
|
-
scheme: string;
|
|
86
|
-
status: number | null;
|
|
87
|
-
/** Durée totale serveur (ms), dérivée des phases. */
|
|
88
|
-
durationMs: number | null;
|
|
89
|
-
route: string | null;
|
|
90
|
-
controller: string | null;
|
|
91
|
-
action: string | null;
|
|
92
|
-
remoteAddress: string | null;
|
|
93
|
-
/** Identité (username) si le firewall l'a injectée, sinon `null`. */
|
|
94
|
-
user: string | null;
|
|
95
|
-
/** `traceparent` W3C Trace Context (P2.7) — corrélation distribuée RFC-propre. */
|
|
96
|
-
traceparent: string | null;
|
|
97
|
-
error: string | null;
|
|
98
|
-
phases: ProfilePhase[];
|
|
99
|
-
/** Requêtes ORM (SEAM futur — `undefined` tant qu'aucun adapter ne pushe). */
|
|
100
|
-
queries?: ProfileQuery[] | undefined;
|
|
101
|
-
/** Traversée du firewall — `undefined` si la requête n'a croisé aucune zone. */
|
|
102
|
-
security?: ProfileSecurity | undefined;
|
|
103
|
-
}
|
|
104
|
-
/** Résumé léger d'un profil pour la liste `recent` (sans les phases). */
|
|
105
|
-
export interface ProfileSummary {
|
|
106
|
-
requestId: string;
|
|
107
|
-
ts: number;
|
|
108
|
-
kind: "http" | "ws";
|
|
109
|
-
method: string | null;
|
|
110
|
-
url: string;
|
|
111
|
-
status: number | null;
|
|
112
|
-
durationMs: number | null;
|
|
113
|
-
route: string | null;
|
|
114
|
-
error: string | null;
|
|
115
|
-
}
|
|
21
|
+
import type { ProfiledResolver } from "./FrameProfile.js";
|
|
22
|
+
import type { ProtocolName } from "../../interfaces/IContext.js";
|
|
23
|
+
import type { IProfileEntry, IProfilePhase, IProfileQuery, IProfileSecurity, IProfileSummary } from "nodefony";
|
|
24
|
+
export type ProfilePhase = IProfilePhase;
|
|
25
|
+
export type ProfileQuery = IProfileQuery;
|
|
26
|
+
export type ProfileSecurity = IProfileSecurity;
|
|
27
|
+
export type ProfileEntry = IProfileEntry;
|
|
28
|
+
export type ProfileSummary = IProfileSummary;
|
|
116
29
|
/** Forme structurelle minimale lue sur un `Context` (lecture défensive). */
|
|
117
30
|
interface ProfilableContext {
|
|
118
31
|
requestId?: string | undefined;
|
|
119
32
|
userIdentifier?: string | null | undefined;
|
|
120
|
-
type?:
|
|
33
|
+
type?: ProtocolName | undefined;
|
|
121
34
|
scheme?: string | undefined;
|
|
122
35
|
method?: string | null | undefined;
|
|
123
36
|
url?: string | undefined;
|
|
@@ -134,15 +47,12 @@ interface ProfilableContext {
|
|
|
134
47
|
startMs: number;
|
|
135
48
|
durationMs?: number | undefined;
|
|
136
49
|
}> | undefined;
|
|
137
|
-
resolver?:
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
} | null | undefined;
|
|
144
|
-
actionName?: string | undefined;
|
|
145
|
-
} | null | undefined;
|
|
50
|
+
resolver?: ProfiledResolver | null | undefined;
|
|
51
|
+
/**
|
|
52
|
+
* Arrête l'horloge de la requête et rend sa durée (ms) — la même que le
|
|
53
|
+
* journal d'accès (`IContext.stopClock`). `null` si `timing.enabled` vaut `false`.
|
|
54
|
+
*/
|
|
55
|
+
stopClock(): number | null;
|
|
146
56
|
/**
|
|
147
57
|
* Buffer de requêtes ORM rempli pendant la requête (dev-only). Même tableau
|
|
148
58
|
* que la payload ALS — les adapters ORM y poussent via `RequestContext`.
|
|
@@ -168,10 +78,50 @@ interface ProfilableContext {
|
|
|
168
78
|
roles: string[] | null;
|
|
169
79
|
} | null | undefined;
|
|
170
80
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
81
|
+
/** Les profils collectés depuis un curseur. */
|
|
82
|
+
export interface IProfileBatch {
|
|
83
|
+
/** Profils de numéro supérieur au curseur, du plus ancien au plus récent. */
|
|
84
|
+
entries: ProfileEntry[];
|
|
85
|
+
/** Curseur à repasser au prochain appel : le dernier numéro attribué. */
|
|
86
|
+
cursor: number;
|
|
87
|
+
/**
|
|
88
|
+
* Profils collectés depuis le curseur mais disparus avant d'être lus —
|
|
89
|
+
* évincés par le tampon, ou écrasés par un identifiant réutilisé. Exact.
|
|
90
|
+
*/
|
|
91
|
+
lost: number;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Ce qu'un lecteur extérieur (outil de l'agent de code, banc) attend du
|
|
95
|
+
* profileur : suivre les profils au fil de l'eau, ou en retrouver un par son
|
|
96
|
+
* identifiant. Contrat structurel — on le résout par NOM dans le conteneur
|
|
97
|
+
* (`"profiler"`), sans dépendre de la classe.
|
|
98
|
+
*/
|
|
99
|
+
export interface IProfilerReader {
|
|
100
|
+
/** Curseur courant : le passer à {@link since} pour ne lire que la suite. */
|
|
101
|
+
readonly cursor: number;
|
|
102
|
+
/** Profils collectés depuis `cursor`, et le compte de ceux qui ont été perdus. */
|
|
103
|
+
since(cursor: number): IProfileBatch;
|
|
104
|
+
/** Profil complet d'une requête, ou `undefined` si évincé/inconnu. */
|
|
105
|
+
get(requestId: string): ProfileEntry | undefined;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Collecteur des profils de requête, en un anneau par provenance
|
|
109
|
+
* ({@link profileLane}) : l'application, l'outillage, les assets relayés.
|
|
110
|
+
* Chacun évince ses propres profils — ouvrir la console ne chasse plus celui
|
|
111
|
+
* qu'on y consulte.
|
|
112
|
+
*/
|
|
113
|
+
export declare class Profiler implements IProfilerReader {
|
|
114
|
+
#private;
|
|
115
|
+
private readonly _lanes;
|
|
116
|
+
private readonly _caps;
|
|
117
|
+
/** Dernier numéro d'ordre attribué (0 = aucun profil collecté). */
|
|
118
|
+
private _seq;
|
|
119
|
+
/**
|
|
120
|
+
* @param cap - capacité de l'anneau de l'application.
|
|
121
|
+
* @param sideCap - capacité de chacun des anneaux de l'outillage et des
|
|
122
|
+
* assets relayés.
|
|
123
|
+
*/
|
|
124
|
+
constructor(cap?: number, sideCap?: number);
|
|
175
125
|
/**
|
|
176
126
|
* Snapshot un `Context` en fin de requête. Tolérant aux champs absents
|
|
177
127
|
* (handshake WS, erreur précoce). À appeler AVANT `context.clean()`.
|
|
@@ -183,11 +133,29 @@ export declare class Profiler {
|
|
|
183
133
|
get(requestId: string): ProfileEntry | undefined;
|
|
184
134
|
/**
|
|
185
135
|
* Résumés des requêtes les plus récentes (récent → ancien), capés à `limit`.
|
|
136
|
+
*
|
|
137
|
+
* @param limit - nombre maximal de résumés
|
|
138
|
+
* @param connection - le requestId d'une connexion WebSocket : ses SEULES
|
|
139
|
+
* frames du pont (`<connection>.<n>`, règle `frameIndexOf` du cœur)
|
|
140
|
+
*/
|
|
141
|
+
recent(limit?: number, connection?: string): ProfileSummary[];
|
|
142
|
+
/** Dernier numéro d'ordre attribué : le point de départ d'une lecture suivie. */
|
|
143
|
+
get cursor(): number;
|
|
144
|
+
/**
|
|
145
|
+
* Profils collectés après `cursor`, tous anneaux confondus, dans l'ordre
|
|
146
|
+
* des numéros.
|
|
147
|
+
*
|
|
148
|
+
* Les pertes se comptent sans estimation : chaque numéro attribué est un
|
|
149
|
+
* profil collecté, donc ce qui manque entre le curseur et le dernier numéro
|
|
150
|
+
* a disparu avant d'être lu. Un curseur venu d'ailleurs (supérieur au
|
|
151
|
+
* dernier numéro) repart de zéro.
|
|
152
|
+
*
|
|
153
|
+
* @param cursor - le `cursor` rendu par l'appel précédent, ou {@link cursor}.
|
|
186
154
|
*/
|
|
187
|
-
|
|
155
|
+
since(cursor: number): IProfileBatch;
|
|
188
156
|
/** Nombre de profils en mémoire. */
|
|
189
157
|
get size(): number;
|
|
190
|
-
/** Vide
|
|
158
|
+
/** Vide les anneaux. */
|
|
191
159
|
clear(): void;
|
|
192
160
|
}
|
|
193
161
|
export default Profiler;
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import type { ProfileEntry } from "./Profiler.js";
|
|
2
|
+
import type { IStatusBreakdown, IPhaseTotal, IRouteStats, INPlusOne, ISqlShapeStats, IErrorSample, IProfileReport } from "nodefony";
|
|
3
|
+
export type { IStatusBreakdown, IPhaseTotal, IRouteStats, INPlusOne, ISqlShapeStats, IErrorSample, IProfileReport, };
|
|
4
|
+
/**
|
|
5
|
+
* Agrégation des profils de requêtes — règle PURE, sans horloge ni I/O.
|
|
6
|
+
*
|
|
7
|
+
* Une seule implémentation pour tout ce qui résume le profileur : l'outil MCP
|
|
8
|
+
* qui observe l'application (`nodefony_observe`), celui qui tire lui-même des
|
|
9
|
+
* requêtes sur une route, et demain la console d'administration. Elle est
|
|
10
|
+
* bornée par construction : un échantillon de durées par route, un nombre
|
|
11
|
+
* maximal de formes SQL retenues, quelques exemples d'erreurs — observer une
|
|
12
|
+
* application chargée ne fait jamais grossir la mémoire avec la fenêtre.
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Répétitions d'une même forme SQL, dans UNE requête, à partir desquelles on
|
|
16
|
+
* signale un N+1. En dessous, ce sont des boucles courtes légitimes (quelques
|
|
17
|
+
* lectures de configuration, une pagination) qu'on signalerait à tort.
|
|
18
|
+
*/
|
|
19
|
+
export declare const N_PLUS_ONE_MIN_REPEATS = 5;
|
|
20
|
+
/** Durées retenues par route pour les percentiles (échantillonnage au-delà). */
|
|
21
|
+
export declare const ROUTE_SAMPLE_CAP = 256;
|
|
22
|
+
/** Formes SQL distinctes retenues ; les suivantes ne sont plus que comptées. */
|
|
23
|
+
export declare const SQL_SHAPE_CAP = 200;
|
|
24
|
+
/** Exemples d'erreurs retenus (statut ≥ 500 ou exception). */
|
|
25
|
+
export declare const ERROR_SAMPLE_CAP = 10;
|
|
26
|
+
/**
|
|
27
|
+
* Préfixe de l'espace réservé au framework.
|
|
28
|
+
*
|
|
29
|
+
* @deprecated Ne dit pas ce qui est de l'outillage : une connexion
|
|
30
|
+
* d'utilisateur (`/nodefony/security/api/auth/…`) ou une route d'application
|
|
31
|
+
* (`/nodefony/test/index`) passent sous ce préfixe. La règle est
|
|
32
|
+
* `isConsolePath` (`nodefony`), que `profileLane` appelle.
|
|
33
|
+
*/
|
|
34
|
+
export declare const TOOLING_URL_PREFIX = "/nodefony/";
|
|
35
|
+
/**
|
|
36
|
+
* Provenance d'un profil : l'application, l'outillage (`/nodefony/…` :
|
|
37
|
+
* console, API d'administration, porte MCP), ou un asset relayé sous un
|
|
38
|
+
* préfixe de module (`/_vite/`).
|
|
39
|
+
*/
|
|
40
|
+
export type ProfileLane = "app" | "tooling" | "asset";
|
|
41
|
+
/**
|
|
42
|
+
* Range un profil par provenance, d'après son URL. L'outillage est reconnu par
|
|
43
|
+
* la règle du cœur, `isConsolePath` — la même que les Journaux, la barre de
|
|
44
|
+
* débogage et le Studio : une connexion d'utilisateur reste de l'application.
|
|
45
|
+
* Les anneaux du profileur et le filtre de l'agrégation la lisent tous deux.
|
|
46
|
+
*
|
|
47
|
+
* @param url - URL du profil, absolue ou chemin.
|
|
48
|
+
* @returns la provenance du profil.
|
|
49
|
+
*/
|
|
50
|
+
export declare function profileLane(url: string): ProfileLane;
|
|
51
|
+
/**
|
|
52
|
+
* Le profil vient-il de l'outillage (routes `/nodefony/…` ou assets relayés)
|
|
53
|
+
* plutôt que de l'application.
|
|
54
|
+
*
|
|
55
|
+
* @param url - URL du profil, absolue ou chemin.
|
|
56
|
+
*/
|
|
57
|
+
export declare function isToolingUrl(url: string): boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Une requête de cette URL se profile-t-elle ? L'application toujours ;
|
|
60
|
+
* l'outillage et les assets relayés seulement sur demande (`timing.tooling`)
|
|
61
|
+
* — on ne mesure pas la façon dont on mesure.
|
|
62
|
+
*
|
|
63
|
+
* @param url - URL ou chemin de la requête (ou de la frame du pont)
|
|
64
|
+
* @param tooling - profiler aussi l'outillage
|
|
65
|
+
*/
|
|
66
|
+
export declare function isProfiledUrl(url: string, tooling: boolean): boolean;
|
|
67
|
+
/** Groupe des requêtes qu'aucune route n'a servies (404, statique, sondes). */
|
|
68
|
+
export declare const NO_ROUTE = "(aucune route)";
|
|
69
|
+
/** Pseudo-phase : le temps de l'action hors phases imbriquées et hors SQL. */
|
|
70
|
+
export declare const ACTION_SELF_PHASE = "action.self";
|
|
71
|
+
/** Réglages d'une agrégation. */
|
|
72
|
+
export interface IProfileAggregatorOptions {
|
|
73
|
+
/** Répétitions à partir desquelles une forme SQL est un N+1. */
|
|
74
|
+
nPlusOneMinRepeats?: number | undefined;
|
|
75
|
+
/** Agréger aussi les requêtes de l'outillage (`/nodefony/…`, `/_vite/…`). */
|
|
76
|
+
includeTooling?: boolean | undefined;
|
|
77
|
+
/** Source d'aléa de l'échantillonnage — injectée par les tests. */
|
|
78
|
+
random?: (() => number) | undefined;
|
|
79
|
+
}
|
|
80
|
+
/** Accumulateur : on lui donne les profils un à un, il rend le rapport. */
|
|
81
|
+
export interface IProfileAggregator {
|
|
82
|
+
/** Ajoute un profil ; `false` s'il a été écarté (outillage). */
|
|
83
|
+
add(entry: ProfileEntry): boolean;
|
|
84
|
+
/** Le rapport à cet instant ; l'accumulateur continue d'accepter des profils. */
|
|
85
|
+
result(): IProfileReport;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Réduit une requête SQL (ou le descripteur d'une commande NoSQL) à sa FORME :
|
|
89
|
+
* valeurs remplacées par `?`, listes de valeurs repliées, blancs compactés.
|
|
90
|
+
*
|
|
91
|
+
* Deux requêtes qui ne diffèrent que par leurs valeurs ont la même forme — c'est
|
|
92
|
+
* ce qui permet de reconnaître un N+1. Et aucune valeur ne survit : la forme
|
|
93
|
+
* peut sortir dans un rapport sans emporter une donnée personnelle.
|
|
94
|
+
*
|
|
95
|
+
* @param sql - le texte tel que l'adaptateur l'a poussé au profileur.
|
|
96
|
+
* @returns la forme normalisée.
|
|
97
|
+
*/
|
|
98
|
+
export declare function sqlShape(sql: string): string;
|
|
99
|
+
/**
|
|
100
|
+
* Une requête en ERREUR du serveur : statut ≥ 500, ou exception levée sans
|
|
101
|
+
* verdict client. Règle unique — le rapport, ses exemples et la lecture de leurs
|
|
102
|
+
* journaux en dépendent.
|
|
103
|
+
*
|
|
104
|
+
* Un statut 4xx n'en est JAMAIS une, même porteur d'une exception : un refus
|
|
105
|
+
* 401/403 (l'authentification lève une `AuthenticationError`) ou une ressource
|
|
106
|
+
* absente est le verdict rendu au client, compté à part — le lister parmi les
|
|
107
|
+
* erreurs ferait chercher une panne là où il manque une identité.
|
|
108
|
+
*
|
|
109
|
+
* @param entry - le profil (seuls statut et erreur sont lus).
|
|
110
|
+
*/
|
|
111
|
+
export declare function isFailedProfile(entry: Pick<ProfileEntry, "status" | "error">): boolean;
|
|
112
|
+
/**
|
|
113
|
+
* Le chemin d'une URL de profil. Le profileur enregistre l'URL ABSOLUE
|
|
114
|
+
* (`http://hôte:port/chemin`) : un filtre écrit sur le chemin ne mordrait
|
|
115
|
+
* jamais dessus. Sans `URL` à construire — appelée sur chaque profil lu.
|
|
116
|
+
*/
|
|
117
|
+
export declare function urlPath(url: string): string;
|
|
118
|
+
/**
|
|
119
|
+
* Crée un accumulateur de profils.
|
|
120
|
+
*
|
|
121
|
+
* @param options - seuil N+1, prise en compte de l'outillage, aléa injecté.
|
|
122
|
+
* @returns l'accumulateur ; son `result()` peut être appelé à tout moment.
|
|
123
|
+
*/
|
|
124
|
+
export declare function createProfileAggregator(options?: IProfileAggregatorOptions): IProfileAggregator;
|
|
125
|
+
/**
|
|
126
|
+
* Agrège une liste de profils en une fois.
|
|
127
|
+
*
|
|
128
|
+
* @param entries - les profils, dans n'importe quel ordre.
|
|
129
|
+
* @param options - mêmes réglages que {@link createProfileAggregator}.
|
|
130
|
+
* @returns le rapport.
|
|
131
|
+
*/
|
|
132
|
+
export declare function aggregateProfiles(entries: Iterable<ProfileEntry>, options?: IProfileAggregatorOptions): IProfileReport;
|
|
@@ -140,8 +140,20 @@ export declare function forwardRequest(req: ProxiedRequest, res: ProxiedResponse
|
|
|
140
140
|
* @returns la tête complète, CRLF final compris
|
|
141
141
|
*/
|
|
142
142
|
export declare function rawHead(status: string, rawHeaders: readonly string[], skip?: ReadonlySet<string> | null, extra?: readonly string[]): string;
|
|
143
|
-
/**
|
|
144
|
-
|
|
143
|
+
/**
|
|
144
|
+
* Réponse brute minimale sur un socket d'upgrade, puis fermeture.
|
|
145
|
+
*
|
|
146
|
+
* Les en-têtes passent par la validation de `node:http` : un nom ou une valeur
|
|
147
|
+
* invalide — un saut de ligne surtout, qui forgerait un en-tête de plus — est
|
|
148
|
+
* OMIS, jamais écrit. `Connection` et `Content-Length` sont posés ici et ne se
|
|
149
|
+
* remplacent pas.
|
|
150
|
+
*
|
|
151
|
+
* @param socket - socket du client, encore en attente de sa réponse
|
|
152
|
+
* @param status - statut HTTP du refus
|
|
153
|
+
* @param reason - phrase de raison
|
|
154
|
+
* @param headers - en-têtes du refus (`WWW-Authenticate`, `Retry-After`…)
|
|
155
|
+
*/
|
|
156
|
+
export declare function refuseUpgrade(socket: Duplex, status: number, reason: string, headers?: Readonly<Record<string, string | number>> | null): void;
|
|
145
157
|
/**
|
|
146
158
|
* Relaie un upgrade WebSocket DÉJÀ validé (méthode, `Upgrade`, clé, version,
|
|
147
159
|
* `Origin` — cf `ReverseProxy.handleUpgrade`) : rejoue le handshake vers
|
|
@@ -42,6 +42,12 @@ export interface ProxyIntrospection {
|
|
|
42
42
|
httpPort: number;
|
|
43
43
|
/** Port HTTPS/2 du backend (re-encrypt). */
|
|
44
44
|
httpsPort: number;
|
|
45
|
+
/**
|
|
46
|
+
* Port h2c du backend (`servers.h2c`), ou `null` s'il n'est pas activé. Le
|
|
47
|
+
* générateur haproxy y envoie le trafic en HTTP/2 (`proto h2`) ; nginx, qui
|
|
48
|
+
* ne parle pas HTTP/2 à ses amonts, l'ignore.
|
|
49
|
+
*/
|
|
50
|
+
h2cPort?: number | null;
|
|
45
51
|
/** Dossiers statiques servis à la racine `/` (ordre = priorité). */
|
|
46
52
|
staticRoots: string[];
|
|
47
53
|
/** Montages statiques préfixés (servis tels quels). */
|
|
@@ -71,6 +77,16 @@ export interface ProxyIntrospection {
|
|
|
71
77
|
* saines.
|
|
72
78
|
*/
|
|
73
79
|
keepaliveIntervalMs: number;
|
|
80
|
+
/**
|
|
81
|
+
* Chemin de la sonde de disponibilité (`health.readinessPath`), ou `null`
|
|
82
|
+
* si les sondes sont désactivées.
|
|
83
|
+
*
|
|
84
|
+
* HAProxy la sonde (`option httpchk`) au lieu d'un simple contrôle de
|
|
85
|
+
* connexion : un exemplaire qui draine garde son port ouvert, mais `/readyz`
|
|
86
|
+
* répond déjà `503` — c'est ce qui le retire du répartiteur AVANT qu'il
|
|
87
|
+
* cesse d'accepter. Un contrôle TCP le garderait jusqu'à la fermeture du port.
|
|
88
|
+
*/
|
|
89
|
+
readinessPath?: string | null;
|
|
74
90
|
/**
|
|
75
91
|
* Terminaison TLS au frontal, ou `null` pour n'écouter qu'en clair.
|
|
76
92
|
*
|
|
@@ -78,6 +78,9 @@ export declare function isAmbiguousPath(url: string): boolean;
|
|
|
78
78
|
* un tel handshake est relayé : un `Upgrade` quelconque (`h2c`…) raccordé
|
|
79
79
|
* octet pour octet ouvrirait un tunnel que rien n'inspecte.
|
|
80
80
|
*
|
|
81
|
+
* Appelé à CHAQUE handshake (proxy inverse et routes de Nodefony) : aucune
|
|
82
|
+
* allocation — des expressions testées, jamais de découpe de chaîne.
|
|
83
|
+
*
|
|
81
84
|
* @param method - méthode de la requête
|
|
82
85
|
* @param headers - en-têtes reçus
|
|
83
86
|
* @returns la raison du refus, ou `null` si le handshake est conforme
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { Http2SecureServer, Http2Server, ServerOptions } from "node:http2";
|
|
2
|
+
import type { IHttpConfig } from "../../config/config.js";
|
|
3
|
+
/**
|
|
4
|
+
* Limites anti-DoS d'un serveur HTTP/2, lues dans la section `http2` du module :
|
|
5
|
+
* `maxSessionMemory` (amplification mémoire) et `maxConcurrentStreams` dans les
|
|
6
|
+
* SETTINGS (CVE-2023-44487, Rapid Reset). Règle UNIQUE des serveurs HTTP/2 — TLS
|
|
7
|
+
* (5152) comme h2c — : une limite oubliée sur l'un d'eux en ferait la porte de
|
|
8
|
+
* l'attaque.
|
|
9
|
+
*
|
|
10
|
+
* Une limite absente garde le défaut de Node (aucune régression).
|
|
11
|
+
*
|
|
12
|
+
* @param limits - `module.options.http2`.
|
|
13
|
+
* @returns les options à fusionner dans celles de `createServer`/`createSecureServer`.
|
|
14
|
+
*/
|
|
15
|
+
export declare function http2ServerLimits(limits: Partial<IHttpConfig["http2"]> | undefined): Pick<ServerOptions, "maxSessionMemory" | "settings">;
|
|
16
|
+
/**
|
|
17
|
+
* Borne l'inactivité des sessions d'un serveur HTTP/2 — TLS (5152) comme h2c —
|
|
18
|
+
* et contourne un défaut de Node qui garde chaque session fermée en vie jusqu'à
|
|
19
|
+
* l'échéance de ce délai.
|
|
20
|
+
*
|
|
21
|
+
* Le défaut (Node 24, 26) : `closeSession` (`internal/http2/core`) marque la
|
|
22
|
+
* session détruite PUIS appelle `session.setTimeout(0)` ; or `setStreamTimeout`
|
|
23
|
+
* sort aussitôt sur un objet détruit. Le minuteur n'est jamais désarmé et retient
|
|
24
|
+
* la session (~2,4 Ko) pendant `timeoutMs` : sous un flux de connexions neuves,
|
|
25
|
+
* connexions/s × délai × 2,4 Ko. Signalé à Node : https://github.com/nodejs/node/issues/66885
|
|
26
|
+
*
|
|
27
|
+
* Le contournement : désarmer à la réception du GOAWAY, AVANT la destruction —
|
|
28
|
+
* c'est ainsi que ferment un proxy et un client Node, même par `destroy()`. Rien
|
|
29
|
+
* n'est retiré à la protection : Node n'agit déjà plus à l'échéance sur une
|
|
30
|
+
* session fermée (`sessionOnTimeout` sort sur `closed`). Une coupure TCP sans
|
|
31
|
+
* GOAWAY garde la rétention, bornée au délai.
|
|
32
|
+
*
|
|
33
|
+
* @param server - le serveur HTTP/2.
|
|
34
|
+
* @param timeoutMs - délai d'inactivité ; 0 ou absent le laisse désactivé.
|
|
35
|
+
* @param onTimeout - appelé à l'échéance (événement `timeout` du serveur).
|
|
36
|
+
*/
|
|
37
|
+
export declare function setHttp2SessionTimeout(server: Http2Server | Http2SecureServer, timeoutMs: number | undefined, onTimeout: () => void): void;
|
|
@@ -10,6 +10,15 @@ import type { ServersConfig } from "nodefony";
|
|
|
10
10
|
* @returns la section typée, ou `undefined` si elle est absente ou n'est pas un objet.
|
|
11
11
|
*/
|
|
12
12
|
export declare function asServersConfig(servers: unknown): ServersConfig | undefined;
|
|
13
|
+
/**
|
|
14
|
+
* Le serveur h2c démarre-t-il ? Seul un `enabled: true` EXPLICITE l'allume : la
|
|
15
|
+
* section existe toujours (défauts), un port seul ne vaut pas activation.
|
|
16
|
+
*
|
|
17
|
+
* @param entry - `servers.h2c`.
|
|
18
|
+
*/
|
|
19
|
+
export declare function isH2cEnabled(entry: {
|
|
20
|
+
enabled?: boolean | undefined;
|
|
21
|
+
} | undefined): boolean;
|
|
13
22
|
/**
|
|
14
23
|
* Port DEMANDÉ pour un serveur (`servers.<type>.port`), ou `undefined` si le
|
|
15
24
|
* serveur est désactivé, absent, ou sans port numérique.
|
|
@@ -17,4 +26,4 @@ export declare function asServersConfig(servers: unknown): ServersConfig | undef
|
|
|
17
26
|
* @param servers - section `servers` déjà rétrécie ({@link asServersConfig}).
|
|
18
27
|
* @param type - le serveur visé.
|
|
19
28
|
*/
|
|
20
|
-
export declare function configuredServerPort(servers: ServersConfig | undefined, type: "http" | "https"): number | undefined;
|
|
29
|
+
export declare function configuredServerPort(servers: ServersConfig | undefined, type: "http" | "https" | "h2c"): number | undefined;
|
|
@@ -3,12 +3,19 @@ import { resolvePortPolicy } from "nodefony";
|
|
|
3
3
|
import type { PortPolicy } from "nodefony";
|
|
4
4
|
export { resolvePortPolicy };
|
|
5
5
|
export type { PortPolicy };
|
|
6
|
-
/**
|
|
6
|
+
/**
|
|
7
|
+
* Serveur écoutable (surface minimale commune `http`/`https`/`http2`).
|
|
8
|
+
*
|
|
9
|
+
* Les écouteurs sont typés événement par événement : c'est la forme que les
|
|
10
|
+
* surcharges de Node acceptent telle quelle, sans conversion chez l'appelant.
|
|
11
|
+
*/
|
|
7
12
|
export interface Listenable {
|
|
8
13
|
listen(port: number, host?: string): unknown;
|
|
9
14
|
address(): AddressInfo | string | null;
|
|
10
|
-
once(event:
|
|
11
|
-
|
|
15
|
+
once(event: "error", listener: (error: NodeJS.ErrnoException) => void): unknown;
|
|
16
|
+
once(event: "listening", listener: () => void): unknown;
|
|
17
|
+
removeListener(event: "error", listener: (error: NodeJS.ErrnoException) => void): unknown;
|
|
18
|
+
removeListener(event: "listening", listener: () => void): unknown;
|
|
12
19
|
}
|
|
13
20
|
/** Nombre de ports essayés après le désiré, en `auto`. */
|
|
14
21
|
export declare const DEFAULT_PORT_RETRY_ATTEMPTS = 20;
|
|
@@ -34,18 +41,35 @@ export interface ServersPortConfig {
|
|
|
34
41
|
https?: {
|
|
35
42
|
port?: number | undefined;
|
|
36
43
|
} | false;
|
|
44
|
+
h2c?: {
|
|
45
|
+
enabled?: boolean | undefined;
|
|
46
|
+
port?: number | undefined;
|
|
47
|
+
};
|
|
37
48
|
portPolicy?: PortPolicy;
|
|
38
49
|
portRetryAttempts?: number;
|
|
39
50
|
}
|
|
51
|
+
/** Serveur dont `buildBindPlan` compose le plan. */
|
|
52
|
+
export type BoundServer = "http" | "https" | "h2c";
|
|
53
|
+
/**
|
|
54
|
+
* Serveur actif qui convoite le MÊME port que h2c, ou `null`.
|
|
55
|
+
*
|
|
56
|
+
* Un port partagé avec h2c n'est pas un conflit à contourner : sur ce port, le
|
|
57
|
+
* client HTTP/1.1 et le proxy h2c se marchent dessus, et le repli `auto` ferait
|
|
58
|
+
* glisser l'un des deux là où personne ne l'attend. Le boot le refuse.
|
|
59
|
+
*
|
|
60
|
+
* @param servers - `kernel.options.servers`.
|
|
61
|
+
* @returns `"http"` ou `"https"` en conflit, sinon `null` (h2c inactif, port 0).
|
|
62
|
+
*/
|
|
63
|
+
export declare function h2cPortConflict(servers: ServersPortConfig | undefined): "http" | "https" | null;
|
|
40
64
|
/**
|
|
41
65
|
* Compose le plan de bind d'un serveur depuis la config du kernel — source UNIQUE
|
|
42
|
-
* (les
|
|
66
|
+
* (les serveurs l'appellent ; la politique n'est décidée qu'ici).
|
|
43
67
|
*
|
|
44
68
|
* @param which - le serveur qu'on borne.
|
|
45
69
|
* @param servers - `kernel.options.servers`.
|
|
46
70
|
* @param environment - `kernel.environment` (arbitre le défaut de la politique).
|
|
47
71
|
*/
|
|
48
|
-
export declare function buildBindPlan(which:
|
|
72
|
+
export declare function buildBindPlan(which: BoundServer, servers: ServersPortConfig | undefined, environment: string | undefined): BindPlan;
|
|
49
73
|
/**
|
|
50
74
|
* Sonde « un serveur répond-il déjà ici ? ».
|
|
51
75
|
*
|