@nodefony/http 10.0.0-beta.2 → 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 (139) hide show
  1. package/dist/_virtual/{_@oxc-project_runtime@0.152.0 → _@oxc-project_runtime@0.155.0}/helpers/esm/decorate.js +1 -2
  2. package/dist/_virtual/{_@oxc-project_runtime@0.152.0 → _@oxc-project_runtime@0.155.0}/helpers/esm/decorateParam.js +1 -2
  3. package/dist/index.js +19 -11
  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 +45 -6
  9. package/dist/nodefony/config/defineModuleConfig.js +2 -3
  10. package/dist/nodefony/interfaces/IReverseProxy.js +1 -0
  11. package/dist/nodefony/service/HttpAdminApi.js +2 -3
  12. package/dist/nodefony/service/ProfilerAdminApi.js +1 -2
  13. package/dist/nodefony/service/audit-logger.js +22 -16
  14. package/dist/nodefony/service/certificates.js +228 -19
  15. package/dist/nodefony/service/error-renderer.js +30 -13
  16. package/dist/nodefony/service/http-kernel.js +331 -82
  17. package/dist/nodefony/service/pretty-request-logger.js +5 -4
  18. package/dist/nodefony/service/request-logger.js +24 -16
  19. package/dist/nodefony/service/reverse-proxy.js +336 -0
  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 +7 -10
  25. package/dist/nodefony/service/servers/server-websocket-secure.js +18 -18
  26. package/dist/nodefony/service/servers/server-websocket.js +18 -18
  27. package/dist/nodefony/service/servers/serverShutdown.js +78 -18
  28. package/dist/nodefony/service/servers/wsHeartbeat.js +32 -17
  29. package/dist/nodefony/service/sessions/sessions-service.js +34 -20
  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 +51 -32
  36. package/dist/nodefony/src/context/domainMatcher.js +21 -4
  37. package/dist/nodefony/src/context/forwarded.js +3 -4
  38. package/dist/nodefony/src/context/http/HttpContext.js +98 -46
  39. package/dist/nodefony/src/context/http/Request.js +34 -38
  40. package/dist/nodefony/src/context/http/Response.js +39 -7
  41. package/dist/nodefony/src/context/http/SseStream.js +349 -0
  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 +22 -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/responseEnded.js +26 -0
  49. package/dist/nodefony/src/context/transport.js +45 -0
  50. package/dist/nodefony/src/context/trustProxy.js +1 -2
  51. package/dist/nodefony/src/context/websocket/Response.js +42 -6
  52. package/dist/nodefony/src/context/websocket/WebsocketContext.js +94 -20
  53. package/dist/nodefony/src/context/websocket/isWebsocketContext.js +17 -0
  54. package/dist/nodefony/src/context/websocket/websocketUrl.js +20 -0
  55. package/dist/nodefony/src/context/websocket/wsBackpressure.js +1 -2
  56. package/dist/nodefony/src/context/websocket/wsCloseReason.js +1 -2
  57. package/dist/nodefony/src/context/websocket/wsLogContent.js +1 -2
  58. package/dist/nodefony/src/cookies/cookie.js +3 -7
  59. package/dist/nodefony/src/errors/httpError.js +1 -2
  60. package/dist/nodefony/src/errors/thrownMessage.js +1 -2
  61. package/dist/nodefony/src/profiler/FrameProfile.js +1 -2
  62. package/dist/nodefony/src/profiler/Profiler.js +108 -30
  63. package/dist/nodefony/src/profiler/aggregate.js +422 -0
  64. package/dist/nodefony/src/proxy/forward.js +500 -0
  65. package/dist/nodefony/src/proxy/generateProxyConfig.js +14 -6
  66. package/dist/nodefony/src/proxy/rules.js +188 -0
  67. package/dist/nodefony/src/rateLimit/MemoryRateLimitStore.js +1 -2
  68. package/dist/nodefony/src/rateLimit/WsConnectionCounter.js +1 -2
  69. package/dist/nodefony/src/rateLimit/rateLimitFilters.js +1 -2
  70. package/dist/nodefony/src/servers/http2Limits.js +50 -0
  71. package/dist/nodefony/src/servers/kernelServers.js +12 -3
  72. package/dist/nodefony/src/servers/portBinder.js +41 -10
  73. package/dist/nodefony/src/servers/upgradeDispatch.js +128 -0
  74. package/dist/nodefony/src/session/session.js +30 -15
  75. package/dist/nodefony/src/session/sessionStoreFailure.js +1 -2
  76. package/dist/nodefony/src/session/storage/MemorySessionStorage.js +1 -2
  77. package/dist/nodefony/src/session/storage/RevocationGuardStorage.js +1 -2
  78. package/dist/nodefony/src/session/storage/sessionFilters.js +1 -2
  79. package/dist/nodefony/src/session/storage/sessionSort.js +1 -2
  80. package/dist/types/index.d.ts +12 -3
  81. package/dist/types/nodefony/config/config.d.ts +16 -0
  82. package/dist/types/nodefony/interfaces/IContext.d.ts +65 -4
  83. package/dist/types/nodefony/interfaces/IErrorRenderer.d.ts +1 -1
  84. package/dist/types/nodefony/interfaces/IRequest.d.ts +9 -4
  85. package/dist/types/nodefony/interfaces/IReverseProxy.d.ts +67 -0
  86. package/dist/types/nodefony/interfaces/IRouting.d.ts +26 -0
  87. package/dist/types/nodefony/interfaces/ISecurity.d.ts +6 -0
  88. package/dist/types/nodefony/interfaces/index.d.ts +3 -2
  89. package/dist/types/nodefony/service/audit-logger.d.ts +2 -1
  90. package/dist/types/nodefony/service/certificates.d.ts +147 -5
  91. package/dist/types/nodefony/service/error-renderer.d.ts +32 -1
  92. package/dist/types/nodefony/service/http-kernel.d.ts +157 -15
  93. package/dist/types/nodefony/service/reverse-proxy.d.ts +156 -0
  94. package/dist/types/nodefony/service/servers/clientError.d.ts +16 -0
  95. package/dist/types/nodefony/service/servers/server-h2c.d.ts +51 -0
  96. package/dist/types/nodefony/service/servers/server-http.d.ts +3 -3
  97. package/dist/types/nodefony/service/servers/server-https.d.ts +4 -4
  98. package/dist/types/nodefony/service/servers/server-websocket-secure.d.ts +2 -3
  99. package/dist/types/nodefony/service/servers/server-websocket.d.ts +2 -3
  100. package/dist/types/nodefony/service/servers/serverShutdown.d.ts +30 -16
  101. package/dist/types/nodefony/service/servers/wsHeartbeat.d.ts +26 -0
  102. package/dist/types/nodefony/service/sessions/sessions-service.d.ts +19 -1
  103. package/dist/types/nodefony/src/context/Context.d.ts +35 -6
  104. package/dist/types/nodefony/src/context/domainMatcher.d.ts +11 -1
  105. package/dist/types/nodefony/src/context/http/HttpContext.d.ts +48 -1
  106. package/dist/types/nodefony/src/context/http/Request.d.ts +20 -15
  107. package/dist/types/nodefony/src/context/http/Response.d.ts +14 -0
  108. package/dist/types/nodefony/src/context/http/SseStream.d.ts +155 -0
  109. package/dist/types/nodefony/src/context/http/parser.d.ts +18 -2
  110. package/dist/types/nodefony/src/context/http2/Request.d.ts +1 -1
  111. package/dist/types/nodefony/src/context/http2/Response.d.ts +15 -5
  112. package/dist/types/nodefony/src/context/responseEnded.d.ts +20 -0
  113. package/dist/types/nodefony/src/context/transport.d.ts +53 -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 +57 -7
  116. package/dist/types/nodefony/src/context/websocket/isWebsocketContext.d.ts +15 -0
  117. package/dist/types/nodefony/src/context/websocket/websocketUrl.d.ts +16 -0
  118. package/dist/types/nodefony/src/profiler/FrameProfile.d.ts +13 -12
  119. package/dist/types/nodefony/src/profiler/Profiler.d.ts +69 -15
  120. package/dist/types/nodefony/src/profiler/aggregate.d.ts +215 -0
  121. package/dist/types/nodefony/src/proxy/forward.d.ts +168 -0
  122. package/dist/types/nodefony/src/proxy/generateProxyConfig.d.ts +16 -0
  123. package/dist/types/nodefony/src/proxy/rules.d.ts +88 -0
  124. package/dist/types/nodefony/src/servers/http2Limits.d.ts +37 -0
  125. package/dist/types/nodefony/src/servers/kernelServers.d.ts +10 -1
  126. package/dist/types/nodefony/src/servers/portBinder.d.ts +29 -5
  127. package/dist/types/nodefony/src/servers/upgradeDispatch.d.ts +69 -0
  128. package/dist/types/nodefony/src/session/session.d.ts +2 -0
  129. package/docs/cookies.md +85 -78
  130. package/docs/index.md +5 -1
  131. package/docs/observabilite.md +81 -81
  132. package/docs/rate-limit.md +83 -83
  133. package/docs/reverse-proxy.md +522 -0
  134. package/docs/servers.md +378 -230
  135. package/docs/session.md +180 -180
  136. package/docs/sse.md +287 -0
  137. package/docs/upload.md +120 -117
  138. package/package.json +10 -11
  139. package/dist/_virtual/_@oxc-project_runtime@0.152.0/helpers/esm/decorateMetadata.js +0 -6
