Плагины GameAP публикуются на plugins.gameap.dev — оттуда их устанавливают прямо из панели. Этот гайд проводит по всему пути: от создания карточки плагина до автоматической выкладки новых версий из CI.

Предполагается, что плагин у вас уже написан и собирается в .wasm. Ещё понадобится аккаунт на plugins.gameap.dev: обычная регистрация с подтверждением почты либо вход через GitHub, GitLab или Google.

Загружать версии можно двумя способами: вручную через дашборд и через API из CI. Начать проще с дашборда, а когда сборка встанет на рельсы — переключиться на CI.

Шаг 1. Аккаунт разработчика #

Публиковать плагины может аккаунт со статусом разработчика. Он выдаётся бесплатно и сразу — достаточно принять правила публикации.

В каталоге плагинов нажмите «Опубликовать свой плагин» — кнопка в правом верхнем углу.

Кнопка «Опубликовать свой плагин» в каталоге плагинов
Каталог плагинов

Откроется страница с правилами публикации. Коротко, о чём вы договариваетесь:

  • Рабочие и качественные плагины — только работоспособные и протестированные, делающие то, что заявлено в описании.
  • Никакого вредоносного кода — без бэкдоров, скрытых майнеров и запутанной логики; сбор данных пользователей должен быть явно описан.
  • Права и лицензирование — вы владеете кодом или вправе его распространять, чужие лицензии соблюдены, лицензия плагина указана.
  • Совместимость с GameAP — плагин работает с актуальными версиями панели и соответствует требованиям к формату.
  • Обновления и поддержка — критические ошибки и уязвимости чинятся в разумные сроки, на обращения пользователей есть ответ.
  • Модерация — каждый плагин и каждая версия проходят проверку, нарушающий правила плагин может быть снят в любой момент.
  • Без спама и дубликатов — без вводящих в заблуждение названий и накрутки ключевых слов.

Полный текст — на самой странице, прочитать стоит целиком.

Внизу нажмите «Принять». Роль выдаётся мгновенно, без модерации и ожидания: в сайдбаре появится раздел «Разработчик» с пунктами «Панель управления», «Мои плагины», «Новый плагин» и «Поддержка», а на почту придёт письмо о том, что вы стали разработчиком.

Важно. Принять правила можно только с подтверждённой почтой: иначе кнопка «Принять» неактивна, а на странице висит напоминание подтвердить email. При входе через GitHub, GitLab или Google почта считается подтверждённой сразу.

Кнопка «Опубликовать свой плагин» видна всем, включая не вошедших в аккаунт. Без входа на странице правил будет «Войти и принять» — после авторизации вас вернёт обратно к правилам.

Шаг 2. Создание плагина #

В меню слева выберите «Новый плагин» — откроется форма создания.

Форма создания плагина в дашборде plugins.gameap.dev
Создание нового плагина
ПолеОбязательноеЧто указать
НазваниедаДо 255 символов
Краткое описаниедаОдна фраза для карточки в каталоге, до 500 символов
ОписаниедаПолное описание в Markdown — над полем есть панель с разметкой
КатегориянетОдна из трёх, см. ниже
МеткинетКлючевые слова, по которым плагин проще найти
ЛицензиянетПроизвольный текст: MIT, GPL-3.0, Proprietary
Исходный коднетСсылка на исходники, если они открыты
РепозиторийнетСсылка на репозиторий
Домашняя страницанетСайт плагина или автора

Категории:

  • Управление сервером — большинство плагинов. Всё, что добавляет действия над игровым сервером.
  • Файлы — расширения файлового менеджера: редакторы, просмотрщики отдельных форматов.
  • Интеграция — плагины, существенно расширяющие функциональность панели, например управление базами данных.

Иконку на этом шаге загрузить нельзя — форма прямо об этом предупреждает, загрузка появится сразу после создания.

Важно. Поля «Исходный код» и «Репозиторий» влияют не только на карточку. Если не заполнено ни одно из них, к каждой версии придётся прикладывать архив с исходниками — модераторам нужно чем-то проверять сборку. Заполните хотя бы одно поле, если исходники открыты.

Шаг 3. ID плагина #

После нажатия «Создать» вы попадёте на страницу редактирования плагина. Первым блоком там идёт ID плагина — поле только для чтения с кнопкой копирования.

Этот ID нужно прописать в исходном коде плагина — в поле id структуры PluginInfo, которую возвращает метод GetInfo. По нему панель сопоставляет установленный у пользователя плагин с записью в маркетплейсе.

