@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,27 @@
|
|
|
1
|
+
import { HttpTerminator } from "http-terminator";
|
|
2
|
+
import type { Server as HttpServer } from "node:http";
|
|
3
|
+
import type { Server as HttpsServer } from "node:https";
|
|
4
|
+
import type { Http2SecureServer } from "node:http2";
|
|
5
|
+
/**
|
|
6
|
+
* Fabrique le terminator de drain graceful d'un serveur HTTP/HTTPS/HTTP2.
|
|
7
|
+
*
|
|
8
|
+
* Au `terminate()` (shutdown SIGTERM/docker stop) : les requêtes in-flight se
|
|
9
|
+
* terminent (header `connection: close` injecté sur les réponses en cours), les
|
|
10
|
+
* sockets idle sont fermées immédiatement, et tout ce qui reste après
|
|
11
|
+
* `shutdownTimeout` ms est détruit de force. Le terminator appelle lui-même
|
|
12
|
+
* `server.close()` — ne pas le rappeler derrière.
|
|
13
|
+
*
|
|
14
|
+
* ⚠️ Les sockets WebSocket upgradées (sans réponse HTTP en cours) sont détruites
|
|
15
|
+
* SANS frame Close par le terminator → les serveurs WS doivent fermer leurs
|
|
16
|
+
* clients (close 1001) AVANT ce drain. Garanti par l'ordre des listeners
|
|
17
|
+
* `onTerminate` : WS/WSS s'attachent en `prependOnceListener`, les serveurs
|
|
18
|
+
* HTTP en `once`.
|
|
19
|
+
*
|
|
20
|
+
* @param server - serveur Node à drainer (créé, pas forcément listening)
|
|
21
|
+
* @param shutdownTimeout - délai de drain en ms avant destruction forcée
|
|
22
|
+
* @returns le terminator à invoquer au shutdown
|
|
23
|
+
*/
|
|
24
|
+
export declare function createDrainTerminator(server: HttpServer | HttpsServer | Http2SecureServer, shutdownTimeout?: number): HttpTerminator;
|
|
25
|
+
/** Drain par défaut (ms) — même valeur que le défaut Zod `servers.*.shutdownTimeout`. */
|
|
26
|
+
export declare const DEFAULT_SHUTDOWN_TIMEOUT = 5000;
|
|
27
|
+
export type { HttpTerminator };
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import Ws, { WebSocketServer } from "ws";
|
|
2
|
+
/**
|
|
3
|
+
* Options keep-alive d'un serveur WebSocket.
|
|
4
|
+
*
|
|
5
|
+
* Héritées de l'ancienne lib `websocket` (theturtle32) qui les gérait nativement.
|
|
6
|
+
* `ws@8` n'a AUCUN keep-alive natif (il n'expose que `ping()`/`pong()` manuels) :
|
|
7
|
+
* on réimplémente donc la sémantique au-dessus de `ws` pour que ces knobs — déjà
|
|
8
|
+
* déclarés dans le schéma Zod — ne soient plus une config qui ment.
|
|
9
|
+
*/
|
|
10
|
+
export interface IWsHeartbeatOptions {
|
|
11
|
+
/** Intervalle (ms) entre deux pings. `0` ou absent → keep-alive désactivé. */
|
|
12
|
+
keepaliveInterval?: number;
|
|
13
|
+
/** Délai (ms) accordé pour recevoir le `pong` avant de couper la socket. */
|
|
14
|
+
keepaliveGracePeriod?: number;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Arme le suivi keep-alive d'UNE connexion : initialise l'horodatage de vie et
|
|
18
|
+
* attache l'unique listener `pong` qui le rafraîchit.
|
|
19
|
+
*
|
|
20
|
+
* Le listener `pong` vit et meurt avec la socket (l'émetteur EST la socket `ws`,
|
|
21
|
+
* détruite au `close`/`terminate`) → aucun `removeListener` explicite à prévoir.
|
|
22
|
+
* Un seul listener par connexion, c'est le pair-event obligatoire du ping.
|
|
23
|
+
*
|
|
24
|
+
* @param ws - la socket fraîchement connectée
|
|
25
|
+
*/
|
|
26
|
+
export declare const trackPong: (ws: Ws) => void;
|
|
27
|
+
/**
|
|
28
|
+
* Démarre le heartbeat keep-alive du serveur : détecte les connexions zombies
|
|
29
|
+
* (half-open — TCP encore ouvert mais le pair a disparu sans frame Close) et les
|
|
30
|
+
* `terminate()` pour libérer slot mémoire + descripteur de fichier.
|
|
31
|
+
*
|
|
32
|
+
* Sémantique (fidèle à l'ancienne lib `websocket`) : un ping est émis tous les
|
|
33
|
+
* `keepaliveInterval` ms ; si aucun `pong` n'arrive dans les `keepaliveGracePeriod`
|
|
34
|
+
* ms qui suivent ce ping, la socket est détruite. Temps de réclamation borné par
|
|
35
|
+
* `keepaliveInterval + keepaliveGracePeriod` (+ une granularité de tick).
|
|
36
|
+
*
|
|
37
|
+
* PERF (hot path WS) : **UN seul `setInterval` par serveur** — jamais un timer par
|
|
38
|
+
* connexion. Chaque tick ne lit/écrit que des `number` sur la socket → 0 allocation
|
|
39
|
+
* sur le chemin nominal. `unref()` pour ne pas retenir le process à l'arrêt. Le timer
|
|
40
|
+
* DOIT être `clearInterval` au shutdown (cf appelant).
|
|
41
|
+
*
|
|
42
|
+
* @param server - le `WebSocketServer` dont on surveille `clients`
|
|
43
|
+
* @param options - knobs keep-alive (depuis la config Zod du module)
|
|
44
|
+
* @returns le timer à nettoyer au shutdown, ou `null` si le keep-alive est désactivé
|
|
45
|
+
*/
|
|
46
|
+
export declare const startHeartbeat: (server: WebSocketServer, options: IWsHeartbeatOptions) => ReturnType<typeof setInterval> | null;
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import { Service, Module } from "nodefony";
|
|
2
|
+
import type { IPage } from "nodefony";
|
|
3
|
+
import type { ISessionStorage, ISessionSummary, ISessionRecord, ISessionListQuery } from "../../interfaces/ISession.js";
|
|
4
|
+
import HttpKernel, { ContextType } from "../http-kernel.js";
|
|
5
|
+
import Session, { OptionsSessionType } from "../../src/session/session.js";
|
|
6
|
+
import Certificate from "../../service/certificates.js";
|
|
7
|
+
import type { ISessionCounts } from "../../src/session/storage/sessionFilters.js";
|
|
8
|
+
export type sessionStrategyType = "none" | "migrate" | "invalidate";
|
|
9
|
+
export type FlashBagSessionType = Record<string, unknown>;
|
|
10
|
+
export type MetaBagSessionType = Record<string, unknown>;
|
|
11
|
+
/** Constructeur d'un storage de session (enregistré dans le registre). */
|
|
12
|
+
export type SessionStorageCtor = new (manager: SessionsService) => ISessionStorage;
|
|
13
|
+
/**
|
|
14
|
+
* Dérive le pseudonyme public d'une session — `HMAC-SHA256(secret, id)` tronqué,
|
|
15
|
+
* préfixé `sess_`. **Non réversible** : exposer ce `ref` ne révèle pas l'id de
|
|
16
|
+
* session (= le jeton du cookie). Fonction **pure** (testable sans instancier le
|
|
17
|
+
* service ni démarrer de serveur).
|
|
18
|
+
*/
|
|
19
|
+
export declare function computeSessionRef(secret: Buffer, id: string): string;
|
|
20
|
+
/**
|
|
21
|
+
* Projette une entrée brute {@link ISessionRecord} en {@link ISessionSummary}
|
|
22
|
+
* **redacté par construction** (allowlist) : jamais `Attributes`, jamais
|
|
23
|
+
* `flashBag`, jamais l'id brut — seulement le `ref` + des champs sûrs
|
|
24
|
+
* (`user`/`ip`/`ua`/dates). Fonction **pure** (cœur de la garantie anti-fuite,
|
|
25
|
+
* testée isolément).
|
|
26
|
+
*/
|
|
27
|
+
export declare function toSessionSummary(rec: ISessionRecord, ref: string, currentRef?: string | null): ISessionSummary;
|
|
28
|
+
declare class SessionsService extends Service {
|
|
29
|
+
httpKernel: HttpKernel;
|
|
30
|
+
/**
|
|
31
|
+
* Registre des storages de session — inversion de contrôle.
|
|
32
|
+
*
|
|
33
|
+
* Chaque module qui fournit un storage l'enregistre à son chargement
|
|
34
|
+
* (`SessionsService.registerStorage("drizzle", DrizzleStorage)`). Ainsi
|
|
35
|
+
* `@nodefony/http` **ne dépend d'aucun ORM** : pas d'import croisé, pas de
|
|
36
|
+
* cycle, et ajouter un driver ne touche plus ce fichier. Le handler de la
|
|
37
|
+
* config (`session.store`) sélectionne le storage par son nom.
|
|
38
|
+
*/
|
|
39
|
+
private static readonly storages;
|
|
40
|
+
/**
|
|
41
|
+
* Enregistre un storage de session sous un nom de store (insensible à la
|
|
42
|
+
* casse) et émet l'événement kernel `onRegisterSessionStorage` (observabilité
|
|
43
|
+
* Studio / extension). Le kernel peut être absent au tout premier chargement
|
|
44
|
+
* (registration statique) → fire gardé.
|
|
45
|
+
*/
|
|
46
|
+
static registerStorage(name: string, ctor: SessionStorageCtor): void;
|
|
47
|
+
/** Storage enregistré pour un store, ou `undefined`. */
|
|
48
|
+
static getStorage(name: string): SessionStorageCtor | undefined;
|
|
49
|
+
/** Noms des handlers de session enregistrés. */
|
|
50
|
+
static storageHandlers(): string[];
|
|
51
|
+
sessionStrategy: sessionStrategyType;
|
|
52
|
+
storage: ISessionStorage | null;
|
|
53
|
+
module: Module;
|
|
54
|
+
defaultSessionName: string;
|
|
55
|
+
secret?: Buffer;
|
|
56
|
+
iv?: Buffer;
|
|
57
|
+
certificates: Certificate | null;
|
|
58
|
+
private gcScheduler;
|
|
59
|
+
constructor(module: Module, httpKernel: HttpKernel);
|
|
60
|
+
init(): Promise<this>;
|
|
61
|
+
initializeStorage(): ISessionStorage | null;
|
|
62
|
+
createSecret(): Buffer;
|
|
63
|
+
createIv(): Buffer;
|
|
64
|
+
start(context: ContextType, readOnly?: boolean): Promise<Session | null>;
|
|
65
|
+
saveSession(context: ContextType): Promise<Session | null>;
|
|
66
|
+
createSession(name: string, options?: OptionsSessionType): Session;
|
|
67
|
+
setSessionStrategy(strategy: sessionStrategyType): void;
|
|
68
|
+
/**
|
|
69
|
+
* Une passe de purge du store (`storage.gc(idle, absolute)`) — point d'entrée
|
|
70
|
+
* public d'un ordonnanceur : le {@link GcScheduler} l'appelle, mais un futur
|
|
71
|
+
* worker cron (`session:gc` / k8s CronJob) peut l'appeler à sa place (poser
|
|
72
|
+
* alors `gcIntervalS:0`). L'anti-empilement et la capture d'erreur vivent dans
|
|
73
|
+
* le GcScheduler (via `onError`) — ici, la passe métier nue.
|
|
74
|
+
*/
|
|
75
|
+
runGc(): Promise<void>;
|
|
76
|
+
/**
|
|
77
|
+
* `true` si le backend de session courant sait s'énumérer **par pages**
|
|
78
|
+
* (`listPage`). Un store KV/edge sans scan retourne `false` → l'endpoint admin
|
|
79
|
+
* répond **501** (refus honnête, jamais une liste vide trompeuse).
|
|
80
|
+
*
|
|
81
|
+
* C'est bien `listPage` — et non `listAll` — qui fait foi : toute la surface
|
|
82
|
+
* d'administration (listing, révocation par référence, « déconnecter partout »)
|
|
83
|
+
* est bâtie sur la pagination, pour que son coût mémoire soit **indépendant du
|
|
84
|
+
* nombre de sessions**. Un store qui ne saurait que tout charger serait une
|
|
85
|
+
* régression déguisée en capacité.
|
|
86
|
+
*/
|
|
87
|
+
supportsEnumeration(): boolean;
|
|
88
|
+
/**
|
|
89
|
+
* Champs de tri que le backend de session **actuellement configuré** sait
|
|
90
|
+
* honorer, en vocabulaire public.
|
|
91
|
+
*
|
|
92
|
+
* La capacité se CONSTATE au runtime : la même application rend `["updatedAt",
|
|
93
|
+
* "id"]` sur SQLite et `[]` sur Redis (`SCAN` ne donne aucun ordre global).
|
|
94
|
+
* Le data plane transmet cette liste à `parsePageQuery`, qui **refuse** (400)
|
|
95
|
+
* un `order` qu'aucun store ne pourrait honorer — au lieu de rendre une page
|
|
96
|
+
* non triée en laissant croire le contraire.
|
|
97
|
+
*
|
|
98
|
+
* @returns les champs triables, liste vide si le backend ne trie pas.
|
|
99
|
+
*/
|
|
100
|
+
sortableFields(): readonly string[];
|
|
101
|
+
/**
|
|
102
|
+
* Dérive le pseudonyme public d'une session — `HMAC-SHA256(secret, id)` tronqué,
|
|
103
|
+
* préfixé `sess_`. **Non réversible** : exposer ce `ref` ne révèle pas l'id de
|
|
104
|
+
* session (= le jeton du cookie). Le secret HMAC = celui de la couche session
|
|
105
|
+
* (`this.secret`, dérivé de la clé du certificat au boot), jamais sérialisé.
|
|
106
|
+
*
|
|
107
|
+
* @throws Error si le secret n'est pas initialisé (service pas démarré) — capté
|
|
108
|
+
* en 503 côté endpoint plutôt que d'émettre un `ref` faible.
|
|
109
|
+
*/
|
|
110
|
+
sessionRef(id: string): string;
|
|
111
|
+
/**
|
|
112
|
+
* Énumère les sessions persistées en {@link ISessionSummary} **redactés** (jamais
|
|
113
|
+
* d'id brut ni d'`Attributes`), des plus récentes aux plus anciennes. Le filtre
|
|
114
|
+
* `user` est poussé au store (WHERE SQL) PUIS ré-appliqué ici (défense si un
|
|
115
|
+
* store l'ignore). Pré-condition : {@link supportsEnumeration} (sinon throw).
|
|
116
|
+
*/
|
|
117
|
+
/**
|
|
118
|
+
* Référence publique de la session qui porte la **requête en cours**, lue dans
|
|
119
|
+
* le contexte de l'ALS — ou `null` quand la requête n'en porte aucune (CLI,
|
|
120
|
+
* appel interne, session jamais démarrée).
|
|
121
|
+
*
|
|
122
|
+
* Point UNIQUE de cette dérivation : marquer « cet appareil » se fait ici, et
|
|
123
|
+
* les deux énumérations (admin et self-service) s'en servent — sans quoi
|
|
124
|
+
* chaque appelant recalculerait la règle et l'une des copies dériverait.
|
|
125
|
+
* Un HMAC par page d'administration, jamais sur le chemin nominal.
|
|
126
|
+
*/
|
|
127
|
+
currentSessionRef(): string | null;
|
|
128
|
+
listSessionsPage(query: ISessionListQuery): Promise<IPage<ISessionSummary>>;
|
|
129
|
+
/**
|
|
130
|
+
* Compte les sessions sans les énumérer (KPI de la console). Renvoie **`-1`**
|
|
131
|
+
* si le backend ne sait pas compter à coût raisonnable (Redis) — l'appelant
|
|
132
|
+
* affiche alors l'inconnu plutôt qu'un chiffre inventé.
|
|
133
|
+
*/
|
|
134
|
+
countSessions(query?: Partial<ISessionListQuery>): Promise<number>;
|
|
135
|
+
/**
|
|
136
|
+
* Compte les utilisateurs **distincts** ayant une session — le second nombre
|
|
137
|
+
* de la console, celui que `countSessions` ne dit pas (« 400 sessions » n'est
|
|
138
|
+
* pas « 400 personnes »).
|
|
139
|
+
*
|
|
140
|
+
* @returns le nombre d'utilisateurs distincts, ou **`-1`** si le backend ne
|
|
141
|
+
* sait pas agréger (Redis).
|
|
142
|
+
*/
|
|
143
|
+
countDistinctUsers(query?: Partial<ISessionListQuery>): Promise<number>;
|
|
144
|
+
/**
|
|
145
|
+
* Les compteurs de tête de la console — posés sur la collection ENTIÈRE, pas
|
|
146
|
+
* sur la page affichée.
|
|
147
|
+
*
|
|
148
|
+
* C'est la correction d'un mensonge d'affichage : les cartes étaient calculées
|
|
149
|
+
* dans le navigateur à partir des sessions chargées, donc bornées par la
|
|
150
|
+
* fenêtre du tableau. Elles décrivaient l'échantillon visible en ayant l'air
|
|
151
|
+
* de décrire le parc.
|
|
152
|
+
*
|
|
153
|
+
* Chaque compteur vaut `null` quand le backend ne sait pas répondre — la
|
|
154
|
+
* console affiche alors l'inconnu (« — ») plutôt qu'un zéro qui se lirait
|
|
155
|
+
* comme une absence.
|
|
156
|
+
*
|
|
157
|
+
* @param query - filtres à appliquer avant comptage (sans fenêtre).
|
|
158
|
+
*/
|
|
159
|
+
countSessionFacets(query?: Partial<ISessionListQuery>): Promise<ISessionCounts>;
|
|
160
|
+
/**
|
|
161
|
+
* Storage courant, garanti énumérable — factorise la pré-condition de toute la
|
|
162
|
+
* surface admin (une seule formulation de l'erreur, un seul point à faire
|
|
163
|
+
* évoluer).
|
|
164
|
+
*
|
|
165
|
+
* @throws Error si le storage est absent ou n'implémente pas `listPage`.
|
|
166
|
+
*/
|
|
167
|
+
private enumerable;
|
|
168
|
+
/**
|
|
169
|
+
* Parcourt les sessions **page par page**, en ne gardant JAMAIS plus d'une page
|
|
170
|
+
* en mémoire — le cœur de la gouvernance bornée : retrouver une session par sa
|
|
171
|
+
* référence publique impose de recalculer un HMAC sur chaque id, mais pas de
|
|
172
|
+
* charger le parc entier pour le faire.
|
|
173
|
+
*
|
|
174
|
+
* Gère les deux modes du contrat de façon transparente pour l'appelant :
|
|
175
|
+
* curseur (`nextCursor` du store) ou offset (avance de `SCAN_PAGE`). Le visiteur
|
|
176
|
+
* renvoie `true` pour **arrêter** le parcours (court-circuit dès le match).
|
|
177
|
+
*
|
|
178
|
+
* @param filter - restriction poussée au store (ex. `user`).
|
|
179
|
+
* @param visit - appelé pour chaque record ; `true` = stop.
|
|
180
|
+
* @returns `true` si le parcours a été arrêté par le visiteur.
|
|
181
|
+
*/
|
|
182
|
+
private eachSessionRecord;
|
|
183
|
+
/**
|
|
184
|
+
* Révoque une session par son `ref` public : re-scanne, recalcule le HMAC de
|
|
185
|
+
* chaque id pour retrouver l'id réel (l'id brut ne quitte jamais le process),
|
|
186
|
+
* puis `destroy()`. `ref` étant public (pas un secret), la comparaison directe
|
|
187
|
+
* est sûre. Idempotent — `false` si aucun `ref` ne correspond.
|
|
188
|
+
*/
|
|
189
|
+
destroyByRef(ref: string, actor?: string | null): Promise<boolean>;
|
|
190
|
+
/**
|
|
191
|
+
* « Déconnexion partout » : détruit TOUTES les sessions d'un utilisateur (scan
|
|
192
|
+
* O(N) — pas d'index inverse, acceptable en admin). Renvoie le nombre détruit.
|
|
193
|
+
*/
|
|
194
|
+
destroyByUser(identifier: string, actor?: string | null): Promise<number>;
|
|
195
|
+
/**
|
|
196
|
+
* Énumère **une page** des sessions APPARTENANT à `identifier`
|
|
197
|
+
* ({@link ISessionSummary} redactés). Délègue à {@link listSessionsPage} avec le
|
|
198
|
+
* filtre `user` (poussé au store PUIS ré-appliqué — défense en profondeur). Un
|
|
199
|
+
* `identifier` vide renvoie une page vide (jamais les sessions anonymes
|
|
200
|
+
* `user===""`, qui appartiennent à tout le monde et donc à personne).
|
|
201
|
+
*/
|
|
202
|
+
listOwnSessionsPage(identifier: string, query: ISessionListQuery): Promise<IPage<ISessionSummary>>;
|
|
203
|
+
/**
|
|
204
|
+
* Révoque UNE session **possédée par `identifier`**, désignée par son `ref`
|
|
205
|
+
* public. Contrairement à {@link destroyByRef} (admin, scan GLOBAL), le scan est
|
|
206
|
+
* RESTREINT aux sessions de `identifier` (+ re-check d'appartenance) : un `ref`
|
|
207
|
+
* qui ne lui appartient pas est introuvable → `false`, ce qui ferme l'IDOR.
|
|
208
|
+
* Idempotent. Audité (`self: true`, acteur = le propriétaire).
|
|
209
|
+
*/
|
|
210
|
+
destroyOwnByRef(identifier: string, ref: string, actor?: string | null): Promise<boolean>;
|
|
211
|
+
/**
|
|
212
|
+
* Émet un événement dans le journal d'audit de `@nodefony/security` s'il est
|
|
213
|
+
* monté (résolu par nom au runtime) — **no-op** si security est absent/désactivé.
|
|
214
|
+
* L'action de révocation reste tracée par `this.log()` dans tous les cas.
|
|
215
|
+
*/
|
|
216
|
+
private emitAudit;
|
|
217
|
+
}
|
|
218
|
+
export default SessionsService;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* W3C Trace Context — parse + generate `traceparent` headers (P2.7).
|
|
3
|
+
*
|
|
4
|
+
* Spec: https://www.w3.org/TR/trace-context/
|
|
5
|
+
* Format: `<version>-<traceId>-<parentId>-<flags>`
|
|
6
|
+
* - version: 2 hex chars (currently always `00`; `ff` is reserved/invalid)
|
|
7
|
+
* - traceId: 32 hex chars (16 bytes), non-zero
|
|
8
|
+
* - parentId / spanId: 16 hex chars (8 bytes), non-zero
|
|
9
|
+
* - flags: 2 hex chars (`01` = sampled)
|
|
10
|
+
*
|
|
11
|
+
* Behaviour at the request boundary:
|
|
12
|
+
* - Valid incoming traceparent → keep `version`/`traceId`/`flags`, generate
|
|
13
|
+
* a fresh `parentId` (we are a child span in the existing trace).
|
|
14
|
+
* - Missing or invalid → mint a brand-new traceparent (version `00`,
|
|
15
|
+
* `flags=01` sampled by default).
|
|
16
|
+
*
|
|
17
|
+
* The result is propagated through {@link RequestContext} and echoed on the
|
|
18
|
+
* HTTP response so downstream services and clients can stitch the trace.
|
|
19
|
+
*/
|
|
20
|
+
export interface ParsedTraceparent {
|
|
21
|
+
version: string;
|
|
22
|
+
traceId: string;
|
|
23
|
+
parentId: string;
|
|
24
|
+
flags: string;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Parse a `traceparent` header value. Returns `null` when the header is
|
|
28
|
+
* missing, malformed, or carries an all-zero traceId/spanId (per W3C the
|
|
29
|
+
* recipient MUST NOT propagate such values).
|
|
30
|
+
*/
|
|
31
|
+
export declare function parseTraceparent(header: string | undefined | null): ParsedTraceparent | null;
|
|
32
|
+
/**
|
|
33
|
+
* Resolve the traceparent to attach to a new request. Honors an incoming
|
|
34
|
+
* valid header, generates a fresh one otherwise.
|
|
35
|
+
*
|
|
36
|
+
* @param header - raw value read from `request.headers.traceparent`
|
|
37
|
+
* @returns the traceparent string to propagate (always well-formed)
|
|
38
|
+
*/
|
|
39
|
+
export declare function resolveTraceparent(header: string | undefined | null): string;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { Service, FileClass, Severity, Msgid, Pdu, Message, Pci, Module } from "nodefony";
|
|
2
|
+
import HttpKernel from "../http-kernel.js";
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import type { IParsedUploadFile } from "../../interfaces/IUpload.js";
|
|
5
|
+
export declare class upload extends Service {
|
|
6
|
+
httpKernel: HttpKernel;
|
|
7
|
+
path?: string | fs.PathLike;
|
|
8
|
+
module: Module;
|
|
9
|
+
constructor(module: Module, httpKernel: HttpKernel);
|
|
10
|
+
/**
|
|
11
|
+
* Construit un `UploadedFile` à partir d'un fichier multipart parsé —
|
|
12
|
+
* **async, non bloquant** (stat via `fsp.lstat`, plus de `lstatSync` par
|
|
13
|
+
* fichier uploadé).
|
|
14
|
+
*
|
|
15
|
+
* @param file - fichier parsé (forme neutre `IParsedUploadFile`, busboy).
|
|
16
|
+
* @param name - nom de champ (fallback si pas de `originalFilename`).
|
|
17
|
+
* @returns le `UploadedFile` hydraté.
|
|
18
|
+
*/
|
|
19
|
+
createUploadFile(file: IParsedUploadFile, name: string): Promise<UploadedFile>;
|
|
20
|
+
log(pci: Pci, severity?: Severity, msgid?: Msgid, msg?: Message): Pdu;
|
|
21
|
+
}
|
|
22
|
+
declare class UploadedFile extends FileClass {
|
|
23
|
+
#private;
|
|
24
|
+
parsedFile: IParsedUploadFile;
|
|
25
|
+
size: number;
|
|
26
|
+
prettySize: string;
|
|
27
|
+
filename: string;
|
|
28
|
+
lastModifiedDate: Date | null | undefined;
|
|
29
|
+
hashAlgorithm: false | "sha1" | "md5" | "sha256";
|
|
30
|
+
hash: string | null | undefined;
|
|
31
|
+
constructor(parsedFile: IParsedUploadFile, name: string, options?: {
|
|
32
|
+
defer?: boolean;
|
|
33
|
+
});
|
|
34
|
+
/**
|
|
35
|
+
* Construit un `UploadedFile` SANS `lstatSync` bloquant — stat résolu en async
|
|
36
|
+
* (`FileClass.stat`). À utiliser dans le pipeline d'upload (per-request).
|
|
37
|
+
*
|
|
38
|
+
* @param parsedFile - fichier multipart parsé (forme neutre busboy).
|
|
39
|
+
* @param name - nom de champ (fallback de nom).
|
|
40
|
+
* @returns le `UploadedFile` hydraté (stats async).
|
|
41
|
+
* @remarks Nommée `create` (pas `from`) pour ne pas entrer en conflit avec la
|
|
42
|
+
* signature statique de `FileClass.from(path)` (TS2417).
|
|
43
|
+
*/
|
|
44
|
+
static create(parsedFile: IParsedUploadFile, name: string): Promise<UploadedFile>;
|
|
45
|
+
getSize(): number;
|
|
46
|
+
getPrettySize(): string;
|
|
47
|
+
realName(name?: string): string;
|
|
48
|
+
getMimeType(): string | false;
|
|
49
|
+
move(target: string): FileClass;
|
|
50
|
+
/**
|
|
51
|
+
* Variante **async** de `move()` — déplace le fichier uploadé sans bloquer
|
|
52
|
+
* l'event-loop (`fsp.access`/`fsp.rename` via `FileClass.moveAsync`).
|
|
53
|
+
* À préférer dans le pipeline (controller).
|
|
54
|
+
*
|
|
55
|
+
* @param target - destination (fichier ou dossier existant).
|
|
56
|
+
* @returns nouvelle instance `FileClass` (hydratée async) sur la destination.
|
|
57
|
+
*/
|
|
58
|
+
moveAsync(target: fs.PathLike): Promise<FileClass>;
|
|
59
|
+
}
|
|
60
|
+
export default upload;
|
|
61
|
+
export { UploadedFile };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Une source d'assets statiques : un dossier servi sous un préfixe d'URL.
|
|
3
|
+
* Provient soit des montages natifs `server-static.mounts` (publics de module),
|
|
4
|
+
* soit des bundles `@nodefony/frontend` (`publicPath` → `outDir` buildé).
|
|
5
|
+
*/
|
|
6
|
+
export interface AssetSource {
|
|
7
|
+
/** Préfixe d'URL public (ex. `/_assets/studio/`, `/test/`). */
|
|
8
|
+
prefix: string;
|
|
9
|
+
/** Dossier ABSOLU servi sous ce préfixe. */
|
|
10
|
+
dir: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Une entrée du plan de publication : copier `dir` → `target` (sous-arbre de
|
|
14
|
+
* `outDir` miroir du préfixe d'URL), servi à terme par le CDN sous `prefix`.
|
|
15
|
+
*/
|
|
16
|
+
export interface AssetPlanEntry {
|
|
17
|
+
prefix: string;
|
|
18
|
+
dir: string;
|
|
19
|
+
/** Dossier de destination ABSOLU dans l'arbre `outDir`. */
|
|
20
|
+
target: string;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Construit le plan de publication des assets : pour chaque source unique
|
|
24
|
+
* (dédupliquée par préfixe — le DERNIER gagne, comme `addMount`), calcule le
|
|
25
|
+
* dossier cible `outDir/<préfixe-en-chemin>` miroir de l'URL.
|
|
26
|
+
*
|
|
27
|
+
* PUR (0 I/O) → testable. La copie réelle + le manifeste sont faits par la
|
|
28
|
+
* commande `assets:publish`. L'upload (S3/CDN/rsync) reste à l'orchestrateur :
|
|
29
|
+
* Nodefony assemble l'arbre, le déploiement le pousse (cloud-native).
|
|
30
|
+
*
|
|
31
|
+
* @param sources dossiers + préfixes (mounts natifs + bundles frontend)
|
|
32
|
+
* @param outDir racine ABSOLUE de l'arbre de sortie (ex. `<root>/dist-assets`)
|
|
33
|
+
* @returns plan ordonné, 1 entrée par préfixe unique
|
|
34
|
+
*/
|
|
35
|
+
export declare function planAssetPublish(sources: ReadonlyArray<AssetSource>, outDir: string): AssetPlanEntry[];
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Molette de livraison de l'UI embarquée d'un module (`ui` dans sa config).
|
|
3
|
+
* - `auto` : Vite si possible (dev + sources + @nodefony/frontend), sinon statique.
|
|
4
|
+
* - `static` : force les assets pré-buildés shippés dans le paquet npm.
|
|
5
|
+
* - `vite` : force le dev-server Vite (repo self-hosted / contrib).
|
|
6
|
+
*/
|
|
7
|
+
export type UiDeliveryMode = "auto" | "static" | "vite";
|
|
8
|
+
/** Mode effectivement résolu — `none` = UI indisponible (fail-loud à l'appelant). */
|
|
9
|
+
export type UiDeliveryResolved = "vite" | "static" | "none";
|
|
10
|
+
/** Résultat de {@link resolveUiDelivery} : mode effectif + raison LOGGABLE. */
|
|
11
|
+
export interface IUiDeliveryResolution {
|
|
12
|
+
mode: UiDeliveryResolved;
|
|
13
|
+
/** Pourquoi ce mode (toujours renseigné) — à logger tel quel par le module. */
|
|
14
|
+
reason: string;
|
|
15
|
+
}
|
|
16
|
+
/** Entrées de {@link resolveUiDelivery}. */
|
|
17
|
+
export interface IUiDeliveryOptions {
|
|
18
|
+
/** Molette demandée par la config du module (défaut `auto`). */
|
|
19
|
+
requested?: UiDeliveryMode;
|
|
20
|
+
/** `kernel.environment` (`development`, `production`, …). */
|
|
21
|
+
environment: string | undefined;
|
|
22
|
+
/** Le service `frontend` (@nodefony/frontend) est-il présent dans le container ? */
|
|
23
|
+
hasFrontendService: boolean;
|
|
24
|
+
/** Dossier des SOURCES front du module (ex. `<module>/frontend/src`). */
|
|
25
|
+
sourcesDir: string;
|
|
26
|
+
/** Chemin de l'index pré-buildé shippé npm (ex. `<module>/dist/frontend/index.html`). */
|
|
27
|
+
distIndex: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Résout le mode de livraison de l'UI embarquée d'un module.
|
|
31
|
+
*
|
|
32
|
+
* Pattern universel des admin-UI embarquées (bull-board, GraphiQL, profiler
|
|
33
|
+
* Symfony) : le consommateur ne compile JAMAIS l'UI d'un module tiers — les
|
|
34
|
+
* assets sont pré-buildés au publish et servis statiques. Le mode `vite`
|
|
35
|
+
* (HMR) n'a de sens que là où les sources existent (repo self-hosted, `--link`).
|
|
36
|
+
*
|
|
37
|
+
* PUR hormis deux `existsSync` (boot uniquement, jamais dans le hot path).
|
|
38
|
+
*
|
|
39
|
+
* @returns le mode effectif + la raison à logger (fail-loud si `none`)
|
|
40
|
+
*/
|
|
41
|
+
export declare function resolveUiDelivery(opts: IUiDeliveryOptions): IUiDeliveryResolution;
|
|
42
|
+
/** Vue minimale du Container (résolution par nom uniquement). */
|
|
43
|
+
interface IContainerView {
|
|
44
|
+
get?(name: string): unknown;
|
|
45
|
+
}
|
|
46
|
+
/** Vue minimale du Kernel (retry du mount si `server-static` pas encore créé). */
|
|
47
|
+
interface IKernelView {
|
|
48
|
+
once(event: "onReady", cb: () => void): unknown;
|
|
49
|
+
}
|
|
50
|
+
/** Options de {@link PrebuiltUi}. */
|
|
51
|
+
export interface IPrebuiltUiOptions {
|
|
52
|
+
/** Préfixe public des assets (ex. `/_assets/studio/`) — normalisé `/x/`. */
|
|
53
|
+
publicPath: string;
|
|
54
|
+
/** Dossier ABSOLU des assets pré-buildés (ex. `<module>/dist/frontend`). */
|
|
55
|
+
distDir: string;
|
|
56
|
+
/** Nom de l'index dans `distDir` (défaut `index.html`). */
|
|
57
|
+
indexFile?: string;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Livraison STATIQUE de l'UI pré-buildée d'un module (mode `static`).
|
|
61
|
+
*
|
|
62
|
+
* Deux responsabilités, zéro dépendance à @nodefony/frontend :
|
|
63
|
+
* 1. {@link mount} — sert `distDir` sous `publicPath` via `server-static`
|
|
64
|
+
* (assets hashés immuables produits par `vite build` au publish).
|
|
65
|
+
* 2. {@link renderIndex} — document HTML d'entrée (l'`index.html` transformé
|
|
66
|
+
* par Vite, tags déjà réécrits vers `publicPath`), nonce CSP injecté par
|
|
67
|
+
* requête. Le SPA fallback reste au controller du module (routes littérales,
|
|
68
|
+
* cf. StudioController).
|
|
69
|
+
*
|
|
70
|
+
* Perf : l'index est lu UNE fois (lazy, caché) ; seule l'injection du nonce
|
|
71
|
+
* coûte un `replaceAll` par rendu — route d'entrée UI, jamais un hot path.
|
|
72
|
+
*/
|
|
73
|
+
export declare class PrebuiltUi {
|
|
74
|
+
readonly publicPath: string;
|
|
75
|
+
readonly distDir: string;
|
|
76
|
+
private readonly indexPath;
|
|
77
|
+
/** Template HTML caché — `null` tant que non lu (lazy). */
|
|
78
|
+
private template;
|
|
79
|
+
constructor(opts: IPrebuiltUiOptions);
|
|
80
|
+
/**
|
|
81
|
+
* Monte `distDir` sous `publicPath` auprès de `server-static` (résolu par
|
|
82
|
+
* nom). Si le service n'existe pas encore (module chargé avant http), un
|
|
83
|
+
* retry unique est armé sur `onReady`.
|
|
84
|
+
*
|
|
85
|
+
* @returns `true` si monté immédiatement, `false` si différé/indisponible
|
|
86
|
+
* (l'appelant loggue — ce helper n'a pas de logger)
|
|
87
|
+
*/
|
|
88
|
+
mount(container: IContainerView | null | undefined, kernel?: IKernelView | null): boolean;
|
|
89
|
+
/**
|
|
90
|
+
* Document HTML d'entrée de l'UI (index pré-buildé par Vite).
|
|
91
|
+
*
|
|
92
|
+
* @param nonce nonce CSP de la requête (`Context.cspNonce`) — injecté sur
|
|
93
|
+
* chaque `<script>` ; les assets `src` same-origin passent déjà
|
|
94
|
+
* par `'self'`, le nonce couvre un éventuel inline Vite.
|
|
95
|
+
* @returns le HTML, ou un commentaire HTML fail-loud si l'index est absent
|
|
96
|
+
*/
|
|
97
|
+
renderIndex(nonce?: string): string;
|
|
98
|
+
}
|
|
99
|
+
export {};
|