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

                    
此代碼塊在浮窗中顯示