@@ -1,9 +1,8 @@
1
- //#region \0@oxc-project+runtime@0.152.0/helpers/esm/decorate.js
1
+ // \0@oxc-project+runtime@0.155.0/helpers/esm/decorate.js
2
2
  function __decorate(decorators, target, key, desc) {
3
3
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
4
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
5
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
6
  return c > 3 && r && Object.defineProperty(target, key, r), r;
7
7
  }
8
- //#endregion
9
8
  export { __decorate as default };
@@ -1,8 +1,7 @@
1
- //#region \0@oxc-project+runtime@0.152.0/helpers/esm/decorateParam.js
1
+ // \0@oxc-project+runtime@0.155.0/helpers/esm/decorateParam.js
2
2
  function __decorateParam(paramIndex, decorator) {
3
3
  return function(target, key) {
4
4
  decorator(target, key, paramIndex);
5
5
  };
6
6
  }
7
- //#endregion
8
7
  export { __decorateParam as default };
package/dist/index.js CHANGED
@@ -1,7 +1,9 @@
1
+ import { normalizePrefix, parseProxyOrigin, proxyMountProblems } from "./nodefony/src/proxy/rules.js";
1
2
  import config, { httpConfigSchema, httpOverlaySchema } from "./nodefony/config/config.js";
2
3
  import { defineHttpConfig, httpConfigJsonSchema } from "./nodefony/config/defineModuleConfig.js";
3
4
  import { createHttpAdminApi } from "./nodefony/service/HttpAdminApi.js";
4
5
  import { createProfilerAdminApi } from "./nodefony/service/ProfilerAdminApi.js";
6
+ import { ACTION_SELF_PHASE, NO_ROUTE, N_PLUS_ONE_MIN_REPEATS, TOOLING_URL_PREFIX, aggregateProfiles, createProfileAggregator, isFailedProfile, sqlShape } from "./nodefony/src/profiler/aggregate.js";
5
7
  import { Profiler } from "./nodefony/src/profiler/Profiler.js";
6
8
  import HttpError from "./nodefony/src/errors/httpError.js";
7
9
  import { MemoryRateLimitStore } from "./nodefony/src/rateLimit/MemoryRateLimitStore.js";
@@ -16,19 +18,21 @@ import HttpRequest from "./nodefony/src/context/http/Request.js";
16
18
  import HttpResponse from "./nodefony/src/context/http/Response.js";
17
19
  import Http2Request from "./nodefony/src/context/http2/Request.js";
18
20
  import Http2Response from "./nodefony/src/context/http2/Response.js";
21
+ import { SSE_HEARTBEAT_MS, SseStream, acceptsEventStream, openSseStream } from "./nodefony/src/context/http/SseStream.js";
19
22
  import HttpContext from "./nodefony/src/context/http/HttpContext.js";
20
- import DefaultErrorRenderer, { schemaMismatchOf } from "./nodefony/service/error-renderer.js";
21
- import DefaultRequestLogger from "./nodefony/service/request-logger.js";
23
+ import DefaultErrorRenderer, { schemaMismatchOf, toValidationFields } from "./nodefony/service/error-renderer.js";
22
24
  import JsonAuditLogger from "./nodefony/service/audit-logger.js";
25
+ import DefaultRequestLogger from "./nodefony/service/request-logger.js";
23
26
  import PrettyRequestLogger from "./nodefony/service/pretty-request-logger.js";