ID генерируется один раз при создании и не может быть изменён. Под капотом это 64-битное число (8 случайных байт), записанное в base32 — 13 символов латиницы и цифр, например fmqnme42gg7da. Тот же ID подставляется в URL страницы плагина и в адрес CI-эндпоинта.

Как это выглядит в существующих плагинах:

Важно. Пропишите ID и пересоберите .wasm до загрузки первой версии. Версии неизменяемы: перезалить файл под тем же номером не получится, придётся поднимать версию.

Шаг 4. Иконка и переводы #

На той же странице редактирования есть загрузчик иконки: JPG, PNG, WebP или SVG, до 2 МБ, рекомендуемый размер 128×128.

На странице плагина есть блок «Переводы». Каталог двуязычный, и посетитель видит карточку на своём языке: без перевода русский пользователь получит английское описание и наоборот. Название, краткое и полное описание переводятся отдельно для каждого языка — это пять минут работы, которые заметно меняют вид карточки.

Шаг 5. Загрузка версии #

На странице плагина найдите карточку «Версии» и нажмите «Загрузить версию».

Форма загрузки версии плагина
Загрузка новой версии
ПолеОбязательноеЧто указать
ВерсиядаСемантическая версия: 1.0.0, 1.2.0-beta.1
Файл плагинадаСкомпилированный .wasm, до 100 МБ
GPG подписьнетОткрепленная подпись .sig или .asc, до 1 МБ
Архив исходного кодазависит.zip или .tar.gz, до 50 МБ
Список измененийнетЧто изменилось по сравнению с прошлой версией, Markdown
Стабильный релизПереключатель, по умолчанию включён
Мин. версия GameAPнетВерсия панели, начиная с которой плагин работает

GPG подпись необязательна, но желательна: сервер хранит её как есть и никак не проверяет — она нужна пользователям, чтобы самостоятельно убедиться в подлинности файла.

Архив исходного кода обязателен, если у плагина не заполнены ни «Исходный код», ни «Репозиторий» — форма сама переключит подпись поля с «(необязательно)» на «(обязательно)». Архив используется только для модерации и проверки сборки, нигде не публикуется и недоступен через публичные эндпоинты.

Важно. Загруженная через дашборд версия остаётся черновиком. Пока вы не отправите её на проверку, её никто не увидит.

Скриншоты версии #

Сразу после загрузки откроется второй шаг — «Добавить скриншоты». Скриншоты привязаны к конкретной версии: JPG, PNG или WebP, до 10 штук, каждый до 5 МБ. Шаг можно пропустить и вернуться к нему позже со страницы версии.

Шаг 6. Отправка на проверку #

Плагины проходят модерацию — по тем самым правилам публикации, которые вы приняли на первом шаге. В шапке страницы плагина есть кнопка «Отправить на проверку» — она видна, только пока плагин в статусе «Черновик» или «Отклонён».

Отправить плагин без единой версии нельзя — сначала загрузите версию. Отправка версии на проверку из таблицы версий заодно переводит и сам плагин из черновика в статус «На проверке», так что отдельно нажимать кнопку в шапке обычно не требуется.

СтатусЧто значитЧто можно сделать
ЧерновикСоздан, никуда не отправленРедактировать, отправить на проверку, удалить
На проверкеЖдёт модератораЖдать
ОтклонёнМодератор вернул на доработкуИсправить и отправить снова
ОпубликованДоступен всем в каталогеЗагружать новые версии
ОдобренПромежуточный статус в модели данных
УстарелПомечен как неактуальныйВсё ещё устанавливается, но помечен
ОтозванСнят с публикацииНедоступен для установки

Одобрение сразу переводит плагин и версию в «Опубликован». Публично видны только объекты в этом статусе: если плагин опубликован, а его единственная версия ещё на проверке, установить будет нечего.

Причина отклонения приходит на почту — на странице плагина отображается только статус, поэтому проверьте входящие.

Токены деплоя #

Чтобы публиковать версии из CI, нужен токен деплоя. Он живёт в самом низу страницы плагина, в карточке «Токены деплоя».

Карточка «Токены деплоя» внизу страницы плагина
Карточка токенов деплоя

Нажмите «Создать токен» и заполните диалог: название (например, GitHub Actions) и, при желании, срок действия.

Диалог создания токена деплоя с полями «Название» и «Срок действия»
Создание токена деплоя

Важно. Токен показывается ровно один раз, сразу после создания. На сервере не хранится в исходном виде, восстановить значение невозможно — скопируйте его сразу в секреты CI.

