npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@seaverse/auth-sdk

v0.3.8

Published

SDK for SeaVerse Backend API

Downloads

2,805

Readme

@seaverse/auth-sdk

SeaVerse Backend API 客户端 SDK - 提供完整的认证、容器管理、技能市场等功能

npm version License: MIT

功能特性

  • 🔐 用户认证 - 注册、登录、登出、密码重置
  • 🌐 OAuth登录 - Google、Discord、GitHub 第三方登录
  • 🎨 登录UI组件 - 开箱即用的精美登录弹窗
  • Toast 通知 - 现代化玻璃态提示,CSS 自动注入
  • 🌍 多环境支持 - Production、Staging、Development、Local
  • TypeScript - 完整的类型定义
  • 🔧 认证集成 - 内置Auth、Hooks系统支持
  • 🔄 响应格式兼容 - 自动兼容多种API响应格式

安装

npm install @seaverse/auth-sdk
# 或
pnpm add @seaverse/auth-sdk

核心概念

App ID 和多租户架构

重要: 从 v0.2.0 开始,appId 是初始化 SDK 时的必需参数

什么是 App ID?

每个应用都有唯一的 app_id

  • app_id = "your app id"

多租户隔离

  • 用户数据按 app_id 隔离
  • 同一邮箱可在不同应用中注册,使用不同密码
  • 每个应用拥有独立的用户池

X-App-ID 请求头

SDK 会自动在每个请求的请求头中添加 X-App-ID,无需手动设置:

const client = new SeaVerseBackendAPIClient({
  appId: 'game-abc123',  // SDK 自动将此值添加到所有请求的 X-App-ID header
});

// 所有 API 调用都会自动携带 X-App-ID: game-abc123
await client.login({ email, password });
await client.getCurrentUser();

快速开始

1. 基本使用

import { SeaVerseBackendAPIClient } from '@seaverse/auth-sdk';

// 方式1: SeaVerse 平台应用(自动检测环境)
const client = new SeaVerseBackendAPIClient({
  appId: 'your app id', // 必需:应用ID
});

// 方式2: 第三方应用(指定环境)
const client = new SeaVerseBackendAPIClient({
  appId: 'your app id',        // 必需:您的应用ID
  environment: 'production',   // 'production' | 'staging' | 'development' | 'local'
});

// 方式3: 自定义URL
const client = new SeaVerseBackendAPIClient({
  appId: 'your app id',             // 必需:您的应用ID
  baseURL: 'https://custom-api.example.com',
});

// 方式4: 启用请求重试(默认禁用)
const client = new SeaVerseBackendAPIClient({
  appId: 'your app id',
  retryOptions: {
    maxRetries: 3,                  // 最多重试 3 次
    retryDelay: 1000,               // 初始延迟 1000ms,每次重试延迟加倍
    retryStatusCodes: [408, 429, 500, 502, 503, 504],  // 这些状态码会触发重试
  },
});

// 健康检查
const health = await client.getHealth();
console.log('Health:', health);

2. 用户认证

// 注册新用户
const registerResult = await client.register({
  email: '[email protected]',
  password: 'SecurePassword123',
  username: 'johndoe',              // 可选,未提供则从邮箱自动生成
  invitation_code: 'INVITE123',     // 可选
  frontend_url: 'https://mygame.com/verify',  // 可选,邮箱验证链接的前端URL,默认为 window.location.href
});

// 检查注册结果
if (registerResult.success) {
  console.log('注册成功:', registerResult);
} else if (registerResult.code === 'ACCOUNT_EXISTS') {
  console.log('账户已存在,请直接登录');
  console.log('错误详情:', registerResult.details);
}

// 登录
const loginResult = await client.login({
  email: '[email protected]',
  password: 'SecurePassword123',
});

// 保存token
localStorage.setItem('token', loginResult.token);

// ⚠️ 注意:邀请码自动跳转
// 如果服务器返回 INVITE_CODE_REQUIRED 错误且包含 redirectUrl,
// SDK 会自动将用户重定向到该 URL(通常是邀请码输入页面)
// 无需额外处理,页面会自动跳转

// 获取当前用户信息
const user = await client.getCurrentUser();
console.log('User:', user);
console.log('App ID:', user.app_id);           // 多租户应用ID
console.log('Email verified:', user.email_verified);

// 登出
await client.logout();

// 忘记密码
await client.forgotPassword({
  email: '[email protected]',
  frontend_url: 'https://mygame.com/',  // 可选,默认为 window.location.href
});

// 重置密码
await client.resetPassword({
  token: 'reset-token-from-email',
  new_password: 'NewSecurePassword123',
});

3. OAuth 第三方登录 (Backend Proxy Mode)

SDK 使用 Backend Proxy Mode,Client Secret 永不暴露给前端,安全性更高。

优势:

  • ✅ Client Secret 从不暴露给前端
  • ✅ 支持任意开发者域名(无需在 OAuth 平台配置)
  • ✅ 内置 CSRF 防护
  • ✅ 零配置,开箱即用

工作流程:

  1. 前端调用 {provider}Authorize() 获取 OAuth URL
  2. 前端重定向用户到 OAuth 提供商
  3. 用户授权后,OAuth 提供商回调到固定的 account-hub URL
  4. account-hub 处理 OAuth,创建 JWT token
  5. account-hub 302 重定向到 return_url?token=xxx
  6. 前端从 URL 提取 token 并存储

使用示例

方式1:使用默认 return_url(当前页面)

// Google 登录
const { authorize_url } = await client.googleAuthorize();
window.location.href = authorize_url;

// Discord 登录
const { authorize_url } = await client.discordAuthorize();
window.location.href = authorize_url;

// GitHub 登录
const { authorize_url } = await client.githubAuthorize();
window.location.href = authorize_url;

方式2:自定义 return_url

// 登录后跳转到 dashboard
const { authorize_url } = await client.googleAuthorize({
  return_url: 'https://mygame.com/dashboard'
});
window.location.href = authorize_url;

