Перейти до вмісту

Архітектура

Загальний потік

За замовчуванням (локальний tmux + тунель):

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

Прямий режим пісочниці (Daytona, без тунелю):

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

Коли задано --no-tunnel, Termbridge пропускає Cloudflare і використовує наданий вами публічний URL.

Компоненти

Процес CLI

  • Запускає сервер HTTP, який обслуговує ресурси UI.
  • Запускає сервер WebSocket для вводу-виводу термінала.
  • Створює один або кілька сеансів tmux (або псевдотерміналів Daytona).
  • Видає одноразові токени для отримання доступу.
  • Запускає тунель і стежить за ним, якщо його ввімкнено (нині Cloudflare).
  • У прямому режимі пісочниці запускає Termbridge усередині пісочниці та очікує на посилання для доступу URL.

Бекенд термінала

  • Бекенд tmux: використовує node-pty для підключення до tmux і передавання натискань клавіш та виводу.
  • Бекенд Daytona: використовує псевдотермінали Daytona у пісочниці.
  • Встановлює TERM=xterm-256color і COLORTERM=truecolor для повної підтримки кольорів.
  • Для tmux вимикає рядок стану tmux, щоб не захаращувати UI.

Реєстр терміналів

  • Відстежує доступні сеанси термінала.
  • Надає список для UI і перевіряє вибрані ідентифікатори терміналів.

Автентифікація та сеанс

  • Одноразовий токен виводиться як URL і кодується у QR коді.
  • GET /__tb/s/:token отримує токен і встановлює сеансовий cookie.
  • Для з’єднань WebSocket потрібні дійсний сеансовий cookie та CSRF-токен.
  • CSRF-токен отримується через GET /__tb/api/csrf і передається як параметр запиту WebSocket.

Режим проксі

Коли передано --proxy <port>:

  • Усі маршрути termbridge розміщуються за префіксом /__tb/
  • Запити, не пов’язані з /__tb/, перенаправляються до цільового застосунку
  • UI надає подання «Термінал» і «Попередній перегляд» через перемикач «Подання»
  • Подання «Попередній перегляд» завантажує iframe, що вказує на /
  • З’єднання WebSocket для HMR пересилаються до цільового застосунку

Безпека

  • Захист від CSRF: для оновлення WebSocket потрібен CSRF-токен, що запобігає перехопленню між сайтами.
  • Обмеження розміру вводу: тіло HTTP до 64KB, повідомлення WebSocket до 1MB, введення в термінал до 64KB на повідомлення.
  • Обмеження частоти запитів: ліміти для отримання токена та з’єднань WebSocket на IP.

Кінцеві точки API

Усі маршрути розміщуються за префіксом /__tb/, щоб уникнути конфліктів із проксійованими застосунками:

  • GET /__tb/healthz — перевірка працездатності
  • GET /__tb/s/:token — отримання токена → cookie → перенаправлення
  • GET /__tb/api/terminals — список терміналів
  • GET /__tb/api/csrf — отримання CSRF-токена для WebSocket
  • GET /__tb/api/config — отримання конфігурації (proxyPort, devProxyUrl)
  • POST /__tb/api/terminals — створення нового сеансу tmux
  • GET /__tb/app/* — резервний маршрут SPA
  • WS /__tb/ws/terminal/:terminalId?csrf=<token> — потокове передавання вводу-виводу термінала

Коли режим проксі ввімкнено:

  • GET / — перенаправляє до проксійованого застосунку (або /__tb/app, якщо вимкнено)
  • * /* — проксіюється до цільового застосунку

Протокол WebSocket

Клієнт → сервер:

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

Сервер → клієнт:

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

Стек UI

  • Vite + TanStack Router
  • xterm.js + додаток Fit + рушій WebGL
  • Макет насамперед для мобільних пристроїв із закріпленим рядком вводу
  • Автоматичне повторне підключення з експоненційною затримкою (до 10 спроб)
  • Індикатор стану з’єднання