logo
开发者文档
搜索
SDK API 参考

SDK API 参考

官方 SDK 是两个框架无关、零运行时依赖的包,可以在 GitHub 中获取源码,地址为:https://github.com/gptbots/workspace-extension-sdk

包名 运行位置 入口
@gptbots/workspace-extension-verify 后端(Node ≥ 18) verifyWsa, exchangeWorkspaceCode
@gptbots/workspace-extension-sdk 浏览器 consumeHandoff, startWorkspaceLogin, completeWorkspaceLogin

两个包均为 ESM"type": "module")。CommonJS 项目请用动态 import() 或改用 ESM。


后端包 @gptbots/workspace-extension-verify

verifyWsa(token, options): WorkspaceIdentity

校验 wsa 并返回工作空间身份。校验顺序:签名 → issaud → 过期(exp±leeway,含 iat/nbf) → 必填声明

interface VerifyOptions { secret?: string; // HS256 密钥(per-app 或共享)。校验 HS256 时必填 publicKey?: string; // RS256 PEM 公钥。校验 RS256 时必填(路线图) audience: string; // 扩展应用 host,必须等于令牌 aud(必填) issuer?: string; // 默认 'gptbots-workspace' leewaySeconds?: number; // 时钟漂移容忍(秒),默认 30 algorithms?: ('HS256' | 'RS256')[]; // 默认 ['HS256'] } interface WorkspaceIdentity { accountId: string; // = JWT sub role: 'OWNER' | 'ADMIN' | 'MEMBER'; // 未知值归一化为 MEMBER workspaceId: string; // = JWT workspace_id username?: string; email?: string; avatar?: string; appName?: string; issuedAt?: number; // = iat(秒) expiresAt?: number; // = exp(秒) }
                      