在回调页面提取 token:

// URL: https://mygame.com/?token=eyJhbGc...
const token = new URLSearchParams(window.location.search).get('token');
if (token) {
  localStorage.setItem('token', token);
  // 登录成功,跳转或更新 UI
}

OAuth 账号解绑

// 解绑 Google 账号
await client.unlinkGoogle();

// 解绑 Discord 账号
await client.unlinkDiscord();

// 解绑 GitHub 账号
await client.unlinkGithub();

4. 使用登录UI组件

SDK 提供精美的登录弹窗组件,支持深色和浅色两种主题:

主题对比

| 主题 | 设计风格 | 适用场景 | |------|---------|---------| | Dark 🌙 | 动态网格渐变 + 玻璃态效果 | 科技感产品、游戏平台、深色界面应用 | | Light ☀️ | 提升的卡片设计 + 柔和阴影 | 商务应用、内容平台、浅色界面应用 |

基础用法

import { SeaVerseBackendAPIClient, AuthModal } from '@seaverse/auth-sdk';
import '@seaverse/auth-sdk/auth-modal.css'; // 导入样式

const client = new SeaVerseBackendAPIClient({
  appId: 'your app id',         // 必需:您的应用ID
  environment: 'production',
});

// 创建登录弹窗
const authModal = new AuthModal({
  client,
  theme: 'dark', // 'dark' | 'light' - 默认为 'dark'

  // 登录成功回调
  onLoginSuccess: (token, user) => {
    localStorage.setItem('token', token);
    console.log('登录成功:', user);
  },

  // 注册成功回调
  onSignupSuccess: (token, user) => {
    localStorage.setItem('token', token);
    console.log('注册成功:', user);
  },

  // 邀请码需求回调(可选)
  onInviteCodeRequired: (userId, email) => {
    console.log('需要邀请码激活账户:', userId, email);
    // AuthModal 会自动显示邀请码输入界面
  },

  // 申请邀请码成功回调(可选)
  onApplyInviteSuccess: (applicationId, email) => {
    console.log('邀请码申请已提交:', applicationId, email);
    // 可以在这里添加自定义逻辑,如显示提示信息
  },

  // 错误回调
  onError: (error) => {
    console.error('认证错误:', error.message);
  },

  // OAuth 配置(可选)
  returnUrl: 'https://mygame.com/',  // OAuth 登录后返回的 URL,可选,默认为 window.location.href
  enableOAuth: {
    google: true,   // 启用 Google 登录
    discord: true,  // 启用 Discord 登录
    github: true,   // 启用 GitHub 登录
  },
});

// 显示登录界面
authModal.show('login');

// 显示注册界面
authModal.show('signup');

// 隐藏弹窗
authModal.hide();

// 销毁弹窗
authModal.destroy();

✨ 新特性:自动 Toast 通知

AuthModal 内置了现代化的 Toast 通知系统,无需额外配置:

// Toast 会自动显示,CSS 自动注入
// - 注册成功 → 绿色成功提示
// - 账号已存在 → 黄色警告提示
// - 登录失败 → 红色错误提示
// - 重置密码 → 蓝色信息提示

// 你也可以单独使用 Toast(CSS 自动注入)
import { Toast } from '@seaverse/auth-sdk';

Toast.success('操作成功', '数据已保存');
Toast.error('操作失败', '请稍后重试');
Toast.warning('注意', '账号已存在');
Toast.info('提示', '邮件已发送');

重置密码流程

AuthModal 支持完整的密码重置流程:

  1. 用户触发忘记密码:在登录界面点击 "Forgot Password?" 链接
  2. 发送重置邮件:输入邮箱后,系统发送带有 reset_token 的重置链接
  3. 自动唤起重置弹窗:用户点击邮件中的链接返回网站时,AuthModal 会自动检测 URL 中的 reset_token 参数并显示重置密码表单
  4. 设置新密码:用户输入并确认新密码后提交
  5. 自动清理 URL:重置成功后自动清除 URL 中的 reset_token 参数

整个流程无需额外代码,AuthModal 会自动处理:

// 1. 初始化 AuthModal(只需一次)
const authModal = new AuthModal({
  client,
  // ... 其他配置
});

// 2. 用户点击邮件中的重置链接后,AuthModal 会自动:
//    - 检测 URL 中的 ?reset_token=xxx 参数
//    - 显示重置密码表单
//    - 用户提交新密码
//    - 调用 client.resetPassword() API
//    - 清理 URL 中的 reset_token 参数
//    - 显示成功消息

OAuth 配置说明

enableOAuth 参数是完全可选的

  • 如果不提供 enableOAuth,则不会显示任何第三方登录按钮
  • 如果部分配置(如只启用 Google),则只显示已启用的按钮
  • 如果完整配置所有平台,则显示所有第三方登录按钮

配置字段说明

  • returnUrl可选 - OAuth 登录后返回的 URL,不填则默认为 window.location.href
  • enableOAuth.google:是否启用 Google 登录
  • enableOAuth.discord:是否启用 Discord 登录
  • enableOAuth.github:是否启用 GitHub 登录
// 示例1:无OAuth按钮
const authModal1 = new AuthModal({
  client,
  theme: 'dark',
  // 不传 enableOAuth,不显示任何OAuth按钮
});

// 示例2:只显示Google登录
const authModal2 = new AuthModal({
  client,
  theme: 'light',
  returnUrl: 'https://mygame.com/dashboard',
  enableOAuth: {
    google: true,
    // Discord 和 GitHub 未启用,不会显示这些按钮
  },
});

// 示例3:显示所有OAuth按钮
const authModal3 = new AuthModal({
  client,
  theme: 'dark',
  enableOAuth: {
    google: true,
    discord: true,
    github: true,
  },
});

处理 OAuth 回调

