Verstak · Релизы 20 июня 2026 · дневник разработки

Сага релизов: 9% install error и лимит GitHub API

Если бы меня спросили, что в десктопном продукте недооценивают сильнее всего — я бы ответил: доставку обновлений. Написать фичу — полдела. Сделать так, чтобы она доехала до пользователя и установилась, — отдельный продукт со своими граблями. У Verstak их было много.

Канал обновлений — electron-updater + GitHub Releases (frolofpavel/verstak). Версии 1.5.8 → 1.5.17 — это почти сплошь сага про надёжность доставки.

Грабля №1: лимит GitHub API (фикс 1.5.12)

Апдейтер на каждой проверке дёргал api.github.com — releases/latest + tags + release-notes. Неавторизованный лимит — 60 запросов в час на IP. Результат: 403 → fetchRemoteVersion возвращает null → у пользователя «обновлений нет», автообновление молча мертво.

Фикс: версию берём из raw.githubusercontent/.../package.json — это CDN, лимит API не ест. API остаётся только как fallback. Кэш версии 20 минут. 403 + x-ratelimit-remaining: 0 детектится → backoff + флаг для UI.

Правило, выведенное кровью: не добавлять вызовы api.github.com в update-флоу без крайней нужды. raw-CDN для версии, latest.yml (download URL) для артефактов — они лимит не едят.

Грабля №2: 9% install error (фикс 1.5.17)

С 1.5.8 Илья сменил build-систему (NSIS убран, кастомный установщик). С 1.5.17 — снова: build-setup.cjs пакует приложение в app-payload.7z (~285 МБ) и собирает self-extracting Verstak-Setup-X.Y.Z-x64.exe (~360 МБ, payload внутри Setup). Пользователи ловили «9% install error» / «версия не скачивалась».

Лечение: апдейтер качает только Setup.exe через latest.yml, watchdog извлекает payload локально и robocopy'ит. Релизить надо ровно два ассета: Setup.exe + latest.yml. Отдельный app-payload.7z грузить НЕ нужно — это и ломало установку.

Грабля №3: latest.yml собираем вручную

Новый build не генерит latest.yml и .blockmap (это делал только NSIS). А без latest.yml автообновление вообще не триггерится — клиент видит «ожидает публикации». Поэтому теперь latest.yml собирается руками: sha512 = base64 от SHA-512 файла Setup.exe, size = байты, плюс поля version / path / releaseDate.

И порядок загрузки ассетов важен: сначала .exe, latest.yml — ПОСЛЕДНИМ. Пока latest.yml нет, клиенты видят «ожидает публикации» и не качают битый фид. Зальёшь yml первым — кто-то успеет скачать его раньше exe и упрётся в 404.

Чек-лист выкатки (как делаем сейчас)

  1. Закрыть npm run dev — иначе electron-rebuild падает EPERM на залоченном better_sqlite3.node.
  2. Bump версии + запись в changelog.
  3. npm run dist:win → Setup.exe.
  4. Собрать latest.yml вручную (sha512 + size).
  5. git tag + push main + push tag.
  6. Публикация через GitHub REST API (токен из Git Credential Manager — никогда не печатать в лог): создать release, залить Setup.exe первым, latest.yml последним.
  7. Проверка: curl latest.yml → 200, размер Setup.exe == size в yml.

Мораль

Каждый из этих багов выглядел как «у пользователя не обновляется», а причины были в трёх совершенно разных местах: лимит чужого API, формат установщика, порядок заливки файлов. Доставка — это не «нажать публиковать». Это инфраструктура, которую надо тестировать на скачиваемость каждый раз.

→ Дальше: Работа в четыре руки: дизайн-форк Ильи


← Все статьи · Скачать Verstak