@nodefony/realtime 10.0.0-alpha.8 → 10.0.0-beta.1
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/dist/_virtual/{_@oxc-project_runtime@0.150.0 → _@oxc-project_runtime@0.151.0}/helpers/esm/decorate.js +1 -1
- package/dist/_virtual/{_@oxc-project_runtime@0.150.0 → _@oxc-project_runtime@0.151.0}/helpers/esm/decorateMetadata.js +1 -1
- package/dist/index.js +2 -2
- package/dist/nodefony/src/backplane/envelope.js +2 -1
- package/dist/nodefony/src/cluster/ClusterProbeClient.js +1 -1
- package/dist/nodefony/src/server/RealtimeController.js +52 -11
- package/dist/nodefony/src/server/RealtimeHub.js +14 -12
- package/dist/nodefony/src/server/ServerRealtimeSocket.js +9 -7
- package/dist/nodefony/src/service/RealtimeService.js +7 -6
- package/dist/nodefony/testing/index.js +4 -2
- package/dist/types/nodefony/config/defineModuleConfig.d.ts +1 -1
- package/dist/types/nodefony/interfaces/IChannelPolicy.d.ts +3 -3
- package/dist/types/nodefony/interfaces/IRealtimeAuthenticatorMatcher.d.ts +1 -1
- package/dist/types/nodefony/interfaces/IRealtimeHandshake.d.ts +1 -1
- package/dist/types/nodefony/src/server/RealtimeController.d.ts +27 -0
- package/dist/types/nodefony/testing/index.d.ts +2 -2
- package/docs/actions.md +14 -13
- package/docs/architecture.md +35 -35
- package/docs/configuration.md +12 -11
- package/docs/cookbook-chat.md +18 -18
- package/docs/index.md +5 -8
- package/docs/observabilite.md +11 -13
- package/docs/protocole.md +28 -26
- package/docs/securite.md +54 -54
- package/docs/vocabulaire.md +35 -35
- package/package.json +12 -13
package/docs/vocabulaire.md
CHANGED
|
@@ -127,7 +127,7 @@ vers un autre service — et le consommateur ne voit jamais la différence
|
|
|
127
127
|
**`contrôleur` est le même mot qu'en HTTP.** Un endpoint temps réel est un contrôleur qui étend
|
|
128
128
|
`RealtimeController` (`RealtimeController.ts:144`) et porte une route WebSocket : HTTP et WebSocket
|
|
129
129
|
vivent dans le **même contexte de contrôleur**. C'est ce qui permet au pont `api.request`
|
|
130
|
-
(`RealtimeController.realtimeApiRequest()`, `RealtimeController.ts:
|
|
130
|
+
(`RealtimeController.realtimeApiRequest()`, `RealtimeController.ts:276`) de rejouer sur la socket
|
|
131
131
|
**la même action** que celle servie en REST.
|
|
132
132
|
|
|
133
133
|
## 🚀 Démarrage rapide — les mots en situation
|
|
@@ -229,7 +229,7 @@ Un **tuyau bidirectionnel nommé**, multiplexé sur la connexion : `"chat:room-4
|
|
|
229
229
|
`"nodefony:orm:health"`, `"nodefony:socket"`. Convention de nommage par `:` (espace de noms, puis
|
|
230
230
|
précision). Ce n'est pas une classe — c'est une **chaîne de caractères indexée par le hub**.
|
|
231
231
|
|
|
232
|
-
`RealtimeHub.subscribe()` (`RealtimeHub.ts:
|
|
232
|
+
`RealtimeHub.subscribe()` (`RealtimeHub.ts:462`) l'indexe ; `IRealtimeSocket.subscribe()`
|
|
233
233
|
(`IRealtimeSocket.ts:132`) le demande. Plusieurs canaux cohabitent sur **une** connexion : c'est le
|
|
234
234
|
multiplexage.
|
|
235
235
|
|
|
@@ -269,8 +269,8 @@ Un handler qui lève une erreur rend un `-32603` **générique** ; seule une `Rp
|
|
|
269
269
|
### `canal entrant` (inbound) — le client pousse
|
|
270
270
|
|
|
271
271
|
Un canal où le **client a le droit d'émettre** vers le serveur. Défaut sûr : **aucun**. Un canal
|
|
272
|
-
n'accepte d'entrée que déclaré explicitement, par `@RealtimeInbound` (`realtimeDecorators.ts:
|
|
273
|
-
par l'override `realtimeInbound()` (`RealtimeController.ts:
|
|
272
|
+
n'accepte d'entrée que déclaré explicitement, par `@RealtimeInbound` (`realtimeDecorators.ts:231`) ou
|
|
273
|
+
par l'override `realtimeInbound()` (`RealtimeController.ts:262`).
|
|
274
274
|
|
|
275
275
|
Le handler reçoit `(params, reply)` — `params` vient du réseau, donc **jamais fiable** :
|
|
276
276
|
`RealtimeInboundHandler` (`IRealtimeController.ts:16`).
|
|
@@ -297,7 +297,7 @@ importable **sans** aucune dépendance serveur, ce qui est la condition de l'iso
|
|
|
297
297
|
(`ServerRealtimeSocket.ts:223`) : un service métier tient un handle et publie **comme une page
|
|
298
298
|
front**. Une différence assumée : `request()` n'y est pas supporté — au-dessus du hub il n'y a pas
|
|
299
299
|
**un** pair mais N clients. Pour un appel serveur → un client précis, c'est `requestClient()`
|
|
300
|
-
(`RealtimeController.ts:
|
|
300
|
+
(`RealtimeController.ts:329`).
|
|
301
301
|
|
|
302
302
|
### `accueil` (welcome) — la première frame
|
|
303
303
|
|
|
@@ -335,7 +335,7 @@ handshake, jamais renégociée par frame.
|
|
|
335
335
|
### `hub` — le broker du process
|
|
336
336
|
|
|
337
337
|
Le **standard téléphonique** du pod : il tient la table « canal → abonnés locaux » et diffuse. Un
|
|
338
|
-
process = un hub, obtenu par `getRealtimeHub()` (`RealtimeHub.ts:
|
|
338
|
+
process = un hub, obtenu par `getRealtimeHub()` (`RealtimeHub.ts:1451`). Il ne connaît **ni** les
|
|
339
339
|
contrôleurs, **ni** le métier : ce sont les providers qui portent les dépendances.
|
|
340
340
|
|
|
341
341
|
`RealtimeHub` (`RealtimeHub.ts:213`). ⚠️ « hub » désigne **toujours** le serveur ; ce que tient le
|
|
@@ -347,7 +347,7 @@ L'action de diffuser : une charge publiée sur un canal part vers **tous** les s
|
|
|
347
347
|
localement. Une connexion fautive ne casse pas la diffusion aux autres — chaque livraison est isolée.
|
|
348
348
|
|
|
349
349
|
`RealtimeHub.publish()` (`RealtimeHub.ts:604`) pour le chemin complet, `publishLocal()`
|
|
350
|
-
(`RealtimeHub.ts:
|
|
350
|
+
(`RealtimeHub.ts:623`) pour la diffusion **strictement locale** (voie d'entrée du backplane).
|
|
351
351
|
|
|
352
352
|
### `sink` — le point de livraison d'une connexion
|
|
353
353
|
|
|
@@ -371,7 +371,7 @@ Le modèle de coût du module : là où une implémentation naïve crée un tick
|
|
|
371
371
|
Nodefony en crée **un par canal et par pod** et se contente d'ajouter un sink par abonné. Mille
|
|
372
372
|
spectateurs d'un tableau de bord coûtent un timer, pas mille.
|
|
373
373
|
|
|
374
|
-
`RealtimeHub.subscribe()` (`RealtimeHub.ts:
|
|
374
|
+
`RealtimeHub.subscribe()` (`RealtimeHub.ts:462`).
|
|
375
375
|
|
|
376
376
|
### `canal passif` — écouter n'est pas posséder
|
|
377
377
|
|
|
@@ -395,7 +395,7 @@ Un canal dont la fabrique est déclarée par un module bas niveau (le journal d'
|
|
|
395
395
|
qui devient servable par **n'importe quel** endpoint, présent ou futur, sans qu'aucun contrôleur ne
|
|
396
396
|
le connaisse. Consulté seulement quand la fabrique du contrôleur a dit « inconnu ».
|
|
397
397
|
|
|
398
|
-
`RealtimeHub.registerSystemChannel()` (`RealtimeHub.ts:
|
|
398
|
+
`RealtimeHub.registerSystemChannel()` (`RealtimeHub.ts:1297`).
|
|
399
399
|
|
|
400
400
|
### `canal broadcast` — celui qui traverse le backplane
|
|
401
401
|
|
|
@@ -403,7 +403,7 @@ Un canal **déclaré** comme franchissant la frontière du process : chat, prés
|
|
|
403
403
|
déclaration se fait par **préfixe**, ce qui couvre les variantes de cadence (`chat:` couvre
|
|
404
404
|
`chat:room-42:1000`).
|
|
405
405
|
|
|
406
|
-
`RealtimeHub.markBroadcastChannel()` (`RealtimeHub.ts:
|
|
406
|
+
`RealtimeHub.markBroadcastChannel()` (`RealtimeHub.ts:668`), déclaré côté contrôleur par
|
|
407
407
|
`@RealtimeBroadcast` (`realtimeDecorators.ts:342`).
|
|
408
408
|
|
|
409
409
|
### `canal instance-local` — le défaut
|
|
@@ -420,7 +420,7 @@ La classe de base d'un endpoint : elle porte tout le protocole (handshake, accue
|
|
|
420
420
|
des frames, cycle de vie des canaux) et ne laisse au métier que ses canaux et ses actions.
|
|
421
421
|
|
|
422
422
|
`RealtimeController` (`RealtimeController.ts:144`), point d'entrée `handleRealtime()`
|
|
423
|
-
(`RealtimeController.ts:
|
|
423
|
+
(`RealtimeController.ts:299`). C'est un **contrôleur** au sens habituel de Nodefony : la même classe
|
|
424
424
|
peut porter des routes HTTP.
|
|
425
425
|
|
|
426
426
|
### `service realtime` — la façade d'injection
|
|
@@ -437,8 +437,8 @@ L'option qui expose la méthode `api.request { path }` : la connexion rejoue **l
|
|
|
437
437
|
contrôleur** que celle servie en REST, avec **la même garde**. Le pont n'atteint que les routes qui
|
|
438
438
|
déclarent explicitement le transport WebSocket — aucun contournement possible.
|
|
439
439
|
|
|
440
|
-
`realtimeApiRequest()` (`RealtimeController.ts:
|
|
441
|
-
(`RealtimeController.ts:
|
|
440
|
+
`realtimeApiRequest()` (`RealtimeController.ts:276`), mise en œuvre `invokeApiRequest()`
|
|
441
|
+
(`RealtimeController.ts:949`). Désactivé par défaut.
|
|
442
442
|
|
|
443
443
|
## 🔌 Le protocole et le transport — ce qui passe sur le fil
|
|
444
444
|
|
|
@@ -469,14 +469,14 @@ Client et serveur sont des **pairs** : classer une frame, router, corréler les
|
|
|
469
469
|
travail des deux côtés. Nodefony l'écrit **une seule fois** ; chaque côté l'entoure de son transport
|
|
470
470
|
et de ses handlers. Aucune dépendance Node — le même fichier tourne dans le navigateur.
|
|
471
471
|
|
|
472
|
-
`JsonRpcPeer` (`JsonRpcPeer.ts:
|
|
472
|
+
`JsonRpcPeer` (`JsonRpcPeer.ts:280`), contrat `IRealtimePeer` (`JsonRpcPeer.ts:213`).
|
|
473
473
|
|
|
474
474
|
### `dispatch` — classer puis router
|
|
475
475
|
|
|
476
476
|
Le geste du pair sur une frame entrante : décider de sa nature, trouver le handler, l'appeler,
|
|
477
477
|
renvoyer la réponse s'il en faut une. Ce n'est pas une méthode publique — c'est un **moment**, et
|
|
478
478
|
c'est précisément là que se greffe le [verrou de frame](#verrou-de-frame--la-décision-par-frame),
|
|
479
|
-
par le crochet `beforeDispatch` (`JsonRpcPeer.ts:
|
|
479
|
+
par le crochet `beforeDispatch` (`JsonRpcPeer.ts:192`).
|
|
480
480
|
|
|
481
481
|
### `transport` — la couche octets
|
|
482
482
|
|
|
@@ -534,7 +534,7 @@ Le **fond de panier** d'un rack : la carte qui relie toutes les autres. Ici, le
|
|
|
534
534
|
publications d'un process aux autres. Un contrat volontairement minuscule — `publish`, `onMessage`,
|
|
535
535
|
`start`, `stop`, `describe` — parce que tout ce qui est riche appartient au hub.
|
|
536
536
|
|
|
537
|
-
`IBackplane` (`IBackplane.ts:
|
|
537
|
+
`IBackplane` (`IBackplane.ts:107`), message `IBackplaneMessage` (`IBackplane.ts:51`), branchement
|
|
538
538
|
`RealtimeHub.setBackplane()` (`RealtimeHub.ts:714`).
|
|
539
539
|
|
|
540
540
|
> [!TIP]
|
|
@@ -630,7 +630,7 @@ l'authenticator tourne et que l'identité est figée. Tout ce qui coûte cher se
|
|
|
630
630
|
frame.
|
|
631
631
|
|
|
632
632
|
DTO neutre `IRealtimeHandshake` (`IRealtimeHandshake.ts:14`) — en-têtes, cookies, URL, origine,
|
|
633
|
-
sous-protocoles. Traitement dans `onHandshake()` (`RealtimeController.ts:
|
|
633
|
+
sous-protocoles. Traitement dans `onHandshake()` (`RealtimeController.ts:374`).
|
|
634
634
|
|
|
635
635
|
### `authenticator` — du handshake à l'identité
|
|
636
636
|
|
|
@@ -639,7 +639,7 @@ La stratégie qui transforme une poignée de main en identité : `supports` (est
|
|
|
639
639
|
HTTP — un seul modèle mental pour les deux transports.
|
|
640
640
|
|
|
641
641
|
`IRealtimeAuthenticator` (`IRealtimeAuthenticator.ts:24`), enregistrement
|
|
642
|
-
`RealtimeHub.useAuthenticator()` (`RealtimeHub.ts:
|
|
642
|
+
`RealtimeHub.useAuthenticator()` (`RealtimeHub.ts:943`).
|
|
643
643
|
|
|
644
644
|
### `matcher` — qui capture quoi
|
|
645
645
|
|
|
@@ -647,7 +647,7 @@ Le sélecteur (motif d'URL, hôte optionnel) qui décide **quel** authenticator
|
|
|
647
647
|
**premier** qui capture gagne : on enregistre donc du plus spécifique au plus général.
|
|
648
648
|
|
|
649
649
|
`IRealtimeAuthenticatorMatcher` (`IRealtimeAuthenticatorMatcher.ts:25`), résolution
|
|
650
|
-
`resolveAuthenticator()` (`RealtimeHub.ts:
|
|
650
|
+
`resolveAuthenticator()` (`RealtimeHub.ts:961`).
|
|
651
651
|
|
|
652
652
|
### `jeton` (token) — l'identité figée
|
|
653
653
|
|
|
@@ -664,7 +664,7 @@ Les exigences déclarées d'un canal : authentifié, rôles, scopes. Elles s'att
|
|
|
664
664
|
canal, pas à la méthode qui l'implémente — parce que c'est le nom que le pare-feu résout.
|
|
665
665
|
|
|
666
666
|
`IChannelPolicy` (`IChannelPolicy.ts:20`), déclaration par `@RealtimeChannel`
|
|
667
|
-
(`realtimeDecorators.ts:192`), résolution `resolveChannelPolicy()` (`RealtimeHub.ts:
|
|
667
|
+
(`realtimeDecorators.ts:192`), résolution `resolveChannelPolicy()` (`RealtimeHub.ts:1228`).
|
|
668
668
|
|
|
669
669
|
### `verrou de frame` — la décision par frame
|
|
670
670
|
|
|
@@ -672,8 +672,8 @@ La fonction qui répond « cette frame passe-t-elle ? » à partir du jeton **d
|
|
|
672
672
|
**Synchrone par doctrine** : attendre une réponse distante à chaque frame sérialiserait le flux d'une
|
|
673
673
|
connexion. Un contrôle qui doit interroger le réseau se fait au handshake, pas ici.
|
|
674
674
|
|
|
675
|
-
`FrameAuthorizer` (`RealtimeHub.ts:39`), pose `setFrameAuthorizer()` (`RealtimeHub.ts:
|
|
676
|
-
`runAuthorizer()` (`RealtimeHub.ts:
|
|
675
|
+
`FrameAuthorizer` (`RealtimeHub.ts:39`), pose `setFrameAuthorizer()` (`RealtimeHub.ts:1039`), appel
|
|
676
|
+
`runAuthorizer()` (`RealtimeHub.ts:1328`).
|
|
677
677
|
|
|
678
678
|
### `contrôle d'origine` — la défense d'ouverture
|
|
679
679
|
|
|
@@ -681,7 +681,7 @@ Le contrôle de l'en-tête `Origin` à l'ouverture (RFC 6455 §10.2) : un site t
|
|
|
681
681
|
ouvrir une connexion authentifiée dans le dos de l'utilisateur. Correspondance **exacte**, aucun
|
|
682
682
|
caractère générique.
|
|
683
683
|
|
|
684
|
-
`OriginGuard` (`RealtimeHub.ts:
|
|
684
|
+
`OriginGuard` (`RealtimeHub.ts:33`), configuration `csrf.checkOrigin` (`config.ts:255`).
|
|
685
685
|
|
|
686
686
|
### `révocation` — la connexion qui survit à sa session
|
|
687
687
|
|
|
@@ -689,7 +689,7 @@ Le problème que ce mot nomme : une connexion ouverte pourrait survivre à la se
|
|
|
689
689
|
autorisée, puisque le verrou de frame ne relit rien. Un contrôle périodique referme l'écart en
|
|
690
690
|
re-validant les identités révocables et en fermant celles qui ne valent plus.
|
|
691
691
|
|
|
692
|
-
`registerRevocable()` (`RealtimeHub.ts:
|
|
692
|
+
`registerRevocable()` (`RealtimeHub.ts:794`), `revalidateRevocable()` (`RealtimeHub.ts:826`), période
|
|
693
693
|
`REVOCATION_REVALIDATE_MS` (`RealtimeHub.ts:111`). Une re-validation en erreur **ferme** — jamais
|
|
694
694
|
l'inverse.
|
|
695
695
|
|
|
@@ -708,7 +708,7 @@ Le signal émis sur les événements protocolaires qui méritent une trace : fra
|
|
|
708
708
|
refusée, méthode inconnue, erreur interne. Émis sans attente, avec le pair — ce qui permet de
|
|
709
709
|
retrouver **qui** a été refusé, pas seulement d'où venait le paquet.
|
|
710
710
|
|
|
711
|
-
`FrameAuditReason` (`JsonRpcPeer.ts:
|
|
711
|
+
`FrameAuditReason` (`JsonRpcPeer.ts:155`), crochet `onFrameAudit` (`JsonRpcPeer.ts:210`).
|
|
712
712
|
|
|
713
713
|
### `seam` — le point de greffe
|
|
714
714
|
|
|
@@ -716,8 +716,8 @@ Littéralement une **couture** : un point prévu dans une couche basse pour qu'u
|
|
|
716
716
|
greffe du comportement **sans modifier la couche basse**. Le module en expose cinq, et c'est ce qui
|
|
717
717
|
permet à la couche sécurité de se brancher sans qu'aucune ligne de realtime ne la connaisse.
|
|
718
718
|
|
|
719
|
-
Les deux du protocole sont `beforeDispatch` (`JsonRpcPeer.ts:
|
|
720
|
-
(`JsonRpcPeer.ts:
|
|
719
|
+
Les deux du protocole sont `beforeDispatch` (`JsonRpcPeer.ts:192`) et `onFrameAudit`
|
|
720
|
+
(`JsonRpcPeer.ts:210`) ; les trois du hub sont l'authenticator, le matcher et le contrôle d'origine.
|
|
721
721
|
|
|
722
722
|
→ [Sécurité](./securite.md) pour le détail de chacun.
|
|
723
723
|
|
|
@@ -728,7 +728,7 @@ ressources ; sans borne, une seule connexion peut les épuiser. Au-delà, l'abon
|
|
|
728
728
|
client en est informé.
|
|
729
729
|
|
|
730
730
|
`limits.maxChannelsPerConnection` (`config.ts:142`), pose `setMaxChannelsPerConnection()`
|
|
731
|
-
(`RealtimeHub.ts:
|
|
731
|
+
(`RealtimeHub.ts:995`).
|
|
732
732
|
|
|
733
733
|
## 📡 L'observabilité — ce que la socket dit d'elle-même
|
|
734
734
|
|
|
@@ -747,7 +747,7 @@ L'oscilloscope du module : « voici mon état, maintenant ». Canaux et abonnés
|
|
|
747
747
|
livraisons, connexions, octets, back-pressure, carte d'identité du backplane. Lecture **pure**, sans
|
|
748
748
|
allocation sur le chemin chaud.
|
|
749
749
|
|
|
750
|
-
`RealtimeHub.probe()` (`RealtimeHub.ts:
|
|
750
|
+
`RealtimeHub.probe()` (`RealtimeHub.ts:865`) rend un `IRealtimeProbe` (`IRealtimeProbe.ts:61`).
|
|
751
751
|
|
|
752
752
|
> [!WARNING]
|
|
753
753
|
> `IRealtimeProbe` est la **forme des données**, pas une interface à implémenter avec une méthode
|
|
@@ -769,8 +769,8 @@ décide de rien. Les seuils d'ACTION, eux, sont des réglages : `websocket.maxBa
|
|
|
769
769
|
Une connexion dont le back-pressure dépasse le seuil de comptage. C'est une **métrique**, pas une
|
|
770
770
|
sanction : le seuil de comptage se règle indépendamment des seuils d'action.
|
|
771
771
|
|
|
772
|
-
`slowConsumer.bytes` (`config.ts:
|
|
773
|
-
(`IRealtimeProbe.ts:
|
|
772
|
+
`slowConsumer.bytes` (`config.ts:121`), champ `backpressure.slowConsumers`
|
|
773
|
+
(`IRealtimeProbe.ts:102`).
|
|
774
774
|
|
|
775
775
|
### `compteurs de canal` — mesurés à l'arrivée
|
|
776
776
|
|
|
@@ -794,20 +794,20 @@ Le producteur qui expose la sonde sous `/nodefony/realtime/api/health`, selon la
|
|
|
794
794
|
routage des administrations de modules. C'est de l'**auto-observabilité** : la socket se regarde
|
|
795
795
|
elle-même par le même chemin que les autres modules.
|
|
796
796
|
|
|
797
|
-
`createRealtimeAdminApi()` (`RealtimeAdminApi.ts:
|
|
797
|
+
`createRealtimeAdminApi()` (`RealtimeAdminApi.ts:98`), construction `buildOwnHealth()`
|
|
798
798
|
(`RealtimeAdminApi.ts:52`).
|
|
799
799
|
|
|
800
800
|
## ⚠️ Pièges — les faux-amis du vocabulaire
|
|
801
801
|
|
|
802
802
|
| Symptôme | Cause — le mot pris pour un autre | Correction |
|
|
803
803
|
| ------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- |
|
|
804
|
-
| « Je suis abonné mais je ne reçois rien » | `subscribe` confondu avec `on` : le flux est demandé, aucun écouteur ne le lit | Les deux : `subscribe(canal)` **et** `on(canal, handler)` (`IRealtimeSocket.ts:
|
|
804
|
+
| « Je suis abonné mais je ne reçois rien » | `subscribe` confondu avec `on` : le flux est demandé, aucun écouteur ne le lit | Les deux : `subscribe(canal)` **et** `on(canal, handler)` (`IRealtimeSocket.ts:131`) |
|
|
805
805
|
| « Ça marche en local, plus rien dès qu'on passe à plusieurs pods » | canal resté **instance-local** — le défaut. Traverser le process est une capacité qu'on **demande** | Déclarer le préfixe dans `@RealtimeBroadcast` (`realtimeDecorators.ts:342`) |
|
|
806
|
-
| « Le client publie, le serveur ignore » | canal non déclaré **entrant**. Un client ne peut rien pousser tant qu'aucun handler n'existe | `@RealtimeInbound("mon:canal")` (`realtimeDecorators.ts:
|
|
806
|
+
| « Le client publie, le serveur ignore » | canal non déclaré **entrant**. Un client ne peut rien pousser tant qu'aucun handler n'existe | `@RealtimeInbound("mon:canal")` (`realtimeDecorators.ts:231`) |
|
|
807
807
|
| Deux déploiements se mélangent sur un même serveur Redis | pas de **cloison** — le numéro de base ne cloisonne pas le pub/sub | Poser `backplane.namespace` (`config.ts:59`) |
|
|
808
808
|
| Le fan-out disparaît entre conteneurs identiques | **origine** dérivée du seul identifiant de processus : deux conteneurs sont tous deux le n° 1, l'anti-écho avale tout | `resolveBackplaneOriginId()` (`originId.ts:24`) dérive du pod ou de l'hôte |
|
|
809
809
|
| Deux tickers pour le même tableau de bord | **cadence** différente = **canal** différent, jamais réconcilié | Fabriquer le nom via `rateChannel()` (`channelRate.ts:44`) des deux côtés |
|
|
810
|
-
| Un canal se croit protégé mais laisse tout passer | **politique** déclarée sans **verrou de frame** posé pour la faire respecter | Le hub le détecte et avertit : `hasUnenforcedChannelPolicies()` (`RealtimeHub.ts:
|
|
810
|
+
| Un canal se croit protégé mais laisse tout passer | **politique** déclarée sans **verrou de frame** posé pour la faire respecter | Le hub le détecte et avertit : `hasUnenforcedChannelPolicies()` (`RealtimeHub.ts:1117`) |
|
|
811
811
|
| Une connexion garde ses flux après une déconnexion applicative | le **verrou de frame** ne relit rien : par construction, il ne voit pas la session mourir | Inscrire l'identité au registre de **révocation** (`RealtimeHub.ts:433`) |
|
|
812
812
|
| « Le provider a planté après la fermeture d'un onglet » | **provider** confondu avec **sink** : le provider est partagé, il survit à la connexion créatrice | N'y capturer que des dépendances à longue vie (`ChannelFactory`, `RealtimeHub.ts:170`) |
|
|
813
813
|
| « Notre store realtime est indisponible » | **store** employé pour **driver** : le backplane ne conserve rien, il fait passer | Dire « le driver de backplane » — les données ont des stores, les flux ont des drivers |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nodefony/realtime",
|
|
3
|
-
"version": "10.0.0-
|
|
3
|
+
"version": "10.0.0-beta.1",
|
|
4
4
|
"description": "Couche temps réel serveur de Nodefony : canaux, appels bidirectionnels JSON-RPC 2.0, contre-pression, et diffusion entre plusieurs instances (boucle locale, IPC de grappe, Redis)",
|
|
5
5
|
"author": "Christophe CAMENSULI <ccamensuli@gmail.com>",
|
|
6
6
|
"type": "module",
|
|
@@ -20,9 +20,9 @@
|
|
|
20
20
|
"./package.json": "./package.json"
|
|
21
21
|
},
|
|
22
22
|
"scripts": {
|
|
23
|
-
"build": "
|
|
23
|
+
"build": "rolldown -c rolldown.config.ts && tsgo -p tsconfig.declarations.json",
|
|
24
24
|
"dev": "rolldown -c rolldown.config.ts --watch",
|
|
25
|
-
"clean": "
|
|
25
|
+
"clean": "node --eval \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"",
|
|
26
26
|
"test": "vitest run",
|
|
27
27
|
"test:cluster": "vitest run --config vitest.cluster.config.ts",
|
|
28
28
|
"coverage": "vitest run --coverage",
|
|
@@ -41,21 +41,20 @@
|
|
|
41
41
|
"esm"
|
|
42
42
|
],
|
|
43
43
|
"peerDependencies": {
|
|
44
|
-
"@nodefony/framework": "^10.0.0-
|
|
45
|
-
"@nodefony/http": "^10.0.0-
|
|
46
|
-
"nodefony": "^10.0.0-
|
|
44
|
+
"@nodefony/framework": "^10.0.0-beta.1",
|
|
45
|
+
"@nodefony/http": "^10.0.0-beta.1",
|
|
46
|
+
"nodefony": "^10.0.0-beta.1",
|
|
47
47
|
"reflect-metadata": "0.2.2",
|
|
48
48
|
"zod": "^4.6.5"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
|
-
"@nodefony/framework": "^10.0.0-
|
|
52
|
-
"@nodefony/http": "^10.0.0-
|
|
53
|
-
"@types/node": "26.6.
|
|
54
|
-
"@vitest/coverage-v8": "5.0.
|
|
55
|
-
"nodefony": "^10.0.0-
|
|
51
|
+
"@nodefony/framework": "^10.0.0-beta.1",
|
|
52
|
+
"@nodefony/http": "^10.0.0-beta.1",
|
|
53
|
+
"@types/node": "26.6.3",
|
|
54
|
+
"@vitest/coverage-v8": "5.0.2",
|
|
55
|
+
"nodefony": "^10.0.0-beta.1",
|
|
56
56
|
"reflect-metadata": "0.2.2",
|
|
57
|
-
"
|
|
58
|
-
"vitest": "5.0.1"
|
|
57
|
+
"vitest": "5.0.2"
|
|
59
58
|
},
|
|
60
59
|
"private": false,
|
|
61
60
|
"engines": {
|