在 Backend Proxy Mode 下,OAuth 登录后会重定向到 returnUrl?token=xxx。在页面加载时检查并处理token:

// 在页面加载时自动处理 OAuth 回调
const result = AuthModal.handleOAuthCallback({
  client,
  onLoginSuccess: (token) => {
    localStorage.setItem('token', token);
    console.log('OAuth 登录成功');

    // 现在可以直接调用需要认证的接口
    // handleOAuthCallback 已自动调用 client.setToken()
    client.getCurrentUser()
      .then(user => console.log('用户信息:', user));
  },
});

if (result) {
  console.log('处理了 OAuth 回调,token:', result.token);
}

重要说明

  • handleOAuthCallback() 会自动调用 client.setToken(token) 来更新 client 的认证配置
  • 这意味着在 onLoginSuccess 回调之后,所有需要认证的 API(如 getCurrentUser()logout() 等)都会自动带上 Authorization header

手动设置 Token

如果你不使用 AuthModal.handleOAuthCallback(),也可以手动设置 token:

// 从 URL 提取 token
const token = new URLSearchParams(window.location.search).get('token');
if (token) {
  // 手动设置 token
  client.setToken(token);
  localStorage.setItem('token', token);

  // 现在可以调用需要认证的接口
  const user = await client.getCurrentUser();
}

5. 容器管理

// 列出所有容器
const containers = await client.listContainers();

// 注册新容器
const result = await client.registerContainer({
  containerId: 'container-123',
  metadata: {
    version: '1.0.0',
    capabilities: ['skill-execution'],
  },
});

// 获取容器信息
const container = await client.getContainer({
  containerId: 'container-123',
});

// 容器心跳
await client.containerHeartbeat({
  containerId: 'container-123',
  status: 'healthy',
});

// 注销容器
await client.unregisterContainer({
  containerId: 'container-123',
});

// 获取容器统计
const stats = await client.getContainerStats();

6. 技能市场

// 列出市场技能
const skills = await client.listMarketplaceSkills({
  category: 'productivity',
  page: 1,
  pageSize: 20,
});

// 获取技能详情
const skill = await client.getMarketplaceSkill({
  skillId: 'skill-123',
});

// 安装技能
await client.installSkill({
  skillId: 'skill-123',
});

// 列出已安装的技能
const userSkills = await client.listUserSkills();

// 卸载技能
await client.uninstallSkill({
  skillId: 'skill-123',
});

7. 邀请码管理

// 申请邀请码(当用户没有邀请码时)
const application = await client.applyInvite({
  email: '[email protected]',
  reason: 'I want to join this amazing platform to build innovative applications and connect with the community.'
});

if (application.success) {
  console.log('申请已提交:', application.data);
  console.log('申请ID:', application.data.id);
  console.log('状态:', application.data.status); // 'pending'
} else {
  // 处理错误
  if (application.code === 'APPLICATION_DUPLICATE') {
    console.log('您在过去24小时内已提交过申请');
  } else {
    console.error('申请失败:', application.error);
  }
}

// 列出我的邀请码
const invites = await client.listInvites({
  status: 'active',
  page: 1,
  page_size: 20,
});
console.log('我的邀请码:', invites.data.invites);

// 获取邀请码统计
const stats = await client.getInviteStats();
console.log('总邀请码数:', stats.data.total_codes);
console.log('活跃邀请码:', stats.data.active_codes);
console.log('总使用次数:', stats.data.total_uses);

// 获取邀请码详情
const invite = await client.getInvite('inv_abc123');
console.log('邀请码:', invite.data.code);
console.log('已使用:', invite.data.used_count);
console.log('最大使用次数:', invite.data.max_uses);

// 获取邀请码使用记录
const usages = await client.getInviteUsages('inv_abc123', {
  page: 1,
  page_size: 20,
});
console.log('使用记录:', usages.data.usages);

8. 邮箱验证与邀请码绑定

邮箱验证(自动登录)

用户注册后会收到验证邮件,邮件中包含验证链接,格式为:frontend_url?verify_token=xxx

方式一:使用 AuthModal 自动处理(推荐)

import { AuthModal } from '@seaverse/auth-sdk';

// 创建 AuthModal 实例
const modal = new AuthModal({
  client,
  onLoginSuccess: (token, user) => {
    localStorage.setItem('token', token);
    console.log('邮箱验证并登录成功:', user);
  },
  onError: (error) => {
    console.error('邮箱验证失败:', error);
  }
});

// AuthModal 会自动检测 URL 中的 verify_token 参数
// 检测到后会自动:
// 1. 调用 verifyEmail() API 验证邮箱
// 2. 获取返回的 JWT token 并自动登录
// 3. 触发 onLoginSuccess 回调
// 4. 清理 URL 中的 verify_token 参数
// 5. 显示成功消息

调试提示

如果邮箱验证出现问题,请检查浏览器控制台日志:

// 正常情况应该看到:
[AuthModal] Detected verify_token, starting email verification...
[AuthModal] Email verification successful: { id: "xxx", email: "[email protected]", ... }

// 如果验证失败,会看到:
[AuthModal] Email verification failed: Error: ...

方式二:手动处理邮箱验证

// 验证邮箱(从邮件链接中获取 verify_token)
const urlParams = new URLSearchParams(window.location.search);
const verifyToken = urlParams.get('verify_token');

if (verifyToken) {
  const result = await client.verifyEmail(verifyToken);

  // 自动登录:保存返回的 token
  localStorage.setItem('token', result.data.token);
  localStorage.setItem('refreshToken', result.data.refreshToken);

  console.log('邮箱验证成功,已自动登录:', result.data.user);

  // 重定向到主页
  window.location.href = '/';
}

邀请码绑定(账户激活)

当使用外部邮箱注册或 OAuth 登录但未提供邀请码时,会创建临时账户并需要后续绑定邀请码激活。

申请邀请码功能

