@nodefony/http 10.0.0-alpha.1
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/LICENSE +544 -0
- package/README.md +77 -0
- package/dist/_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorate.js +9 -0
- package/dist/_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorateMetadata.js +6 -0
- package/dist/_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorateParam.js +8 -0
- package/dist/index.js +108 -0
- package/dist/nodefony/command/assetsPublishCommand.js +102 -0
- package/dist/nodefony/command/certificatesCommand.js +47 -0
- package/dist/nodefony/command/networkCommand.js +27 -0
- package/dist/nodefony/command/proxyGenerateCommand.js +66 -0
- package/dist/nodefony/config/config.js +335 -0
- package/dist/nodefony/config/defineModuleConfig.js +93 -0
- package/dist/nodefony/interfaces/IContext.js +1 -0
- package/dist/nodefony/interfaces/ICookie.js +1 -0
- package/dist/nodefony/interfaces/IErrorRenderer.js +1 -0
- package/dist/nodefony/interfaces/IHttpConfig.js +1 -0
- package/dist/nodefony/interfaces/IHttpKernel.js +1 -0
- package/dist/nodefony/interfaces/IRequest.js +1 -0
- package/dist/nodefony/interfaces/IRequestLogger.js +1 -0
- package/dist/nodefony/interfaces/IResponse.js +1 -0
- package/dist/nodefony/interfaces/ISession.js +1 -0
- package/dist/nodefony/interfaces/IUpload.js +1 -0
- package/dist/nodefony/interfaces/index.js +1 -0
- package/dist/nodefony/service/HttpAdminApi.js +376 -0
- package/dist/nodefony/service/ProfilerAdminApi.js +73 -0
- package/dist/nodefony/service/audit-logger.js +159 -0
- package/dist/nodefony/service/certificates.js +545 -0
- package/dist/nodefony/service/error-renderer.js +320 -0
- package/dist/nodefony/service/http-kernel.js +948 -0
- package/dist/nodefony/service/pretty-request-logger.js +72 -0
- package/dist/nodefony/service/request-logger.js +54 -0
- package/dist/nodefony/service/servers/clientError.js +20 -0
- package/dist/nodefony/service/servers/server-http.js +135 -0
- package/dist/nodefony/service/servers/server-https.js +204 -0
- package/dist/nodefony/service/servers/server-static.js +192 -0
- package/dist/nodefony/service/servers/server-websocket-secure.js +104 -0
- package/dist/nodefony/service/servers/server-websocket.js +104 -0
- package/dist/nodefony/service/servers/serverShutdown.js +31 -0
- package/dist/nodefony/service/servers/wsHeartbeat.js +64 -0
- package/dist/nodefony/service/sessions/sessions-service.js +580 -0
- package/dist/nodefony/service/trace.js +72 -0
- package/dist/nodefony/service/upload/upload-service.js +171 -0
- package/dist/nodefony/src/assets/collectAssets.js +34 -0
- package/dist/nodefony/src/assets/prebuiltUi.js +125 -0
- package/dist/nodefony/src/context/Context.js +415 -0
- package/dist/nodefony/src/context/domainMatcher.js +88 -0
- package/dist/nodefony/src/context/forwarded.js +185 -0
- package/dist/nodefony/src/context/http/HttpContext.js +309 -0
- package/dist/nodefony/src/context/http/Request.js +543 -0
- package/dist/nodefony/src/context/http/Response.js +368 -0
- package/dist/nodefony/src/context/http/parser.js +188 -0
- package/dist/nodefony/src/context/http/urlFastPath.js +103 -0
- package/dist/nodefony/src/context/http2/Request.js +29 -0
- package/dist/nodefony/src/context/http2/Response.js +97 -0
- package/dist/nodefony/src/context/metaData.js +47 -0
- package/dist/nodefony/src/context/requestId.js +41 -0
- package/dist/nodefony/src/context/trustProxy.js +167 -0
- package/dist/nodefony/src/context/websocket/Response.js +181 -0
- package/dist/nodefony/src/context/websocket/WebsocketContext.js +389 -0
- package/dist/nodefony/src/context/websocket/wsBackpressure.js +56 -0
- package/dist/nodefony/src/context/websocket/wsLogContent.js +68 -0
- package/dist/nodefony/src/cookies/cookie.js +258 -0
- package/dist/nodefony/src/errors/httpError.js +69 -0
- package/dist/nodefony/src/profiler/FrameProfile.js +95 -0
- package/dist/nodefony/src/profiler/Profiler.js +139 -0
- package/dist/nodefony/src/proxy/generateProxyConfig.js +157 -0
- package/dist/nodefony/src/rateLimit/IRateLimitStore.js +1 -0
- package/dist/nodefony/src/rateLimit/MemoryRateLimitStore.js +146 -0
- package/dist/nodefony/src/rateLimit/WsConnectionCounter.js +64 -0
- package/dist/nodefony/src/rateLimit/rateLimitFilters.js +20 -0
- package/dist/nodefony/src/servers/portBinder.js +114 -0
- package/dist/nodefony/src/session/session.js +390 -0
- package/dist/nodefony/src/session/storage/MemorySessionStorage.js +185 -0
- package/dist/nodefony/src/session/storage/RevocationGuardStorage.js +137 -0
- package/dist/nodefony/src/session/storage/sessionFilters.js +83 -0
- package/dist/nodefony/src/session/storage/sessionSort.js +53 -0
- package/dist/types/index.d.ts +83 -0
- package/dist/types/nodefony/command/assetsPublishCommand.d.ts +23 -0
- package/dist/types/nodefony/command/certificatesCommand.d.ts +17 -0
- package/dist/types/nodefony/command/networkCommand.d.ts +8 -0
- package/dist/types/nodefony/command/proxyGenerateCommand.d.ts +19 -0
- package/dist/types/nodefony/config/config.d.ts +197 -0
- package/dist/types/nodefony/config/defineModuleConfig.d.ts +39 -0
- package/dist/types/nodefony/interfaces/IContext.d.ts +138 -0
- package/dist/types/nodefony/interfaces/ICookie.d.ts +47 -0
- package/dist/types/nodefony/interfaces/IErrorRenderer.d.ts +55 -0
- package/dist/types/nodefony/interfaces/IHttpConfig.d.ts +12 -0
- package/dist/types/nodefony/interfaces/IHttpKernel.d.ts +10 -0
- package/dist/types/nodefony/interfaces/IRequest.d.ts +35 -0
- package/dist/types/nodefony/interfaces/IRequestLogger.d.ts +31 -0
- package/dist/types/nodefony/interfaces/IResponse.d.ts +39 -0
- package/dist/types/nodefony/interfaces/ISession.d.ts +283 -0
- package/dist/types/nodefony/interfaces/IUpload.d.ts +66 -0
- package/dist/types/nodefony/interfaces/index.d.ts +7 -0
- package/dist/types/nodefony/service/HttpAdminApi.d.ts +18 -0
- package/dist/types/nodefony/service/ProfilerAdminApi.d.ts +23 -0
- package/dist/types/nodefony/service/audit-logger.d.ts +143 -0
- package/dist/types/nodefony/service/certificates.d.ts +246 -0
- package/dist/types/nodefony/service/error-renderer.d.ts +74 -0
- package/dist/types/nodefony/service/http-kernel.d.ts +377 -0
- package/dist/types/nodefony/service/pretty-request-logger.d.ts +25 -0
- package/dist/types/nodefony/service/request-logger.d.ts +18 -0
- package/dist/types/nodefony/service/servers/clientError.d.ts +14 -0
- package/dist/types/nodefony/service/servers/server-http.d.ts +42 -0
- package/dist/types/nodefony/service/servers/server-https.d.ts +41 -0
- package/dist/types/nodefony/service/servers/server-static.d.ts +62 -0
- package/dist/types/nodefony/service/servers/server-websocket-secure.d.ts +29 -0
- package/dist/types/nodefony/service/servers/server-websocket.d.ts +29 -0
- package/dist/types/nodefony/service/servers/serverShutdown.d.ts +27 -0
- package/dist/types/nodefony/service/servers/wsHeartbeat.d.ts +46 -0
- package/dist/types/nodefony/service/sessions/sessions-service.d.ts +218 -0
- package/dist/types/nodefony/service/trace.d.ts +39 -0
- package/dist/types/nodefony/service/upload/upload-service.d.ts +61 -0
- package/dist/types/nodefony/src/assets/collectAssets.d.ts +35 -0
- package/dist/types/nodefony/src/assets/prebuiltUi.d.ts +99 -0
- package/dist/types/nodefony/src/context/Context.d.ts +195 -0
- package/dist/types/nodefony/src/context/domainMatcher.d.ts +67 -0
- package/dist/types/nodefony/src/context/forwarded.d.ts +95 -0
- package/dist/types/nodefony/src/context/http/HttpContext.d.ts +85 -0
- package/dist/types/nodefony/src/context/http/Request.d.ts +203 -0
- package/dist/types/nodefony/src/context/http/Response.d.ts +68 -0
- package/dist/types/nodefony/src/context/http/parser.d.ts +65 -0
- package/dist/types/nodefony/src/context/http/urlFastPath.d.ts +52 -0
- package/dist/types/nodefony/src/context/http2/Request.d.ts +14 -0
- package/dist/types/nodefony/src/context/http2/Response.d.ts +20 -0
- package/dist/types/nodefony/src/context/metaData.d.ts +58 -0
- package/dist/types/nodefony/src/context/requestId.d.ts +28 -0
- package/dist/types/nodefony/src/context/trustProxy.d.ts +77 -0
- package/dist/types/nodefony/src/context/websocket/Response.d.ts +53 -0
- package/dist/types/nodefony/src/context/websocket/WebsocketContext.d.ts +125 -0
- package/dist/types/nodefony/src/context/websocket/wsBackpressure.d.ts +73 -0
- package/dist/types/nodefony/src/context/websocket/wsLogContent.d.ts +37 -0
- package/dist/types/nodefony/src/cookies/cookie.d.ts +88 -0
- package/dist/types/nodefony/src/errors/httpError.d.ts +15 -0
- package/dist/types/nodefony/src/profiler/FrameProfile.d.ts +110 -0
- package/dist/types/nodefony/src/profiler/Profiler.d.ts +192 -0
- package/dist/types/nodefony/src/proxy/generateProxyConfig.d.ts +76 -0
- package/dist/types/nodefony/src/rateLimit/IRateLimitStore.d.ts +98 -0
- package/dist/types/nodefony/src/rateLimit/MemoryRateLimitStore.d.ts +40 -0
- package/dist/types/nodefony/src/rateLimit/WsConnectionCounter.d.ts +37 -0
- package/dist/types/nodefony/src/rateLimit/rateLimitFilters.d.ts +18 -0
- package/dist/types/nodefony/src/servers/portBinder.d.ts +102 -0
- package/dist/types/nodefony/src/session/session.d.ts +171 -0
- package/dist/types/nodefony/src/session/storage/MemorySessionStorage.d.ts +77 -0
- package/dist/types/nodefony/src/session/storage/RevocationGuardStorage.d.ts +81 -0
- package/dist/types/nodefony/src/session/storage/sessionFilters.d.ts +102 -0
- package/dist/types/nodefony/src/session/storage/sessionSort.d.ts +45 -0
- package/docs/cookies.md +365 -0
- package/docs/index.md +163 -0
- package/docs/observabilite.md +460 -0
- package/docs/rate-limit.md +372 -0
- package/docs/servers.md +935 -0
- package/docs/session.md +768 -0
- package/docs/upload.md +460 -0
- package/package.json +101 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { IHttpConfig, IHttpConfigInput } from "../interfaces/IHttpConfig.js";
|
|
2
|
+
/**
|
|
3
|
+
* Sous-ensemble structurel du kernel nécessaire aux défauts dérivés — découple
|
|
4
|
+
* le builder du type `Kernel`/`IKernel` (testable sans kernel complet). Tous les
|
|
5
|
+
* champs sont optionnels : un kernel absent ou minimal retombe sur les fallbacks.
|
|
6
|
+
*/
|
|
7
|
+
export interface IKernelConfigDefaults {
|
|
8
|
+
tmpDir?: {
|
|
9
|
+
path?: unknown;
|
|
10
|
+
} | null;
|
|
11
|
+
domain?: string;
|
|
12
|
+
projectName?: string;
|
|
13
|
+
/** Environnement courant — pilote les défauts secure-by-default (ex. `Server:`). */
|
|
14
|
+
environment?: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Builder type-safe de la configuration de `@nodefony/http`.
|
|
18
|
+
*
|
|
19
|
+
* ⭐ TL;DR : MACHINERIE DE BOOT — on n'édite (presque) jamais ce fichier. Même
|
|
20
|
+
* pattern que `nodefony.config.ts` ↔ `defineConfig()` du core : `config.ts` PORTE
|
|
21
|
+
* la config (schéma + défauts), `define<X>Config()` la VALIDE au boot (parse +
|
|
22
|
+
* env + freeze) et publie le JSON Schema Studio.
|
|
23
|
+
*
|
|
24
|
+
* Aligné sur `defineRedisConfig` / `defineSecurityConfig` : source unique =
|
|
25
|
+
* `./config.ts` (Zod) ; le builder VALIDE puis complète les défauts kernel.
|
|
26
|
+
*
|
|
27
|
+
* @param config - configuration brute (sections omises = défauts sûrs).
|
|
28
|
+
* @param kernel - kernel courant, pour les défauts dérivés (tmpDir, domain).
|
|
29
|
+
* @returns config validée et complétée (NON gelée — les services la mutent).
|
|
30
|
+
* @throws BootConfigurationError si un champ est invalide ou une clé inconnue —
|
|
31
|
+
* `parseModuleConfig` (cœur) porte le message ET le type d'erreur, pour que le
|
|
32
|
+
* refus interrompe le boot en développement comme en production.
|
|
33
|
+
*/
|
|
34
|
+
export declare function defineHttpConfig(config?: IHttpConfigInput, kernel?: IKernelConfigDefaults | null): IHttpConfig;
|
|
35
|
+
/**
|
|
36
|
+
* JSON Schema introspectable de la config HTTP — destiné au formulaire
|
|
37
|
+
* d'édition Studio (futur) et à la documentation générée.
|
|
38
|
+
*/
|
|
39
|
+
export declare function httpConfigJsonSchema(): unknown;
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import type { URL } from "node:url";
|
|
2
|
+
import type { ICookie } from "./ICookie.js";
|
|
3
|
+
import type { ISession } from "./ISession.js";
|
|
4
|
+
import type { HTTPMethodType } from "./IRequest.js";
|
|
5
|
+
export type ServerType = "http" | "https" | "http2" | "http3" | "websocket" | "websocket-secure";
|
|
6
|
+
export type SchemeType = "http" | "https" | "ws" | "wss";
|
|
7
|
+
export type WebSocketStateType = "handshake" | "connected" | "closed" | "error" | "message" | null;
|
|
8
|
+
export type CookiesMap = Record<string, ICookie>;
|
|
9
|
+
export type PhaseName = "parse" | "resolve" | "firewall" | "initialize" | "action" | "render" | "send" | (string & {});
|
|
10
|
+
export interface PhaseTiming {
|
|
11
|
+
name: PhaseName;
|
|
12
|
+
startMs: number;
|
|
13
|
+
endMs?: number;
|
|
14
|
+
durationMs?: number;
|
|
15
|
+
}
|
|
16
|
+
/** Issue de la traversée d'une zone firewall. */
|
|
17
|
+
export type SecurityOutcome =
|
|
18
|
+
/** Identité authentifiée (un authenticator a résolu un token). */
|
|
19
|
+
"granted"
|
|
20
|
+
/** Anonyme EXPLICITE (authenticator `anonymous` listé par la zone). */
|
|
21
|
+
| "anonymous"
|
|
22
|
+
/** Refus par POLITIQUE (aucune preuve présentée en zone fermée → 401). */
|
|
23
|
+
| "denied"
|
|
24
|
+
/** Preuve PRÉSENTÉE mais invalide (l'acteur a échoué une preuve → 401). */
|
|
25
|
+
| "failure"
|
|
26
|
+
/** Backoff NIST actif (429). */
|
|
27
|
+
| "throttled"
|
|
28
|
+
/** Route exemptée (`bypassFirewall`) — la zone est traversée sans auth. */
|
|
29
|
+
| "bypass";
|
|
30
|
+
/**
|
|
31
|
+
* Décision du firewall sur CETTE requête — matière de la « radiographie »
|
|
32
|
+
* (Studio / debug bar) : la zone dit ce qui était POSSIBLE (via
|
|
33
|
+
* `context.security`), cette trace dit ce qui s'est RÉELLEMENT passé.
|
|
34
|
+
*
|
|
35
|
+
* Le contrat vit ici (et non dans `@nodefony/security`) parce que
|
|
36
|
+
* `@nodefony/http` ne peut pas importer le module de sécurité (cycle) : http
|
|
37
|
+
* porte le champ, security le REMPLIT — exactement le pattern de
|
|
38
|
+
* `profilerQueries` (buffer porté par http, rempli par les adapters ORM).
|
|
39
|
+
*
|
|
40
|
+
* **Dev-only** : alloué par le firewall UNIQUEMENT si `context.profiling` est
|
|
41
|
+
* vrai (profiler actif → jamais en production). Le chemin nominal de succès
|
|
42
|
+
* n'émet aucun événement d'audit (le volume n'est pas un signal) : sans cette
|
|
43
|
+
* trace, une requête qui PASSE ne laisse aucune empreinte de sa zone.
|
|
44
|
+
*/
|
|
45
|
+
export interface ISecurityTrace {
|
|
46
|
+
/** Authenticator qui a résolu le token — `null` si aucun n'a abouti. */
|
|
47
|
+
authenticator: string | null;
|
|
48
|
+
/** Ce qui s'est passé. */
|
|
49
|
+
outcome: SecurityOutcome;
|
|
50
|
+
/** Motif du refus (`no_credentials`, `invalid_credentials`…), `null` si succès. */
|
|
51
|
+
reason: string | null;
|
|
52
|
+
/**
|
|
53
|
+
* Identité résolue par le firewall. Le token vit dans l'ALS (pas sur
|
|
54
|
+
* `context.user`) : sans ce champ, une requête authentifiée s'affiche
|
|
55
|
+
* « anonyme » alors qu'elle porte des rôles.
|
|
56
|
+
*/
|
|
57
|
+
user: string | null;
|
|
58
|
+
/** Rôles portés par le token résolu, `null` hors succès. */
|
|
59
|
+
roles: string[] | null;
|
|
60
|
+
}
|
|
61
|
+
export type AfterResponseHandler = (ctx: IContext) => void | Promise<void>;
|
|
62
|
+
export interface IContext {
|
|
63
|
+
requestId: string;
|
|
64
|
+
readonly cspNonce: string;
|
|
65
|
+
cspDirectives: Record<string, readonly string[]> | null;
|
|
66
|
+
csrfProtect: boolean;
|
|
67
|
+
csrfExempt: boolean;
|
|
68
|
+
csrfToken: string | null;
|
|
69
|
+
type: ServerType;
|
|
70
|
+
scheme: SchemeType;
|
|
71
|
+
method: HTTPMethodType | null;
|
|
72
|
+
url: string;
|
|
73
|
+
domain: string;
|
|
74
|
+
request: object | null;
|
|
75
|
+
response: object | null;
|
|
76
|
+
secure: boolean;
|
|
77
|
+
finished: boolean;
|
|
78
|
+
cleaned: boolean;
|
|
79
|
+
webSocketState: WebSocketStateType;
|
|
80
|
+
isJson: boolean;
|
|
81
|
+
isHtml: boolean;
|
|
82
|
+
remoteAddress: string | null | undefined;
|
|
83
|
+
originUrl: URL | null | undefined;
|
|
84
|
+
session: ISession | null | undefined;
|
|
85
|
+
cookieSession: ICookie | null | undefined;
|
|
86
|
+
cookies: CookiesMap;
|
|
87
|
+
user: unknown;
|
|
88
|
+
error: Error | null | undefined;
|
|
89
|
+
metaData: object;
|
|
90
|
+
readonly phases: PhaseTiming[];
|
|
91
|
+
phaseStart(name: PhaseName): void;
|
|
92
|
+
phaseEnd(name: PhaseName): void;
|
|
93
|
+
profiling: boolean;
|
|
94
|
+
securityTrace: ISecurityTrace | null;
|
|
95
|
+
onAfterResponse(fn: AfterResponseHandler): void;
|
|
96
|
+
readonly signal: AbortSignal;
|
|
97
|
+
addRequestCookie(cookie: ICookie): ICookie;
|
|
98
|
+
getRequestCookies(name?: string): CookiesMap | ICookie | null;
|
|
99
|
+
setCookie(cookie: ICookie): void;
|
|
100
|
+
parseCookies(): void;
|
|
101
|
+
getRequest(): object | null;
|
|
102
|
+
getResponse(): object | null;
|
|
103
|
+
isValidDomain(): boolean;
|
|
104
|
+
saveSession(): Promise<ISession | null>;
|
|
105
|
+
hasSession(): boolean;
|
|
106
|
+
getCookieSession(name: string): ICookie | null;
|
|
107
|
+
getSessionCookieName(): string;
|
|
108
|
+
setMetaData(obj?: Record<string, unknown>): object;
|
|
109
|
+
}
|
|
110
|
+
export interface IHttpContext extends IContext {
|
|
111
|
+
proxy: object | null;
|
|
112
|
+
isRedirect: boolean;
|
|
113
|
+
handle(): Promise<object>;
|
|
114
|
+
render(chunk: unknown, encoding?: BufferEncoding, status?: string | number, headers?: Record<string, string | number>): Promise<object>;
|
|
115
|
+
send(chunk?: unknown, encoding?: BufferEncoding): Promise<object>;
|
|
116
|
+
end(): Promise<object>;
|
|
117
|
+
redirect(url: string, status?: number | string, headers?: Record<string, string | number>): unknown;
|
|
118
|
+
getHostName(): string | undefined;
|
|
119
|
+
getRemoteAddress(): string | null | undefined;
|
|
120
|
+
getHost(): string | undefined;
|
|
121
|
+
getUserAgent(): string | undefined;
|
|
122
|
+
}
|
|
123
|
+
export interface IWebsocketContext extends IContext {
|
|
124
|
+
acceptedProtocol?: string;
|
|
125
|
+
connection: unknown | null;
|
|
126
|
+
rejected: boolean;
|
|
127
|
+
port: number | string;
|
|
128
|
+
wsUrl: URL | null;
|
|
129
|
+
queryGet: Record<string, string>;
|
|
130
|
+
connect(): Promise<unknown>;
|
|
131
|
+
handle(data?: unknown[]): Promise<object>;
|
|
132
|
+
close(reasonCode: number, description: string): unknown;
|
|
133
|
+
send(data?: Buffer | string | null, encoding?: BufferEncoding): Promise<object>;
|
|
134
|
+
broadcast(data: Buffer | string): void;
|
|
135
|
+
getRemoteAddress(): string | null | undefined;
|
|
136
|
+
getHost(): string | undefined;
|
|
137
|
+
getUserAgent(): string | undefined;
|
|
138
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export type SameSiteType = "Strict" | "Lax" | "None";
|
|
2
|
+
export type PriorityType = "High" | "Medium" | "Low" | undefined;
|
|
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;
|
|
13
|
+
priority?: PriorityType;
|
|
14
|
+
}
|
|
15
|
+
export interface IWsCookie {
|
|
16
|
+
name: string;
|
|
17
|
+
value: string;
|
|
18
|
+
maxage?: number;
|
|
19
|
+
domain?: string;
|
|
20
|
+
path?: string;
|
|
21
|
+
expires?: Date;
|
|
22
|
+
httponly?: boolean;
|
|
23
|
+
secure?: boolean;
|
|
24
|
+
}
|
|
25
|
+
export interface ICookie {
|
|
26
|
+
name: string;
|
|
27
|
+
value: unknown;
|
|
28
|
+
options: ICookieOptions;
|
|
29
|
+
signed?: boolean;
|
|
30
|
+
originalMaxAge?: number;
|
|
31
|
+
expires?: Date;
|
|
32
|
+
maxAge?: number;
|
|
33
|
+
path?: string;
|
|
34
|
+
domain?: string | undefined;
|
|
35
|
+
httpOnly?: boolean;
|
|
36
|
+
secure?: boolean;
|
|
37
|
+
sameSite?: SameSiteType;
|
|
38
|
+
priority?: string;
|
|
39
|
+
setValue(value: unknown): unknown;
|
|
40
|
+
toString(): string;
|
|
41
|
+
serialize(): string;
|
|
42
|
+
serializeWebSocket(): IWsCookie;
|
|
43
|
+
clearCookie(): void;
|
|
44
|
+
sign(val: string, secret: string): string;
|
|
45
|
+
unsign(val?: string, secret?: string): string | false;
|
|
46
|
+
getMaxAge(): number | undefined;
|
|
47
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { IHttpContext, IWebsocketContext } from "./IContext.js";
|
|
2
|
+
/**
|
|
3
|
+
* Result of rendering an error for an HTTP response.
|
|
4
|
+
* `body` will be passed verbatim to `context.render()` (which JSON-stringifies).
|
|
5
|
+
* `status` and `message` go into ServerResponse.writeHead().
|
|
6
|
+
* `headers` are optional extra headers (e.g. Allow for 405, WWW-Authenticate for 401).
|
|
7
|
+
*/
|
|
8
|
+
export interface IErrorHttpResult {
|
|
9
|
+
status: number;
|
|
10
|
+
message: string;
|
|
11
|
+
body: unknown;
|
|
12
|
+
headers?: Record<string, string | number>;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Aide jointe au corps d'erreur — ce que le développeur doit faire, en clair.
|
|
16
|
+
*
|
|
17
|
+
* **Jamais en production**, et ce n'est pas une précaution de confort : une
|
|
18
|
+
* aide nomme la table et la colonne en cause, c'est-à-dire de la cartographie
|
|
19
|
+
* de schéma offerte à qui frappe la porte. Le même parti-pris que le message
|
|
20
|
+
* opaque des pannes 5xx.
|
|
21
|
+
*
|
|
22
|
+
* Le champ est ADDITIONNEL, sur le modèle de `fields` en validation : un client
|
|
23
|
+
* qui l'ignore lit le corps exactement comme avant.
|
|
24
|
+
*/
|
|
25
|
+
export interface IErrorHint {
|
|
26
|
+
/** Famille d'aide — un seul cas aujourd'hui, la base en retard sur le code. */
|
|
27
|
+
readonly kind: "schema-mismatch";
|
|
28
|
+
/** Le fait, en français, sans jargon de pilote. */
|
|
29
|
+
readonly message: string;
|
|
30
|
+
/** Les gestes possibles, du plus probable au moins probable. Copiables tels quels. */
|
|
31
|
+
readonly actions: readonly string[];
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Result of rendering an error for a WebSocket close frame.
|
|
35
|
+
* `code` MUST be a valid WS close code (1000-4999). RFC 6455 §7.4.
|
|
36
|
+
* `reason` is a UTF-8 string sent in the close frame (max 123 bytes).
|
|
37
|
+
*/
|
|
38
|
+
export interface IErrorWebsocketResult {
|
|
39
|
+
code: number;
|
|
40
|
+
reason: string;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Unified error rendering contract — HTTP + WebSocket.
|
|
44
|
+
* The default implementation preserves the legacy Nodefony JSON error shape:
|
|
45
|
+
* { code, message, error: HttpError.toJSON(), nodefony: { requestId, scheme, ... }, result }
|
|
46
|
+
*
|
|
47
|
+
* Override via `httpKernel.setErrorRenderer(custom)` to customise:
|
|
48
|
+
* - hide stack traces in prod
|
|
49
|
+
* - emit RFC 7807 problem+json
|
|
50
|
+
* - inject auth challenge headers
|
|
51
|
+
*/
|
|
52
|
+
export interface IErrorRenderer {
|
|
53
|
+
renderHttp(error: Error, context: IHttpContext): IErrorHttpResult;
|
|
54
|
+
renderWebsocket(error: Error, context: IWebsocketContext): IErrorWebsocketResult;
|
|
55
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { HttpConfig, HttpConfigInput } from "../config/config.js";
|
|
2
|
+
/**
|
|
3
|
+
* Configuration validée de `@nodefony/http` (sortie du parse Zod + défauts
|
|
4
|
+
* kernel appliqués par le builder). Source de vérité = `../config/config.ts`.
|
|
5
|
+
*/
|
|
6
|
+
export type IHttpConfig = HttpConfig;
|
|
7
|
+
/**
|
|
8
|
+
* Configuration brute fournie par l'application (toutes sections optionnelles —
|
|
9
|
+
* les sections omises reçoivent leurs défauts). Entrée du builder
|
|
10
|
+
* {@link import("../config/defineModuleConfig").defineHttpConfig}.
|
|
11
|
+
*/
|
|
12
|
+
export type IHttpConfigInput = HttpConfigInput;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ServerType } from "./IContext.js";
|
|
2
|
+
export interface IHttpKernel {
|
|
3
|
+
domain: string;
|
|
4
|
+
httpPort?: number;
|
|
5
|
+
httpsPort?: number;
|
|
6
|
+
handle(request: unknown, response: unknown, type: ServerType): Promise<unknown>;
|
|
7
|
+
handleFrontController(context: object, checkFirewall?: boolean): Promise<unknown>;
|
|
8
|
+
onError(error: unknown, context?: object, extraHeaders?: object): Promise<object>;
|
|
9
|
+
isValidDomain(context: object): boolean;
|
|
10
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { URL } from "node:url";
|
|
2
|
+
import type { ICookie } from "./ICookie.js";
|
|
3
|
+
export type HTTPMethodType = "GET" | "HEAD" | "POST" | "PUT" | "DELETE" | "CONNECT" | "OPTIONS" | "TRACE" | "PATCH" | "WEBSOCKET";
|
|
4
|
+
export interface IRequest {
|
|
5
|
+
url: URL | string;
|
|
6
|
+
method: HTTPMethodType | null | undefined;
|
|
7
|
+
getMethod(): HTTPMethodType | null | undefined;
|
|
8
|
+
getHeader(name: string): string | string[] | undefined;
|
|
9
|
+
getHeaders(): Record<string, string | string[] | undefined>;
|
|
10
|
+
}
|
|
11
|
+
export interface IHttpRequest extends IRequest {
|
|
12
|
+
url: URL;
|
|
13
|
+
query: Record<string, unknown>;
|
|
14
|
+
queryGet: Record<string, unknown>;
|
|
15
|
+
queryPost: Record<string, unknown>;
|
|
16
|
+
queryFile: unknown[];
|
|
17
|
+
remoteAddress: string | null | undefined;
|
|
18
|
+
acceptHtml: boolean;
|
|
19
|
+
getRemoteAddress(): string | null | undefined;
|
|
20
|
+
getHost(): string | undefined;
|
|
21
|
+
getHostName(): string | undefined;
|
|
22
|
+
getUserAgent(): string | undefined;
|
|
23
|
+
getOrigin(): string | undefined;
|
|
24
|
+
getCookies(): Record<string, ICookie>;
|
|
25
|
+
}
|
|
26
|
+
export interface IHttp2Request extends IHttpRequest {
|
|
27
|
+
stream: unknown;
|
|
28
|
+
}
|
|
29
|
+
export interface IWsRequest extends IRequest {
|
|
30
|
+
url: URL;
|
|
31
|
+
query: Record<string, string>;
|
|
32
|
+
queryGet: Record<string, string>;
|
|
33
|
+
path: string;
|
|
34
|
+
cookies?: Record<string, ICookie>;
|
|
35
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { Severity } from "nodefony";
|
|
2
|
+
import type { IHttpContext, IWebsocketContext } from "./IContext.js";
|
|
3
|
+
/**
|
|
4
|
+
* Result of rendering a request log entry. Returned by IRequestLogger and
|
|
5
|
+
* passed verbatim to `context.log(text, severity, msgid)`.
|
|
6
|
+
*/
|
|
7
|
+
export interface IRequestLogEntry {
|
|
8
|
+
text: string;
|
|
9
|
+
severity: Severity;
|
|
10
|
+
msgid: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Unified per-request logger contract — HTTP + WebSocket.
|
|
14
|
+
*
|
|
15
|
+
* The default implementation preserves the legacy Nodefony "URL : ... FROM : ...
|
|
16
|
+
* ORIGIN : ... ID : <uuid>" colored format. Swap via
|
|
17
|
+
* `httpKernel.setRequestLogger(custom)` to:
|
|
18
|
+
* - emit JSON access logs (audit / P3.1)
|
|
19
|
+
* - render NCSA Common Log Format
|
|
20
|
+
* - pretty-format with one colored line per request (P3.2)
|
|
21
|
+
*/
|
|
22
|
+
export interface IRequestLogger {
|
|
23
|
+
renderHttp(context: IHttpContext, error?: Error | null): IRequestLogEntry;
|
|
24
|
+
renderWebsocket(context: IWebsocketContext, error?: Error | null, acceptedProtocol?: string | null): IRequestLogEntry;
|
|
25
|
+
/**
|
|
26
|
+
* Optional audit-sampling gate, evaluated by `Context.logRequest()` BEFORE
|
|
27
|
+
* `renderHttp`. Return `false` to skip the log entirely (no object alloc, no
|
|
28
|
+
* `JSON.stringify`). Absent ⇒ always log (loggers without sampling).
|
|
29
|
+
*/
|
|
30
|
+
shouldSample?(context: IHttpContext, error?: Error | null): boolean;
|
|
31
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { ICookie } from "./ICookie.js";
|
|
2
|
+
export interface IResponse {
|
|
3
|
+
statusCode: number;
|
|
4
|
+
statusMessage: string;
|
|
5
|
+
encoding: BufferEncoding;
|
|
6
|
+
body: Buffer | null;
|
|
7
|
+
cookies: Record<string, ICookie>;
|
|
8
|
+
addCookie(cookie: ICookie): ICookie;
|
|
9
|
+
send(data?: Buffer | string | null, encoding?: BufferEncoding): Promise<unknown>;
|
|
10
|
+
clean(): void;
|
|
11
|
+
}
|
|
12
|
+
export interface IHttpResponse extends IResponse {
|
|
13
|
+
headers: Record<string, unknown>;
|
|
14
|
+
contentType: string;
|
|
15
|
+
setStatusCode(code: number | string, message?: string): {
|
|
16
|
+
code: number;
|
|
17
|
+
message: string;
|
|
18
|
+
};
|
|
19
|
+
getStatusCode(): number;
|
|
20
|
+
getStatusMessage(): string;
|
|
21
|
+
isHeaderSent(): boolean;
|
|
22
|
+
setHeader(name: string, value: string | number | string[]): void;
|
|
23
|
+
getHeader(name: string): string | number | string[] | undefined;
|
|
24
|
+
setHeaders(headers: Record<string, string | number>): void;
|
|
25
|
+
setContentType(type: string): void;
|
|
26
|
+
setBody(data: unknown): void;
|
|
27
|
+
redirect(url: string, code?: number): Promise<IHttpResponse>;
|
|
28
|
+
isHtml(): boolean;
|
|
29
|
+
setTimeout(ms: number): void;
|
|
30
|
+
deleteCookie(cookie: ICookie): void;
|
|
31
|
+
setCookie(cookie: ICookie): void;
|
|
32
|
+
}
|
|
33
|
+
export interface IWebsocketResponse extends IResponse {
|
|
34
|
+
connection: unknown | null;
|
|
35
|
+
webSocketVersion?: number;
|
|
36
|
+
setConnection(connection: unknown): unknown;
|
|
37
|
+
broadcast(data: Buffer | string): void;
|
|
38
|
+
close(code?: number, message?: string): Promise<void>;
|
|
39
|
+
}
|