Client/serveur et canal

La règle

Un broker par environnement. Un canal est un objet standard, abonné des deux côtés en miroir croisé de CHANNEL. Rien ne parle jamais directement au canal : chaque objet publie auprès de son broker. Émettre = publier au broker, jamais « envoyer au serveur ».

Pourquoi

Les objets coexistent sans savoir sur quelle machine s'exécutent les autres. Un frère local peut réagir à une émission destinée au serveur. Et changer de transport ne touche ni les composants, ni les contrats, ni les brokers.

Dans le chat

ecran_connexion est abonné localement à deconnexion_demande, un message destiné au serveur : il repasse à l'état vierge sans composant de navigation.

Contre-exemple

this.deps.socket.send(JSON.stringify({ message_demande: { ref, texte } })); // un composant qui parle au transport

Plus de validation, plus de frère local, plus de test sans réseau. Le composant connaît le transport : il n'est plus un composant fwtozza.

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

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.

Montage