@nodefony/http 10.0.0-beta.5 → 10.0.0-beta.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -0
- package/dist/_virtual/{_@oxc-project_runtime@0.155.0 → _@oxc-project_runtime@0.158.0}/helpers/esm/decorate.js +1 -1
- package/dist/_virtual/{_@oxc-project_runtime@0.155.0 → _@oxc-project_runtime@0.158.0}/helpers/esm/decorateParam.js +1 -1
- package/dist/index.js +30 -26
- package/dist/nodefony/command/proxyGenerateCommand.js +2 -2
- package/dist/nodefony/config/config.js +29 -4
- package/dist/nodefony/grpc/GrpcCall.js +298 -0
- package/dist/nodefony/grpc/GrpcEndpoint.js +528 -0
- package/dist/nodefony/grpc/index.js +4 -0
- package/dist/nodefony/interfaces/IRpcCall.js +1 -0
- package/dist/nodefony/service/ProfilerAdminApi.js +5 -2
- package/dist/nodefony/service/audit-logger.js +52 -6
- package/dist/nodefony/service/error-renderer.js +47 -13
- package/dist/nodefony/service/http-kernel.js +306 -49
- package/dist/nodefony/service/pretty-request-logger.js +5 -3
- package/dist/nodefony/service/request-logger.js +21 -6
- package/dist/nodefony/service/reverse-proxy.js +8 -3
- package/dist/nodefony/service/servers/clientError.js +53 -4
- package/dist/nodefony/service/servers/server-h2c.js +6 -6
- package/dist/nodefony/service/servers/server-http.js +6 -4
- package/dist/nodefony/service/servers/server-https.js +14 -7
- package/dist/nodefony/service/servers/server-static.js +1 -6
- package/dist/nodefony/service/servers/server-websocket-secure.js +7 -11
- package/dist/nodefony/service/servers/server-websocket.js +7 -11
- package/dist/nodefony/service/servers/serverShutdown.js +43 -6
- package/dist/nodefony/service/sessions/sessions-service.js +7 -7
- package/dist/nodefony/service/upload/upload-service.js +2 -2
- package/dist/nodefony/src/assets/prebuiltUi.js +23 -5
- package/dist/nodefony/src/context/Context.js +12 -1
- package/dist/nodefony/src/context/http/ByteStream.js +364 -0
- package/dist/nodefony/src/context/http/HttpContext.js +139 -32
- package/dist/nodefony/src/context/http/Request.js +111 -22
- package/dist/nodefony/src/context/http/Response.js +459 -37
- package/dist/nodefony/src/context/http/SseStream.js +83 -148
- package/dist/nodefony/src/context/http/StreamLifecycle.js +582 -0
- package/dist/nodefony/src/context/http/parser.js +29 -11
- package/dist/nodefony/src/context/http/urlFastPath.js +80 -1
- package/dist/nodefony/src/context/http/webResponse.js +56 -0
- package/dist/nodefony/src/context/http2/Request.js +1 -1
- package/dist/nodefony/src/context/http2/Response.js +55 -12
- package/dist/nodefony/src/context/requestTrace.js +6 -2
- package/dist/nodefony/src/context/rpcOutcome.js +20 -0
- package/dist/nodefony/src/context/transport.js +20 -1
- package/dist/nodefony/src/context/websocket/Response.js +15 -3
- package/dist/nodefony/src/context/websocket/WebsocketContext.js +86 -18
- package/dist/nodefony/src/context/websocket/websocketUrl.js +7 -0
- package/dist/nodefony/src/context/websocket/wsBackpressure.js +15 -15
- package/dist/nodefony/src/context/websocket/wsFrameRate.js +71 -0
- package/dist/nodefony/src/context/websocket/wsLogContent.js +55 -17
- package/dist/nodefony/src/cookies/cookie.js +57 -14
- package/dist/nodefony/src/errors/httpError.js +58 -25
- package/dist/nodefony/src/grpc/cors.js +59 -0
- package/dist/nodefony/src/grpc/limits.js +16 -0
- package/dist/nodefony/src/grpc/refusal.js +271 -0
- package/dist/nodefony/src/profiler/Profiler.js +14 -1
- package/dist/nodefony/src/profiler/aggregate.js +2 -2
- package/dist/nodefony/src/proxy/forward.js +109 -9
- package/dist/nodefony/src/proxy/generateProxyConfig.js +97 -17
- package/dist/nodefony/src/proxy/rules.js +29 -14
- package/dist/nodefony/src/servers/http2Goaway.js +76 -0
- package/dist/nodefony/src/servers/http2Limits.js +41 -15
- package/dist/nodefony/src/servers/http2StreamGrace.js +100 -0
- package/dist/nodefony/src/servers/receiveDeadline.js +177 -0
- package/dist/nodefony/src/servers/upgradeDispatch.js +62 -4
- package/dist/types/index.d.ts +11 -2
- package/dist/types/nodefony/config/config.d.ts +14 -0
- package/dist/types/nodefony/grpc/GrpcCall.d.ts +142 -0
- package/dist/types/nodefony/grpc/GrpcEndpoint.d.ts +98 -0
- package/dist/types/nodefony/grpc/index.d.ts +15 -0
- package/dist/types/nodefony/interfaces/IContext.d.ts +9 -0
- package/dist/types/nodefony/interfaces/IErrorRenderer.d.ts +14 -0
- package/dist/types/nodefony/interfaces/IRequest.d.ts +2 -1
- package/dist/types/nodefony/interfaces/IRequestTrace.d.ts +10 -0
- package/dist/types/nodefony/interfaces/IRouting.d.ts +19 -0
- package/dist/types/nodefony/interfaces/IRpcCall.d.ts +83 -0
- package/dist/types/nodefony/interfaces/ISecurity.d.ts +27 -2
- package/dist/types/nodefony/interfaces/IUpload.d.ts +51 -4
- package/dist/types/nodefony/interfaces/index.d.ts +2 -1
- package/dist/types/nodefony/service/ProfilerAdminApi.d.ts +2 -1
- package/dist/types/nodefony/service/audit-logger.d.ts +33 -3
- package/dist/types/nodefony/service/error-renderer.d.ts +27 -5
- package/dist/types/nodefony/service/http-kernel.d.ts +36 -3
- package/dist/types/nodefony/service/request-logger.d.ts +10 -0
- package/dist/types/nodefony/service/servers/clientError.d.ts +3 -2
- package/dist/types/nodefony/service/servers/serverShutdown.d.ts +7 -5
- package/dist/types/nodefony/src/assets/prebuiltUi.d.ts +9 -4
- package/dist/types/nodefony/src/context/Context.d.ts +9 -1
- package/dist/types/nodefony/src/context/http/ByteStream.d.ts +109 -0
- package/dist/types/nodefony/src/context/http/HttpContext.d.ts +99 -3
- package/dist/types/nodefony/src/context/http/Request.d.ts +46 -9
- package/dist/types/nodefony/src/context/http/Response.d.ts +188 -8
- package/dist/types/nodefony/src/context/http/SseStream.d.ts +33 -8
- package/dist/types/nodefony/src/context/http/StreamLifecycle.d.ts +106 -0
- package/dist/types/nodefony/src/context/http/parser.d.ts +17 -3
- package/dist/types/nodefony/src/context/http/urlFastPath.d.ts +40 -0
- package/dist/types/nodefony/src/context/http/webResponse.d.ts +31 -0
- package/dist/types/nodefony/src/context/http2/Response.d.ts +40 -5
- package/dist/types/nodefony/src/context/requestTrace.d.ts +3 -1
- package/dist/types/nodefony/src/context/rpcOutcome.d.ts +11 -0
- package/dist/types/nodefony/src/context/transport.d.ts +17 -0
- package/dist/types/nodefony/src/context/websocket/Response.d.ts +6 -1
- package/dist/types/nodefony/src/context/websocket/WebsocketContext.d.ts +48 -0
- package/dist/types/nodefony/src/context/websocket/websocketUrl.d.ts +4 -0
- package/dist/types/nodefony/src/context/websocket/wsBackpressure.d.ts +12 -2
- package/dist/types/nodefony/src/context/websocket/wsFrameRate.d.ts +69 -0
- package/dist/types/nodefony/src/context/websocket/wsLogContent.d.ts +16 -8
- package/dist/types/nodefony/src/cookies/cookie.d.ts +20 -2
- package/dist/types/nodefony/src/errors/httpError.d.ts +29 -4
- package/dist/types/nodefony/src/grpc/cors.d.ts +32 -0
- package/dist/types/nodefony/src/grpc/limits.d.ts +14 -0
- package/dist/types/nodefony/src/grpc/refusal.d.ts +136 -0
- package/dist/types/nodefony/src/profiler/Profiler.d.ts +11 -1
- package/dist/types/nodefony/src/proxy/forward.d.ts +37 -2
- package/dist/types/nodefony/src/proxy/generateProxyConfig.d.ts +15 -2
- package/dist/types/nodefony/src/proxy/rules.d.ts +20 -0
- package/dist/types/nodefony/src/servers/http2Goaway.d.ts +41 -0
- package/dist/types/nodefony/src/servers/http2Limits.d.ts +27 -14
- package/dist/types/nodefony/src/servers/http2StreamGrace.d.ts +34 -0
- package/dist/types/nodefony/src/servers/receiveDeadline.d.ts +77 -0
- package/dist/types/nodefony/src/servers/upgradeDispatch.d.ts +41 -1
- package/docs/byte-stream.md +406 -0
- package/docs/cookies.md +13 -3
- package/docs/diagnostics-channel.md +45 -1
- package/docs/index.md +8 -0
- package/docs/reverse-proxy.md +15 -3
- package/docs/servers.md +67 -43
- package/docs/session.md +3 -3
- package/docs/sse.md +27 -20
- package/docs/upload.md +43 -17
- package/package.json +38 -18
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Severity } from "nodefony";
|
|
2
2
|
import type { IRequestLogger, IRequestLogEntry } from "../interfaces/IRequestLogger.js";
|
|
3
3
|
import type { IContext, IHttpContext, IWebsocketContext } from "../interfaces/IContext.js";
|
|
4
|
+
import type { IRpcOutcome } from "../interfaces/IRpcCall.js";
|
|
4
5
|
declare const statusOf: (context: IContext) => number | null;
|
|
5
6
|
/**
|
|
6
7
|
* Canonical audit log entry — 1 JSON PDU per request (P3.1).
|
|
@@ -35,6 +36,15 @@ export interface AuditLogEntry {
|
|
|
35
36
|
name: string;
|
|
36
37
|
durationMs: number | null;
|
|
37
38
|
}[] | undefined;
|
|
39
|
+
/**
|
|
40
|
+
* L'appel RPC de la requête (système, méthode, code, nom), `null` hors
|
|
41
|
+
* RPC et pour une WebSocket : forme stable (ADR-0026 D10 point 4) —
|
|
42
|
+
* toujours posé par `JsonAuditLogger` ; optionnel au type, pour qu'un
|
|
43
|
+
* journal maison qui bâtit une entrée ne casse pas.
|
|
44
|
+
*
|
|
45
|
+
* @experimental Surface gRPC, ADR-0026 D11.
|
|
46
|
+
*/
|
|
47
|
+
rpc?: IRpcOutcome | null | undefined;
|
|
38
48
|
error?: AuditErrorEntry | undefined;
|
|
39
49
|
protocol?: string | null | undefined;
|
|
40
50
|
}
|
|
@@ -59,6 +69,25 @@ export interface AuditErrorEntry {
|
|
|
59
69
|
* Unknown/missing status → INFO.
|
|
60
70
|
*/
|
|
61
71
|
declare function severityFromStatus(status: number | null | undefined): Severity;
|
|
72
|
+
/**
|
|
73
|
+
* Gravité d'un appel RPC selon son code (ADR-0026 D10 point 4) : 0 → INFO ;
|
|
74
|
+
* une erreur du serveur ({@link RPC_SERVER_ERRORS}) → ERROR ; les autres —
|
|
75
|
+
* refus, échecs métier ou client — → WARNING.
|
|
76
|
+
*
|
|
77
|
+
* @param code - le code de l'appel (gRPC : 0 à 16).
|
|
78
|
+
* @returns la gravité de la ligne.
|
|
79
|
+
*/
|
|
80
|
+
declare function severityFromRpcCode(code: number): Severity;
|
|
81
|
+
/**
|
|
82
|
+
* Gravité de la ligne d'une requête HTTP : celle du code de son appel RPC
|
|
83
|
+
* quand il est fixé — le statut HTTP d'un appel gRPC reste 200 quand l'appel
|
|
84
|
+
* échoue —, sinon celle de son statut.
|
|
85
|
+
*
|
|
86
|
+
* @param context - le contexte de la requête.
|
|
87
|
+
* @param status - son statut HTTP.
|
|
88
|
+
* @returns la gravité de la ligne.
|
|
89
|
+
*/
|
|
90
|
+
declare function severityOfHttp(context: IHttpContext, status: number | null | undefined): Severity;
|
|
62
91
|
export interface JsonAuditLoggerOptions {
|
|
63
92
|
/**
|
|
64
93
|
* Whether to include `error.stack` and recursive `error.cause.stack`.
|
|
@@ -115,8 +144,9 @@ declare class JsonAuditLogger implements IRequestLogger {
|
|
|
115
144
|
/**
|
|
116
145
|
* Decide whether the current HTTP request must be logged (audit sampling).
|
|
117
146
|
*
|
|
118
|
-
* Always `true` when `sampleRate <= 1`, on errors,
|
|
119
|
-
*
|
|
147
|
+
* Always `true` when `sampleRate <= 1`, on errors, for `status >= 400` and
|
|
148
|
+
* for a failed RPC call — whose HTTP status may stay 200 (failures are
|
|
149
|
+
* never sampled out). Otherwise selects 1 in `sampleRate` of
|
|
120
150
|
* the 2xx/3xx requests with a deterministic counter.
|
|
121
151
|
*
|
|
122
152
|
* Called by `Context.logRequest()` **before** `renderHttp`, so a sampled-out
|
|
@@ -137,4 +167,4 @@ declare class JsonAuditLogger implements IRequestLogger {
|
|
|
137
167
|
private serializeError;
|
|
138
168
|
}
|
|
139
169
|
export default JsonAuditLogger;
|
|
140
|
-
export { severityFromStatus, statusOf };
|
|
170
|
+
export { severityFromRpcCode, severityFromStatus, severityOfHttp, statusOf };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { IErrorRenderer, IErrorHttpResult, IErrorWebsocketResult } from "../interfaces/IErrorRenderer.js";
|
|
1
|
+
import type { IErrorRenderer, IErrorHttpResult, IErrorWebsocketResult, IErrorDescription } from "../interfaces/IErrorRenderer.js";
|
|
2
2
|
import type { IHttpContext, IWebsocketContext } from "../interfaces/IContext.js";
|
|
3
3
|
/** Champ fautif, tel qu'exposé au client dans le corps JSON (`error.fields`). */
|
|
4
4
|
export interface IValidationField {
|
|
@@ -34,10 +34,11 @@ export declare function toValidationFields(error: Error): IValidationField[] | n
|
|
|
34
34
|
/**
|
|
35
35
|
* Reconnaît un identifiant MAL FORMÉ refusé par la base, et rend la valeur fautive.
|
|
36
36
|
*
|
|
37
|
-
*
|
|
38
|
-
* un ObjectId), PostgreSQL par `22P02` (la clé est un `uuid` ou un entier)
|
|
39
|
-
*
|
|
40
|
-
*
|
|
37
|
+
* Trois sources le disent : MongoDB par une `CastError` de Mongoose (la clé est
|
|
38
|
+
* un ObjectId), PostgreSQL par `22P02` (la clé est un `uuid` ou un entier), et
|
|
39
|
+
* le kit de colonnes portable par une `ColumnValueError` de genre `uuid` ou
|
|
40
|
+
* `integer` — il refuse sur les trois moteurs la clé que PostgreSQL refuserait. Une clé rangée en
|
|
41
|
+
* texte NATIF ne lève rien, la lecture rend « rien » : le même 404.
|
|
41
42
|
*
|
|
42
43
|
* Même descente dans `cause` que {@link isUniqueViolation} (Drizzle enveloppe).
|
|
43
44
|
*
|
|
@@ -105,6 +106,27 @@ export declare function schemaMismatchOf(error: unknown): SchemaMismatchConfiden
|
|
|
105
106
|
declare class DefaultErrorRenderer implements IErrorRenderer {
|
|
106
107
|
renderHttp(error: Error, context: IHttpContext): IErrorHttpResult;
|
|
107
108
|
renderWebsocket(error: Error, context: IWebsocketContext): IErrorWebsocketResult;
|
|
109
|
+
/**
|
|
110
|
+
* Le statut HTTP et le message client qu'une route HTTP rendrait pour cette
|
|
111
|
+
* erreur — mêmes classements que {@link renderHttp} (validation 422, conflit
|
|
112
|
+
* 409, identifiant malformé, code numérique) et même opacité d'un 5xx en
|
|
113
|
+
* production —, sans RIEN écrire : ni statut sur la réponse, ni `metaData`,
|
|
114
|
+
* ni pile formatée. Sert les transports sans corps d'erreur : un appel gRPC
|
|
115
|
+
* traduit ce statut en code (ADR-0026 D7).
|
|
116
|
+
*
|
|
117
|
+
* Un identifiant malformé y vaut 400 : sans contexte, aucun chemin ne le
|
|
118
|
+
* désigne.
|
|
119
|
+
*
|
|
120
|
+
* @param error - l'erreur levée.
|
|
121
|
+
* @returns son statut émettable et le message destiné au client.
|
|
122
|
+
*
|
|
123
|
+
* @experimental Surface gRPC, ADR-0026 D11.
|
|
124
|
+
*/
|
|
125
|
+
describe(error: Error): IErrorDescription;
|
|
126
|
+
/**
|
|
127
|
+
* Ramène une erreur à une `HttpError`. Sans contexte (`describe`), rien
|
|
128
|
+
* n'est écrit : `HttpError` ne pose le statut sur la réponse qu'avec lui.
|
|
129
|
+
*/
|
|
108
130
|
private toHttpError;
|
|
109
131
|
/**
|
|
110
132
|
* Ramène un `code` d'erreur à un statut HTTP réellement émettable.
|
|
@@ -147,11 +147,20 @@ declare class HttpKernel extends Service implements IHttpKernelInterface {
|
|
|
147
147
|
* dans `onHttpRequest` (0 alloc/concat par requête).
|
|
148
148
|
*/
|
|
149
149
|
private computeSecurityHeaderCaches;
|
|
150
|
+
/**
|
|
151
|
+
* En-têtes du transport d'une réponse, figés au démarrage — ce que
|
|
152
|
+
* `HttpResponse` place en tête de sa réserve.
|
|
153
|
+
*
|
|
154
|
+
* @param type - famille du serveur qui a reçu la requête.
|
|
155
|
+
* @returns la liste plate `[nom, valeur, …]`, noms en minuscules.
|
|
156
|
+
*/
|
|
157
|
+
transportHeaders(type: ServerType): readonly string[];
|
|
150
158
|
/**
|
|
151
159
|
* Ce que ce kernel ÉMET réellement comme en-têtes de sécurité transport.
|
|
152
160
|
*
|
|
153
161
|
* Ces trois en-têtes (HSTS, X-Frame-Options, X-Content-Type-Options) sont posés
|
|
154
|
-
*
|
|
162
|
+
* par `@nodefony/http` sur TOUTE réponse (en tête de la réserve de `HttpResponse`),
|
|
163
|
+
* statiques et pages d'erreur comprises
|
|
155
164
|
* — pas par `@nodefony/security`, dont les clés homonymes sont inertes. Toute
|
|
156
165
|
* console d'administration doit donc lire CE point, sinon elle affiche une
|
|
157
166
|
* intention de configuration au lieu de l'état appliqué.
|
|
@@ -207,7 +216,7 @@ declare class HttpKernel extends Service implements IHttpKernelInterface {
|
|
|
207
216
|
* Le message nomme l'action, ce qu'elle a rendu et le geste qui convient
|
|
208
217
|
* (`unsentResponseWarning`).
|
|
209
218
|
*
|
|
210
|
-
* Appelé au timeout, AVANT que le
|
|
219
|
+
* Appelé au timeout, AVANT que le 503 parte — après, `sended` est vrai et
|
|
211
220
|
* plus rien ne se signalerait — et au démontage, pour un client parti avant.
|
|
212
221
|
* Gratuit en production : rien n'est lu au-delà de `waitAsync`.
|
|
213
222
|
*
|
|
@@ -474,6 +483,17 @@ declare class HttpKernel extends Service implements IHttpKernelInterface {
|
|
|
474
483
|
* @returns `undefined` quand le démontage est terminé ; sinon la promesse de
|
|
475
484
|
* sa fin, qui ne rejette pas.
|
|
476
485
|
*/
|
|
486
|
+
/**
|
|
487
|
+
* Fixe le code d'un appel RPC au `close` : « réponse finie » est la règle
|
|
488
|
+
* unique du noyau ({@link responseEnded}, celle du 499), jamais
|
|
489
|
+
* `writableFinished`, qui dit « finie » sur une annulation HTTP/2. Une cause
|
|
490
|
+
* rendue par l'appel devient l'erreur de la requête : la ligne d'accès la
|
|
491
|
+
* porte, le canal la publie — une ligne par appel en erreur (D10 point 3).
|
|
492
|
+
*
|
|
493
|
+
* @param context - le contexte de la requête.
|
|
494
|
+
* @param rpc - son appel RPC.
|
|
495
|
+
*/
|
|
496
|
+
private settleRpc;
|
|
477
497
|
private teardownHttp;
|
|
478
498
|
/**
|
|
479
499
|
* Suite ASYNCHRONE du démontage, quand il y a des hooks à attendre :
|
|
@@ -522,6 +542,10 @@ declare class HttpKernel extends Service implements IHttpKernelInterface {
|
|
|
522
542
|
/**
|
|
523
543
|
* Chemin d'erreur de {@link handleHttp} : libère le scope d'un contexte qui
|
|
524
544
|
* n'a pas pu se construire, puis rend l'erreur au client (`onError`).
|
|
545
|
+
*
|
|
546
|
+
* Sans contexte, `onError` n'a rien sur quoi écrire : la réponse BRUTE
|
|
547
|
+
* reçoit alors un 500 nu. Sinon HTTP/1.1 coupait la connexion sans un octet
|
|
548
|
+
* et HTTP/2 laissait le flux pendu.
|
|
525
549
|
*/
|
|
526
550
|
private failHttp;
|
|
527
551
|
/**
|
|
@@ -545,6 +569,15 @@ declare class HttpKernel extends Service implements IHttpKernelInterface {
|
|
|
545
569
|
* N'attend que le repli statique, et seulement quand aucune route ne matche.
|
|
546
570
|
*/
|
|
547
571
|
private routeHttpRequest;
|
|
572
|
+
/**
|
|
573
|
+
* L'échéance de réception HTTP/2 du serveur qui sert (`requestTimeout` de sa
|
|
574
|
+
* section), créée au premier corps HTTP/2 lu ; `null` si le délai vaut 0.
|
|
575
|
+
*
|
|
576
|
+
* À l'échéance, la réception en cours est interrompue (`abortBody`) et la
|
|
577
|
+
* requête rendue en 408 par le chemin d'erreur habituel — comme un corps qui
|
|
578
|
+
* dépasse sa limite (413).
|
|
579
|
+
*/
|
|
580
|
+
private http2ReceiveDeadline;
|
|
548
581
|
/**
|
|
549
582
|
* Le corps — lu seulement s'il y en a un à lire —, puis les gardes
|
|
550
583
|
* ({@link onRequestEnd}) et l'action. Chacun n'est attendu que s'il attend.
|
|
@@ -715,7 +748,7 @@ declare class HttpKernel extends Service implements IHttpKernelInterface {
|
|
|
715
748
|
once(event: "close", listener: () => void): unknown;
|
|
716
749
|
}): boolean;
|
|
717
750
|
/**
|
|
718
|
-
* Re-valide tous les flux
|
|
751
|
+
* Re-valide tous les flux en cours et ferme ceux dont l'identité est morte.
|
|
719
752
|
* Publique pour qu'un banc la déclenche sans attendre le tick.
|
|
720
753
|
*/
|
|
721
754
|
revalidateStreams(): Promise<void>;
|
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
import type { IRequestLogger, IRequestLogEntry } from "../interfaces/IRequestLogger.js";
|
|
2
2
|
import type { IHttpContext, IWebsocketContext } from "../interfaces/IContext.js";
|
|
3
|
+
import type { IRpcOutcome } from "../interfaces/IRpcCall.js";
|
|
4
|
+
/**
|
|
5
|
+
* Segment d'un appel RPC sur la ligne d'accès : `RPC : <méthode> <NOM>`
|
|
6
|
+
* (ADR-0026 D10 point 4) — le statut HTTP reste à sa place. Sans code (appel
|
|
7
|
+
* jamais commencé), la méthode seule.
|
|
8
|
+
*
|
|
9
|
+
* @param rpc - le résultat de l'appel.
|
|
10
|
+
* @returns le segment, sans espace de tête.
|
|
11
|
+
*/
|
|
12
|
+
export declare function rpcSegment(rpc: IRpcOutcome): string;
|
|
3
13
|
/**
|
|
4
14
|
* Default Nodefony per-request logger — preserves the legacy colored format.
|
|
5
15
|
*
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Duplex } from "node:stream";
|
|
2
2
|
/**
|
|
3
|
-
* Gère l'event `clientError` d'un `http.Server` / `https.Server
|
|
3
|
+
* Gère l'event `clientError` d'un `http.Server` / `https.Server`, et des connexions
|
|
4
|
+
* HTTP/1.1 d'un serveur HTTP/2 à `allowHTTP1`.
|
|
4
5
|
*
|
|
5
6
|
* ⚠️ Doc Node (`http.Server` event `'clientError'`) : dès qu'un listener
|
|
6
7
|
* `clientError` est attaché, Node **cesse de fermer le socket automatiquement**
|
|
@@ -11,7 +12,7 @@ import type { Duplex } from "node:stream";
|
|
|
11
12
|
* @param error - erreur émise (codes `llhttp` : `HPE_*`, ou `ECONNRESET`…).
|
|
12
13
|
* @param socket - flux client brut (l'event `clientError` fournit un `Duplex`).
|
|
13
14
|
*/
|
|
14
|
-
export declare function handleClientError(error:
|
|
15
|
+
export declare function handleClientError(error: Error, socket: Duplex): void;
|
|
15
16
|
/**
|
|
16
17
|
* Gère l'event `sessionError` d'un serveur HTTP/2 (h2c ou TLS) : un pair PARTI
|
|
17
18
|
* se tait, toute autre erreur est rapportée.
|
|
@@ -16,9 +16,11 @@ export interface IDrainTerminator {
|
|
|
16
16
|
* Fabrique l'arrêt gracieux d'un serveur HTTP/1.1, HTTPS, HTTP/2 sur TLS ou h2c.
|
|
17
17
|
*
|
|
18
18
|
* Au `terminate()` (SIGTERM, `docker stop`), le serveur cesse d'accepter, puis :
|
|
19
|
-
* - **HTTP/2** : chaque session reçoit un GOAWAY
|
|
20
|
-
*
|
|
21
|
-
*
|
|
19
|
+
* - **HTTP/2** : chaque session reçoit un GOAWAY en deux temps — d'abord à
|
|
20
|
+
* `2^31-1` ({@link announceShutdown}), puis, un aller-retour plus tard, le
|
|
21
|
+
* définitif (`session.close()`). Les flux en vol se terminent, les nouveaux
|
|
22
|
+
* sont refusés, et le client sait qu'il doit rouvrir ailleurs au lieu de
|
|
23
|
+
* constater une coupure ;
|
|
22
24
|
* - **HTTP/1.1** : la réponse en vol part avec `Connection: close`, la socket
|
|
23
25
|
* inactive est fermée tout de suite, une requête qui arrive encore sur une
|
|
24
26
|
* socket gardée ouverte reçoit aussi `Connection: close`.
|
|
@@ -28,8 +30,8 @@ export interface IDrainTerminator {
|
|
|
28
30
|
*
|
|
29
31
|
* ⚠️ Les sockets WebSocket upgradées (sans réponse HTTP en cours) sont détruites
|
|
30
32
|
* SANS frame Close → les serveurs WS doivent fermer leurs clients (close 1001)
|
|
31
|
-
* AVANT ce drain. Garanti par
|
|
32
|
-
*
|
|
33
|
+
* AVANT ce drain. Garanti par `HttpKernel.drainTraffic` (ADR-0027 D2) : l'étape
|
|
34
|
+
* `dismiss` (1001) est attendue avant l'étape `drain`.
|
|
33
35
|
*
|
|
34
36
|
* @param server - serveur Node à drainer, créé AVANT son `listen` (le suivi des
|
|
35
37
|
* connexions commence ici)
|
|
@@ -67,8 +67,8 @@ export interface IPrebuiltUiOptions {
|
|
|
67
67
|
* requête. Le SPA fallback reste au controller du module (routes littérales,
|
|
68
68
|
* cf. StudioController).
|
|
69
69
|
*
|
|
70
|
-
* Perf : l'index est lu UNE fois (lazy, caché)
|
|
71
|
-
*
|
|
70
|
+
* Perf : l'index est lu UNE fois (lazy, caché) et découpé UNE fois autour des
|
|
71
|
+
* emplacements du nonce ; un rendu ne coûte qu'un `join`.
|
|
72
72
|
*/
|
|
73
73
|
export declare class PrebuiltUi {
|
|
74
74
|
readonly publicPath: string;
|
|
@@ -76,6 +76,8 @@ export declare class PrebuiltUi {
|
|
|
76
76
|
private readonly indexPath;
|
|
77
77
|
/** Template HTML caché — `null` tant que non lu (lazy). */
|
|
78
78
|
private template;
|
|
79
|
+
/** Index découpé autour des emplacements du nonce — `null` tant que non calculé. */
|
|
80
|
+
private nonceParts;
|
|
79
81
|
constructor(opts: IPrebuiltUiOptions);
|
|
80
82
|
/**
|
|
81
83
|
* Monte `distDir` sous `publicPath` auprès de `server-static` (résolu par
|
|
@@ -90,8 +92,11 @@ export declare class PrebuiltUi {
|
|
|
90
92
|
* Document HTML d'entrée de l'UI (index pré-buildé par Vite).
|
|
91
93
|
*
|
|
92
94
|
* @param nonce nonce CSP de la requête (`Context.cspNonce`) — injecté sur
|
|
93
|
-
* chaque `<script
|
|
94
|
-
*
|
|
95
|
+
* chaque `<script>`, `src` compris : sous `'strict-dynamic'`
|
|
96
|
+
* (ADR-0024 §C1), `'self'` est ignoré et seul le nonce autorise
|
|
97
|
+
* une balise ; ce qu'elle importe ensuite hérite de la confiance.
|
|
98
|
+
* Annoncé aussi par `<meta property="csp-nonce">` en tête de
|
|
99
|
+
* `<head>` (ADR-0024 §C2) : les `<style>` créés à l'exécution.
|
|
95
100
|
* @returns le HTML, ou un commentaire HTML fail-loud si l'index est absent
|
|
96
101
|
*/
|
|
97
102
|
renderIndex(nonce?: string): string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Container, Service, Severity, Msgid, Message, Pci, Pdu, KernelEventsType, nodefonyError, Scope } from "nodefony";
|
|
2
|
-
import type { IProfilerQuery, RequestContextPayload } from "nodefony";
|
|
2
|
+
import type { IProfilerQuery, IRequestUser, RequestContextPayload } from "nodefony";
|
|
3
3
|
import type { IRouteResolver, IRequestRouter } from "../../interfaces/IRouting.js";
|
|
4
4
|
import type { ISecurityZone } from "../../interfaces/ISecurity.js";
|
|
5
5
|
import { WebSocketServer } from "ws";
|
|
@@ -213,6 +213,14 @@ declare class Context extends Service implements IContextInterface {
|
|
|
213
213
|
* @param store - le magasin passé à `RequestContext.run`
|
|
214
214
|
*/
|
|
215
215
|
holdRequestStore(store: RequestContextPayload): void;
|
|
216
|
+
/**
|
|
217
|
+
* L'utilisateur authentifié de l'unité de travail, lu sur son magasin et
|
|
218
|
+
* non sur l'ALS : valable là où la bulle n'est plus active (rendu d'une
|
|
219
|
+
* erreur, démontage). Même règle que `RequestContext.getAuthenticatedUser`.
|
|
220
|
+
*
|
|
221
|
+
* @returns l'utilisateur connecté, ou `null` (anonyme, hors zone, nettoyé).
|
|
222
|
+
*/
|
|
223
|
+
authenticatedUser(): IRequestUser | null;
|
|
216
224
|
clean(): void;
|
|
217
225
|
/**
|
|
218
226
|
* Log d'un event du cycle de vie — gate boot-time (V2.1) : en production le
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import http from "node:http";
|
|
2
|
+
import { Readable } from "node:stream";
|
|
3
|
+
import type HttpContext from "./HttpContext.js";
|
|
4
|
+
/**
|
|
5
|
+
* Réponse en FLUX D'OCTETS — la sortie d'un processus, le relais d'un autre
|
|
6
|
+
* service, une archive construite à la volée : toute source d'octets qui n'est
|
|
7
|
+
* pas un fichier du disque.
|
|
8
|
+
*
|
|
9
|
+
* Le cycle de vie (prise de la réponse, session, fermeture lue sur la réponse,
|
|
10
|
+
* plafond par IP, révocation, coupure d'un client qui ne lit plus) est celui de
|
|
11
|
+
* la brique commune au SSE (`StreamLifecycle`). Ce fichier porte ce qui est
|
|
12
|
+
* propre aux octets :
|
|
13
|
+
* - les en-têtes au PREMIER morceau : une erreur de la source avant lui passe
|
|
14
|
+
* par le chemin d'erreur normal (`HttpKernel.onError`), donc un vrai 5xx ;
|
|
15
|
+
* - l'arrêt de la source par `destroy()`, jamais `unpipe()` — qui la laisse en
|
|
16
|
+
* pause, et un producteur bloqué en écriture ne meurt plus ;
|
|
17
|
+
* - un chien de garde sur une source MUETTE (`idleTimeout`) : un seul minuteur
|
|
18
|
+
* périodique par flux, qui compare le compteur d'octets — aucun minuteur ni
|
|
19
|
+
* appel d'horloge par morceau (mesuré : l'horodatage par morceau coûtait
|
|
20
|
+
* 2 à 6 % de CPU sur des morceaux de 4 Kio) ;
|
|
21
|
+
* - la coupure (jamais une fin propre) quand la source échoue après le premier
|
|
22
|
+
* octet : le client doit savoir que le corps est tronqué.
|
|
23
|
+
*/
|
|
24
|
+
/**
|
|
25
|
+
* Raison de la fin d'un flux d'octets.
|
|
26
|
+
*
|
|
27
|
+
* - `end` : la source est finie, ou le serveur a fermé le flux (durée de vie,
|
|
28
|
+
* révocation de l'identité, arrêt du serveur pour un flux `live`) ;
|
|
29
|
+
* - `client` : le client est parti ;
|
|
30
|
+
* - `error` : la source a échoué ;
|
|
31
|
+
* - `timeout` : la source est restée muette plus de `idleTimeout` ;
|
|
32
|
+
* - `stall` : le client ne lisait plus depuis `stallTimeout`.
|
|
33
|
+
*
|
|
34
|
+
* L'union PEUT S'AGRANDIR : un `switch` exhaustif garde une branche `default`.
|
|
35
|
+
*/
|
|
36
|
+
export type ByteStreamEndReason = "end" | "client" | "error" | "timeout" | "stall";
|
|
37
|
+
/** Ce que rend la fin d'un flux d'octets. */
|
|
38
|
+
export interface IByteStreamResult {
|
|
39
|
+
/** Pourquoi le flux s'est terminé. */
|
|
40
|
+
reason: ByteStreamEndReason;
|
|
41
|
+
/** Octets écrits sur la réponse. */
|
|
42
|
+
bytes: number;
|
|
43
|
+
}
|
|
44
|
+
/** Options d'une réponse en flux d'octets. */
|
|
45
|
+
export interface IByteStreamOptions {
|
|
46
|
+
/** Statut de la réponse, entre 200 et 599. Défaut : 200. */
|
|
47
|
+
status?: number | undefined;
|
|
48
|
+
/**
|
|
49
|
+
* En-têtes de la réponse, écrits au premier morceau. `Content-Length` est
|
|
50
|
+
* repris s'il est fourni ; sinon HTTP/1.1 envoie par morceaux. Défauts posés
|
|
51
|
+
* seulement s'ils manquent — ni ici, ni déjà sur la réponse :
|
|
52
|
+
* `Content-Type: application/octet-stream`, et pour un flux `live`
|
|
53
|
+
* `Cache-Control: no-cache, no-transform` et `X-Accel-Buffering: no`.
|
|
54
|
+
*/
|
|
55
|
+
headers?: http.OutgoingHttpHeaders | undefined;
|
|
56
|
+
/**
|
|
57
|
+
* Flux VIVANT (défaut `true`) : la sortie d'un processus, un relais — un
|
|
58
|
+
* proxy inverse ne doit pas le mettre en tampon, ni un cache le garder, d'où
|
|
59
|
+
* `Cache-Control: no-cache, no-transform` et `X-Accel-Buffering: no` par
|
|
60
|
+
* défaut. `false` pour une source FINIE et rejouable (un fichier, une
|
|
61
|
+
* archive) : aucun de ces deux en-têtes n'est posé.
|
|
62
|
+
*/
|
|
63
|
+
live?: boolean | undefined;
|
|
64
|
+
/**
|
|
65
|
+
* Délai maximal sans un octet de la source, en ms ; `0` le désarme. Au-delà :
|
|
66
|
+
* 504 si rien n'est encore parti, coupure sinon. Le silence est constaté
|
|
67
|
+
* par un tour de garde tous les quarts de délai : la coupure tombe entre
|
|
68
|
+
* `idleTimeout` et 1,25 × `idleTimeout`. Défaut : le délai de réponse
|
|
69
|
+
* du serveur (`responseTimeout`, 30 s). À garder sous le délai de lecture du
|
|
70
|
+
* proxy inverse (`proxy_read_timeout`, 60 s chez nginx).
|
|
71
|
+
*/
|
|
72
|
+
idleTimeout?: number | undefined;
|
|
73
|
+
/**
|
|
74
|
+
* Délai maximal pendant lequel une écriture peut rester bloquée — le client
|
|
75
|
+
* ne lit plus —, en ms ; au-delà, la connexion est coupée. `false` pour
|
|
76
|
+
* l'éteindre. Défaut : 30 000, celui du SSE.
|
|
77
|
+
*/
|
|
78
|
+
stallTimeout?: number | false | undefined;
|
|
79
|
+
/** Durée de vie maximale du flux, en ms. `false` (défaut) : pas de borne. */
|
|
80
|
+
maxDuration?: number | false | undefined;
|
|
81
|
+
/**
|
|
82
|
+
* Appelé une fois à la fin du flux, avec sa raison — AVANT la fin de la
|
|
83
|
+
* requête et la résolution de la promesse. Lié au contexte asynchrone de la
|
|
84
|
+
* requête.
|
|
85
|
+
*/
|
|
86
|
+
onClose?: ((reason: ByteStreamEndReason) => void) | undefined;
|
|
87
|
+
}
|
|
88
|
+
/** Une source d'octets : flux Node, ou flux web (`fetch().body`). */
|
|
89
|
+
export type ByteStreamSource = Readable | ReadableStream<Uint8Array>;
|
|
90
|
+
/**
|
|
91
|
+
* Répond par un flux d'octets sur la réponse d'un contexte HTTP.
|
|
92
|
+
*
|
|
93
|
+
* Prend la réponse à l'appel (le noyau ne peut plus répondre par-dessus) ;
|
|
94
|
+
* les en-têtes partent au premier morceau de la source. La promesse se règle à
|
|
95
|
+
* la fin du flux, quelle qu'en soit la raison, et ne rejette JAMAIS.
|
|
96
|
+
*
|
|
97
|
+
* @param context - le contexte de la requête, pas encore répondu.
|
|
98
|
+
* @param source - flux Node, ou flux web (`fetch().body`) ; jamais en mode objet.
|
|
99
|
+
* @param options - statut, en-têtes, délais, écouteur de fin.
|
|
100
|
+
* @returns la raison de la fin et le nombre d'octets envoyés.
|
|
101
|
+
* @throws TypeError quand la source est en mode objet.
|
|
102
|
+
* @throws RangeError quand une option est hors bornes.
|
|
103
|
+
* @throws HttpError 500 quand la réponse est déjà partie ; 429 quand l'IP a
|
|
104
|
+
* déjà tous ses flux et sockets (`wsMaxConnectionsPerIp`).
|
|
105
|
+
*
|
|
106
|
+
* La source appartient au flux dès l'appel : quand l'appel lève, elle est
|
|
107
|
+
* DÉTRUITE (un flux web est annulé) avant que l'erreur ne remonte.
|
|
108
|
+
*/
|
|
109
|
+
export declare function openByteStream(context: HttpContext, source: ByteStreamSource, options?: IByteStreamOptions): Promise<IByteStreamResult>;
|
|
@@ -2,7 +2,7 @@ import { ServerType, SchemeType } from "../../../service/http-kernel.js";
|
|
|
2
2
|
import HttpError from "../../errors/httpError.js";
|
|
3
3
|
import Context, { HTTPMethod } from "../Context.js";
|
|
4
4
|
import { Container, Scope, nodefonyError } from "nodefony";
|
|
5
|
-
import type { MaybePromise } from "nodefony";
|
|
5
|
+
import type { DefaultEventsMap, EventsMap, MaybePromise } from "nodefony";
|
|
6
6
|
import HttpRequest from "./Request.js";
|
|
7
7
|
import HttpResponse from "./Response.js";
|
|
8
8
|
import Http2Request from "../http2/Request.js";
|
|
@@ -43,8 +43,32 @@ export interface ProxyType {
|
|
|
43
43
|
export declare function switchUrlScheme(from: URL, scheme: "http" | "https", port?: number): string;
|
|
44
44
|
export type HttpRequestType = Http2Request | HttpRequest;
|
|
45
45
|
export type HttpRsponseType = Http2Response | HttpResponse;
|
|
46
|
+
/**
|
|
47
|
+
* Route le délai d'inactivité d'une socket HTTP/1.1 vers la requête qu'elle
|
|
48
|
+
* porte : 503 si une requête est en cours, fermeture si la connexion
|
|
49
|
+
* persistante est inactive. Écouteur `timeout` du SERVEUR — un seul pour
|
|
50
|
+
* toutes ses connexions —, que Node appelle avec la socket en argument
|
|
51
|
+
* (`socketOnTimeout` → `server.emit("timeout", socket)`).
|
|
52
|
+
*
|
|
53
|
+
* Pourquoi au serveur et pas sur la socket : Node y pose déjà son propre
|
|
54
|
+
* écouteur `timeout`, et un second faisait créer à `EventEmitter` un tableau
|
|
55
|
+
* d'écouteurs par CONNEXION. Ce site d'allocation, partagé avec tout le
|
|
56
|
+
* processus et toujours survivant (une connexion vit longtemps), finissait
|
|
57
|
+
* par être basculé dans le vieux tas par V8 (pretenuring) — dans un démarrage
|
|
58
|
+
* sur trois environ, mesuré sous charge. Le graphe de chaque requête y
|
|
59
|
+
* restait alors accroché jusqu'à la collecte complète suivante : +45 % de CPU
|
|
60
|
+
* par requête, 14 à 19 collectes complètes au lieu de 3. Un écouteur par
|
|
61
|
+
* serveur supprime aussi une fermeture et une entrée de registre par connexion.
|
|
62
|
+
*
|
|
63
|
+
* @param socket - la socket dont le délai a expiré ; une session HTTP/2 (même
|
|
64
|
+
* événement sur un serveur `allowHTTP1`) est fermée par l'écouteur que pose
|
|
65
|
+
* `setHttp2SessionTimeout` (`src/servers/http2Limits.ts`)
|
|
66
|
+
*/
|
|
67
|
+
export declare function routeSocketTimeout(socket: unknown): void;
|
|
46
68
|
import type { IHttpContext as IHttpContextInterface } from "../../../interfaces/IContext.js";
|
|
69
|
+
import type { IRpcCall } from "../../../interfaces/IRpcCall.js";
|
|
47
70
|
import { type ISseStreamOptions, type SseStream } from "./SseStream.js";
|
|
71
|
+
import { type ByteStreamSource, type IByteStreamOptions, type IByteStreamResult } from "./ByteStream.js";
|
|
48
72
|
declare class HttpContext extends Context implements IHttpContextInterface {
|
|
49
73
|
proxy: ProxyType | null;
|
|
50
74
|
/** Socket h1 inscrite dans `socketActiveContext` — retirée par `clean()`. */
|
|
@@ -56,6 +80,15 @@ declare class HttpContext extends Context implements IHttpContextInterface {
|
|
|
56
80
|
* son montage. `null` = servie par l'application (cas de toute requête).
|
|
57
81
|
*/
|
|
58
82
|
relayAccessLog: "all" | "errors" | null;
|
|
83
|
+
/**
|
|
84
|
+
* L'appel RPC servi sur cette requête (gRPC, gRPC-Web, Connect), `null`
|
|
85
|
+
* hors appel RPC (ADR-0026 D10) : un champ, aucune allocation. Posé par le
|
|
86
|
+
* point d'entrée gRPC ; à l'échéance du délai de réponse, {@link _onTimeout}
|
|
87
|
+
* le termine au lieu d'écrire un 503.
|
|
88
|
+
*
|
|
89
|
+
* @experimental Surface gRPC, ADR-0026 D11.
|
|
90
|
+
*/
|
|
91
|
+
rpc: IRpcCall | null;
|
|
59
92
|
request: HttpRequestType;
|
|
60
93
|
response: HttpRsponseType;
|
|
61
94
|
uploadService: uploadService | null;
|
|
@@ -75,6 +108,18 @@ declare class HttpContext extends Context implements IHttpContextInterface {
|
|
|
75
108
|
* d'éventuels listeners externes — guard 0-listener : 0 alloc sinon.
|
|
76
109
|
*/
|
|
77
110
|
_onTimeout(): void;
|
|
111
|
+
/**
|
|
112
|
+
* Ré-arme le délai de réponse de la requête à la valeur propre de sa route
|
|
113
|
+
* (`responseTimeout` d'une option de route), une fois celle-ci résolue.
|
|
114
|
+
*
|
|
115
|
+
* Même mécanisme que {@link setTimeout} — délai d'inactivité de la socket
|
|
116
|
+
* (HTTP/1.1) ou du flux (HTTP/2) —, sans second écouteur : sous HTTP/2,
|
|
117
|
+
* `setTimeout(ms)` sans rappel remplace le minuteur et garde celui posé par
|
|
118
|
+
* {@link setTimeout}. `0` désactive le délai pour la requête.
|
|
119
|
+
*
|
|
120
|
+
* @param ms - délai de la route, en millisecondes.
|
|
121
|
+
*/
|
|
122
|
+
rearmTimeout(ms: number): void;
|
|
78
123
|
setScheme(): SchemeType;
|
|
79
124
|
/**
|
|
80
125
|
* Sert la requête : délai de réponse, hooks `onRequest`, puis l'action
|
|
@@ -95,9 +140,21 @@ declare class HttpContext extends Context implements IHttpContextInterface {
|
|
|
95
140
|
* réellement rendu (le relais écrit la réponse brute, pas celle du
|
|
96
141
|
* contexte) ; un montage `accessLog: "errors"` ne l'écrit qu'en échec.
|
|
97
142
|
*
|
|
143
|
+
* Le statut natif n'est recopié que si la réponse a été TERMINÉE
|
|
144
|
+
* ({@link responseEnded}) : sinon il n'a jamais atteint le client (200 par
|
|
145
|
+
* défaut de Node), et le statut du contexte — 499 d'un client parti — dit
|
|
146
|
+
* vrai. Règle unique pour toute réponse écrite par un tiers (#695, critère
|
|
147
|
+
* 38).
|
|
148
|
+
*
|
|
98
149
|
* @param httpError - l'erreur de la requête, s'il y en a une
|
|
99
150
|
*/
|
|
100
151
|
logRequest(httpError?: Error | HttpError | nodefonyError | null): import("nodefony").Pdu | undefined;
|
|
152
|
+
/**
|
|
153
|
+
* Reprend le statut de la réponse native, écrite par un tiers (relais,
|
|
154
|
+
* adaptateur RPC) — si la réponse est TERMINÉE seulement : sinon ce statut
|
|
155
|
+
* n'a jamais atteint le client, et celui du contexte (499) dit vrai.
|
|
156
|
+
*/
|
|
157
|
+
private adoptNativeStatus;
|
|
101
158
|
/**
|
|
102
159
|
* Nettoie le contexte, et le DÉTACHE de sa socket h1 : la connexion
|
|
103
160
|
* persistante survit à la requête, et l'entrée de `socketActiveContext`
|
|
@@ -157,11 +214,50 @@ declare class HttpContext extends Context implements IHttpContextInterface {
|
|
|
157
214
|
*
|
|
158
215
|
* La requête ne se termine qu'à `close()` du flux, ou au départ du client.
|
|
159
216
|
*
|
|
217
|
+
* @typeParam Events - carte des événements du flux (cf `SseStream`).
|
|
160
218
|
* @param options - battement de cœur, délai `retry:` initial.
|
|
161
219
|
* @returns le flux, ou sa promesse quand une session est à sauver d'abord.
|
|
162
220
|
* @throws HttpError 500 quand la réponse est déjà partie.
|
|
163
221
|
*/
|
|
164
|
-
openSse(options?: ISseStreamOptions): SseStream | Promise<SseStream
|
|
222
|
+
openSse<Events extends EventsMap = DefaultEventsMap>(options?: ISseStreamOptions): SseStream<Events> | Promise<SseStream<Events>>;
|
|
223
|
+
/**
|
|
224
|
+
* Répond par un FLUX D'OCTETS : un `<video src>`, un `fetch()`, un
|
|
225
|
+
* téléchargement ou un outil tiers (curl) le consomment comme n'importe quelle
|
|
226
|
+
* réponse HTTP, une réponse par consommateur.
|
|
227
|
+
*
|
|
228
|
+
* La réponse est prise à l'appel, ses en-têtes partent au premier morceau de
|
|
229
|
+
* la source. La source est DÉTRUITE à la fin, quelle qu'en soit la raison
|
|
230
|
+
* (jamais `unpipe`, qui laisse un producteur bloqué en écriture). Pour des
|
|
231
|
+
* événements texte lus par `EventSource`, voir {@link HttpContext.openSse}.
|
|
232
|
+
* Dans un middleware, la requête est répondue : ne pas appeler la suite.
|
|
233
|
+
*
|
|
234
|
+
* @param source - flux Node, ou flux web (`fetch().body`) ; jamais en mode objet.
|
|
235
|
+
* @param options - statut, en-têtes, délais, écouteur de fin.
|
|
236
|
+
* @returns la raison de la fin et le nombre d'octets ; ne rejette jamais.
|
|
237
|
+
* @throws HttpError 500 quand la réponse est déjà partie, 429 au-delà du
|
|
238
|
+
* plafond de connexions par IP ; TypeError pour une source en mode objet.
|
|
239
|
+
* Quand l'appel lève, la source est DÉTRUITE (un flux web est annulé).
|
|
240
|
+
*/
|
|
241
|
+
openStream(source: ByteStreamSource, options?: IByteStreamOptions): Promise<IByteStreamResult>;
|
|
242
|
+
/**
|
|
243
|
+
* Répond par une `Response` Web standard — celle que rend `fetch()`, ou une
|
|
244
|
+
* réponse construite (`new Response(…)`, `Response.json(…)`) : son statut,
|
|
245
|
+
* ses en-têtes, et son corps EN FLUX, jamais lu d'avance.
|
|
246
|
+
*
|
|
247
|
+
* C'est ce que fait le framework quand une action renvoie une `Response`.
|
|
248
|
+
* Une réponse relayée (issue de `fetch`) perd `content-encoding`,
|
|
249
|
+
* `content-length` et `set-cookie` de l'amont ; une réponse construite garde
|
|
250
|
+
* les siens. Les en-têtes de connexion ne partent jamais. Le reste — arrêt au
|
|
251
|
+
* départ du client, contre-pression, délais, HEAD sans lire le corps — est
|
|
252
|
+
* celui de {@link HttpContext.openStream}.
|
|
253
|
+
*
|
|
254
|
+
* @param response - une `Response` dont le corps n'a pas été consommé.
|
|
255
|
+
* @param options - délais et écouteur de fin ; statut et en-têtes viennent de la réponse.
|
|
256
|
+
* @returns la raison de la fin et le nombre d'octets ; ne rejette jamais.
|
|
257
|
+
* @throws HttpError 502 pour `Response.error()` (statut 0, aucune réponse) ;
|
|
258
|
+
* les cas de {@link HttpContext.openStream} sinon.
|
|
259
|
+
*/
|
|
260
|
+
openWebResponse(response: Response, options?: Omit<IByteStreamOptions, "status" | "headers">): Promise<IByteStreamResult>;
|
|
165
261
|
flush(chunk: unknown, encoding: BufferEncoding): MaybePromise<HttpResponse>;
|
|
166
262
|
/**
|
|
167
263
|
* Termine la requête : hook `onClose`, puis fin de la réponse si l'envoi ne
|
|
@@ -194,7 +290,7 @@ declare class HttpContext extends Context implements IHttpContextInterface {
|
|
|
194
290
|
getHost(): string | undefined;
|
|
195
291
|
getUserAgent(): string | undefined;
|
|
196
292
|
getMethod(): HTTPMethod;
|
|
197
|
-
setContentType(type?: string, encoding?: BufferEncoding): void
|
|
293
|
+
setContentType(type?: string, encoding?: BufferEncoding): void;
|
|
198
294
|
protected resolveIsHtml(): boolean;
|
|
199
295
|
setDefaultContentType(): void;
|
|
200
296
|
setContextJson(encoding?: BufferEncoding): void;
|