@nodefony/http 10.0.0-beta.5 → 10.0.0-beta.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -0
- package/dist/_virtual/{_@oxc-project_runtime@0.155.0 → _@oxc-project_runtime@0.158.0}/helpers/esm/decorate.js +1 -1
- package/dist/_virtual/{_@oxc-project_runtime@0.155.0 → _@oxc-project_runtime@0.158.0}/helpers/esm/decorateParam.js +1 -1
- package/dist/index.js +30 -26
- package/dist/nodefony/command/proxyGenerateCommand.js +2 -2
- package/dist/nodefony/config/config.js +29 -4
- package/dist/nodefony/grpc/GrpcCall.js +298 -0
- package/dist/nodefony/grpc/GrpcEndpoint.js +528 -0
- package/dist/nodefony/grpc/index.js +4 -0
- package/dist/nodefony/interfaces/IRpcCall.js +1 -0
- package/dist/nodefony/service/ProfilerAdminApi.js +5 -2
- package/dist/nodefony/service/audit-logger.js +52 -6
- package/dist/nodefony/service/error-renderer.js +47 -13
- package/dist/nodefony/service/http-kernel.js +306 -49
- package/dist/nodefony/service/pretty-request-logger.js +5 -3
- package/dist/nodefony/service/request-logger.js +21 -6
- package/dist/nodefony/service/reverse-proxy.js +8 -3
- package/dist/nodefony/service/servers/clientError.js +53 -4
- package/dist/nodefony/service/servers/server-h2c.js +6 -6
- package/dist/nodefony/service/servers/server-http.js +6 -4
- package/dist/nodefony/service/servers/server-https.js +14 -7
- package/dist/nodefony/service/servers/server-static.js +1 -6
- package/dist/nodefony/service/servers/server-websocket-secure.js +7 -11
- package/dist/nodefony/service/servers/server-websocket.js +7 -11
- package/dist/nodefony/service/servers/serverShutdown.js +43 -6
- package/dist/nodefony/service/sessions/sessions-service.js +7 -7
- package/dist/nodefony/service/upload/upload-service.js +2 -2
- package/dist/nodefony/src/assets/prebuiltUi.js +23 -5
- package/dist/nodefony/src/context/Context.js +12 -1
- package/dist/nodefony/src/context/http/ByteStream.js +364 -0
- package/dist/nodefony/src/context/http/HttpContext.js +139 -32
- package/dist/nodefony/src/context/http/Request.js +111 -22
- package/dist/nodefony/src/context/http/Response.js +459 -37
- package/dist/nodefony/src/context/http/SseStream.js +83 -148
- package/dist/nodefony/src/context/http/StreamLifecycle.js +582 -0
- package/dist/nodefony/src/context/http/parser.js +29 -11
- package/dist/nodefony/src/context/http/urlFastPath.js +80 -1
- package/dist/nodefony/src/context/http/webResponse.js +56 -0
- package/dist/nodefony/src/context/http2/Request.js +1 -1
- package/dist/nodefony/src/context/http2/Response.js +55 -12
- package/dist/nodefony/src/context/requestTrace.js +6 -2
- package/dist/nodefony/src/context/rpcOutcome.js +20 -0
- package/dist/nodefony/src/context/transport.js +20 -1
- package/dist/nodefony/src/context/websocket/Response.js +15 -3
- package/dist/nodefony/src/context/websocket/WebsocketContext.js +86 -18
- package/dist/nodefony/src/context/websocket/websocketUrl.js +7 -0
- package/dist/nodefony/src/context/websocket/wsBackpressure.js +15 -15
- package/dist/nodefony/src/context/websocket/wsFrameRate.js +71 -0
- package/dist/nodefony/src/context/websocket/wsLogContent.js +55 -17
- package/dist/nodefony/src/cookies/cookie.js +57 -14
- package/dist/nodefony/src/errors/httpError.js +58 -25
- package/dist/nodefony/src/grpc/cors.js +59 -0
- package/dist/nodefony/src/grpc/limits.js +16 -0
- package/dist/nodefony/src/grpc/refusal.js +271 -0
- package/dist/nodefony/src/profiler/Profiler.js +14 -1
- package/dist/nodefony/src/profiler/aggregate.js +2 -2
- package/dist/nodefony/src/proxy/forward.js +109 -9
- package/dist/nodefony/src/proxy/generateProxyConfig.js +97 -17
- package/dist/nodefony/src/proxy/rules.js +29 -14
- package/dist/nodefony/src/servers/http2Goaway.js +76 -0
- package/dist/nodefony/src/servers/http2Limits.js +41 -15
- package/dist/nodefony/src/servers/http2StreamGrace.js +100 -0
- package/dist/nodefony/src/servers/receiveDeadline.js +177 -0
- package/dist/nodefony/src/servers/upgradeDispatch.js +62 -4
- package/dist/types/index.d.ts +11 -2
- package/dist/types/nodefony/config/config.d.ts +14 -0
- package/dist/types/nodefony/grpc/GrpcCall.d.ts +142 -0
- package/dist/types/nodefony/grpc/GrpcEndpoint.d.ts +98 -0
- package/dist/types/nodefony/grpc/index.d.ts +15 -0
- package/dist/types/nodefony/interfaces/IContext.d.ts +9 -0
- package/dist/types/nodefony/interfaces/IErrorRenderer.d.ts +14 -0
- package/dist/types/nodefony/interfaces/IRequest.d.ts +2 -1
- package/dist/types/nodefony/interfaces/IRequestTrace.d.ts +10 -0
- package/dist/types/nodefony/interfaces/IRouting.d.ts +19 -0
- package/dist/types/nodefony/interfaces/IRpcCall.d.ts +83 -0
- package/dist/types/nodefony/interfaces/ISecurity.d.ts +27 -2
- package/dist/types/nodefony/interfaces/IUpload.d.ts +51 -4
- package/dist/types/nodefony/interfaces/index.d.ts +2 -1
- package/dist/types/nodefony/service/ProfilerAdminApi.d.ts +2 -1
- package/dist/types/nodefony/service/audit-logger.d.ts +33 -3
- package/dist/types/nodefony/service/error-renderer.d.ts +27 -5
- package/dist/types/nodefony/service/http-kernel.d.ts +36 -3
- package/dist/types/nodefony/service/request-logger.d.ts +10 -0
- package/dist/types/nodefony/service/servers/clientError.d.ts +3 -2
- package/dist/types/nodefony/service/servers/serverShutdown.d.ts +7 -5
- package/dist/types/nodefony/src/assets/prebuiltUi.d.ts +9 -4
- package/dist/types/nodefony/src/context/Context.d.ts +9 -1
- package/dist/types/nodefony/src/context/http/ByteStream.d.ts +109 -0
- package/dist/types/nodefony/src/context/http/HttpContext.d.ts +99 -3
- package/dist/types/nodefony/src/context/http/Request.d.ts +46 -9
- package/dist/types/nodefony/src/context/http/Response.d.ts +188 -8
- package/dist/types/nodefony/src/context/http/SseStream.d.ts +33 -8
- package/dist/types/nodefony/src/context/http/StreamLifecycle.d.ts +106 -0
- package/dist/types/nodefony/src/context/http/parser.d.ts +17 -3
- package/dist/types/nodefony/src/context/http/urlFastPath.d.ts +40 -0
- package/dist/types/nodefony/src/context/http/webResponse.d.ts +31 -0
- package/dist/types/nodefony/src/context/http2/Response.d.ts +40 -5
- package/dist/types/nodefony/src/context/requestTrace.d.ts +3 -1
- package/dist/types/nodefony/src/context/rpcOutcome.d.ts +11 -0
- package/dist/types/nodefony/src/context/transport.d.ts +17 -0
- package/dist/types/nodefony/src/context/websocket/Response.d.ts +6 -1
- package/dist/types/nodefony/src/context/websocket/WebsocketContext.d.ts +48 -0
- package/dist/types/nodefony/src/context/websocket/websocketUrl.d.ts +4 -0
- package/dist/types/nodefony/src/context/websocket/wsBackpressure.d.ts +12 -2
- package/dist/types/nodefony/src/context/websocket/wsFrameRate.d.ts +69 -0
- package/dist/types/nodefony/src/context/websocket/wsLogContent.d.ts +16 -8
- package/dist/types/nodefony/src/cookies/cookie.d.ts +20 -2
- package/dist/types/nodefony/src/errors/httpError.d.ts +29 -4
- package/dist/types/nodefony/src/grpc/cors.d.ts +32 -0
- package/dist/types/nodefony/src/grpc/limits.d.ts +14 -0
- package/dist/types/nodefony/src/grpc/refusal.d.ts +136 -0
- package/dist/types/nodefony/src/profiler/Profiler.d.ts +11 -1
- package/dist/types/nodefony/src/proxy/forward.d.ts +37 -2
- package/dist/types/nodefony/src/proxy/generateProxyConfig.d.ts +15 -2
- package/dist/types/nodefony/src/proxy/rules.d.ts +20 -0
- package/dist/types/nodefony/src/servers/http2Goaway.d.ts +41 -0
- package/dist/types/nodefony/src/servers/http2Limits.d.ts +27 -14
- package/dist/types/nodefony/src/servers/http2StreamGrace.d.ts +34 -0
- package/dist/types/nodefony/src/servers/receiveDeadline.d.ts +77 -0
- package/dist/types/nodefony/src/servers/upgradeDispatch.d.ts +41 -1
- package/docs/byte-stream.md +406 -0
- package/docs/cookies.md +13 -3
- package/docs/diagnostics-channel.md +45 -1
- package/docs/index.md +8 -0
- package/docs/reverse-proxy.md +15 -3
- package/docs/servers.md +67 -43
- package/docs/session.md +3 -3
- package/docs/sse.md +27 -20
- package/docs/upload.md +43 -17
- package/package.json +38 -18
package/docs/servers.md
CHANGED
|
@@ -22,7 +22,7 @@ tags:
|
|
|
22
22
|
]
|
|
23
23
|
version: "doc"
|
|
24
24
|
status: stable
|
|
25
|
-
updated: 2026-
|
|
25
|
+
updated: 2026-10-30
|
|
26
26
|
source: "src/packages/@nodefony/http/docs/servers.md"
|
|
27
27
|
coverageModule: http
|
|
28
28
|
coverageFiles: servers/server-http.ts,servers/server-https.ts,servers/server-websocket.ts,certificates.ts
|
|
@@ -428,7 +428,7 @@ souvent **moins** de requêtes par seconde qu'en HTTP/1.1. Le choix se fait sur
|
|
|
428
428
|
|
|
429
429
|
| Forme du trafic | h2c ? | Pourquoi |
|
|
430
430
|
| -------------------------------------------- | ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
431
|
-
| gRPC
|
|
431
|
+
| gRPC natif derrière le proxy | **requis** | gRPC n'existe qu'en HTTP/2 ; gRPC-Web et Connect passent aussi en HTTP/1.1 — voir [gRPC](../../framework/docs/grpc.md). |
|
|
432
432
|
| Beaucoup de flux longs (SSE) par pod | **oui** | En HTTP/1.1, chaque flux occupe une connexion du proxy ; en h2c, ils partagent quelques connexions. |
|
|
433
433
|
| En-têtes lourds et répétés (cookies, jetons) | probable | HPACK les compresse d'une requête à l'autre. |
|
|
434
434
|
| REST classique, petites réponses | **mesurer** | Souvent neutre, parfois perdant. |
|
|
@@ -473,9 +473,9 @@ automatiquement un éventuel décalage de port.
|
|
|
473
473
|
le battement de cœur (`server-websocket.ts#Websocket.createServer`).
|
|
474
474
|
- **Keep-alive** armé à la création (`startHeartbeat()`, `server-websocket.ts#Websocket.createServer`) et par connexion
|
|
475
475
|
(`trackPong()`, `http-kernel.ts#HttpKernel.handleWebsocket`, juste après l'acceptation du handshake).
|
|
476
|
-
- **Arrêt** : il s'inscrit
|
|
477
|
-
(`
|
|
478
|
-
|
|
476
|
+
- **Arrêt** : il s'inscrit à l'étape « congé » de l'arrêt du trafic
|
|
477
|
+
(`addShutdownStep("dismiss")`, `server-websocket.ts#Websocket.createServer`), attendue avant le
|
|
478
|
+
drain HTTP — voir la section Arrêt gracieux.
|
|
479
479
|
|
|
480
480
|
### `server-websocket-secure` — WebSocket sur TLS
|
|
481
481
|
|
|
@@ -522,16 +522,16 @@ Défauts matérialisés dans `defaultAppConfig` (`src/nodefony/src/config/defaul
|
|
|
522
522
|
Table dérivée de `httpServerSchema` (`config.ts#httpServerSchema`) ; la section `https` reprend les mêmes clés et en
|
|
523
523
|
ajoute une (`httpsServerSchema`, `config.ts#httpsServerSchema`).
|
|
524
524
|
|
|
525
|
-
| Option | Type | Défaut | Effet
|
|
526
|
-
| ---------------------------- | ----- | ------- |
|
|
527
|
-
| `maxHeadersCount` | int | `2000` | Nombre maximum d'en-têtes par requête — anti _header flooding_.
|
|
528
|
-
| `keepAliveTimeout` | ms | `5000` | Délai de réutilisation de la socket TCP entre deux requêtes.
|
|
529
|
-
| `timeout` | ms | `30000` | Timeout global de socket, aligné sur `responseTimeout`. `0` = désactivé.
|
|
530
|
-
| `requestTimeout` | ms | `30000` | Délai de réception de la requête complète — **anti slow-loris
|
|
531
|
-
| `responseTimeout` | ms | `30000` | Délai d'
|
|
532
|
-
| `shutdownTimeout` | ms | `5000` | Drain au shutdown avant destruction forcée. Garder < grâce orchestrateur.
|
|
533
|
-
| `headers` | objet | `null` | En-têtes ajoutés à toutes les réponses.
|
|
534
|
-
| `rejectUnauthorized` (https) | bool | `false` | Rejette les certificats invalides. `false` en dev (auto-signés), `true` en prod.
|
|
525
|
+
| Option | Type | Défaut | Effet |
|
|
526
|
+
| ---------------------------- | ----- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
527
|
+
| `maxHeadersCount` | int | `2000` | Nombre maximum d'en-têtes par requête — anti _header flooding_. |
|
|
528
|
+
| `keepAliveTimeout` | ms | `5000` | Délai de réutilisation de la socket TCP entre deux requêtes. |
|
|
529
|
+
| `timeout` | ms | `30000` | Timeout global de socket, aligné sur `responseTimeout`. En HTTP/2 (5152, h2c), une connexion inactive au-delà de ce délai est fermée par GOAWAY ; les flux en cours vont à leur terme. `0` = désactivé. |
|
|
530
|
+
| `requestTimeout` | ms | `30000` | Délai de réception de la requête complète — **anti slow-loris**, en HTTP/1.1 (Node) comme en HTTP/2 (framework : 408, puis flux fermé). `0` le désactive. |
|
|
531
|
+
| `responseTimeout` | ms | `30000` | Délai d'inactivité d'une action (couche pipeline) : au-delà, 503 et `ctx.signal` annulé. Réglable par route (`responseTimeout` d'une option de route). |
|
|
532
|
+
| `shutdownTimeout` | ms | `5000` | Drain au shutdown avant destruction forcée. Garder < grâce orchestrateur. |
|
|
533
|
+
| `headers` | objet | `null` | En-têtes ajoutés à toutes les réponses. |
|
|
534
|
+
| `rejectUnauthorized` (https) | bool | `false` | Rejette les certificats invalides. `false` en dev (auto-signés), `true` en prod. |
|
|
535
535
|
|
|
536
536
|
Ces deux sections sont **permissives** (`z.looseObject`) : toute option supplémentaire de
|
|
537
537
|
`http.Server` / `net.Server` / TLS (`insecureHTTPParser`, `ciphers`, `minVersion`…) est transmise telle
|
|
@@ -552,22 +552,27 @@ Depuis `http2Schema` (`config.ts#http2Schema`), appliqué seulement si défini
|
|
|
552
552
|
Depuis `websocketSchema` (`config.ts#websocketSchema`). Les deux sections partagent la forme et les défauts ; le WSS
|
|
553
553
|
lit `websocketSecure` (`config.ts#httpConfigSchema`).
|
|
554
554
|
|
|
555
|
-
| Option
|
|
556
|
-
|
|
|
557
|
-
| `keepaliveInterval`
|
|
558
|
-
| `keepaliveGracePeriod`
|
|
559
|
-
| `closeTimeout`
|
|
560
|
-
| `maxPayload`
|
|
561
|
-
| `allowedOrigins`
|
|
562
|
-
| `perMessageDeflate`
|
|
563
|
-
| `skipUTF8Validation`
|
|
564
|
-
| `autoPong`
|
|
565
|
-
| `
|
|
566
|
-
| `
|
|
567
|
-
| `
|
|
555
|
+
| Option | Type | Défaut | Effet |
|
|
556
|
+
| ----------------------------- | ------------------- | ------- | ----------------------------------------------------------------------------------------------- |
|
|
557
|
+
| `keepaliveInterval` | ms | `20000` | Intervalle des pings — détecte les connexions zombies. |
|
|
558
|
+
| `keepaliveGracePeriod` | ms | `10000` | Délai de grâce après un ping sans réponse avant fermeture. |
|
|
559
|
+
| `closeTimeout` | ms | `5000` | Délai de fermeture propre avant destruction de la socket. |
|
|
560
|
+
| `maxPayload` | octets | `1 MiB` | Taille max d'un message entrant → au-delà, **close 1009** (`config.ts#websocketSchema`). |
|
|
561
|
+
| `allowedOrigins` | bool \| str \| list | `false` | Allowlist d'`Origin` au handshake — **anti-CSWSH** (`config.ts#websocketSchema`). |
|
|
562
|
+
| `perMessageDeflate` | bool \| objet | `false` | Compression RFC 7692. Désactivée par défaut : coût CPU/RAM + risque de _zip bomb_. |
|
|
563
|
+
| `skipUTF8Validation` | bool | `false` | Désactive la validation UTF-8 des frames texte (RFC 6455 §8.1). À laisser `false`. |
|
|
564
|
+
| `autoPong` | bool | `true` | Répond automatiquement aux pings entrants (RFC 6455 §5.5.2-3). À laisser `true`. |
|
|
565
|
+
| `maxPendingAutoPongs` | entier ≥ 0 | `60` | Pongs en attente au-delà desquels la connexion est coupée — anti-DoS mémoire. `0` = sans borne. |
|
|
566
|
+
| `allowSynchronousEvents` | bool | `true` | Émet plusieurs frames d'un même chunk réseau de façon synchrone (débit vs équité). |
|
|
567
|
+
| `maxBackpressure` | octets | `4 MiB` | Seuil du tampon d'envoi par connexion (client lent à recevoir) — anti-OOM. |
|
|
568
|
+
| `backpressurePolicy` | `drop` \| `close` | `drop` | Au-delà du seuil : sauter la frame, ou fermer le client (close 1013). |
|
|
569
|
+
| `backpressureCloseAfterDrops` | frames | `1000` | Solde de frames refusées (+1 refus, −1 envoi) qui ferme en 1013 ; `0` = jamais. |
|
|
570
|
+
| `maxFramesPerSecond` | trames / s | `0` | Trames REÇUES admises par connexion ; au-delà, écartées avant décodage. `0` = coupé. |
|
|
571
|
+
| `frameRateCloseAfterRejects` | trames | `1000` | Solde de trames écartées (+1 écartée, −1 admise) qui ferme en 1008 ; `0` = jamais. |
|
|
568
572
|
|
|
569
573
|
> [!WARNING]
|
|
570
|
-
> `keepalive*`, `closeTimeout`, `maxBackpressure
|
|
574
|
+
> `keepalive*`, `closeTimeout`, `maxBackpressure`, `backpressurePolicy`,
|
|
575
|
+
> `backpressureCloseAfterDrops`, `maxFramesPerSecond` et `frameRateCloseAfterRejects` sont des **réglages
|
|
571
576
|
> Nodefony**, pas des options de `ws` : la bibliothèque les ignore, c'est le framework qui les
|
|
572
577
|
> implémente. À l'inverse, `server`, `noServer`, `clientTracking`, `host`, `port` et `backlog` sont
|
|
573
578
|
> **gérés par Nodefony** et non exposés — les forcer n'aurait pas d'effet.
|
|
@@ -851,7 +856,9 @@ serveurs (HTTP et HTTPS) servent ces chemins — un kubelet configuré en `schem
|
|
|
851
856
|
## Arrêt gracieux — la séquence du SIGTERM
|
|
852
857
|
|
|
853
858
|
Un arrêt brutal coupe les requêtes en vol : à chaque mise à jour progressive, des utilisateurs voient
|
|
854
|
-
une erreur. L'arrêt de Nodefony est une **séquence ordonnée**, et l'ordre est le cœur du sujet.
|
|
859
|
+
une erreur. L'arrêt de Nodefony est une **séquence ordonnée**, et l'ordre est le cœur du sujet. Il
|
|
860
|
+
est écrit dans **une seule fonction**, `http-kernel.ts#HttpKernel.drainTraffic`, l'écouteur `onDrain` du
|
|
861
|
+
module (ADR-0027) : les serveurs s'y inscrivent à leur création, ils n'écoutent pas le noyau.
|
|
855
862
|
|
|
856
863
|
```mermaid
|
|
857
864
|
sequenceDiagram
|
|
@@ -860,21 +867,22 @@ sequenceDiagram
|
|
|
860
867
|
participant W as server-websocket
|
|
861
868
|
participant H as server-http / https
|
|
862
869
|
O->>K: SIGTERM
|
|
863
|
-
K->>K:
|
|
870
|
+
K->>K: isTerminating → readyz 503 (+ shutdownDelay)
|
|
864
871
|
Note over K: le load balancer retire le pod
|
|
865
|
-
K->>W:
|
|
872
|
+
K->>W: onDrain — étape « congé »
|
|
866
873
|
W->>W: close 1001 « Going Away » à chaque client
|
|
867
|
-
Note over W: fenêtre ~300 ms
|
|
868
|
-
K->>H:
|
|
874
|
+
Note over W: fenêtre ~300 ms, fin des flux longs en même temps
|
|
875
|
+
K->>H: onDrain — étape « drain », serveurs ensemble
|
|
869
876
|
H->>H: drain — in-flight terminées, sockets idle fermées
|
|
870
877
|
Note over H: destruction forcée après shutdownTimeout
|
|
878
|
+
K->>K: onTerminate — sessions, base, Redis (dernier inscrit d'abord)
|
|
871
879
|
K->>O: exit 0
|
|
872
880
|
```
|
|
873
881
|
|
|
874
|
-
**Étape 1 — la disponibilité bascule en premier.**
|
|
875
|
-
|
|
876
|
-
load balancer cesse d'envoyer du trafic, et `shutdownDelay`
|
|
877
|
-
propager.
|
|
882
|
+
**Étape 1 — la disponibilité bascule en premier.** Le noyau pose `kernel.isTerminating` avant toute
|
|
883
|
+
phase d'arrêt (`Kernel.ts#Kernel.isTerminating`), y compris pour un arrêt reçu pendant le démarrage :
|
|
884
|
+
`readyz` répond `503`, le load balancer cesse d'envoyer du trafic, et `shutdownDelay` (attendu si le
|
|
885
|
+
pod a été annoncé disponible) laisse à cette information le temps de se propager.
|
|
878
886
|
|
|
879
887
|
**Étape 2 — les clients WebSocket sont prévenus.** `Websocket.terminate()` (`server-websocket.ts#Websocket.terminate`)
|
|
880
888
|
envoie un message applicatif puis une **frame Close 1001 « Going Away »** (`server-websocket.ts#Websocket.terminate`).
|
|
@@ -891,11 +899,16 @@ indiscernable d'une panne réseau. Avec 1001, le client sait qu'il doit simpleme
|
|
|
891
899
|
fermées.
|
|
892
900
|
|
|
893
901
|
Ce qui reste au-delà de `shutdownTimeout` (défaut `5000` ms, `serverShutdown.ts#DEFAULT_SHUTDOWN_TIMEOUT`)
|
|
894
|
-
est détruit.
|
|
902
|
+
est détruit. Les serveurs (HTTP, HTTPS, h2c) se drainent **ensemble** : ports distincts, aucune
|
|
903
|
+
dépendance — l'arrêt dure un `shutdownTimeout`, pas un par serveur.
|
|
904
|
+
|
|
905
|
+
**Étape 4 — les ressources sont libérées.** Une fois plus aucune requête en vol, `onTerminate` ferme
|
|
906
|
+
le stockage des sessions, les pools du proxy inverse, les connexions aux bases et à Redis — du
|
|
907
|
+
dernier inscrit au premier.
|
|
895
908
|
|
|
896
909
|
> [!IMPORTANT]
|
|
897
|
-
> L'ordre WS-avant-HTTP n'est pas cosmétique.
|
|
898
|
-
>
|
|
910
|
+
> L'ordre WS-avant-HTTP n'est pas cosmétique. `drainTraffic` attend la fin de l'étape « congé »
|
|
911
|
+
> (`server-websocket.ts#Websocket.createServer`) avant de lancer l'étape « drain »
|
|
899
912
|
> (`server-http.ts#ServerHttp.createServer`). Inversé, le drain détruirait les sockets déjà upgradées **sans** frame
|
|
900
913
|
> Close : retour du 1006 pour tous les clients temps réel.
|
|
901
914
|
|
|
@@ -914,8 +927,12 @@ transport.
|
|
|
914
927
|
Dès qu'un écouteur `clientError` est attaché, **Node cesse de fermer la socket automatiquement**. Un
|
|
915
928
|
écouteur naïf (« je journalise et je passe ») transforme donc une requête malformée en **fuite de
|
|
916
929
|
socket et de descripteur de fichier** — c'est-à-dire un vecteur de déni de service. Nodefony répond et
|
|
917
|
-
ferme explicitement (`
|
|
918
|
-
(RFC 6585 §5)
|
|
930
|
+
ferme explicitement (`clientError.ts#handleClientError`), avec la réponse que Node aurait donnée sans
|
|
931
|
+
écouteur : `431` si les en-têtes débordent (RFC 6585 §5) ou `414` si c'est la cible (RFC 9112 §3),
|
|
932
|
+
`413` si les extensions de chunk débordent, `408` si la réception dépasse `requestTimeout`
|
|
933
|
+
(RFC 9110 §15.5.9), `400` sinon. Rien n'est écrit si la socket est déjà morte — ni si une réponse en
|
|
934
|
+
vol a déjà envoyé ses en-têtes : une ligne de statut écrite après elle corromprait ce que lit le
|
|
935
|
+
client ; la socket est alors détruite, comme le fait Node.
|
|
919
936
|
|
|
920
937
|
### Connexions WebSocket zombies
|
|
921
938
|
|
|
@@ -952,6 +969,13 @@ descripteur et du TLS, et couvre tous les pods. Ne l'activer que sur une machine
|
|
|
952
969
|
l'OOM — un seul lent peut plomber une diffusion générale. La politique par défaut, `drop`, saute la
|
|
953
970
|
frame et garde le client connecté.
|
|
954
971
|
|
|
972
|
+
Dans l'autre sens, `maxFramesPerSecond` borne le **nombre** de trames qu'une connexion envoie
|
|
973
|
+
(désactivé par défaut). Le compte se fait à l'arrivée de la trame brute
|
|
974
|
+
(`wsFrameRate.ts#admitFrame`) : une trame écartée ne paie ni décodage ni routage, elle est
|
|
975
|
+
comptée (`frameRateRejectedTotal()`, relayé par la sonde du hub temps réel) et la connexion reste
|
|
976
|
+
ouverte — jusqu'à ce que le solde de refus atteigne `frameRateCloseAfterRejects`, qui ferme en
|
|
977
|
+
**1008**. Seul un flux au-delà du double de la borne fait monter ce solde ; un pic passager non.
|
|
978
|
+
|
|
955
979
|
## ⚡ Performance & mémoire
|
|
956
980
|
|
|
957
981
|
Le transport est du **chemin chaud absolu** : ce qui coûte ici est multiplié par le nombre de requêtes
|
package/docs/session.md
CHANGED
|
@@ -469,8 +469,8 @@ timer (`gcIntervalS: 0`).
|
|
|
469
469
|
|
|
470
470
|
## Entités de persistance
|
|
471
471
|
|
|
472
|
-
**Drizzle (SQL).** La table est décrite une seule fois en spec logique (`
|
|
473
|
-
`sessionEntity.ts#
|
|
472
|
+
**Drizzle (SQL).** La table est décrite une seule fois en spec logique (`SESSION_TABLE`,
|
|
473
|
+
`sessionEntity.ts#SESSION_TABLE`) et déclinée par dialecte par `defineTable()` (`colKit.ts#defineTable`) — mêmes **noms** de
|
|
474
474
|
colonnes partout, donc un store dialect-agnostique.
|
|
475
475
|
|
|
476
476
|
| Colonne | Type logique | SQLite | PostgreSQL | MySQL / MariaDB | Rôle |
|
|
@@ -485,7 +485,7 @@ colonnes partout, donc un store dialect-agnostique.
|
|
|
485
485
|
|
|
486
486
|
En MySQL/MariaDB, une colonne texte indexée devient `varchar` (un `TEXT` InnoDB n'est pas indexable
|
|
487
487
|
sans préfixe) et le type JSON passe par un type compatible qui tolère MariaDB, laquelle stocke le JSON
|
|
488
|
-
en `LONGTEXT` (`colKit.ts#
|
|
488
|
+
en `LONGTEXT` (`colKit.mysql.ts#buildMySqlTable`).
|
|
489
489
|
|
|
490
490
|
**Mongoose (MongoDB).** Schéma équivalent (`@nodefony/mongoose/nodefony/entity/sessionEntity.ts#schema`) :
|
|
491
491
|
`session_id` (String, index **unique**), `Attributes`/`flashBag`/`metaBag` (Object, défaut `{}`), `user`
|
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. **
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
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
|
-
|
|
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
|
|
227
|
-
|
|
228
|
-
|
|
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/docs/upload.md
CHANGED
|
@@ -297,6 +297,30 @@ du calque de configuration — une application peut les changer pour une requêt
|
|
|
297
297
|
sont lus au moment de lire le corps (`Request.readBodyLimits()`), donc un calque posé après ce moment
|
|
298
298
|
(au pare-feu, dans un contrôleur) n'agit pas. Détail : [configuration](../../../../../docs/guides/configuration.md).
|
|
299
299
|
|
|
300
|
+
### Par route — l'option `upload`
|
|
301
|
+
|
|
302
|
+
Une route règle ses propres bornes d'envoi, sans toucher à celles des autres : un dépôt de vidéos
|
|
303
|
+
relève `maxFileSize`, un avatar l'abaisse. Chaque clé déclarée remplace celle de la configuration,
|
|
304
|
+
**dans les deux sens** ; une clé absente garde la valeur de la configuration
|
|
305
|
+
(`framework/nodefony/src/Route.ts#RouteOptions.upload`).
|
|
306
|
+
|
|
307
|
+
```ts ignore
|
|
308
|
+
// un avatar : 256 Kio au plus, un seul fichier, son empreinte calculée pendant le flux
|
|
309
|
+
@Post("/avatar", { upload: { maxFileSize: 262_144, maxFiles: 1, hashAlgorithm: "sha256" } })
|
|
310
|
+
async avatar(@UploadedFile() file: IUploadedFile | undefined) {
|
|
311
|
+
return { size: file?.size ?? 0, sha256: file?.hash ?? null };
|
|
312
|
+
}
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
- **Le fichier trop gros est coupé PENDANT son flux** (413) : la route est résolue avant la lecture
|
|
316
|
+
du corps, ses bornes s'appliquent donc à busboy comme celles de la configuration — jamais un
|
|
317
|
+
fichier écrit en entier puis refusé (`context/http/Request.ts#HttpRequest.readBodyLimits`).
|
|
318
|
+
- **Une route sans l'option ne paie rien** : aucune fusion, aucune allocation.
|
|
319
|
+
- **Validée à la déclaration** (`framework/nodefony/decorators/routerDecorators.ts#checkedUpload`) :
|
|
320
|
+
entiers ≥ 1, empreinte connue, aucune clé inconnue — une faute de frappe (`maxFilesize`) laisserait
|
|
321
|
+
sinon la route sur la borne de l'application. `uploadDir` et `encoding` restent ceux de la
|
|
322
|
+
configuration. Exclue avec `bodyStream: true`, dont le corps n'est jamais lu par le pipeline.
|
|
323
|
+
|
|
300
324
|
### Fichiers multipart — `upload.*`
|
|
301
325
|
|
|
302
326
|
Table dérivée de `uploadSchema` (`config/config.ts#uploadSchema`). Toutes les bornes sont `runtimeMutable`.
|
|
@@ -342,15 +366,15 @@ Les décorateurs `@UploadedFile` / `@UploadedFiles` sont des fabriques de param
|
|
|
342
366
|
Chaque entrée de `files` est un `UploadedFile` (`service/upload/upload-service.ts#UploadedFile`), déjà écrit
|
|
343
367
|
sur disque. Ses membres utiles :
|
|
344
368
|
|
|
345
|
-
| Membre | Ce qu'il donne
|
|
346
|
-
| ------------------------ |
|
|
347
|
-
| `filename` | Nom **d'origine** déclaré par le client (métadonnée, jamais le chemin).
|
|
348
|
-
| `size` | Taille réellement écrite (octets).
|
|
349
|
-
| `prettySize` | Taille lisible (`« 1.2 MB »`).
|
|
350
|
-
| `mimeType` | Type MIME déclaré (`image/png`…), sinon deviné de l'extension.
|
|
351
|
-
| `hash` / `hashAlgorithm` | Empreinte d'intégrité si `upload.hashAlgorithm` est réglé.
|
|
352
|
-
| `moveAsync(target)` | Déplace le temp — **non bloquant, recommandé** dans le pipeline.
|
|
353
|
-
| `move(target)` | Variante **synchrone** (compat) — bloque l'event-loop.
|
|
369
|
+
| Membre | Ce qu'il donne | Ancrage |
|
|
370
|
+
| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------- |
|
|
371
|
+
| `filename` | Nom **d'origine** déclaré par le client (métadonnée, jamais le chemin). | `realName()` (`service/upload/upload-service.ts#UploadedFile.realName`) |
|
|
372
|
+
| `size` | Taille réellement écrite (octets). | `getSize()` (`service/upload/upload-service.ts#UploadedFile.getSize`) |
|
|
373
|
+
| `prettySize` | Taille lisible (`« 1.2 MB »`). | `getPrettySize()` (`service/upload/upload-service.ts#UploadedFile.getPrettySize`) |
|
|
374
|
+
| `mimeType` | Type MIME déclaré (`image/png`…), sinon deviné de l'extension ; `false` si ni l'un ni l'autre. Déclaratif : jamais une preuve du contenu. | `getMimeType()` (`service/upload/upload-service.ts#UploadedFile.getMimeType`) |
|
|
375
|
+
| `hash` / `hashAlgorithm` | Empreinte d'intégrité si `upload.hashAlgorithm` est réglé. | `interfaces/IUpload.ts#IUploadedFile.hashAlgorithm` |
|
|
376
|
+
| `moveAsync(target)` | Déplace le temp — **non bloquant, recommandé** dans le pipeline. Rend le `FileClass` de la destination (sans nom d'origine ni empreinte : ils restent sur le fichier reçu). | `moveAsync()` (`service/upload/upload-service.ts#UploadedFile.moveAsync`) |
|
|
377
|
+
| `move(target)` | Variante **synchrone** (compat) — bloque l'event-loop. | `move()` (`service/upload/upload-service.ts#UploadedFile.move`) |
|
|
354
378
|
|
|
355
379
|
`move`/`moveAsync` acceptent un **fichier cible** ou un **dossier existant** : sur un dossier, la
|
|
356
380
|
destination est bâtie avec `filename` — d'où l'avertissement de sécurité ci-dessous.
|
|
@@ -429,6 +453,7 @@ pipeline : `npm run test:memory` (skill `nodefony-check-memory-health`).
|
|
|
429
453
|
| `@Body()` est vide sur un upload de fichier | Les fichiers vont dans `files`, **pas** dans `body` | Lire les fichiers avec `@UploadedFiles()` / `this.files` ; `@Body()` = champs texte |
|
|
430
454
|
| Un `POST` JSON de 1,5 Mo est refusé en `413` | `maxBodySize` vaut **1 MiB** par défaut | Augmenter `maxBodySize` (pas `upload.maxFileSize`) |
|
|
431
455
|
| Un gros fichier passe alors que `maxBodySize` est petit | Le multipart **n'écoute pas** `maxBodySize` | Régler `upload.maxFileSize` / `maxTotalFileSize` |
|
|
456
|
+
| Un avatar de 2 Go remplit le disque avant d'être refusé | La borne de l'application (500 Mo) vaut pour toutes les routes | Option de route `upload: { maxFileSize }` — coupé pendant le flux |
|
|
432
457
|
| `413` sur upload sans message clair | Une borne busboy atteinte en streaming (fichier, cumul, nombre) | Vérifier les bornes `upload.*` — 413 émis sur `stream.on("limit")` (`context/http/Request.ts#HttpRequest.enforceBodyLimit`) |
|
|
433
458
|
| Un fichier écrit `../../etc/…` après un `move` | `move(dossier)` utilise le nom **client** (`upload-service.ts#UploadedFile.move`) | Passer une cible complète, ou `path.basename(file.filename)` |
|
|
434
459
|
| Des fichiers temporaires s'accumulent dans `uploadDir` | Le contrôleur ne déplace jamais le temp | Appeler `moveAsync()` (ou purger l'ancien temp par TTL) |
|
|
@@ -441,14 +466,15 @@ pipeline : `npm run test:memory` (skill `nodefony-check-memory-health`).
|
|
|
441
466
|
Les chiffres exacts vivent dans la carte de tests de cette page (régénérée depuis vitest, jamais figés
|
|
442
467
|
dans le Markdown).
|
|
443
468
|
|
|
444
|
-
| Type | Où
|
|
445
|
-
| --------------------------- |
|
|
446
|
-
| Unitaires — `UploadedFile` | `unit/UploadedFile.test.ts` — `create()` async, `move`/`moveAsync`, `mimeType`, `realName`
|
|
447
|
-
| Unitaires — `@Body` stream | `framework` `unit/BodyStream.test.ts` — `@Body({ stream })`, `resolveParamArg`, `routeExpectsBodyStream`
|
|
448
|
-
| Intégration — multipart | `http/upload.test.ts` — upload simple, multi-fichiers, mime non-octet, champ + fichier, `413` par fichier et cumulé |
|
|
449
|
-
|
|
|
450
|
-
| Intégration —
|
|
451
|
-
| Intégration —
|
|
469
|
+
| Type | Où |
|
|
470
|
+
| --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
471
|
+
| Unitaires — `UploadedFile` | `unit/UploadedFile.test.ts` — `create()` async, `move`/`moveAsync`, `mimeType`, `realName` |
|
|
472
|
+
| Unitaires — `@Body` stream | `framework` `unit/BodyStream.test.ts` — `@Body({ stream })`, `resolveParamArg`, `routeExpectsBodyStream` |
|
|
473
|
+
| Intégration — multipart | `http/upload.test.ts` — upload simple, multi-fichiers, mime non-octet, champ + fichier, `413` par fichier et cumulé ; bornes et empreinte PAR ROUTE (abaissée, relevée), aucun temporaire laissé par un refus |
|
|
474
|
+
| Unitaires — option `upload` | `framework` `unit/httpMethodDecorators.test.ts` — portée jusqu'à la route, figée ; refus à la déclaration |
|
|
475
|
+
| Intégration — content-types | `http/body-content-types.test.ts` — JSON, urlencoded, `@Body("champ")`, XML → `body` |
|
|
476
|
+
| Intégration — bornes | `http/body-limit.test.ts` — sous la limite `200`, `Content-Length` > 1 MiB → `413`, chunked > 1 MiB refusé |
|
|
477
|
+
| Intégration — flux brut | `integration/bodyStream.test.ts` — `@Body({ stream })` bout-en-bout (TLS + clair), non-régression `@Body()` |
|
|
452
478
|
|
|
453
479
|
Ce qui **manque** aujourd'hui : pas de banc de **charge** dédié à l'upload (le streaming multipart n'est
|
|
454
480
|
exercé que fonctionnellement), pas de test **d'attaque** (`*.attack.test.ts`) sur le path traversal de
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nodefony/http",
|
|
3
|
-
"version": "10.0.0-beta.
|
|
3
|
+
"version": "10.0.0-beta.7",
|
|
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",
|
|
@@ -12,6 +12,12 @@
|
|
|
12
12
|
"types": "./dist/types/index.d.ts",
|
|
13
13
|
"import": "./dist/index.js",
|
|
14
14
|
"default": "./dist/index.js"
|
|
15
|
+
},
|
|
16
|
+
"./grpc": {
|
|
17
|
+
"nodefony-source": "./nodefony/grpc/index.ts",
|
|
18
|
+
"types": "./dist/types/nodefony/grpc/index.d.ts",
|
|
19
|
+
"import": "./dist/nodefony/grpc/index.js",
|
|
20
|
+
"default": "./dist/nodefony/grpc/index.js"
|
|
15
21
|
}
|
|
16
22
|
},
|
|
17
23
|
"scripts": {
|
|
@@ -27,7 +33,7 @@
|
|
|
27
33
|
},
|
|
28
34
|
"private": false,
|
|
29
35
|
"engines": {
|
|
30
|
-
"node": "
|
|
36
|
+
"node": "^24.16.0 || >=26.0.0"
|
|
31
37
|
},
|
|
32
38
|
"keywords": [
|
|
33
39
|
"nodefony",
|
|
@@ -51,38 +57,52 @@
|
|
|
51
57
|
"test": "./nodefony/tests"
|
|
52
58
|
},
|
|
53
59
|
"dependencies": {
|
|
54
|
-
"@fastify/busboy": "3.2.
|
|
55
|
-
"
|
|
60
|
+
"@fastify/busboy": "3.2.5",
|
|
61
|
+
"@types/ms": "2.1.0",
|
|
62
|
+
"@types/qs": "6.15.1",
|
|
63
|
+
"@types/serve-static": "2.2.0",
|
|
64
|
+
"@types/ws": "8.18.2",
|
|
65
|
+
"@types/xml2js": "0.4.14",
|
|
66
|
+
"cookie": "2.0.2",
|
|
56
67
|
"mime-types": "3.0.2",
|
|
57
68
|
"ms": "^2.1.3",
|
|
58
|
-
"qs": "^6.
|
|
69
|
+
"qs": "^6.17.1",
|
|
59
70
|
"serve-static": "2.2.1",
|
|
60
|
-
"tslib": "2.
|
|
61
|
-
"ws": "8.
|
|
71
|
+
"tslib": "2.9.1",
|
|
72
|
+
"ws": "8.23.0",
|
|
62
73
|
"xml2js": "0.6.2"
|
|
63
74
|
},
|
|
64
75
|
"devDependencies": {
|
|
65
76
|
"@types/chai": "5.2.3",
|
|
66
77
|
"@types/mime-types": "3.0.1",
|
|
67
|
-
"@types/
|
|
68
|
-
"@types/node": "26.6.5",
|
|
69
|
-
"@types/qs": "6.15.1",
|
|
70
|
-
"@types/serve-static": "2.2.0",
|
|
78
|
+
"@types/node": "26.6.6",
|
|
71
79
|
"@types/websocket": "1.0.10",
|
|
72
|
-
"@
|
|
73
|
-
"
|
|
74
|
-
"@vitest/coverage-v8": "5.0.5",
|
|
75
|
-
"nodefony": "^10.0.0-beta.5",
|
|
80
|
+
"@vitest/coverage-v8": "5.1.0",
|
|
81
|
+
"nodefony": "^10.0.0-beta.7",
|
|
76
82
|
"tsx": "4.23.15",
|
|
77
|
-
"vitest": "5.0
|
|
83
|
+
"vitest": "5.1.0"
|
|
78
84
|
},
|
|
79
85
|
"license": "Apache-2.0",
|
|
80
86
|
"readmeFilename": "README.md",
|
|
81
87
|
"contributors": [],
|
|
82
88
|
"peerDependencies": {
|
|
83
|
-
"
|
|
89
|
+
"@bufbuild/protobuf": "^2.7.0",
|
|
90
|
+
"@connectrpc/connect": "^2.3.0",
|
|
91
|
+
"@connectrpc/connect-node": "^2.3.0",
|
|
92
|
+
"nodefony": "^10.0.0-beta.7",
|
|
84
93
|
"zod": "^4.6.7"
|
|
85
94
|
},
|
|
95
|
+
"peerDependenciesMeta": {
|
|
96
|
+
"@bufbuild/protobuf": {
|
|
97
|
+
"optional": true
|
|
98
|
+
},
|
|
99
|
+
"@connectrpc/connect": {
|
|
100
|
+
"optional": true
|
|
101
|
+
},
|
|
102
|
+
"@connectrpc/connect-node": {
|
|
103
|
+
"optional": true
|
|
104
|
+
}
|
|
105
|
+
},
|
|
86
106
|
"files": [
|
|
87
107
|
"dist",
|
|
88
108
|
"docs"
|
|
@@ -90,7 +110,7 @@
|
|
|
90
110
|
"publishConfig": {
|
|
91
111
|
"access": "public"
|
|
92
112
|
},
|
|
93
|
-
"homepage": "https://nodefony.
|
|
113
|
+
"homepage": "https://nodefony.net/",
|
|
94
114
|
"bugs": {
|
|
95
115
|
"url": "https://github.com/nodefony/nodefony-core/issues"
|
|
96
116
|
}
|