如果用户没有邀请码,AuthModal 提供了内置的申请功能:

  1. 在邀请码输入界面,用户可以点击 "Don't have an invitation code? Apply for one" 链接
  2. 自动跳转到申请邀请码表单
  3. 用户填写邮箱和申请原因(10-500字符)
  4. 提交后会调用 applyInvite() API,后台审核通过后会通过邮件发送邀请码

自动跳转机制:

  • login() 返回 INVITE_CODE_REQUIRED 错误且包含 redirectUrl 时,SDK 会自动将页面重定向到该 URL
  • redirectUrl 通常包含 error_code=INVITE_CODE_REQUIRED&user_id=xxx&email=xxx 参数
  • 无需手动处理跳转逻辑,SDK 会自动完成

对于其他场景(如 OAuth 登录后的重定向),后端会直接重定向到 frontend_url?error_code=INVITE_CODE_REQUIRED&user_id=xxx&email=xxx

方式一:使用 AuthModal 自动处理(推荐)

import { AuthModal } from '@seaverse/auth-sdk';

// 创建 AuthModal 实例
const modal = new AuthModal({
  client,
  onLoginSuccess: (token, user) => {
    localStorage.setItem('token', token);
    console.log('登录成功:', user);
  },
  onInviteCodeRequired: (userId, email) => {
    // 可选:当需要邀请码时的自定义处理
    console.log('需要邀请码激活账户:', userId, email);
  }
});

// AuthModal 会自动检测 URL 中的以下参数组合:
// - error_code=INVITE_CODE_REQUIRED
// - user_id 或 temp_user_id(用户ID)
// - email(可选,用户邮箱)
//
// 检测到后会自动:
// 1. 显示邀请码输入界面
// 2. 用户输入邀请码后调用 bindInviteCode() API
// 3. 激活成功后自动登录(保存 token)
// 4. 清理 URL 中的参数

调试提示

如果邀请码弹窗没有出现,请检查浏览器控制台是否有以下日志:

// 正常情况应该看到:
[AuthModal] Detected INVITE_CODE_REQUIRED: {
  errorCode: "INVITE_CODE_REQUIRED",
  userId: "xxx",
  tempUserId: null,
  email: "[email protected]",
  fullURL: "http://localhost:8001/?error_code=INVITE_CODE_REQUIRED&user_id=xxx&email=xxx"
}

// 如果 user_id 缺失,会看到错误提示:
[AuthModal] Missing user_id in URL parameters.
// 并弹出 alert 显示完整 URL,方便排查后端重定向问题

方式二:手动处理邀请码绑定

// 1. 检查 URL 中是否需要邀请码
const urlParams = new URLSearchParams(window.location.search);
const errorCode = urlParams.get('error_code');
const userId = urlParams.get('user_id');

if (errorCode === 'INVITE_CODE_REQUIRED' && userId) {
  // 2. 显示邀请码输入界面(自定义 UI)
  const inviteCode = await showInviteCodeInput(); // 你的自定义UI

  // 3. 绑定邀请码
  const result = await client.bindInviteCode({
    user_id: userId,
    invite_code: inviteCode
  });

  // 4. 激活成功,自动登录
  localStorage.setItem('token', result.data.token);
  localStorage.setItem('refreshToken', result.data.refreshToken);
  console.log('账户激活成功:', result.data.user);

  // 5. 重定向到主页
  window.location.href = '/';
}

方式三:使用静态方法处理

import { AuthModal } from '@seaverse/auth-sdk';

// AuthModal 提供静态方法处理邀请码场景
const inviteCodeInfo = AuthModal.handleInviteCodeRequired(
  { client },
  (userId, email) => {
    // 自定义处理逻辑
    const code = prompt(`请输入邀请码激活账户 (${email}):`);
    if (code) {
      client.bindInviteCode({ user_id: userId, invite_code: code })
        .then(res => {
          localStorage.setItem('token', res.data.token);
          window.location.reload();
        });
    }
  }
);

9. 其他功能

// 获取API Service Token
const apiToken = await client.getApiServiceToken();

// 获取对话状态
const status = await client.getConversationStatus({
  conversationId: 'conv-123',
});

// 获取语音Token
const speechToken = await client.getSpeechToken();

高级配置

自定义认证

import { AuthFactory } from '@seaverse/auth-sdk';

const client = new SeaVerseBackendAPIClient({
  appId: 'your app id',         // 必需:应用ID
  environment: 'production',

  // 使用JWT认证
  auth: AuthFactory.create({
    type: 'jwt',
    credentials: {
      type: 'jwt',
      token: localStorage.getItem('token'),
    },
  }),
});

自定义Hooks

import { BuiltInHooks } from '@seaverse/auth-sdk';

const client = new SeaVerseBackendAPIClient({
  appId: 'your app id',         // 必需:应用ID
  environment: 'production',

  hooks: {
    hooks: [
      // 日志Hook
      BuiltInHooks.createLoggerHook({
        logLevel: 'debug',
        logRequestBody: true,
        logResponseBody: true,
      }),

      // 请求ID Hook
      BuiltInHooks.createRequestIdHook(),

      // 自定义Hook
      {
        type: 'beforeRequest',
        name: 'custom-hook',
        priority: 100,
        handler: async (context) => {
          console.log('Before request:', context.config.url);
        },
      },
    ],
  },
});

请求重试配置

SDK 支持自定义 HTTP 请求重试策略。默认情况下重试功能是禁用的(maxRetries: 0),以确保请求的可预测性。

默认行为(禁用重试)

const client = new SeaVerseBackendAPIClient({
  appId: 'your app id',
  // retryOptions 未设置,默认不重试
});

// 如果请求失败,会立即返回错误,不会重试

启用基础重试

import { SeaVerseBackendAPIClient } from '@seaverse/auth-sdk';

