@nodefony/http 10.0.0-beta.3 → 10.0.0-beta.5

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.
Files changed (138) hide show
  1. package/dist/_virtual/{_@oxc-project_runtime@0.153.0 → _@oxc-project_runtime@0.155.0}/helpers/esm/decorate.js +1 -2
  2. package/dist/_virtual/{_@oxc-project_runtime@0.153.0 → _@oxc-project_runtime@0.155.0}/helpers/esm/decorateParam.js +1 -2
  3. package/dist/index.js +13 -10
  4. package/dist/nodefony/command/assetsPublishCommand.js +5 -3
  5. package/dist/nodefony/command/certificatesCommand.js +5 -3
  6. package/dist/nodefony/command/networkCommand.js +5 -3
  7. package/dist/nodefony/command/proxyGenerateCommand.js +8 -3
  8. package/dist/nodefony/config/config.js +3 -3
  9. package/dist/nodefony/config/defineModuleConfig.js +1 -2
  10. package/dist/nodefony/interfaces/IRequestTrace.js +1 -0
  11. package/dist/nodefony/service/HttpAdminApi.js +2 -2
  12. package/dist/nodefony/service/ProfilerAdminApi.js +13 -3
  13. package/dist/nodefony/service/audit-logger.js +23 -30
  14. package/dist/nodefony/service/certificates.js +97 -13
  15. package/dist/nodefony/service/error-renderer.js +29 -12
  16. package/dist/nodefony/service/http-kernel.js +198 -50
  17. package/dist/nodefony/service/pretty-request-logger.js +15 -13
  18. package/dist/nodefony/service/request-logger.js +24 -16
  19. package/dist/nodefony/service/reverse-proxy.js +3 -3
  20. package/dist/nodefony/service/servers/clientError.js +22 -3
  21. package/dist/nodefony/service/servers/server-h2c.js +126 -0
  22. package/dist/nodefony/service/servers/server-http.js +5 -8
  23. package/dist/nodefony/service/servers/server-https.js +12 -24
  24. package/dist/nodefony/service/servers/server-static.js +3 -3
  25. package/dist/nodefony/service/servers/server-websocket-secure.js +10 -18
  26. package/dist/nodefony/service/servers/server-websocket.js +10 -18
  27. package/dist/nodefony/service/servers/serverShutdown.js +78 -18
  28. package/dist/nodefony/service/servers/wsHeartbeat.js +1 -2
  29. package/dist/nodefony/service/sessions/sessions-service.js +7 -14
  30. package/dist/nodefony/service/trace.js +1 -2
  31. package/dist/nodefony/service/upload/upload-service.js +5 -8
  32. package/dist/nodefony/service/x509.js +1 -2
  33. package/dist/nodefony/src/assets/collectAssets.js +1 -2
  34. package/dist/nodefony/src/assets/prebuiltUi.js +1 -2
  35. package/dist/nodefony/src/context/Context.js +78 -43
  36. package/dist/nodefony/src/context/domainMatcher.js +1 -2
  37. package/dist/nodefony/src/context/forwarded.js +1 -2
  38. package/dist/nodefony/src/context/http/HttpContext.js +28 -6
  39. package/dist/nodefony/src/context/http/Request.js +33 -29
  40. package/dist/nodefony/src/context/http/Response.js +23 -6
  41. package/dist/nodefony/src/context/http/SseStream.js +1 -2
  42. package/dist/nodefony/src/context/http/parser.js +36 -10
  43. package/dist/nodefony/src/context/http/urlFastPath.js +1 -2
  44. package/dist/nodefony/src/context/http2/Request.js +4 -8
  45. package/dist/nodefony/src/context/http2/Response.js +41 -9
  46. package/dist/nodefony/src/context/metaData.js +1 -2
  47. package/dist/nodefony/src/context/requestId.js +1 -2
  48. package/dist/nodefony/src/context/requestTrace.js +104 -0
  49. package/dist/nodefony/src/context/responseEnded.js +1 -2
  50. package/dist/nodefony/src/context/timingMode.js +21 -0
  51. package/dist/nodefony/src/context/transport.js +45 -0
  52. package/dist/nodefony/src/context/trustProxy.js +1 -2
  53. package/dist/nodefony/src/context/unsentResponse.js +30 -0
  54. package/dist/nodefony/src/context/websocket/Response.js +33 -6
  55. package/dist/nodefony/src/context/websocket/WebsocketContext.js +104 -25
  56. package/dist/nodefony/src/context/websocket/isWebsocketContext.js +17 -0
  57. package/dist/nodefony/src/context/websocket/websocketUrl.js +1 -2
  58. package/dist/nodefony/src/context/websocket/wsBackpressure.js +1 -2
  59. package/dist/nodefony/src/context/websocket/wsCloseReason.js +1 -2
  60. package/dist/nodefony/src/context/websocket/wsLogContent.js +1 -2
  61. package/dist/nodefony/src/cookies/cookie.js +3 -7
  62. package/dist/nodefony/src/errors/httpError.js +1 -2
  63. package/dist/nodefony/src/errors/thrownMessage.js +1 -2
  64. package/dist/nodefony/src/profiler/FrameProfile.js +23 -2
  65. package/dist/nodefony/src/profiler/Profiler.js +104 -32
  66. package/dist/nodefony/src/profiler/aggregate.js +442 -0
  67. package/dist/nodefony/src/proxy/forward.js +29 -5
  68. package/dist/nodefony/src/proxy/generateProxyConfig.js +14 -6
  69. package/dist/nodefony/src/proxy/rules.js +12 -6
  70. package/dist/nodefony/src/rateLimit/MemoryRateLimitStore.js +1 -2
  71. package/dist/nodefony/src/rateLimit/WsConnectionCounter.js +1 -2
  72. package/dist/nodefony/src/rateLimit/rateLimitFilters.js +1 -2
  73. package/dist/nodefony/src/servers/http2Limits.js +50 -0
  74. package/dist/nodefony/src/servers/kernelServers.js +12 -3
  75. package/dist/nodefony/src/servers/portBinder.js +41 -10
  76. package/dist/nodefony/src/servers/upgradeDispatch.js +86 -7
  77. package/dist/nodefony/src/session/session.js +2 -3
  78. package/dist/nodefony/src/session/sessionStoreFailure.js +1 -2
  79. package/dist/nodefony/src/session/storage/MemorySessionStorage.js +1 -2
  80. package/dist/nodefony/src/session/storage/RevocationGuardStorage.js +1 -2
  81. package/dist/nodefony/src/session/storage/sessionFilters.js +1 -2
  82. package/dist/nodefony/src/session/storage/sessionSort.js +1 -2
  83. package/dist/types/index.d.ts +9 -3
  84. package/dist/types/nodefony/config/config.d.ts +4 -0
  85. package/dist/types/nodefony/interfaces/IContext.d.ts +72 -4
  86. package/dist/types/nodefony/interfaces/IRequest.d.ts +9 -4
  87. package/dist/types/nodefony/interfaces/IRequestTrace.d.ts +56 -0
  88. package/dist/types/nodefony/interfaces/IReverseProxy.d.ts +8 -0
  89. package/dist/types/nodefony/interfaces/IRouting.d.ts +26 -0
  90. package/dist/types/nodefony/interfaces/index.d.ts +3 -2
  91. package/dist/types/nodefony/service/ProfilerAdminApi.d.ts +3 -0
  92. package/dist/types/nodefony/service/audit-logger.d.ts +3 -11
  93. package/dist/types/nodefony/service/certificates.d.ts +55 -4
  94. package/dist/types/nodefony/service/error-renderer.d.ts +31 -0
  95. package/dist/types/nodefony/service/http-kernel.d.ts +96 -10
  96. package/dist/types/nodefony/service/servers/clientError.d.ts +16 -0
  97. package/dist/types/nodefony/service/servers/server-h2c.d.ts +51 -0
  98. package/dist/types/nodefony/service/servers/server-http.d.ts +3 -3
  99. package/dist/types/nodefony/service/servers/server-https.d.ts +4 -4
  100. package/dist/types/nodefony/service/servers/server-websocket-secure.d.ts +1 -3
  101. package/dist/types/nodefony/service/servers/server-websocket.d.ts +1 -3
  102. package/dist/types/nodefony/service/servers/serverShutdown.d.ts +30 -16
  103. package/dist/types/nodefony/src/context/Context.d.ts +38 -5
  104. package/dist/types/nodefony/src/context/http/HttpContext.d.ts +16 -2
  105. package/dist/types/nodefony/src/context/http/Request.d.ts +20 -15
  106. package/dist/types/nodefony/src/context/http/Response.d.ts +11 -0
  107. package/dist/types/nodefony/src/context/http/parser.d.ts +18 -2
  108. package/dist/types/nodefony/src/context/http2/Request.d.ts +1 -1
  109. package/dist/types/nodefony/src/context/http2/Response.d.ts +27 -5
  110. package/dist/types/nodefony/src/context/requestTrace.d.ts +64 -0
  111. package/dist/types/nodefony/src/context/timingMode.d.ts +23 -0
  112. package/dist/types/nodefony/src/context/transport.d.ts +53 -0
  113. package/dist/types/nodefony/src/context/unsentResponse.d.ts +16 -0
  114. package/dist/types/nodefony/src/context/websocket/Response.d.ts +18 -2
  115. package/dist/types/nodefony/src/context/websocket/WebsocketContext.d.ts +58 -8
  116. package/dist/types/nodefony/src/context/websocket/isWebsocketContext.d.ts +15 -0
  117. package/dist/types/nodefony/src/profiler/FrameProfile.d.ts +28 -12
  118. package/dist/types/nodefony/src/profiler/Profiler.d.ts +79 -111
  119. package/dist/types/nodefony/src/profiler/aggregate.d.ts +132 -0
  120. package/dist/types/nodefony/src/proxy/forward.d.ts +14 -2
  121. package/dist/types/nodefony/src/proxy/generateProxyConfig.d.ts +16 -0
  122. package/dist/types/nodefony/src/proxy/rules.d.ts +3 -0
  123. package/dist/types/nodefony/src/servers/http2Limits.d.ts +37 -0
  124. package/dist/types/nodefony/src/servers/kernelServers.d.ts +10 -1
  125. package/dist/types/nodefony/src/servers/portBinder.d.ts +29 -5
  126. package/dist/types/nodefony/src/servers/upgradeDispatch.d.ts +33 -3
  127. package/docs/cookies.md +85 -78
  128. package/docs/diagnostics-channel.md +303 -0
  129. package/docs/index.md +6 -1
  130. package/docs/observabilite.md +159 -81
  131. package/docs/rate-limit.md +83 -83
  132. package/docs/reverse-proxy.md +72 -70
  133. package/docs/servers.md +338 -224
  134. package/docs/session.md +179 -179
  135. package/docs/sse.md +24 -20
  136. package/docs/upload.md +120 -117
  137. package/package.json +8 -9
  138. package/dist/_virtual/_@oxc-project_runtime@0.153.0/helpers/esm/decorateMetadata.js +0 -6