24
- import __decorateMetadata from "./_virtual/_@oxc-project_runtime@0.152.0/helpers/esm/decorateMetadata.js";
25
- import __decorate from "./_virtual/_@oxc-project_runtime@0.152.0/helpers/esm/decorate.js";
27
+ import __decorate from "./_virtual/_@oxc-project_runtime@0.155.0/helpers/esm/decorate.js";
26
28
  import http_kernel_default from "./nodefony/service/http-kernel.js";
27
29
  import server_http_default from "./nodefony/service/servers/server-http.js";
28
30
  import server_https_default from "./nodefony/service/servers/server-https.js";
31
+ import server_h2c_default from "./nodefony/service/servers/server-h2c.js";
29
32
  import server_websocket_default from "./nodefony/service/servers/server-websocket.js";
30
33
  import server_websocket_secure_default from "./nodefony/service/servers/server-websocket-secure.js";
31
34
  import Statics from "./nodefony/service/servers/server-static.js";
35
+ import ReverseProxy from "./nodefony/service/reverse-proxy.js";
32
36
  import Network from "./nodefony/command/networkCommand.js";
33
37
  import Certificates from "./nodefony/command/certificatesCommand.js";
34
38
  import ProxyGenerate from "./nodefony/command/proxyGenerateCommand.js";
@@ -36,11 +40,12 @@ import AssetsPublish from "./nodefony/command/assetsPublishCommand.js";
36
40
  import Session from "./nodefony/src/session/session.js";
37
41
  import { SESSION_COLUMN_ALIASES, SESSION_DEFAULT_ORDER, SESSION_DEFAULT_ORDER_SQL, SESSION_SORTABLE_FIELDS } from "./nodefony/src/session/storage/sessionSort.js";
38
42
  import sessions_service_default from "./nodefony/service/sessions/sessions-service.js";
39
- import Certificate from "./nodefony/service/certificates.js";
43
+ import Certificate, { trustOutboundAuthorities } from "./nodefony/service/certificates.js";
40
44
  import upload_service_default from "./nodefony/service/upload/upload-service.js";
45
+ import { isWebsocketContext } from "./nodefony/src/context/websocket/isWebsocketContext.js";
41
46
  import { PrebuiltUi, resolveUiDelivery } from "./nodefony/src/assets/prebuiltUi.js";