Что стоит знать про токены:

  • Токен привязан к одному плагину и умеет только загружать его версии. Ни другие плагины, ни остальные эндпоинты API он не открывает.
  • Формат — gapd_ и 43 символа, всего 48. Префикс легко ловится сканерами секретов.
  • В таблице видно префикс токена, дату создания, последнего использования и срок действия — удобно понять, какой токен ещё используется.
  • Отзыв срабатывает мгновенно: пайплайн с отозванным токеном сломается на следующем запуске.
  • На один плагин можно завести до 20 токенов.

Публикация из CI #

CI-эндпоинт принимает новую версию без интерактивного входа — авторизация идёт по токену деплоя.

Загрузка через curl #

curl --fail-with-body -sS \
  -H "Authorization: Bearer $GAMEAP_DEPLOY_TOKEN" \
  -F "version=1.2.3" \
  -F "file=@build/plugin.wasm" \
  -F "signature=@build/plugin.wasm.asc" \
  -F "changelog=Исправлено падение при перезапуске сервера" \
  -F "min_gameap_version=4.1.0" \
  -F "is_stable=true" \
  "https://plugins.gameap.dev/api/ci/plugins/$GAMEAP_PLUGIN_ID/versions"

Запрос — POST с multipart/form-data. Поля формы:

ПолеОбязательноеОписание
versionдаСемантическая версия, например 1.2.3
fileдаСкомпилированный .wasm, до 100 МБ
signatureнетОткрепленная GPG-подпись, до 1 МБ
sourceзависитАрхив исходников .zip/.tar.gz до 50 МБ; обязателен, если у плагина не указаны ни «Исходный код», ни «Репозиторий»
changelogнетСписок изменений; удобно передавать из файла: -F "changelog=<CHANGELOG.md"
min_gameap_versionнетМинимальная версия GameAP
min_plugin_api_versionнетМинимальная версия Plugin API (в форме дашборда этого поля нет)
is_stableнетtrue или 1 помечает версию стабильной
submitнетПо умолчанию true; false оставит версию черновиком

Не ставьте слеш в конце URL. На .../versions/ роутер отвечает редиректом 301, а curl не повторяет тело POST при редиректе — загрузка молча превратится в GET.

Успешный ответ — 201 с телом вида:

{
  "id": 123,
  "plugin_id": "fmqnme42gg7da",
  "version": "1.2.3",
  "file_size": 1048576,
  "file_hash": "9f86d081884c7d65...",
  "has_source": false,
  "status": "pending_review"
}

GitHub Actions #

Этот workflow срабатывает на публикацию GitHub-релиза, собирает плагин, подписывает его и выкладывает на plugins.gameap.dev. Тело релиза уходит в список изменений, а стабильной версия помечается, только если релиз не отмечен как pre-release.

name: Publish plugin

on:
  release:
    types: [published]

jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Build plugin
        run: make wasm            # должен получиться build/plugin.wasm

      - name: Sign plugin
        env:
          GPG_SIGNING_KEY: ${{ secrets.GPG_SIGNING_KEY }}
        run: |
          printf '%s' "$GPG_SIGNING_KEY" | gpg --batch --import
          gpg --batch --yes --detach-sign --armor \
            -o build/plugin.wasm.asc build/plugin.wasm

      - name: Publish to plugins.gameap.dev
        env:
          GAMEAP_DEPLOY_TOKEN: ${{ secrets.GAMEAP_DEPLOY_TOKEN }}
          GAMEAP_PLUGIN_ID: ${{ vars.GAMEAP_PLUGIN_ID }}
          TAG: ${{ github.event.release.tag_name }}
          RELEASE_BODY: ${{ github.event.release.body }}
          PRERELEASE: ${{ github.event.release.prerelease }}
        run: |
          VERSION="${TAG#v}"
          printf '%s' "$RELEASE_BODY" > "$RUNNER_TEMP/changelog.md"
          ARGS=(--fail-with-body -sS
            -H "Authorization: Bearer ${GAMEAP_DEPLOY_TOKEN}"
            -F "version=${VERSION}"
            -F "file=@build/plugin.wasm"
            -F "signature=@build/plugin.wasm.asc"
            -F "changelog=<${RUNNER_TEMP}/changelog.md")
          if [ "$PRERELEASE" != "true" ]; then
            ARGS+=(-F "is_stable=true")
          fi
          curl "${ARGS[@]}" \
            "https://plugins.gameap.dev/api/ci/plugins/${GAMEAP_PLUGIN_ID}/versions"

VERSION="${TAG#v}" срезает ведущую v, чтобы тег v1.2.3 публиковался как версия 1.2.3.

