Architecture
画面からLINE RPCまで、どの層が何を担当するかを整理します。
全体像
Browser
│ HTTP (通常のUI同期)
│ WebSocket (通話PCMブリッジ)
▼
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
責務境界
| 層 | 責務 | 主な場所 |
|---|---|---|
| UI | 会話、設定、アカウント、テーマ等の表示 | Vyline/apps/desktop |
| Backend | HTTP API、アカウント状態、DB、メディア、restore、plugin runtime | Vyline/backend |
| Protocol | LINE RPC、login、transport、E2EE、Talk domain | Vyline/packages/protocol |
| Plugin | 外部拡張の型・権限・lifecycle | Vyline/packages/plugin |
| Themes | VyTheme preset/token | Vyline/packages/themes |
| Tools | Desktop LINEのversion/unpack/xref/decompile補助 | tools |
WebからLINEまで
- UIがBackendのBFF APIを呼ぶ。
- Backendがaccount IDからlogin済みsessionを取得する。
lineServiceまたはdomain facadeがProtocolへ処理を渡す。- Protocolがdevice mode、transport、E2EE状態を使ってLINEへRPCを送る。
- 取得したchat/messageはBackendのaccount別SQLiteへ反映される。
- Frontendはbootstrapと差分pollingでstoreへ取り込む。通話だけは専用WebSocketを使う。
起動とsession復元
- Bunが
Vyline/backend/src/index.tsを起動し、Hono router・static UI・WebSocket upgrade handlerを用意する。 clientManagerが保存済みaccount/sessionを読み、利用可能なsessionを復元する。- sessionをactivateするとE2EE/transportを含むProtocol clientを使える状態にし、バックグラウンドのTalk syncを開始する。
- Browserはaccountを選ぶと
/line/:accountId/bootstrapからローカルSQLiteのchat/message previewを先に取得する。 - 初期表示後に
useVylineSyncが新着eventとactive chatのdeltaを同期し、必要な部分だけstoreへmergeする。
初回表示を毎回LINE RPC待ちにしないのが重要です。bootstrapはローカルDBから即時hydrateし、remote fetchはfreshnessやユーザー操作に応じて後から行います。
受信・同期の流れ
LINE Talk sync
↓
clientManager fetch-ops loop
↓
lineService.processFetchedOperations
├─ decrypt / normalize
├─ SQLiteへ保存
└─ event bufferへ追加
↓
GET /line/:accountId/events/poll?cursor=...
↓
Frontend pollIncoming()
↓
Zustand store / active chat
active chatは必要に応じて
GET /messages/:chatMid/delta?after=...
でも追従
Backend側には通常処理用Talk RPC、background poll、urgent fetch、sendの実行経路が分かれており、同期処理が送信を不必要に塞がないようclientManagerで調整しています。
送信の流れ
Composer
↓ HTTP
POST /line/:accountId/send
↓
api/line.ts 入力検証・HTTP response
↓
lineService message生成・E2EE・retry・保存
↓
@vyline/protocol TalkService / E2EE RPC
↓
LINE
↓
結果をSQLite/storeへ反映
api/line.tsはBFF境界で、LINE固有のretryやE2EE処理を抱え込まずservice/lineService.tsへ委譲します。Protocolの生Thrift型をUIへ直接返すのではなく、Backend/Frontendの型へ正規化して渡します。
メディア
画像・動画・音声・ファイルはmessage metadataとbinary本体を分けて扱います。Protocol/BackendがLINEのobject storage経路とE2EEを処理し、BrowserはBackendのmedia endpointを通して取得します。Dockerでは保存済みmedia/cacheは/app/storage、account状態・chat DB等は/app/dataへ分離して永続化します。
BrowserとBackendの信頼境界
loopback bindではowner accessをローカルとして扱います。非loopback bindは、VYLINE_LAN_ACCESSを変更していなくてもremote deploymentとして扱われ、BFFはinstallation-bound subdevice sessionを要求します。Browser側はinstallation IDとsessionを組み合わせ、別browserへtokenだけをコピーしても同じsessionとして扱わない設計です。
VYLINE_TRUST_REMOTE_OWNER=trueは、Tailscale ACLやCloudflare Access等で到達経路自体を別層で強く制限している場合に、そのtransportをowner trustとして明示するための例外です。通常のLAN/Internet公開用スイッチではありません。
本体とsubmodule
protocol、plugin、themes、tools はGit submoduleです。一方、Backend、Desktop UI、共有型、CLI等はメインリポジトリのworkspaceです。Protocol単体の型チェックでは @vyline/line-types など兄弟workspace packageも必要になります。
Source Map
| 追いたい処理 | 入口 | 次に見る場所 |
|---|---|---|
| 画面のデータ取得 | apps/desktop/src/api/client.ts | hooks/useLineData.ts / useVylineSync.ts |
| HTTP endpoint | backend/src/api/line.ts | service/lineService.ts |
| account/session | backend/src/line/clientManager.ts | @vyline/protocol login/client |
| 永続化 | backend/src/storage/chatStore.ts | chatStoreSqlite.ts / media storage |
| LINE RPC | packages/protocol/src/dictionary/rpcMap.ts | stack → domain → Backend |
| Desktop更新追従 | packages/protocol/src/modules.map.ts | tools / analysis docs |
詳細は Submodules を参照してください。LINE通信はProtocol、永続化とアプリの業務処理はBackend、presetはThemes、Desktop仕様の調査はToolsにあります。