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

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 (81) hide show
  1. package/README.md +24 -0
  2. package/dist/_virtual/{_@oxc-project_runtime@0.155.0 → _@oxc-project_runtime@0.157.0}/helpers/esm/decorate.js +1 -1
  3. package/dist/_virtual/{_@oxc-project_runtime@0.155.0 → _@oxc-project_runtime@0.157.0}/helpers/esm/decorateParam.js +1 -1
  4. package/dist/index.js +29 -26
  5. package/dist/nodefony/command/proxyGenerateCommand.js +2 -2
  6. package/dist/nodefony/config/config.js +4 -2
  7. package/dist/nodefony/service/ProfilerAdminApi.js +5 -2
  8. package/dist/nodefony/service/error-renderer.js +6 -4
  9. package/dist/nodefony/service/http-kernel.js +112 -34
  10. package/dist/nodefony/service/pretty-request-logger.js +1 -1
  11. package/dist/nodefony/service/request-logger.js +1 -1
  12. package/dist/nodefony/service/reverse-proxy.js +7 -2
  13. package/dist/nodefony/service/servers/clientError.js +28 -4
  14. package/dist/nodefony/service/servers/server-h2c.js +5 -5
  15. package/dist/nodefony/service/servers/server-http.js +5 -3
  16. package/dist/nodefony/service/servers/server-https.js +12 -5
  17. package/dist/nodefony/service/servers/server-static.js +1 -6
  18. package/dist/nodefony/service/servers/server-websocket-secure.js +6 -10
  19. package/dist/nodefony/service/servers/server-websocket.js +6 -10
  20. package/dist/nodefony/service/servers/serverShutdown.js +63 -4
  21. package/dist/nodefony/service/sessions/sessions-service.js +3 -3
  22. package/dist/nodefony/service/upload/upload-service.js +2 -2
  23. package/dist/nodefony/src/assets/prebuiltUi.js +23 -5
  24. package/dist/nodefony/src/context/http/ByteStream.js +359 -0
  25. package/dist/nodefony/src/context/http/HttpContext.js +55 -26
  26. package/dist/nodefony/src/context/http/Request.js +15 -6
  27. package/dist/nodefony/src/context/http/Response.js +354 -35
  28. package/dist/nodefony/src/context/http/SseStream.js +81 -146
  29. package/dist/nodefony/src/context/http/StreamLifecycle.js +273 -0
  30. package/dist/nodefony/src/context/http/urlFastPath.js +80 -1
  31. package/dist/nodefony/src/context/http2/Request.js +1 -1
  32. package/dist/nodefony/src/context/http2/Response.js +8 -4
  33. package/dist/nodefony/src/context/transport.js +20 -1
  34. package/dist/nodefony/src/context/websocket/Response.js +4 -2
  35. package/dist/nodefony/src/context/websocket/WebsocketContext.js +71 -14
  36. package/dist/nodefony/src/context/websocket/websocketUrl.js +7 -0
  37. package/dist/nodefony/src/context/websocket/wsBackpressure.js +15 -15
  38. package/dist/nodefony/src/context/websocket/wsFrameRate.js +71 -0
  39. package/dist/nodefony/src/context/websocket/wsLogContent.js +55 -17
  40. package/dist/nodefony/src/cookies/cookie.js +54 -13
  41. package/dist/nodefony/src/profiler/Profiler.js +14 -1
  42. package/dist/nodefony/src/proxy/forward.js +109 -9
  43. package/dist/nodefony/src/proxy/generateProxyConfig.js +6 -2
  44. package/dist/nodefony/src/proxy/rules.js +29 -14
  45. package/dist/nodefony/src/servers/upgradeDispatch.js +62 -4
  46. package/dist/types/index.d.ts +6 -0
  47. package/dist/types/nodefony/config/config.d.ts +4 -0
  48. package/dist/types/nodefony/interfaces/ISecurity.d.ts +27 -2
  49. package/dist/types/nodefony/service/ProfilerAdminApi.d.ts +2 -1
  50. package/dist/types/nodefony/service/error-renderer.d.ts +5 -4
  51. package/dist/types/nodefony/service/http-kernel.d.ts +15 -2
  52. package/dist/types/nodefony/service/servers/clientError.d.ts +3 -2
  53. package/dist/types/nodefony/service/servers/serverShutdown.d.ts +5 -3
  54. package/dist/types/nodefony/src/assets/prebuiltUi.d.ts +9 -4
  55. package/dist/types/nodefony/src/context/http/ByteStream.d.ts +109 -0
  56. package/dist/types/nodefony/src/context/http/HttpContext.d.ts +45 -3
  57. package/dist/types/nodefony/src/context/http/Request.d.ts +8 -1
  58. package/dist/types/nodefony/src/context/http/Response.d.ts +134 -8
  59. package/dist/types/nodefony/src/context/http/SseStream.d.ts +32 -7
  60. package/dist/types/nodefony/src/context/http/StreamLifecycle.d.ts +53 -0
  61. package/dist/types/nodefony/src/context/http/urlFastPath.d.ts +40 -0
  62. package/dist/types/nodefony/src/context/http2/Response.d.ts +5 -3
  63. package/dist/types/nodefony/src/context/transport.d.ts +17 -0
  64. package/dist/types/nodefony/src/context/websocket/WebsocketContext.d.ts +40 -0
  65. package/dist/types/nodefony/src/context/websocket/websocketUrl.d.ts +4 -0
  66. package/dist/types/nodefony/src/context/websocket/wsBackpressure.d.ts +12 -2
  67. package/dist/types/nodefony/src/context/websocket/wsFrameRate.d.ts +69 -0
  68. package/dist/types/nodefony/src/context/websocket/wsLogContent.d.ts +16 -8
  69. package/dist/types/nodefony/src/cookies/cookie.d.ts +20 -2
  70. package/dist/types/nodefony/src/profiler/Profiler.d.ts +11 -1
  71. package/dist/types/nodefony/src/proxy/forward.d.ts +30 -2
  72. package/dist/types/nodefony/src/proxy/rules.d.ts +20 -0
  73. package/dist/types/nodefony/src/servers/upgradeDispatch.d.ts +41 -1
  74. package/docs/byte-stream.md +371 -0
  75. package/docs/cookies.md +13 -3
  76. package/docs/index.md +8 -0
  77. package/docs/reverse-proxy.md +15 -3
  78. package/docs/servers.md +26 -15
  79. package/docs/session.md +3 -3
  80. package/docs/sse.md +27 -20
  81. package/package.json +16 -16
