@seaverse/auth-sdk
v0.4.10
Published
SDK for SeaVerse Backend API
Readme
@seaverse/auth-sdk
SeaVerse Backend API Client SDK - Provides complete authentication, container management, skill marketplace, and more
Features
- 🔐 User Authentication - Registration, login, logout, password reset
- 🌐 OAuth Login - Google, Discord, GitHub third-party login
- 🎨 Login UI Components - Out-of-the-box beautiful login modal
- ✨ Toast Notifications - Modern glassmorphism alerts with auto-injected CSS
- 🌍 Multi-Environment Support - Production, Staging, Development, Local
- ⚡ TypeScript - Full type definitions
- 🔧 Auth Integration - Built-in Auth and Hooks system support
- 🔄 Response Format Compatibility - Automatic compatibility with multiple API response formats
Installation
npm install @seaverse/auth-sdk
# or
pnpm add @seaverse/auth-sdkCore Concepts
App ID and Multi-Tenant Architecture
Important: Starting from v0.2.0, appId is a required parameter when initializing the SDK.
What is App ID?
Each application has a unique app_id:
app_id = "your app id"
Multi-Tenant Isolation
- User data is isolated by
app_id - The same email can be registered in different applications with different passwords
- Each application has its own independent user pool
X-App-ID Request Header
The SDK automatically adds X-App-ID to every request header, no manual configuration needed:
const client = new SeaVerseBackendAPIClient({
appId: 'game-abc123', // SDK automatically adds this value to all requests' X-App-ID header
});
// All API calls will automatically carry X-App-ID: game-abc123
await client.login({ email, password });
await client.getCurrentUser();Quick Start
1. Basic Usage
import { SeaVerseBackendAPIClient } from '@seaverse/auth-sdk';
// Method 1: SeaVerse platform application (auto-detect environment)
const client = new SeaVerseBackendAPIClient({
appId: 'your app id', // Required: Application ID
});
// Method 2: Third-party application (specify environment)
const client = new SeaVerseBackendAPIClient({
appId: 'your app id', // Required: Your application ID
environment: 'production', // 'production' | 'staging' | 'development' | 'local'
});
// Method 3: Custom URL
const client = new SeaVerseBackendAPIClient({
appId: 'your app id', // Required: Your application ID
baseURL: 'https://custom-api.example.com',
});
// Method 4: Enable request retry (disabled by default)
const client = new SeaVerseBackendAPIClient({
appId: 'your app id',
retryOptions: {
maxRetries: 3, // Retry up to 3 times
retryDelay: 1000, // Initial delay 1000ms, doubles each retry
retryStatusCodes: [408, 429, 500, 502, 503, 504], // Retry on these status codes
},
});
// Health check
const health = await client.getHealth();
console.log('Health:', health);2. Token Retrieval in Iframe Scenarios
When your application is embedded in an iframe, you can use the getIframeToken() method to retrieve the authentication token from the parent page. This is particularly useful for third-party login redirect scenarios.
Check if Running in Iframe
Before calling iframe-related methods, it's recommended to check if the application is running in an iframe:
import { SeaVerseBackendAPIClient } from '@seaverse/auth-sdk';
// Method 1: Use static method (no client instance needed)
if (SeaVerseBackendAPIClient.isInIframe()) {
console.log('Application is running in iframe');
} else {
console.log('Application is not running in iframe');
}
// Method 2: Use instance method
const client = new SeaVerseBackendAPIClient({
appId: 'your app id',
});
if (client.isInIframe()) {
console.log('Application is running in iframe');
// Safe to call getIframeToken()
}Child Page (Inside Iframe) Usage
import { SeaVerseBackendAPIClient } from '@seaverse/auth-sdk';
const client = new SeaVerseBackendAPIClient({
appId: 'your app id',
});
// First check if running in iframe
if (!client.isInIframe()) {
console.log('Not in iframe, skip token retrieval');
// Can use other login methods
} else {
// Request token from parent page while in iframe
try {
const token = await client.getIframeToken({
timeout: 10000 // Optional, default 30 seconds
});
// Set token to client
client.setToken(token);
localStorage.setItem('token', token);
console.log('Successfully retrieved token from parent page');
// Now can use authenticated APIs
const user = await client.getCurrentUser();
console.log('Current user:', user);
} catch (error) {
console.error('Failed to retrieve token:', error);
}
}Parent Page Listens and Responds to Token Requests
// Parent page needs to listen for token requests from iframe
window.addEventListener('message', (event) => {
// Check message type
if (event.data.type === 'seaverse:get_token') {
const requestId = event.data.requestId;
// Get your token (from localStorage, API, etc)
const token = localStorage.getItem('token');
if (token) {
// Send token to iframe
event.source.postMessage({
type: 'seaverse:token',
requestId: requestId,
payload: {
accessToken: token,
expiresIn: 3600,
},
}, '*');
} else {
// Send error message
event.source.postMessage({
type: 'seaverse:token_error',
requestId: requestId,
error: 'No token available',
}, '*');
}
}
});Complete Iframe Login Flow Example
// Child page (iframe)
import { SeaVerseBackendAPIClient } from '@seaverse/auth-sdk';
const client = new SeaVerseBackendAPIClient({
appId: 'your app id',
});
async function initIframeApp() {
// 0. Check if running in iframe
if (!client.isInIframe()) {
console.log('Not in iframe, use regular login flow');
// Use regular login flow
showLoginForm();
return;
}
try {
// 1. Try to get token from parent page
const token = await client.getIframeToken();
client.setToken(token);
localStorage.setItem('token', token);
// 2. Validate token and get user info
const user = await client.getCurrentUser();
console.log('Logged in:', user);
// 3. Continue app logic
startApp(user);
} catch (error) {
// 4. If failed, notify parent page that login is needed
window.parent.postMessage({
type: 'seaverse:need_login',
}, '*');
}
}
initIframeApp();// Parent page
window.addEventListener('message', (event) => {
// Handle token request
if (event.data.type === 'seaverse:get_token') {
const requestId = event.data.requestId;
const token = localStorage.getItem('token');
if (token) {
event.source.postMessage({
type: 'seaverse:token',
requestId: requestId,
payload: {
accessToken: token,
expiresIn: 3600,
},
}, '*');
} else {
// If no token, trigger login
showLoginModal();
}
}
// Handle need login message
if (event.data.type === 'seaverse:need_login') {
showLoginModal();
}
});
// After successful login, notify iframe
function onLoginSuccess(newToken) {
const iframe = document.querySelector('iframe');
iframe.contentWindow.postMessage({
type: 'seaverse:token',
requestId: 'auto', // Can use fixed ID for auto-login
payload: {
accessToken: newToken,
expiresIn: 3600,
},
}, '*');
}TypeScript Type Definitions
The SDK provides complete TypeScript type support:
import type {
IframeTokenRequestMessage,
IframeTokenResponseMessage,
IframeTokenErrorMessage,
} from '@seaverse/auth-sdk';
// Token request message
const request: IframeTokenRequestMessage = {
type: 'seaverse:get_token',
requestId: 'unique-id',
};
// Token response message
const response: IframeTokenResponseMessage = {
type: 'seaverse:token',
requestId: 'unique-id',
payload: {
accessToken: 'jwt-token',
expiresIn: 3600,
},
};
// Error message
const error: IframeTokenErrorMessage = {
type: 'seaverse:token_error',
requestId: 'unique-id',
error: 'Token not available',
};Security Considerations
Use specific origin: In production, use specific origin instead of
'*':// Parent page const ALLOWED_ORIGIN = 'https://your-iframe-domain.com'; event.source.postMessage(message, ALLOWED_ORIGIN); // Child page can also specify when sending window.parent.postMessage(message, 'https://parent-domain.com');Verify message origin: Validate origin when handling postMessage:
window.addEventListener('message', (event) => { // Verify origin if (event.origin !== 'https://trusted-domain.com') { return; } // Handle message... });Handle token expiration: Remember to handle token expiration:
try { const user = await client.getCurrentUser(); } catch (error) { if (error.response?.status === 401) { // Token expired, re-retrieve const newToken = await client.getIframeToken(); client.setToken(newToken); } }
3. User Authentication
// Register new user
const registerResult = await client.register({
email: '[email protected]',
password: 'SecurePassword123',
username: 'johndoe', // Optional, auto-generated from email if not provided
invitation_code: 'INVITE123', // Optional
frontend_url: 'https://mygame.com/verify', // Optional, frontend URL for email verification link, defaults to window.location.href
});
// Check registration result
if (registerResult.success) {
console.log('Registration successful:', registerResult);
} else if (registerResult.code === 'ACCOUNT_EXISTS') {
console.log('Account exists, please login directly');
console.log('Error details:', registerResult.details);
}
// Login
const loginResult = await client.login({
email: '[email protected]',
password: 'SecurePassword123',
});
// Save token
localStorage.setItem('token', loginResult.token);
// ⚠️ Note: Automatic invitation code redirect
// If server returns INVITE_CODE_REQUIRED error and includes redirectUrl,
// SDK will automatically redirect user to that URL (usually invitation code input page)
// No extra handling needed, page will redirect automatically
// Get current user info
const user = await client.getCurrentUser();
console.log('User:', user);
console.log('App ID:', user.app_id); // Multi-tenant application ID
console.log('Email verified:', user.email_verified);
// Logout
await client.logout();
// Forgot password
await client.forgotPassword({
email: '[email protected]',
frontend_url: 'https://mygame.com/', // Optional, defaults to window.location.href
});
// Reset password
await client.resetPassword({
token: 'reset-token-from-email',
new_password: 'NewSecurePassword123',
});4. OAuth Third-Party Login (Backend Proxy Mode)
The SDK uses Backend Proxy Mode where Client Secret is never exposed to the frontend, providing higher security.
Advantages:
- ✅ Client Secret is never exposed to frontend
- ✅ Supports any developer domain (no need to configure in OAuth platform)
- ✅ Built-in CSRF protection
- ✅ Zero configuration, works out of the box
Workflow:
- Frontend calls
{provider}Authorize()to get OAuth URL - Frontend redirects user to OAuth provider
- After user authorization, OAuth provider callbacks to fixed account-hub URL
- account-hub handles OAuth, creates JWT token
- account-hub 302 redirects to
return_url?token=xxx - Frontend extracts token from URL and stores it
Usage Examples
Method 1: Use default return_url (current page)
// Google login
const { authorize_url } = await client.googleAuthorize();
window.location.href = authorize_url;
// Discord login
const { authorize_url } = await client.discordAuthorize();
window.location.href = authorize_url;
// GitHub login
const { authorize_url } = await client.githubAuthorize();
window.location.href = authorize_url;Method 2: Custom return_url
// Redirect to dashboard after login
const { authorize_url } = await client.googleAuthorize({
return_url: 'https://mygame.com/dashboard'
});
window.location.href = authorize_url;Extract token in callback page:
// URL: https://mygame.com/?token=eyJhbGc...
const token = new URLSearchParams(window.location.search).get('token');
if (token) {
localStorage.setItem('token', token);
// Login successful, redirect or update UI
}OAuth Account Unlinking
// Unlink Google account
await client.unlinkGoogle();
// Unlink Discord account
await client.unlinkDiscord();
// Unlink GitHub account
await client.unlinkGithub();5. Using Login UI Components
The SDK provides beautiful login modal components with dark and light themes:
Theme Comparison
| Theme | Design Style | Use Cases | |------|---------|---------| | Dark 🌙 | Modern glassmorphism with brand color (#00E599) | Tech products, gaming platforms, dark interface apps | | Light ☀️ | Elevated card design + soft shadows | Business apps, content platforms, light interface apps |
Login Flow Design
The dark theme login interface features a dual-view system with progressive disclosure:
New Style View (Default):
- Initial View: Shows OAuth login buttons (Google primary, GitHub/Discord secondary) with brand green (#00E599) for the primary action
- Email Option: A "Sign in with Email" button allows users to switch to traditional email/password login
- Smart View Reset: When navigating from signup or other forms back to login, automatically resets to this modern OAuth-first view
Old Style View (On-Demand):
- Traditional Form: Activated by clicking "Sign in with Email", displays the classic email and password input fields
- Complete Experience: Includes "Welcome back." title, signup link, and all familiar login elements
- Back Navigation: Users can easily return to the OAuth options view with "Back to other options" button
This dual-view design:
- ✨ Prioritizes OAuth login for better conversion rates
- 🔄 Keeps traditional email login accessible when needed
- 🎯 Reduces cognitive load with clear, focused interfaces
- 📱 Provides smooth transitions between authentication methods
Basic Usage
import { SeaVerseBackendAPIClient, AuthModal } from '@seaverse/auth-sdk';
import '@seaverse/auth-sdk/auth-modal.css'; // Import styles
const client = new SeaVerseBackendAPIClient({
appId: 'your app id', // Required: Your application ID
environment: 'production',
});
// Create login modal
const authModal = new AuthModal({
client,
theme: 'dark', // 'dark' | 'light' - defaults to 'dark'
// Login success callback
onLoginSuccess: (token, user) => {
localStorage.setItem('token', token);
console.log('Login successful:', user);
},
// Signup success callback
onSignupSuccess: (token, user) => {
localStorage.setItem('token', token);
console.log('Signup successful:', user);
},
// Invitation code required callback (optional)
onInviteCodeRequired: (userId, email) => {
console.log('Need invitation code to activate account:', userId, email);
// AuthModal will automatically show invitation code input interface
},
// Apply invite success callback (optional)
onApplyInviteSuccess: (applicationId, email) => {
console.log('Invitation code application submitted:', applicationId, email);
// Can add custom logic here, such as showing notifications
},
// Error callback
onError: (error) => {
console.error('Authentication error:', error.message);
},
// OAuth configuration (optional)
returnUrl: 'https://mygame.com/', // URL to return after OAuth login, optional, defaults to window.location.href
enableOAuth: {
google: true, // Enable Google login
discord: true, // Enable Discord login
github: true, // Enable GitHub login
},
});
// Show login interface
authModal.show('login');
// Show signup interface
authModal.show('signup');
// Hide modal
authModal.hide();
// Destroy modal
authModal.destroy();✨ New Feature: Auto Toast Notifications
AuthModal has built-in modern Toast notification system, no extra configuration needed:
// Toast displays automatically, CSS auto-injected
// - Registration success → Green success notification
// - Account exists → Yellow warning notification
// - Login failure → Red error notification
// - Reset password → Blue info notification
// You can also use Toast independently (CSS auto-injected)
import { Toast } from '@seaverse/auth-sdk';
Toast.success('Success', 'Data saved');
Toast.error('Failed', 'Please try again later');
Toast.warning('Notice', 'Account already exists');
Toast.info('Info', 'Email sent');Password Reset Flow
AuthModal supports complete password reset flow:
- User triggers forgot password: Click "Forgot Password?" link in login interface
- Send reset email: After entering email, system sends reset link with
reset_token - Auto trigger reset modal: When user clicks link in email and returns to website, AuthModal automatically detects
reset_tokenparameter in URL and shows reset password form - Set new password: User enters and confirms new password then submits
- Auto cleanup URL: After successful reset, automatically clears
reset_tokenparameter from URL
The entire process requires no extra code, AuthModal handles it automatically:
// 1. Initialize AuthModal (only once)
const authModal = new AuthModal({
client,
// ... other configuration
});
// 2. After user clicks reset link in email, AuthModal automatically:
// - Detects ?reset_token=xxx parameter in URL
// - Shows reset password form
// - User submits new password
// - Calls client.resetPassword() API
// - Cleans reset_token parameter from URL
// - Shows success messageOAuth Configuration Instructions
The enableOAuth parameter is completely optional:
- If not provided, no third-party login buttons will be shown
- If partially configured (e.g., only enable Google), only enabled buttons will be shown
- If fully configured for all platforms, all third-party login buttons will be shown
Configuration field descriptions:
returnUrl: Optional - URL to return after OAuth login, defaults towindow.location.hrefif not providedenableOAuth.google: Whether to enable Google loginenableOAuth.discord: Whether to enable Discord loginenableOAuth.github: Whether to enable GitHub login
// Example 1: No OAuth buttons
const authModal1 = new AuthModal({
client,
theme: 'dark',
// No enableOAuth, no OAuth buttons shown
});
// Example 2: Only show Google login
const authModal2 = new AuthModal({
client,
theme: 'light',
returnUrl: 'https://mygame.com/dashboard',
enableOAuth: {
google: true,
// Discord and GitHub not enabled, won't show these buttons
},
});
// Example 3: Show all OAuth buttons
const authModal3 = new AuthModal({
client,
theme: 'dark',
enableOAuth: {
google: true,
discord: true,
github: true,
},
});Handling OAuth Callback
In Backend Proxy Mode, after OAuth login it redirects to returnUrl?token=xxx. Check and handle token on page load:
// Automatically handle OAuth callback on page load
const result = AuthModal.handleOAuthCallback({
client,
onLoginSuccess: (token) => {
localStorage.setItem('token', token);
console.log('OAuth login successful');
// Can now call authenticated APIs directly
// handleOAuthCallback has automatically called client.setToken()
client.getCurrentUser()
.then(user => console.log('User info:', user));
},
});
if (result) {
console.log('Handled OAuth callback, token:', result.token);
}Important Note:
handleOAuthCallback()automatically callsclient.setToken(token)to update client authentication configuration- This means after the
onLoginSuccesscallback, all authenticated APIs (such asgetCurrentUser(),logout(), etc.) will automatically include theAuthorizationheader
Manual Token Setting
If you don't use AuthModal.handleOAuthCallback(), you can also set the token manually:
// Extract token from URL
const token = new URLSearchParams(window.location.search).get('token');
if (token) {
// Manually set token
client.setToken(token);
localStorage.setItem('token', token);
// Now can call authenticated APIs
const user = await client.getCurrentUser();
}6. Container Management
// List all containers
const containers = await client.listContainers();
// Register new container
const result = await client.registerContainer({
containerId: 'container-123',
metadata: {
version: '1.0.0',
capabilities: ['skill-execution'],
},
});
// Get container info
const container = await client.getContainer({
containerId: 'container-123',
});
// Container heartbeat
await client.containerHeartbeat({
containerId: 'container-123',
status: 'healthy',
});
// Unregister container
await client.unregisterContainer({
containerId: 'container-123',
});
// Get container stats
const stats = await client.getContainerStats();7. Skill Marketplace
// List marketplace skills
const skills = await client.listMarketplaceSkills({
category: 'productivity',
page: 1,
pageSize: 20,
});
// Get skill details
const skill = await client.getMarketplaceSkill({
skillId: 'skill-123',
});
// Install skill
await client.installSkill({
skillId: 'skill-123',
});
// List installed skills
const userSkills = await client.listUserSkills();
// Uninstall skill
await client.uninstallSkill({
skillId: 'skill-123',
});8. Invitation Code Management
// Apply for invitation code (when user doesn't have one)
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 submitted:', application.data);
console.log('Application ID:', application.data.id);
console.log('Status:', application.data.status); // 'pending'
} else {
// Handle error
if (application.code === 'APPLICATION_DUPLICATE') {
console.log('You have already submitted an application in the past 24 hours');
} else {
console.error('Application failed:', application.error);
}
}
// List my invitation codes
const invites = await client.listInvites({
status: 'active',
page: 1,
page_size: 20,
});
console.log('My invitation codes:', invites.data.invites);
// Get invitation code stats
const stats = await client.getInviteStats();
console.log('Total invitation codes:', stats.data.total_codes);
console.log('Active invitation codes:', stats.data.active_codes);
console.log('Total usage count:', stats.data.total_uses);
// Get invitation code details
const invite = await client.getInvite('inv_abc123');
console.log('Invitation code:', invite.data.code);
console.log('Used count:', invite.data.used_count);
console.log('Max uses:', invite.data.max_uses);
// Get invitation code usage records
const usages = await client.getInviteUsages('inv_abc123', {
page: 1,
page_size: 20,
});
console.log('Usage records:', usages.data.usages);9. Email Verification and Invitation Code Binding
Email Verification (Auto Login)
After registration, users receive a verification email containing a verification link in the format: frontend_url?verify_token=xxx
Method 1: Use AuthModal Auto-Handling (Recommended)
import { AuthModal } from '@seaverse/auth-sdk';
// Create AuthModal instance
const modal = new AuthModal({
client,
onLoginSuccess: (token, user) => {
localStorage.setItem('token', token);
console.log('Email verified and logged in successfully:', user);
},
onError: (error) => {
console.error('Email verification failed:', error);
}
});
// AuthModal will automatically detect verify_token parameter in URL
// After detection, it will automatically:
// 1. Call verifyEmail() API to verify email
// 2. Get returned JWT token and auto-login
// 3. Trigger onLoginSuccess callback
// 4. Clean verify_token parameter from URL
// 5. Show success messageDebugging Tips:
If email verification has issues, check browser console logs:
// Normal case should show:
[AuthModal] Detected verify_token, starting email verification...
[AuthModal] Email verification successful: { id: "xxx", email: "[email protected]", ... }
// If verification fails, will show:
[AuthModal] Email verification failed: Error: ...Method 2: Manual Email Verification Handling
// Verify email (get verify_token from email link)
const urlParams = new URLSearchParams(window.location.search);
const verifyToken = urlParams.get('verify_token');
if (verifyToken) {
const result = await client.verifyEmail(verifyToken);
// Auto-login: save returned token
localStorage.setItem('token', result.data.token);
localStorage.setItem('refreshToken', result.data.refreshToken);
console.log('Email verified successfully, auto-logged in:', result.data.user);
// Redirect to homepage
window.location.href = '/';
}Invitation Code Binding (Account Activation)
When registering with external email or OAuth login without providing invitation code, a temporary account is created and requires subsequent invitation code binding for activation.
Apply for Invitation Code Feature:
If user doesn't have an invitation code, AuthModal provides built-in application feature:
- In invitation code input interface, user can click "Don't have an invitation code? Apply for one" link
- Automatically jumps to apply for invitation code form
- User fills in email and application reason (10-500 characters)
- After submission, calls
applyInvite()API, after backend approval, invitation code will be sent via email
Auto Redirect Mechanism:
- When
login()returnsINVITE_CODE_REQUIREDerror and includesredirectUrl, SDK automatically redirects page to that URL - redirectUrl usually contains
error_code=INVITE_CODE_REQUIRED&user_id=xxx&email=xxxparameters - No need to manually handle redirect logic, SDK completes automatically
For other scenarios (such as redirects after OAuth login), backend directly redirects to frontend_url?error_code=INVITE_CODE_REQUIRED&user_id=xxx&email=xxx.
Method 1: Use AuthModal Auto-Handling (Recommended)
import { AuthModal } from '@seaverse/auth-sdk';
// Create AuthModal instance
const modal = new AuthModal({
client,
onLoginSuccess: (token, user) => {
localStorage.setItem('token', token);
console.log('Login successful:', user);
},
onInviteCodeRequired: (userId, email) => {
// Optional: custom handling when invitation code is needed
console.log('Need invitation code to activate account:', userId, email);
}
});
// AuthModal will automatically detect the following parameter combinations in URL:
// - error_code=INVITE_CODE_REQUIRED
// - user_id or temp_user_id (user ID)
// - email (optional, user email)
//
// After detection, it will automatically:
// 1. Show invitation code input interface
// 2. After user inputs invitation code, call bindInviteCode() API
// 3. After successful activation, auto-login (save token)
// 4. Clean parameters from URLDebugging Tips:
If invitation code modal doesn't appear, check browser console for the following logs:
// Normal case should show:
[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"
}
// If user_id is missing, will show error:
[AuthModal] Missing user_id in URL parameters.
// And shows alert with full URL for troubleshooting backend redirect issuesMethod 2: Manual Invitation Code Binding Handling
// 1. Check if invitation code is needed in 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. Show invitation code input interface (custom UI)
const inviteCode = await showInviteCodeInput(); // Your custom UI
// 3. Bind invitation code
const result = await client.bindInviteCode({
user_id: userId,
invite_code: inviteCode
});
// 4. Activation successful, auto-login
localStorage.setItem('token', result.data.token);
localStorage.setItem('refreshToken', result.data.refreshToken);
console.log('Account activated successfully:', result.data.user);
// 5. Redirect to homepage
window.location.href = '/';
}Method 3: Use Static Method Handling
import { AuthModal } from '@seaverse/auth-sdk';
// AuthModal provides static method to handle invitation code scenario
const inviteCodeInfo = AuthModal.handleInviteCodeRequired(
{ client },
(userId, email) => {
// Custom handling logic
const code = prompt(`Please enter invitation code to activate account (${email}):`);
if (code) {
client.bindInviteCode({ user_id: userId, invite_code: code })
.then(res => {
localStorage.setItem('token', res.data.token);
window.location.reload();
});
}
}
);10. Other Features
// Get API Service Token
const apiToken = await client.getApiServiceToken();
// Get conversation status
const status = await client.getConversationStatus({
conversationId: 'conv-123',
});
// Get speech token
const speechToken = await client.getSpeechToken();Advanced Configuration
Custom Authentication
import { AuthFactory } from '@seaverse/auth-sdk';
const client = new SeaVerseBackendAPIClient({
appId: 'your app id', // Required: Application ID
environment: 'production',
// Use JWT authentication
auth: AuthFactory.create({
type: 'jwt',
credentials: {
type: 'jwt',
token: localStorage.getItem('token'),
},
}),
});Custom Hooks
import { BuiltInHooks } from '@seaverse/auth-sdk';
const client = new SeaVerseBackendAPIClient({
appId: 'your app id', // Required: Application ID
environment: 'production',
hooks: {
hooks: [
// Logger Hook
BuiltInHooks.createLoggerHook({
logLevel: 'debug',
logRequestBody: true,
logResponseBody: true,
}),
// Request ID Hook
BuiltInHooks.createRequestIdHook(),
// Custom Hook
{
type: 'beforeRequest',
name: 'custom-hook',
priority: 100,
handler: async (context) => {
console.log('Before request:', context.config.url);
},
},
],
},
});Request Retry Configuration
The SDK supports custom HTTP request retry strategies. By default, retry functionality is disabled (maxRetries: 0) to ensure request predictability.
Default Behavior (Retry Disabled)
const client = new SeaVerseBackendAPIClient({
appId: 'your app id',
// retryOptions not set, no retry by default
});
// If request fails, will return error immediately, no retryEnable Basic Retry
import { SeaVerseBackendAPIClient } from '@seaverse/auth-sdk';
const client = new SeaVerseBackendAPIClient({
appId: 'your app id',
retryOptions: {
maxRetries: 3, // Retry up to 3 times
retryDelay: 1000, // Initial delay 1000ms (1 second)
// Defaults to retry on these status codes: [408, 429, 500, 502, 503, 504]
},
});Retry Strategy Explanation:
- Uses exponential backoff algorithm: 1st retry waits 1 second, 2nd waits 2 seconds, 3rd waits 4 seconds
- HTTP status codes that trigger auto-retry:
408- Request Timeout429- Too Many Requests (rate limiting)500- Internal Server Error502- Bad Gateway503- Service Unavailable504- Gateway Timeout
- Network errors (no response) will also trigger retry
Custom Retry Status Codes
const client = new SeaVerseBackendAPIClient({
appId: 'your app id',
retryOptions: {
maxRetries: 5,
retryDelay: 2000,
retryStatusCodes: [503, 504], // Only retry on 503 and 504
},
});Custom Retry Logic
import type { RetryOptions } from '@seaverse/auth-sdk';
const retryOptions: RetryOptions = {
maxRetries: 3,
retryDelay: 1000,
// Custom judgment logic: only retry on specific errors
shouldRetry: (error) => {
// Only retry on service unavailable errors
if (error.response?.status === 503) {
return true;
}
// Retry on network errors with no response
if (!error.response) {
return true;
}
return false;
},
};
const client = new SeaVerseBackendAPIClient({
appId: 'your app id',
retryOptions,
});RetryOptions Type Definition
interface RetryOptions {
maxRetries?: number; // Maximum retry count, default 0 (disabled)
retryDelay?: number; // Initial retry delay (milliseconds), default 1000
retryStatusCodes?: number[]; // List of status codes that trigger retry
shouldRetry?: (error: AxiosError) => boolean; // Custom retry judgment function
}Usage Recommendations:
- ⚠️ Recommended to disable retry in production (default behavior), avoid duplicate requests on business logic errors
- ✅ Only enable retry in unstable network scenarios, such as mobile apps, weak network environments
- ✅ Ensure backend APIs support idempotent operations, avoid side effects from retries
- ✅ For critical business (such as payments), recommended to use custom
shouldRetryto carefully control retry logic
Environment Configuration
The SDK supports the following environments:
| Environment | Description | BaseURL |
|------|------|---------|
| production | Production environment | https://account-hub.seaverse.ai |
| staging | Staging environment | https://api.staging.seaverse.dev |
| development | Development environment | https://api.dev.seaverse.dev |
| local | Local environment | http://localhost:3000 |
Auto-detection rules:
*.seaverse.com→ production*.staging.seaverse.dev→ staging*.dev.seaverse.dev→ developmentlocalhost→ local
API Reference
Authentication Related
| Method | Parameters | Return Value | Description |
|------|------|--------|------|
| register() | { email, password, username?, invitation_code?, frontend_url? } | RegisterResponse | Register new user, frontend_url is frontend URL for email verification link, defaults to window.location.href |
| login() | { email, password, frontend_url? } | LoginResponse | User login, frontend_url used for sending verification email when email not verified, defaults to https://seaverse.ai/. ⚠️ If returns INVITE_CODE_REQUIRED with redirectUrl, will automatically redirect |
| getCurrentUser() | - | User | Get current user |
| logout() | - | SuccessResponse | Logout |
| verifyEmail() | verifyToken: string | EmailVerificationResponse | Verify email and return auto-login token |
| bindInviteCode() | { user_id, invite_code } | BindInviteCodeResponse | Bind invitation code to activate temporary account and auto-login |
| forgotPassword() | { email, frontend_url? } | SuccessResponse | Forgot password, frontend_url defaults to window.location.href |
| resetPassword() | { token, new_password } | SuccessResponse | Reset password |
| setToken() | token: string | void | Set authentication token (used after OAuth login) |
| isInIframe() | - | boolean | Check if application is running in iframe (supports static method and instance method) |
| getIframeToken() | { timeout? } | Promise<string> | Get token from parent page (iframe scenario only), timeout defaults to 30000ms |
| getApiServiceToken() | - | ApiServiceTokenResponse | Get API Token |
Registration Flow Description
The register() method supports three registration flows, SDK automatically handles based on backend response:
Flow 1: Immediate Activation (Default)
const response = await client.register({ email, password });
// response.success === true
// response.requiresEmailVerification === undefined (or false)
// response.requiresInvitationCode === undefined (or false)
// → SDK automatically calls login() and triggers onSignupSuccess callbackFlow 2: Requires Email Verification
const response = await client.register({ email, password });
// response.success === true
// response.requiresEmailVerification === true
// → SDK shows Toast prompting user to check email
// → Does not auto-call login(), user needs to click verification link in emailFlow 3: Requires Invitation Code Activation
const response = await client.register({ email, password });
// response.success === true
// response.requiresInvitationCode === true
// response.tempUserId === "temp_xxx"
// → SDK shows invitation code input form
// → Does not auto-call login(), user needs to input invitation codeImportant Note:
- AuthModal automatically handles these three flows, no manual judgment needed
- Only when no verification or activation is needed, will
login()be automatically called - This avoids unnecessary login requests when email is not verified or account is not activated
OAuth Related
| Method | Parameters | Return Value | Description |
|------|------|--------|------|
| googleAuthorize() | { return_url? } | OAuthAuthorizeResponse | Google OAuth authorization URL |
| discordAuthorize() | { return_url? } | OAuthAuthorizeResponse | Discord OAuth authorization URL |
| githubAuthorize() | { return_url? } | OAuthAuthorizeResponse | GitHub OAuth authorization URL |
| unlinkGoogle() | - | SuccessResponse | Unlink Google |
| unlinkDiscord() | - | SuccessResponse | Unlink Discord |
| unlinkGithub() | - | SuccessResponse | Unlink GitHub |
Container Management
| Method | Parameters | Return Value | Description |
|------|------|--------|------|
| listContainers() | - | ContainerListResponse | List containers |
| registerContainer() | { containerId, metadata } | SuccessResponse | Register container |
| getContainer() | { containerId } | Container | Get container info |
| unregisterContainer() | { containerId } | SuccessResponse | Unregister container |
| containerHeartbeat() | { containerId, status } | SuccessResponse | Container heartbeat |
| getContainerStats() | - | ContainerStatsResponse | Container stats |
Skill Marketplace
| Method | Parameters | Return Value | Description |
|------|------|--------|------|
| listMarketplaceSkills() | { category?, page?, pageSize? } | MarketplaceSkillsListResponse | List marketplace skills |
| getMarketplaceSkill() | { skillId } | MarketplaceSkill | Get skill details |
| installSkill() | { skillId } | SuccessResponse | Install skill |
| listUserSkills() | - | UserInstalledSkillsListResponse | List installed skills |
| uninstallSkill() | { skillId } | SuccessResponse | Uninstall skill |
Invitation Code Management
| Method | Parameters | Return Value | Description |
|------|------|--------|------|
| applyInvite() | { email, reason } | ApplyInviteResponse | Apply for invitation code (reason needs 10-500 characters)|
| listInvites() | { page?, page_size?, status? } | ListInvitesResponse | List my invitation codes |
| getInviteStats() | - | InviteStatsResponse | Get invitation code stats |
| getInvite() | inviteId: string | InviteCodeDetailResponse | Get invitation code details |
| getInviteUsages() | inviteId: string, { page?, page_size? } | ListInviteUsagesResponse | Get invitation code usage records |
Others
| Method | Parameters | Return Value | Description |
|------|------|--------|------|
| getHealth() | - | HealthResponse | Health check |
| getConversationStatus() | { conversationId } | ConversationStatusResponse | Get conversation status |
| getSpeechToken() | - | SpeechTokenResponse | Get speech token |
Response Format Compatibility
Auto Response Unwrapping
Starting from v0.2.5, SDK automatically supports two API response formats, no manual handling needed:
Format 1: Wrapped Format (Recommended)
{
"data": {
"token": "eyJhbGc...",
"user": { ... }
},
"success": true
}Format 2: Flat Format (Backward Compatible)
{
"token": "eyJhbGc...",
"user": { ... }
}SDK automatically detects response format and extracts correct data:
// Regardless of which format backend returns, the following code works
const loginResult = await client.login({
email: '[email protected]',
password: 'password123',
});
console.log(loginResult.token); // ✅ Always gets token correctly
console.log(loginResult.user); // ✅ Always gets user correctlyAffected Methods
The following methods have implemented auto response unwrapping:
- ✅
login()- Login API - ✅
register()- Registration API - ✅
getCurrentUser()- Get current user
Implementation Principle
SDK internally handles response format through the following logic:
const response = await httpClient.request(config);
const responseData = response.data;
// Detect and unwrap
if (responseData.data && typeof responseData.data === 'object') {
// Wrapped format: extract data field
return responseData.data;
}
// Flat format: return directly
return responseData;This means:
- 🔄 Backend format changes don't require frontend modifications - Backend can freely adjust response format
- 🔧 Progressive migration - Different APIs can be migrated to new format gradually
- ✅ Backward compatible - Old code continues to work without modifications
Error Handling
Error Response Format
All API errors follow a unified response format:
interface ApiError {
success: false; // Always false on error
error: string; // Human-readable error message
code?: string; // Machine-readable error code
details?: any; // Additional error details
}Error Codes
SDK provides standard error code enums:
import { ErrorCode } from '@seaverse/auth-sdk';
// Account-related errors
ErrorCode.ACCOUNT_EXISTS // Account already exists
ErrorCode.ACCOUNT_NOT_FOUND // Account not found
ErrorCode.ACCOUNT_SUSPENDED // Account suspended
ErrorCode.INVALID_CREDENTIALS // Invalid login credentials
ErrorCode.EMAIL_NOT_VERIFIED // Email not verified
// Validation-related errors
ErrorCode.INVALID_EMAIL // Invalid email address
ErrorCode.INVALID_PASSWORD // Invalid password
ErrorCode.PASSWORD_TOO_WEAK // Password too weak
// Invitation code-related errors
ErrorCode.INVALID_INVITATION_CODE // Invalid invitation code
ErrorCode.INVITATION_REQUIRED // Invitation code required
ErrorCode.INVITE_CODE_REQUIRED // Invitation code required (will auto-redirect to redirectUrl)
// Token-related errors
ErrorCode.INVALID_TOKEN // Invalid token
ErrorCode.TOKEN_EXPIRED // Token expired
// Internal errors
ErrorCode.INTERNAL_ERROR // Server internal errorError Handling Best Practices
1. Handle Duplicate Users During Registration
Since backend returns 200 OK when account exists (success response), frontend won't throw exception, but includes error info in response body.
import { ErrorCode } from '@seaverse/auth-sdk';
const result = await client.register({
email: '[email protected]',
password: 'password123',
});
// Check success field in response
if (result.success) {
console.log('Registration successful:', result);
// Proceed with follow-up actions, such as auto-login
} else if (result.code === ErrorCode.ACCOUNT_EXISTS) {
// Account exists, prompt user
const { email, app_id } = result.details;
console.log(`Account ${email} already exists in application ${app_id}`);
// Show friendly prompt
alert('This email is already registered. Please login instead.');
// Or guide user to login
showLoginModal();
} else {
// Handle other errors
console.error('Registration failed:', result.error);
}2. Handle Various Errors During Login
try {
const result = await client.login({
email: '[email protected]',
password: 'wrong-password',
});
console.log('Login successful:', result);
} catch (error) {
const errorCode = error.response?.data?.code;
switch (errorCode) {
case ErrorCode.INVALID_CREDENTIALS:
showError('Incorrect username or password');
break;
case ErrorCode.EMAIL_NOT_VERIFIED:
showError('Please verify your email first');
showResendVerificationButton();
break;
case ErrorCode.ACCOUNT_SUSPENDED:
showError('Your account has been suspended, please contact administrator');
break;
default:
showError('Login failed, please try again later');
}
}3. Generic Error Handling Function
import { ErrorCode } from '@seaverse/auth-sdk';
function handleApiError(error: any) {
const apiError = error.response?.data;
if (!apiError) {
// Network error or other unknown error
return {
title: 'Network Error',
message: 'Please check your network connection',
};
}
// Return user-friendly messages based on error code
const errorMessages: Record<string, { title: string; message: string }> = {
[ErrorCode.ACCOUNT_EXISTS]: {
title: 'Account Exists',
message: 'This email is already registered, please login directly',
},
[ErrorCode.INVALID_CREDENTIALS]: {
title: 'Login Failed',
message: 'Incorrect username or password',
},
[ErrorCode.EMAIL_NOT_VERIFIED]: {
title: 'Email Not Verified',
message: 'Please verify your email address first',
},
[ErrorCode.INVALID_INVITATION_CODE]: {
title: 'Invalid Invitation Code',
message: 'Please check if your invitation code is correct',
},
[ErrorCode.TOKEN_EXPIRED]: {
title: 'Login Expired',
message: 'Please login again',
},
};
return errorMessages[apiError.code] || {
title: 'Operation Failed',
message: apiError.error || 'Unknown error occurred',
};
}
// Usage example
try {
await client.register({ email, password });
} catch (error) {
const { title, message } = handleApiError(error);
showNotification(title, message);
}4. TypeScript Type-Safe Error Handling
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 Status Code Reference
| HTTP Status Code | Error Code Example | Description |
|-----------|----------|------|
| 200 OK | ACCOUNT_EXISTS | Account exists (business error but returns success response) |
| 400 Bad Request | INVALID_EMAIL, PASSWORD_TOO_WEAK | Invalid request parameters |
| 401 Unauthorized | INVALID_CREDENTIALS, TOKEN_EXPIRED | Authentication failed |
| 403 Forbidden | EMAIL_NOT_VERIFIED, ACCOUNT_SUSPENDED | Insufficient permissions |
| 500 Internal Server Error | INTERNAL_ERROR | Server internal error |
Note: For registration API, account exists case returns 200 OK, but in response body success: false and code: "ACCOUNT_EXISTS". This design makes it easier for frontend to handle this common business scenario.
Type Definitions
// User info
interface User {
id?: string;
app_id?: string | null; // Application ID (multi-tenant support)
email?: string;
username?: string;
created_at?: number; // Unix timestamp
email_verified?: boolean; // Email verification status
google_id?: string | null; // Google account ID
discord_id?: string | null; // Discord account ID
github_id?: string | null; // GitHub account ID
// Deprecated fields (backward compatible)
createdAt?: number; // @deprecated Use created_at
emailVerified?: boolean; // @deprecated Use email_verified
googleId?: string; // @deprecated Use google_id
discordId?: string; // @deprecated Use discord_id
githubId?: string; // @deprecated Use github_id
}
// Login response
interface LoginResponse {
token: string;
user: User;
}
// Registration response
interface RegisterResponse {
success: boolean;
message?: string;
userId?: string;
// Email verification related
requiresEmailVerification?: boolean; // Whether email verification is required
// Invitation code activation related
requiresInvitationCode?: boolean; // Whether invitation code activation is required
tempUserId?: string; // Temporary user ID (needs activation)
// Error info
error?: string;
code?: string; // E.g. 'ACCOUNT_EXISTS'
details?: Record<string, any>;
}
// AuthModal options
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; // Callback when invitation code activation is needed
onApplyInviteSuccess?: (applicationId: string, email: string) => void; // Callback when invitation code application succeeds
onError?: (error: Error) => void;
returnUrl?: string; // URL to return after OAuth login, optional, defaults to window.location.href
enableOAuth?: {
google?: boolean; // Enable Google login
discord?: boolean; // Enable Discord login
github?: boolean; // Enable GitHub login
};
}Complete Examples
Check examples/auth-sdk-demo directory for complete runnable examples.
# Run example
cd examples/auth-sdk-demo
pnpm install
pnpm devMigration from Old Versions
v0.1.x → v0.2.0 Upgrade Guide
1. Backward Compatibility
Good news! v0.2.0 is fully backward compatible, existing code works without modifications.
2. Recommended Migration Steps
While not required, we recommend gradually migrating to new field naming conventions:
// Old code (still works)
const user = await client.getCurrentUser();
console.log(user.emailVerified); // ⚠️ Deprecated but works
console.log(user.createdAt); // ⚠️ Deprecated but works
// New code (recommended)
const user = await client.getCurrentUser();
console.log(user.email_verified); // ✅ Recommended
console.log(user.created_at); // ✅ Recommended
console.log(user.app_id); // ✅ New field: multi-tenant support3. Registration API Update
// Old code (still works)
await client.register({
email: '[email protected]',
password: 'password123',
invitationCode: 'INVITE123', // ⚠️ Deprecated but works
});
// New code (recommended)
await client.register({
email: '[email protected]',
password: 'password123',
username: 'myusername', // ✨ New feature
invitation_code: 'INVITE123', // ✅ Recommended
});4. Password Reset API Update
// Old code (needs update)
await client.resetPassword({
token: 'reset-token',
newPassword: 'NewPass123', // ⚠️ Deprecated
});
// New code (recommended)
await client.resetPassword({
token: 'reset-token',
new_password: 'NewPass123', // ✅ Recommended
});5. TypeScript Type Hints
If you use TypeScript, compiler will automatically hint deprecated fields:
const user = await client.getCurrentUser();
user.emailVerified; // TypeScript will show strikethrough and deprecation warning
user.email_verified; // ✅ No warning6. Multi-Tenant Feature (New)
If your application needs multi-tenant architecture support, you can use the new app_id field:
const user = await client.getCurrentUser();
console.log('your app id:', user.app_id);FAQ
How to Handle Authentication Token?
// Save token after successful login
const loginResult = await client.login({ email, password });
localStorage.setItem('token', loginResult.token);
// Create authenticated client
import { AuthFactory } from '@seaverse/auth-sdk';
const authenticatedClient = new SeaVerseBackendAPIClient({
appId: 'your app id', // Required: Application ID
environment: 'production',
auth: AuthFactory.create({
type: 'jwt',
credentials: {
type: 'jwt',
token: localStorage.getItem('token'),
},
}),
});OAuth redirect_uri_mismatch Error?
Ensure the redirect URI in OAuth application configuration exactly matches the redirectUri in code (including protocol, domain, port, path).
How to Customize Request Timeout?
const client = new SeaVerseBackendAPIClient({
appId: 'your app id', // Required: Application ID
environment: 'production',
timeout: 30000, // 30 seconds
});How to Connect to Local API in Local Development?
const client = new SeaVerseBackendAPIClient({
appId: 'your app id', // Required: Application ID
environment: 'local', // Or use baseURL: 'http://localhost:3000'
});Development
# Install dependencies
pnpm install
# Build
pnpm build
# Watch mode
pnpm dev
# Test
pnpm testRelated Links
License
MIT © SeaVerse Team
Changelog
v0.4.7 (Current Version)
- 🎨 UI Style Update: Modernized login interface with refined visual design
- Updated primary button color to brighter green (#00E599 → #00e599, #00f5a8 on hover)
- OAuth buttons layout (applies to login and signup pages):
- Desktop & Mobile: Google and GitHub in first row (2 columns grid), Discord spans full width in second row
- Uses CSS Grid layout with
grid-column: 1 / -1for Discord button to span both columns - Consistent button styling across all OAuth providers
- Enhanced input field styling with improved hover and focus states
- Refined modal layout: left panel (374px) + right panel (456px), fixed height (636px)
- Updated mesh gradient animation for smoother visual effects
- Improved button styles across all views (signin, signup, forgot password)
- Enhanced form labels, dividers, and social login buttons
- Better spacing and typography throughout the interface
- Optimized responsive design for mobile devices
v0.4.6
- 🐛 Bug Fix: Fix OAuth buttons not responding in email login view
- Fixed HTML element ID conflict between new style and old style login views
- Old style login view OAuth buttons now have unique IDs with 'old' prefix
- Properly bind click events to all OAuth buttons in both views
v0.4.4
- 🎨 Login UI Redesign: Dual-view login system with progressive disclosure
- New Style View (Default): Modern OAuth-first interface with brand color #00E599
- Google as primary button, GitHub/Discord as secondary options
- "Sign in with Email" toggle for traditional login
- Automatically shown when returning to login from other views
- Old Style View (On-Demand): Classic email/password form
- Activated by clicking "Sign in with Email"
- Complete traditional login experience with "Welcome back." title
- "Back to other options" button to return to OAuth view
- Enhanced visual design: improved input fields, button states, and typography
- Smooth view transitions with CSS-scoped styling for each mode
- New Style View (Default): Modern OAuth-first interface with brand color #00E599
v0.3.6
- 🧹 Code Cleanup: Remove desktop application OAuth callback related functionality
- Remove
oauthDesktopURLconfiguration option - Simplify OAuth flow, unified use of
returnUrlparameter - Clean up related documentation and code comments
- Remove
v0.2.5
- 🔄 Response Format Compatibility: Automatic compatibility with wrapped and flat API response formats
- Fix "Invalid response from server" prompt during login
login(),register(),getCurrentUser()methods auto-unwrapdatafield- Support two formats:
{ data: {...}, success: true }and{ ... }
- 📝 Documentation Update: Add response format compatibility section
v0.2.0
- 🔄 API Path Update: All authentication APIs migrated from
/api/auth/*to/sdk/v1/auth/* - 🏢 Multi-Tenant Support: User model adds
app_idfield, supports multi-application isolation - 🔑 Important Change:
appIdis now a required parameter, SDK automatically addsX-App-IDrequest header to all requests - ✨ New Features:
- Registration supports custom
username(optional) - All fields standardized to snake_case (retains camelCase backward compatibility)
- Registration supports custom
- 📝 Field Updates:
SeaVerseBackendAPIClientOptions: Add required fieldappIdUser: Addapp_id,created_at,email_verified,google_id,discord_id,github_idRegisterRequest: Addusername,invitation_codeResetPasswordRequest:newPassword→new_password
- ⚠️ Breaking Changes:
- Must provide
appIdparameter to initialize client - API path changes require backend support
- Must provide
- ✅ Backward Compatible: Except for
appId, all old fields still work
v0.1.5
- Fix OAuth state management, switch from sessionStorage to localStorage
- Enhance API response handling
v0.1.4
- Enhance API response handling
- Optimize error handling
v0.1.2
- Update package name to @seaverse/auth-sdk
- Add multi-environment support
View complete changelog: CHANGELOG.md
