Разработка плагинов
Плагин iEXExchanger — это ZIP-пакет с обязательным файлом iex-plugin.json. Пакет может добавить один или несколько источников курсов, платёжных шлюзов, провайдеров KYC/AML, каналов уведомлений, GeoIP- или proxy-провайдеров, обработчиков событий, административных страниц и других интеграций.
Актуальный формат манифеста:
iex.plugin.v2Установка, настройка, включение, проверка, обновление и удаление готового пакета описаны отдельно
Форматы runtime: "php", runtime: "js", modules, корневые поля type, name, entry, class, standard, activeByDefault и команда iex:plugin-make не относятся к текущему контракту iex.plugin.v2.
В текущем наборе CLI команды php artisan iex:plugin-make нет. Структура пакета создаётся вручную, а полная проверка ZIP выполняется через действие «Проверить пакет» в панели управления.
Основные понятия
Пакет
ZIP-архив с iex-plugin.json и файлами выбранного runtime
Издатель
Значение package.namespace
Имя пакета
Значение package.name; одновременно системный slug плагина
Релиз
Одна установленная версия пакета
Capability
Версионированная возможность, которую пакет подключает к ядру
Instance
Экземпляр capability с уникальным instance_key
Action
Разрешённая операция runtime, например rates.fetch
Runtime
Среда, в которой выполняется реализация плагина
Permission
Запрашиваемый доступ к данным или действиям iEXExchanger
Scope
Ограничение permission конкретными ключами, хостами или событиями
Grant
Фактически подтверждённый доступ установленной capability
Preview
Проверка ZIP без установки и выполнения кода
Health-check
Проверка работоспособности установленной capability
Уникальный идентификатор capability внутри пакета строится в формате:
Пример:
Жизненный цикл плагина
Предпросмотр
ZIP распаковывается во временный каталог; проверяются структура, манифест, совместимость, permissions, runtime, файлы и план установки
Подтверждение
Система создаёт краткоживущий токен, связанный с SHA-256 архива, манифеста и плана
Установка
Проверки повторяются; создаётся новый неизменяемый релиз, capability, настройки, секреты и миграции
Настройка
Оператор заполняет обычные настройки и данные подключения
Обновление данных
Официальные миграции запускаются отдельным административным действием
Включение
Повторно проверяются файлы, совместимость, permissions, обязательные поля и политика runtime
Выполнение
Доменный адаптер вызывает action через единый runtime gateway
Проверка работы
Выполняется health.check или специализированная проверка источника курсов
Карантин
После повторяющихся ошибок capability может получить состояние quarantined
Обновление
Новый ZIP проходит тот же preview-first процесс и создаёт новый релиз
Откат
Активным становится предыдущий релиз; плагин остаётся отключённым до повторного включения
Удаление
Исполнение останавливается, управляемые файлы удаляются, запись получает состояние removed
Предпросмотр не выполняет PHP, WASM, OCI-контейнер или удалённый HTTP runtime. Для native_php обнаружение пар через discoverOnInstall запускается только во время установки после подтверждения проверенного архива.
Установленный или обновлённый плагин всегда получает статус disabled. Поле для автоматического включения в iex.plugin.v2 отсутствует.
Отличия от прежнего формата
Прежний формат
iex.plugin.v2
Без поля версии схемы
"schema": "iex.plugin.v2"
Корневые name, version
Объект package
Корневые title, description
Объект metadata
"runtime": "php"
"runtime": {"kind": "native_php", ...}
"runtime": "js"
Не поддерживается
modules
capabilities
capability
key
Корневые entry и class
runtime.entrypoint и runtime.config.class
standard задаётся вручную
Строится как iex.<key>.<api_version>
activeByDefault
Плагин всегда устанавливается отключённым
Alias-поля base, quote, rate, bid, ask
Только from, to, buy, sell
PHP-код мог читать секреты через модель
Используется $context->secrets
Runtime мог выполняться при preview
Preview не выполняет код
iex:plugin-make
Команды нет; пакет создаётся вручную
Выбор capability и runtime
Поддерживаемые runtime
declarative
Статические интеграции без исполняемого кода
Каждый action возвращает заранее объявленный JSON-объект result; выражения, шаблоны, JavaScript и PHP запрещены
remote_http
Внешнее приложение разработчика
Публичный HTTPS endpoint, порт 443, без credentials, query и fragment
wasm
WASM-модуль во внешнем sandbox worker
Нужен файл .wasm и настроенный сервером sandbox worker
isolated_worker
Изолированный OCI worker
Нужны entrypoint, настроенный sandbox worker и OCI image с закреплённым SHA-256 digest
native_php
PHP-код внутри Laravel
Только официальный подписанный пакет; это не sandbox
Один пакет использует один корневой runtime для всех своих capabilities.
Если capabilities требуют несовместимые runtime, разделите их на разные пакеты. Например, rates.source с native_php нельзя объединить в одном ZIP с ui.admin, потому что ui.admin поддерживает только declarative и remote_http.
Declarative
Declarative runtime не выполняет пользовательский код. Результат каждого действия хранится непосредственно в манифесте:
result обязан быть JSON-объектом. Подстановка данных invocation в result не выполняется.
Remote HTTP
remote_http подходит для сторонних разработчиков: исполняемый код находится на внешнем сервере, а ZIP может содержать только iex-plugin.json и иконку.
Endpoint должен соответствовать требованиям:
протокол HTTPS;
публичный IP-адрес;
порт
443;отсутствие логина и пароля в URL;
отсутствие query string;
отсутствие fragment;
отсутствие перенаправлений;
отсутствие сжатого runtime-ответа.
Во время соединения iEXExchanger закрепляет DNS-результат и проверяет фактический IP, поэтому endpoint не может использовать DNS rebinding для обращения во внутреннюю сеть.
WASM и isolated worker
iEXExchanger передаёт invocation внешнему sandbox agent через:
Транспортный протокол:
Запрос содержит runtime, сведения об артефакте, SHA-256 релиза, entrypoint, capability, короткоживущий gateway token, ограничения и invocation.
Запрос и ответ подписываются HMAC-заголовками sandbox agent.
Native PHP
native_php выполняется с правами Laravel-приложения и не является изолированной средой.
Поэтому:
runtime доступен только пакету с уровнем доверия
official;обычный ZIP, загруженный через панель или URL, всегда считается
unverified;PHP-миграции разрешены только официальным релизам;
доверие нельзя объявить внутри
iex-plugin.json;закрытые ключи издателя не включаются в продукт или ZIP.
Для источника курсов используется специализированный контракт RateParserPluginInterface. Для остальных официальных native-capabilities используется NativePluginCapabilityInterface.
Каталог capabilities
rates.source
Источник курсов
rates:write
declarative, remote_http, wasm, isolated_worker, native_php
payments.merchant
Приём платежей
payments:initiate, payments:read
remote_http, wasm, isolated_worker, native_php
payments.payout
Выплаты
payouts:initiate, payouts:read
remote_http, wasm, isolated_worker, native_php
compliance.kyc
Проверка личности
kyc:verify
remote_http, wasm, isolated_worker, native_php
compliance.aml
AML-проверка адресов и транзакций
aml:screen
remote_http, wasm, isolated_worker, native_php
notifications.channel
Канал уведомлений
notifications:send
remote_http, wasm, isolated_worker, native_php
network.proxy
Динамический proxy endpoint
proxy:resolve
remote_http, wasm, isolated_worker, native_php
geoip.provider
GeoIP-провайдер
geoip:lookup
declarative, remote_http, wasm, isolated_worker, native_php
ui.admin
Безопасные страницы панели управления
admin-ui:contribute
declarative, remote_http
events.consumer
Подписчик событий
events:subscribe
remote_http, wasm, isolated_worker
integration.generic
Универсальная автоматизация или коннектор
core:read
declarative, remote_http, wasm, isolated_worker
Обязательные permissions добавляются ядром автоматически, но их рекомендуется явно указывать в манифесте: так разработчик и оператор видят полный набор доступов до установки.
Тип пакета выводится из capability:
rates.source
parser-rate
payments.merchant
merchant
payments.payout
payout
compliance.kyc
kyc
compliance.aml
aml
Остальные capabilities
external
Один пакет может объявить несколько capabilities. Для каждого экземпляра требуется уникальная комбинация key, api_version и instance_key.
Действия доменных адаптеров
Каждый используемый action должен быть объявлен в runtime.config.actions.
Capability
Action
Основной payload
Результат в data
Любая capability
health.check
{}
JSON-объект, подтверждающий доступность runtime
rates.source
rates.fetch
options
rates с элементами from, to, buy, необязательным sell
payments.merchant
payments.<operation>
operation, parameters, merchant_config_keys, task_id, headers
status и данные платёжной операции
payments.payout
payments.<operation>
operation, parameters, merchant_config_keys, task_id, headers
status и данные выплаты
compliance.kyc
kyc.issue
user, service, context
success, status, message, external_id, completed, data, raw
compliance.kyc
kyc.status
user, service, context
Тот же формат, что у kyc.issue
compliance.aml
aml.transaction.check
currency, address, tx, amount, direction, client_id, extra
status, risk_score, risk_signals, external_id
compliance.aml
aml.address.check
Тот же формат без обязательной транзакции
Тот же AML-результат
notifications.channel
notifications.send
event, model, recipient, message, payload
message_id, status
notifications.channel
notifications.test
target
message
network.proxy
proxy.resolve
context
type, публичный IP host, port, необязательные username, password
geoip.provider
geoip.locate
ip, locale
Нормализованная GeoIP-структура
geoip.provider
geoip.country
ip, locale
Нормализованная GeoIP-структура
geoip.provider
geoip.asn
ip, locale
Нормализованная GeoIP-структура
events.consumer
events.deliver
Объект event
Любой успешный JSON-объект
ui.admin
Action из DSL страницы
Зависит от load, form или button
Данные административной страницы
integration.generic
Action из манифеста
Определяется интеграцией
Определяется интеграцией
Формальная проверка манифеста автоматически требует health.check, events.deliver, actions расписаний и actions административного интерфейса. Доменные actions вроде rates.fetch или notifications.send необходимо объявлять самостоятельно. Если action отсутствует, манифест может пройти базовый preview, но рабочий вызов будет отклонён runtime gateway.
Структура ZIP-пакета
Минимальная структура
Расширенный официальный пакет может содержать:
Автоматическая Composer-автозагрузка файлов внутри ZIP не выполняется. Для native runtime загружается только runtime.entrypoint. Если реализация разделена на несколько файлов, entrypoint должен подключить их через require_once.
Правила архива
iex-plugin.jsonдолжен находиться в корне ZIP или внутри единственной общей корневой папки;абсолютные пути запрещены;
сегменты
..запрещены;скрытые сегменты, включая
.envи.git, запрещены;__MACOSX,.DS_Storeи._*игнорируются;entrypoint, миграции и иконка должны находиться внутри пакета;
ZIP не должен содержать пароли, приватные ключи, дампы базы и рабочие логи;
максимальный размер ZIP по умолчанию —
50 MiB;максимальный размер после распаковки по умолчанию —
200 MiB;максимальное количество записей ZIP по умолчанию —
1000.
Иконка
Путь к иконке указывается явно:
Поддерживаемые расширения:
Максимальный размер по умолчанию — 1 MiB.
SVG проходит allowlist-проверку. Скрипты, обработчики событий, внешние ссылки, опасные namespace и активное содержимое запрещены.
Манифест iex-plugin.json
Корневые поля
schema
Да
Всегда iex.plugin.v2
package
Да
Идентичность и версия пакета
metadata
Да
Название, описание, автор, совместимость и иконка
runtime
Да
Единая среда выполнения пакета
capabilities
Да
Одна или несколько возможностей
rateParser
Нет
Первичный список пар для rates.source
adminNavigation
Нет
Безопасное расширение меню панели управления
Неизвестные корневые поля запрещены.
package
namespace
^[a-z][a-z0-9_-]{1,99}$
name
^[a-z][a-z0-9_-]{1,99}$
version
Семантическая версия, например 1.0.0 или 1.2.0-beta.1
Пара namespace/name является постоянной идентичностью пакета. Новая версия должна сохранять эти значения.
Официальную идентичность нельзя обновить неподписанным ZIP, даже если строки namespace и name совпадают.
metadata
Обязательны только title и description.
Совместимость поддерживает:
core
Composer Semver constraint для версии iEXExchanger
core_min
Минимальная версия продукта включительно
core_max
Максимальная версия продукта включительно или null
php
Composer Semver constraint PHP
laravel
Composer Semver constraint Laravel
extensions
Список PHP-расширений или объект extension: constraint
core_min разрешает указанную версию и последующие версии, пока разработчик явно не добавит core_max.
Указывайте только реально проверенные ограничения. Не ограничивайте будущие версии продукта без технической причины.
Полный пример remote_http источника курсов
Замените https://example.com/iex-plugin/v1/invoke рабочим публичным endpoint до проверки пакета.
Для remote_http значение rateParser.discoverOnInstall не запускает внешний endpoint во время установки. Если пары известны заранее, передайте их через rateParser.pairs. Если список динамический, оператор сможет создать необходимые пары после установки источника.
Полный пример официального native_php источника курсов
Пакет с native_php, загруженный как обычный ZIP или по URL, будет отклонён политикой доверия. Такой runtime публикуется только как официальный подписанный пакет из серверного каталога готовых плагинов.
capabilities
Минимальная capability:
key
Да
Ключ capability из системного каталога
api_version
Да
Версия контракта в формате v1, v2
instance_key
Да
Стабильный ключ экземпляра
permissions
Да
Запрашиваемые permissions и scopes
title
Нет
Название capability
description
Нет
Описание
translations
Нет
Переводы названия и описания
type
Нет
Явный доменный тип; обычно выводится из key
permission_scopes
Нет
Альтернативная форма описания scopes
config
Нет
Декларативная конфигурация адаптера
settings
Нет
Описание секретных полей
config_schema
Нет
Описание обычных настроек
migrations
Нет
PHP-миграции официального пакета
health
Нет
Параметры health-check
events
Нет
Подписки на события
schedules
Нет
Расписания capability
Правило instance_key:
config.alias использует то же правило и применяется доменными resolver-адаптерами.
Разработка источника курсов
Контракт native PHP
Класс должен реализовать:
Метод интерфейса:
Каждый элемент результата должен быть объектом RateParserRuntimeRate или массивом с точными полями:
from, to и buy обязательны. sell необязателен.
Alias-поля base, quote, currency_from, currency_to, rate, default, value, bid и ask текущим DTO не преобразуются.
Пример Parser.php
Endpoint и структура ответа в примере демонстрационные. Замените их контрактом реального поставщика.
Здесь base, quote, bid и ask являются полями внешнего API. Перед возвратом плагин самостоятельно преобразует их в обязательный контракт from, to, buy, sell.
RateParserContext
$context->plugin
Данные установленного плагина текущего запуска
$context->manifest
Нормализованный манифест capability
$context->options
Опции конкретного запуска
$context->extra
Дополнительный runtime-контекст
$context->config
Обычные настройки, сгруппированные по capability
$context->secrets
Секреты, сгруппированные по capability
$context->pluginPath()
Безопасный путь к файлу внутри установленного релиза
Чтение обычной настройки:
Чтение секрета:
Проверка режима health-check:
Чтение файла пакета:
Не запрашивайте секреты через $context->plugin->secrets(). Native parser выполняется в отдельном коротком Artisan-процессе и получает подготовленные значения через $context->secrets.
Валидация курса
RateParserRuntimeRate проверяет:
fromиtoне пустые;длина кода не превышает
64символа;первый символ является Unicode-буквой или цифрой;
остальные символы принадлежат набору букв, цифр,
.,_,:,+,-;fromиtoне совпадают без учёта регистра;buyявляется положительным числом;sell, если задан, является положительным числом.
Возвращайте курсы строками:
Это предотвращает потерю точности при преобразовании через float.
Ограничения native parser
По умолчанию один запуск ограничен:
Время выполнения
20 секунд
Количество курсов
100000
Размер JSONL-результата
64 MiB
Формат вывода
Одна JSON-запись на строку
Минимальный результат
Хотя бы один корректный курс
Внутренняя команда:
является скрытым transport-компонентом. Не запускайте её вручную: команда требует временные файлы, созданные PhpRateParserRunner, и проверяет их расположение.
rateParser.pairs
rateParser.pairs описывает строки, создаваемые при первичном импорте. Это не результат текущего runtime-запроса.
from
Да
Исходная валюта
to
Да
Целевая валюта
type
Нет
Числовой тип строки; по умолчанию 0
type_price
Нет
Дополнительный тип цены
number_format
Нет
Точность от 0 до 18; по умолчанию 10
amount
Нет
Неотрицательное значение или null
status
Нет
Декларативный статус
Новые строки импортируются выключенными независимо от попытки указать активный статус. Оператор включает нужные пары после проверки.
Повторяющиеся определения пар сохраняются как отдельные строки в исходном порядке. Для каждой записи фиксируется порядковый номер occurrence.
discoverOnInstall
Фактическое runtime-обнаружение во время установки выполняется только для native_php.
Последовательность:
Протокол remote_http
Входящий запрос
iEXExchanger отправляет JSON через POST на runtime.endpoint_url.
Заголовки:
Authorization
Bearer <короткоживущий runtime token>
X-iEX-Capability
Ключ capability
X-iEX-Capability-Version
Версия API capability
X-iEX-Correlation-ID
Идентификатор сквозного запроса
Idempotency-Key
Ключ идемпотентности
X-iEX-Gateway-URL
Базовый URL runtime API iEXExchanger
Accept-Encoding
identity
Тело запроса:
invocation.action всегда нужно сверять с allowlist своего приложения. Не выполняйте произвольный метод, полученный из строки action.
idempotency_key должен связываться с содержимым операции. Повтор с тем же ключом и другим payload отклоняется системой.
Успешный ответ
Ответ с ошибкой
Требования:
successfulобязано быть boolean;dataдолжно быть JSON-объектом;error.codeдолжен быть коротким стабильным машинным кодом;metadataдолжно быть JSON-объектом;HTTP-ответ должен укладываться в лимит платформы;
технические исключения, токены и персональные данные нельзя возвращать в
error.message.
Runtime gateway очищает ошибку перед передачей доменному адаптеру. Не рассчитывайте, что произвольный текст внешнего исключения будет показан оператору.
Обязательный health.check
Каждая capability v2 должна объявлять:
Пример ответа:
Для rates.source health-check может вернуть:
abilities action
runtime.config.actions.<action>.abilities перечисляет дополнительные runtime API, которые понадобятся во время конкретного action.
Каждая ability должна быть объявлена как permission хотя бы одной capability пакета и разрешена каталогом этой capability.
Короткоживущий bearer token создаётся перед invocation и отзывается после завершения операции. Не сохраняйте его как постоянный ключ подключения.
Permissions и scopes
Каталог permissions
core:read
low
Безопасные сведения ядра
rates:read
low
Чтение курсов
rates:write
medium
Предоставление или изменение курсов
currencies:read
low
Чтение списка валют
orders:read
high
Чтение заявок
orders:write
critical
Изменение заявок
payments:read
high
Чтение платежей
payments:initiate
critical
Инициация платежа
payments:refund
critical
Возврат платежа
payouts:read
high
Чтение выплат
payouts:initiate
critical
Инициация выплаты
customers:pii.read
critical
Чтение персональных данных клиента
kyc:verify
high
Выполнение KYC
aml:screen
high
Выполнение AML-проверки
notifications:send
high
Отправка уведомлений
proxy:resolve
medium
Получение proxy endpoint
geoip:lookup
low
GeoIP-поиск
http:egress
high
HTTP-запрос через контролируемый broker
secrets:read
critical
Чтение объявленного секрета
storage:read
low
Чтение KV-хранилища capability
storage:write
medium
Изменение KV-хранилища capability
events:subscribe
medium
Подписка на события
events:publish
high
Публикация событий плагина
schedules:manage
medium
Запуск actions по расписанию
admin-ui:contribute
high
Добавление административной страницы
Обязательные scopes
http:egress
Массив host
secrets:read
Массив key
events:publish
Массив event_name
events:subscribe
event_name; может быть выведен из events
Пример:
Альтернативная форма:
Не запрашивайте доступы «на будущее». Preview показывает permissions оператору, а активация повторно проверяет действующие grants.
Настройки и секреты
Обычные настройки
Обычные настройки объявляются в config_schema.
Поддерживаемые типы:
Правила:
selectтребует непустой массивoptions;integerиnumberподдерживаютmetadata.minиmetadata.max;строковые поля поддерживают
metadata.max_length;URL допускает только
httpилиhttpsбез credentials;обязательное поле без
defaultдопустимо, но плагин нельзя включить до его заполнения;значения хранятся отдельно от файлов релиза;
при обновлении значение сохраняется, если capability и
keyне изменились.
Секреты
Секреты объявляются в settings.
В манифесте находится только описание поля. Значение вводится оператором и хранится отдельно в зашифрованном виде.
Для native rate parser:
Для remote_http, wasm или isolated_worker секрет читается через runtime API:
Ответ:
Для доступа нужны:
permission
secrets:read;scope с точным ключом;
ability
secrets:readу выполняемого action.
Не записывайте значение секрета в логи, события, metadata или runtime-ответ.
Runtime API
Базовый путь:
Runtime получает точный URL в заголовке X-iEX-Gateway-URL.
Tenant определяется bearer token. Параметр plugin_id API не принимает.
GET
/me
Токен runtime
Capability, abilities, invocation scope и срок токена
POST