package/docs/sse.md CHANGED
@@ -23,7 +23,7 @@ status: stable
23
23
  updated: 2026-10-08
24
24
  source: "src/packages/@nodefony/http/docs/sse.md"
25
25
  coverageModule: http
26
- coverageFiles: context/http/SseStream.ts
26
+ coverageFiles: context/http/SseStream.ts,context/http/StreamLifecycle.ts
27
27
  ---
28
28
 
29
29
  📍 [Documentation](../../../../../docs/index.md) › [@nodefony/http](index.md) › **Flux SSE**
@@ -153,16 +153,16 @@ data: {"step":"écriture"}
153
153
 
154
154
  ### Côté serveur — `this.renderSse()` et l'objet `SseStream`
155
155
 
156
- | Membre | Rôle |
157
- | ------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
158
- | `this.renderSse(options?)` | ouvre le flux (`Controller.renderSse()`, `Controller.ts#Controller.renderSse`) ; lève sur WebSocket |
159
- | `this.acceptsSse()` | le client a-t-il demandé `text/event-stream` ? (`Controller.acceptsSse()`, `Controller.ts#Controller.acceptsSse`) |
160
- | `sse.send(data, { event, id })` | un événement ; texte tel quel, objet en JSON (`SseStream.send()`, `SseStream.ts#SseStream.send`) |
161
- | `sse.comment(text)` | un commentaire, ignoré par le client |
162
- | `sse.retry(ms)` | impose le délai de reconnexion du client |
163
- | `sse.onClose(fn)` | appelé à la fermeture, quel que soit le bout qui ferme (`SseStream.onClose()`, `SseStream.ts#SseStream.onClose`) |
164
- | `sse.close()` | termine la requête, idempotent (`SseStream.close()`, `SseStream.ts#SseStream.close`) |
165
- | `sse.closed` | le flux est-il fermé — à tester dans une boucle longue |
156
+ | Membre | Rôle |
157
+ | ------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
158
+ | `this.renderSse(options?)` | ouvre le flux (`Controller.renderSse()`, `Controller.ts#Controller.renderSse`) ; lève sur WebSocket |
159
+ | `this.acceptsSse()` | le client a-t-il demandé `text/event-stream` ? (`Controller.acceptsSse()`, `Controller.ts#Controller.acceptsSse`) |
160
+ | `sse.send(data, { event, id })` | un événement ; texte tel quel, objet en JSON ; des octets (`Uint8Array`, `Buffer`) lèvent un `TypeError` : les encoder soi-même (base64) (`SseStream.send()`, `SseStream.ts#SseStream.send`) |
161
+ | `sse.comment(text)` | un commentaire, ignoré par le client |
162
+ | `sse.retry(ms)` | impose le délai de reconnexion du client |
163
+ | `sse.onClose(fn)` | appelé à la fermeture, quel que soit le bout qui ferme (`SseStream.onClose()`, `SseStream.ts#SseStream.onClose`) |
164
+ | `sse.close()` | termine la requête, idempotent (`SseStream.close()`, `SseStream.ts#SseStream.close`) |
165
+ | `sse.closed` | le flux est-il fermé — à tester dans une boucle longue |
166
166
 
