关于 tiun-sdk
tiun-sdk 是面向 Agent 的指导技能,用于集成或调试 tiun 的 JavaScript 与 React Native SDK。它涵盖订阅、一次性购买和按时计费访问,并分别说明平台用法及安全授权要求。
主要功能
- 01指导订阅和一次性购买配置
- 02说明按时计费访问流程
- 03区分 Web 与 React Native SDK
- 04介绍 MCP 的检测与安装
- 05指导后端令牌验证
适用场景
- 01在 Web 应用集成订阅结账
- 02为一次性购买后的内容设置访问限制
- 03为付费内容添加按时计费访问
- 04排查 SDK 配置或环境不匹配
MCP 相关
该技能要求 Agent 检测 tiun 的 MCP,并在缺少时提供安装选项;不可用或用户拒绝时可改为手动操作。连接并完成认证后,MCP 可列出服务提供方和产品,为集成选择提供依据。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ tiun-app/ skills --skill tiun-sdk安装后在 Claude Code 中输入/tiun-sdk确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/api-reference.mddiscovery.mdevents.mdframeworks.mdinstallation.mdmcp.mdone-time.mdoverview.mdreact-native.mdserver-verification.mdsubscriptions.mdtime-based.mdtroubleshooting.md详细介绍
tiun SDK 技能
当用户集成、扩展或调试使用 @tiun/sdk 或 @tiun/react-native-sdk 的代码时,请使用此技能。权威上游文档:https://docs.tiun.io/llms-full.txt。
tiun 是什么
tiun 是一个商业后端平台,通过单个 JS SDK 提供身份验证、支付和权益。tiun 单例支持三种流程,具体选择取决于集成者的意图(参见“步骤 0 — 编写代码前先了解需求”):
- 订阅 — 持久化用户账户(OTP 登录)、周期性账单,以及
user.productAccess[]中按产品划分的权益。入口:tiun.checkout({ productId })。参见 references/subscriptions.md。 - 一次性购买 — 与订阅使用相同的账户和入口,但采用单笔固定费用,权益永久有效:没有计费周期、试用期、续订或到期时间。入口:
tiun.checkout({ productId })。参见 references/one-time.md。 - 基于时间 — 按会话提供匿名访问(无需账户),根据用户在付费内容上花费的时间计量。入口:
tiun.start()+paywallShow/paywallHide事件。参见 references/time-based.md。
安装:npm install @tiun/sdk。初始化:应用启动时调用 tiun.init({ snippetId, language: 'en' })(幂等)。
tiun 的线上环境和沙盒环境是两个独立并行的环境。SDK 的 sandbox 标志用于选择环境,参见 references/installation.md。
React Native 使用独立的 SDK。 @tiun/react-native-sdk 使用 <TiunProvider> + useTiun() / useTiunEvent(),通过 host 选择环境(不使用 sandbox 标志),需要 returnUrl 深层链接,并且仅支持订阅和一次性购买。相关内容请参见 references/react-native.md。下方的 tiun.* 代码、最简可用示例和各框架接入方式仅适用于 Web,切勿在 React Native 应用中生成这些内容。
步骤 0 — 编写代码前先完成发现
优先确认平台。 提问前先检查项目:如果 package.json 中有 react-native 依赖(或存在 ios/ + android/ 文件夹),则为 React Native → 在进行此处发现的同时,遵循 references/react-native.md。否则即为 Web SDK。在 React Native 中,按时长计费不可用——如果用户提出此需求,请在 0b 中说明。
编写任何集成代码之前,先确认以下四项。只询问用户尚未说明的内容。如果用户的提示已完整明确(“在 sandbox 中接入产品 p-test-pro 的订阅,以限制 /watch/* 的访问”),则跳过发现步骤。
如果客户端支持结构化提问原语(例如 AskQuestion),请使用;否则直接在聊天中提问。
0a. 检测 MCP;如果缺失,则询问是否安装。 各客户端的安装说明和检测方法见 references/mcp.md。分为三种状态:
- MCP 已存在且已完成身份验证 → 在 0c 中使用它列出提供商和产品。
- MCP 已存在,但尚未完成身份验证 → 提示用户完成身份验证一次;如果用户拒绝,则改用手动模式。
- MCP 不存在 → 询问是否安装(用一句话说明其价值:“直接获取你的 snippetId 和 productIds,避免复制粘贴出错。”)。如果用户拒绝,则改用手动模式。
0b. 确定集成模式。 是订阅、一次性购买、按时长计费,还是组合模式?各模式对应的用户表述线索见 references/discovery.md。不要根据账户中的产品库存推断模式。 某个提供商今天可能只有一种产品类型,但明天也许会计划增加其他类型。
0c. 收集标识符。 根据模式和 MCP 是否可用,问题有所不同:
- 订阅,MCP 可用 → 列出提供商,让用户选择;列出产品,让用户选择一个或多个套餐;根据提供商的 sandbox/live 标签确认环境。
- 订阅,MCP 不可用 → 询问
snippetId;询问用户要一个产品还是多个套餐;对每个产品,询问productId和标签;确认使用 sandbox 还是 live(p-test-.../p-live-...前缀是重要线索)。 - 一次性购买,MCP 可用 → 列出提供商,让用户选择;列出产品,让用户选择要解锁的一个或多个产品;根据提供商的 sandbox/live 标签确认环境。不要询问套餐——一次性产品没有分级套餐。
- 一次性购买,MCP 不可用 → 询问
snippetId;对每个产品,询问productId和标签;确认使用 sandbox 还是 live(前缀是重要线索)。 - 按时长计费,MCP 可用 → 列出提供商,让用户选择;根据提供商标签确认环境。
- 按时长计费,MCP 不可用 → 询问
snippetId;确认使用 sandbox 还是 live。
MCP 可用时,提问应基于现有产品库存(“你有一个 sandbox 按时长计费产品 p-test-xxx——要接入这个产品,还是先设置订阅产品?”),而不是盲目提问。
0d. 确定要限制访问的内容。 缺少这一步,Agent 生成的就只是没有目标的样板代码。请询问:
- 哪些路由、组件或功能需要限制访问?
- 未登录用户应看到什么?应用的使用流程从何处开始?(商品展示页或定价页 / 先登录、遇到升级提示后再升级的账户优先型应用 / 全屏付费墙 / 预览内容 + 订阅)。保持与应用设计相符的流程。
- 已通过身份验证但无访问权限的用户应看到什么?(通常沿用相同的体验,只需改用“升级”文案)
- 是否提供免费预览?(如果有,这通常表明用户真正需要的是按时长计费,而不是订阅——请将此信息反馈到 0b。)
- 如果有多个套餐:哪些路由或功能对应哪个套餐?
何时查看什么
| 任务 | 查看 |
|---|---|
| 发现、范围界定、MCP 检测、模式选择 | references/discovery.md |
| 各客户端的 MCP 安装、检测、身份验证 | references/mcp.md |
| tiun 是什么、支持的平台、产品模式、托管 UI 的边界 | references/overview.md |
| 安装 / 初始化 / 配置 / 向各主机注入环境变量 | references/installation.md |
| 方法或属性查询 | references/api-reference.md |
| 事件名称和负载 | references/events.md |
| 订阅门控(账户 + 定期计费)、选择结账还是登录 | references/subscriptions.md |
| 一次性购买门控(固定费用、永久访问权限) | references/one-time.md |
| 基于时长的付费墙(按会话计费、匿名、按量计费) | references/time-based.md |
| 可信后端授权 | references/server-verification.md |
| 框架接入(任意技术栈)+ 生命周期矩阵 | references/frameworks.md |
| “覆盖层未显示”、SSR 错误、沙箱不匹配、覆盖层注入失效 | references/troubleshooting.md |
React Native:安装、返回深层链接、TiunProvider、钩子、host、设备测试 | references/react-native.md |
关键规则
tiun.init({ snippetId, language })在客户端早期启动阶段运行。 在 Next.js/Nuxt 中,将其封装在仅客户端组件/插件中。切勿在服务端调用。init具有幂等性——再次调用会合并配置,而不是重新初始化,因此无需设置isInitialized检查。snippetId不是机密。 它用于标识环境。使用NEXT_PUBLIC_*/public运行时配置。- 对于基于结账的访问控制(订阅和一次性购买),应以
userChange为准,而不是只读取一次tiun.user。权益会在会话期间发生变化。在 Web SDK 中,载荷包含event: 'init' | 'login' | 'checkout' | 'logout' | 'update',可用于判断是什么触发了变更。React Native 的载荷没有event字段——请改用单独的login/logout事件。 - 切勿信任客户端进行授权。 对于受保护的服务端资源:
tiun.getUserVerificationToken()会返回一个 JWT(有效期为 5 分钟),将其发送到后端,由后端通过带有X-TIUN-API-KEY的POST /live_api/s2s/v1/users/verification验证。对于基于时长的访问,请使用paywallHide中的sessionId调用PATCH /live_api/s2s/v1/sessions/{sessionId}/status。参见references/server-verification.md。 - 托管 UI 是黑盒——不要重新实现,也不要修改。 tiun 会在 shadow DOM 中渲染结账、登录和连接浮层。使用
tiun.checkout({ productId })、tiun.login()或tiun.start()打开它们,到此为止。切勿穿透shadowRoot来查询、追加或观察节点;切勿向其中注入文本、工具提示、徽章或横幅;切勿使用 CSS 定位它(宿主选择器、::part、::slotted、!important覆盖);切勿重新定位或包装它;切勿读取其输入框中的值。其内部结构没有版本保证,可能随时变更且不另行通知;而且它位于支付流程中——注入内容一旦失效,不会有提示,并会导致结账流程一并中断。唯一受支持的配置项是init()配置(language、tone)和控制台设置。如果客户需要额外文案或说明,请将其放在自己的页面上、触发入口旁边,并在浮层打开前展示——不要放在浮层内。配置和控制台未提供的任何功能,都应通过 [email protected] 联系支持团队,而不是打客户端补丁。参见 references/overview.md。 - 在
ready之前调用的方法可能会排队或不执行。checkout/login/start/setContent/logout等方法已在内部调用ensureInitialized()并执行await this.waitForReady()——无需再套一层。 - 在组件卸载时取消订阅
tiun.on(...)返回的处理程序,以避免监听器失效。或者,在整个子树即将销毁时调用tiun.destroy()。 - Live 和 sandbox 是相互独立的并行环境。 每个环境都有自己的 snippet ID、产品、产品 ID 前缀(
p-live-...与p-test-...)、API 密钥和 API 基础 URL(https://api.tiun.live与https://api-sandbox.tiun.live)。环境切换项(Web 上的sandbox标志,React Native 中的host)必须与控制台视图及产品 ID 前缀相匹配,否则结账会无提示地失败。Live 环境会阻止localhost,sandbox 环境默认启用localhost。每个环境都有自己的 Settings → Environment setup(Web 的 Live 域名,应用的 App scheme)。 - 没有运行时产品列表 API。 产品在 tiun 控制台(
my.tiun.business)中配置,并通过硬编码的productId字符串引用。不要杜撰tiun.getProducts()之类的方法或 REST 端点;请引导用户前往控制台。 - 没有 Webhook。 tiun 不会发送 Webhook。对于后端集成,请根据
getUserVerificationToken()返回的 JWT 或paywallHide中的sessionId驱动状态。不要杜撰 Webhook 端点或事件载荷。 - 忠实遵循上游文档。 所有代码示例都必须与 https://docs.tiun.io 一致。如果某种模式未在上游文档中说明(自定义 SSR 接线、多环境设置、其他语言的后端 SDK 等),请引导用户查看上游文档,而不是杜撰代码片段。
- 不要根据账户中的产品库存推断集成模式。 始终向用户确认(参见“步骤 0”)。MCP 报告的是当前存在的内容;并不会报告集成者想要构建的内容。
productAccess中的一次性产品 ID 永久有效。 它在结账时加入,之后永远不会移除——event: 'update'也不会将其移除。对于一次性产品,不要生成到期、续订、取消、试用或撤销处理逻辑;这些逻辑对应的状态不可能发生,只会成为死代码。续订和取消仅适用于订阅。参见references/one-time.md。- 不要为了添加
isInitialized/waitForReady检查而包装 SDK 方法。tiun.checkout、tiun.login、tiun.start、tiun.setContent和tiun.logout均已在内部完成这两项处理。围绕这些方法编写包装辅助函数只会增加冗余。 - 不要向
init()传入baseUrl。 这是仅供内部使用的字段,仅供 tiun 自身基础设施使用。在 Web SDK 中,非生产环境请使用sandbox: true;这是唯一公开的环境切换项,SDK 会自动路由到相应的 API 主机。(React Native 例外:它没有sandbox标志,而是通过host选择环境——参见references/react-native.md。) language是一个封闭枚举:'en' | 'de' | 'fr',不区分大小写。不受支持的值会触发一次控制台警告,并回退到'en'。不要生成其他值。- 不要根据
error.code来分支应用逻辑。 它是字符串,但没有公开的枚举定义;错误代码可能随 SDK 版本变化。向用户显示err.message,并记录err.code以供支持排查。 - 将运行时配置写入打包工具实际会加载的文件。
.env.example只是文档,不会被求值。Vite 会加载.env/.env.local;Next.js 会加载.env.local,且客户端可访问的值必须使用NEXT_PUBLIC_*前缀;Nuxt 通过nuxt.config.ts中的runtimeConfig.public加载配置。各宿主的配置表参见references/installation.md。 - 账户入口使用认证,购买使用结账。 注册或登录 →
tiun.login();购买产品或方案 →tiun.checkout({ productId });退出登录 →tiun.logout()。根据操作的目的选择,而不是根据它的标签选择。结账会处理购买过程中涉及的认证和回访客户场景,因此购买操作应直接打开结账,而不是先跳转到单独的登录流程。这说的是购买操作应打开什么,不是应用结构——先购买和先进入账户的流程都有效。参见references/subscriptions.md→“选择 checkout 还是 login”。 - React Native 结账需要在三个地方使用同一个 scheme。 控制台的 Settings → Environment setup → App scheme(例如
myapp://)、原生注册(iOS 的Info.plist+AppDelegate中的RCTLinkingManager转发;Android 的 intent filter +android:launchMode="singleTask"),以及TiunConfig中的returnUrl(例如myapp://tiun/return)。重用应用现有的 scheme,而不是另行创建,并告知用户在host指向的环境对应的控制台中注册该 scheme。任何一处不匹配都会导致支付成功,但结账流程无法返回。参见references/react-native.md。
最小可用示例
三个基本构件——在所有受支持的环境中都适用。根据你的技术栈调整响应式基本构件(状态钩子、ref、信号、存储、DOM 更新)。
import { tiun } from '@tiun/sdk';
tiun.init({ snippetId: 'YOUR_SNIPPET_ID', language: 'en' });
const off = tiun.on('userChange', ({ event, isAuthenticated, user }) => {
// push into your framework's reactive primitive
});
document.querySelector('#buy').onclick =
() => tiun.checkout({ productId: 'p-live-pro' });
// off(); tiun.destroy();
各模式的完整演练请见 references/subscriptions.md、references/one-time.md 和 references/time-based.md。各框架的适配方式请见 references/frameworks.md。
判断线索
- 用户提到“订阅”“定期”“会员”“付费账户”“产品和套餐” → 订阅流程。引导至 subscriptions.md。
- 用户提到“买一次”“付一次款”“一次性”“终身”“终身优惠”“单笔付款”“永久解锁”“固定费用”“永久许可证”“无需订阅” → 一次性流程。引导至 one-time.md。
- 用户提到“文章付费墙”“先看视频再付费”“会话”“无需账户”“捐赠提示”“前 N 秒免费” → 按时长计费流程。引导至 time-based.md。
- 用户提到“付费墙后的视频”“高级内容”(含义不明确) → 询问用户选择哪种模式。不要猜测。
- 用户问“如何让我的 Agent 集成 tiun?”/“如何用 AI 编码 Agent 设置这个?” → 指向 docs.tiun.io 上游的 Agent 集成指南,以及
references/mcp.md中的npx skills add tiun-app/skills快速入门。 - 用户问“如何列出产品?”/“获取所有产品?” → 在
my.tiun.business控制面板中配置产品;没有运行时产品列表 API。(MCP 会向 Agent 暴露库存信息以供设置;这不是运行时 SDK 功能。) - 用户提到“在后端验证”“保护 API”“信任客户端” → 服务端验证(
X-TIUN-API-KEY标头;各环境使用不同的基础 URL)。 - 用户提到沙盒 /
localhost/“为什么在本地无法运行” → 确认设置了sandbox: true,使用了沙盒代码片段 ID 和p-test-...产品 ID(在localhost上会硬性阻止正式环境)。 - 用户要求重新设计覆盖层样式、重命名其字段,或在结账或登录界面内添加帮助文本 / 备注 / 工具提示 → 不支持。覆盖层内部内容不允许更改(规则 5);请将文案放在自己页面的触发控件旁,并将品牌相关请求转交至 [email protected]。
- 用户正在配置购买、登录或登出操作 → 根据用途分别对应:购买调用
tiun.checkout({ productId }),账户入口调用tiun.login(),登出调用tiun.logout()。保留应用现有的用户流程(规则 19)。 - 遇到“覆盖层未显示”“ready 之前调用了方法”等错误 → 排查问题。
- 项目使用 React Native,或用户提到
@tiun/react-native-sdk、TiunProvider、useTiun、“iOS/Android 应用”、“深度链接”、“returnUrl”、“结账后无法返回应用” → 查看 references/react-native.md。不要查看 frameworks.md 的 WebView 部分,也不要使用@tiun/sdk。 - 用户想在 React Native 应用中按时长计费 → React Native SDK 不支持;请说明这一点,并引导用户联系 [email protected]。