@@ -1,4 +1,4 @@
1
- //#region nodefony/src/servers/kernelServers.ts
1
+ // nodefony/src/servers/kernelServers.ts
2
2
  /**
3
3
  * Rétrécit la section `servers` de la configuration du kernel (lue dans le sac
4
4
  * de config non typé du cœur) en {@link ServersConfig}, sans propager `any`.
@@ -13,6 +13,15 @@ function asServersConfig(servers) {
13
13
  return servers !== null && typeof servers === "object" ? servers : void 0;
14
14
  }
15
15
  /**
16
+ * Le serveur h2c démarre-t-il ? Seul un `enabled: true` EXPLICITE l'allume : la
17
+ * section existe toujours (défauts), un port seul ne vaut pas activation.
18
+ *
19
+ * @param entry - `servers.h2c`.
20
+ */
21
+ function isH2cEnabled(entry) {
22
+ return entry?.enabled === true;
23
+ }
24
+ /**
16
25
  * Port DEMANDÉ pour un serveur (`servers.<type>.port`), ou `undefined` si le
17
26
  * serveur est désactivé, absent, ou sans port numérique.
18
27
  *
@@ -22,8 +31,8 @@ function asServersConfig(servers) {
22
31
  function configuredServerPort(servers, type) {
23
32
  const entry = servers?.[type];
24
33
  if (!entry) return void 0;
34
+ if (type === "h2c" && !isH2cEnabled(servers.h2c)) return void 0;
25
35
  const port = entry.port;
26
36
  return typeof port === "number" ? port : void 0;
27
37
  }
28
- //#endregion
29
- export { asServersConfig, configuredServerPort };
38
+ export { asServersConfig, configuredServerPort, isH2cEnabled };
@@ -1,6 +1,7 @@
1
+ import { isH2cEnabled } from "./kernelServers.js";
1
2
  import { isPortListening, resolvePortPolicy } from "nodefony";
2
3
  import cluster from "node:cluster";
3
- //#region nodefony/src/servers/portBinder.ts
4
+ // nodefony/src/servers/portBinder.ts
4
5
  /**
5
6
  * **portBinder** — écoute sur le port désiré, ou sur le prochain port libre.
6
7
  *
@@ -48,27 +49,58 @@ import cluster from "node:cluster";
48
49
  */
