SelSup Developers

专业技术 · 导游

扩展和定制集成

使用任何框架构建一个普通的HTML/JavaScript页面. SelSup将其嵌入到iframe中;它不会执行您的React代码在柜内.

章节: 11开发人员指南
→

使用任何框架构建一个普通的HTML/JavaScript页面. SelSup将其嵌入到iframe中;它不会执行您的React代码在柜内.

应用程序开发人员和技术合作伙伴

1

选择集成类型

  1. 1

    外部后端服务

    对于 ERP,网店,WMS,BI等同步功能,最好.该代币留在服务器上,数据通过API和网关移动.

  2. 2

    柜子iframe板

    使用任何框架构建一个普通的HTML/JavaScript页面. SelSup将其嵌入到iframe中;它不会执行您的React代码在柜内.

  3. 3

    后端模块 SelSup

    需要参与共享SelSup背景流程的深入市场或交付集成.

i
开始用一个薄的垂直切片

首先实现一个完整的工作流程及其可观察性. 调整后添加大量进口,UI和更多事件类型是稳定的.

2

外部应用架构

存储代币在秘密管理器中,只从后端调用SelSup. 浏览器应用程序应该与API交谈,并且永远不会接收SelSup代币.

隔离SelSup适配器,工作队列和域名模型.

对于进来的事件使用收件箱和出发的变更,使用输入箱.

数据流 · Text
SelSup webhook → inbox → domain worker → ERP/WMS
ERP/WMS change → outbox → SelSup API → reconciliation

3

柜子iframe板

使用任何框架构建一个普通的HTML/JavaScript页面. SelSup将其嵌入到iframe中;它不会执行您的React代码在柜内.

设置一个独立的HTTPS网站,该网站与柜台没有 Cookie域名. 打开集成 → 我的扩展 → 添加扩展,选择名称,图标,URL,菜单部分和位置. 保存一个没有权限的私人面板,然后只启用所需的权限. 存储发布需要SelSup审查.

4

服务器侧集成模块

交付服务通常包括代币,卡片,价格,股票,订单和背景状态更新.

本模块改变了主要SelSup后端,并遵循其审查,测试,本地化和发布过程. 在实施之前,同意接口和数据界限.

将外部API故障转换为稳定的ApplicationError值和撤销或无效的外部代币,根据后端项目规则转换成AccessException.

i
共享数据兼容性

没有添加市场特定的领域到共享实体. 保持原始合同的集成DTO和地图它们在边界.

5

释放和运行

  1. 1

    创建测试帐户

    根据客户生产数据,单独测试代币,仓库,产品和订单.

  2. 2

    增加可观测性

    追踪排队延迟,代码错误,重复试数,和差.

  3. 3

    计划合同迁移

    在过渡期间支持旧字段,并在禁用旧格式之前部署消费者.

  4. 4

    文件断开连接

    用户必须知道如何撤销代币,删除网络链接,

6

产品和订单单

选择菜单页面 (MENU_PAGE),产品卡卡卡 (PRODUCT_TAB) 或订单卡 (ORDER_TAB).菜单部分和位置仅适用于MENU_PAGE. 卡需要存储一个具有ID的实体.

7

文本和权限

只有授予的语境字段才会共享.USER提供user.id和user.locale;CLIENT提供client.id;ORGANIZATION提供可访问的组织ID和名称. PRODUCT单独授予产品卡上的 product.modelId;ORDER授予订单上的 order.id.id是完全的记录,联系人,密码和代币除外.这些是已开放的页面的标识符,而不是您的后端的访问证明.

文本 v1 · JSON
{
  "type": "selsup.extension.context",
  "version": 1,
  "context": {
    "version": 1,
    "extensionId": "example-extension-id",
    "placement": "MENU_PAGE",
    "user": {"id": 101, "locale": "ru"},
    "client": {"id": 202},
    "organizations": [{"id": 303, "name": "Demo"}]
  }
}
标签背景 v1 · JSON
[
  {
    "version": 1,
    "extensionId": "example",
    "placement": "PRODUCT_TAB",
    "apiMethods": [],
    "product": {
      "modelId": 404
    }
  },
  {
    "version": 1,
    "extensionId": "example",
    "placement": "ORDER_TAB",
    "apiMethods": [],
    "order": {
      "id": 505
    }
  }
]

8

邮件v1消息

查看事件.起源,事件.来源 ===窗户.父母,消息类型,版本和结构. 连接和请求文本即可更新. SelSup重新检查访问并将频繁的请求合并.永远不要在URL,面板 localStorage或消息中传输代币.

