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

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 (124) 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 +12 -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 +1 -2
  9. package/dist/nodefony/config/defineModuleConfig.js +1 -2
  10. package/dist/nodefony/service/HttpAdminApi.js +2 -2
  11. package/dist/nodefony/service/ProfilerAdminApi.js +1 -2
  12. package/dist/nodefony/service/audit-logger.js +20 -13
  13. package/dist/nodefony/service/certificates.js +97 -13
  14. package/dist/nodefony/service/error-renderer.js +29 -12
  15. package/dist/nodefony/service/http-kernel.js +118 -43
  16. package/dist/nodefony/service/pretty-request-logger.js +5 -4
  17. package/dist/nodefony/service/request-logger.js +24 -16
  18. package/dist/nodefony/service/reverse-proxy.js +3 -3
  19. package/dist/nodefony/service/servers/clientError.js +22 -3
  20. package/dist/nodefony/service/servers/server-h2c.js +126 -0
  21. package/dist/nodefony/service/servers/server-http.js +5 -8
  22. package/dist/nodefony/service/servers/server-https.js +12 -24
  23. package/dist/nodefony/service/servers/server-static.js +3 -3
  24. package/dist/nodefony/service/servers/server-websocket-secure.js +10 -18
  25. package/dist/nodefony/service/servers/server-websocket.js +10 -18
  26. package/dist/nodefony/service/servers/serverShutdown.js +78 -18
  27. package/dist/nodefony/service/servers/wsHeartbeat.js +1 -2
  28. package/dist/nodefony/service/sessions/sessions-service.js +7 -14
  29. package/dist/nodefony/service/trace.js +1 -2
  30. package/dist/nodefony/service/upload/upload-service.js +5 -8
  31. package/dist/nodefony/service/x509.js +1 -2
  32. package/dist/nodefony/src/assets/collectAssets.js +1 -2
  33. package/dist/nodefony/src/assets/prebuiltUi.js +1 -2
  34. package/dist/nodefony/src/context/Context.js +23 -31
  35. package/dist/nodefony/src/context/domainMatcher.js +1 -2
  36. package/dist/nodefony/src/context/forwarded.js +1 -2
  37. package/dist/nodefony/src/context/http/HttpContext.js +7 -6
  38. package/dist/nodefony/src/context/http/Request.js +33 -29
  39. package/dist/nodefony/src/context/http/Response.js +23 -6
  40. package/dist/nodefony/src/context/http/SseStream.js +1 -2
  41. package/dist/nodefony/src/context/http/parser.js +36 -10
  42. package/dist/nodefony/src/context/http/urlFastPath.js +1 -2
  43. package/dist/nodefony/src/context/http2/Request.js +4 -8
  44. package/dist/nodefony/src/context/http2/Response.js +22 -9
  45. package/dist/nodefony/src/context/metaData.js +1 -2
  46. package/dist/nodefony/src/context/requestId.js +1 -2
  47. package/dist/nodefony/src/context/responseEnded.js +1 -2
  48. package/dist/nodefony/src/context/transport.js +45 -0
  49. package/dist/nodefony/src/context/trustProxy.js +1 -2
  50. package/dist/nodefony/src/context/websocket/Response.js +33 -6
  51. package/dist/nodefony/src/context/websocket/WebsocketContext.js +92 -17
  52. package/dist/nodefony/src/context/websocket/isWebsocketContext.js +17 -0
  53. package/dist/nodefony/src/context/websocket/websocketUrl.js +1 -2
  54. package/dist/nodefony/src/context/websocket/wsBackpressure.js +1 -2
  55. package/dist/nodefony/src/context/websocket/wsCloseReason.js +1 -2
  56. package/dist/nodefony/src/context/websocket/wsLogContent.js +1 -2
  57. package/dist/nodefony/src/cookies/cookie.js +3 -7
  58. package/dist/nodefony/src/errors/httpError.js +1 -2
  59. package/dist/nodefony/src/errors/thrownMessage.js +1 -2
  60. package/dist/nodefony/src/profiler/FrameProfile.js +1 -2
  61. package/dist/nodefony/src/profiler/Profiler.js +102 -20
  62. package/dist/nodefony/src/profiler/aggregate.js +422 -0
  63. package/dist/nodefony/src/proxy/forward.js +29 -5
  64. package/dist/nodefony/src/proxy/generateProxyConfig.js +14 -6
  65. package/dist/nodefony/src/proxy/rules.js +12 -6
  66. package/dist/nodefony/src/rateLimit/MemoryRateLimitStore.js +1 -2
  67. package/dist/nodefony/src/rateLimit/WsConnectionCounter.js +1 -2
  68. package/dist/nodefony/src/rateLimit/rateLimitFilters.js +1 -2
  69. package/dist/nodefony/src/servers/http2Limits.js +50 -0
  70. package/dist/nodefony/src/servers/kernelServers.js +12 -3
  71. package/dist/nodefony/src/servers/portBinder.js +41 -10
  72. package/dist/nodefony/src/servers/upgradeDispatch.js +86 -7
  73. package/dist/nodefony/src/session/session.js +2 -3
  74. package/dist/nodefony/src/session/sessionStoreFailure.js +1 -2
  75. package/dist/nodefony/src/session/storage/MemorySessionStorage.js +1 -2
  76. package/dist/nodefony/src/session/storage/RevocationGuardStorage.js +1 -2
  77. package/dist/nodefony/src/session/storage/sessionFilters.js +1 -2
  78. package/dist/nodefony/src/session/storage/sessionSort.js +1 -2
  79. package/dist/types/index.d.ts +7 -3
  80. package/dist/types/nodefony/interfaces/IContext.d.ts +63 -4
  81. package/dist/types/nodefony/interfaces/IRequest.d.ts +9 -4
  82. package/dist/types/nodefony/interfaces/IRouting.d.ts +10 -0
  83. package/dist/types/nodefony/interfaces/index.d.ts +2 -2
  84. package/dist/types/nodefony/service/certificates.d.ts +55 -4
  85. package/dist/types/nodefony/service/error-renderer.d.ts +31 -0
  86. package/dist/types/nodefony/service/http-kernel.d.ts +46 -10
  87. package/dist/types/nodefony/service/servers/clientError.d.ts +16 -0
  88. package/dist/types/nodefony/service/servers/server-h2c.d.ts +51 -0
  89. package/dist/types/nodefony/service/servers/server-http.d.ts +3 -3
  90. package/dist/types/nodefony/service/servers/server-https.d.ts +4 -4
  91. package/dist/types/nodefony/service/servers/server-websocket-secure.d.ts +1 -3
  92. package/dist/types/nodefony/service/servers/server-websocket.d.ts +1 -3
  93. package/dist/types/nodefony/service/servers/serverShutdown.d.ts +30 -16
  94. package/dist/types/nodefony/src/context/Context.d.ts +13 -4
  95. package/dist/types/nodefony/src/context/http/HttpContext.d.ts +1 -1
  96. package/dist/types/nodefony/src/context/http/Request.d.ts +20 -15
  97. package/dist/types/nodefony/src/context/http/Response.d.ts +11 -0
  98. package/dist/types/nodefony/src/context/http/parser.d.ts +18 -2
  99. package/dist/types/nodefony/src/context/http2/Request.d.ts +1 -1
  100. package/dist/types/nodefony/src/context/http2/Response.d.ts +15 -5
  101. package/dist/types/nodefony/src/context/transport.d.ts +53 -0
  102. package/dist/types/nodefony/src/context/websocket/Response.d.ts +18 -2
  103. package/dist/types/nodefony/src/context/websocket/WebsocketContext.d.ts +57 -7
  104. package/dist/types/nodefony/src/context/websocket/isWebsocketContext.d.ts +15 -0
  105. package/dist/types/nodefony/src/profiler/FrameProfile.d.ts +13 -12
  106. package/dist/types/nodefony/src/profiler/Profiler.d.ts +68 -15
  107. package/dist/types/nodefony/src/profiler/aggregate.d.ts +215 -0
  108. package/dist/types/nodefony/src/proxy/forward.d.ts +14 -2
  109. package/dist/types/nodefony/src/proxy/generateProxyConfig.d.ts +16 -0
  110. package/dist/types/nodefony/src/proxy/rules.d.ts +3 -0
  111. package/dist/types/nodefony/src/servers/http2Limits.d.ts +37 -0
  112. package/dist/types/nodefony/src/servers/kernelServers.d.ts +10 -1
  113. package/dist/types/nodefony/src/servers/portBinder.d.ts +29 -5
  114. package/dist/types/nodefony/src/servers/upgradeDispatch.d.ts +33 -3
  115. package/docs/cookies.md +85 -78
  116. package/docs/observabilite.md +80 -80
  117. package/docs/rate-limit.md +83 -83
  118. package/docs/reverse-proxy.md +54 -54
  119. package/docs/servers.md +338 -224
  120. package/docs/session.md +179 -179
  121. package/docs/sse.md +24 -20
  122. package/docs/upload.md +120 -117
  123. package/package.json +8 -9
  124. package/dist/_virtual/_@oxc-project_runtime@0.153.0/helpers/esm/decorateMetadata.js +0 -6