                      interface VerifyOptions {
  secret?: string;        // HS256 密钥(per-app 或共享)。校验 HS256 时必填
  publicKey?: string;     // RS256 PEM 公钥。校验 RS256 时必填(路线图)
  audience: string;       // 扩展应用 host,必须等于令牌 aud(必填)
  issuer?: string;        // 默认 'gptbots-workspace'
  leewaySeconds?: number; // 时钟漂移容忍(秒),默认 30
  algorithms?: ('HS256' | 'RS256')[]; // 默认 ['HS256']
}

interface WorkspaceIdentity {
  accountId: string;                  // = JWT sub
  role: 'OWNER' | 'ADMIN' | 'MEMBER'; // 未知值归一化为 MEMBER
  workspaceId: string;                // = JWT workspace_id
  username?: string; email?: string; avatar?: string; appName?: string;
  issuedAt?: number;   // = iat(秒)
  expiresAt?: number;  // = exp(秒)
}

                    
此代码块在浮窗中显示
  • exp 强制:缺失或非有限数字 → 抛 MissingClaim(不会被当作「永不过期」)。
  • iat / nbf(如存在)在未来超出 leeway → 抛 NotYetValid
  • 失败抛 WsaVerificationError(带 .code);调用方配置错误(如缺密钥)抛 TypeError

WsaVerificationError.code 取值:

code 含义
InvalidToken 令牌为空 / 结构非法 / segment 不是 JSON 对象
InvalidSignature 签名不匹配(密钥错、被篡改)
Expired 已过期(exp + leeway 之前)
NotYetValid iat/nbf 在未来(超出 leeway)
WrongIssuer iss ≠ 期望值
WrongAudience aud ≠ 你的 audience
MissingClaim exp / sub / role / workspace_id
UnsupportedAlgorithm alg 不在白名单(默认仅 HS256

exchangeWorkspaceCode(options): Promise<WorkspaceCodeExchangeResult>

拉式登录用:在扩展应用后端把一次性 code + PKCE codeVerifier 换成 wsa。切勿在浏览器调用。

interface ExchangeWorkspaceCodeOptions { tokenUrl: string; // 平台 /token 端点(绝对 URL) code: string; // 回调拿到的一次性授权码 codeVerifier: string; // 与 code_challenge 对应的 PKCE verifier fetch?: typeof fetch; // 可注入 fetch(测试/旧运行时);默认全局 fetch timeoutMs?: number; // 请求超时,默认 10000;传 0 关闭 } interface WorkspaceCodeExchangeResult { wsa: string; // 签名后的 wsa,交给 verifyWsa tokenType?: string; // 'Bearer' expiresIn?: number; // wsa 有效期(秒) }
                      
                      interface ExchangeWorkspaceCodeOptions {
  tokenUrl: string;      // 平台 /token 端点(绝对 URL)
  code: string;          // 回调拿到的一次性授权码
  codeVerifier: string;  // 与 code_challenge 对应的 PKCE verifier
  fetch?: typeof fetch;  // 可注入 fetch(测试/旧运行时);默认全局 fetch
  timeoutMs?: number;    // 请求超时,默认 10000;传 0 关闭
}

interface WorkspaceCodeExchangeResult {
  wsa: string;           // 签名后的 wsa,交给 verifyWsa
  tokenType?: string;    // 'Bearer'
  expiresIn?: number;    // wsa 有效期(秒)
}

                    
此代码块在浮窗中显示
  • 传输失败 / 非 2xx / 业务 code≠0(如 403209 invalid_grant403210 invalid_verifier)/ 缺 data.wsa → 抛 Error
  • 超时抛 token exchange timed out after <ms>ms(默认 10s,防平台慢响应挂住你的后端)。

Express 中间件示例

import { verifyWsa, WsaVerificationError } from '@gptbots/workspace-extension-verify'; export function requireWorkspaceIdentity(secret: string, audience: string) { return (req, res, next) => { try { req.identity = verifyWsa(req.body.wsa, { secret, audience }); next(); } catch (e) { const code = e instanceof WsaVerificationError ? e.code : 'Error'; res.status(401).json({ code }); } }; }
                      
                      import { verifyWsa, WsaVerificationError } from '@gptbots/workspace-extension-verify';

export function requireWorkspaceIdentity(secret: string, audience: string) {
  return (req, res, next) => {
    try {
      req.identity = verifyWsa(req.body.wsa, { secret, audience });
      next();
    } catch (e) {
      const code = e instanceof WsaVerificationError ? e.code : 'Error';
      res.status(401).json({ code });
    }
  };
}

                    
此代码块在浮窗中显示

浏览器包 @gptbots/workspace-extension-sdk

推式(Push handoff)

readHandoffToken(search?, paramName?): string | null

纯函数,从查询串读取原始 wsasearch 默认 location.searchparamName 默认 'wsa'

stripHandoffToken(paramName?, ctx?): void

history.replaceState 从当前 URL 移除 wsa,让它不残留在地址栏/历史/Referer。浏览器外安全空操作。ctx?: { history?, location? } 可注入(测试)。

consumeHandoff(options): Promise<WorkspaceIdentity>

use 档便捷流:读 wsa → POST 至扩展应用后端 → 成功后抹除 wsa → 返回身份。

interface ConsumeHandoffOptions { exchangeUrl: string; // 扩展应用的后端校验接口 fetch?: typeof fetch; // 可注入 search?: string; // 默认 location.search paramName?: string; // 默认 'wsa' strip?: boolean; // 默认 true(仅成功时抹除) }
                      
                      interface ConsumeHandoffOptions {
  exchangeUrl: string;   // 扩展应用的后端校验接口
  fetch?: typeof fetch;  // 可注入
  search?: string;       // 默认 location.search
  paramName?: string;    // 默认 'wsa'
  strip?: boolean;       // 默认 true(仅成功时抹除)
}

                    
此代码块在浮窗中显示

令牌仅成功交换后抹除,以便瞬时失败可刷新重试。若希望失败也立即抹除,catch 后手动 stripHandoffToken()

拉式(Pull / M-Auth)

startWorkspaceLogin(options): Promise<WorkspaceLoginRequest>

生成 PKCE、存 sessionStorage、构建并(默认)跳转到 /authorize。需要安全上下文(HTTPS/localhost)。

interface StartWorkspaceLoginOptions { authorizeUrl: string; // 平台 /authorize 端点(绝对 URL) clientId: string; // 扩展应用的 app home URL redirectUri: string; // 回调地址,host 须与 clientId 同域 state?: string; // 默认自动生成 16 字节随机 CSRF state workspaceId?: string; // 预选工作空间,跳过组织选择页 storage?: StorageLike; // 默认 sessionStorage redirect?: (url: string) => void; // 默认 location.assign navigate?: boolean; // false = 只构建 URL 不跳转(popup/测试) } interface WorkspaceLoginRequest { url: string; state: string; codeVerifier: string; }
                      
                      interface StartWorkspaceLoginOptions {
  authorizeUrl: string;  // 平台 /authorize 端点(绝对 URL)
  clientId: string;      // 扩展应用的 app home URL
  redirectUri: string;   // 回调地址,host 须与 clientId 同域
  state?: string;        // 默认自动生成 16 字节随机 CSRF state
  workspaceId?: string;  // 预选工作空间,跳过组织选择页
  storage?: StorageLike; // 默认 sessionStorage
  redirect?: (url: string) => void; // 默认 location.assign
  navigate?: boolean;    // false = 只构建 URL 不跳转(popup/测试)
}
interface WorkspaceLoginRequest { url: string; state: string; codeVerifier: string; }

                    
此代码块在浮窗中显示

readAuthorizeCallback(search?, storage?): AuthorizeCallback | null

在回调落地页:读 code + state,校验 state(CSRF),返回 code + 存储的 codeVerifier不会消费存储的请求(消费延迟到成功交换),以便瞬时失败可刷新重试。无 code 且无 error 时返回 null

interface AuthorizeCallback { code: string; state: string | null; codeVerifier: string; }
                      
                      interface AuthorizeCallback { code: string; state: string | null; codeVerifier: string; }

                    
此代码块在浮窗中显示

stripAuthorizeCallback(ctx?): void

从当前 URL 移除 code / state

completeWorkspaceLogin(options): Promise<WorkspaceIdentity>

use 档便捷流:读并校验回调 → POST {code, codeVerifier} 给你后端 → 成功后抹除 URL → 返回身份。

interface CompleteWorkspaceLoginOptions { exchangeUrl: string; // 你自己的后端换取接口 fetch?: typeof fetch; search?: string; // 默认 location.search storage?: StorageLike; // 默认 sessionStorage strip?: boolean; // 默认 true }
                      
                      interface CompleteWorkspaceLoginOptions {
  exchangeUrl: string;   // 你自己的后端换取接口
  fetch?: typeof fetch;
  search?: string;       // 默认 location.search
  storage?: StorageLike; // 默认 sessionStorage
  strip?: boolean;       // 默认 true
}

                    
此代码块在浮窗中显示

WorkspaceLoginError.code 取值

code 含义
NoCallback URL 里没有授权码
MissingRequest 没有/损坏的已存登录请求(先调 startWorkspaceLogin
StateMismatch state CSRF 校验不通过
AuthorizeError 回调是 OAuth 错误重定向(?error=...
NoFetch 无可用 fetch 实现
ExchangeFailed 交换接口返回非 2xx
InvalidResponse 交换接口返回非法 JSON
CryptoUnavailable 无 Web Crypto(需 HTTPS/localhost 安全上下文)
StorageUnavailable 无 sessionStorage(无法存 PKCE verifier)
InvalidAuthorizeUrl authorizeUrl 不是绝对 URL

三、从压缩包本地安装

unzip workspace-extension-sdk-0.1.0.zip # 两个包已预构建 dist(main=dist/index.js, types=dist/index.d.ts) npm i ./workspace-extension-sdk/packages/verify # 后端 npm i ./workspace-extension-sdk/packages/browser # 前端
                      
                      unzip workspace-extension-sdk-0.1.0.zip
# 两个包已预构建 dist(main=dist/index.js, types=dist/index.d.ts)
npm i ./workspace-extension-sdk/packages/verify   # 后端
npm i ./workspace-extension-sdk/packages/browser  # 前端

                    
此代码块在浮窗中显示

如需自行构建 / 跑测试:

cd workspace-extension-sdk npm install npm run build # tsc → 各包 dist npm test # node --test(零外部测试依赖,需 Node ≥ 22.6 以直跑 .ts) npm run type-check # tsc --noEmit
                      
                      cd workspace-extension-sdk
npm install
npm run build       # tsc → 各包 dist
npm test            # node --test(零外部测试依赖,需 Node ≥ 22.6 以直跑 .ts)
npm run type-check  # tsc --noEmit

                    
此代码块在浮窗中显示