Упаковка плагинов Channel (official / steam)
Плагины Channel (Discord, Feishu, Telegram, Slack, WhatsApp и т. д.) распространяются вместе с установщиком как предварительно собранные артефакты. Этот документ объясняет их полный путь от исходного кода до runtime, различия упаковки между каналами сборки (official / steam), а также почему в канале steam однажды отсутствовали плагины и как аудит теперь предотвращает это.
Два каталога обнаружения
Во время выполнения ChannelPluginLoader обнаруживает плагины Channel в двух каталогах, при этом pluginsDir имеет более высокий приоритет, чем bundledDir (переопределяет при одинаковом type):
| Каталог | Путь | Чтение/запись | Источник |
|---|---|---|---|
Установленные пользователем (pluginsDir) | <userData>/channel-plugins/ | Чтение/запись | Загрузка из Marketplace / Локальная установка |
Встроенные (bundledDir) | <resources>/bundled-channel-plugins/ | Только чтение | Распространяется с установщиком |
Связанный код:
packages/desktop/app/main/services/capabilities/integrations/channel/ChannelPluginLoader.ts,packages/desktop/app/main/bootstrap/capabilities-channel.ts.
Разрешение bundledDir находится в bootstrap/index.ts:
const channelBundledDir = isDev
? path.join(__dirname, '..', '..', '..', 'elftia-channels', 'dist-plugins') // Dev mode: workspace source directory
: path.join(process.resourcesPath, 'bundled-channel-plugins'); // Packaged mode: copy under resources
ChannelPluginLoader выполняет проверку существования bundledDir при создании:
this.bundledDir = bundledDir && existsSync(bundledDir) ? bundledDir : null;
Ключевое следствие: если упакованный <resources>/bundled-channel-plugins/ не существует, bundledDir устанавливается в null, и у discover() останется только каталог <userData>/channel-plugins/. Для новых установок этот каталог пуст → обнаружено 0 плагинов Channel → на странице Channel нет доступных плагинов.
От исходного кода до установщика
Артефакты сборки исходного кода плагинов Channel находятся в каталоге workspace:
packages/elftia-channels/dist-plugins/
├── discord/
├── feishu/
├── telegram/
├── slack/
├── whatsapp/
└── … (total ~26)
packages/elftia-channels/dist-plugins— это каталог предварительно собранных артефактов, а не часть inline-цепочки сборкиbuild:official/build:steam; он должен уже существовать до упаковки.
Во время упаковки extraResources в electron-builder копирует его в resources/bundled-channel-plugins. Оба канала сборки должны объявлять это:
# Both electron/electron-builder.official.yml and electron/electron-builder.steam.yml need:
extraResources:
- from: packages/elftia-channels/dist-plugins
to: bundled-channel-plugins
filter:
- "**/*"
Различия упаковки между official и steam
| Элемент | official | steam |
|---|---|---|
| Файл конфигурации | electron/electron-builder.official.yml | electron/electron-builder.steam.yml |
renderer-extension/byo-providers | Включено (BYO — ключевое обещание official) | Исключено (разделение для соответствия Steam, явное отрицательное совпадение filter) |
bundled-channel-plugins | Включено | Также должно быть включено |
Плагины Channel не связаны с разделением соответствия BYO: плагины Channel используют собственные bot tokens пользователя (Discord bot token, Telegram bot token и т. д.), а не относятся к категории «BYO LLM provider key / off-site payment», которую Steam отклоняет. Единственное исключение по соответствию для канала Steam — renderer-extension/byo-providers; плагины Channel не входят в список исключений.
Предыдущий баг: отсутствующая конфигурация в steam.yml
В extraResources файла electron-builder.steam.yml когда-то полностью отсутствовал bundled-channel-plugins (он никогда не появлялся во всей истории git). Последствия:
- В пакете Steam не было каталога
resources/bundled-channel-plugins/; - Во время выполнения
channelBundledDirуказывает на несуществующий путь →ChannelPluginLoader.bundledDir = null; discover()сканирует только пустой пользовательский каталог → обнаружено 0 плагинов Channel;- Пользовательский опыт: версия Steam не может использовать плагины Channel, официальная версия работает нормально.
Этот пропуск не был намеренным разделением по соответствию (у всех намеренных исключений есть комментарии + отрицательные совпадения filter), а был extraResources, пропущенным при ответвлении steam.yml от official.yml.
Резервный аудит: verify:steam-package
scripts/verify-steam-packaging.mts (npm run verify:steam-package, теперь интегрирован в конец цепочки build:steam) проверяет четыре инварианта:
| Инвариант | Значение |
|---|---|
byo-providers ABSENT | Пакет Steam не содержит renderer-extension/byo-providers (соответствует требованиям) |
design-studio PRESENT | Пакет Steam содержит renderer-extension/design-studio |
channel === 'steam' | Метаданные канала равны steam |
bundled-channel-plugins PRESENT | Пакет Steam включает хотя бы 1 плагин Channel ← недавно добавлено |
Контракт кодов выхода: 0 — все проверки пройдены; 2 — есть хотя бы одно нарушение; 1 — входные данные недоступны.
У аудита есть два режима (по приоритету):
- MODE 1 (Уже упаковано, авторитетно): если существует
release/steam/<platform>-unpacked/…/resources/plugins/renderer-extension/, напрямую аудировать реальный артефакт; количество плагинов Channel = число подкаталогов вresources/bundled-channel-plugins/на том же уровне. - MODE 2 (Staged dry-run, fallback): разобрать записи
extraResourcesвelectron-builder.steam.yml, сопоставленные сbundled-channel-plugins, посчитать подкаталоги в исходном каталоге изfrom:; нет записи → считать как 0 → инвариант не проходит (именно это предотвращается).
Исторический урок: предыдущие аудиты смотрели только на
renderer-extension, а плагины Channel полностью оставались вне области проверки — поэтому, когда в пакете было 0 плагинов Channel, аудит все равно проходил. Новый инвариантbundled-channel-plugins PRESENTзакрывает эту слепую зону.
Чек-лист изменения / проверки
При добавлении или корректировке упаковки плагинов Channel:
-
electron-builder.steam.ymlиofficial.ymlоба объявляютpackages/elftia-channels/dist-plugins → bundled-channel-plugins; - Перед упаковкой
packages/elftia-channels/dist-plugins/собран и не пуст; - Пересборка:
npm run build:steam:win(обратите внимание, что старыйrelease/steam/win-unpacked/— это предыдущая сборка, аудит MODE 1 будет использовать ее; перед аудитом необходимо пересобрать); - Проверка артефактов:
release/steam/win-unpacked/resources/bundled-channel-plugins/содержит все каталоги плагинов; - Аудит проходит:
npm run verify:steam-packageвозвращает код выхода0,[PASS] bundled-channel-plugins PRESENT; - Runtime-проверка: лог основного процесса показывает
Channel plugin directories … bundledExists: trueиChannel plugin discover: found N plugin(s)(N > 0).