主机/扩展桥 · JavaScript
const allowedOrigins = new Set(['https://your-cabinet.example.com']);
window.addEventListener('message', (event) => {
  if (event.source !== window.parent || !allowedOrigins.has(event.origin)) return;
  const message = event.data;
  if (!message || message.type !== 'selsup.extension.context' || message.version !== 1) return;
  const context = message.context;
  if (!context || context.version !== 1 || !['MENU_PAGE', 'PRODUCT_TAB', 'ORDER_TAB'].includes(context.placement)) return;
  // The complete sample also validates fields and strips unknown properties.
  document.querySelector('#context').textContent = JSON.stringify(context, null, 2);
});
for (const origin of allowedOrigins) {
  window.parent.postMessage({type: 'selsup.extension.ready', version: 1}, origin);
}
// Refresh after connecting: use the validated origin, never "*".
window.parent.postMessage({type: 'selsup.extension.request-context', version: 1},
  'https://your-cabinet.example.com');

9

通过iframe桥API

编者在扩展设置中声明所需的方法.每个安装客户端都明确授予该声明中的方法. API访问默认不允许任何,包括现有安装.更改请求列表需要再次审查;安装的副本从未自动获得新的权限.

服务器使用 SelSupFront 服务只使用以下方法,使用当前员工的权限.现有的服务器访问控制仍然适用.客户端服务和 authService 完全禁止;此列表之外的所有方法也被拒绝.应用程序无法提供URL,标题,代币或任意的Axios配置.服务器检查当前的安装和其补贴在实际API请求上.

API 补助是独立于文本权限. context.apiMethods列出授予的方法. 补贴适用于员工访问范围内的整个内方法,而不是仅仅在当前选项表中的实体.结果只包含文档化字段,从来没有Axios对象或凭证.

飞行时的请求,每秒最多一次启动.最后的256个请求ID免受重复保护.主机错误:ACCESS_DENIED,INVALID_REQUEST, RATE_LIMITED,EDUPLICATE_REQUEST,EREQUEST_FAILED.SDK错误还包括NOT_CONNECTED,DISCONNECTED和 TIMEOUT (20秒).永远不要自动重新尝试突变:error,时间过关或iframe关闭并不意味着操作已被推迟.

允许的方法v1 · Text
tagService.findTags              {query?, page?, limit?}   => {rows: [{id, name}]}
tagService.createTag             {name}                   => {id, name}
tagService.updateTag             {id, name}               => {id, name}
tagService.deleteTag             {id}                     => null
productService.updateFavourite   {id, favourite}          => null

id: positive safe integer; updateFavourite.id = product.modelId
favourite: boolean
name: 1..100 characters (trimmed); query: 0..100 characters
page: 1..10000, default 1; limit: 1..100, default 30
请求 · JSON
{
  "type": "selsup.extension.api-request",
  "version": 1,
  "requestId": "request-1",
  "method": "tagService.createTag",
  "params": {
    "name": "Demo"
  }
}
响应 · JSON
{
  "type": "selsup.extension.api-response",
  "version": 1,
  "requestId": "request-1",
  "ok": true,
  "result": {
    "id": 1,
    "name": "Demo"
  }
}
样本 SDK:接收后的 context.apiMethods · JavaScript
// connection = connectExtension(...) from selsup-extension.js
// Run from a button click after receiving context.apiMethods.
const tag = await connection.callApi('tagService.createTag', {name: 'Demo'});
console.log(tag.id, tag.name);

10

应用程序和托管

样本可以复制到一个独立的 GitHub 存储库.使用 Node.js 22+, npm 测试和 npm启动运行测试以及没有 API 密钥或实际数据的本地模拟柜.配置config.js,并部署五个静态文件到 HTTPS 托管.下面链接的档案下载,并复制其内容到 GitHub 的存储室.

地方演示 · Shell
cd selsup-extension-example
npm test
npm start
# Mock host: http://localhost:4174/
# Panel: http://127.0.0.1:4173/
通过 HTTPS 响应标题 · HTTP
Content-Security-Policy: default-src 'none'; script-src 'self'; style-src 'self'; connect-src 'none'; form-action 'none'; base-uri 'none'; frame-ancestors https://your-cabinet.example.com
Referrer-Policy: no-referrer
X-Content-Type-Options: nosniff
备用GitHub/ZIP的样本 · URL
https://api.selsup.ru/assets/examples/selsup-extension-example.zip

11

安全边界

沙盒阻止表格,弹出窗口,下载,顶级导航和敏感浏览器API.面板来源显示在iframe以上.扩展器绝不能要求SelSup密码.其网站仍然可以看到访问者IP,保留或转发给它提供的数据.审查不能结在外部URL上提供的代码.只允许必要的权限.

SelSup本身允许iframe桥接;cookies和代币从来没有进入应用程序.您的自己的后端仍然需要自己的身份验证:文本不证明身份.只在服务器上保存长期的SelSup代币.完全订购/product记录和内线卡块不支持.