@nodefony/http 10.0.0-alpha.9 → 10.0.0-beta.2
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 +12 -3
- package/dist/_virtual/{_@oxc-project_runtime@0.151.0 → _@oxc-project_runtime@0.152.0}/helpers/esm/decorate.js +1 -1
- package/dist/_virtual/{_@oxc-project_runtime@0.151.0 → _@oxc-project_runtime@0.152.0}/helpers/esm/decorateMetadata.js +1 -1
- package/dist/_virtual/{_@oxc-project_runtime@0.151.0 → _@oxc-project_runtime@0.152.0}/helpers/esm/decorateParam.js +1 -1
- package/dist/index.js +6 -4
- package/dist/nodefony/command/assetsPublishCommand.js +1 -1
- package/dist/nodefony/command/certificatesCommand.js +1 -2
- package/dist/nodefony/command/networkCommand.js +1 -1
- package/dist/nodefony/command/proxyGenerateCommand.js +1 -1
- package/dist/nodefony/config/config.js +26 -4
- package/dist/nodefony/interfaces/IRouting.js +1 -0
- package/dist/nodefony/interfaces/ISecurity.js +1 -0
- package/dist/nodefony/service/ProfilerAdminApi.js +2 -1
- package/dist/nodefony/service/audit-logger.js +16 -13
- package/dist/nodefony/service/certificates.js +87 -144
- package/dist/nodefony/service/error-renderer.js +11 -8
- package/dist/nodefony/service/http-kernel.js +342 -165
- package/dist/nodefony/service/pretty-request-logger.js +3 -10
- package/dist/nodefony/service/servers/clientError.js +2 -2
- package/dist/nodefony/service/servers/server-http.js +23 -23
- package/dist/nodefony/service/servers/server-https.js +41 -42
- package/dist/nodefony/service/servers/server-static.js +13 -17
- package/dist/nodefony/service/servers/server-websocket-secure.js +11 -10
- package/dist/nodefony/service/servers/server-websocket.js +11 -10
- package/dist/nodefony/service/servers/wsHeartbeat.js +2 -2
- package/dist/nodefony/service/sessions/sessions-service.js +22 -15
- package/dist/nodefony/service/trace.js +3 -2
- package/dist/nodefony/service/upload/upload-service.js +11 -10
- package/dist/nodefony/service/x509.js +324 -0
- package/dist/nodefony/src/assets/prebuiltUi.js +1 -1
- package/dist/nodefony/src/context/Context.js +34 -19
- package/dist/nodefony/src/context/forwarded.js +4 -4
- package/dist/nodefony/src/context/http/HttpContext.js +133 -88
- package/dist/nodefony/src/context/http/Request.js +108 -46
- package/dist/nodefony/src/context/http/Response.js +134 -54
- package/dist/nodefony/src/context/http/parser.js +9 -10
- package/dist/nodefony/src/context/http/urlFastPath.js +35 -11
- package/dist/nodefony/src/context/http2/Response.js +53 -25
- package/dist/nodefony/src/context/metaData.js +1 -1
- package/dist/nodefony/src/context/trustProxy.js +4 -3
- package/dist/nodefony/src/context/websocket/Response.js +13 -6
- package/dist/nodefony/src/context/websocket/WebsocketContext.js +59 -26
- package/dist/nodefony/src/context/websocket/wsCloseReason.js +41 -0
- package/dist/nodefony/src/cookies/cookie.js +3 -3
- package/dist/nodefony/src/errors/httpError.js +6 -6
- package/dist/nodefony/src/errors/thrownMessage.js +27 -0
- package/dist/nodefony/src/profiler/FrameProfile.js +4 -3
- package/dist/nodefony/src/profiler/Profiler.js +4 -4
- package/dist/nodefony/src/servers/kernelServers.js +29 -0
- package/dist/nodefony/src/servers/portBinder.js +65 -23
- package/dist/nodefony/src/session/session.js +18 -10
- package/dist/nodefony/src/session/sessionStoreFailure.js +2 -1
- package/dist/nodefony/src/session/storage/RevocationGuardStorage.js +24 -9
- package/dist/types/index.d.ts +16 -0
- package/dist/types/nodefony/config/config.d.ts +23 -0
- package/dist/types/nodefony/interfaces/IContext.d.ts +24 -7
- package/dist/types/nodefony/interfaces/ICookie.d.ts +18 -18
- package/dist/types/nodefony/interfaces/IHttpKernel.d.ts +10 -4
- package/dist/types/nodefony/interfaces/IResponse.d.ts +1 -1
- package/dist/types/nodefony/interfaces/IRouting.d.ts +87 -0
- package/dist/types/nodefony/interfaces/ISecurity.d.ts +45 -0
- package/dist/types/nodefony/interfaces/ISession.d.ts +8 -8
- package/dist/types/nodefony/interfaces/IUpload.d.ts +9 -9
- package/dist/types/nodefony/interfaces/index.d.ts +2 -0
- package/dist/types/nodefony/service/audit-logger.d.ts +14 -10
- package/dist/types/nodefony/service/certificates.d.ts +42 -57
- package/dist/types/nodefony/service/http-kernel.d.ts +192 -42
- package/dist/types/nodefony/service/servers/server-http.d.ts +4 -1
- package/dist/types/nodefony/service/servers/server-https.d.ts +4 -1
- package/dist/types/nodefony/service/servers/server-websocket-secure.d.ts +4 -1
- package/dist/types/nodefony/service/servers/server-websocket.d.ts +4 -1
- package/dist/types/nodefony/service/sessions/sessions-service.d.ts +6 -2
- package/dist/types/nodefony/service/upload/upload-service.d.ts +1 -1
- package/dist/types/nodefony/service/x509.d.ts +86 -0
- package/dist/types/nodefony/src/context/Context.d.ts +21 -10
- package/dist/types/nodefony/src/context/forwarded.d.ts +3 -3
- package/dist/types/nodefony/src/context/http/HttpContext.d.ts +75 -18
- package/dist/types/nodefony/src/context/http/Request.d.ts +39 -2
- package/dist/types/nodefony/src/context/http/Response.d.ts +47 -7
- package/dist/types/nodefony/src/context/http/parser.d.ts +1 -1
- package/dist/types/nodefony/src/context/http2/Response.d.ts +32 -2
- package/dist/types/nodefony/src/context/websocket/Response.d.ts +4 -4
- package/dist/types/nodefony/src/context/websocket/WebsocketContext.d.ts +11 -2
- package/dist/types/nodefony/src/context/websocket/wsCloseReason.d.ts +21 -0
- package/dist/types/nodefony/src/cookies/cookie.d.ts +9 -9
- package/dist/types/nodefony/src/errors/httpError.d.ts +7 -7
- package/dist/types/nodefony/src/errors/thrownMessage.d.ts +12 -0
- package/dist/types/nodefony/src/profiler/Profiler.d.ts +28 -28
- package/dist/types/nodefony/src/servers/kernelServers.d.ts +20 -0
- package/dist/types/nodefony/src/servers/portBinder.d.ts +16 -65
- package/dist/types/nodefony/src/session/session.d.ts +12 -12
- package/dist/types/nodefony/src/session/storage/RevocationGuardStorage.d.ts +1 -1
- package/docs/cookies.md +25 -25
- package/docs/index.md +4 -2
- package/docs/observabilite.md +27 -27
- package/docs/rate-limit.md +20 -20
- package/docs/servers.md +82 -79
- package/docs/session.md +74 -69
- package/docs/upload.md +49 -43
- package/package.json +9 -12
package/dist/types/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Kernel, Module } from "nodefony";
|
|
2
|
+
import { type IHttpOverlay } from "./nodefony/config/config.js";
|
|
2
3
|
import type { IHttpConfig, IHttpConfigInput } from "./nodefony/interfaces/IHttpConfig.js";
|
|
3
4
|
import { Profiler } from "./nodefony/src/profiler/Profiler.js";
|
|
4
5
|
import HttpKernel from "./nodefony/service/http-kernel.js";
|
|
@@ -22,8 +23,21 @@ declare module "nodefony" {
|
|
|
22
23
|
interface NodefonyModuleConfig {
|
|
23
24
|
"@nodefony/http": IHttpConfigInput;
|
|
24
25
|
}
|
|
26
|
+
interface NodefonyModuleOverlay {
|
|
27
|
+
"@nodefony/http": IHttpOverlay;
|
|
28
|
+
}
|
|
25
29
|
}
|
|
26
30
|
declare class Http extends Module<IHttpConfig> {
|
|
31
|
+
overlaySchema: import("zod").ZodObject<{
|
|
32
|
+
maxBodySize: import("zod").ZodOptional<import("zod").ZodType<number, number, import("zod/v4/core").$ZodTypeInternals<number, number>>>;
|
|
33
|
+
upload: import("zod").ZodOptional<import("zod").ZodObject<{
|
|
34
|
+
maxFileSize: import("zod").ZodOptional<import("zod").ZodType<number, number, import("zod/v4/core").$ZodTypeInternals<number, number>>>;
|
|
35
|
+
maxTotalFileSize: import("zod").ZodOptional<import("zod").ZodType<number, number, import("zod/v4/core").$ZodTypeInternals<number, number>>>;
|
|
36
|
+
maxFiles: import("zod").ZodOptional<import("zod").ZodType<number, number, import("zod/v4/core").$ZodTypeInternals<number, number>>>;
|
|
37
|
+
maxFields: import("zod").ZodOptional<import("zod").ZodType<number, number, import("zod/v4/core").$ZodTypeInternals<number, number>>>;
|
|
38
|
+
maxFieldsSize: import("zod").ZodOptional<import("zod").ZodType<number, number, import("zod/v4/core").$ZodTypeInternals<number, number>>>;
|
|
39
|
+
}, import("zod/v4/core").$strict>>;
|
|
40
|
+
}, import("zod/v4/core").$strict>;
|
|
27
41
|
constructor(kernel: Kernel);
|
|
28
42
|
/**
|
|
29
43
|
* Expose le JSON Schema de la config http (dérivé du schéma Zod, flags `meta()`
|
|
@@ -75,6 +89,8 @@ export { SESSION_SORTABLE_FIELDS, SESSION_DEFAULT_ORDER, SESSION_DEFAULT_ORDER_S
|
|
|
75
89
|
export type { IHttpRequest, IHttp2Request, IWsRequest, HTTPMethodType, } from "./nodefony/interfaces/IRequest.js";
|
|
76
90
|
export type { IHttpResponse, IWebsocketResponse, } from "./nodefony/interfaces/IResponse.js";
|
|
77
91
|
export type { IHttpKernel } from "./nodefony/interfaces/IHttpKernel.js";
|
|
92
|
+
export type { IResolvedRoute, IRouteResolver, IRequestRouter, } from "./nodefony/interfaces/IRouting.js";
|
|
93
|
+
export type { ISecurityZone, IFirewallGate, } from "./nodefony/interfaces/ISecurity.js";
|
|
78
94
|
export type { IUploadedFile, IUploadService, IParsedUploadFile, IUploadOptions, } from "./nodefony/interfaces/IUpload.js";
|
|
79
95
|
export type { IErrorRenderer, IErrorHttpResult, IErrorWebsocketResult, } from "./nodefony/interfaces/IErrorRenderer.js";
|
|
80
96
|
export type { IRequestLogger, IRequestLogEntry, } from "./nodefony/interfaces/IRequestLogger.js";
|
|
@@ -87,6 +87,7 @@ export declare const httpConfigSchema: z.ZodObject<{
|
|
|
87
87
|
name: z.ZodOptional<z.ZodString>;
|
|
88
88
|
value: z.ZodOptional<z.ZodString>;
|
|
89
89
|
shortName: z.ZodOptional<z.ZodString>;
|
|
90
|
+
type: z.ZodOptional<z.ZodString>;
|
|
90
91
|
}, z.core.$loose>>>;
|
|
91
92
|
}, z.core.$strict>>;
|
|
92
93
|
}, z.core.$strict>>;
|
|
@@ -189,6 +190,28 @@ export declare const httpConfigSchema: z.ZodObject<{
|
|
|
189
190
|
export type IHttpConfig = z.infer<typeof httpConfigSchema>;
|
|
190
191
|
/** Type d'entrée (toutes sections omissibles — défauts du schéma). */
|
|
191
192
|
export type IHttpConfigInput = z.input<typeof httpConfigSchema>;
|
|
193
|
+
/**
|
|
194
|
+
* LISTE BLANCHE des clés qu'une requête peut surcharger pour elle seule
|
|
195
|
+
* (`overlayConfig("@nodefony/http", …)`, #494) : les quotas de corps et
|
|
196
|
+
* d'envoi, lus au MOMENT de lire le corps (`Request.readBodyLimits`) — un
|
|
197
|
+
* calque posé avant la lecture du corps (écouteur `onRequestScope`, organisation
|
|
198
|
+
* reconnue à son nom d'hôte) les voit. Tout le reste est refusé : en-têtes de
|
|
199
|
+
* sécurité, pare-feu, `trustProxy`, sessions, limites de débit, certificats —
|
|
200
|
+
* et `queryString`, lu au constructeur de la requête, avant tout calque.
|
|
201
|
+
* Chaque champ réutilise celui du schéma (mêmes bornes) sans son défaut.
|
|
202
|
+
*/
|
|
203
|
+
export declare const httpOverlaySchema: z.ZodObject<{
|
|
204
|
+
maxBodySize: z.ZodOptional<z.ZodType<number, number, z.core.$ZodTypeInternals<number, number>>>;
|
|
205
|
+
upload: z.ZodOptional<z.ZodObject<{
|
|
206
|
+
maxFileSize: z.ZodOptional<z.ZodType<number, number, z.core.$ZodTypeInternals<number, number>>>;
|
|
207
|
+
maxTotalFileSize: z.ZodOptional<z.ZodType<number, number, z.core.$ZodTypeInternals<number, number>>>;
|
|
208
|
+
maxFiles: z.ZodOptional<z.ZodType<number, number, z.core.$ZodTypeInternals<number, number>>>;
|
|
209
|
+
maxFields: z.ZodOptional<z.ZodType<number, number, z.core.$ZodTypeInternals<number, number>>>;
|
|
210
|
+
maxFieldsSize: z.ZodOptional<z.ZodType<number, number, z.core.$ZodTypeInternals<number, number>>>;
|
|
211
|
+
}, z.core.$strict>>;
|
|
212
|
+
}, z.core.$strict>;
|
|
213
|
+
/** Calque accepté par `overlayConfig("@nodefony/http", …)`. */
|
|
214
|
+
export type IHttpOverlay = z.input<typeof httpOverlaySchema>;
|
|
192
215
|
/**
|
|
193
216
|
* Défauts du module, matérialisés depuis le schéma (source unique). Toujours
|
|
194
217
|
* valides par construction ; passés au `super(..., config)` du Module class.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { URL } from "node:url";
|
|
2
|
+
import type { MaybePromise } from "nodefony";
|
|
2
3
|
import type { ICookie } from "./ICookie.js";
|
|
3
4
|
import type { ISession } from "./ISession.js";
|
|
4
5
|
import type { HTTPMethodType } from "./IRequest.js";
|
|
@@ -10,8 +11,8 @@ export type PhaseName = "parse" | "resolve" | "firewall" | "initialize" | "actio
|
|
|
10
11
|
export interface PhaseTiming {
|
|
11
12
|
name: PhaseName;
|
|
12
13
|
startMs: number;
|
|
13
|
-
endMs?: number;
|
|
14
|
-
durationMs?: number;
|
|
14
|
+
endMs?: number | undefined;
|
|
15
|
+
durationMs?: number | undefined;
|
|
15
16
|
}
|
|
16
17
|
/** Issue de la traversée d'une zone firewall. */
|
|
17
18
|
export type SecurityOutcome =
|
|
@@ -110,9 +111,25 @@ export interface IContext {
|
|
|
110
111
|
export interface IHttpContext extends IContext {
|
|
111
112
|
proxy: object | null;
|
|
112
113
|
isRedirect: boolean;
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
114
|
+
/**
|
|
115
|
+
* Sert la requête — synchrone quand l'action et son rendu le sont.
|
|
116
|
+
*
|
|
117
|
+
* @returns le résultat du rendu, ou sa promesse dès qu'une étape attend.
|
|
118
|
+
*/
|
|
119
|
+
handle(): MaybePromise<object>;
|
|
120
|
+
/**
|
|
121
|
+
* Sérialise puis envoie — synchrone quand l'envoi l'est.
|
|
122
|
+
*
|
|
123
|
+
* @returns la réponse, ou sa promesse dès qu'une étape attend.
|
|
124
|
+
*/
|
|
125
|
+
render(chunk: unknown, encoding?: BufferEncoding, status?: string | number, headers?: Record<string, string | number>): MaybePromise<object>;
|
|
126
|
+
/**
|
|
127
|
+
* Envoie la réponse — synchrone sans session à sauver, sans hook `onSend`,
|
|
128
|
+
* pour une réponse unique.
|
|
129
|
+
*
|
|
130
|
+
* @returns la réponse, ou sa promesse dès qu'une étape attend.
|
|
131
|
+
*/
|
|
132
|
+
send(chunk?: unknown, encoding?: BufferEncoding): MaybePromise<object>;
|
|
116
133
|
end(): Promise<object>;
|
|
117
134
|
redirect(url: string, status?: number | string, headers?: Record<string, string | number>): unknown;
|
|
118
135
|
getHostName(): string | undefined;
|
|
@@ -121,8 +138,8 @@ export interface IHttpContext extends IContext {
|
|
|
121
138
|
getUserAgent(): string | undefined;
|
|
122
139
|
}
|
|
123
140
|
export interface IWebsocketContext extends IContext {
|
|
124
|
-
acceptedProtocol?: string;
|
|
125
|
-
connection: unknown
|
|
141
|
+
acceptedProtocol?: string | undefined;
|
|
142
|
+
connection: unknown;
|
|
126
143
|
rejected: boolean;
|
|
127
144
|
port: number | string;
|
|
128
145
|
wsUrl: URL | null;
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
export type SameSiteType = "Strict" | "Lax" | "None";
|
|
2
2
|
export type PriorityType = "High" | "Medium" | "Low" | undefined;
|
|
3
3
|
export interface ICookieOptions {
|
|
4
|
-
maxAge?: number;
|
|
5
|
-
path?: string;
|
|
6
|
-
domain?: string;
|
|
7
|
-
secure?: boolean;
|
|
8
|
-
expires?: Date | string | number;
|
|
9
|
-
sameSite?: SameSiteType;
|
|
10
|
-
httpOnly?: boolean;
|
|
11
|
-
signed?: boolean;
|
|
12
|
-
secret?: string;
|
|
4
|
+
maxAge?: number | undefined;
|
|
5
|
+
path?: string | undefined;
|
|
6
|
+
domain?: string | undefined;
|
|
7
|
+
secure?: boolean | undefined;
|
|
8
|
+
expires?: Date | string | number | undefined;
|
|
9
|
+
sameSite?: SameSiteType | undefined;
|
|
10
|
+
httpOnly?: boolean | undefined;
|
|
11
|
+
signed?: boolean | undefined;
|
|
12
|
+
secret?: string | undefined;
|
|
13
13
|
priority?: PriorityType;
|
|
14
14
|
}
|
|
15
15
|
export interface IWsCookie {
|
|
@@ -26,16 +26,16 @@ export interface ICookie {
|
|
|
26
26
|
name: string;
|
|
27
27
|
value: unknown;
|
|
28
28
|
options: ICookieOptions;
|
|
29
|
-
signed?: boolean;
|
|
30
|
-
originalMaxAge?: number;
|
|
31
|
-
expires?: Date;
|
|
32
|
-
maxAge?: number;
|
|
33
|
-
path?: string;
|
|
29
|
+
signed?: boolean | undefined;
|
|
30
|
+
originalMaxAge?: number | undefined;
|
|
31
|
+
expires?: Date | undefined;
|
|
32
|
+
maxAge?: number | undefined;
|
|
33
|
+
path?: string | undefined;
|
|
34
34
|
domain?: string | undefined;
|
|
35
|
-
httpOnly?: boolean;
|
|
36
|
-
secure?: boolean;
|
|
37
|
-
sameSite?: SameSiteType;
|
|
38
|
-
priority?: string;
|
|
35
|
+
httpOnly?: boolean | undefined;
|
|
36
|
+
secure?: boolean | undefined;
|
|
37
|
+
sameSite?: SameSiteType | undefined;
|
|
38
|
+
priority?: string | undefined;
|
|
39
39
|
setValue(value: unknown): unknown;
|
|
40
40
|
toString(): string;
|
|
41
41
|
serialize(): string;
|
|
@@ -1,9 +1,15 @@
|
|
|
1
|
+
import type { IServerKernel, MaybePromise } from "nodefony";
|
|
1
2
|
import type { ServerType } from "./IContext.js";
|
|
2
|
-
export interface IHttpKernel {
|
|
3
|
+
export interface IHttpKernel extends IServerKernel {
|
|
3
4
|
domain: string;
|
|
4
|
-
httpPort?: number;
|
|
5
|
-
httpsPort?: number;
|
|
6
|
-
|
|
5
|
+
httpPort?: number | undefined;
|
|
6
|
+
httpsPort?: number | undefined;
|
|
7
|
+
/**
|
|
8
|
+
* Pipeline public d'une requête (appelé par les serveurs HTTP/HTTPS).
|
|
9
|
+
*
|
|
10
|
+
* @returns le contexte servi, ou sa promesse dès qu'une étape attend.
|
|
11
|
+
*/
|
|
12
|
+
handle(request: unknown, response: unknown, type: ServerType): MaybePromise<unknown>;
|
|
7
13
|
handleFrontController(context: object, checkFirewall?: boolean): Promise<unknown>;
|
|
8
14
|
onError(error: unknown, context?: object, extraHeaders?: object): Promise<object>;
|
|
9
15
|
isValidDomain(context: object): boolean;
|
|
@@ -31,7 +31,7 @@ export interface IHttpResponse extends IResponse {
|
|
|
31
31
|
setCookie(cookie: ICookie): void;
|
|
32
32
|
}
|
|
33
33
|
export interface IWebsocketResponse extends IResponse {
|
|
34
|
-
connection: unknown
|
|
34
|
+
connection: unknown;
|
|
35
35
|
webSocketVersion?: number;
|
|
36
36
|
setConnection(connection: unknown): unknown;
|
|
37
37
|
broadcast(data: Buffer | string): void;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import type { MaybePromise } from "nodefony";
|
|
2
|
+
import type { ContextType } from "../service/http-kernel.js";
|
|
3
|
+
/**
|
|
4
|
+
* Ce que le pipeline HTTP/WS lit d'une route résolue — et rien de plus.
|
|
5
|
+
*
|
|
6
|
+
* Le routage vit dans `@nodefony/framework`, qui dépend de `@nodefony/http` :
|
|
7
|
+
* `http` ne peut donc pas nommer ses classes sans recréer un cycle. C'est le
|
|
8
|
+
* LECTEUR qui définit le contrat ; `Route` (framework) le satisfait par
|
|
9
|
+
* structure, et le typecheck de `framework` garantit l'alignement.
|
|
10
|
+
*/
|
|
11
|
+
export interface IResolvedRoute {
|
|
12
|
+
/** Nom de la route (journalisation, diagnostic). */
|
|
13
|
+
readonly name: string;
|
|
14
|
+
/** Corps laissé en flux (`@Body({ stream: true })`) : le parse est sauté. */
|
|
15
|
+
readonly bodyStream?: boolean | undefined;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Ce que le pipeline HTTP/WS attend du résolveur d'une requête, posé sur
|
|
19
|
+
* `context.resolver` par le routeur.
|
|
20
|
+
*
|
|
21
|
+
* Implémenté par `Resolver` (`@nodefony/framework`), qui l'étend de ses propres
|
|
22
|
+
* membres — un code de `framework` qui a besoin de la classe entière la tient
|
|
23
|
+
* de son routeur, pas de ce contrat.
|
|
24
|
+
*/
|
|
25
|
+
export interface IRouteResolver {
|
|
26
|
+
/** Route matchée, `null` tant qu'aucune ne l'est. */
|
|
27
|
+
readonly route: IResolvedRoute | null;
|
|
28
|
+
/** `true` si une route a matché la requête. */
|
|
29
|
+
resolve: boolean;
|
|
30
|
+
/** Erreur levée pendant la résolution, relue par le pipeline. */
|
|
31
|
+
exception?: Error | null | undefined;
|
|
32
|
+
/** Classe du controller résolu — seul son nom est lu (erreurs, journal). */
|
|
33
|
+
readonly controller?: {
|
|
34
|
+
readonly name: string;
|
|
35
|
+
} | null | undefined;
|
|
36
|
+
/** Nom de l'action résolue. */
|
|
37
|
+
actionName?: string | undefined;
|
|
38
|
+
/**
|
|
39
|
+
* Rejoue le match d'une route sur un contexte (WS : handshake puis frames).
|
|
40
|
+
*
|
|
41
|
+
* @param route - la route à matcher, lue sur {@link IRouteResolver.route}
|
|
42
|
+
* @param context - le contexte courant
|
|
43
|
+
* @param cleanPath - chemin imposé (pont WS-RPC), sinon l'URL du contexte
|
|
44
|
+
*/
|
|
45
|
+
match(route: IResolvedRoute, context: ContextType, cleanPath?: string): unknown;
|
|
46
|
+
/**
|
|
47
|
+
* Instancie le controller résolu — le pipeline ne fait que le transmettre.
|
|
48
|
+
*
|
|
49
|
+
* @param context - le contexte de la requête
|
|
50
|
+
* @returns l'instance du controller — directement quand elle existe déjà ou
|
|
51
|
+
* se construit sans rien attendre, sinon la promesse de sa création
|
|
52
|
+
*/
|
|
53
|
+
newController(context?: ContextType): MaybePromise<object>;
|
|
54
|
+
/**
|
|
55
|
+
* Exécute l'action résolue, puis rend sa valeur sur le transport.
|
|
56
|
+
*
|
|
57
|
+
* @param data - arguments supplémentaires de l'action
|
|
58
|
+
* @param reload - rejouer depuis l'instance en cache (forward)
|
|
59
|
+
* @returns le résultat du rendu — synchrone quand ni l'action ni le rendu
|
|
60
|
+
* n'attendent, sinon sa promesse
|
|
61
|
+
*/
|
|
62
|
+
callController(data?: unknown[], reload?: boolean): MaybePromise<unknown>;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Ce que le pipeline HTTP/WS attend du service `router` — implémenté par
|
|
66
|
+
* `Router` (`@nodefony/framework`).
|
|
67
|
+
*/
|
|
68
|
+
export interface IRequestRouter {
|
|
69
|
+
/**
|
|
70
|
+
* Résout la route d'un contexte.
|
|
71
|
+
*
|
|
72
|
+
* @param context - le contexte HTTP/WS courant
|
|
73
|
+
* @param cleanPathOverride - chemin porté par un message (pont WS-RPC)
|
|
74
|
+
* @param methodOverride - méthode logique exigée en plus du transport WS
|
|
75
|
+
* @returns le résolveur (`resolve === true` si une route a matché)
|
|
76
|
+
*/
|
|
77
|
+
resolve(context: ContextType, cleanPathOverride?: string, methodOverride?: string): IRouteResolver;
|
|
78
|
+
/**
|
|
79
|
+
* Instance partagée d'un controller `scope: "singleton"`, créée une seule fois.
|
|
80
|
+
*
|
|
81
|
+
* @param ctor - la classe du controller (clé du cache)
|
|
82
|
+
* @param create - fabrique exécutée au premier appel
|
|
83
|
+
* @returns l'instance partagée une fois créée ; la promesse de sa création
|
|
84
|
+
* tant qu'elle est en cours
|
|
85
|
+
*/
|
|
86
|
+
getSingletonController<T extends object>(ctor: new (...args: never[]) => T, create: () => MaybePromise<T>): MaybePromise<T>;
|
|
87
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { ContextType } from "../service/http-kernel.js";
|
|
2
|
+
/**
|
|
3
|
+
* Ce que le pipeline HTTP/WS — et le résolveur de framework — lit de la zone de sécurité posée sur
|
|
4
|
+
* `context.security` — et rien de plus.
|
|
5
|
+
*
|
|
6
|
+
* Le pare-feu vit dans `@nodefony/security`, qui dépend de `@nodefony/http` :
|
|
7
|
+
* `http` ne peut donc pas nommer ses classes sans recréer un cycle. C'est le
|
|
8
|
+
* LECTEUR qui définit le contrat ; `ISecuredArea` (security) l'étend, et le
|
|
9
|
+
* typecheck de `security` garantit l'alignement.
|
|
10
|
+
*/
|
|
11
|
+
export interface ISecurityZone {
|
|
12
|
+
/** Nom de la zone (journalisation, profiler). */
|
|
13
|
+
readonly name: string;
|
|
14
|
+
/** `true` si la zone exige une authentification. */
|
|
15
|
+
readonly security: boolean;
|
|
16
|
+
/** Zone sans session : aucune session n'est ouverte ni lue. */
|
|
17
|
+
readonly stateless: boolean;
|
|
18
|
+
/** Stratégie des authenticators : le premier qui répond, ou tous. */
|
|
19
|
+
readonly mode: "first" | "all";
|
|
20
|
+
/** Noms des authenticators candidats, dans l'ordre. */
|
|
21
|
+
readonly authenticators: readonly string[];
|
|
22
|
+
/**
|
|
23
|
+
* Rôles exigés par la zone, en OU (un seul suffit) ; `null` = aucune exigence
|
|
24
|
+
* de rôle. Lu par le résolveur de `@nodefony/framework` pour l'autorisation.
|
|
25
|
+
*/
|
|
26
|
+
readonly roles: readonly string[] | null;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Ce que le noyau HTTP appelle du pare-feu, service `firewall` du conteneur.
|
|
30
|
+
*
|
|
31
|
+
* Implémenté par `Firewall` (`@nodefony/security`), dont `IFirewall` étend ce
|
|
32
|
+
* contrat de ses propres membres (CSP, authenticators, description).
|
|
33
|
+
*/
|
|
34
|
+
export interface IFirewallGate {
|
|
35
|
+
/** Match rapide de zone : pose `context.security`, `true` si une zone capture. */
|
|
36
|
+
isSecure(context: ContextType): boolean;
|
|
37
|
+
/** Authentifie la requête d'une zone protégée ; rejette si elle est refusée. */
|
|
38
|
+
handleSecurity(context: ContextType): Promise<ContextType>;
|
|
39
|
+
/** Refuse une requête qui ne présente pas le jeton CSRF attendu. */
|
|
40
|
+
enforceCsrf(context: ContextType): void;
|
|
41
|
+
/** Répond au preflight CORS ; `204` quand la réponse est déjà envoyée. */
|
|
42
|
+
handleCors(context: ContextType): number | undefined;
|
|
43
|
+
/** Pose les en-têtes de sécurité (CSP, HSTS…) de la réponse. */
|
|
44
|
+
applySecurityHeaders(context: ContextType): void;
|
|
45
|
+
}
|
|
@@ -13,7 +13,7 @@ export type MetaBagType = Record<string, unknown>;
|
|
|
13
13
|
* - `readOnly` : la session est lue/reprise mais **jamais persistée** (0 write storage).
|
|
14
14
|
*/
|
|
15
15
|
export interface SessionIntent {
|
|
16
|
-
readOnly?: boolean;
|
|
16
|
+
readOnly?: boolean | undefined;
|
|
17
17
|
}
|
|
18
18
|
/**
|
|
19
19
|
* Données de session **sérialisées** échangées avec un {@link ISessionStorage}
|
|
@@ -25,8 +25,8 @@ export interface ISerializedSession {
|
|
|
25
25
|
metaBag: Record<string, unknown>;
|
|
26
26
|
flashBag: Record<string, unknown>;
|
|
27
27
|
user: string;
|
|
28
|
-
createdAt?: Date;
|
|
29
|
-
updatedAt?: Date;
|
|
28
|
+
createdAt?: Date | undefined;
|
|
29
|
+
updatedAt?: Date | undefined;
|
|
30
30
|
}
|
|
31
31
|
/**
|
|
32
32
|
* Projection **redactée** d'une session pour l'ADMINISTRATION (data plane Studio,
|
|
@@ -100,7 +100,7 @@ export interface ISessionListFilter {
|
|
|
100
100
|
/** Restreint aux sessions d'un utilisateur (pour « déconnecter partout »). */
|
|
101
101
|
user?: string;
|
|
102
102
|
/** Slot multi-tenant — non scopé aujourd'hui (réserve coût-0). */
|
|
103
|
-
tenantId?: string | null;
|
|
103
|
+
tenantId?: string | null | undefined;
|
|
104
104
|
}
|
|
105
105
|
/**
|
|
106
106
|
* Requête d'énumération **paginée** des sessions — le {@link IPageQuery} standard
|
|
@@ -253,10 +253,10 @@ export interface ISession {
|
|
|
253
253
|
cookieSession: ICookie | null | undefined;
|
|
254
254
|
flashBag: FlashBagType;
|
|
255
255
|
strategy: SessionStrategyType;
|
|
256
|
-
created?: Date;
|
|
257
|
-
updated?: Date;
|
|
258
|
-
user?: string;
|
|
259
|
-
lifetime?: number;
|
|
256
|
+
created?: Date | undefined;
|
|
257
|
+
updated?: Date | undefined;
|
|
258
|
+
user?: string | undefined;
|
|
259
|
+
lifetime?: number | undefined;
|
|
260
260
|
storage: ISessionStorage;
|
|
261
261
|
start(context: unknown): Promise<ISession>;
|
|
262
262
|
save(user?: string): Promise<ISession>;
|
|
@@ -28,21 +28,21 @@ export interface IParsedUploadFile {
|
|
|
28
28
|
*/
|
|
29
29
|
export interface IUploadOptions {
|
|
30
30
|
/** Répertoire de dépôt des fichiers temporaires. */
|
|
31
|
-
uploadDir?: string;
|
|
31
|
+
uploadDir?: string | undefined;
|
|
32
32
|
/** Taille max d'UN fichier (octets) — `limits.fileSize` busboy. */
|
|
33
|
-
maxFileSize?: number;
|
|
33
|
+
maxFileSize?: number | undefined;
|
|
34
34
|
/** Taille max CUMULÉE des fichiers d'une requête (octets) — appliquée par Nodefony. */
|
|
35
|
-
maxTotalFileSize?: number;
|
|
35
|
+
maxTotalFileSize?: number | undefined;
|
|
36
36
|
/** Nombre max de fichiers — `limits.files` busboy. */
|
|
37
|
-
maxFiles?: number;
|
|
37
|
+
maxFiles?: number | undefined;
|
|
38
38
|
/** Nombre max de champs texte — `limits.fields` busboy. */
|
|
39
|
-
maxFields?: number;
|
|
39
|
+
maxFields?: number | undefined;
|
|
40
40
|
/** Taille max d'un champ texte (octets) — `limits.fieldSize` busboy. */
|
|
41
|
-
maxFieldsSize?: number;
|
|
41
|
+
maxFieldsSize?: number | undefined;
|
|
42
42
|
/** Hash calculé pendant le stream (défaut `false` = aucun). */
|
|
43
|
-
hashAlgorithm?: false | "sha1" | "md5" | "sha256";
|
|
43
|
+
hashAlgorithm?: false | "sha1" | "md5" | "sha256" | undefined;
|
|
44
44
|
/** Encodage par défaut des parts texte. */
|
|
45
|
-
encoding?: string;
|
|
45
|
+
encoding?: string | undefined;
|
|
46
46
|
}
|
|
47
47
|
export interface IUploadedFile {
|
|
48
48
|
filename: string;
|
|
@@ -60,7 +60,7 @@ export interface IUploadedFile {
|
|
|
60
60
|
getPrettySize(): string;
|
|
61
61
|
}
|
|
62
62
|
export interface IUploadService {
|
|
63
|
-
path?:
|
|
63
|
+
path?: unknown;
|
|
64
64
|
/** Construit un `UploadedFile` en async (stat non bloquant). */
|
|
65
65
|
createUploadFile(file: unknown, name: string): Promise<IUploadedFile>;
|
|
66
66
|
}
|
|
@@ -5,3 +5,5 @@ export type { IRequest, IHttpRequest, IHttp2Request, IWsRequest, HTTPMethodType,
|
|
|
5
5
|
export type { IResponse, IHttpResponse, IWebsocketResponse } from "./IResponse.js";
|
|
6
6
|
export type { IContext, IHttpContext, IWebsocketContext, ServerType, SchemeType, WebSocketStateType, CookiesMap, } from "./IContext.js";
|
|
7
7
|
export type { IHttpKernel } from "./IHttpKernel.js";
|
|
8
|
+
export type { IResolvedRoute, IRouteResolver, IRequestRouter, } from "./IRouting.js";
|
|
9
|
+
export type { ISecurityZone, IFirewallGate } from "./ISecurity.js";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Severity } from "nodefony";
|
|
2
2
|
import type { IRequestLogger, IRequestLogEntry } from "../interfaces/IRequestLogger.js";
|
|
3
|
-
import type { IHttpContext, IWebsocketContext } from "../interfaces/IContext.js";
|
|
3
|
+
import type { IHttpContext, IWebsocketContext, PhaseTiming } from "../interfaces/IContext.js";
|
|
4
4
|
/**
|
|
5
5
|
* Canonical audit log entry — 1 JSON PDU per request (P3.1).
|
|
6
6
|
*
|
|
@@ -32,9 +32,9 @@ export interface AuditLogEntry {
|
|
|
32
32
|
phases?: {
|
|
33
33
|
name: string;
|
|
34
34
|
durationMs: number | null;
|
|
35
|
-
}[];
|
|
36
|
-
error?: AuditErrorEntry;
|
|
37
|
-
protocol?: string | null;
|
|
35
|
+
}[] | undefined;
|
|
36
|
+
error?: AuditErrorEntry | undefined;
|
|
37
|
+
protocol?: string | null | undefined;
|
|
38
38
|
}
|
|
39
39
|
/**
|
|
40
40
|
* Enriched error description for audit logs (P3.5).
|
|
@@ -51,6 +51,15 @@ export interface AuditErrorEntry {
|
|
|
51
51
|
/** Recursive — capped to depth 5 to avoid pathological cycles. */
|
|
52
52
|
cause?: AuditErrorEntry;
|
|
53
53
|
}
|
|
54
|
+
/**
|
|
55
|
+
* Durée totale de la requête, de la première phase (`startMs`) à maintenant.
|
|
56
|
+
* `null` si le chronométrage est coupé (aucune phase enregistrée). Partagée
|
|
57
|
+
* par le journal d'audit et le journal lisible — une seule définition.
|
|
58
|
+
*
|
|
59
|
+
* @param phases - phases chronométrées du contexte
|
|
60
|
+
* @returns durée en millisecondes, ou `null`
|
|
61
|
+
*/
|
|
62
|
+
declare function computeDurationMs(phases: PhaseTiming[]): number | null;
|
|
54
63
|
/**
|
|
55
64
|
* Severity derived from HTTP status code — RFC 9110 categories.
|
|
56
65
|
* 1xx/2xx/3xx → INFO ; 4xx → WARNING ; 5xx → ERROR.
|
|
@@ -127,11 +136,6 @@ declare class JsonAuditLogger implements IRequestLogger {
|
|
|
127
136
|
shouldSample(context: IHttpContext, error?: Error | null): boolean;
|
|
128
137
|
renderHttp(context: IHttpContext, error?: Error | null): IRequestLogEntry;
|
|
129
138
|
renderWebsocket(context: IWebsocketContext, error?: Error | null, acceptedProtocol?: string | null): IRequestLogEntry;
|
|
130
|
-
/**
|
|
131
|
-
* Total request duration computed from the first phase startMs to now.
|
|
132
|
-
* Returns null if timing is disabled (no phases recorded).
|
|
133
|
-
*/
|
|
134
|
-
private computeDurationMs;
|
|
135
139
|
/**
|
|
136
140
|
* Serialise an Error (recursively for `cause` chain) into an AuditErrorEntry.
|
|
137
141
|
* Stack is included only when `includeStack === true` (dev default).
|
|
@@ -140,4 +144,4 @@ declare class JsonAuditLogger implements IRequestLogger {
|
|
|
140
144
|
private serializeError;
|
|
141
145
|
}
|
|
142
146
|
export default JsonAuditLogger;
|
|
143
|
-
export { severityFromStatus };
|
|
147
|
+
export { computeDurationMs, severityFromStatus };
|