49
50
  /** Nombre de ports essayés après le désiré, en `auto`. */
50
51
  const DEFAULT_PORT_RETRY_ATTEMPTS = 20;
52
+ const BOUND_SERVERS = [
53
+ "http",
54
+ "https",
55
+ "h2c"
56
+ ];
51
57
  /** Port configuré d'un serveur, ou `0` (désactivé / non précisé → choix noyau). */
52
- function configuredPort(entry) {
58
+ function configuredPort(servers, which) {
59
+ if (which === "h2c") {
60
+ const entry = servers?.h2c;
61
+ return isH2cEnabled(entry) ? entry?.port ?? 0 : 0;
62
+ }
63
+ const entry = servers?.[which];
53
64
  if (!entry) return 0;
54
65
  return entry.port ?? 0;
55
66
  }
56
67
  /**
68
+ * Serveur actif qui convoite le MÊME port que h2c, ou `null`.
69
+ *
70
+ * Un port partagé avec h2c n'est pas un conflit à contourner : sur ce port, le
71
+ * client HTTP/1.1 et le proxy h2c se marchent dessus, et le repli `auto` ferait
72
+ * glisser l'un des deux là où personne ne l'attend. Le boot le refuse.
73
+ *
74
+ * @param servers - `kernel.options.servers`.
75
+ * @returns `"http"` ou `"https"` en conflit, sinon `null` (h2c inactif, port 0).
76
+ */
77
+ function h2cPortConflict(servers) {
78
+ const port = configuredPort(servers, "h2c");
79
+ if (port === 0) return null;
80
+ if (configuredPort(servers, "http") === port) return "http";
81
+ if (configuredPort(servers, "https") === port) return "https";
82
+ return null;
83
+ }
84
+ /**
57
85
  * Compose le plan de bind d'un serveur depuis la config du kernel — source UNIQUE
58
- * (les deux serveurs l'appellent ; la politique n'est décidée qu'ici).
86
+ * (les serveurs l'appellent ; la politique n'est décidée qu'ici).
59
87
  *
60
88
  * @param which - le serveur qu'on borne.
61
89
  * @param servers - `kernel.options.servers`.
62
90
  * @param environment - `kernel.environment` (arbitre le défaut de la politique).
63
91
  */
64
92
  function buildBindPlan(which, servers, environment) {
65
- const desired = configuredPort(servers?.[which]);
66
- const other = configuredPort(servers?.[which === "http" ? "https" : "http"]);
67
- const policy = resolvePortPolicy(environment, servers?.portPolicy);
93
+ const desired = configuredPort(servers, which);
94
+ const reserved = [];
95
+ for (const other of BOUND_SERVERS) {
96
+ if (other === which) continue;
97
+ const port = configuredPort(servers, other);
98
+ if (port > 0 && port !== desired) reserved.push(port);
99
+ }
68
100
  return {
69
101
  desired,
70
- reserved: other > 0 && other !== desired ? [other] : [],
71
- attempts: policy === "auto" ? servers?.portRetryAttempts ?? 20 : 0
102
+ reserved,
103
+ attempts: resolvePortPolicy(environment, servers?.portPolicy) === "auto" ? servers?.portRetryAttempts ?? 20 : 0
72
104
  };
73
105
  }
74
106
  /** Adresses qui désignent « toutes les interfaces » — rien ne s'y connecte. */
@@ -224,5 +256,4 @@ async function bindWithFallback(server, host, plan, probe = isPortListening, sha
224
256
  candidate = next;
225
257
  }
226
258
  }
227
- //#endregion
228
- export { DEFAULT_PORT_RETRY_ATTEMPTS, bindWithFallback, buildBindPlan, conflictProbeTargets, detectPortConflict, resolvePortPolicy };
259
+ export { DEFAULT_PORT_RETRY_ATTEMPTS, bindWithFallback, buildBindPlan, conflictProbeTargets, detectPortConflict, h2cPortConflict, resolvePortPolicy };
@@ -1,6 +1,79 @@
1
+ import { websocketHandshakeProblem } from "../proxy/rules.js";
1
2
  import { refuseUpgrade } from "../proxy/forward.js";
2
3
  import { STATUS_CODES } from "node:http";