@@ -1,16 +1,14 @@
1
1
  import { asServersConfig, configuredServerPort } from "../../src/servers/kernelServers.js";
2
- import __decorateMetadata from "../../../_virtual/_@oxc-project_runtime@0.153.0/helpers/esm/decorateMetadata.js";
3
- import __decorate from "../../../_virtual/_@oxc-project_runtime@0.153.0/helpers/esm/decorate.js";
4
- import http_kernel_default from "../http-kernel.js";
5
- import { handleClientError } from "./clientError.js";
2
+ import __decorate from "../../../_virtual/_@oxc-project_runtime@0.155.0/helpers/esm/decorate.js";
3
+ import { handleClientError, handleSessionError } from "./clientError.js";
6
4
  import { createDrainTerminator } from "./serverShutdown.js";
7
5
  import { bindWithFallback, buildBindPlan } from "../../src/servers/portBinder.js";
8
- import __decorateParam from "../../../_virtual/_@oxc-project_runtime@0.153.0/helpers/esm/decorateParam.js";
9
- import { Module, Service, extend, inject, nodefonyError } from "nodefony";
6
+ import __decorateParam from "../../../_virtual/_@oxc-project_runtime@0.155.0/helpers/esm/decorateParam.js";
7
+ import { http2ServerLimits, setHttp2SessionTimeout } from "../../src/servers/http2Limits.js";
8
+ import { Inject, Service, extend, nodefonyError } from "nodefony";
10
9
  import http2 from "node:http2";
11
10
  import https from "node:https";
