Client/serveur et canal
Un catalogue par canal
Chaque x.catalog.js exporte le trio de sa population de clients : SHARED (les contrats client ↔ serveur), FINGERPRINT (millésime manuel, consultatif) et CHANNEL (l'autorisation de transit : clientEmits, clientReceives). Les deux moitiés importent littéralement le même fichier.
Chaque broker reçoit un seul catalogue d'union, seul endroit où les catalogues de canaux se rencontrent, et où vivent les contrats client-only ou serveur-only. Le spread ne fusionne pas : garde-fou obligatoire, comparé en forme canonique.
Les clés d'enveloppe id et session
id: identifiant de session, stable à travers les reconnexions. Le canal serveur le pose sur tout entrant. Un objet serveur peut le joindre à son émission (une session ou un tableau) pour ne toucher que ces clients ; sansid, diffusion à tous. Ne part jamais sur le réseau.session: l'objet{ data }, joint côté serveur par référence, jamais cloné. C'est cette référence partagée qui fait vivre l'état de session sans annuaire global.
Le broker client ignore les deux clés.
connection_event
Contrat fourni par fw/channel.catalog.js, payload { event, channel }, enveloppe portant id et session. Publié à quatre moments : connected, resumed, disconnected (la session survit), expired (TTL écoulé, dernière livraison où la session est lisible). C'est là qu'un composant libère ce qu'il tenait.
Le handshake
Rien ne transite avant accord. Le client envoie ses listes de transit, les schémas complets des messages qui traversent, et le jeton d'une session à reprendre. Le serveur juge la compatibilité : mêmes messages et versions, égalité des schémas des révisions partagées en forme canonique, règle directionnelle « récepteur ≥ émetteur ». On valide toujours contre son propre catalogue, jamais celui du pair. Le millésime différent n'est qu'un avertissement. En retour : un jeton et les bases d'upcast serveur → client.
Les exigences d'un canal, en trois strates
A, tout canal : (1) objet standard, transport reçu ouvert par deps, pas de destroy() ; (2) miroir croisé de CHANNEL, validation aux deux bouts ; (3) forme canonique, jamais de downcast ; (4) plomberie hors catalogue, mais id/session sont du framework.
B, canal pontant deux catalogues séparés : (5) rien ne transite avant accord ; (6) décision d'alignement normative ; (7) upcast vers le latest local.
C, sessions : (8) sessions à jeton survivant sessionTtlMs ; (9) le canal peuple id/session et traduit un id en sockets ; (10) il publie connection_event ; (11) grille d'admission allowMessage, requise dès qu'un canal porte des sessions.
Le canal local en mémoire de la démo respecte A et C, sans B : ses deux moitiés chargent le même catalogue.
Garanties
Tant que la connexion vit, TCP garantit livraison et ordre. Les messages émis pendant une coupure sont perdus (avertissement), sans tampon ni rejeu ; la session survit, et c'est aux composants de rejouer l'état applicatif au retour.