3
- //#region nodefony/src/servers/upgradeDispatch.ts
4
+ // nodefony/src/servers/upgradeDispatch.ts
5
+ /** Défaut sans noyau : tout upgrade conforme est accepté puis émis en `connection`. */
6
+ function acceptAll(wss) {
7
+ return (req, admission) => {
8
+ const accepted = admission.accept();
9
+ if (accepted instanceof Promise) accepted.then((ws) => {
10
+ if (ws !== null) wss.emit("connection", ws, req);
11
+ });
12
+ else if (accepted !== null) wss.emit("connection", accepted, req);
13
+ };
14
+ }
15
+ /**
16
+ * Le verdict d'UN upgrade. Pendant que le noyau décide, le socket n'a plus
17
+ * d'écouteur `error` (`node:http` retire les siens à l'émission d'`upgrade`,
18
+ * `ws` ne pose les siens qu'à `handleUpgrade`) : une coupure du client
19
+ * (`ECONNRESET`) y deviendrait une erreur non gérée qui abat le process. D'où
20
+ * l'écouteur de la fenêtre d'attente, retiré quand le verdict tombe.
21
+ *
22
+ * Une classe, pas un objet de fermetures : une allocation par handshake (plus
23
+ * l'écouteur), méthodes partagées par le prototype.
24
+ */
25
+ var UpgradeAdmission = class {
26
+ wss;
27
+ req;
28
+ socket;
29
+ head;
30
+ #accepted = void 0;
31
+ #settled = false;
32
+ #onPendingError;
33
+ constructor(wss, req, socket, head) {
34
+ this.wss = wss;
35
+ this.req = req;
36
+ this.socket = socket;
37
+ this.head = head;
38
+ this.#onPendingError = () => socket.destroy();
39
+ socket.on("error", this.#onPendingError);
40
+ }
41
+ #settle() {
42
+ if (this.#settled) return false;
43
+ this.#settled = true;
44
+ this.socket.removeListener("error", this.#onPendingError);
45
+ return true;
46
+ }
47
+ accept() {
48
+ if (this.#accepted !== void 0) return this.#accepted;
49
+ if (!this.#settle()) return this.#accepted = null;
50
+ const { socket } = this;
51
+ if (socket.destroyed || !socket.writable) {
52
+ socket.destroy();
53
+ return this.#accepted = null;
54
+ }
55
+ let ws;
56
+ let late = null;
57
+ const onClose = () => late?.(null);
58
+ this.wss.handleUpgrade(this.req, socket, this.head, (accepted) => {
59
+ if (late === null) {
60
+ ws = accepted;
61
+ return;
62
+ }
63
+ socket.removeListener("close", onClose);
64
+ late(accepted);
65
+ });
66
+ if (ws !== void 0) return this.#accepted = ws;
67
+ socket.once("close", onClose);
68
+ return this.#accepted = new Promise((resolve) => {
69
+ late = resolve;
70
+ });
71
+ }
72
+ refuse(status, headers) {
73
+ if (!this.#settle()) return;
74
+ refuseUpgrade(this.socket, status, STATUS_CODES[status] ?? "Refused", headers);
75
+ }
76
+ };
4
77
  /**
5
78
  * Pose l'UNIQUE écouteur `upgrade` d'un serveur : le proxy inverse d'abord,
6
79
  * puis le serveur WebSocket de Nodefony.
@@ -14,7 +87,10 @@ import { STATUS_CODES } from "node:http";
14
87
  *
15
88
  * Entre les deux, `refusal` tranche ce qui doit être refusé AVANT le `101`
16
89
  * (RFC 6455 §4.2.2) : un chemin sans route WebSocket reçoit un statut HTTP,
17
- * jamais une ouverture suivie d'une fermeture.
90
+ * jamais une ouverture suivie d'une fermeture. Puis la FORME du handshake est
91
+ * contrôlée (`websocketHandshakeProblem`, la règle du proxy inverse) : un
92
+ * handshake malformé reçoit `400` sans jamais atteindre le noyau. Enfin
93
+ * `admit` décide — pare-feu, garde de l'action — et seul son verdict ouvre.
18
94
  *
19
95
  * Sans montage, le coût par connexion est une lecture de champ.
20
96
  *
@@ -23,9 +99,11 @@ import { STATUS_CODES } from "node:http";
23
99
  * @param relay - proxy inverse, lu à chaque upgrade (il peut naître après)
24
100
  * @param refusal - statut HTTP qui refuse l'upgrade, `null` pour l'admettre
25
101
  * (cf `HttpKernel.websocketUpgradeRefusal`)
102
+ * @param admit - décide d'un upgrade admis (cf `HttpKernel.onWebsocketUpgrade`) ;
103
+ * par défaut, tout upgrade conforme est accepté et émis en `connection`
26
104
  * @returns la fonction qui retire l'écouteur — à appeler à l'arrêt
27
105
  */
28
- function attachUpgradeDispatch(server, wss, relay, refusal) {
106
+ function attachUpgradeDispatch(server, wss, relay, refusal, admit = acceptAll(wss)) {
29
107
  const onUpgrade = (req, socket, head) => {
30
108
  const proxy = relay();
31
109
  if (proxy !== null && proxy.mounts !== null) {
@@ -36,14 +114,15 @@ function attachUpgradeDispatch(server, wss, relay, refusal) {
36
114
  refuseUpgrade(socket, status, STATUS_CODES[status] ?? "Refused");
37
115
  return;
38
116
  }
39
- wss.handleUpgrade(req, socket, head, (ws) => {
40
- wss.emit("connection", ws, req);
41
- });
117
+ if (websocketHandshakeProblem(req.method, req.headers) !== null) {
118
+ refuseUpgrade(socket, 400, STATUS_CODES[400] ?? "Bad Request");
119
+ return;
120
+ }
121
+ admit(req, new UpgradeAdmission(wss, req, socket, head));
42
122
  };
43
123
  server.on("upgrade", onUpgrade);
44
124
  return () => {
45
125
  server.removeListener("upgrade", onUpgrade);
46
126
  };
47
127
  }
48
- //#endregion
49
128
  export { attachUpgradeDispatch };
@@ -1,7 +1,7 @@
1
1
  import Cookie from "../cookies/cookie.js";
2
2
  import { extend } from "nodefony";
3
3
  import { randomBytes } from "node:crypto";
4
- //#region nodefony/src/session/session.ts
4
+ // nodefony/src/session/session.ts
5
5
  const defaultSessionOptions = {
6
6
  name: "nodefony",
7
7
  strictMode: true,
@@ -238,7 +238,7 @@ var Session = class {
238
238
  }
239
239
  isValidSession(_data, context) {
240
240
  if (this.options.refererCheck) {
241
- let sameHost = false;
241
+ let sameHost;
242
242
  try {
243
243
  sameHost = this.checkSecureReferer(context);
244
244
  } catch {
@@ -410,5 +410,4 @@ var Session = class {
410
410
  }
411
411
  }
412
412
  };
413
- //#endregion
414
413
  export { Session as default };
@@ -1,5 +1,5 @@
1
1
  import { thrownMessage } from "../errors/thrownMessage.js";
2
- //#region nodefony/src/session/sessionStoreFailure.ts
2
+ // nodefony/src/session/sessionStoreFailure.ts
3
3
  /**
4
4
  * Reconnaît une table de session absente, quel que soit le dialecte.
5
5
  *
@@ -26,5 +26,4 @@ function describeSessionStoreFailure(error) {
26
26
  message: `La session n'a pas pu être persistée — la requête est servie en 500 plutôt que laissée sans réponse. Cause : ${cause}.${looksLikeMissingTable(cause) ? " La table de session est probablement absente : appliquer les migrations (`nodefony orm:migrate`) avant de servir, ou choisir un autre stockage (`http.session.store`)." : " Vérifier que le stockage de session déclaré sous `http.session.store` est joignable ; à défaut, appliquer les migrations (`nodefony orm:migrate`)."}`
27
27
  };
28
28
  }
29
- //#endregion
30
29
  export { describeSessionStoreFailure };
@@ -1,6 +1,6 @@
1
1
  import { SESSION_DEFAULT_ORDER, SESSION_SORTABLE_FIELDS } from "./sessionSort.js";
2
2
  import { assertPageQuery, compareByOrder, pickOrder } from "nodefony";
3
- //#region nodefony/src/session/storage/MemorySessionStorage.ts
3
+ // nodefony/src/session/storage/MemorySessionStorage.ts
4
4
  /**
5
5
  * Store de sessions **en mémoire** (Map process) — implémentation de référence
6
6
  * d'{@link ISessionStorage}, pendant `session` des `Memory*Store` de sécurité.
@@ -181,5 +181,4 @@ var MemorySessionStorage = class {
181
181
  return Promise.resolve(users.size);
182
182
  }
183
183
  };
184
- //#endregion
185
184
  export { MemorySessionStorage as default };
@@ -1,4 +1,4 @@
1
- //#region nodefony/src/session/storage/RevocationGuardStorage.ts
1
+ // nodefony/src/session/storage/RevocationGuardStorage.ts
2
2
  /**
3
3
  * Durée de vie (ms) d'une pierre tombale de révocation. Couvre la fenêtre
4
4
  * pendant laquelle une requête « en vol » — qui avait chargé la session AVANT
@@ -148,5 +148,4 @@ var RevocationGuardStorage = class {
148
148
  if (t.size === 0) this.#tombstones = null;
149
149
  }
150
150
  };
151
- //#endregion
152
151
  export { RevocationGuardStorage as default };
@@ -1,4 +1,4 @@
1
- //#region nodefony/src/session/storage/sessionFilters.ts
1
+ // nodefony/src/session/storage/sessionFilters.ts
2
2
  /**
3
3
  * **Le vocabulaire de filtre des sessions**, en noms PUBLICS — celui que la
4
4
  * console d'administration écrit dans l'URL (`?user=alice`).
@@ -79,5 +79,4 @@ const SESSION_FACETS = {
79
79
  * rouvert du même geste.
80
80
  */
81
81
  const SESSION_STATS_FILTERS = { user: "string" };
82
- //#endregion
83
82
  export { SESSION_FACETS, SESSION_FILTERS, SESSION_STATS_FILTERS };
@@ -1,5 +1,5 @@
1
1
  import { renameOrderFields } from "nodefony";
2
- //#region nodefony/src/session/storage/sessionSort.ts
2
+ // nodefony/src/session/storage/sessionSort.ts
3
3
  /**
4
4
  * **Le vocabulaire de tri des sessions**, en noms PUBLICS — ceux qu'un client
5
5
  * écrit dans l'URL (`?order=updatedAt:DESC`), jamais des noms de colonne.
@@ -49,5 +49,4 @@ const SESSION_COLUMN_ALIASES = { id: "session_id" };
49
49
  * `session_id` — {@link SESSION_DEFAULT_ORDER} déjà traduit.
50
50
  */
51
51
  const SESSION_DEFAULT_ORDER_SQL = renameOrderFields(SESSION_DEFAULT_ORDER, SESSION_COLUMN_ALIASES);
52
- //#endregion
53
52
  export { SESSION_COLUMN_ALIASES, SESSION_DEFAULT_ORDER, SESSION_DEFAULT_ORDER_SQL, SESSION_SORTABLE_FIELDS };
@@ -71,6 +71,9 @@ export { defineHttpConfig, httpConfigJsonSchema, } from "./nodefony/config/defin
71
71
  export { httpConfigSchema } from "./nodefony/config/config.js";
72
72
  export type { IHttpConfig, IHttpConfigInput, } from "./nodefony/interfaces/IHttpConfig.js";
73
73
  export { decideSend, readBackpressureOptions, type WsBackpressurePolicy, type WsSendDecision, type IWsBackpressureOptions, type IBackpressureSocket, type IBackpressureTarget, } from "./nodefony/src/context/websocket/wsBackpressure.js";
74
+ export { isWebsocketContext } from "./nodefony/src/context/websocket/isWebsocketContext.js";
75
+ export { REQUEST_TRACE_CHANNEL } from "./nodefony/src/context/requestTrace.js";
76
+ export type { IRequestTrace, RequestTraceProtocol, } from "./nodefony/interfaces/IRequestTrace.js";
74
77
  export { compileDomainPattern, compileDomainPatterns, compileTrustedHosts, isDomainAllowed, } from "./nodefony/src/context/domainMatcher.js";
75
78
  export type { DomainPattern, ITrustedHostsConfig, } from "./nodefony/src/context/domainMatcher.js";
76
79
  export { MemoryRateLimitStore } from "./nodefony/src/rateLimit/MemoryRateLimitStore.js";
@@ -79,7 +82,10 @@ export { Context, Session, SessionsService, HttpError, HttpKernel, Response, Htt
79
82
  export { SseStream, openSseStream, acceptsEventStream, SSE_HEARTBEAT_MS, } from "./nodefony/src/context/http/SseStream.js";
80
83
  export type { ISseStreamOptions, ISseSendOptions, } from "./nodefony/src/context/http/SseStream.js";
81
84
  export { schemaMismatchOf, type SchemaMismatchConfidence, } from "./nodefony/service/error-renderer.js";
82
- export type { ProfileEntry, ProfileSummary, ProfilePhase, ProfileQuery, ProfileSecurity, } from "./nodefony/src/profiler/Profiler.js";
85
+ export { toValidationFields, type IValidationField, } from "./nodefony/service/error-renderer.js";
86
+ export type { ProfileEntry, ProfileSummary, ProfilePhase, ProfileQuery, ProfileSecurity, IProfileBatch, IProfilerReader, } from "./nodefony/src/profiler/Profiler.js";
87
+ export { aggregateProfiles, createProfileAggregator, isFailedProfile, sqlShape, N_PLUS_ONE_MIN_REPEATS, ACTION_SELF_PHASE, NO_ROUTE, TOOLING_URL_PREFIX, } from "./nodefony/src/profiler/aggregate.js";
88
+ export type { IProfileAggregator, IProfileAggregatorOptions, IProfileReport, IRouteStats, IStatusBreakdown, IPhaseTotal, INPlusOne, ISqlShapeStats, IErrorSample, } from "./nodefony/src/profiler/aggregate.js";
83
89
  export { FrameProfile } from "./nodefony/src/profiler/FrameProfile.js";
84
90
  export type { FrameProfileInit, ProfiledArea, ProfiledResolver, } from "./nodefony/src/profiler/FrameProfile.js";
85
91
  export { default as ReverseProxy } from "./nodefony/service/reverse-proxy.js";
@@ -87,11 +93,11 @@ export { parseProxyOrigin, normalizePrefix, proxyMountProblems, } from "./nodefo
87
93
  export type { IProxyMount, IProxyMountOptions, ProxyTarget, } from "./nodefony/interfaces/IReverseProxy.js";
88
94
  export { resolveUiDelivery, PrebuiltUi, } from "./nodefony/src/assets/prebuiltUi.js";
89
95
  export type { UiDeliveryMode, UiDeliveryResolved, IUiDeliveryResolution, IUiDeliveryOptions, IPrebuiltUiOptions, } from "./nodefony/src/assets/prebuiltUi.js";
90
- export type { IContext, IHttpContext, IWebsocketContext, ServerType, SchemeType, WebSocketStateType, CookiesMap, ISecurityTrace, SecurityOutcome, } from "./nodefony/interfaces/IContext.js";
96
+ export type { IContext, IHttpContext, IWebsocketContext, IWebsocketConnectionState, ServerType, ProtocolName, AlpnProtocol, SchemeType, WebSocketStateType, CookiesMap, ISecurityTrace, SecurityOutcome, } from "./nodefony/interfaces/IContext.js";
91
97
  export type { ICookie, ICookieOptions, IWsCookie, SameSiteType, PriorityType, } from "./nodefony/interfaces/ICookie.js";
92
98
  export type { ISession, ISessionStorage, ISerializedSession, ISessionSummary, ISessionRecord, ISessionListFilter, ISessionListQuery, SessionIntent, SessionStatusType, SessionStrategyType, FlashBagType, MetaBagType, } from "./nodefony/interfaces/ISession.js";
93
99
  export { SESSION_SORTABLE_FIELDS, SESSION_DEFAULT_ORDER, SESSION_DEFAULT_ORDER_SQL, SESSION_COLUMN_ALIASES, } from "./nodefony/src/session/storage/sessionSort.js";
94
- export type { IHttpRequest, IHttp2Request, IWsRequest, HTTPMethodType, } from "./nodefony/interfaces/IRequest.js";
100
+ export type { IHttpRequest, RequestBody, IHttp2Request, IWsRequest, HTTPMethodType, } from "./nodefony/interfaces/IRequest.js";
95
101
  export type { IHttpResponse, IWebsocketResponse, } from "./nodefony/interfaces/IResponse.js";
96
102
  export type { IHttpKernel } from "./nodefony/interfaces/IHttpKernel.js";
97
103
  export type { IResolvedRoute, IRouteResolver, IRequestRouter, } from "./nodefony/interfaces/IRouting.js";
@@ -198,6 +198,10 @@ export declare const httpConfigSchema: z.ZodObject<{
198
198
  stripHeaders: z.ZodDefault<z.ZodArray<z.ZodString>>;
199
199
  timeoutMs: z.ZodOptional<z.ZodNumber>;
200
200
  secure: z.ZodDefault<z.ZodBoolean>;
201
+ accessLog: z.ZodDefault<z.ZodEnum<{
202
+ all: "all";
203
+ errors: "errors";
204
+ }>>;
201
205
  }, z.core.$strict>>>;
202
206
  }, z.core.$strict>>;
203
207
  wsMaxConnectionsPerIp: z.ZodDefault<z.ZodNullable<z.ZodNumber>>;
@@ -3,7 +3,35 @@ import type { MaybePromise } from "nodefony";
3
3
  import type { ICookie } from "./ICookie.js";
4
4
  import type { ISession } from "./ISession.js";
5
5
  import type { HTTPMethodType } from "./IRequest.js";
6
- export type ServerType = "http" | "https" | "http2" | "http3" | "websocket" | "websocket-secure";
6
+ /**
7
+ * Identité du serveur qui a reçu la requête, nommée par le schéma d'URI qu'il
8
+ * sert en LOCAL (RFC 9110 §4.2, RFC 6455 §3) : elle choisit la section de
9
+ * configuration du serveur (`http`, `https`, `websocket`, `websocketSecure`).
10
+ * Ce n'est PAS un protocole — `https` sert HTTP/1.1 et h2 sur le même port ;
11
+ * le protocole du saut se lit dans {@link AlpnProtocol}.
12
+ */
13
+ export type ServerType = "http" | "https" | "ws" | "wss";
14
+ /**
15
+ * Famille du protocole que le contrôleur traite, nommée comme l'attribut
16
+ * OpenTelemetry `network.protocol.name`.
17
+ *
18
+ * Union OUVERTE : une valeur peut apparaître en version mineure
19
+ * (`"webtransport"` sur HTTP/3) — pas de `switch` exhaustif sans `default`.
20
+ */
21
+ export type ProtocolName = "http" | "websocket";
22
+ /**
23
+ * Protocole du saut qui atteint CE processus, nommé par le registre IANA des
24
+ * identifiants ALPN — la valeur même que Node expose (`TLSSocket.alpnProtocol`,
25
+ * `Http2Session.alpnProtocol`, qui vaut `"h2c"` sur une session en clair).
26
+ *
27
+ * Union OUVERTE : `"h3"` s'ajoutera en version mineure, sans rupture.
28
+ */
29
+ export type AlpnProtocol = "http/1.1" | "h2" | "h2c";
30
+ /**
31
+ * Schéma d'URI vu par le CLIENT (RFC 9110 §4.2, RFC 6455 §3) : derrière un
32
+ * proxy de confiance, c'est le schéma qu'il a annoncé (`Forwarded`), pas
33
+ * celui du saut local. Toute décision de sécurité lit ce champ.
34
+ */
7
35
  export type SchemeType = "http" | "https" | "ws" | "wss";
8
36
  export type WebSocketStateType = "handshake" | "connected" | "closed" | "error" | "message" | null;
9
37
  export type CookiesMap = Record<string, ICookie>;
@@ -67,8 +95,14 @@ export interface IContext {
67
95
  csrfProtect: boolean;
68
96
  csrfExempt: boolean;
69
97
  csrfToken: string | null;
70
- type: ServerType;
98
+ /** Famille traitée : `"http"` ou `"websocket"` (union ouverte). */
99
+ type: ProtocolName;
100
+ /** Schéma vu par le client — seul champ que lit une décision de sécurité. */
71
101
  scheme: SchemeType;
102
+ /** Protocole du saut local : `"http/1.1"`, `"h2"`, `"h2c"` (union ouverte). */
103
+ alpnProtocol: AlpnProtocol;
104
+ /** Serveur qui a reçu la requête — choisit la configuration par serveur. */
105
+ serverType: ServerType;
72
106
  method: HTTPMethodType | null;
73
107
  url: string;
74
108
  domain: string;
@@ -93,6 +127,15 @@ export interface IContext {
93
127
  readonly phases: PhaseTiming[];
94
128
  phaseStart(name: PhaseName): void;
95
129
  phaseEnd(name: PhaseName): void;
130
+ /**
131
+ * Arrête l'horloge de la requête (au premier appel) et rend sa durée en ms —
132
+ * la SEULE durée de requête du framework, mesurée partout par défaut ; `null`
133
+ * seulement si `timing.enabled` vaut `false`.
134
+ *
135
+ * Membre REQUIS : le journal d'accès et le profileur le lisent sans repli.
136
+ * Une implémentation maison d'`IContext` qui ne mesure rien rend `null`.
137
+ */
138
+ stopClock(): number | null;
96
139
  profiling: boolean;
97
140
  securityTrace: ISecurityTrace | null;
98
141
  onAfterResponse(fn: AfterResponseHandler): void;
@@ -139,13 +182,38 @@ export interface IHttpContext extends IContext {
139
182
  getHost(): string | undefined;
140
183
  getUserAgent(): string | undefined;
141
184
  }
142
- export interface IWebsocketContext extends IContext {
185
+ /**
186
+ * Ce qu'un module attache à une connexion WebSocket pour toute sa durée — interface
187
+ * VIDE par construction, qu'un module AUGMENTE par fusion de déclarations.
188
+ *
189
+ * `@nodefony/http` ignore les protocoles bâtis au-dessus de la socket (le JSON-RPC
190
+ * de `@nodefony/realtime`, par exemple) et ne peut pas les importer. Le module qui
191
+ * en porte un déclare son champ ici : {@link IWebsocketContext} et `WebsocketContext`
192
+ * le reçoivent typé, sans conversion chez le lecteur et sans rien coûter à
193
+ * l'exécution — la lecture reste un accès de champ ordinaire.
194
+ *
195
+ * Chaque champ se déclare OPTIONNEL : il n'existe qu'une fois posé par son module
196
+ * (à la poignée de main, en général), et vaut `undefined` avant, comme sur toute
197
+ * connexion que ce module ne sert pas.
198
+ *
199
+ * @example
200
+ * ```ts
201
+ * declare module "@nodefony/http" {
202
+ * interface IWebsocketConnectionState {
203
+ * myProtocol?: IMyProtocolState;
204
+ * }
205
+ * }
206
+ * ```
207
+ */
208
+ export interface IWebsocketConnectionState {
209
+ }
210
+ export interface IWebsocketContext extends IContext, IWebsocketConnectionState {
143
211
  acceptedProtocol?: string | undefined;
144
212
  connection: unknown;
145
213
  rejected: boolean;
146
214
  port: number | string;
147
215
  wsUrl: URL | null;
148
- queryGet: Record<string, string>;
216
+ query: Record<string, string>;
149
217
  connect(): Promise<unknown>;
150
218
  handle(data?: unknown[]): Promise<object>;
151
219
  close(reasonCode: number, description: string): unknown;
@@ -8,12 +8,18 @@ export interface IRequest {
8
8
  getHeader(name: string): string | string[] | undefined;
9
9
  getHeaders(): Record<string, string | string[] | undefined>;
10
10
  }
11
+ /**
12
+ * Le corps DÉCODÉ d'une requête : un objet (JSON, formulaire, champs
13
+ * multipart, XML), une chaîne (`text/*`), ou des octets (`Uint8Array` — tout
14
+ * autre type, et un corps sans `Content-Type`). Le même type d'octets que la
15
+ * socket temps réel : un schéma de route valide l'un comme l'autre.
16
+ */
17
+ export type RequestBody = Record<string, unknown> | string | Uint8Array;
11
18
  export interface IHttpRequest extends IRequest {
12
19
  url: URL;
13
20
  query: Record<string, unknown>;
14
- queryGet: Record<string, unknown>;
15
- queryPost: Record<string, unknown>;
16
- queryFile: unknown[];
21
+ body: RequestBody;
22
+ files: readonly unknown[];
17
23
  remoteAddress: string | null | undefined;
18
24
  acceptHtml: boolean;
19
25
  getRemoteAddress(): string | null | undefined;
@@ -29,7 +35,6 @@ export interface IHttp2Request extends IHttpRequest {
29
35
  export interface IWsRequest extends IRequest {
30
36
  url: URL;
31
37
  query: Record<string, string>;
32
- queryGet: Record<string, string>;
33
38
  path: string;
34
39
  cookies?: Record<string, ICookie>;
35
40
  }
@@ -0,0 +1,56 @@
1
+ import type { SchemeType } from "./IContext.js";
2
+ import type { HTTPMethodType } from "./IRequest.js";
3
+ /**
4
+ * Nature de l'opération tracée : une requête HTTP, ou le handshake d'une
5
+ * connexion WebSocket.
6
+ */
7
+ export type RequestTraceProtocol = "http" | "websocket";
8
+ /**
9
+ * Message publié sur le `TracingChannel` `nodefony.http.request`, le même
10
+ * objet de `start` à `asyncEnd` pour une requête donnée.
11
+ *
12
+ * Les champs d'identité (`requestId`, `protocol`, `method`, `scheme`, `url`)
13
+ * sont posés dès `start`. Les champs de résultat (`route`, `routePath`,
14
+ * `module`, `statusCode`, `durationMs`, `error`) valent `null` jusqu'à la fin
15
+ * de la requête : un abonné les lit sur `asyncEnd`. Tout est en lecture seule
16
+ * pour l'abonné — c'est Nodefony qui les remplit.
17
+ */
18
+ export interface IRequestTrace {
19
+ /** Identifiant de corrélation de la requête (`X-Request-Id` entrant, sinon généré). */
20
+ readonly requestId: string;
21
+ /** `"http"` pour une requête, `"websocket"` pour un handshake. */
22
+ readonly protocol: RequestTraceProtocol;
23
+ /** Méthode de la requête (`"WEBSOCKET"` pour un handshake). */
24
+ readonly method: HTTPMethodType | null;
25
+ /** Schéma vu par le client, proxy de confiance compris (`url.scheme` d'OpenTelemetry). */
26
+ readonly scheme: SchemeType;
27
+ /** URL complète de la requête, chaîne de requête comprise — l'abonné en tire `url.path` et `url.query`. */
28
+ readonly url: string;
29
+ /** Nom de la route qui a répondu, `null` sans route (statique, 404). */
30
+ readonly route: string | null;
31
+ /**
32
+ * Gabarit de la route, préfixe compris (`/users/{id}`) : faible cardinalité,
33
+ * c'est l'attribut `http.route` d'OpenTelemetry. La racine vaut `/`. `null`
34
+ * sans route.
35
+ */
36
+ readonly routePath: string | null;
37
+ /** Module qui a signé la réponse — le même que celui de la ligne d'accès. */
38
+ readonly module: string | null;
39
+ /**
40
+ * Statut rendu au client : celui de l'amont pour une requête relayée, `101`
41
+ * pour un handshake accepté, le statut du refus sinon. `null` si le client
42
+ * est parti avant toute réponse.
43
+ */
44
+ readonly statusCode: number | null;
45
+ /**
46
+ * Durée de la requête en millisecondes, construction du contexte → dernier
47
+ * octet remis (fin du handshake en WebSocket). `null` si `timing.enabled`
48
+ * vaut `false`.
49
+ */
50
+ readonly durationMs: number | null;
51
+ /**
52
+ * Exception attrapée par le pipeline, `null` sinon. Un statut 4xx rendu
53
+ * sans exception n'en porte pas ; c'est à l'abonné de classer un statut.
54
+ */
55
+ readonly error: unknown;
56
+ }
@@ -59,6 +59,14 @@ export interface IProxyMountOptions {
59
59
  * ACCEPTÉ que vers la boucle locale (refus au montage sinon).
60
60
  */
61
61
  secure?: boolean | undefined;
62
+ /**
63
+ * Ligne d'accès des requêtes relayées : `"all"` (défaut) les écrit toutes,
64
+ * `"errors"` seulement celles en échec (statut ≥ 400). Pour un amont qui sert
65
+ * des centaines de fichiers par page (le relais de Vite) : un fichier bien
66
+ * servi n'apprend rien, et ses lignes chassaient les autres de la mémoire
67
+ * du journal.
68
+ */
69
+ accessLog?: "all" | "errors" | undefined;
62
70
  }
63
71
  /** Un montage tel que le proxy le garde : préfixe normalisé + réglages. */
64
72
  export interface IProxyMount extends IProxyMountOptions {
@@ -11,6 +11,15 @@ import type { ContextType } from "../service/http-kernel.js";
11
11
  export interface IResolvedRoute {
12
12
  /** Nom de la route (journalisation, diagnostic). */
13
13
  readonly name: string;
14
+ /**
15
+ * Gabarit de la route, préfixe compris (`/users/{id}`) — faible cardinalité,
16
+ * publié comme `routePath` sur le canal `nodefony.http.request`.
17
+ */
18
+ readonly path?: string | undefined;
19
+ /** Module propriétaire — il signe la ligne d'accès de la requête. */
20
+ readonly module?: {
21
+ readonly name: string;
22
+ } | undefined;
14
23
  /** Corps laissé en flux (`@Body({ stream: true })`) : le parse est sauté. */
15
24
  readonly bodyStream?: boolean | undefined;
16
25
  }
@@ -35,6 +44,13 @@ export interface IRouteResolver {
35
44
  } | null | undefined;
36
45
  /** Nom de l'action résolue. */
37
46
  actionName?: string | undefined;
47
+ /**
48
+ * Ce que l'action a rendu sans que rien ne soit envoyé (`"null"`,
49
+ * `"undefined"`, `"une instance de Book"`…), `null` sinon. Posé seulement
50
+ * sur la branche « l'action répond elle-même » : lu au démontage pour dire,
51
+ * en développement, POURQUOI une requête a attendu son délai d'expiration.
52
+ */
53
+ readonly unrendered?: string | null | undefined;
38
54
  /**
39
55
  * Rejoue le match d'une route sur un contexte (WS : handshake puis frames).
40
56
  *
@@ -60,6 +76,16 @@ export interface IRouteResolver {
60
76
  * n'attendent, sinon sa promesse
61
77
  */
62
78
  callController(data?: unknown[], reload?: boolean): MaybePromise<unknown>;
79
+ /**
80
+ * Juge les gardes de l'action résolue (`@IsGranted`, `@RequireScope`,
81
+ * step-up, rôle de la zone) SANS l'exécuter — le pipeline WebSocket l'appelle
82
+ * avant d'accepter le handshake, pour qu'un refus parte en statut HTTP. Un
83
+ * verdict favorable vaut pour la PROCHAINE exécution, qui ne le rejuge pas.
84
+ *
85
+ * @returns `undefined` quand l'action n'est pas gardée ; sinon la promesse du
86
+ * verdict, rompue par un refus (401/403)
87
+ */
88
+ authorizeAction(): Promise<void> | undefined;
63
89
  }
64
90
  /**
65
91
  * Ce que le pipeline HTTP/WS attend du service `router` — implémenté par
@@ -1,10 +1,11 @@
1
1
  export type { ICookie, ICookieOptions, IWsCookie, SameSiteType, PriorityType, } from "./ICookie.js";
2
2
  export type { ISession, ISessionStorage, ISerializedSession, SessionIntent, SessionStatusType, SessionStrategyType, FlashBagType, MetaBagType, } from "./ISession.js";
3
3
  export type { IUploadedFile, IUploadService, IParsedUploadFile, IUploadOptions, } from "./IUpload.js";
4
- export type { IRequest, IHttpRequest, IHttp2Request, IWsRequest, HTTPMethodType, } from "./IRequest.js";
4
+ export type { IRequest, IHttpRequest, RequestBody, IHttp2Request, IWsRequest, HTTPMethodType, } from "./IRequest.js";
5
5
  export type { IResponse, IHttpResponse, IWebsocketResponse } from "./IResponse.js";
6
- export type { IContext, IHttpContext, IWebsocketContext, ServerType, SchemeType, WebSocketStateType, CookiesMap, } from "./IContext.js";
6
+ export type { IContext, IHttpContext, IWebsocketContext, ServerType, ProtocolName, AlpnProtocol, SchemeType, WebSocketStateType, CookiesMap, } from "./IContext.js";
7
7
  export type { IHttpKernel } from "./IHttpKernel.js";
8
8
  export type { IResolvedRoute, IRouteResolver, IRequestRouter, } from "./IRouting.js";
9
9
  export type { ISecurityZone, IFirewallGate } from "./ISecurity.js";
10
+ export type { IRequestTrace, RequestTraceProtocol } from "./IRequestTrace.js";
10
11
  export type { IProxyMount, IProxyMountOptions, ProxyTarget, } from "./IReverseProxy.js";