const client = new SeaVerseBackendAPIClient({
  appId: 'your app id',
  retryOptions: {
    maxRetries: 3,        // 最多重试 3 次
    retryDelay: 1000,     // 初始延迟 1000ms (1秒)
    // 默认会对以下状态码重试:[408, 429, 500, 502, 503, 504]
  },
});

重试策略说明

  • 采用指数退避算法:第1次等待1秒,第2次等待2秒,第3次等待4秒
  • 自动重试的 HTTP 状态码:
    • 408 - Request Timeout(请求超时)
    • 429 - Too Many Requests(限流)
    • 500 - Internal Server Error(服务器内部错误)
    • 502 - Bad Gateway(网关错误)
    • 503 - Service Unavailable(服务不可用)
    • 504 - Gateway Timeout(网关超时)
  • 网络错误(无响应)也会触发重试

自定义重试状态码

const client = new SeaVerseBackendAPIClient({
  appId: 'your app id',
  retryOptions: {
    maxRetries: 5,
    retryDelay: 2000,
    retryStatusCodes: [503, 504],  // 只对 503 和 504 重试
  },
});

自定义重试逻辑

import type { RetryOptions } from '@seaverse/auth-sdk';

const retryOptions: RetryOptions = {
  maxRetries: 3,
  retryDelay: 1000,
  // 自定义判断逻辑:只对特定错误重试
  shouldRetry: (error) => {
    // 只对服务不可用错误重试
    if (error.response?.status === 503) {
      return true;
    }
    // 对没有响应的网络错误重试
    if (!error.response) {
      return true;
    }
    return false;
  },
};

const client = new SeaVerseBackendAPIClient({
  appId: 'your app id',
  retryOptions,
});

RetryOptions 类型定义

interface RetryOptions {
  maxRetries?: number;           // 最大重试次数,默认 0(禁用)
  retryDelay?: number;           // 初始重试延迟(毫秒),默认 1000
  retryStatusCodes?: number[];   // 触发重试的状态码列表
  shouldRetry?: (error: AxiosError) => boolean;  // 自定义重试判断函数
}

使用建议

  • ⚠️ 生产环境建议禁用重试(默认行为),避免在业务逻辑错误时产生重复请求
  • ✅ 仅在网络不稳定的场景启用重试,如移动端应用、弱网环境
  • ✅ 确保后端 API 支持幂等性操作,避免重试导致的副作用
  • ✅ 对于关键业务(如支付),建议使用自定义 shouldRetry 仔细控制重试逻辑

环境配置

SDK支持以下环境:

| 环境 | 描述 | BaseURL | |------|------|---------| | production | 生产环境 | https://account-hub.seaverse.ai | | staging | 测试环境 | https://api.staging.seaverse.dev | | development | 开发环境 | https://api.dev.seaverse.dev | | local | 本地环境 | http://localhost:3000 |

自动检测规则:

  • *.seaverse.com → production
  • *.staging.seaverse.dev → staging
  • *.dev.seaverse.dev → development
  • localhost → local

API 参考

认证相关

| 方法 | 参数 | 返回值 | 说明 | |------|------|--------|------| | register() | { email, password, username?, invitation_code?, frontend_url? } | RegisterResponse | 注册新用户,frontend_url 为邮箱验证链接的前端URL,默认为 window.location.href | | login() | { email, password, frontend_url? } | LoginResponse | 用户登录,frontend_url 用于未验证邮箱时发送验证邮件,默认为 https://seaverse.ai/。⚠️ 如果返回 INVITE_CODE_REQUIRED 且包含 redirectUrl,会自动跳转 | | getCurrentUser() | - | User | 获取当前用户 | | logout() | - | SuccessResponse | 登出 | | verifyEmail() | verifyToken: string | EmailVerificationResponse | 验证邮箱并返回自动登录 token | | bindInviteCode() | { user_id, invite_code } | BindInviteCodeResponse | 绑定邀请码激活临时账户并自动登录 | | forgotPassword() | { email, frontend_url? } | SuccessResponse | 忘记密码,frontend_url 默认为 window.location.href | | resetPassword() | { token, new_password } | SuccessResponse | 重置密码 | | setToken() | token: string | void | 设置认证 token(OAuth 登录后使用) | | getApiServiceToken() | - | ApiServiceTokenResponse | 获取API Token |

注册流程说明

register() 方法支持三种注册流程,SDK 会根据后端响应自动处理:

流程 1: 立即激活(默认)

const response = await client.register({ email, password });
// response.success === true
// response.requiresEmailVerification === undefined (或 false)
// response.requiresInvitationCode === undefined (或 false)
// → SDK 自动调用 login() 并触发 onSignupSuccess 回调

流程 2: 需要邮箱验证

const response = await client.register({ email, password });
// response.success === true
// response.requiresEmailVerification === true
// → SDK 显示 Toast 提示用户检查邮箱
// → 不会自动调用 login(),用户需要点击邮件中的验证链接

流程 3: 需要邀请码激活

const response = await client.register({ email, password });
// response.success === true
// response.requiresInvitationCode === true
// response.tempUserId === "temp_xxx"
// → SDK 显示邀请码输入表单
// → 不会自动调用 login(),用户需要输入邀请码

重要提示

  • AuthModal 会自动处理这三种流程,无需手动判断
  • 只有在无需验证或激活的情况下,才会自动调用 login()
  • 这避免了在邮箱未验证或账户未激活时产生不必要的登录请求

OAuth相关

| 方法 | 参数 | 返回值 | 说明 | |------|------|--------|------| | googleAuthorize() | { return_url? } | OAuthAuthorizeResponse | Google OAuth 授权 URL | | discordAuthorize() | { return_url? } | OAuthAuthorizeResponse | Discord OAuth 授权 URL | | githubAuthorize() | { return_url? } | OAuthAuthorizeResponse | GitHub OAuth 授权 URL | | unlinkGoogle() | - | SuccessResponse | 解绑Google | | unlinkDiscord() | - | SuccessResponse | 解绑Discord | | unlinkGithub() | - | SuccessResponse | 解绑GitHub |

