@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
|
@@ -108,6 +108,7 @@ export declare const httpConfigSchema: z.ZodObject<{
|
|
|
108
108
|
}, z.core.$loose>]>>;
|
|
109
109
|
skipUTF8Validation: z.ZodDefault<z.ZodBoolean>;
|
|
110
110
|
autoPong: z.ZodDefault<z.ZodBoolean>;
|
|
111
|
+
maxPendingAutoPongs: z.ZodDefault<z.ZodNumber>;
|
|
111
112
|
allowSynchronousEvents: z.ZodDefault<z.ZodBoolean>;
|
|
112
113
|
maxBackpressure: z.ZodDefault<z.ZodNumber>;
|
|
113
114
|
backpressureCloseAfterDrops: z.ZodDefault<z.ZodNumber>;
|
|
@@ -115,6 +116,8 @@ export declare const httpConfigSchema: z.ZodObject<{
|
|
|
115
116
|
close: "close";
|
|
116
117
|
drop: "drop";
|
|
117
118
|
}>>;
|
|
119
|
+
maxFramesPerSecond: z.ZodDefault<z.ZodNumber>;
|
|
120
|
+
frameRateCloseAfterRejects: z.ZodDefault<z.ZodNumber>;
|
|
118
121
|
}, z.core.$loose>>;
|
|
119
122
|
websocketSecure: z.ZodDefault<z.ZodObject<{
|
|
120
123
|
keepaliveInterval: z.ZodDefault<z.ZodNumber>;
|
|
@@ -132,6 +135,7 @@ export declare const httpConfigSchema: z.ZodObject<{
|
|
|
132
135
|
}, z.core.$loose>]>>;
|
|
133
136
|
skipUTF8Validation: z.ZodDefault<z.ZodBoolean>;
|
|
134
137
|
autoPong: z.ZodDefault<z.ZodBoolean>;
|
|
138
|
+
maxPendingAutoPongs: z.ZodDefault<z.ZodNumber>;
|
|
135
139
|
allowSynchronousEvents: z.ZodDefault<z.ZodBoolean>;
|
|
136
140
|
maxBackpressure: z.ZodDefault<z.ZodNumber>;
|
|
137
141
|
backpressureCloseAfterDrops: z.ZodDefault<z.ZodNumber>;
|
|
@@ -139,6 +143,8 @@ export declare const httpConfigSchema: z.ZodObject<{
|
|
|
139
143
|
close: "close";
|
|
140
144
|
drop: "drop";
|
|
141
145
|
}>>;
|
|
146
|
+
maxFramesPerSecond: z.ZodDefault<z.ZodNumber>;
|
|
147
|
+
frameRateCloseAfterRejects: z.ZodDefault<z.ZodNumber>;
|
|
142
148
|
}, z.core.$loose>>;
|
|
143
149
|
statics: z.ZodDefault<z.ZodObject<{
|
|
144
150
|
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
@@ -204,6 +210,14 @@ export declare const httpConfigSchema: z.ZodObject<{
|
|
|
204
210
|
}>>;
|
|
205
211
|
}, z.core.$strict>>>;
|
|
206
212
|
}, z.core.$strict>>;
|
|
213
|
+
grpc: z.ZodDefault<z.ZodObject<{
|
|
214
|
+
grpc: z.ZodDefault<z.ZodBoolean>;
|
|
215
|
+
grpcWeb: z.ZodDefault<z.ZodBoolean>;
|
|
216
|
+
connect: z.ZodDefault<z.ZodBoolean>;
|
|
217
|
+
readMaxBytes: z.ZodDefault<z.ZodNumber>;
|
|
218
|
+
writeMaxBytes: z.ZodDefault<z.ZodNumber>;
|
|
219
|
+
requireConnectProtocolHeader: z.ZodDefault<z.ZodBoolean>;
|
|
220
|
+
}, z.core.$strict>>;
|
|
207
221
|
wsMaxConnectionsPerIp: z.ZodDefault<z.ZodNullable<z.ZodNumber>>;
|
|
208
222
|
}, z.core.$strict>;
|
|
209
223
|
/** Type de sortie (config normalisée + défauts appliqués). */
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import type { ContextKey, ContextValues, HandlerContext } from "@connectrpc/connect";
|
|
2
|
+
import type { IRpcCall, RpcSystem } from "../interfaces/IRpcCall.js";
|
|
3
|
+
import type HttpContext from "../src/context/http/HttpContext.js";
|
|
4
|
+
/**
|
|
5
|
+
* Fiche d'un appel gRPC : ce que Nodefony attache à l'appel, et le
|
|
6
|
+
* `ContextValues` que Connect remet au gestionnaire (`ctx.values`).
|
|
7
|
+
*
|
|
8
|
+
* Connect alloue à chaque appel un `ContextValues` fait d'un objet littéral et
|
|
9
|
+
* de trois fermetures (`context-values.js#createContextValues`), dont la forme
|
|
10
|
+
* change à chaque `set`. La fiche le REMPLACE (option `contextValues` de
|
|
11
|
+
* l'adaptateur) : une classe à champs déclarés, méthodes au prototype, une
|
|
12
|
+
* allocation par appel au lieu de quatre.
|
|
13
|
+
*
|
|
14
|
+
* Les clés posées par un tiers (intercepteur, porte) sont confiées à un
|
|
15
|
+
* `createContextValues()` créé au premier `set` : aucune allocation tant que
|
|
16
|
+
* personne n'en pose, et aucune conversion de type — la valeur rendue est celle
|
|
17
|
+
* que le magasin de Connect a typée.
|
|
18
|
+
*
|
|
19
|
+
* C'est aussi l'appel RPC du contexte (`HttpContext.rpc`, ADR-0026 D10) : à
|
|
20
|
+
* l'échéance du délai de réponse, le noyau le termine par {@link expire} ; au
|
|
21
|
+
* `close` de la réponse, il en fixe le code par {@link settle}, que lisent la
|
|
22
|
+
* ligne d'accès, l'audit et le canal de traçage.
|
|
23
|
+
*
|
|
24
|
+
* @experimental Surface gRPC, ADR-0026 D11.
|
|
25
|
+
*/
|
|
26
|
+
export declare class GrpcCall implements ContextValues, IRpcCall {
|
|
27
|
+
#private;
|
|
28
|
+
/**
|
|
29
|
+
* L'objet qui implémente le service pour CET appel : le contrôleur, une
|
|
30
|
+
* instance par appel sous `@Scope("request")`. `null` quand l'adaptateur est
|
|
31
|
+
* appelé hors de {@link GrpcEndpoint.serve} (jamais en service normal).
|
|
32
|
+
*/
|
|
33
|
+
readonly target: object | null;
|
|
34
|
+
/**
|
|
35
|
+
* Le contexte de la requête qui porte l'appel : l'identité y est lue
|
|
36
|
+
* (`authenticatedUser()`) sur son magasin, jamais par l'ALS, pour choisir
|
|
37
|
+
* entre 16 et 7 (ADR-0026 D5, D7). `null` hors de {@link GrpcEndpoint.serve}.
|
|
38
|
+
*/
|
|
39
|
+
readonly context: HttpContext | null;
|
|
40
|
+
constructor(target: object | null, context?: HttpContext | null);
|
|
41
|
+
/**
|
|
42
|
+
* Le protocole parlé sur le fil : celui du contexte d'appel (`grpc`,
|
|
43
|
+
* `grpc-web`, `connect`) ; à défaut, celui des en-têtes de la requête.
|
|
44
|
+
*/
|
|
45
|
+
get system(): RpcSystem;
|
|
46
|
+
/**
|
|
47
|
+
* `paquet.Service/Méthode` : le chemin de la route, que l'adaptateur a
|
|
48
|
+
* reconnu à l'octet près. Lu à la première demande, puis retenu.
|
|
49
|
+
*/
|
|
50
|
+
get method(): string;
|
|
51
|
+
/** Le code de l'appel (0 à 16), `null` avant {@link settle}. */
|
|
52
|
+
get code(): number | null;
|
|
53
|
+
/** Le nom du code (`OK`, `UNAVAILABLE`…), `null` avec lui. */
|
|
54
|
+
get codeName(): string | null;
|
|
55
|
+
/**
|
|
56
|
+
* Fixe le code de l'appel au `close` de la réponse (ADR-0026 D10 point 2) :
|
|
57
|
+
*
|
|
58
|
+
* - motif `ConnectError` → son code ; sa cause, si c'est une `Error`, part
|
|
59
|
+
* à la ligne d'accès (exception traduite par D7). Réponse NON finie : 1,
|
|
60
|
+
* sauf une fin posée par le serveur (échéance 4, interruption de la fiche)
|
|
61
|
+
* — le client est parti, quel que soit le code de son `RST_STREAM` ;
|
|
62
|
+
* - `AbortError` ou aucun motif → 0 si la réponse est finie, sinon 1 (le
|
|
63
|
+
* client est parti — le 499 du noyau, dit en gRPC) ;
|
|
64
|
+
* - autre valeur → 13, et elle part à la ligne d'accès.
|
|
65
|
+
*
|
|
66
|
+
* Une interruption du serveur (délai échu, identité révoquée) abaisse le
|
|
67
|
+
* signal avec sa `ConnectError` : elle suit la première règle. Sans contexte
|
|
68
|
+
* d'appel, le code reste `null`.
|
|
69
|
+
*
|
|
70
|
+
* @param ended - la réponse a-t-elle été terminée par le serveur ?
|
|
71
|
+
* @returns la cause à porter par la ligne d'accès, `null` sinon.
|
|
72
|
+
*/
|
|
73
|
+
settle(ended: boolean): Error | null;
|
|
74
|
+
/**
|
|
75
|
+
* Lit une valeur posée par un tiers, ou la valeur par défaut de sa clé.
|
|
76
|
+
*
|
|
77
|
+
* @param key - la clé (`createContextKey`).
|
|
78
|
+
* @returns la valeur posée, sinon `key.defaultValue`.
|
|
79
|
+
*/
|
|
80
|
+
get<T>(key: ContextKey<T>): T;
|
|
81
|
+
/**
|
|
82
|
+
* Pose une valeur pour la durée de l'appel.
|
|
83
|
+
*
|
|
84
|
+
* @param key - la clé (`createContextKey`).
|
|
85
|
+
* @param value - la valeur.
|
|
86
|
+
* @returns la fiche, pour chaîner.
|
|
87
|
+
*/
|
|
88
|
+
set<T>(key: ContextKey<T>, value: T): this;
|
|
89
|
+
/**
|
|
90
|
+
* Retire une valeur ; sa clé rendra de nouveau sa valeur par défaut.
|
|
91
|
+
*
|
|
92
|
+
* @param key - la clé (`createContextKey`).
|
|
93
|
+
* @returns la fiche, pour chaîner.
|
|
94
|
+
*/
|
|
95
|
+
delete(key: ContextKey<unknown>): this;
|
|
96
|
+
/**
|
|
97
|
+
* Le délai de réponse du serveur est échu : le signal de l'appel s'abaisse
|
|
98
|
+
* (`ctx.abort`) et l'appel se termine en 4 `DEADLINE_EXCEEDED`, même si le
|
|
99
|
+
* gestionnaire ne lit pas son signal. Échu avant que le gestionnaire ne
|
|
100
|
+
* démarre : il est terminé dès son démarrage. Sans effet après la fin.
|
|
101
|
+
*/
|
|
102
|
+
expire(): void;
|
|
103
|
+
/**
|
|
104
|
+
* L'identité qui a ouvert l'appel n'est plus valable : le signal de l'appel
|
|
105
|
+
* s'abaisse et l'appel se termine en 16 `UNAUTHENTICATED`. Réponse unique :
|
|
106
|
+
* sa promesse est rejetée. Flux : il s'arrête au message suivant, même si le
|
|
107
|
+
* gestionnaire ne lit pas son signal — au plus le message déjà en vol part.
|
|
108
|
+
* Sans effet après la fin, ou après une autre interruption.
|
|
109
|
+
*/
|
|
110
|
+
revoke(): void;
|
|
111
|
+
/**
|
|
112
|
+
* Le serveur s'arrête : le signal de l'appel s'abaisse et l'appel se termine
|
|
113
|
+
* en 14 `UNAVAILABLE` — le client le rejoue ailleurs (ADR-0026 D8). Flux : il
|
|
114
|
+
* s'arrête au message suivant, même si le gestionnaire ne lit pas son
|
|
115
|
+
* signal. Un gestionnaire bloqué qui n'écoute rien tombe avec sa connexion, à
|
|
116
|
+
* `shutdownTimeout`. Sans effet après la fin, ou après une autre interruption.
|
|
117
|
+
*/
|
|
118
|
+
shutdown(): void;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Le contexte d'appel que Connect remet réellement au gestionnaire : son type
|
|
122
|
+
* public (`HandlerContext`) ne dit pas `abort`, que porte pourtant l'objet créé
|
|
123
|
+
* par `createHandlerContext` (`HandlerContextController`, non exporté).
|
|
124
|
+
*
|
|
125
|
+
* @experimental Surface gRPC, ADR-0026 D11.
|
|
126
|
+
*/
|
|
127
|
+
export interface IAbortableHandlerContext extends HandlerContext {
|
|
128
|
+
/** Interrompt l'appel : `ctx.signal` s'abaisse avec `reason`. */
|
|
129
|
+
abort(reason?: unknown): void;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Garde de type : le contexte d'appel porte-t-il `abort` ? Connect le pose sur
|
|
133
|
+
* tout contexte qu'il crée ; le garde le CONSTATE au lieu de le supposer, pour
|
|
134
|
+
* qu'une version de Connect qui le retirerait se voie à l'exécution (et au
|
|
135
|
+
* test qui le garde) plutôt que par un appel qui ne s'interrompt plus.
|
|
136
|
+
*
|
|
137
|
+
* @param ctx - le contexte remis au gestionnaire.
|
|
138
|
+
* @returns `true` si `ctx.abort` est une fonction.
|
|
139
|
+
*
|
|
140
|
+
* @experimental Surface gRPC, ADR-0026 D11.
|
|
141
|
+
*/
|
|
142
|
+
export declare function hasAbort(ctx: HandlerContext): ctx is IAbortableHandlerContext;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import type { DescService } from "@bufbuild/protobuf";
|
|
2
|
+
import type HttpContext from "../src/context/http/HttpContext.js";
|
|
3
|
+
/**
|
|
4
|
+
* Protocoles servis — la section `grpc` de la configuration http
|
|
5
|
+
* (ADR-0026 D3, point 5).
|
|
6
|
+
*
|
|
7
|
+
* @experimental Surface gRPC, ADR-0026 D11.
|
|
8
|
+
*/
|
|
9
|
+
export interface IGrpcProtocols {
|
|
10
|
+
readonly grpc: boolean;
|
|
11
|
+
readonly grpcWeb: boolean;
|
|
12
|
+
readonly connect: boolean;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* La section `grpc` de la configuration http : protocoles servis (D3, point
|
|
16
|
+
* 5) et bornes des messages (D4, points 1, 2 et 6).
|
|
17
|
+
*
|
|
18
|
+
* @experimental Surface gRPC, ADR-0026 D11.
|
|
19
|
+
*/
|
|
20
|
+
export interface IGrpcSettings extends IGrpcProtocols {
|
|
21
|
+
/** Taille maximale d'un message reçu, après décompression (octets). */
|
|
22
|
+
readonly readMaxBytes: number;
|
|
23
|
+
/** Taille maximale d'un message émis (octets). */
|
|
24
|
+
readonly writeMaxBytes: number;
|
|
25
|
+
/** Exige l'en-tête `Connect-Protocol-Version` sur les requêtes Connect. */
|
|
26
|
+
readonly requireConnectProtocolHeader: boolean;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Options d'un {@link GrpcEndpoint}.
|
|
30
|
+
*
|
|
31
|
+
* @experimental Surface gRPC, ADR-0026 D11.
|
|
32
|
+
*/
|
|
33
|
+
export interface IGrpcEndpointOptions {
|
|
34
|
+
/**
|
|
35
|
+
* `true` : la cible change à chaque appel (contrôleur `@Scope("request")`),
|
|
36
|
+
* chaque méthode la relit dans la fiche d'appel. `false` (défaut) : la cible
|
|
37
|
+
* du premier appel sert tous les suivants (contrôleur singleton) et ses
|
|
38
|
+
* méthodes sont liées une fois — aucune indirection par appel.
|
|
39
|
+
*/
|
|
40
|
+
readonly perCall?: boolean;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Point d'entrée gRPC d'un service : possède l'adaptateur Connect
|
|
44
|
+
* (`connectNodeAdapter`) et lui confie la requête et la réponse BRUTES de Node
|
|
45
|
+
* d'un contexte déjà passé par le pipeline (pare-feu, gardes).
|
|
46
|
+
*
|
|
47
|
+
* L'adaptateur est construit au premier appel, depuis la section `grpc` de la
|
|
48
|
+
* configuration http. Il reçoit la fiche d'appel ({@link GrpcCall}) par son
|
|
49
|
+
* option `contextValues`, qu'il appelle de façon SYNCHRONE avant toute
|
|
50
|
+
* attente (`connect-node-adapter.js#nodeRequestHandler`) : la cible passe par
|
|
51
|
+
* une case lue à cet instant — ni ALS, ni promesse, ni écouteur de plus.
|
|
52
|
+
*
|
|
53
|
+
* Les méthodes s'inscrivent une à une par `router.rpc`, SANS options : des
|
|
54
|
+
* options passées à l'inscription rallumeraient gRPC et gRPC-Web coupés par la
|
|
55
|
+
* configuration (connectrpc/connect-es#1835). La restriction de protocoles
|
|
56
|
+
* vit sur l'adaptateur seul.
|
|
57
|
+
*
|
|
58
|
+
* @experimental Surface gRPC, ADR-0026 D11.
|
|
59
|
+
*/
|
|
60
|
+
export declare class GrpcEndpoint<S extends DescService = DescService> {
|
|
61
|
+
#private;
|
|
62
|
+
/** Le contrat servi (descripteur généré par `buf`). */
|
|
63
|
+
readonly service: S;
|
|
64
|
+
/** Cible relue à chaque appel (`@Scope("request")`). */
|
|
65
|
+
readonly perCall: boolean;
|
|
66
|
+
constructor(service: S, options?: IGrpcEndpointOptions);
|
|
67
|
+
/**
|
|
68
|
+
* Remet la requête du contexte à l'adaptateur, qui écrit lui-même la
|
|
69
|
+
* réponse et ses trailers. Synchrone : rien n'est attendu ici.
|
|
70
|
+
*
|
|
71
|
+
* Avant de la remettre : le contexte est marqué répondu (`sended`), si bien
|
|
72
|
+
* que le pipeline n'attend aucune réponse de l'action.
|
|
73
|
+
*
|
|
74
|
+
* - Appel unaire : le délai de réponse de Nodefony reste armé, et termine
|
|
75
|
+
* l'appel en 4 `DEADLINE_EXCEEDED` par sa fiche (`HttpContext.rpc`,
|
|
76
|
+
* ADR-0026 D4 point 3).
|
|
77
|
+
* - Flux : aucune échéance. Il s'ouvre par le cycle de vie d'un flux
|
|
78
|
+
* (`openStreamLifecycle`, D4 point 4) — délai de réponse désarmé (à
|
|
79
|
+
* l'expiration il écrirait un 503 par-dessus l'adaptateur), place dans
|
|
80
|
+
* le budget de connexions longues par IP, client qui ne lit plus coupé
|
|
81
|
+
* par le balayage de blocage. Synchrone, sauf quand une session est à
|
|
82
|
+
* sauver : l'appel n'est remis qu'après.
|
|
83
|
+
*
|
|
84
|
+
* @param context - le contexte HTTP de la requête, pas encore répondu.
|
|
85
|
+
* @param target - l'objet qui implémente le service pour cet appel.
|
|
86
|
+
* @returns rien, ou la promesse de la remise quand une session est à sauver.
|
|
87
|
+
* @throws HttpError 500 quand la réponse est déjà partie, ou que son
|
|
88
|
+
* transport n'est pas reconnu.
|
|
89
|
+
* @throws HttpError 429 quand l'IP du client a déjà tous ses flux et sockets
|
|
90
|
+
* (`wsMaxConnectionsPerIp`) — rendu par le pipeline en 14 `UNAVAILABLE`.
|
|
91
|
+
* @throws HttpError 400 quand l'adaptateur refuse la requête avant d'avoir
|
|
92
|
+
* rien écrit (requête sans autorité `Host`) — la réponse revient alors au
|
|
93
|
+
* pipeline.
|
|
94
|
+
* @throws HttpError 404 quand aucune méthode ne correspond au chemin exact
|
|
95
|
+
* (casse modifiée) — rendu par le pipeline en 12 `UNIMPLEMENTED`.
|
|
96
|
+
*/
|
|
97
|
+
serve(context: HttpContext, target: object): void | Promise<void>;
|
|
98
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@nodefony/http/grpc` — la primitive de transport gRPC (ADR-0026).
|
|
3
|
+
*
|
|
4
|
+
* Sous-chemin à part : le point d'entrée principal de `@nodefony/http` ne cite
|
|
5
|
+
* ni Connect ni protobuf, même en type (D12). Seule une application qui
|
|
6
|
+
* déclare un service l'importe — par `@nodefony/framework/grpc` — et charge
|
|
7
|
+
* alors Connect au démarrage.
|
|
8
|
+
*
|
|
9
|
+
* @experimental Surface gRPC, ADR-0026 D11.
|
|
10
|
+
*/
|
|
11
|
+
export { GrpcCall, hasAbort } from "./GrpcCall.js";
|
|
12
|
+
export type { IAbortableHandlerContext } from "./GrpcCall.js";
|
|
13
|
+
export { GrpcEndpoint } from "./GrpcEndpoint.js";
|
|
14
|
+
export type { IGrpcEndpointOptions, IGrpcProtocols, IGrpcSettings, } from "./GrpcEndpoint.js";
|
|
15
|
+
export { markGrpcRoute } from "../src/grpc/refusal.js";
|
|
@@ -3,6 +3,7 @@ import type { MaybePromise } from "nodefony";
|
|
|
3
3
|
import type { ICookie } from "./ICookie.js";
|
|
4
4
|
import type { ISession } from "./ISession.js";
|
|
5
5
|
import type { HTTPMethodType } from "./IRequest.js";
|
|
6
|
+
import type { IRpcCall } from "./IRpcCall.js";
|
|
6
7
|
/**
|
|
7
8
|
* Identité du serveur qui a reçu la requête, nommée par le schéma d'URI qu'il
|
|
8
9
|
* sert en LOCAL (RFC 9110 §4.2, RFC 6455 §3) : elle choisit la section de
|
|
@@ -156,6 +157,14 @@ export interface IContext {
|
|
|
156
157
|
export interface IHttpContext extends IContext {
|
|
157
158
|
proxy: object | null;
|
|
158
159
|
isRedirect: boolean;
|
|
160
|
+
/**
|
|
161
|
+
* L'appel RPC servi par cette requête (gRPC, gRPC-Web, Connect), `null` hors
|
|
162
|
+
* appel RPC — ADR-0026 D10. Son code est fixé au `close`, avant la ligne
|
|
163
|
+
* d'accès.
|
|
164
|
+
*
|
|
165
|
+
* @experimental Surface gRPC, ADR-0026 D11.
|
|
166
|
+
*/
|
|
167
|
+
rpc: IRpcCall | null;
|
|
159
168
|
/**
|
|
160
169
|
* Sert la requête — synchrone quand l'action et son rendu le sont.
|
|
161
170
|
*
|
|
@@ -11,6 +11,20 @@ export interface IErrorHttpResult {
|
|
|
11
11
|
body: unknown;
|
|
12
12
|
headers?: Record<string, string | number>;
|
|
13
13
|
}
|
|
14
|
+
/**
|
|
15
|
+
* Ce qu'une route HTTP rendrait pour une erreur — son statut et le message
|
|
16
|
+
* destiné au client —, sans rien écrire. Sert les transports qui n'ont pas de
|
|
17
|
+
* corps d'erreur à rendre : un appel gRPC traduit ce statut en code
|
|
18
|
+
* (ADR-0026 D7).
|
|
19
|
+
*
|
|
20
|
+
* @experimental Surface gRPC, ADR-0026 D11.
|
|
21
|
+
*/
|
|
22
|
+
export interface IErrorDescription {
|
|
23
|
+
/** Statut HTTP émettable (100 à 599). */
|
|
24
|
+
readonly status: number;
|
|
25
|
+
/** Message pour le client : opaque pour un 5xx en production. */
|
|
26
|
+
readonly message: string;
|
|
27
|
+
}
|
|
14
28
|
/**
|
|
15
29
|
* Aide jointe au corps d'erreur — ce que le développeur doit faire, en clair.
|
|
16
30
|
*
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { URL } from "node:url";
|
|
2
2
|
import type { ICookie } from "./ICookie.js";
|
|
3
|
+
import type { IUploadedFile } from "./IUpload.js";
|
|
3
4
|
export type HTTPMethodType = "GET" | "HEAD" | "POST" | "PUT" | "DELETE" | "CONNECT" | "OPTIONS" | "TRACE" | "PATCH" | "WEBSOCKET";
|
|
4
5
|
export interface IRequest {
|
|
5
6
|
url: URL | string;
|
|
@@ -19,7 +20,7 @@ export interface IHttpRequest extends IRequest {
|
|
|
19
20
|
url: URL;
|
|
20
21
|
query: Record<string, unknown>;
|
|
21
22
|
body: RequestBody;
|
|
22
|
-
files: readonly
|
|
23
|
+
files: readonly IUploadedFile[];
|
|
23
24
|
remoteAddress: string | null | undefined;
|
|
24
25
|
acceptHtml: boolean;
|
|
25
26
|
getRemoteAddress(): string | null | undefined;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { SchemeType } from "./IContext.js";
|
|
2
2
|
import type { HTTPMethodType } from "./IRequest.js";
|
|
3
|
+
import type { IRpcOutcome } from "./IRpcCall.js";
|
|
3
4
|
/**
|
|
4
5
|
* Nature de l'opération tracée : une requête HTTP, ou le handshake d'une
|
|
5
6
|
* connexion WebSocket.
|
|
@@ -53,4 +54,13 @@ export interface IRequestTrace {
|
|
|
53
54
|
* sans exception n'en porte pas ; c'est à l'abonné de classer un statut.
|
|
54
55
|
*/
|
|
55
56
|
readonly error: unknown;
|
|
57
|
+
/**
|
|
58
|
+
* L'appel RPC (gRPC, gRPC-Web, Connect) servi par la requête, `null` hors
|
|
59
|
+
* RPC : système, méthode, code et son nom (ADR-0026 D10 point 5). Un flux
|
|
60
|
+
* est UN message, de l'ouverture au `close` ; rien par message.
|
|
61
|
+
* `statusCode` reste le statut HTTP, vrai sur le fil.
|
|
62
|
+
*
|
|
63
|
+
* @experimental Surface gRPC, ADR-0026 D11.
|
|
64
|
+
*/
|
|
65
|
+
readonly rpc: IRpcOutcome | null;
|
|
56
66
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { MaybePromise } from "nodefony";
|
|
2
2
|
import type { ContextType } from "../service/http-kernel.js";
|
|
3
|
+
import type { IRouteUploadOptions } from "./IUpload.js";
|
|
3
4
|
/**
|
|
4
5
|
* Ce que le pipeline HTTP/WS lit d'une route résolue — et rien de plus.
|
|
5
6
|
*
|
|
@@ -22,6 +23,24 @@ export interface IResolvedRoute {
|
|
|
22
23
|
} | undefined;
|
|
23
24
|
/** Corps laissé en flux (`@Body({ stream: true })`) : le parse est sauté. */
|
|
24
25
|
readonly bodyStream?: boolean | undefined;
|
|
26
|
+
/**
|
|
27
|
+
* Route servie par un point d'entrée gRPC (`markGrpcRoute`) : une requête
|
|
28
|
+
* gRPC native n'est acceptée que sur une telle route (ADR-0026 D13 point 3).
|
|
29
|
+
*
|
|
30
|
+
* @experimental Surface gRPC, ADR-0026 D11.
|
|
31
|
+
*/
|
|
32
|
+
readonly grpc?: boolean | undefined;
|
|
33
|
+
/**
|
|
34
|
+
* Délai de réponse propre à la route (ms) ; `null` ou absent = celui du
|
|
35
|
+
* serveur. Ré-armé par `HttpContext.handle` une fois la route résolue.
|
|
36
|
+
*/
|
|
37
|
+
readonly responseTimeout?: number | null | undefined;
|
|
38
|
+
/**
|
|
39
|
+
* Bornes d'envoi propres à la route (option `upload`), fusionnées sur celles
|
|
40
|
+
* de la configuration à la lecture du corps ; `null` ou absent = celles de
|
|
41
|
+
* la configuration.
|
|
42
|
+
*/
|
|
43
|
+
readonly upload?: IRouteUploadOptions | null | undefined;
|
|
25
44
|
}
|
|
26
45
|
/**
|
|
27
46
|
* Ce que le pipeline HTTP/WS attend du résolveur d'une requête, posé sur
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Le protocole RPC parlé sur le fil : `grpc`, `grpc-web` ou `connect` pour un
|
|
3
|
+
* appel gRPC (ADR-0026 D10). Union OUVERTE : un appel JSON-RPC (porte MCP,
|
|
4
|
+
* A2A) pourra s'y ajouter (`jsonrpc`) sans rupture.
|
|
5
|
+
*
|
|
6
|
+
* @experimental Surface gRPC, ADR-0026 D11.
|
|
7
|
+
*/
|
|
8
|
+
export type RpcSystem = "grpc" | "grpc-web" | "connect" | (string & {});
|
|
9
|
+
/**
|
|
10
|
+
* Le résultat d'un appel RPC tel que le voient la ligne d'accès, l'audit et le
|
|
11
|
+
* canal de traçage (ADR-0026 D10) : quatre champs, jamais la fiche d'appel
|
|
12
|
+
* entière — elle porte le contrôleur et le contexte.
|
|
13
|
+
*
|
|
14
|
+
* @experimental Surface gRPC, ADR-0026 D11.
|
|
15
|
+
*/
|
|
16
|
+
export interface IRpcOutcome {
|
|
17
|
+
/** Le protocole parlé sur le fil. */
|
|
18
|
+
readonly system: RpcSystem;
|
|
19
|
+
/**
|
|
20
|
+
* La méthode appelée, `paquet.Service/Méthode` — tirée de la route : jamais
|
|
21
|
+
* une valeur inventée (`_OTHER`), la route est connue.
|
|
22
|
+
*/
|
|
23
|
+
readonly method: string;
|
|
24
|
+
/**
|
|
25
|
+
* Le code de l'appel (gRPC : 0 à 16), lu une fois au `close` de la réponse.
|
|
26
|
+
* `null` avant, ou quand l'appel n'a jamais commencé (requête refusée par le
|
|
27
|
+
* transport avant tout contexte d'appel : le statut HTTP dit alors tout).
|
|
28
|
+
*/
|
|
29
|
+
readonly code: number | null;
|
|
30
|
+
/** Le nom du code (`OK`, `UNAVAILABLE`…), `null` avec lui. */
|
|
31
|
+
readonly codeName: string | null;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Un appel RPC servi sur une requête HTTP — gRPC, gRPC-Web ou Connect —, porté
|
|
35
|
+
* par `HttpContext.rpc`, `null` hors appel RPC (ADR-0026 D10).
|
|
36
|
+
*
|
|
37
|
+
* Le contrat vit dans `@nodefony/http` et ne nomme rien de l'adaptateur : un
|
|
38
|
+
* appel JSON-RPC pourra le porter sans rupture. La fiche d'appel gRPC
|
|
39
|
+
* (`GrpcCall`, sous-chemin `@nodefony/http/grpc`) l'implémente : aucune
|
|
40
|
+
* allocation de plus par appel.
|
|
41
|
+
*
|
|
42
|
+
* @experimental Surface gRPC, ADR-0026 D11.
|
|
43
|
+
*/
|
|
44
|
+
export interface IRpcCall extends IRpcOutcome {
|
|
45
|
+
/**
|
|
46
|
+
* Le délai de réponse du serveur est échu : termine l'appel au format de
|
|
47
|
+
* son protocole (gRPC : 4 `DEADLINE_EXCEEDED`). Appelé par
|
|
48
|
+
* `HttpContext._onTimeout` À LA PLACE du 503, qui serait un second
|
|
49
|
+
* écrivain sur une réponse que l'adaptateur possède (ADR-0026 D4, point 3).
|
|
50
|
+
* Sans effet sur un appel déjà terminé.
|
|
51
|
+
*/
|
|
52
|
+
expire(): void;
|
|
53
|
+
/**
|
|
54
|
+
* L'identité qui a ouvert l'appel n'est plus valable (jeton révoqué,
|
|
55
|
+
* session fermée, droits changés) : termine l'appel au format de son
|
|
56
|
+
* protocole (gRPC : 16 `UNAUTHENTICATED`). Appelé par le cycle de vie d'un
|
|
57
|
+
* flux À LA PLACE de la destruction du transport, qui ne dirait au client
|
|
58
|
+
* qu'une coupure (ADR-0026 D6). Sans effet sur un appel déjà terminé.
|
|
59
|
+
*/
|
|
60
|
+
revoke(): void;
|
|
61
|
+
/**
|
|
62
|
+
* Le serveur s'arrête : termine l'appel au format de son protocole (gRPC :
|
|
63
|
+
* 14 `UNAVAILABLE`, « réessaie, ailleurs »). Appelé par le noyau à l'arrêt,
|
|
64
|
+
* AVANT le drain des connexions, pour chaque flux long encore ouvert
|
|
65
|
+
* (ADR-0026 D8) — à la place de la destruction du transport à
|
|
66
|
+
* `shutdownTimeout`, qui ne dirait au client qu'une coupure. Sans effet sur
|
|
67
|
+
* un appel déjà terminé, ou déjà interrompu.
|
|
68
|
+
*/
|
|
69
|
+
shutdown(): void;
|
|
70
|
+
/**
|
|
71
|
+
* Fixe le code de l'appel, une fois, au `close` de la réponse — appelé par
|
|
72
|
+
* le noyau AVANT la ligne d'accès (`HttpKernel.teardownHttp`, ADR-0026 D10
|
|
73
|
+
* point 2). Les appels suivants ne changent rien.
|
|
74
|
+
*
|
|
75
|
+
* @param ended - la réponse a-t-elle été terminée par le serveur
|
|
76
|
+
* (`responseEnded`) ? Un appel sans motif d'interruption est alors réussi
|
|
77
|
+
* (0), sinon annulé par le client (1).
|
|
78
|
+
* @returns la cause à porter par la ligne d'accès (`context.error`) quand
|
|
79
|
+
* l'appel a échoué sur une exception — UNE ligne par appel en erreur
|
|
80
|
+
* (D10 point 3) —, `null` sinon.
|
|
81
|
+
*/
|
|
82
|
+
settle(ended: boolean): Error | null;
|
|
83
|
+
}
|
|
@@ -40,12 +40,37 @@ export interface IFirewallGate {
|
|
|
40
40
|
enforceCsrf(context: ContextType): void;
|
|
41
41
|
/** Répond au preflight CORS ; `204` quand la réponse est déjà envoyée. */
|
|
42
42
|
handleCors(context: ContextType): number | undefined;
|
|
43
|
-
/**
|
|
44
|
-
|
|
43
|
+
/**
|
|
44
|
+
* Pose les en-têtes de sécurité applicatifs (CSP, Permissions-Policy…) de la
|
|
45
|
+
* réponse, appelé par la réponse juste avant son `writeHead`.
|
|
46
|
+
*
|
|
47
|
+
* @param contentType - `Content-Type` de la réponse, qui choisit la politique ;
|
|
48
|
+
* `null` = réponse sans contenu ; omis = type inconnu (politique complète).
|
|
49
|
+
* @param servedAsFile - corps servi tel quel (fichier statique, relais) : aucun
|
|
50
|
+
* gabarit ne l'a écrit, il ne peut pas porter de nonce.
|
|
51
|
+
*/
|
|
52
|
+
applySecurityHeaders(context: ContextType, contentType?: string | null, servedAsFile?: boolean): void;
|
|
45
53
|
/**
|
|
46
54
|
* Le revalidateur de l'identité authentifiée de la requête courante, pour une
|
|
47
55
|
* connexion longue qui la gardera (flux SSE) : la même règle que les sockets
|
|
48
56
|
* WebSocket. `null` pour un anonyme — rien à révoquer.
|
|
49
57
|
*/
|
|
50
58
|
currentRevalidator?(): ((nowMs?: number) => Promise<boolean>) | null;
|
|
59
|
+
/**
|
|
60
|
+
* Prévenu quand le noyau HTTP a recalculé ses en-têtes de transport (édition à
|
|
61
|
+
* chaud de `securityHeaders`) : la politique de contenu suit `frameOptions`,
|
|
62
|
+
* qui pilote aussi `frame-ancestors`.
|
|
63
|
+
*/
|
|
64
|
+
onTransportHeadersChanged?(): void;
|
|
65
|
+
/**
|
|
66
|
+
* Déclare les sources qu'un module ajoute à la politique de contenu
|
|
67
|
+
* (`{ "connect-src": ["wss://rt.example.com"] }`). Un second appel du même
|
|
68
|
+
* module REMPLACE sa contribution. Absent quand aucun pare-feu ne pose de CSP.
|
|
69
|
+
*
|
|
70
|
+
* @param moduleName - module qui contribue, clé de sa contribution
|
|
71
|
+
* @param fragment - sources par directive, origines exactes (sans joker)
|
|
72
|
+
*/
|
|
73
|
+
registerCspOrigins?(moduleName: string, fragment: Readonly<Record<string, readonly string[]>>): void;
|
|
74
|
+
/** Retire la contribution CSP de `moduleName`. */
|
|
75
|
+
unregisterCspOrigins?(moduleName: string): void;
|
|
51
76
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { FileClass } from "nodefony";
|
|
1
2
|
/**
|
|
2
3
|
* Forme neutre d'un fichier multipart parsé (temp écrit sur disque), découplée
|
|
3
4
|
* du parser sous-jacent. Remplace l'ex-couplage à `formidable.File` : le moteur
|
|
@@ -44,18 +45,64 @@ export interface IUploadOptions {
|
|
|
44
45
|
/** Encodage par défaut des parts texte. */
|
|
45
46
|
encoding?: string | undefined;
|
|
46
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* Les bornes d'envoi qu'une ROUTE règle pour elle-même (option de route
|
|
50
|
+
* `upload`). Chaque clé déclarée remplace celle de la configuration http,
|
|
51
|
+
* dans les deux sens : un dépôt de vidéos relève `maxFileSize` sans le
|
|
52
|
+
* relever pour les autres routes, un avatar l'abaisse à quelques centaines de
|
|
53
|
+
* kilo-octets — et le fichier trop gros est coupé PENDANT le flux, avant
|
|
54
|
+
* d'avoir rempli le disque. Une clé absente garde la valeur de la
|
|
55
|
+
* configuration.
|
|
56
|
+
*
|
|
57
|
+
* Lues au moment de lire le corps, quand la route est déjà résolue : une route
|
|
58
|
+
* qui ne déclare rien ne paie rien. Le dossier de dépôt et l'encodage restent
|
|
59
|
+
* ceux de la configuration.
|
|
60
|
+
*/
|
|
61
|
+
export interface IRouteUploadOptions {
|
|
62
|
+
/** Taille max d'UN fichier (octets). */
|
|
63
|
+
readonly maxFileSize?: number | undefined;
|
|
64
|
+
/** Taille max CUMULÉE des fichiers de la requête (octets). */
|
|
65
|
+
readonly maxTotalFileSize?: number | undefined;
|
|
66
|
+
/** Nombre max de fichiers. */
|
|
67
|
+
readonly maxFiles?: number | undefined;
|
|
68
|
+
/** Nombre max de champs texte. */
|
|
69
|
+
readonly maxFields?: number | undefined;
|
|
70
|
+
/** Taille max d'un champ texte (octets). */
|
|
71
|
+
readonly maxFieldsSize?: number | undefined;
|
|
72
|
+
/** Empreinte calculée pendant le flux (`false` = aucune). */
|
|
73
|
+
readonly hashAlgorithm?: false | "sha1" | "md5" | "sha256" | undefined;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Un fichier reçu dans un corps multipart, déjà écrit dans le dossier
|
|
77
|
+
* d'upload sous un nom temporaire.
|
|
78
|
+
*
|
|
79
|
+
* Le temporaire est EFFACÉ à la fin de la requête (réponse envoyée ou client
|
|
80
|
+
* parti) : pour garder le fichier, l'action le déplace avec `moveAsync()`
|
|
81
|
+
* avant de répondre. Un refus (pare-feu, garde, erreur de l'action) ne laisse
|
|
82
|
+
* donc rien sur le disque.
|
|
83
|
+
*/
|
|
47
84
|
export interface IUploadedFile {
|
|
48
85
|
filename: string;
|
|
49
86
|
size: number;
|
|
50
87
|
prettySize: string;
|
|
51
|
-
|
|
88
|
+
/**
|
|
89
|
+
* Le type DÉCLARÉ par le client, sinon deviné de l'extension ; `false`
|
|
90
|
+
* quand ni l'un ni l'autre ne le disent. Déclaratif : jamais une preuve du
|
|
91
|
+
* contenu.
|
|
92
|
+
*/
|
|
93
|
+
mimeType: string | false;
|
|
52
94
|
hash: string | null | undefined;
|
|
53
95
|
hashAlgorithm: false | "sha1" | "md5" | "sha256";
|
|
54
96
|
lastModifiedDate: Date | null | undefined;
|
|
55
|
-
|
|
97
|
+
/**
|
|
98
|
+
* Déplace le fichier vers `target` (un fichier, ou un dossier existant) et
|
|
99
|
+
* rend le fichier de DESTINATION — un `FileClass`, pas un fichier reçu : le
|
|
100
|
+
* nom d'origine, la taille déclarée et l'empreinte restent sur celui-ci.
|
|
101
|
+
*/
|
|
102
|
+
move(target: string): FileClass;
|
|
56
103
|
/** Variante non bloquante de `move()` (recommandée dans le pipeline). */
|
|
57
|
-
moveAsync(target: string): Promise<
|
|
58
|
-
getMimeType(): string |
|
|
104
|
+
moveAsync(target: string): Promise<FileClass>;
|
|
105
|
+
getMimeType(): string | false;
|
|
59
106
|
getSize(): number;
|
|
60
107
|
getPrettySize(): string;
|
|
61
108
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export type { ICookie, ICookieOptions, IWsCookie, SameSiteType, PriorityType, } from "./ICookie.js";
|
|
2
2
|
export type { ISession, ISessionStorage, ISerializedSession, SessionIntent, SessionStatusType, SessionStrategyType, FlashBagType, MetaBagType, } from "./ISession.js";
|
|
3
|
-
export type { IUploadedFile, IUploadService, IParsedUploadFile, IUploadOptions, } from "./IUpload.js";
|
|
3
|
+
export type { IUploadedFile, IUploadService, IParsedUploadFile, IUploadOptions, IRouteUploadOptions, } from "./IUpload.js";
|
|
4
4
|
export type { IRequest, IHttpRequest, RequestBody, IHttp2Request, IWsRequest, HTTPMethodType, } from "./IRequest.js";
|
|
5
5
|
export type { IResponse, IHttpResponse, IWebsocketResponse } from "./IResponse.js";
|
|
6
6
|
export type { IContext, IHttpContext, IWebsocketContext, ServerType, ProtocolName, AlpnProtocol, SchemeType, WebSocketStateType, CookiesMap, } from "./IContext.js";
|
|
@@ -8,4 +8,5 @@ export type { IHttpKernel } from "./IHttpKernel.js";
|
|
|
8
8
|
export type { IResolvedRoute, IRouteResolver, IRequestRouter, } from "./IRouting.js";
|
|
9
9
|
export type { ISecurityZone, IFirewallGate } from "./ISecurity.js";
|
|
10
10
|
export type { IRequestTrace, RequestTraceProtocol } from "./IRequestTrace.js";
|
|
11
|
+
export type { IRpcCall, IRpcOutcome, RpcSystem } from "./IRpcCall.js";
|
|
11
12
|
export type { IProxyMount, IProxyMountOptions, ProxyTarget, } from "./IReverseProxy.js";
|
|
@@ -13,7 +13,8 @@ import type { Profiler } from "../src/profiler/Profiler.js";
|
|
|
13
13
|
* `?connection=<requestId>` : les seules frames de cette socket WebSocket
|
|
14
14
|
* - `GET /nodefony/profiler/api/summary` → les profils de l'anneau agrégés par
|
|
15
15
|
* route (percentiles, phases, formes SQL, N+1, erreurs — `aggregateProfiles`)
|
|
16
|
-
* - `GET /nodefony/profiler/api/{id}` → profil complet (phases) d'un requestId
|
|
16
|
+
* - `GET /nodefony/profiler/api/{id}` → profil complet (phases) d'un requestId ;
|
|
17
|
+
* absent → 404 `{ startedAt, clearedAt }` : depuis quand l'anneau sait quelque chose
|
|
17
18
|
* - `DELETE /nodefony/profiler/api/recent` → vide le ring buffer
|
|
18
19
|
*
|
|
19
20
|
* La debug bar (toute page, dev) lit `X-Request-Id` de SON appel AJAX puis
|