167
167
  Options de `renderSse()` :
168
168
 
@@ -214,18 +214,25 @@ le même qui relit le flux dans les tests du serveur.
214
214
 
215
215
  ## 🏗️ Architecture interne — ce que fait l'ouverture
216
216
 
217
+ L'ouverture repose sur le **cycle de vie commun aux réponses en flux**
218
+ (`StreamLifecycle.ts#openStreamLifecycle`, non exporté) — la même brique sert le [flux d'octets](byte-stream.md) :
219
+
217
220
  1. **La réponse est prise** (`context.sended`) : plus rien ne peut répondre à la place du flux.
218
- 2. **La session est sauvée** s'il y en a une — ses cookies partent avec les en-têtes.
219
- 3. **Le transport se constate** : flux HTTP/2, ou réponse HTTP/1.1 ; ni l'un ni l'autre → 500,
220
- avant d'avoir rien écrit (`startSseStream()`, `SseStream.ts#startSseStream`).
221
- 4. **Les en-têtes partent** — `respond()` en HTTP/2, `flushHeaders()` en HTTP/1.1 — et le délai
221
+ 2. **Le transport se constate** : flux HTTP/2, ou réponse HTTP/1.1 ; ni l'un ni l'autre → 500,
222
+ avant d'avoir rien écrit.
223
+ 3. **La fermeture de la réponse est écoutée AVANT toute attente** : un client parti pendant la
224
+ sauvegarde de la session est vu, et le flux naît fermé (`closed`) sans rien écrire. Un client
225
+ déjà parti ne prend pas de place dans le plafond par IP.
226
+ 4. **La session est sauvée** s'il y en a une — ses cookies partent avec les en-têtes.
227
+ 5. **Les en-têtes partent** — `respond()` en HTTP/2, `flushHeaders()` en HTTP/1.1 — et le délai
222
228
  d'inactivité de la requête est **désarmé** : sans cela, le flux vivant prendrait un 408 au bout
223
- de 30 s.
224
- 5. **Le battement démarre** sur un minuteur `unref()`.
229
+ de 30 s (`SseStream.ts#startSseStream`).
230
+ 6. **Le battement démarre** sur un minuteur `unref()`.
225
231
 
226
- La fin, quel que soit le bout qui ferme, passe par **un seul** nettoyage (`SseStream.ts#SseStream.send`) :
227
- minuteur arrêté, écouteurs `close` et `drain` retirés, attente de `drain` libérée, puis les
228
- écouteurs `onClose`.
232
+ La fin, quel que soit le bout qui ferme, passe par **un seul** nettoyage
233
+ (`StreamLifecycle.ts#StreamLifecycle.finish`) : écouteur `close` retiré, minuteurs de durée de vie et
234
+ de blocage arrêtés, sortie du registre de révocation, puis le nettoyage propre au SSE (battement,
235
+ écouteur `drain`, attente libérée), puis les écouteurs `onClose`.
229
236
 
230
237
  ## 🔐 Sécurité
231
238
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nodefony/http",
3
- "version": "10.0.0-beta.5",
3
+ "version": "10.0.0-beta.6",
4
4
  "description": "Serveurs HTTP, HTTPS, HTTP/2 et WebSocket natifs pour Nodefony : sessions, contextes de requête, certificats TLS",
5
5
  "author": "Christophe CAMENSULI <ccamensuli@gmail.com>",
6
6
  "main": "./dist/index.js",
@@ -51,36 +51,36 @@
51
51
  "test": "./nodefony/tests"
52
52
  },