容器管理

| 方法 | 参数 | 返回值 | 说明 | |------|------|--------|------| | listContainers() | - | ContainerListResponse | 列出容器 | | registerContainer() | { containerId, metadata } | SuccessResponse | 注册容器 | | getContainer() | { containerId } | Container | 获取容器信息 | | unregisterContainer() | { containerId } | SuccessResponse | 注销容器 | | containerHeartbeat() | { containerId, status } | SuccessResponse | 容器心跳 | | getContainerStats() | - | ContainerStatsResponse | 容器统计 |

技能市场

| 方法 | 参数 | 返回值 | 说明 | |------|------|--------|------| | listMarketplaceSkills() | { category?, page?, pageSize? } | MarketplaceSkillsListResponse | 列出市场技能 | | getMarketplaceSkill() | { skillId } | MarketplaceSkill | 获取技能详情 | | installSkill() | { skillId } | SuccessResponse | 安装技能 | | listUserSkills() | - | UserInstalledSkillsListResponse | 列出已安装技能 | | uninstallSkill() | { skillId } | SuccessResponse | 卸载技能 |

邀请码管理

| 方法 | 参数 | 返回值 | 说明 | |------|------|--------|------| | applyInvite() | { email, reason } | ApplyInviteResponse | 申请邀请码(reason 需10-500字符)| | listInvites() | { page?, page_size?, status? } | ListInvitesResponse | 列出我的邀请码 | | getInviteStats() | - | InviteStatsResponse | 获取邀请码统计 | | getInvite() | inviteId: string | InviteCodeDetailResponse | 获取邀请码详情 | | getInviteUsages() | inviteId: string, { page?, page_size? } | ListInviteUsagesResponse | 获取邀请码使用记录 |

其他

| 方法 | 参数 | 返回值 | 说明 | |------|------|--------|------| | getHealth() | - | HealthResponse | 健康检查 | | getConversationStatus() | { conversationId } | ConversationStatusResponse | 获取对话状态 | | getSpeechToken() | - | SpeechTokenResponse | 获取语音Token |

响应格式兼容性

自动响应解包

从 v0.2.5 开始,SDK 自动兼容两种API响应格式,无需手动处理:

格式 1: 包装格式(推荐)

{
  "data": {
    "token": "eyJhbGc...",
    "user": { ... }
  },
  "success": true
}

格式 2: 扁平格式(向后兼容)

{
  "token": "eyJhbGc...",
  "user": { ... }
}

SDK 会自动检测响应格式并提取正确的数据:

// 无论后端返回哪种格式,以下代码都能正常工作
const loginResult = await client.login({
  email: '[email protected]',
  password: 'password123',
});

console.log(loginResult.token); // ✅ 始终能正确获取 token
console.log(loginResult.user);  // ✅ 始终能正确获取 user

受影响的方法

以下方法已实现自动响应解包:

  • login() - 登录接口
  • register() - 注册接口
  • getCurrentUser() - 获取当前用户

实现原理

SDK 内部通过以下逻辑自动处理响应格式:

const response = await httpClient.request(config);
const responseData = response.data;

// 检测并解包
if (responseData.data && typeof responseData.data === 'object') {
  // 包装格式: 提取 data 字段
  return responseData.data;
}
// 扁平格式: 直接返回
return responseData;

这意味着:

  • 🔄 后端格式变更无需前端修改 - 后端可以自由调整响应格式
  • 🔧 渐进式迁移 - 可以逐步将不同接口迁移到新格式
  • 向后兼容 - 旧代码无需修改即可继续工作

错误处理

错误响应格式

所有 API 错误都遵循统一的响应格式:

interface ApiError {
  success: false;           // 错误时始终为 false
  error: string;            // 人类可读的错误消息
  code?: string;            // 机器可读的错误码
  details?: any;            // 额外的错误详情
}

错误码

SDK 提供了标准的错误码枚举:

import { ErrorCode } from '@seaverse/auth-sdk';

// 账户相关错误
ErrorCode.ACCOUNT_EXISTS         // 账户已存在
ErrorCode.ACCOUNT_NOT_FOUND      // 账户不存在
ErrorCode.ACCOUNT_SUSPENDED      // 账户已被暂停
ErrorCode.INVALID_CREDENTIALS    // 登录凭证无效
ErrorCode.EMAIL_NOT_VERIFIED     // 邮箱未验证

// 验证相关错误
ErrorCode.INVALID_EMAIL          // 无效的邮箱地址
ErrorCode.INVALID_PASSWORD       // 无效的密码
ErrorCode.PASSWORD_TOO_WEAK      // 密码强度不够

// 邀请码相关错误
ErrorCode.INVALID_INVITATION_CODE // 无效的邀请码
ErrorCode.INVITATION_REQUIRED     // 需要邀请码
ErrorCode.INVITE_CODE_REQUIRED    // 需要邀请码(会自动跳转到 redirectUrl)

// Token 相关错误
ErrorCode.INVALID_TOKEN          // 无效的 token
ErrorCode.TOKEN_EXPIRED          // Token 已过期

// 内部错误
ErrorCode.INTERNAL_ERROR         // 服务器内部错误

错误处理最佳实践

1. 注册时处理重复用户

由于后端在账户已存在时返回 200 OK(成功响应),所以前端不会抛出异常,而是在响应体中包含错误信息。

import { ErrorCode } from '@seaverse/auth-sdk';

const result = await client.register({
  email: '[email protected]',
  password: 'password123',
});

// 检查响应中的 success 字段
if (result.success) {
  console.log('注册成功:', result);
  // 进行后续操作,如自动登录
} else if (result.code === ErrorCode.ACCOUNT_EXISTS) {
  // 账户已存在,提示用户
  const { email, app_id } = result.details;
  console.log(`账户 ${email} 已存在于应用 ${app_id} 中`);

  // 显示友好的提示信息
  alert('This email is already registered. Please login instead.');

  // 或者引导用户去登录
  showLoginModal();
} else {
  // 处理其他错误
  console.error('注册失败:', result.error);
}