42
- import { Kernel, Module, services } from "nodefony";
43
- //#region index.ts
47
+ import { Module, services } from "nodefony";
48
+ // index.ts
44
49
  let Http = class Http extends Module {
45
50
  overlaySchema = httpOverlaySchema;
46
51
  constructor(kernel) {
@@ -70,7 +75,9 @@ let Http = class Http extends Module {
70
75
  */
71
76
  async onKernelRegister() {
72
77
  const input = this.options;
73
- this.options = defineHttpConfig(input ?? {}, this.kernel);
78
+ const options = defineHttpConfig(input ?? {}, this.kernel);
79
+ this.options = options;
80
+ await trustOutboundAuthorities(options.certificates.extraCaFiles, this.kernel?.path ?? process.cwd(), (message, severity) => this.log(message, severity), { development: this.kernel?.environment === "development" });
74
81
  return this;
75
82
  }
76
83
  /**
@@ -99,12 +106,13 @@ Http = __decorate([services([
99
106
  Certificate,
100
107
  sessions_service_default,
101
108
  Statics,
109
+ ReverseProxy,
102
110
  server_http_default,
103
111
  server_https_default,
112
+ server_h2c_default,
104
113
  server_websocket_default,
105
114
  server_websocket_secure_default,
106
115
  upload_service_default
107
- ]), __decorateMetadata("design:paramtypes", [typeof Kernel === "undefined" ? Object : Kernel])], Http);
116
+ ])], Http);
108
117
  var http_default = Http;
109
- //#endregion
110
- export { Context, Cookie, DefaultErrorRenderer, DefaultRequestLogger, FrameProfile, Http2Request, Http2Response, HttpContext, HttpError, http_kernel_default as HttpKernel, HttpRequest, HttpResponse, HttpResponse as Response, JsonAuditLogger, MemoryRateLimitStore, PrebuiltUi, PrettyRequestLogger, Profiler, SESSION_COLUMN_ALIASES, SESSION_DEFAULT_ORDER, SESSION_DEFAULT_ORDER_SQL, SESSION_SORTABLE_FIELDS, Session, sessions_service_default as SessionsService, WebsocketContext, WebsocketResponse, WebsocketResponse as wsResponse, compileDomainPattern, compileDomainPatterns, compileTrustedHosts, decideSend, http_default as default, defineHttpConfig, httpConfigJsonSchema, httpConfigSchema, isDomainAllowed, readBackpressureOptions, resolveUiDelivery, schemaMismatchOf };
118
+ export { ACTION_SELF_PHASE, Context, Cookie, DefaultErrorRenderer, DefaultRequestLogger, FrameProfile, Http2Request, Http2Response, HttpContext, HttpError, http_kernel_default as HttpKernel, HttpRequest, HttpResponse, HttpResponse as Response, JsonAuditLogger, MemoryRateLimitStore, NO_ROUTE, N_PLUS_ONE_MIN_REPEATS, PrebuiltUi, PrettyRequestLogger, Profiler, ReverseProxy, SESSION_COLUMN_ALIASES, SESSION_DEFAULT_ORDER, SESSION_DEFAULT_ORDER_SQL, SESSION_SORTABLE_FIELDS, SSE_HEARTBEAT_MS, Session, sessions_service_default as SessionsService, SseStream, TOOLING_URL_PREFIX, WebsocketContext, WebsocketResponse, WebsocketResponse as wsResponse, acceptsEventStream, aggregateProfiles, compileDomainPattern, compileDomainPatterns, compileTrustedHosts, createProfileAggregator, decideSend, http_default as default, defineHttpConfig, httpConfigJsonSchema, httpConfigSchema, isDomainAllowed, isFailedProfile, isWebsocketContext, normalizePrefix, openSseStream, parseProxyOrigin, proxyMountProblems, readBackpressureOptions, resolveUiDelivery, schemaMismatchOf, sqlShape, toValidationFields };
@@ -3,7 +3,7 @@ import { Command } from "nodefony";
3
3
  import { existsSync } from "node:fs";
4
4
  import fsp from "node:fs/promises";
5
5
  import { isAbsolute, join, resolve } from "node:path";
6
- //#region nodefony/command/assetsPublishCommand.ts
6
+ // nodefony/command/assetsPublishCommand.ts
7
7
  const options = {
8
8
  helpGroup: "FRONT ET RÉSEAU",
9
9
  showBanner: false,
@@ -35,7 +35,10 @@ async function countFiles(dir) {
35
35
  */
36
36
  var AssetsPublish = class extends Command {
37
37
  constructor(cli) {
38
- super("assets:publish", "rassemble les fichiers statiques pour un CDN", cli, options);
38
+ super("assets:publish", "rassemble les fichiers statiques pour un CDN", cli, {
39
+ ...options,
40
+ examples: ["nodefony assets:publish", "nodefony assets:publish --out dist-assets --clean"]
41
+ });
39
42
  this.addOption("-o, --out <dir>", "output directory (default ./dist-assets)");
40
43
  this.addOption("--clean", "remove the output directory first");
41
44
  this.addOption("--json", "print a machine-readable summary");
@@ -96,5 +99,4 @@ var AssetsPublish = class extends Command {
96
99
  return sources;
97
100
  }
98
101
  };
99
- //#endregion
100
102
  export { AssetsPublish as default };
@@ -1,6 +1,6 @@
1
1
  import { Command } from "nodefony";
2
2
  import { inspect } from "node:util";
3
- //#region nodefony/command/certificatesCommand.ts
3
+ // nodefony/command/certificatesCommand.ts
4
4
  const options = {
5
5
  helpGroup: "FRONT ET RÉSEAU",
6
6
  showBanner: false,
@@ -16,7 +16,10 @@ const options = {
16
16
  */
17
17
  var Certificates = class extends Command {
18
18
  constructor(cli) {
19
- super("http:certificates", "engendre ou inspecte le certificat TLS de dev", cli, options);
19
+ super("http:certificates", "engendre ou inspecte le certificat TLS de dev", cli, {
20
+ ...options,
21
+ examples: ["nodefony http:certificates", "nodefony http:certificates --force"]
22
+ });
20
23
  this.addOption("-f, --force", "regenerate even if a valid certificate already exists");
21
24
  this.addOption("-j, --json", "output the certificate summary as JSON");
22
25
  }
@@ -42,5 +45,4 @@ Requête vérifiée (NE PAS utiliser -k / rejectUnauthorized:false) :
42
45
  return this;
43
46
  }
44
47
  };
45
- //#endregion
46
48
  export { Certificates as default };
@@ -1,6 +1,6 @@
1
1
  import { Command } from "nodefony";
2
2
  import { inspect } from "node:util";
3
- //#region nodefony/command/networkCommand.ts
3
+ // nodefony/command/networkCommand.ts
4
4
  const options = {
5
5
  helpGroup: "FRONT ET RÉSEAU",
6
6
  showBanner: false,
@@ -8,7 +8,10 @@ const options = {
8
8
  };
9
9
  var Network = class extends Command {
10
10
  constructor(cli) {
11
- super("http:network", "les interfaces réseau et adresses de cette machine", cli, options);
11
+ super("http:network", "les interfaces réseau et adresses de cette machine", cli, {
12
+ ...options,
13
+ examples: ["nodefony http:network", "nodefony http:network eth0 --json"]
14
+ });
12
15
  this.addArgument("[interface]", "Selection interface example eth0 ");
13
16
  this.addOption("-j, --json", "get json");
14
17
  }
@@ -23,5 +26,4 @@ var Network = class extends Command {
23
26
  return this;
24
27
  }
25
28
  };
26
- //#endregion
27
29
  export { Network as default };
@@ -1,10 +1,11 @@
1
1
  import { resolveTrustedHostNames } from "../src/context/domainMatcher.js";
2
+ import { asServersConfig, configuredServerPort } from "../src/servers/kernelServers.js";
2
3
  import { defaultIntrospection, generateHaproxyConfig, generateNginxConfig } from "../src/proxy/generateProxyConfig.js";
3
4
  import { planAssetPublish } from "../src/assets/collectAssets.js";
4
5
  import { Command } from "nodefony";
5
6
  import fsp from "node:fs/promises";
6
7
  import { isAbsolute, resolve } from "node:path";
7
- //#region nodefony/command/proxyGenerateCommand.ts
8
+ // nodefony/command/proxyGenerateCommand.ts
8
9
  const options = {
9
10
  helpGroup: "FRONT ET RÉSEAU",
10
11
  showBanner: false,
@@ -18,7 +19,10 @@ const options = {
18
19
  */
19
20
  var ProxyGenerate = class extends Command {
20
21
  constructor(cli) {
21
- super("proxy:generate", "engendre une configuration nginx ou haproxy", cli, options);
22
+ super("proxy:generate", "engendre une configuration nginx ou haproxy", cli, {
23
+ ...options,
24
+ examples: ["nodefony proxy:generate nginx", "nodefony proxy:generate haproxy --out haproxy.cfg"]
25
+ });
22
26
  this.addArgument("<target>", "nginx | haproxy");
23
27
  this.addOption("-o, --out <file>", "write to file instead of stdout");
24
28
  this.addOption("-b, --backend <host>", "backend host the proxy connects to (default 127.0.0.1)");
@@ -67,12 +71,14 @@ var ProxyGenerate = class extends Command {
67
71
  backendHost: opts.backend ?? "127.0.0.1",
68
72
  httpPort: Number(servers?.http?.port) || defaultIntrospection.httpPort,
69
73
  httpsPort: Number(servers?.https?.port) || defaultIntrospection.httpsPort,
74
+ h2cPort: configuredServerPort(asServersConfig(this.kernel?.options.servers), "h2c") ?? null,
70
75
  staticRoots,
71
76
  mounts,
72
77
  listen: opts.listen ? Number(opts.listen) : defaultIntrospection.listen,
73
78
  reencrypt: Boolean(opts.reencrypt),
74
79
  maxBodyBytes: Number(httpOpts.maxBodySize) || 0,
75
80
  keepaliveIntervalMs: Number(httpOpts.websocket?.keepaliveInterval) || 0,
81
+ readinessPath: httpOpts.health?.enabled === false ? null : httpOpts.health?.readinessPath ?? "/readyz",
76
82
  tls: opts.tlsCert && opts.tlsKey ? {
77
83
  certPath: opts.tlsCert,
78
84
  keyPath: opts.tlsKey,
@@ -81,5 +87,4 @@ var ProxyGenerate = class extends Command {
81
87
  };
82
88
  }
83
89
  };
84
- //#endregion
85
90
  export { ProxyGenerate as default };
@@ -1,6 +1,7 @@
1
+ import { normalizePrefix, proxyMountProblems } from "../src/proxy/rules.js";
1
2
  import { overlayField } from "nodefony";
2
3
  import { z } from "zod";
3
- //#region nodefony/config/config.ts
4
+ // nodefony/config/config.ts
4
5
  /**
5
6
  * @nodefony/http — CONFIGURATION DU MODULE (schéma Zod = source unique).
6
7
  *
@@ -182,7 +183,7 @@ const sanSchema = z.strictObject({
182
183
  description: "Noms DNS du Subject Alternative Name (RFC 5280 §4.2.1.6). Vide = dérivé du kernel (localhost + domain)."
183
184
  }),
184
185
  ip: z.array(z.string()).default([]).describe("Adresses IP du SAN. Vide = dérivé (127.0.0.1, ::1).")
185
- }).describe("Subject Alternative Name explicite. Vide = dérivé (localhost + domaine kernel). Chrome ignore le commonName depuis RFC 2818 → le SAN fait foi.");
186
+ }).describe("Subject Alternative Name explicite. Vide = dérivé (localhost + domaine kernel). Chrome ignore le commonName ; le SAN seul fait foi (RFC 9525).");
186
187
  const certDevSchema = z.strictObject({ useMkcert: z.boolean().default(true).describe("Préférer mkcert (CA locale trustée) en dev → HTTPS sans erreur navigateur (HMR/WSS). false = forcer le fallback auto-signé. Ignoré hors dev.") }).describe("Options de génération du certificat en développement.");
187
188
  const certificatesSchema = z.strictObject({
188
189
  strategy: z.enum([
@@ -195,6 +196,7 @@ const certificatesSchema = z.strictObject({
195
196
  key: z.string().default("").describe("Chemin de la clé privée TLS. Vide = générée."),
196
197
  cert: z.string().default("").describe("Chemin du certificat TLS. Vide = généré."),
197
198
  privateKeyMode: z.number().int().default(384).meta({ description: "Permissions POSIX de la clé privée écrite sur disque (0600 = lecture/écriture owner uniquement). Une clé TLS ne doit JAMAIS être world-readable." }),
199
+ extraCaFiles: z.array(z.string().min(1)).default([]).describe("Autorités de certification supplémentaires pour les requêtes SORTANTES du processus (découverte OpenID, jeton, jeu de clés, API tierces) : fichiers PEM, absolus ou relatifs à la racine de l'application, un fichier pouvant porter une chaîne entière. L'équivalent porté par l'application de NODE_EXTRA_CA_CERTS — sans syntaxe de shell, donc identique sous Windows. Fichier illisible ou sans certificat = refus au démarrage. La CA de développement générée par Nodefony n'a pas besoin d'y figurer."),
198
200
  san: sanSchema.default(() => sanSchema.parse({})),
199
201
  dev: certDevSchema.default(() => certDevSchema.parse({})),
200
202
  selfSigned: selfSignedSchema.default(() => selfSignedSchema.parse({}))
@@ -221,9 +223,9 @@ const websocketSchema = z.looseObject({
221
223
  autoPong: z.boolean().default(true).describe("Répond automatiquement par un pong à chaque ping entrant (RFC 6455 §5.5.2-5.5.3). Laisser true — requis par le protocole et par le heartbeat des pairs."),
222
224
  allowSynchronousEvents: z.boolean().default(true).describe("Émet les events ('message', 'ping'…) de plusieurs frames lues dans un même chunk réseau de façon synchrone (ws@8.18+). true = meilleur débit ; false = un event par tick d'event loop (latence plus régulière, plus équitable entre connexions)."),
223
225
  maxBackpressure: z.number().int().nonnegative().default(4194304).describe("Seuil (octets) du buffer d'envoi par connexion (`ws.bufferedAmount`) au-delà duquel `backpressurePolicy` s'applique. Borne la RAM d'envoi face à un client LENT À RECEVOIR (anti-OOM) ; broadcast() amplifie (un seul lent peut plomber la diffusion). 0 = désactivé. Défaut 4 MiB."),
224
- backpressureCloseAfterDrops: z.number().int().nonnegative().default(1e3).describe("Nombre de frames refusées D'AFFILÉE au-delà duquel la connexion est FERMÉE (1013), en politique 'drop'. Une frame qui repart remet le compteur à zéro. POURQUOI une série et pas un second seuil d'octets : une fois qu'on jette, plus rien n'alimente la file — elle plafonne au seuil de drop et n'atteint jamais un seuil supérieur, qui serait donc inatteignable (mesuré). Une série de refus, elle, distingue le pic passager du client mort. 0 = ne jamais fermer. Défaut 1000."),
226
+ backpressureCloseAfterDrops: z.number().int().nonnegative().default(1e3).describe("SOLDE de frames refusées au-delà duquel la connexion est FERMÉE (1013), en politique 'drop' : +1 par frame refusée, −1 par frame envoyée. POURQUOI un solde et pas un second seuil d'octets : une fois qu'on jette, plus rien n'alimente la file — elle plafonne au seuil de drop et n'atteint jamais un seuil supérieur, qui serait donc inatteignable (mesuré). Et pas une série remise à zéro au premier envoi : la file d'un client bloqué oscille autour du seuil, chaque envoi effacerait la série et il ne serait jamais fermé. Le solde, lui, distingue le pic passager du client mort. 0 = ne jamais fermer. Défaut 1000."),
225
227
  backpressurePolicy: z.enum(["drop", "close"]).default("drop").describe("Action quand `ws.bufferedAmount` dépasse `maxBackpressure`. 'drop' = sauter la frame pour ce client (il reste connecté, dégradable — idéal télémétrie/broadcast, défaut). 'close' = fermer le client (RFC 6455 close 1013 « Try Again Later »). La fusion (coalesce) relève de la couche canal realtime, pas du transport.")
226
- }).describe("Serveur WebSocket (`ws@8`). Les options ci-dessus (+ loose : `verifyClient`, `handleProtocols`, `path`, `WebSocket`…) sont transmises à `ws`. GÉRÉ par Nodefony et donc NON exposé : `server`/`host`/`port` (attaché au serveur HTTP), `noServer` (forcé off), `clientTracking` (forcé true — requis par broadcast() + heartbeat), `backlog` (celui du serveur HTTP). `keepalive*`/`closeTimeout` sont des knobs Nodefony, pas des options `ws`.");
228
+ }).describe("Serveur WebSocket (`ws@8`). Les options ci-dessus (+ loose : `verifyClient`, `handleProtocols`, `path`, `WebSocket`…) sont transmises à `ws`. GÉRÉ par Nodefony et donc NON exposé : `server`/`host`/`port`/`noServer` (forcé à `noServer` : l'upgrade du serveur HTTP passe d'abord par le proxy inverse, puis par `ws`), `clientTracking` (forcé true — requis par broadcast() + heartbeat), `backlog` (celui du serveur HTTP). `keepalive*`/`closeTimeout` sont des knobs Nodefony, pas des options `ws`.");
227
229
  const staticOptionsSchema = z.looseObject({
228
230
  cacheControl: z.boolean().optional().describe("Active le header Cache-Control."),
229
231
  maxAge: z.number().int().nonnegative().optional().describe("Durée de cache (selon l'entrée : secondes pour defaultOptions, ms côté serve-static).")
@@ -287,6 +289,43 @@ const healthSchema = z.looseObject({
287
289
  readinessPath: z.string().default("/readyz").describe("Chemin de la probe readiness (k8s `readinessProbe.httpGet.path`). 200 quand le boot est complet (`onPostReady`) ; 503 avant, et dès le début du shutdown (le LB retire le pod AVANT le drain)."),
288
290
  shutdownDelay: z.number().int().nonnegative().default(0).describe("Délai (ms) entre la bascule readiness→503 et le début du drain — laisse aux endpoints k8s/LB le temps de retirer le pod (fenêtre réelle de propagation ~1-2 s). 0 (défaut) = drain immédiat ; alternative opérationnelle : `lifecycle.preStop: sleep N` dans le pod spec. À additionner au budget < grace period (30 s k8s).")
289
291
  }).describe("Probes de santé cloud-native `/livez` + `/readyz` (liveness/readiness k8s, HEALTHCHECK Docker) — servies par les serveurs HTTP et HTTPS.");
292
+ const proxyMountSchema = z.strictObject({
293
+ target: z.string().describe("Origine de l'amont : `scheme://hôte[:port]`, http ou https, SANS chemin (ex. `http://127.0.0.1:8080`). Le chemin relayé est celui de la requête (cf `stripPrefix`)."),
294
+ methods: z.array(z.string()).optional().describe("Méthodes relayées (casse indifférente). Une autre méthode n'est PAS relayée : la requête suit le routage de l'application (404 si rien ne la prend). Absent = toutes."),
295
+ websocket: z.boolean().default(false).describe("Relaie aussi l'upgrade WebSocket du préfixe (même origine, même certificat que la page). Défaut false : un upgrade sur le préfixe reste au serveur WebSocket de Nodefony."),
296
+ stripPrefix: z.boolean().default(false).describe("Retire le préfixe avant de transmettre (`/billing/factures` → `/factures`). Défaut false : l'amont reçoit le chemin complet. ⚠️ Un amont qui ignore son préfixe rendra des liens absolus (`/x`) et des redirections qui sortent du montage."),
297
+ preserveHost: z.boolean().default(false).describe("Transmet le `Host` du client au lieu de celui de la cible. Défaut false : l'amont reçoit son propre nom (ce qu'attend un serveur qui filtre les noms d'hôte), le nom d'origine part en `X-Forwarded-Host`."),
298
+ stripHeaders: z.array(z.string()).default([]).describe("En-têtes de requête à ne PAS transmettre (ex. `[\"cookie\", \"authorization\"]` vers un amont qui n'a pas à voir la session). Les en-têtes de connexion (RFC 9110 §7.6.1) ne le sont jamais."),
299
+ timeoutMs: z.number().optional().describe("Délai d'inactivité avec l'amont (ms) — dépassé avant la réponse (ou avant le `101` d'un upgrade WebSocket) : 504. Absent = `proxy.timeoutMs`. Ne s'applique pas à un WebSocket établi."),
300
+ secure: z.boolean().default(true).describe("Vérifie le certificat d'une cible https. `false` n'est accepté que vers la boucle locale (`127.0.0.0/8`, `localhost`, `::1`) ; ailleurs, fournir l'autorité de l'amont (`certificates.extraCaFiles`, ou `NODE_EXTRA_CA_CERTS`).")
301
+ }).describe("Un montage du proxy inverse : un préfixe d'URL relayé vers un amont.");
302
+ const proxySchema = z.strictObject({
303
+ timeoutMs: z.number().int().positive().default(3e4).describe("Délai d'inactivité par défaut de tous les montages (ms) : un amont muet au-delà rend 504 Gateway Timeout. Défaut 30 s."),
304
+ connectTimeoutMs: z.number().int().positive().default(5e3).describe("Délai d'ÉTABLISSEMENT de la connexion vers un amont (ms), distinct du délai d'inactivité : un amont qui n'accepte pas la connexion rend 504 sans tenir le client pendant `timeoutMs`. Défaut 5 s."),
305
+ maxSockets: z.number().int().positive().default(256).describe("Connexions simultanées maximales vers UN amont (pool keep-alive dédié par montage) ; au-delà, les requêtes attendent un socket libre. Borne aussi les tunnels WebSocket relayés, hors pool : au-delà, l'upgrade rend 503. Défaut 256. Le pool ignore `HTTP_PROXY`/`NODE_USE_ENV_PROXY` : un amont se joint en direct."),
306
+ mounts: z.record(z.string(), proxyMountSchema).default({}).describe("Préfixe d'URL → amont. Consulté AVANT le routage : une route de l'application sous ce préfixe ne sera jamais atteinte. ⚠️ Servi AVANT le pare-feu, la CSRF et les en-têtes applicatifs (CSP, Referrer-Policy, COOP) — l'amont porte sa propre politique d'accès ; les en-têtes de transport (nosniff, X-Frame-Options, HSTS) sont posés si l'amont ne les fixe pas, et les quotas (rate-limit, connexions WebSocket par IP) s'appliquent. Correspondance au préfixe le PLUS LONG. Refusés au démarrage : `/`, ce qui est sous `/nodefony/` (administration) ou `/_vite/` (monté par @nodefony/frontend), deux clés qui désignent le même préfixe.")
307
+ }).superRefine((proxy, ctx) => {
308
+ const seen = /* @__PURE__ */ new Map();
309
+ for (const [prefix, mount] of Object.entries(proxy.mounts)) {
310
+ const normalized = normalizePrefix(prefix);
311
+ const twin = seen.get(normalized);
312
+ if (twin !== void 0) ctx.addIssue({
313
+ code: "custom",
314
+ path: ["mounts", prefix],
315
+ message: `« ${prefix} » et « ${twin} » désignent le même préfixe (${normalized}) — n'en garder qu'un`
316
+ });
317
+ seen.set(normalized, prefix);
318
+ for (const problem of proxyMountProblems(prefix, mount, "config")) ctx.addIssue({
319
+ code: "custom",
320
+ path: problem.field === "prefix" ? ["mounts", prefix] : [
321
+ "mounts",
322
+ prefix,
323
+ problem.field
324
+ ],
325
+ message: problem.message
326
+ });
327
+ }
328
+ }).describe("Proxy inverse : relaie un préfixe d'URL (requêtes et, sur demande, WebSocket) vers un autre serveur, sur la MÊME origine que la page — un seul certificat, l'amont peut rester sur la boucle locale. En-têtes de connexion jamais transmis, `X-Forwarded-*` et `Via` posés, `trustedHosts` appliqué, 502/504 sur amont injoignable/muet, boucle détectée (508).");
290
329
  const httpConfigSchema = z.strictObject({
291
330
  headerServer: z.string().nullable().default("nodefony").meta({
292
331
  runtimeMutable: true,
@@ -323,9 +362,10 @@ const httpConfigSchema = z.strictObject({
323
362
  session: sessionSchema.default(() => sessionSchema.parse({})),
324
363
  rateLimit: rateLimitSchema.default(() => rateLimitSchema.parse({})),
325
364
  health: healthSchema.default(() => healthSchema.parse({})),
365
+ proxy: proxySchema.default(() => proxySchema.parse({})),
326
366
  wsMaxConnectionsPerIp: z.number().int().positive().nullable().default(null).meta({
327
367
  runtimeMutable: true,
328
- description: "Backstop OPT-IN : plafond de connexions WebSocket CONCURRENTES par IP cliente. `null` (DÉFAUT) = désactivé. Distinct de `rateLimit` (qui borne le DÉBIT d'ouverture par fenêtre) : ici on borne le NOMBRE de sockets simultanément ouvertes par IP. Au-delà, l'upgrade est fermé (RFC 6455 close 1013). ⚠️ PORTÉE PAR PROCESS (1 pod) : un vrai plafond GLOBAL/IP se fait à l'INGRESS/LB — nginx `limit_conn`, HAProxy `sc_conn_cur`, annotation k8s `nginx.ingress.kubernetes.io/limit-connections` — qui voit TOUT le trafic, rejette AVANT que l'app paie le fd + le handshake TLS, et couvre tous les pods. En cloud-native, laisser `null` et déléguer à l'edge. N'activer (ex. 20) que sur bare-metal/VPS SANS ingress, comme défense en profondeur. IP résolue forwarded-aware (RFC 7239 + trustProxy)."
368
+ description: "Backstop OPT-IN : plafond de connexions LONGUES CONCURRENTES par IP cliente — sockets WebSocket ET flux SSE, un seul budget pour les deux. `null` (DÉFAUT) = désactivé. Distinct de `rateLimit` (qui borne le DÉBIT d'ouverture par fenêtre) : ici on borne le NOMBRE de connexions simultanément ouvertes par IP. Au-delà, l'upgrade WebSocket est fermé (RFC 6455 close 1013) et un flux SSE répond 429. ⚠️ PORTÉE PAR PROCESS (1 pod) : un vrai plafond GLOBAL/IP se fait à l'INGRESS/LB — nginx `limit_conn`, HAProxy `sc_conn_cur`, annotation k8s `nginx.ingress.kubernetes.io/limit-connections` — qui voit TOUT le trafic, rejette AVANT que l'app paie le fd + le handshake TLS, et couvre tous les pods. En cloud-native, laisser `null` et déléguer à l'edge. N'activer (ex. 20) que sur bare-metal/VPS SANS ingress, comme défense en profondeur. IP résolue forwarded-aware (RFC 7239 + trustProxy)."
329
369
  })
330
370
  }).describe("Configuration de @nodefony/http.");
331
371
  /**
@@ -353,5 +393,4 @@ const httpOverlaySchema = z.strictObject({
353
393
  * valides par construction ; passés au `super(..., config)` du Module class.
354
394
  */
355
395
  const config = httpConfigSchema.parse({});
356
- //#endregion
357
396
  export { config as default, httpConfigSchema, httpOverlaySchema };
@@ -1,7 +1,7 @@
1
1
  import { httpConfigSchema } from "./config.js";
2
2
  import { parseModuleConfig } from "nodefony";
3
3
  import { z } from "zod";
4
- //#region nodefony/config/defineModuleConfig.ts
4
+ // nodefony/config/defineModuleConfig.ts
5
5
  /**
6
6
  * Injecte les défauts dérivés du kernel APRÈS le parse (le schéma reste pur).
7
7
  *
@@ -11,7 +11,7 @@ import { z } from "zod";
11
11
  * Sans ce remplissage, le certificat auto-signé n'aurait pas de commonName.
12
12
  * - `certificates.san` vide → Subject Alternative Name dérivé du kernel
13
13
  * (`localhost` + `kernel.domain` en DNS ; `127.0.0.1`/`::1` en IP). Le SAN fait
14
- * foi pour la vérification d'hôte (RFC 6125) — Chrome ignore le commonName.
14
+ * foi pour la vérification d'hôte (RFC 9525) — Chrome ignore le commonName.
15
15
  * `0.0.0.0` (bind toutes interfaces) n'est PAS un nom DNS valide → exclu.
16
16
  *
17
17
  * Muté EN PLACE (pas de copie) : la config est ré-assignée à `module.options`
@@ -89,5 +89,4 @@ function defineHttpConfig(config = {}, kernel) {
89
89
  function httpConfigJsonSchema() {
90
90
  return z.toJSONSchema(httpConfigSchema);
91
91
  }
92
- //#endregion
93
92
  export { defineHttpConfig, httpConfigJsonSchema };
@@ -0,0 +1 @@
1
+ export {};
@@ -1,7 +1,7 @@
1
1
  import { SESSION_FACETS, SESSION_FILTERS, SESSION_STATS_FILTERS } from "../src/session/storage/sessionFilters.js";
2
2
  import { RATE_LIMIT_FILTERS } from "../src/rateLimit/rateLimitFilters.js";
3
3
  import { parseFilters, parsePageQuery } from "nodefony";
4
- //#region nodefony/service/HttpAdminApi.ts
4
+ // nodefony/service/HttpAdminApi.ts
5
5
  /** Nom du service HttpKernel dans le container (source unique). */
6
6
  const HTTP_KERNEL_SERVICE = "HttpKernel";
7
7
  /**
@@ -25,7 +25,6 @@ function pageParams(query) {
25
25
  function adminActor(user) {
26
26
  if (user && typeof user === "object") {
27
27
  const u = user;
28
- if (typeof u.username === "string" && u.username) return u.username;
29
28
  if (typeof u.identifier === "string" && u.identifier) return u.identifier;
30
29
  }
31
30
  return "admin";
@@ -63,6 +62,7 @@ function createHttpAdminApi(module) {
63
62
  const serverServices = [
64
63
  "server-http",
65
64
  "server-https",
65
+ "server-h2c",
66
66
  "server-websocket",
67
67
  "server-websocket-secure",
68
68
  "server-static"
@@ -372,5 +372,4 @@ function createHttpAdminApi(module) {
372
372
  adminEndpoints: () => endpoints
373
373
  };
374
374
  }
375
- //#endregion
376
375
  export { createHttpAdminApi };
@@ -1,4 +1,4 @@
1
- //#region nodefony/service/ProfilerAdminApi.ts
1
+ // nodefony/service/ProfilerAdminApi.ts
2
2
  /**
3
3
  * Producteur `IAdminApi` du **profiler** — exposé sous `/nodefony/profiler/api/*`.
4
4
  *
@@ -70,5 +70,4 @@ function createProfilerAdminApi(profiler) {
70
70
  adminEndpoints: () => endpoints
71
71
  };
72
72
  }
73
- //#endregion
74
73
  export { createProfilerAdminApi, createProfilerAdminApi as default };
@@ -1,6 +1,12 @@
1
- import { RequestContext } from "nodefony";
1
+ import { handshakeRefusalStatus } from "../src/context/websocket/WebsocketContext.js";
2
2
  import { performance } from "node:perf_hooks";
3
- //#region nodefony/service/audit-logger.ts
3
+ // nodefony/service/audit-logger.ts
4
+ const statusOf = (context) => {
5
+ return context.response?.statusCode ?? null;
6
+ };
7
+ const headersOf = (context) => {
8
+ return context.request?.headers ?? {};
9
+ };
4
10
  /**
5
11
  * Durée totale de la requête, de la première phase (`startMs`) à maintenant.
6
12
  * `null` si le chronométrage est coupé (aucune phase enregistrée). Partagée
@@ -66,25 +72,25 @@ var JsonAuditLogger = class {
66
72
  const ctx = context;
67
73
  if (!this.nominalEnabled) {
68
74
  if (error ?? ctx.error) return true;
69
- const status = ctx.response?.statusCode ?? null;
75
+ const status = statusOf(ctx);
70
76
  return status !== null && status >= 400;
71
77
  }
72
78
  if (this.sampleRate <= 1) return true;
73
79
  if (error ?? ctx.error) return true;
74
- const status = ctx.response?.statusCode ?? null;
80
+ const status = statusOf(ctx);
75
81
  if (status !== null && status >= 400) return true;
76
82
  this.sampleCounter = (this.sampleCounter + 1) % this.sampleRate;
77
83
  return this.sampleCounter === 0;
78
84
  }
79
85
  renderHttp(context, error) {
80
86
  const ctx = context;
81
- const status = ctx.response?.statusCode ?? null;
82
- const headers = ctx.request?.headers ?? {};
87
+ const status = statusOf(ctx);
88
+ const headers = headersOf(ctx);
83
89
  const err = error ?? ctx.error ?? null;
84
90
  const entry = {
85
91
  ts: (/* @__PURE__ */ new Date()).toISOString(),
86
92
  requestId: ctx.requestId,
87
- userId: RequestContext.getUserId() ?? null,
93
+ userIdentifier: ctx.userIdentifier ?? null,
88
94
  type: "http",
89
95
  scheme: ctx.scheme,
90
96
  method: ctx.method,
@@ -92,8 +98,8 @@ var JsonAuditLogger = class {
92
98
  status,
93
99
  durationMs: computeDurationMs(ctx.phases),
94
100
  remoteAddress: ctx.remoteAddress ?? null,
95
- host: ctx.getHost?.() ?? null,
96
- userAgent: ctx.getUserAgent?.() ?? null,
101
+ host: ctx.getHost() ?? null,
102
+ userAgent: ctx.getUserAgent() ?? null,
97
103
  hasAuthorization: Boolean(headers["authorization"]),
98
104
  hasCookie: Boolean(headers["cookie"]),
99
105
  phases: ctx.phases.length ? ctx.phases.map((p) => ({
@@ -110,12 +116,13 @@ var JsonAuditLogger = class {
110
116
  }
111
117
  renderWebsocket(context, error, acceptedProtocol) {
112
118
  const ctx = context;
113
- const status = ctx.response?.statusCode ?? null;
114
- const headers = ctx.request?.headers ?? {};
119
+ const refused = error ? handshakeRefusalStatus(ctx, error) : null;
120
+ const status = refused ?? statusOf(ctx);
121
+ const headers = headersOf(ctx);
115
122
  const entry = {
116
123
  ts: (/* @__PURE__ */ new Date()).toISOString(),
117
124
  requestId: ctx.requestId,
118
- userId: RequestContext.getUserId() ?? null,
125
+ userIdentifier: ctx.userIdentifier ?? null,
119
126
  type: "ws",
120
127
  scheme: ctx.scheme,
121
128
  method: ctx.method,
@@ -123,8 +130,8 @@ var JsonAuditLogger = class {
123
130
  status,
124
131
  durationMs: computeDurationMs(ctx.phases),
125
132
  remoteAddress: ctx.remoteAddress ?? null,
126
- host: ctx.getHost?.() ?? null,
127
- userAgent: ctx.getUserAgent?.() ?? null,
133
+ host: ctx.getHost() ?? null,
134
+ userAgent: ctx.getUserAgent() ?? null,
128
135
  hasAuthorization: Boolean(headers["authorization"]),
129
136
  hasCookie: Boolean(headers["cookie"]),
130
137
  phases: ctx.phases.length ? ctx.phases.map((p) => ({
@@ -136,7 +143,7 @@ var JsonAuditLogger = class {
136
143
  };
137
144
  return {
138
145
  text: JSON.stringify(entry),
139
- severity: error ? "ERROR" : "INFO",
146
+ severity: refused !== null ? severityFromStatus(refused) : error ? "ERROR" : "INFO",
140
147
  msgid: "audit"
141
148
  };
142
149
  }
@@ -158,5 +165,4 @@ var JsonAuditLogger = class {
158
165
  return entry;
159
166
  }
160
167
  };
161
- //#endregion
162
168
  export { computeDurationMs, JsonAuditLogger as default, severityFromStatus };