mcpField
S
salla-embedded-app

salla-embedded-app

github.com/sallaapp开发282 次安装2 周前更新
代码仓库

关于 salla-embedded-app

salla-embedded-app 是将自定义页面集成到 Salla Merchant Dashboard 的技能,涵盖页面注册、SDK 配置、后端安全令牌验证,以及导航和界面控件等仪表板模块的接入。

主要功能

  1. 01注册和管理嵌入式页面
  2. 02初始化 Salla 嵌入式 SDK
  3. 03通过后端会话流程验证令牌
  4. 04同步仪表板主题和语言
  5. 05接入导航、界面及结账模块

适用场景

  1. 01向 Salla 商家仪表板添加自定义页面
  2. 02使用后端验证的令牌认证嵌入式应用
  3. 03连接页面导航和仪表板控件

MCP 相关

它使用 Salla Partners MCP 服务,通过 `salla_embedded_pages` 工具注册和管理仪表板嵌入式页面。执行此步骤需要连接该 MCP 服务。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/sallaapp/salla-partners-agent-kit --skill salla-embedded-app

安装后在 Claude Code 中输入/salla-embedded-app确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
auth-and-session.md
design-guidelines.md
implementation-guide.md
sdk-modules-guide.md

详细介绍

Salla 内嵌应用流程

在 Salla 商家管理后台中集成自定义页面。第 1 步通过 Salla Partners MCP 执行页面注册;SDK 步骤是你要写入应用的代码。请按顺序完成每一步,并通过当前关卡后再继续。

Salla 官方采用 信任但验证 模型:Salla 会在 iframe URL 中传递一个短期有效的令牌;你的前端通过 embedded.auth.getToken() 捕获该令牌,并交给你的后端,后端通过 Salla 的 Introspection API 验证令牌,然后创建自己的会话。前端只是信使,不会做出授权决定。第 3 步是操作指南;references/auth-and-session.md 是权威来源。