2. 登录时处理各种错误

try {
  const result = await client.login({
    email: '[email protected]',
    password: 'wrong-password',
  });
  console.log('登录成功:', result);
} catch (error) {
  const errorCode = error.response?.data?.code;

  switch (errorCode) {
    case ErrorCode.INVALID_CREDENTIALS:
      showError('用户名或密码错误');
      break;
    case ErrorCode.EMAIL_NOT_VERIFIED:
      showError('请先验证您的邮箱');
      showResendVerificationButton();
      break;
    case ErrorCode.ACCOUNT_SUSPENDED:
      showError('您的账户已被暂停,请联系管理员');
      break;
    default:
      showError('登录失败,请稍后重试');
  }
}

3. 通用错误处理函数

import { ErrorCode } from '@seaverse/auth-sdk';

function handleApiError(error: any) {
  const apiError = error.response?.data;

  if (!apiError) {
    // 网络错误或其他未知错误
    return {
      title: '网络错误',
      message: '请检查您的网络连接',
    };
  }

  // 根据错误码返回用户友好的消息
  const errorMessages: Record<string, { title: string; message: string }> = {
    [ErrorCode.ACCOUNT_EXISTS]: {
      title: '账户已存在',
      message: '该邮箱已注册,请直接登录',
    },
    [ErrorCode.INVALID_CREDENTIALS]: {
      title: '登录失败',
      message: '用户名或密码错误',
    },
    [ErrorCode.EMAIL_NOT_VERIFIED]: {
      title: '邮箱未验证',
      message: '请先验证您的邮箱地址',
    },
    [ErrorCode.INVALID_INVITATION_CODE]: {
      title: '邀请码无效',
      message: '请检查您的邀请码是否正确',
    },
    [ErrorCode.TOKEN_EXPIRED]: {
      title: '登录已过期',
      message: '请重新登录',
    },
  };

  return errorMessages[apiError.code] || {
    title: '操作失败',
    message: apiError.error || '发生未知错误',
  };
}

// 使用示例
try {
  await client.register({ email, password });
} catch (error) {
  const { title, message } = handleApiError(error);
  showNotification(title, message);
}

4. TypeScript 类型安全的错误处理

import { ErrorCode, models } from '@seaverse/auth-sdk';

async function safeRegister(email: string, password: string) {
  // Register API now returns 200 OK for both success and account exists cases
  const result = await client.register({ email, password });

  if (result.success) {
    return {
      success: true,
      data: result,
    };
  } else if (result.code === ErrorCode.ACCOUNT_EXISTS) {
    // TypeScript knows the type of details
    const details = result.details as models.AccountExistsErrorDetails;
    return {
      success: false,
      error: 'ACCOUNT_EXISTS',
      email: details.email,
      appId: details.app_id,
    };
  } else {
    return {
      success: false,
      error: result.error || 'Unknown error',
    };
  }
}

// Usage
const registerResult = await safeRegister('[email protected]', 'password123');
if (registerResult.success) {
  console.log('Registration successful');
} else if (registerResult.error === 'ACCOUNT_EXISTS') {
  console.log(`Account already exists: ${registerResult.email}`);
}

HTTP 状态码对照

| HTTP状态码 | 错误码示例 | 说明 | |-----------|----------|------| | 200 OK | ACCOUNT_EXISTS | 账户已存在(业务错误但返回成功响应) | | 400 Bad Request | INVALID_EMAIL, PASSWORD_TOO_WEAK | 请求参数无效 | | 401 Unauthorized | INVALID_CREDENTIALS, TOKEN_EXPIRED | 认证失败 | | 403 Forbidden | EMAIL_NOT_VERIFIED, ACCOUNT_SUSPENDED | 权限不足 | | 500 Internal Server Error | INTERNAL_ERROR | 服务器内部错误 |

注意:对于注册接口,账户已存在的情况会返回 200 OK,但在响应体中 success: falsecode: "ACCOUNT_EXISTS"。这样设计是为了前端能够更容易地处理这种常见的业务场景。

类型定义

// 用户信息
interface User {
  id?: string;
  app_id?: string | null;           // 应用ID(多租户支持)
  email?: string;
  username?: string;
  created_at?: number;               // Unix时间戳
  email_verified?: boolean;          // 邮箱验证状态
  google_id?: string | null;         // Google账号ID
  discord_id?: string | null;        // Discord账号ID
  github_id?: string | null;         // GitHub账号ID

  // 已弃用字段(向后兼容)
  createdAt?: number;                // @deprecated 使用 created_at
  emailVerified?: boolean;           // @deprecated 使用 email_verified
  googleId?: string;                 // @deprecated 使用 google_id
  discordId?: string;                // @deprecated 使用 discord_id
  githubId?: string;                 // @deprecated 使用 github_id
}

// 登录响应
interface LoginResponse {
  token: string;
  user: User;
}

// 注册响应
interface RegisterResponse {
  success: boolean;
  message?: string;
  userId?: string;
  // 邮箱验证相关
  requiresEmailVerification?: boolean;  // 是否需要邮箱验证
  // 邀请码激活相关
  requiresInvitationCode?: boolean;     // 是否需要邀请码激活
  tempUserId?: string;                  // 临时用户ID(需要激活)
  // 错误信息
  error?: string;
  code?: string;                        // 如 'ACCOUNT_EXISTS'
  details?: Record<string, any>;
}