Боевой вариант этого workflow со сборкой фронтенда, кешем Cargo и проверкой HTTP-статуса — в plugin-mysql.

Настройка репозитория GitHub #

Токен и ID плагина не должны лежать в коде — они хранятся в настройках репозитория. Откройте Settings → Secrets and variables (в разделе Security and quality) → Actions.

Пункт «Secrets and variables → Actions» в боковом меню настроек репозитория GitHub
Раздел настроек репозитория

На вкладке Secrets нажмите New repository secret и добавьте:

ИмяЗначение
GAMEAP_DEPLOY_TOKENТокен деплоя, скопированный при создании (начинается с gapd_)
GPG_SIGNING_KEYПриватный GPG-ключ в ASCII-armor, если подписываете сборки
Вкладка Secrets с секретами GAMEAP_DEPLOY_TOKEN и GPG_SIGNING_KEY
Секреты репозитория

На вкладке Variables нажмите New repository variable и добавьте:

ИмяЗначение
GAMEAP_PLUGIN_IDID плагина, например fmqnme42gg7da
Вкладка Variables с переменной GAMEAP_PLUGIN_ID
Переменные репозитория

ID плагина — это тот же base32-идентификатор, который вы прописывали в PluginInfo. Скопировать его можно кнопкой рядом с полем «ID плагина» на странице редактирования или из блока «Детали» на странице плагина.

ID лежит в переменных, а не в секретах, намеренно: он не секретный, а в логах CI его видно — это сильно упрощает разбор ошибок. Токен, наоборот, всегда секрет.

Экспортировать приватный GPG-ключ для GPG_SIGNING_KEY можно так:

gpg --armor --export-secret-keys ВАШ_КЛЮЧ_ID

Публичный ключ выложите там, где пользователи смогут его найти — например, в README плагина, чтобы подпись было чем проверить.

Дашборд и CI: разные умолчания #

ЧтоДашбордCI
Стабильный релизПереключатель включён по умолчаниюis_stable по умолчанию false — передавайте явно
Отправка на проверкуВручную, кнопкойsubmit по умолчанию true — версия уходит на проверку сразу
СкриншотыПредлагаются после загрузкиНе поддерживаются, добавляйте через дашборд

Если из CI нужно только положить файл, а метаданные доделать руками — передайте submit=false, и версия останется черновиком.

Ошибки #

КодПричина
400Неверный ID плагина, битый multipart или не передан file
401Токен отсутствует, неверен или истёк; заголовок не в формате Bearer gapd_...
403Токен валиден, но выдан для другого плагина
409Версия с таким номером уже существует
422Версия не проходит проверку semver; архив исходников отсутствует, слишком большой или не .zip/.tar.gz; превышены лимиты размера файла или подписи

Тело ошибки приходит в общем формате:

{
  "status": "error",
  "error": "version already exists",
  "message": "version already exists",
  "http_code": 409
}

После ошибки 5xx не повторяйте загрузку вслепую. Запись версии и отправка на проверку — не одна транзакция: версия может быть уже создана, и повтор вернёт 409. Загляните в дашборд и посмотрите, что получилось.

Обновление и снятие версий #

Новая версия загружается так же, как первая, — через дашборд или из CI. Уже загруженные версии неизменяемы: перезалить файл под тем же номером нельзя, попытка вернёт 409. Ошиблись в сборке — поднимайте патч-версию.

В таблице версий у каждой строки есть свои действия:

  • Редактировать — правка списка изменений и метаданных.
  • Отправить на проверку — для черновиков и отклонённых версий.
  • Устарел — для опубликованных версий. Версия остаётся доступной, но помечается как неактуальная.
  • Отозвать — для опубликованных и устаревших. Версия снимается с публикации.

Удалить можно только плагин в статусе «Черновик». Опубликованный плагин удалению не подлежит — его можно отозвать.

Чек-лист #

  • Почта подтверждена, правила публикации приняты, аккаунт получил статус разработчика.
  • Плагин создан, название и оба описания заполнены.
  • Заполнены «Исходный код» или «Репозиторий» — иначе к каждой версии нужен архив исходников.
  • ID плагина прописан в PluginInfo.id, и .wasm пересобран после этого.
  • Загружена иконка, добавлены переводы карточки.
  • Версия загружена, приложены подпись и скриншоты.
  • Версия отправлена на проверку — не оставлена черновиком.
  • Для CI создан токен деплоя и сохранён в секретах, ID плагина — в переменных.
  • В workflow нет слеша в конце URL и явно передан is_stable.
  • После релиза проверено, что плагин и версия в статусе «Опубликован».