Aller au contenu

Architecture

Vue d’ensemble du flux

Par défaut (local tmux + tunnel) :

Code
Browser (phone)
  |
  | HTTPS
  v
Cloudflare Quick Tunnel
  |
  | HTTP/WS
  v
Local Termbridge server
  |
  | PTY
  v
Tmux session

Mode bac à sable direct (Daytona, sans tunnel) :

Code
Browser (phone)
  |
  | HTTPS
  v
Daytona preview link
  |
  | HTTP/WS
  v
Termbridge server (sandbox)
  |
  | PTY
  v
Tmux session (sandbox)

Lorsque --no-tunnel est défini, Termbridge ignore Cloudflare et utilise le URL public que vous avez fourni.

Composants

Processus CLI

  • Démarre le serveur HTTP qui sert les ressources UI.
  • Démarre le serveur WebSocket pour les entrées-sorties du terminal.
  • Crée une ou plusieurs sessions tmux (ou des pseudo-terminaux Daytona).
  • Émet des jetons à usage unique.
  • Démarre et surveille le tunnel lorsqu’il est activé (Cloudflare actuellement).
  • En mode bac à sable direct, lance Termbridge dans le bac à sable et attend le URL de partage.

Backend du terminal

  • Backend tmux : utilise node-pty pour se connecter à tmux et gérer les frappes réelles et la sortie.
  • Backend Daytona : utilise les pseudo-terminaux Daytona dans un bac à sable.
  • Définit TERM=xterm-256color et COLORTERM=truecolor pour la prise en charge complète des couleurs.
  • Pour tmux, désactive la barre d’état tmux afin de garder UI propre.

Registre des terminaux

  • Suit les sessions de terminal disponibles.
  • Fournit une liste pour UI et valide les identifiants des terminaux sélectionnés.

Authentification et session

  • Le jeton à usage unique est affiché sous forme de URL et encodé dans un code QR.
  • GET /__tb/s/:token échange le jeton et crée une session par cookie.
  • Les connexions WebSocket nécessitent un cookie de session valide et un jeton CSRF.
  • Le jeton CSRF est récupéré via GET /__tb/api/csrf et transmis dans le paramètre de requête WebSocket.

Mode proxy

Lorsque --proxy <port> est transmis :

  • Toutes les routes termbridge sont sous le préfixe /__tb/.
  • Les requêtes autres que /__tb/ sont transmises au proxy de l’application cible.
  • UI expose les vues Terminal/Aperçu via le sélecteur de vues.
  • La vue Aperçu charge un iframe pointant vers /.
  • Les connexions WebSocket pour HMR sont transmises à la cible.

Sécurité

  • Protection CSRF : les mises à niveau WebSocket exigent un jeton CSRF pour prévenir le détournement intersites.
  • Limites d’entrée : corps HTTP de 64KB, message WebSocket de 1MB, entrée du terminal de 64KB par message.
  • Limitation du débit : limites par IP pour l’échange des jetons et les connexions WebSocket.

Points de terminaison API

Toutes les routes sont sous le préfixe /__tb/ pour éviter les conflits avec les applications utilisant le proxy :

  • GET /__tb/healthz - vérification de l’état
  • GET /__tb/s/:token - échange du jeton → cookie → redirection
  • GET /__tb/api/terminals - lister les terminaux
  • GET /__tb/api/csrf - obtenir le jeton CSRF pour WebSocket
  • GET /__tb/api/config - obtenir la configuration (proxyPort, devProxyUrl)
  • POST /__tb/api/terminals - créer une nouvelle session tmux
  • GET /__tb/app/* - solution de repli pour SPA
  • WS /__tb/ws/terminal/:terminalId?csrf=<token> - flux des entrées-sorties du terminal

Lorsque le mode proxy est activé :

  • GET / - redirige vers l’application utilisant le proxy (ou /__tb/app si désactivé)
  • * /* - transmis au proxy de l’application cible

Protocole WebSocket

Client → serveur :

JSON
{ "type": "input", "data": "ls -la" }
{ "type": "resize", "cols": 120, "rows": 32 }
{ "type": "control", "key": "ctrl_c" }

Serveur → client :

JSON
{ "type": "output", "data": "..." }
{ "type": "status", "state": "connected" }

Pile UI

  • Vite + TanStack Router
  • xterm.js + extension Fit + moteur de rendu WebGL
  • Mise en page conçue d’abord pour les mobiles, avec une barre de saisie fixe
  • Reconnexion automatique avec délai exponentiel (jusqu’à 10 tentatives)
  • Indicateur d’état de connexion