// AuthModal选项
interface AuthModalOptions {
  client: SeaVerseBackendAPIClient;
  theme?: 'dark' | 'light';
  onLoginSuccess?: (token: string, user: any) => void;
  onSignupSuccess?: (token: string, user: any) => void;
  onInviteCodeRequired?: (userId: string, email: string) => void; // 当需要邀请码激活时的回调
  onApplyInviteSuccess?: (applicationId: string, email: string) => void; // 申请邀请码成功的回调
  onError?: (error: Error) => void;
  returnUrl?: string;        // OAuth 登录后返回的 URL,可选,默认为 window.location.href
  enableOAuth?: {
    google?: boolean;        // 启用 Google 登录
    discord?: boolean;       // 启用 Discord 登录
    github?: boolean;        // 启用 GitHub 登录
  };
}

完整示例

查看 examples/auth-sdk-demo 目录获取完整的可运行示例。

# 运行示例
cd examples/auth-sdk-demo
pnpm install
pnpm dev

从旧版本迁移

v0.1.x → v0.2.0 升级指南

1. 向后兼容性

好消息!v0.2.0 完全向后兼容,现有代码无需修改即可继续工作。

2. 推荐的迁移步骤

虽然不是必须的,但我们建议逐步迁移到新的字段命名规范:

// 旧代码(仍然可用)
const user = await client.getCurrentUser();
console.log(user.emailVerified);  // ⚠️ 已弃用但可用
console.log(user.createdAt);      // ⚠️ 已弃用但可用

// 新代码(推荐)
const user = await client.getCurrentUser();
console.log(user.email_verified); // ✅ 推荐使用
console.log(user.created_at);     // ✅ 推荐使用
console.log(user.app_id);         // ✅ 新字段:多租户支持

3. 注册接口更新

// 旧代码(仍然可用)
await client.register({
  email: '[email protected]',
  password: 'password123',
  invitationCode: 'INVITE123',  // ⚠️ 已弃用但可用
});

// 新代码(推荐)
await client.register({
  email: '[email protected]',
  password: 'password123',
  username: 'myusername',       // ✨ 新功能
  invitation_code: 'INVITE123', // ✅ 推荐使用
});

4. 密码重置接口更新

// 旧代码(需要更新)
await client.resetPassword({
  token: 'reset-token',
  newPassword: 'NewPass123',    // ⚠️ 已弃用
});

// 新代码(推荐)
await client.resetPassword({
  token: 'reset-token',
  new_password: 'NewPass123',   // ✅ 推荐使用
});

5. TypeScript 类型提示

如果你使用 TypeScript,编译器会自动提示已弃用的字段:

const user = await client.getCurrentUser();
user.emailVerified;  // TypeScript 会显示删除线和弃用警告
user.email_verified; // ✅ 无警告

6. 多租户功能(新增)

如果你的应用需要支持多租户架构,可以使用新的 app_id 字段:

const user = await client.getCurrentUser();

console.log('your app id:', user.app_id);

常见问题

如何处理认证token?

// 登录成功后保存token
const loginResult = await client.login({ email, password });
localStorage.setItem('token', loginResult.token);

// 创建带认证的client
import { AuthFactory } from '@seaverse/auth-sdk';

const authenticatedClient = new SeaVerseBackendAPIClient({
  appId: 'your app id',         // 必需:应用ID
  environment: 'production',
  auth: AuthFactory.create({
    type: 'jwt',
    credentials: {
      type: 'jwt',
      token: localStorage.getItem('token'),
    },
  }),
});

OAuth redirect_uri_mismatch错误?

确保OAuth应用配置中的重定向URI与代码中的redirectUri完全一致(包括协议、域名、端口、路径)。

如何自定义请求超时?

const client = new SeaVerseBackendAPIClient({
  appId: 'your app id',         // 必需:应用ID
  environment: 'production',
  timeout: 30000,            // 30秒
});

本地开发如何连接到本地API?

const client = new SeaVerseBackendAPIClient({
  appId: 'your app id',         // 必需:应用ID
  environment: 'local',      // 或使用 baseURL: 'http://localhost:3000'
});

开发

# 安装依赖
pnpm install

# 构建
pnpm build

# Watch模式
pnpm dev

# 测试
pnpm test

相关链接

License

MIT © SeaVerse Team

更新日志

v0.3.6 (当前版本)

  • 🧹 代码清理: 移除桌面应用OAuth回调相关功能
    • 移除 oauthDesktopURL 配置选项
    • 简化OAuth流程,统一使用 returnUrl 参数
    • 清理相关文档和代码注释

v0.2.5

  • 🔄 响应格式兼容: 自动兼容包装格式和扁平格式的API响应
    • 修复登录时提示 "Invalid response from server" 的问题
    • login(), register(), getCurrentUser() 方法自动解包 data 字段
    • 支持两种格式: { data: {...}, success: true }{ ... }
  • 📝 文档更新: 新增响应格式兼容性章节

v0.2.0

  • 🔄 API路径更新: 所有认证API从 /api/auth/* 迁移到 /sdk/v1/auth/*
  • 🏢 多租户支持: User模型新增 app_id 字段,支持多应用隔离
  • 🔑 重要变更: appId 现在是必需参数,SDK 自动在所有请求中添加 X-App-ID 请求头
  • 新功能:
    • 注册时支持自定义 username(可选)
    • 所有字段标准化为 snake_case(保留 camelCase 向后兼容)
  • 📝 字段更新:
    • SeaVerseBackendAPIClientOptions: 新增必需字段 appId
    • User: 新增 app_id, created_at, email_verified, google_id, discord_id, github_id
    • RegisterRequest: 新增 username, invitation_code
    • ResetPasswordRequest: newPasswordnew_password
  • ⚠️ Breaking Changes:
    • 必须提供 appId 参数才能初始化 client
    • API 路径变更需要后端支持
  • 向后兼容: 除 appId 外,所有旧字段仍然可用

v0.1.5

  • 修复OAuth state管理,从sessionStorage切换到localStorage
  • 增强API响应处理

v0.1.4

  • 增强API响应处理
  • 优化错误处理

v0.1.2

  • 更新包名为@seaverse/auth-sdk
  • 添加多环境支持

查看完整更新日志:CHANGELOG.md