431013c3e3
Ручной модуль api/calls.ts повторяет контракт сервера: разбор звонка один и тот же для REST-ручек, READY-снапшота и событий DM_CALL_*, поэтому состояние разбирается одним кодом. Стор dmCall ведёт медиа-сессию поверх общей обёртки lib/livekit: те же плитки, устройства, качество публикации и продление токена, но без серверных ролей — мьют и деаф только свои. Рингтон синтезируется Web Audio (файлов в проекте нет): входящий — пока звонят нам, исходящий — пока ждём ответа; свёрнутая вкладка замолкает. Карточка беседы несёт active_call: маркер «идёт звонок» приходит в READY и в списке бесед, а дальше обновляется событиями DM_CALL_RING/UPDATE/END. Завершение гасит локальную сессию и играет сигнал тем, кто был в звонке.