Vyline DOCS

Architecture

A map of which layer owns each step from the browser UI down to LINE RPC.

Overview

Browser
  │ HTTP (normal UI synchronization)
  │ WebSocket (call PCM bridge)
  ▼
Desktop Web UI (Vyline/apps/desktop)
  │
  ▼
Backend (Vyline/backend)
  ├─ account/session orchestration
  ├─ API / storage / restore / media
  ├─ plugin runtime
  └─ profileBridge / lineService
       │
       ▼
@vyline/protocol  ← submodule: vyline-api
  ├─ login (QR / Email / Token)
  ├─ transport / headers / RPC
  ├─ E2EE / identity
  ├─ Talk / sync / domain facade
  └─ Desktop profile updater
       │
       ▼
LINE services

side modules:
@vyline/plugin-sdk ← submodule
@vyline/themes     ← submodule
Vyline-Search      ← submodule / reverse-engineering toolchain

Layer boundaries

LayerResponsibilityMain location
UIChats, settings, accounts, themes, and other presentationVyline/apps/desktop
BackendHTTP API, account state, DB, media, restore, plugin runtimeVyline/backend
ProtocolLINE RPC, login, transport, E2EE, Talk domainVyline/packages/protocol
PluginTypes, permissions, and lifecycle for extensionsVyline/packages/plugin
ThemesVyTheme presets and tokensVyline/packages/themes
ToolsDesktop LINE version, unpack, xref, and decompile toolingtools

From the web UI to LINE

  1. The UI calls a Backend BFF endpoint.
  2. The Backend resolves the logged-in session from the account ID.
  3. lineService or a domain facade passes the operation to Protocol.
  4. Protocol sends a LINE RPC using the selected device mode, transport profile, and E2EE state.
  5. Returned chats and messages are written to the account-specific SQLite database.
  6. The Frontend merges bootstrap data and polling deltas into its store. Calls use a dedicated WebSocket path.

Startup and session restoration

  1. Bun starts Vyline/backend/src/index.ts, which sets up the Hono router, static UI, and WebSocket upgrade handler.
  2. clientManager reads saved account/session state and restores sessions that can be resumed.
  3. Activating a session prepares the Protocol client, including transport and E2EE state, then starts background Talk synchronization.
  4. When a browser selects an account, it first reads local chat/message previews from /line/:accountId/bootstrap.
  5. After the first render, useVylineSync synchronizes new events and active-chat deltas, merging only the required data into the store.

The first screen should not wait for LINE RPC on every launch. bootstrap hydrates from the local database immediately; remote fetches run afterward according to freshness and user actions.

Receive and synchronization flow

LINE Talk sync
  ↓
clientManager fetch-ops loop
  ↓
lineService.processFetchedOperations
  ├─ decrypt / normalize
  ├─ persist to SQLite
  └─ append to event buffer
       ↓
GET /line/:accountId/events/poll?cursor=...
       ↓
Frontend pollIncoming()
       ↓
Zustand store / active chat

the active chat can also follow
GET /messages/:chatMid/delta?after=...
when needed

The Backend keeps normal Talk RPC, background polling, urgent fetches, and send operations on separate execution paths. clientManager coordinates them so background synchronization does not unnecessarily block sending.

Send flow

Composer
  ↓ HTTP
POST /line/:accountId/send
  ↓
api/line.ts       input validation / HTTP response
  ↓
lineService       message creation / E2EE / retry / persistence
  ↓
@vyline/protocol  TalkService / E2EE RPC
  ↓
LINE
  ↓
persist result to SQLite / store

api/line.ts is the BFF boundary. LINE-specific retries and E2EE handling belong in service/lineService.ts, not in the route itself. Raw Thrift types are normalized into Backend/Frontend types instead of being exposed directly to the UI.

Media

Images, video, audio, and files keep message metadata separate from binary content. Protocol and Backend handle LINE object-storage paths and E2EE; the browser retrieves media through Backend media endpoints. In Docker, saved media/cache lives under /app/storage, while account state and chat databases live under /app/data.

Browser/Backend trust boundary

With a loopback bind, owner access is treated as local. A non-loopback bind is treated as a remote deployment even when VYLINE_LAN_ACCESS remains unchanged, and the BFF requires an installation-bound subdevice session. The browser combines an installation ID with the session so copying only a token into another browser does not reproduce the same session.

VYLINE_TRUST_REMOTE_OWNER=true is an explicit exception for deployments where the transport is already strongly restricted by another layer, such as Tailscale ACLs or Cloudflare Access. It is not a general switch for exposing Vyline to a LAN or the Internet.

Main repository and submodules

protocol, plugin, themes, and tools are Git submodules. Backend, Desktop UI, shared types, CLI packages, and other workspaces live in the main repository. Type-checking Protocol by itself still requires sibling workspace packages such as @vyline/line-types.

Source map

What you are tracingStart hereThen inspect
UI data loadingapps/desktop/src/api/client.tshooks/useLineData.ts / useVylineSync.ts
HTTP endpointbackend/src/api/line.tsservice/lineService.ts
Account/sessionbackend/src/line/clientManager.ts@vyline/protocol login/client
Persistencebackend/src/storage/chatStore.tschatStoreSqlite.ts / media storage
LINE RPCpackages/protocol/src/dictionary/rpcMap.tsstack → domain → Backend
Desktop update trackingpackages/protocol/src/modules.map.tstools / analysis docs

See Submodules for the repository boundaries in detail. LINE communication belongs to Protocol, persistence and application behavior to Backend, presets to Themes, and Desktop protocol research to Tools.

Search by page, setting, or command