Search for a command to run...
В этом руководстве вы узнаете, как создать провайдер Medusa для управления своими настройками через Модуль интеграций.
Модуль интеграций позволяет любому плагину описывать свои параметры в виде схемы, а администраторам магазина настраивать их в Admin, без правок и без повторного развёртывания приложения Medusa. Он генерирует UI, предоставляет CRUD API и валидацию, поэтому вам не нужно писать свои модели данных, роуты, формы или воркфлоу.
При разработке своего провайдера Модуля интеграций бывает полезно посмотреть, как устроен готовый провайдер.
Если вам нужен пример реальной реализации, посмотрите провайдер платежей YooKassa в репозитории Medusa Integrations.
Начните с создания новой директории для вашего провайдера Модуля интеграций. Для плагина она размещается в , например .
Создайте файл , который объявляет дескриптор интеграции и сам сервис.
providers/integration-my/services/my-integration.ts1import {2 AbstractIntegrationProvider3} from "@gorgo/medusa-integration"45class MyIntegrationProvider extends AbstractIntegrationProvider {6 // TODO add methods7}89export default MyIntegrationProvider
Родительский класс, который вы расширяете здесь, , абстрактный, поэтому подкласс обязан реализовать его свойство (объявленное через ). Классу также нужен : на него рассчитывает загрузчик.
Каждый провайдер Модуля интеграций имеет уникальный идентификатор. По нему администратор настраивает провайдер, а потребитель получает его параметры.
providers/integration-my/services/my-integration.ts1class MyIntegrationProvider extends AbstractIntegrationProvider {2 static identifier = "my"3 // ...4}
Загрузчик читает это статическое поле, чтобы собрать ключ, под которым регистрируется ваш инстанс: , либо без ID.
Класс провайдера обязан реализовать свойство . Дескриптор содержит единое описание параметров, их группировку в секции настроек и метод проверки соединения (опционально). Создайте его через .
Общий обзор дескриптора смотрите в разделе Основные концепции. Полный список полей (, , , , , , и другие) объявлен в экспортируемом типе .
providers/integration-my/services/my-integration.ts1import {2 AbstractIntegrationProvider,3 defineIntegration,4 z5} from "@gorgo/medusa-integration"67const descriptor = defineIntegration({8 category: "payment",9 displayName: "my.name",10 options: {11 apiKey: {12 type: "string",13 control: "secret",14 secret: true,15 required: true,16 label: "my.apiKey"17 },18 sandbox: {19 type: "boolean",20 control: "switch",21 default: false,22 label: "my.sandbox"23 },24 },25 sections: [26 {27 id: "credentials",28 title: "my.credentials",29 options: ["apiKey", "sandbox"]30 },31 ],32})3334export type MyOptions = z.infer<typeof descriptor.optionsSchema>3536export class MyIntegrationProvider extends AbstractIntegrationProvider {37 // ...38 get descriptor() {39 return descriptor40 }41}4243export default MyIntegrationProvider
описывает итоговый набор параметров: собирает из объекта , и поскольку у указан , а у задан , оба поля в становятся обязательными.
Как и другие провайдеры Medusa, провайдер Модуля интеграций может объявить статический , чтобы проверить свою конфигурацию из уже при загрузке приложения.
providers/integration-my/services/my-integration.ts1class MyIntegrationProvider extends AbstractIntegrationProvider {2 // ...3 static validateOptions(options: Record<string, unknown>) {4 // необязательная fail-fast проверка options.providers[].options5 }6}
Собственный базового класса ничего не делает (), поэтому переопределять его не обязательно. Тип возврата показывает, что метод либо ничего не возвращает, либо выбрасывает исключение, чтобы прервать загрузку.
На практике у провайдера Модуля интеграций почти всегда . Реальные настройки администратор задаёт в Admin, а не в , поэтому здесь нужен реже, чем у других провайдеров Medusa.
В отличие от , который проверяет конфигурацию провайдера в , проверяет сами параметры интеграции (например, API-ключ), обращаясь к стороннему сервису. Администратор запускает эту проверку из Admin, а запланированная задача ежедневно перепроверяет настроенные интеграции. Объявите её прямо в дескрипторе.
providers/integration-my/services/my-integration.ts1const descriptor = defineIntegration({2 // ...3 testConnection: async ({ options }) => {4 const res = await fetch("https://api.my.com/ping", {5 headers: { Authorization: `Bearer ${options.apiKey}` },6 })78 return res.ok9 ? { status: "passed" }10 : { status: "failed", message: `My responded with ${res.status}` }11 },12})
принимает одно из значений . Возврат считается обычным результатом, а не ошибкой. Если провайдер выбросит исключение, ежедневная задача учтёт его отдельно, как .
Создайте файл со следующим содержимым:
providers/integration-my/index.ts1import { ModuleProvider } from "@medusajs/framework/utils"2import { INTEGRATION_MODULE } from "@gorgo/medusa-integration"3import MyIntegrationProvider from "./services/my-integration"45export default ModuleProvider(INTEGRATION_MODULE, {6 services: [MyIntegrationProvider],7})
Это экспортирует определение провайдера, указывая, что является его сервисом.
Чтобы использовать провайдер Модуля интеграций, добавьте его в массив модуля интеграций в :
medusa-config.ts1module.exports = defineConfig({2 // ...3 plugins: [4 {5 resolve: "@gorgo/medusa-integration",6 options: {7 encryptionKey: process.env.INTEGRATION_ENCRYPTION_KEY,8 providers: [9 {10 resolve: "./src/providers/integration-my",11 id: "my-1",12 options: {},13 },14 ],15 },16 },17 // ...18 ],19})
По этой записи загрузчик создаёт инстанс .
У провайдера Модуля интеграций вы задаёте параметр , из него модуль собирает итоговый идентификатор инстанса вида . Без провайдер регистрируется как единственный инстанс с ключом . Если провайдер Модуля интеграций поддерживает несколько инстансов, то у каждого будет свой .
Далее добавьте секретный ключ шифрования в переменные окружения. Модуль интеграций использует его, чтобы зашифровать секреты перед сохранением в базу данных:
.envINTEGRATION_ENCRYPTION_KEY=supersecret
Подходит любое непустое значение. Модуль преобразует его через SHA-256 в 32-байтовый ключ AES-256-GCM, поэтому используйте значение с высокой энтропией, например .
Запустите сервер и откройте Настройки → Интеграции в Medusa Admin. Интеграция появится в списке. Заполните параметры и нажмите Проверить соединение, чтобы вызвать .
Чтобы прочитать сохранённые параметры, используйте , передав тот же , который объявляет ваш класс провайдера:
providers/payment-my/services/my-payment.ts1import { resolveIntegrationOptions } from "@gorgo/medusa-integration"2import type { MyOptions } from "../../integration-my/services/my-integration"34const options = await resolveIntegrationOptions<MyOptions>({5 identifier: "my",6})
Возвращённые типизированы как , уже расшифрованные и проверенные. По умолчанию вызов выбрасывает , если интеграция не настроена, выключена или не заполнена.
Подробнее о том, как получить параметры интеграции из роута, подписчика или шага воркфлоу, читайте в разделе Чтение параметров.