53
53
  "dependencies": {
54
- "@fastify/busboy": "3.2.4",
55
- "cookie": "2.0.1",
54
+ "@fastify/busboy": "3.2.5",
55
+ "@types/ms": "2.1.0",
56
+ "@types/qs": "6.15.1",
57
+ "@types/serve-static": "2.2.0",
58
+ "@types/ws": "8.18.2",
59
+ "@types/xml2js": "0.4.14",
60
+ "cookie": "2.0.2",
56
61
  "mime-types": "3.0.2",
57
62
  "ms": "^2.1.3",
58
- "qs": "^6.16.1",
63
+ "qs": "^6.17.1",
59
64
  "serve-static": "2.2.1",
60
- "tslib": "2.8.1",
61
- "ws": "8.22.0",
65
+ "tslib": "2.9.1",
66
+ "ws": "8.22.1",
62
67
  "xml2js": "0.6.2"
63
68
  },
64
69
  "devDependencies": {
65
70
  "@types/chai": "5.2.3",
66
71
  "@types/mime-types": "3.0.1",
67
- "@types/ms": "2.1.0",
68
- "@types/node": "26.6.5",
69
- "@types/qs": "6.15.1",
70
- "@types/serve-static": "2.2.0",
72
+ "@types/node": "26.6.6",
71
73
  "@types/websocket": "1.0.10",
72
- "@types/ws": "8.18.2",
73
- "@types/xml2js": "0.4.14",
74
- "@vitest/coverage-v8": "5.0.5",
75
- "nodefony": "^10.0.0-beta.5",
74
+ "@vitest/coverage-v8": "5.1.0",
75
+ "nodefony": "^10.0.0-beta.6",
76
76
  "tsx": "4.23.15",
77
- "vitest": "5.0.5"
77
+ "vitest": "5.1.0"
78
78
  },
79
79
  "license": "Apache-2.0",
80
80
  "readmeFilename": "README.md",
81
81
  "contributors": [],
82
82
  "peerDependencies": {
83
- "nodefony": "^10.0.0-beta.5",
83
+ "nodefony": "^10.0.0-beta.6",
84
84
  "zod": "^4.6.7"
85
85
  },
86
86
  "files": [