Перейти к основному содержимому

Упаковка плагинов 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

Элементofficialsteam
Файл конфигурацииelectron/electron-builder.official.ymlelectron/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). Последствия:

  1. В пакете Steam не было каталога resources/bundled-channel-plugins/;
  2. Во время выполнения channelBundledDir указывает на несуществующий путь → ChannelPluginLoader.bundledDir = null;
  3. discover() сканирует только пустой пользовательский каталог → обнаружено 0 плагинов Channel;
  4. Пользовательский опыт: версия 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).