MallaDocs

Temps réel et multijoueur

Salles Yjs dans des Durable Objects, présence, points de contrôle et mises à jour d’agents annulables.

Guide développeur

Chaque page, chaque composant et chaque site a une salle : un Durable Object YRoom qui synchronise un document Yjs via WebSockets, gère la présence, persiste dans son propre stockage SQLite et fait des points de sauvegarde dans Postgres. La salle est aussi le chemin d'enregistrement de l'éditeur, même quand vous travaillez seul.

Jetonapi GET /auth/realtime-token?siteId= signe un jeton de courte durée.
ConnexionWebSocket vers /rooms/page:<id>?token=… ; l'origine et le site sont vérifiés.
SynchronisationProtocole y-websocket ; chaque mise à jour est validée avant d'être conservée.
Point de sauvegardeUne alarme écrit le JSON + l'état Yjs dans Postgres en moins de 30 s.

Salles

  • Les noms sont page:<pageId> (pages et composants) ou site:<siteId> (liste des pages, classes, jetons, variables, formules).
  • Les jetons sont vérifiés par salle ; les lecteurs reçoivent le document et la présence, mais leurs mises à jour sont ignorées. Les éditeurs de contenu ne peuvent modifier que du texte.
  • Les sockets hibernent : une salle inactive ne coûte donc rien ; la présence survit au réveil grâce aux pièces jointes des sockets.
  • Limites : 4 Mio par message, 256 sockets par salle.
ts
import { WebsocketProvider } from 'y-websocket'

const provider = new WebsocketProvider(realtimeUrl + '/rooms', 'page:p_home', ydoc, {
  params: { token },
})

Validation côté serveur

Chaque mise à jour est d'abord appliquée à une copie fantôme. Chaque enregistrement qu'elle a touché est relu en JSON et vérifié : schéma du nœud, liaisons uniquement sur les props liables, $model uniquement sur les champs de formulaire, chaque $expr doit s'analyser, forme des workflows. Une mise à jour en échec n'est ni stockée ni relayée, et la connexion de l'expéditeur est fermée avec 4422, un code définitif pour que le client ne la renvoie pas.

Protocole

text
type 0    sync          step1 / step2 / update (relayed to other sockets)
type 1    awareness     cursors, selections (relayed to every socket)
type 3    query awareness
type 100  agent update  Malla extension: origin byte (0 = ai, 1 = mcp) + Yjs update,
                        sent only to the sockets of the user an AI/MCP edit acted for

Persistance

  • Un journal de mises à jour en ajout seul plus un instantané, compacté à 500 lignes ou 1 Mo, et quand le dernier socket se déconnecte.
  • Les salles vides sont amorcées depuis Postgres avant la première synchronisation : un client ne synchronise donc jamais un document vide par-dessus du vrai contenu.
  • Les points de sauvegarde dans Postgres sont retentés avec backoff pendant cinq minutes au maximum ; la synchronisation ne les attend jamais.

Modifications de l'IA et de MCP annulables

Les modifications côté serveur arrivent dans la salle via POST /internal/rooms/:room/ops, avec l'utilisateur pour le compte duquel elles sont faites. La salle les applique une seule fois, envoie aux sockets de cet utilisateur une agent update (type 100) et à tous les autres une mise à jour ordinaire. L'éditeur applique les agent updates avec l'origine ai ou mcp, que son gestionnaire d'annulation suit comme une étape distincte. Ainsi, l'utilisateur concerné peut annuler le changement de l'agent, et personne ne peut annuler celui de quelqu'un d'autre.