For the complete documentation index, see llms.txt. This page is also available as Markdown.
new

Разработка плагинов

Плагин iEXExchanger — это ZIP-пакет с обязательным файлом iex-plugin.json. Пакет может добавить один или несколько источников курсов, платёжных шлюзов, провайдеров KYC/AML, каналов уведомлений, GeoIP- или proxy-провайдеров, обработчиков событий, административных страниц и других интеграций.

Актуальный формат манифеста:

iex.plugin.v2

Установка, настройка, включение, проверка, обновление и удаление готового пакета описаны отдельно

plugУстановка плагинов

Основные понятия

Понятие
Назначение

Пакет

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

Установленный или обновлённый плагин всегда получает статус 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

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.

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.

Серверная часть определяет транспорт к sandbox agent, но не объявляет самостоятельный публичный guest ABI для WASM или OCI-контейнера. Экспорты WASM, формат запуска OCI и доступные системные вызовы должны соответствовать SDK и версии sandbox agent, установленного на целевом сервере.

Native PHP

native_php выполняется с правами Laravel-приложения и не является изолированной средой.

Поэтому:

  • runtime доступен только пакету с уровнем доверия official;

  • обычный ZIP, загруженный через панель или URL, всегда считается unverified;

  • PHP-миграции разрешены только официальным релизам;

  • доверие нельзя объявить внутри iex-plugin.json;

  • закрытые ключи издателя не включаются в продукт или ZIP.

Для источника курсов используется специализированный контракт RateParserPluginInterface. Для остальных официальных native-capabilities используется NativePluginCapabilityInterface.

Каталог capabilities

Capability
Назначение
Обязательные permissions
Разрешённые runtime

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:

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 из манифеста

Определяется интеграцией

Определяется интеграцией

Структура 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 источника курсов

Для remote_http значение rateParser.discoverOnInstall не запускает внешний endpoint во время установки. Если пары известны заранее, передайте их через rateParser.pairs. Если список динамический, оператор сможет создать необходимые пары после установки источника.

Полный пример официального native_php источника курсов

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

Здесь 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:

Чтение файла пакета:

Валидация курса

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.

Последовательность:

1

Предпросмотр

Система проверяет манифест и файлы, но не запускает Parser.php.

2

Подтверждение

Оператор подтверждает preview, связанный с точным SHA-256 архива и планом установки.

3

Установка релиза

Файлы перемещаются в управляемое хранилище нового релиза.

4

Обнаружение пар

Система запускает rates() с опцией install_discovery.

5

Создание snapshot

Пары записываются в iex-rate-pairs.jsonl, а метаданные — в iex-rate-pairs.json.

6

Импорт

Строки импортируются очередью короткими порциями и остаются выключенными.

Протокол 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

Permission
Риск
Назначение

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

Permission
Обязательный scope

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 не принимает.

Метод
Путь
Ability
Назначение

GET

/me

Токен runtime

Capability, abilities, invocation scope и срок токена

POST