Search for a command to run...
Сменить токен или пароль у провайдера значит изменять код и деплоить заново, если передавать эти опции через . Модуль интеграций убирает этот воркфлоу: настройки переезжают в Medusa Admin, секреты шифруются, провайдер получает готовый конфиг без единой строки кода.
В этом гайде вы узнаете, как перенести существующий провайдер на на примере реальной миграции провайдера ApiShip.
Модуль интеграций позволяет любому плагину описывать свои опции и даёт администраторам магазина настраивать их как интеграции прямо в админке, без правок и передеплоя. Он генерирует admin CRUD API и валидацию, поэтому вам не нужно писать модели данных, роуты или формы.
До миграции настройки ApiShip хранились в : токен, подключения к курьерским службам, адрес отправителя по умолчанию. Эти данные обслуживал собственный Admin UI, на каждую CRUD-операцию был отдельный API-роут. Модуль интеграций сводит всё это в один раздел Настройки → Интеграции.
Рядом с существующим провайдером доставки создайте новый провайдер интеграции: . Опишите в нём дескриптор: тот же список настроек, что и раньше, но каждое поле теперь объявлено явно: тип, обязательность, секретность и способ отображения в форме.
Structure1src/providers/2├── integration-apiship/ # новый: дескриптор настроек для модуля интеграций3└── fulfillment-apiship/ # существующий: провайдер доставки
providers/integration-apiship/services/apiship-integration.ts1import { AbstractIntegrationProvider, defineIntegration, z } from "@gorgo/medusa-integration"2import { ProviderKeys } from "../../../types"3import { APISHIP_ICON } from "../../icon.ts"45const descriptor = defineIntegration({6 category: "fulfillment",7 displayName: "apiship.name",8 icon: APISHIP_ICON,9 preferredLayoutId: "core:two-column",10 supportsMultipleInstances: true,1112 options: {13 token: {14 type: "string",15 required: true,16 secret: true,17 control: "secret",18 label: "apiship.fields.token"19 },20 is_test: {21 type: "boolean",22 default: false,23 control: "switch",24 label: "apiship.fields.isTest"25 },26 // За подключения к курьерским службам, адрес отправителя и параметры товара отвечает свой Admin UI (см. шаг 4),27 // но они всё равно часть схемы: шифруются и валидируются наравне с остальными полями.28 settings: {29 type: "json",30 default: {31 connections: []32 // ...33 },34 control: "json",35 label: "apiship.fields.settings"36 },37 },3839 sections: [40 {41 id: "credentials",42 title: "apiship.sections.credentials",43 options: ["token", "is_test"]44 },45 ],4647 testConnection: async ({ options }) => {48 // Лёгкий read-only вызов к API ApiShip, подтверждающий валидность токена.49 // Возвращает { status, message }, исключений не бросает.50 },51})5253export type ApishipIntegrationOptions = z.infer<typeof descriptor.optionsSchema>5455export class ApishipIntegrationProvider extends AbstractIntegrationProvider {56 static identifier = ProviderKeys.APISHIP5758 get descriptor() {59 return descriptor60 }61}6263export default ApishipIntegrationProvider
medusa-config.ts1// ...23const APISHIP_INTEGRATION_ID = "apiship-1"45module.exports = defineConfig({6 // ...7 plugins: [8 {9 resolve: "@gorgo/medusa-integration",10 options: {11 encryptionKey: process.env.INTEGRATION_ENCRYPTION_KEY,12 providers: [13 {14 resolve: "@gorgo/medusa-fulfillment-apiship/providers/integration-apiship",15 id: APISHIP_INTEGRATION_ID,16 options: {},17 },18 ],19 },20 },21 // ...22 ],23 modules: [24 {25 resolve: "@medusajs/medusa/fulfillment",26 options: {27 providers: [28 {29 resolve: "@gorgo/medusa-fulfillment-apiship/providers/fulfillment-apiship",30 id: "apiship",31 options: { id: APISHIP_INTEGRATION_ID },32 },33 ],34 },35 },36 // ...37 ],38})
Добавьте секретный ключ шифрования в :
.envINTEGRATION_ENCRYPTION_KEY=supersecret
Раньше провайдер доставки читал настройки напрямую из . Теперь он получает их из модуля интеграций через , передавая свой и (тот самый из ). Модуль возвращает уже расшифрованный и провалидированный конфиг:
providers/fulfillment-apiship/core/apiship-base.ts1// ...2import { resolveIntegrationOptions } from "@gorgo/medusa-integration"3import { ProviderKeys } from "../../../types"45class ApishipBase extends AbstractFulfillmentProviderService {6 protected instanceId_: string | null78 constructor({ logger }, options?: Record<string, unknown>) {9 super()10 this.logger_ = logger11 this.instanceId_ = (options?.id as string | undefined) ?? null12 }1314 private async getApishipOptions_(): Promise<ApishipOptionsDTO> {15 const options = await resolveIntegrationOptions<DeepPartial<ApishipOptionsDTO>>({16 identifier: ProviderKeys.APISHIP,17 instance_id: this.instanceId_,18 })19 return this.normalizeApishipOptions_(options)20 }2122 // ...23}
Раньше у ApiShip была отдельная страница в админке. Теперь страницу интеграции с формой из дескриптора рендерит сам модуль, а ваш кастомный UI (подключения к курьерским службам, адрес отправителя) встраивается в неё виджетом через зону расширения:
admin/widgets/apiship-integration-main.tsx1// ...2import { defineWidgetConfig } from "@medusajs/admin-sdk"3import type { IntegrationSectionData } from "@gorgo/medusa-integration"4import { ProviderKeys } from "../../../types"56const ApishipIntegrationWidget = ({ data }: { data: IntegrationSectionData }) => {7 const providerId = data.providerId // ключ инстанса от модуля: "int_apiship" или "int_apiship_<instance>"89 const options = await resolveIntegrationOptions<DeepPartial<ApishipOptionsDTO>>({10 identifier: ProviderKeys.APISHIP,11 instance_id: providerId,12 })1314 return (15 <>16 // ...существующие компоненты, providerId прокидывается дальше во все хуки и запросы17 </>18 )19}2021export const config = defineWidgetConfig({22 // зона расширения модуля: виджет встанет под формой на странице интеграции ApiShip23 zone: "gorgo.integration.apiship.main.after",24})2526export default ApishipIntegrationWidget
Модуль передаёт в виджет готовый ключ инстанса через , так что прокидывать его в свои хуки и запросы к собственным API-роутам можно напрямую. В итоге одна страница совмещает и общую форму от модуля (токен, ), и специфичный для провайдера UI (подключения к курьерским службам, адрес отправителя) вместо двух разрозненных экранов.
Миграция завершена. Теперь провайдер получает настройки из Medusa Admin без правок кода и редеплоя, хранит секреты зашифрованными, из коробки поддерживает несколько инстансов и проверяет соединение прямо из админки. Кастомный UI при этом остаётся вашим, но живёт на одной странице с формой модуля.
Полный код миграции доступен в открытом репозитории: .