npm.io
0.3.4 • Published yesterday

@cyte-editor/license

Licence
SEE LICENSE IN ./LICENSE
Version
0.3.4
Deps
0
Size
60 kB
Vulns
0
Weekly
0

@cyte-editor/license

CyteEditor 商业授权客户端 SDK — JWT 验签、域名/AppId 绑定、撤销同步、降级 fallback。

内部包:本 README 仅供 monorepo 内部开发参考,不发布到 npm 站点(npm 仅消费 dist/ 与公开元数据)。


定位

License Client SDK 是「Worker 颁发的 JWT」与「编辑器运行时」之间的唯一桥梁 —— 把一串字符串翻译成「客户能用哪些功能、能用多久、坏了怎么降级」的运行时决策。

设计原则详见 doc/launch/CyteEditor-Codebase-Refactor-Spec-v0.1.md §5。


当前实施进度

任务 状态 说明
2-12 包骨架(package.json / tsconfig / vite / vitest)
2-13 verifyLicense / requireTier / getLicenseStatus 公共 API(payload 解码 + 字段校验 + 过期/domain/appId 判定 + 5 态状态机 + 事件订阅 + LicenseError)
2-15 当前 scripts/embed-public-key.mjs 构建期注入公钥(多 kid → PEM map 架构 + 指纹交叉校验 + placeholder 降级 + 幂等写入),生成 src/public-key.ts(gitignored)
2-16 待办 JWT ES256 验签(WebCrypto ECDSA P-256,替换 2-13 的"信任解码")
2-17 待办 IndexedDB 24h TTL 缓存 + 单调时间戳防回拨
2-18 待办 完整 7 态状态机(含 tamper_suspected 与防回退)
2-19 待办 4 档校验模式(A 纯离线 默认 / B lazy / C strict+grace / D 硬件指纹)
2-20 待办 反篡改 4 层(冗余校验 / 字符串拆分 / banner 法律证据 / 时间篡改防御)
2-22 待办 applyWatermark / applyReadonly 实际实现(集成层)

2-13 当前阶段 verifyLicense 不做密码学验签(仅 base64url 解码 + 字段校验 + 过期判定),属 Spec §5.5 标准方案。禁止用于生产,待 2-16 完成 ES256 验签后方可上线。


公共 API

import {
  verifyLicense,
  requireTier,
  getLicenseStatus,
  getLicensePayload,
  onLicenseEvent,
  LicenseError,
} from '@cyte-editor/license'

// 1. 异步主入口(EditorManager 启动时调用)
const result = await verifyLicense({
  key: 'eyJ...',           // JWT token
  appId: 'mycompany.app',  // 可选:app_id 绑定校验
  online: false,           // 默认 A 档纯离线
})
// result: { valid, status, reason?, payload?, source, expiringSoonDays? }

// 2. 子包用:tier 同步守卫(不通过抛 LicenseError)
try {
  requireTier('pro_business')
  // ... Pro 功能代码
} catch (e) {
  if (e instanceof LicenseError && e.reason === 'tier_insufficient') {
    // 降级 / 引导升级
  }
}

// 3. 状态查询(同步)
const status = getLicenseStatus()      // 'valid' | 'expiring_soon' | 'expired' | ...
const payload = getLicensePayload()    // LicensePayload | null(深拷贝)

// 4. 事件订阅
const unsubscribe = onLicenseEvent('license:expiring_soon', (e) => {
  console.warn(`License expires in ${e.payload?.exp} days`)
})
unsubscribe()

体积预算

启动期目标:≤ 20 KB(gzip 前 minified 产物)。

阶段 ESM CJS 占用
2-12 骨架 0.91 KB 0.97 KB 4.6%
2-13 公共 API 5.23 KB 4.41 KB 26.2%
2-15 公钥嵌入 5.23 KB 4.41 KB 26.2%public-key.ts 暂未被 SDK 主流程 import,2-16 验签上线后才纳入 bundle)
预算上限 20 KB 20 KB 100%

零运行时依赖;JWT 验签将使用 WebCrypto SubtleCrypto(2-16),无需 jose/jsonwebtoken。


构建 & 测试

pnpm --filter @cyte-editor/license build       # 产出 dist/(前置自动跑 embed-public-key)
pnpm --filter @cyte-editor/license typecheck   # TS 类型检查(前置自动跑 embed-public-key)
pnpm --filter @cyte-editor/license test        # vitest run(含 24 用例:15 API + 9 公钥嵌入)
pnpm --filter @cyte-editor/license run embed-public-key  # 单独跑公钥注入

公钥注入说明(2-15):本包构建/类型检查/测试入口均自动前置调用 scripts/embed-public-key.mjs,从仓库根 keys/public.pem + keys/public.kid 注入 src/public-key.ts(该文件已 gitignored)。当 keys/public.pem 缺失(CI / 全新克隆)时脚本回退到 placeholder 模式,仅生成空骨架不阻塞 typecheck/test。