12
- import { TLSSocket } from "node:tls";
13
- //#region nodefony/service/servers/server-https.ts
11
+ // nodefony/service/servers/server-https.ts
14
12
  let ServerHttps = class ServerHttps extends Service {
15
13
  httpKernel;
16
14
  httpTerminator = null;
@@ -98,7 +96,6 @@ let ServerHttps = class ServerHttps extends Service {
98
96
  createServerH2() {
99
97
  return new Promise((resolve, reject) => {
100
98
  try {
101
- const h2Cfg = this.module.options.http2 ?? {};
102
99
  const opt = extend({
103
100
  allowHTTP1: true,
104
101
  rejectUnauthorized: this.options.rejectUnauthorized,
@@ -106,23 +103,14 @@ let ServerHttps = class ServerHttps extends Service {
106
103
  cert: this.httpKernel.serviceCerticats?.cert,
107
104
  ca: this.httpKernel.serviceCerticats?.ca ? this.httpKernel.serviceCerticats.ca : void 0
108
105
  });
109
- if (h2Cfg.maxSessionMemory) opt.maxSessionMemory = h2Cfg.maxSessionMemory;
110
- if (h2Cfg.maxConcurrentStreams) opt.settings = {
111
- ...opt.settings,
112
- maxConcurrentStreams: h2Cfg.maxConcurrentStreams
113
- };
106
+ Object.assign(opt, http2ServerLimits(this.module.options.http2));
114
107
  this.server = http2.createSecureServer(opt);
115
108
  this.httpTerminator = this.terminator();
116
- if (this.options.timeout) this.server.setTimeout(this.options.timeout, () => {
109
+ setHttp2SessionTimeout(this.server, this.options.timeout, () => {
117
110
  this.fire("onTimeout", this);
118
111
  });
119
112
  this.server.on("request", (request, response) => {
120
- let alpnProtocol = false;
121
- const sessionSocket = request.stream?.session?.socket;
122
- if (sessionSocket instanceof TLSSocket) alpnProtocol = sessionSocket.alpnProtocol;
123
- if (request.socket instanceof TLSSocket) alpnProtocol = request.socket.alpnProtocol;
124
- if (alpnProtocol === "h2") this.httpKernel.onHttpRequest(request, response, "http2");
125
- else this.httpKernel.onHttpRequest(request, response, "https");
113
+ this.httpKernel.onHttpRequest(request, response, this.type);
126
114
  });
127
115
  this.listenWithPolicy().then(() => resolve(this.server)).catch((e) => {
128
116
  const error = e instanceof Error ? e : new Error(String(e));
@@ -139,7 +127,7 @@ let ServerHttps = class ServerHttps extends Service {
139
127
  }
140
128
  });
141
129
  this.server.on("sessionError", (error) => {
142
- this.log(error, "ERROR", "HTTP2 Server sessionError");
130
+ handleSessionError(error, (e) => this.log(e, "ERROR", "HTTP2 Server sessionError"));
143
131
  });
144
132
  this.server.on("streamError", (error) => {
145
133
  this.log(error, "ERROR", "HTTP2 Server streamError");
@@ -157,6 +145,7 @@ let ServerHttps = class ServerHttps extends Service {
157
145
  * `EADDRINUSE` de repli, qui ne sont pas des pannes).
158
146
  */
159
147
  async listenWithPolicy() {
148
+ if (this.server === null) throw new Error("Server https not created");
160
149
  const { address, shiftedFrom } = await bindWithFallback(this.server, this.domain, buildBindPlan("https", asServersConfig(this.module.kernel?.options.servers), this.module.kernel?.environment));
161
150
  this.infos = address;
162
151
  this.port = address.port;
@@ -197,7 +186,6 @@ let ServerHttps = class ServerHttps extends Service {
197
186
  if (this.infos) this.log(`Server Listen on ${this.scheme}://${this.infos.address}:${this.infos.port} Family: ${this.infos.family} Protocol : ${this.protocol}`);
198
187
  }
199
188
  };
200
- ServerHttps = __decorate([__decorateParam(1, inject("HttpKernel")), __decorateMetadata("design:paramtypes", [typeof Module === "undefined" ? Object : Module, typeof http_kernel_default === "undefined" ? Object : http_kernel_default])], ServerHttps);
189
+ ServerHttps = __decorate([__decorateParam(1, Inject("HttpKernel"))], ServerHttps);
201
190
  var server_https_default = ServerHttps;
202
- //#endregion
203
191
  export { server_https_default as default };
@@ -1,4 +1,5 @@
1
1
  import { normalizePrefix } from "../../src/proxy/rules.js";
2
+ import { requestAuthority } from "../../src/context/transport.js";
2
3
  import { Service, extend } from "nodefony";
3
4
  import http from "node:http";
4
5
  import http2 from "node:http2";
@@ -8,7 +9,7 @@ import { join } from "node:path";
8
9
  import mime from "mime-types";
9
10
  import tls from "node:tls";
10
11
  import serveStatic from "serve-static";
11
- //#region nodefony/service/servers/server-static.ts
12
+ // nodefony/service/servers/server-static.ts
12
13
  const defaultOptions = {
13
14
  cacheControl: true,
14
15
  maxAge: 345600
@@ -148,7 +149,7 @@ var Statics = class extends Service {
148
149
  return scheme + "://" + host;
149
150
  } else if (request instanceof http2.Http2ServerRequest) {
150
151
  scheme = request.socket instanceof tls.TLSSocket ? "https" : "http";
151
- host = request.headers[":authority"];
152
+ host = requestAuthority(request.headers);
152
153
  return scheme + "://" + host;
153
154
  }
154
155
  throw new Error(`Bad request type`);
@@ -181,5 +182,4 @@ var Statics = class extends Service {
181
182
  return Promise.resolve(response);
182
183
  }
183
184
  };
184
- //#endregion
185
185
  export { Statics as default };
@@ -1,13 +1,11 @@
1
+ import { startHeartbeat } from "./wsHeartbeat.js";
1
2
  import { asServersConfig, configuredServerPort } from "../../src/servers/kernelServers.js";
2
- import __decorateMetadata from "../../../_virtual/_@oxc-project_runtime@0.153.0/helpers/esm/decorateMetadata.js";
3
- import __decorate from "../../../_virtual/_@oxc-project_runtime@0.153.0/helpers/esm/decorate.js";
4
- import http_kernel_default from "../http-kernel.js";
5
- import __decorateParam from "../../../_virtual/_@oxc-project_runtime@0.153.0/helpers/esm/decorateParam.js";
6
- import { startHeartbeat, trackPong } from "./wsHeartbeat.js";
3
+ import __decorate from "../../../_virtual/_@oxc-project_runtime@0.155.0/helpers/esm/decorate.js";
4
+ import __decorateParam from "../../../_virtual/_@oxc-project_runtime@0.155.0/helpers/esm/decorateParam.js";
7
5
  import { attachUpgradeDispatch } from "../../src/servers/upgradeDispatch.js";
8
- import { Module, Service, inject } from "nodefony";
6
+ import { Inject, Service } from "nodefony";
9
7
  import Ws, { WebSocketServer } from "ws";
10
- //#region nodefony/service/servers/server-websocket-secure.ts
8
+ // nodefony/service/servers/server-websocket-secure.ts
11
9
  let WebsocketSecure = class WebsocketSecure extends Service {
12
10
  httpKernel;
13
11
  module;
@@ -21,7 +19,7 @@ let WebsocketSecure = class WebsocketSecure extends Service {
21
19
  family = null;
22
20
  scheme = "wss";
23
21
  address = null;
24
- type = "websocket-secure";
22
+ type = "wss";
25
23
  infos = null;
26
24
  /** Timer keep-alive (UN par serveur). `null` si désactivé ou pas démarré. */
27
25
  heartbeatTimer = null;
@@ -52,8 +50,9 @@ let WebsocketSecure = class WebsocketSecure extends Service {
52
50
  noServer: true,
53
51
  clientTracking: true
54
52
  });
55
- this.#detachUpgrade = attachUpgradeDispatch(serverHttps.server, this.server, () => this.httpKernel.reverseProxy, (req) => this.httpKernel.websocketUpgradeRefusal(req));
56
- this.server.on("connection", this.onConnection.bind(this));
53
+ this.#detachUpgrade = attachUpgradeDispatch(serverHttps.server, this.server, () => this.httpKernel.reverseProxy, (req) => this.httpKernel.websocketUpgradeRefusal(req), (req, admission) => {
54
+ this.httpKernel.onWebsocketUpgrade(req, admission, this.type).catch(() => {});
55
+ });
57
56
  this.heartbeatTimer = startHeartbeat(this.server, this.options);
58
57
  this.kernel?.prependOnceListener("onTerminate", this.terminate.bind(this));
59
58
  this.ready = true;
@@ -65,12 +64,6 @@ let WebsocketSecure = class WebsocketSecure extends Service {
65
64
  }
66
65
  });
67
66
  }
68
- onConnection(ws, req) {
69
- trackPong(ws);
70
- this.httpKernel.onWebsocketRequest(ws, req, this.type).catch(() => {
71
- process.nextTick(() => {});
72
- });
73
- }
74
67
  terminate() {
75
68
  return new Promise((resolve, reject) => {
76
69
  if (this.heartbeatTimer) {
@@ -107,7 +100,6 @@ let WebsocketSecure = class WebsocketSecure extends Service {
107
100
  if (this.infos) this.log(`Server Listen on ${this.scheme}://${this.infos.address}:${this.infos.port} Family: ${this.infos.family} Protocol : ${this.protocol}`);
108
101
  }
109
102
  };
110
- WebsocketSecure = __decorate([__decorateParam(1, inject("HttpKernel")), __decorateMetadata("design:paramtypes", [typeof Module === "undefined" ? Object : Module, typeof http_kernel_default === "undefined" ? Object : http_kernel_default])], WebsocketSecure);
103
+ WebsocketSecure = __decorate([__decorateParam(1, Inject("HttpKernel"))], WebsocketSecure);
111
104
  var server_websocket_secure_default = WebsocketSecure;
112
- //#endregion
113
105
  export { server_websocket_secure_default as default };
@@ -1,13 +1,11 @@
1
+ import { startHeartbeat } from "./wsHeartbeat.js";
1
2
  import { asServersConfig, configuredServerPort } from "../../src/servers/kernelServers.js";
2
- import __decorateMetadata from "../../../_virtual/_@oxc-project_runtime@0.153.0/helpers/esm/decorateMetadata.js";
3
- import __decorate from "../../../_virtual/_@oxc-project_runtime@0.153.0/helpers/esm/decorate.js";
4
- import http_kernel_default from "../http-kernel.js";
5
- import __decorateParam from "../../../_virtual/_@oxc-project_runtime@0.153.0/helpers/esm/decorateParam.js";
6
- import { startHeartbeat, trackPong } from "./wsHeartbeat.js";
3
+ import __decorate from "../../../_virtual/_@oxc-project_runtime@0.155.0/helpers/esm/decorate.js";
4
+ import __decorateParam from "../../../_virtual/_@oxc-project_runtime@0.155.0/helpers/esm/decorateParam.js";
7
5
  import { attachUpgradeDispatch } from "../../src/servers/upgradeDispatch.js";
8
- import { Module, Service, inject } from "nodefony";
6
+ import { Inject, Service } from "nodefony";
9
7
  import Ws, { WebSocketServer } from "ws";
10
- //#region nodefony/service/servers/server-websocket.ts
8
+ // nodefony/service/servers/server-websocket.ts
11
9
  let Websocket = class Websocket extends Service {
12
10
  httpKernel;
13
11
  module;
@@ -21,7 +19,7 @@ let Websocket = class Websocket extends Service {
21
19
  family = null;
22
20
  scheme = "ws";
23
21
  address = null;
24
- type = "websocket";
22
+ type = "ws";
25
23
  infos = null;
26
24
  /** Timer keep-alive (UN par serveur). `null` si désactivé ou pas démarré. */
27
25
  heartbeatTimer = null;
@@ -52,8 +50,9 @@ let Websocket = class Websocket extends Service {
52
50
  noServer: true,
53
51
  clientTracking: true
54
52
  });
55
- this.#detachUpgrade = attachUpgradeDispatch(serverHttp.server, this.server, () => this.httpKernel.reverseProxy, (req) => this.httpKernel.websocketUpgradeRefusal(req));
56
- this.server.on("connection", this.onConnection.bind(this));
53
+ this.#detachUpgrade = attachUpgradeDispatch(serverHttp.server, this.server, () => this.httpKernel.reverseProxy, (req) => this.httpKernel.websocketUpgradeRefusal(req), (req, admission) => {
54
+ this.httpKernel.onWebsocketUpgrade(req, admission, this.type).catch(() => {});
55
+ });
57
56
  this.heartbeatTimer = startHeartbeat(this.server, this.options);
58
57
  this.kernel?.prependOnceListener("onTerminate", this.terminate.bind(this));
59
58
  this.ready = true;
@@ -65,12 +64,6 @@ let Websocket = class Websocket extends Service {
65
64
  }
66
65
  });
67
66
  }
68
- onConnection(ws, req) {
69
- trackPong(ws);
70
- this.httpKernel.onWebsocketRequest(ws, req, this.type).catch(() => {
71
- process.nextTick(() => {});
72
- });
73
- }
74
67
  terminate() {
75
68
  return new Promise((resolve, reject) => {
76
69
  if (this.heartbeatTimer) {
@@ -107,7 +100,6 @@ let Websocket = class Websocket extends Service {
107
100
  if (this.infos) this.log(`Server Listen on ${this.scheme}://${this.infos.address}:${this.infos.port} Family: ${this.infos.family} Protocol : ${this.protocol}`);
108
101
  }
109
102
  };
110
- Websocket = __decorate([__decorateParam(1, inject("HttpKernel")), __decorateMetadata("design:paramtypes", [typeof Module === "undefined" ? Object : Module, typeof http_kernel_default === "undefined" ? Object : http_kernel_default])], Websocket);
103
+ Websocket = __decorate([__decorateParam(1, Inject("HttpKernel"))], Websocket);
111
104
  var server_websocket_default = Websocket;
112
- //#endregion
113
105
  export { server_websocket_default as default };
@@ -1,31 +1,91 @@
1
- import { createHttpTerminator } from "http-terminator";
2
- //#region nodefony/service/servers/serverShutdown.ts
1
+ import http from "node:http";
2
+ import https from "node:https";
3
+ import tls from "node:tls";
4
+ // nodefony/service/servers/serverShutdown.ts
3
5
  /**
4
- * Fabrique le terminator de drain graceful d'un serveur HTTP/HTTPS/HTTP2.
6
+ * Fabrique l'arrêt gracieux d'un serveur HTTP/1.1, HTTPS, HTTP/2 sur TLS ou h2c.
5
7
  *
6
- * Au `terminate()` (shutdown SIGTERM/docker stop) : les requêtes in-flight se
7
- * terminent (header `connection: close` injecté sur les réponses en cours), les
8
- * sockets idle sont fermées immédiatement, et tout ce qui reste après
9
- * `shutdownTimeout` ms est détruit de force. Le terminator appelle lui-même
10
- * `server.close()` — ne pas le rappeler derrière.
8
+ * Au `terminate()` (SIGTERM, `docker stop`), le serveur cesse d'accepter, puis :
9
+ * - **HTTP/2** : chaque session reçoit un GOAWAY (`session.close()`) — les flux
10
+ * en vol se terminent, les nouveaux sont refusés, et le client sait qu'il doit
11
+ * rouvrir ailleurs au lieu de constater une coupure ;
12
+ * - **HTTP/1.1** : la réponse en vol part avec `Connection: close`, la socket
13
+ * inactive est fermée tout de suite, une requête qui arrive encore sur une
14
+ * socket gardée ouverte reçoit aussi `Connection: close`.
15
+ *
16
+ * Ce qui reste après `shutdownTimeout` ms est détruit. `server.close()` est
17
+ * appelé ici : ne pas le rappeler derrière.
11
18
  *
12
19
  * ⚠️ Les sockets WebSocket upgradées (sans réponse HTTP en cours) sont détruites
13
- * SANS frame Close par le terminator → les serveurs WS doivent fermer leurs
14
- * clients (close 1001) AVANT ce drain. Garanti par l'ordre des listeners
15
- * `onTerminate` : WS/WSS s'attachent en `prependOnceListener`, les serveurs
16
- * HTTP en `once`.
20
+ * SANS frame Close → les serveurs WS doivent fermer leurs clients (close 1001)
21
+ * AVANT ce drain. Garanti par l'ordre des listeners `onTerminate` : WS/WSS
22
+ * s'attachent en `prependOnceListener`, les serveurs HTTP en `once`.
17
23
  *
18
- * @param server - serveur Node à drainer (créé, pas forcément listening)
24
+ * @param server - serveur Node à drainer, créé AVANT son `listen` (le suivi des
25
+ * connexions commence ici)
19
26
  * @param shutdownTimeout - délai de drain en ms avant destruction forcée
20
- * @returns le terminator à invoquer au shutdown
27
+ * @returns l'arrêt à invoquer au shutdown
21
28
  */
22
29
  function createDrainTerminator(server, shutdownTimeout) {
23
- return createHttpTerminator({
24
- server,
25
- gracefulTerminationTimeout: shutdownTimeout ?? 5e3
30
+ const timeout = shutdownTimeout ?? 5e3;
31
+ const emitter = server;
32
+ const speaksHttp2 = !(server instanceof http.Server || server instanceof https.Server);
33
+ const overTls = server instanceof tls.Server;
34
+ const sockets = /* @__PURE__ */ new Set();
35
+ emitter.on("connection", (socket) => track(sockets, socket));
36
+ let http1Sockets = null;
37
+ if (!speaksHttp2) http1Sockets = overTls ? /* @__PURE__ */ new Set() : sockets;
38
+ else if (overTls) http1Sockets = /* @__PURE__ */ new Set();
39
+ if (overTls && http1Sockets !== null) {
40
+ const set = http1Sockets;
41
+ emitter.on("secureConnection", (socket) => {
42
+ if (socket.alpnProtocol !== "h2") track(set, socket);
43
+ });
44
+ }
45
+ let draining = false;
46
+ const sessions = speaksHttp2 ? /* @__PURE__ */ new Set() : null;
47
+ if (sessions !== null) emitter.on("session", (session) => {
48
+ if (draining) {
49
+ session.close();
50
+ return;
51
+ }
52
+ sessions.add(session);
53
+ session.once("close", () => sessions.delete(session));
54
+ });
55
+ let terminating = null;
56
+ const drain = () => new Promise((resolve) => {
57
+ draining = true;
58
+ const deadline = setTimeout(() => {
59
+ if (sessions !== null) for (const s of sessions) s.destroy();
60
+ for (const socket of sockets) socket.destroy();
61
+ }, timeout);
62
+ server.close(() => {
63
+ clearTimeout(deadline);
64
+ resolve();
65
+ });
66
+ if (sessions !== null) for (const s of sessions) s.close();
67
+ if (http1Sockets !== null) {
68
+ emitter.on("request", closeAfterResponse);
69
+ for (const socket of http1Sockets) {
70
+ const response = socket._httpMessage;
71
+ if (!response) socket.destroy();
72
+ else if (!response.headersSent) response.setHeader("connection", "close");
73
+ }
74
+ }
26
75
  });
76
+ return { terminate() {
77
+ terminating ??= drain();
78
+ return terminating;
79
+ } };
80
+ }
81
+ function track(set, socket) {
82
+ set.add(socket);
83
+ socket.once("close", () => set.delete(socket));
84
+ }
85
+ /** Requête HTTP/1.1 reçue pendant le drain : la connexion ne survivra pas à sa réponse. */
86
+ function closeAfterResponse(request, response) {
87
+ if (request.httpVersionMajor === 1 && !response.headersSent) response.setHeader("connection", "close");
27
88
  }
28
89
  /** Drain par défaut (ms) — même valeur que le défaut Zod `servers.*.shutdownTimeout`. */
29
90
  const DEFAULT_SHUTDOWN_TIMEOUT = 5e3;
30
- //#endregion
31
91
  export { DEFAULT_SHUTDOWN_TIMEOUT, createDrainTerminator };
@@ -1,5 +1,5 @@
1
1
  import Ws from "ws";
2
- //#region nodefony/service/servers/wsHeartbeat.ts
2
+ // nodefony/service/servers/wsHeartbeat.ts
3
3
  /**
4
4
  * Arme le suivi keep-alive d'UNE connexion : initialise l'horodatage de vie et
5
5
  * attache l'unique listener `pong` qui le rafraîchit.
@@ -76,5 +76,4 @@ const startHeartbeat = (server, options) => {
76
76
  timer.unref();
77
77
  return timer;
78
78
  };
79
- //#endregion
80
79
  export { heartbeatTick, startHeartbeat, trackPong };
@@ -1,14 +1,12 @@
1
1
  import { SESSION_FACETS } from "../../src/session/storage/sessionFilters.js";
2
- import __decorateMetadata from "../../../_virtual/_@oxc-project_runtime@0.153.0/helpers/esm/decorateMetadata.js";
3
- import __decorate from "../../../_virtual/_@oxc-project_runtime@0.153.0/helpers/esm/decorate.js";
4
- import http_kernel_default from "../http-kernel.js";
5
- import __decorateParam from "../../../_virtual/_@oxc-project_runtime@0.153.0/helpers/esm/decorateParam.js";
2
+ import __decorate from "../../../_virtual/_@oxc-project_runtime@0.155.0/helpers/esm/decorate.js";
3
+ import __decorateParam from "../../../_virtual/_@oxc-project_runtime@0.155.0/helpers/esm/decorateParam.js";
6
4
  import Session from "../../src/session/session.js";
7
5
  import MemorySessionStorage from "../../src/session/storage/MemorySessionStorage.js";
8
6
  import RevocationGuardStorage from "../../src/session/storage/RevocationGuardStorage.js";
9
- import { AUTO_STORE, EMPTY_INFRA, GcScheduler, Module, Nodefony, RequestContext, Service, countFacets, extend, inject, injectable, readStoreConnector, readStoreLocation, resolveAutoStore, runNeedsExternalServices } from "nodefony";
7
+ import { AUTO_STORE, EMPTY_INFRA, GcScheduler, Inject, Nodefony, RequestContext, Service, countFacets, extend, injectable, readStoreConnector, readStoreLocation, resolveAutoStore, storeConnectivity } from "nodefony";
10
8
  import { createHash, createHmac } from "node:crypto";
11
- //#region nodefony/service/sessions/sessions-service.ts
9
+ // nodefony/service/sessions/sessions-service.ts
12
10
  var _SessionsService;
13
11
  /**
14
12
  * Convertit un timestamp de session (`Date` en mémoire, **string ISO** après
@@ -143,7 +141,7 @@ let SessionsService = class SessionsService extends Service {
143
141
  const configured = storeName;
144
142
  let reason = `store explicitement configuré ("${configured}")`;
145
143
  if (storeName === AUTO_STORE) {
146
- const auto = resolveAutoStore("session", this.kernel?.infra ?? EMPTY_INFRA, _SessionsService.storageHandlers(), "memory", runNeedsExternalServices(this.kernel));
144
+ const auto = resolveAutoStore("session", this.kernel?.infra ?? EMPTY_INFRA, _SessionsService.storageHandlers(), "memory", storeConnectivity(this.kernel));
147
145
  storeName = auto.store;
148
146
  reason = auto.reason;
149
147
  this.log(`session.store "auto" → "${storeName}" (${auto.reason})`, "INFO");
@@ -219,7 +217,7 @@ let SessionsService = class SessionsService extends Service {
219
217
  return resolve(context.session);
220
218
  }
221
219
  }
222
- let inst = null;
220
+ let inst;
223
221
  try {
224
222
  context.sessionStarting = true;
225
223
  inst = this.createSession(this.defaultSessionName);
@@ -598,12 +596,7 @@ let SessionsService = class SessionsService extends Service {
598
596
  this.get("auditService")?.record(event);
599
597
  }
600
598
  };
601
- SessionsService = _SessionsService = __decorate([
602
- injectable(),
603
- __decorateParam(1, inject("HttpKernel")),
604
- __decorateMetadata("design:paramtypes", [typeof Module === "undefined" ? Object : Module, typeof http_kernel_default === "undefined" ? Object : http_kernel_default])
605
- ], SessionsService);
599
+ SessionsService = _SessionsService = __decorate([injectable(), __decorateParam(1, Inject("HttpKernel"))], SessionsService);
606
600
  SessionsService.registerStorage("memory", MemorySessionStorage);
607
601
  var sessions_service_default = SessionsService;
608
- //#endregion
609
602
  export { computeSessionRef, sessions_service_default as default, toSessionSummary };
@@ -1,5 +1,5 @@
1
1
  import { randomFillSync } from "node:crypto";
2
- //#region nodefony/service/trace.ts
2
+ // nodefony/service/trace.ts
3
3
  /**
4
4
  * W3C Trace Context — parse + generate `traceparent` headers (P2.7).
5
5
  *
@@ -69,5 +69,4 @@ function resolveTraceparent(header) {
69
69
  const hex = randomHex(24);
70
70
  return `00-${hex.slice(0, 32)}-${hex.slice(32)}-01`;
71
71
  }
72
- //#endregion
73
72
  export { parseTraceparent, resolveTraceparent };
@@ -1,12 +1,10 @@
1
- import __decorateMetadata from "../../../_virtual/_@oxc-project_runtime@0.153.0/helpers/esm/decorateMetadata.js";
2
- import __decorate from "../../../_virtual/_@oxc-project_runtime@0.153.0/helpers/esm/decorate.js";
3
- import http_kernel_default from "../http-kernel.js";
4
- import __decorateParam from "../../../_virtual/_@oxc-project_runtime@0.153.0/helpers/esm/decorateParam.js";
5
- import { Cli, FileClass, Module, Service, inject } from "nodefony";
1
+ import __decorate from "../../../_virtual/_@oxc-project_runtime@0.155.0/helpers/esm/decorate.js";
2
+ import __decorateParam from "../../../_virtual/_@oxc-project_runtime@0.155.0/helpers/esm/decorateParam.js";
3
+ import { Cli, FileClass, Inject, Service } from "nodefony";
6
4
  import fs from "node:fs";
7
5
  import fsp from "node:fs/promises";
8
6
  import path from "node:path";
9
- //#region nodefony/service/upload/upload-service.ts
7
+ // nodefony/service/upload/upload-service.ts
10
8
  /** Test d'existence non bloquant (`fsp.access`) — remplace `existsSync`. */
11
9
  const existsAsync = async (p) => {
12
10
  try {
@@ -58,7 +56,7 @@ let upload = class upload extends Service {
58
56
  throw new Error(`Syslog not ready`);
59
57
  }
60
58
  };
61
- upload = __decorate([__decorateParam(1, inject("HttpKernel")), __decorateMetadata("design:paramtypes", [typeof Module === "undefined" ? Object : Module, typeof http_kernel_default === "undefined" ? Object : http_kernel_default])], upload);
59
+ upload = __decorate([__decorateParam(1, Inject("HttpKernel"))], upload);
62
60
  var UploadedFile = class UploadedFile extends FileClass {
63
61
  parsedFile;
64
62
  size;
@@ -168,5 +166,4 @@ var UploadedFile = class UploadedFile extends FileClass {
168
166
  }
169
167
  };
170
168
  var upload_service_default = upload;
171
- //#endregion
172
169
  export { UploadedFile, upload_service_default as default, upload };
@@ -1,6 +1,6 @@
1
1
  import { isIPv4, isIPv6 } from "node:net";
2
2
  import { createHash, sign } from "node:crypto";
3
- //#region nodefony/service/x509.ts
3
+ // nodefony/service/x509.ts
4
4
  /**
5
5
  * Fabrique et lecture de certificats X.509 par `node:crypto` seul — aucune
6
6
  * dépendance tierce.
@@ -320,5 +320,4 @@ async function createSelfSignedCertificate(spec) {
320
320
  const signature = await signAsync(spec.hash, tbs, spec.privateKey);
321
321
  return toPem(sequence(tbs, algorithm, bitString(signature)));
322
322
  }
323
- //#endregion
324
323
  export { SHA1_WITH_RSA_OID, createSelfSignedCertificate, distinguishedNameField, ipAddressBytes, parseSubjectAltName, signatureAlgorithmName, signatureAlgorithmOid };
@@ -1,6 +1,6 @@
1
1
  import { stripTrailingSlashes } from "nodefony";
2
2
  import { join } from "node:path";
3
- //#region nodefony/src/assets/collectAssets.ts
3
+ // nodefony/src/assets/collectAssets.ts
4
4
  /** Normalise un préfixe en segment de chemin (`/_assets/x/` → `_assets/x`). */
5
5
  const prefixToSegment = (prefix) => stripTrailingSlashes(prefix.replace(/^\/+/, ""));
6
6
  /**
@@ -30,5 +30,4 @@ function planAssetPublish(sources, outDir) {
30
30
  }
31
31
  return plan;
32
32
  }
33
- //#endregion
34
33
  export { planAssetPublish };
@@ -1,6 +1,6 @@
1
1
  import fs from "node:fs";
2
2
  import path from "node:path";
3
- //#region nodefony/src/assets/prebuiltUi.ts
3
+ // nodefony/src/assets/prebuiltUi.ts
4
4
  /**
5
5
  * Résout le mode de livraison de l'UI embarquée d'un module.
6
6
  *
@@ -121,5 +121,4 @@ var PrebuiltUi = class {
121
121
  return this.template.replaceAll("<script", `<script nonce="${nonce}"`);
122
122
  }
123
123
  };
124
- //#endregion
125
124
  export { PrebuiltUi, resolveUiDelivery };
@@ -1,18 +1,13 @@
1
1
  import { buildMetaData } from "./metaData.js";
2
+ import { protocolNameOf } from "./transport.js";
2
3
  import Cookie, { cookiesParser } from "../cookies/cookie.js";
3
4
  import { RequestContext, Service, logColor } from "nodefony";
4
5
  import { randomFillSync, randomUUID } from "node:crypto";
5
6
  import { performance } from "node:perf_hooks";
6
7
  import { AsyncResource } from "node:async_hooks";
7
- //#region nodefony/src/context/Context.ts
8
+ // nodefony/src/context/Context.ts
8
9
  const colorLogEvent = () => logColor.cyanBgBlack("EVENT CONTEXT");
9
10
  const PERF_PROBE_SUB = process.env.NF_PERF_PROBE === "1";
10
- const EVENT_SEVERITY = {
11
- onRequest: "INFO",
12
- onSend: "INFO",
13
- onConnect: "INFO",
14
- onClose: "INFO"
15
- };
16
11
  let lifecycleEventLogging = null;
17
12
  /**
18
13
  * Bascule runtime du gate des logs d'events lifecycle. Réservé HORS hot path :
@@ -54,7 +49,15 @@ var Context = class extends Service {
54
49
  requested = false;
55
50
  sessionStarting = false;
56
51
  domain = "";
52
+ /** Famille traitée (`network.protocol.name` d'OpenTelemetry) — union ouverte. */
57
53
  type;
54
+ /** Serveur qui a reçu la requête — choisit la configuration par serveur. */
55
+ serverType;
56
+ /**
57
+ * Protocole du saut local (registre IANA ALPN) — union ouverte. Une connexion
58
+ * WebSocket naît d'un upgrade HTTP/1.1 ; `HttpContext` le constate sur la requête.
59
+ */
60
+ alpnProtocol = "http/1.1";
58
61
  server;
59
62
  httpKernel;
60
63
  request = null;
@@ -148,13 +151,14 @@ var Context = class extends Service {
148
151
  };
149
152
  scheme;
150
153
  webSocketState = null;
151
- constructor(container, type) {
152
- super(type, container);
154
+ constructor(container, serverType) {
155
+ super(serverType, container);
153
156
  if (PERF_PROBE_SUB) {
154
157
  const p = globalThis.__nfPerfProbe;
155
158
  if (p && p.t0 !== 0n) p.svcNs += Number(process.hrtime.bigint() - p.t0);
156
159
  }
157
- this.type = type;
160
+ this.serverType = serverType;
161
+ this.type = protocolNameOf(serverType);
158
162
  this.set("context", this);
159
163
  this.httpKernel = this.get("HttpKernel");
160
164
  this.sessionService = this.get("sessions");
@@ -167,35 +171,24 @@ var Context = class extends Service {
167
171
  const verbose = (this.kernel?.options)?.timing?.verbose;
168
172
  this._timingVerbose = verbose === true;
169
173
  }
170
- this.scheme = "https";
171
- switch (this.type) {
174
+ this.scheme = serverType;
175
+ switch (serverType) {
172
176
  case "http": {
173
- this.scheme = "http";
174
177
  const server = this.get("server-http");
175
178
  this.server = server?.server;
176
179
  break;
177
180
  }
178
- case "http2":
179
181
  case "https": {
180
- this.scheme = "https";
181
182
  const server = this.get("server-https");
182
183
  this.server = server?.server;
183
184
  break;
184
185
  }
185
- case "http3": {
186
- this.scheme = "https";
187
- const server = this.get("server-http3");
188
- this.server = server?.server ?? null;
189
- break;
190
- }
191
- case "websocket": {
192
- this.scheme = "ws";
186
+ case "ws": {
193
187
  const server = this.get("server-websocket");
194
188
  this.server = server?.server;
195
189
  break;
196
190
  }
197
- case "websocket-secure": {
198
- this.scheme = "wss";
191
+ case "wss": {
199
192
  const server = this.get("server-websocket-secure");
200
193
  this.server = server?.server;
201
194
  break;
@@ -304,7 +297,7 @@ var Context = class extends Service {
304
297
  if (this._abortController && !this._abortController.signal.aborted) this._abortController.abort(new Error(reason ?? "Context aborted"));
305
298
  }
306
299
  log(pci, severity, msgid, msg) {
307
- if (!msgid) msgid = this.type;
300
+ if (!msgid) msgid = this.serverType;
308
301
  if (this.requestId && RequestContext.getRequestId() === void 0) return RequestContext.run({ requestId: this.requestId }, () => super.log(pci, severity, msgid, msg));
309
302
  return super.log(pci, severity, msgid, msg);
310
303
  }
@@ -334,13 +327,13 @@ var Context = class extends Service {
334
327
  }
335
328
  /**
336
329
  * Log d'un event du cycle de vie — gate boot-time (V2.1) : en production le
337
- * Pdu n'est PAS construit (return avant toute allocation). Hors prod, jalon
338
- * notable → INFO (EVENT_SEVERITY), event technique → DEBUG.
330
+ * Pdu n'est PAS construit (return avant toute allocation). Hors prod : DEBUG,
331
+ * pour le Suivi de requête de Studio — la ligne `req` porte le bilan.
339
332
  */
340
333
  logEvent(event) {
341
334
  lifecycleEventLogging ??= this.kernel?.environment !== "production";
342
335
  if (!lifecycleEventLogging) return;
343
- this.log(`${colorLogEvent()} ${event}`, EVENT_SEVERITY[event] || "DEBUG");
336
+ this.log(`${colorLogEvent()} ${event}`, "DEBUG");
344
337
  }
345
338
  fire(event, ...args) {
346
339
  this.logEvent(event);
@@ -394,7 +387,7 @@ var Context = class extends Service {
394
387
  } else line += `${p.name}=…`;
395
388
  i++;
396
389
  }
397
- this.log(`TRACE phases [Σ ${total.toFixed(2)}ms] ${line}`, "DEBUG", `${this.type} TIMING`);
390
+ this.log(`TRACE phases [Σ ${total.toFixed(2)}ms] ${line}`, "DEBUG", `${this.serverType} TIMING`);
398
391
  }
399
392
  addRequestCookie(cookie) {
400
393
  if (cookie instanceof Cookie) return this.cookies[cookie.name] = cookie;
@@ -453,5 +446,4 @@ var Context = class extends Service {
453
446
  setContextJson(_encoding = "utf-8") {}
454
447
  setContextHtml(_encoding = "utf-8") {}
455
448
  };
456
- //#endregion
457
449
  export { Context as default, nextCspNonce, setLifecycleEventLogging };
@@ -1,5 +1,5 @@
1
1
  import { escapeRegExp } from "nodefony";
2
- //#region nodefony/src/context/domainMatcher.ts
2
+ // nodefony/src/context/domainMatcher.ts
3
3
  /**
4
4
  * Matching de domaine (`Host`) — fonctions PURES, politique UNIQUE partagée par
5
5
  * les deux étages de Nodefony :
@@ -135,5 +135,4 @@ function isDomainAllowed(regAlias, domain) {
135
135
  for (const reg of regAlias) if (reg.test(domain)) return true;
136
136
  return false;
137
137
  }
138
- //#endregion
139
138
  export { compileDomainPattern, compileDomainPatterns, compileTrustedHosts, hostnameOf, isDomainAllowed, resolveTrustedHostNames };