安全规则(必须遵守)

  • 通过后端验证每个页面。 后端验证 Salla 令牌(introspect),创建自己的会话,并根据该会话授权每个请求;前端只负责传递令牌。
  • 通过后端 introspect 进行验证 (POST https://api.salla.dev/exchange-authority/v1/introspect,请求头为 S-Source: <YOUR_APP_ID>)。 embedded.auth.introspect()(Client Introspect)仅用于开发/调试 — 文档指出,它“不应作为主要身份验证方法使用”。完整请求/响应 → 第 3 步 + auth-and-session.md。
  • 身份信息只能来自 introspection。 将每条路由和每个查询限定为 introspection 返回的 merchant_id;只能通过 Salla 原生的内嵌应用支持访问管理后台(不要使用信任查询参数或 referer 的独立 /dashboard?store_id=… URL)。

工具

工具操作功能
salla_embedded_pageslist / create / update / delete管理应用的内嵌(iframe)管理后台页面

**前置条件:**必须连接 Salla Partners MCP 服务,并且你需要应用的 app_id。如果工具返回 "Salla session expired",请重新运行登录流程。


第 0 步 — 了解需求

开始前先询问:

  1. 此页面的用途是什么?(设置界面、分析仪表板、插件购买等)
  2. 需要哪些 SDK 模块?
    • auth — getToken、refresh、introspect(仅用于开发),以及核心方法 init/ready/destroy
    • page — setTitle、navigate、redirect、navTo
    • nav — 操作按钮(setAction/onActionClick/clearAction)和子导航项
    • ui — 提示消息、确认对话框、加载状态、面包屑
    • checkout — 插件购买
  3. 页面是否需要销售插件?(启用 Checkout 模块)

第 1 步 — 注册页面

调用 salla_embedded_pages,并传入 action: "create"、app_id,以及以下参数来注册 iframe 页面:

  • route — 页面的 kebab 路径片段(≥ 3 个字符)。显示为 https://s.salla.sa/embedded/app/{appId}/{route}。
  • iframe_url — Salla 在 iframe 中加载的完整 URL(例如 https://dashboard.myapp.net/salla/embedded)。Salla 会附加 token、theme、lang。
  • default — 可选;将此页面设为应用的默认落地页。

create 会返回新页面;Portal 的 update 不会返回响应正文,因此工具会回显你更改的字段({ page: { id, route, iframe_url, default, updated: true } })作为确认。调用 salla_embedded_pages action=list 获取权威的当前状态。使用 update/delete 更改或移除页面。

**手动备用方案:**Portal → App Details → Embedded Pages → Add page。

关卡:"salla_embedded_pages action=list 返回了页面 — 你能在商家管理后台的侧边栏中看到它吗?"

内嵌应用图片(发布时设置)

可嵌入应用包含两张应用商店图片,均在发布过程中设置,而非通过 SDK 设置。请在发布时设置(步骤 6 → salla-publication-consistency):

图片设置位置尺寸 / 限制展示位置
内嵌应用横幅(embedded_image)app_publish 的功能区最小 710×260 px(建议 1420×520),最大 512 KB应用的内嵌 / iframe 展示
Salla 宣传图片app_publish 的功能区(宣传 / 精选)生成前通过 app_publish readiness / salla-docs 确认尺寸Salla 的宣传 / 精选(构建)版块

Salla 宣传图片是第二张图片(除内嵌应用横幅外),用于 Salla 的宣传 / 精选版块——应用在该处展示时,请务必提供。

图片生成补充流程适用于两者:如果缺少任一图片(或这是首次发布),且有可用的图片生成工具 → 确认上述尺寸,生成图片,salla_upload,然后通过 app_publish 的功能区设置;否则请向商家索要真实素材。请勿重复这些步骤——标准流程(以及其他所有列表图片字段)见 salla-app-ui-builder。 手动备用流程:My Apps → App → App Details → Start publishing → App Features。


步骤 2 — 安装并初始化 SDK

安装 npm 包——不要依赖 CDN 全局变量。 从包中导入 embedded,以便 TypeScript 验证方法名称;CDN 版本的全局变量名称 / 结构可能不同,导致启动静默失败。

npm install @salla.sa/embedded-sdk
import { embedded } from "@salla.sa/embedded-sdk";

CDN 备用方案(仅适用于原生 / 未打包页面——请先确认全局变量):

<script src="https://unpkg.com/@salla.sa/embedded-sdk/dist/umd/index.js"></script>
<script>
  const embedded = Salla.embedded; // or SallaEmbeddedSDK.embedded
</script>

每次页面加载时都要初始化——init() 会建立 postMessage 桥接,并解析为控制台 layout:

const { layout } = await embedded.init({ debug: false });
// layout carries theme ("light"|"dark"), locale ("ar"|"en"), dir ("rtl"|"ltr"), …

即使 SDK 调用正确,也有两件事会阻碍内嵌应用首次运行:

  1. 可嵌入性——宿主必须允许 Salla 对页面进行框架嵌入(设置 Content-Security-Policy: frame-ancestors https://s.salla.sa,移除 X-Frame-Options),否则控制台会显示空白 /“拒绝”窗格。
  2. 开发循环——页面需要通过控制台握手获取令牌,因此无法在普通标签页中打开。将 localhost 隧道化,把 iframe_url 指向该隧道,在演示商店中安装,然后点击 Run App。

响应头、开发循环、框架注意事项(React/Next、Vue)、完整示例及可直接复制粘贴的入门模板 → references/implementation-guide.md

模块指南 → references/sdk-modules-guide.md


第 3 步 — 验证会话(信任但验证)

流程顺序如下:

  1. await embedded.init() — 建立桥接;读取 layout。
  2. embedded.auth.getToken() — 从 iframe URL 获取短期令牌 (返回 string | null;若返回 null,表示在 Salla 外部打开)。
  3. 将令牌发送到你自己的后端。 前端只是传递令牌的通道——不要在此处做授权决策。
  4. 后端通过以下接口验证: POST https://api.salla.dev/exchange-authority/v1/introspect, 请求头 S-Source: <YOUR_APP_ID>,请求体 { "token": "..." } → 成功时,声明会嵌套在 data 下:读取 data.merchant_id / data.user_id / data.exp(data.exp 是 ISO-8601 日期时间字符串,不是 Unix 时间戳)。后端生成自己的会话 (JWT / 安全 Cookie)。
  5. embedded.ready() — 仅在后端确认且数据已加载后调用。在此之前,控制面板会显示加载遮罩。
  6. 失败时 — 调用 embedded.destroy() 以正常退出,避免商家一直停留在加载界面。
// 1. Bridge + layout
const { layout } = await embedded.init({ debug: false });

try {
  // 2. Capture the short-lived token from the URL
  const token = embedded.auth.getToken();
  if (!token) throw new Error("Opened outside Salla — no token");

  // 3 + 4. Hand the token to YOUR backend; it introspects and mints a session.
  const res = await fetch("/api/auth/session", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    credentials: "include",
    body: JSON.stringify({ token }),
  });
  if (!res.ok) throw new Error("Verification failed");

  // 5. Backend confirmed + data loaded → reveal the iframe.
  await loadDashboardData();
  embedded.ready();
} catch (err) {
  console.error("Auth failed", err);
  embedded.destroy(); // exit gracefully instead of hanging on the loading overlay
}

embedded.auth.introspect() 仅用于开发/调试——这是前端辅助参考方法,用于演示文档明确指出“不应作为主要身份验证方式”的 introspection 流程。生产环境中的授权始终通过上述后端 introspect 完成。

当后端返回 401 / 令牌过期时 → 调用 embedded.auth.refresh();Salla 会使用新令牌重新加载 iframe,重新运行初始化流程,并从头开始。

完整的后端 introspect(包含 S-Source)、会话生成和 401→refresh 循环 → references/auth-and-session.md

检查项:“你的后端是否会在调用 ready() 前,使用 S-Source 请求头 introspect 令牌并生成自己的会话?请使用演示商店测试。”


第 4 步 — 同步主题和语言区域设置

主题、语言区域设置和方向来自 embedded.init() 返回的 layout——不要手动读取查询参数:

if (layout) {
  document.documentElement.setAttribute("data-theme", layout.theme);
  document.documentElement.setAttribute("lang", layout.locale);
  document.documentElement.setAttribute("dir", layout.dir); // "rtl" for ar, "ltr" for en
}

layout 是外观设置的事实来源;每当 SDK 重新初始化时(例如 embedded.auth.refresh() 重新加载 iframe 后),都要重新应用这些设置。控制面板也支持动态切换主题——在可用时,使用 embedded.onThemeChange() 监听变化。

设计令牌、品牌颜色、RTL 模式 → references/design-guidelines.md


第 5 步 — 接入 SDK 模块

要绘制可见的 UI? 请停在这里并加载 → salla-embedded-ui。 其中的检查项(原生令牌、No-Chrome、RTL、实时截图)必须遵守;仅在接入 SDK 时返回 salla-embedded-app,不要在此处处理样式。

根据第 0 步中的需求,实现相关模块:

Auth — 可恢复的过期情况使用 refresh;仅在无法恢复时 destroy:

// Backend reported the token expired (401): refresh — Salla re-renders the iframe with a fresh one.
embedded.auth.refresh();

// Only when auth is unrecoverable (a fresh token still can't verify, app suspended):
embedded.destroy(); // tears down the iframe so the dashboard doesn't hang

调用顺序很重要:临时过期时必须调用 refresh(),而不是 destroy()。

Page — 标题和控制面板导航:

embedded.page.setTitle("My App");
embedded.page.navigate("/orders"); // internal SPA route (React Router)
embedded.page.redirect("https://docs.my-app.com/help"); // external / full reload
embedded.page.navTo("/orders"); // auto-picks navigate vs redirect

Nav — 操作按钮和子导航项:

embedded.nav.setAction({
  title: "Save",
  value: "save",
  icon: "hgi hgi-stroke hgi-tick-02",
}); // icon optional (Hugeicons class)
const off = embedded.nav.onActionClick((value) => {
  if (value === "save") saveChanges();
});
embedded.nav.clearAction(); // when the merchant leaves this view

UI — 提示消息、加载状态、确认框、面包屑:

embedded.ui.toast.success("Saved!");
embedded.ui.toast.error("Something went wrong");
embedded.ui.loading.show();
embedded.ui.loading.hide();
const { confirmed } = await embedded.ui.confirm({
  title: "Delete?",
  message: "This cannot be undone.",
  variant: "danger", // confirm() resolves to { confirmed }, not a bare boolean
});
embedded.ui.breadcrumbs.hide(); // or .show()

Checkout — 在应用内购买附加组件(如适用): → 按照 salla-addon-purchase-embedded 技能操作(嵌入式/应用内购买流程; 有关附加组件定价/权益机制,请参阅 salla-addon-purchase)

完整的方法签名 → references/sdk-modules-guide.md

检查项:“正式上线前,请在 SDK Playground 中测试你使用的每个模块。” → Playground / Test Kit


第 6 步 — 发布

发布父应用后,嵌入式页面即会上线。请遵循 salla-app-builder 发布步骤中的发布检查清单。


资源

主题链接
概览(中心页)https://docs.salla.dev/embedded-sdk/overview.md
入门https://docs.salla.dev/embedded-sdk/getting-started.md
安装https://docs.salla.dev/embedded-sdk/installation.md
创建嵌入式应用https://docs.salla.dev/embedded-sdk/create-app.md
身份验证https://docs.salla.dev/embedded-sdk/authentication.md
令牌内省(API)https://docs.salla.dev/27474794e0.md
应用设计指南https://docs.salla.dev/embedded-sdk/design-guidelines.md
Playground / 测试https://docs.salla.dev/embedded-sdk/playground.md
支持与社区https://docs.salla.dev/embedded-sdk/resources/support.md
实现指南references/implementation-guide.md
SDK 模块方法references/sdk-modules-guide.md

各模块的页面位于 https://docs.salla.dev/embedded-sdk/modules/...(auth、page、nav、 ui、checkout)。打包的 sdk-modules-guide.md 中包含 相同的函数签名。

评论

支持 Markdown