@seaverse/auth-sdk 0.3.9 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +68 -14
- package/dist/index.cjs +82 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +38 -0
- package/dist/index.js +82 -5
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -98,6 +98,31 @@ console.log('Health:', health);
|
|
|
98
98
|
|
|
99
99
|
当你的应用被嵌入到 iframe 中时,可以使用 `getIframeToken()` 方法从父页面获取认证 token。这对于第三方登录重定向场景特别有用。
|
|
100
100
|
|
|
101
|
+
#### 检查是否在 iframe 中运行
|
|
102
|
+
|
|
103
|
+
在调用 iframe 相关方法前,建议先检查应用是否在 iframe 中运行:
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
import { SeaVerseBackendAPIClient } from '@seaverse/auth-sdk';
|
|
107
|
+
|
|
108
|
+
// 方式 1: 使用静态方法(无需 client 实例)
|
|
109
|
+
if (SeaVerseBackendAPIClient.isInIframe()) {
|
|
110
|
+
console.log('应用正在 iframe 中运行');
|
|
111
|
+
} else {
|
|
112
|
+
console.log('应用不在 iframe 中运行');
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// 方式 2: 使用实例方法
|
|
116
|
+
const client = new SeaVerseBackendAPIClient({
|
|
117
|
+
appId: 'your app id',
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
if (client.isInIframe()) {
|
|
121
|
+
console.log('应用正在 iframe 中运行');
|
|
122
|
+
// 可以安全地调用 getIframeToken()
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
101
126
|
#### 子页面 (iframe 内) 使用方式
|
|
102
127
|
|
|
103
128
|
```typescript
|
|
@@ -107,23 +132,29 @@ const client = new SeaVerseBackendAPIClient({
|
|
|
107
132
|
appId: 'your app id',
|
|
108
133
|
});
|
|
109
134
|
|
|
110
|
-
//
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
135
|
+
// 先检查是否在 iframe 中
|
|
136
|
+
if (!client.isInIframe()) {
|
|
137
|
+
console.log('应用不在 iframe 中,跳过 token 获取');
|
|
138
|
+
// 可以使用其他登录方式
|
|
139
|
+
} else {
|
|
140
|
+
// 在 iframe 中请求父页面的 token
|
|
141
|
+
try {
|
|
142
|
+
const token = await client.getIframeToken({
|
|
143
|
+
timeout: 10000 // 可选,默认 30 秒
|
|
144
|
+
});
|
|
115
145
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
146
|
+
// 设置 token 到 client
|
|
147
|
+
client.setToken(token);
|
|
148
|
+
localStorage.setItem('token', token);
|
|
119
149
|
|
|
120
|
-
|
|
150
|
+
console.log('成功从父页面获取 token');
|
|
121
151
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
} catch (error) {
|
|
126
|
-
|
|
152
|
+
// 现在可以使用需要认证的 API
|
|
153
|
+
const user = await client.getCurrentUser();
|
|
154
|
+
console.log('当前用户:', user);
|
|
155
|
+
} catch (error) {
|
|
156
|
+
console.error('获取 token 失败:', error);
|
|
157
|
+
}
|
|
127
158
|
}
|
|
128
159
|
```
|
|
129
160
|
|
|
@@ -172,6 +203,14 @@ const client = new SeaVerseBackendAPIClient({
|
|
|
172
203
|
});
|
|
173
204
|
|
|
174
205
|
async function initIframeApp() {
|
|
206
|
+
// 0. 检查是否在 iframe 中
|
|
207
|
+
if (!client.isInIframe()) {
|
|
208
|
+
console.log('应用不在 iframe 中,使用常规登录流程');
|
|
209
|
+
// 使用常规登录流程
|
|
210
|
+
showLoginForm();
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
|
|
175
214
|
try {
|
|
176
215
|
// 1. 尝试从父页面获取 token
|
|
177
216
|
const token = await client.getIframeToken();
|
|
@@ -531,8 +570,22 @@ Toast.success('操作成功', '数据已保存');
|
|
|
531
570
|
Toast.error('操作失败', '请稍后重试');
|
|
532
571
|
Toast.warning('注意', '账号已存在');
|
|
533
572
|
Toast.info('提示', '邮件已发送');
|
|
573
|
+
|
|
574
|
+
// 自定义显示时长(默认 3000ms)
|
|
575
|
+
Toast.success('操作成功', '数据已保存', 5000);
|
|
534
576
|
```
|
|
535
577
|
|
|
578
|
+
**🎯 智能交互特性**
|
|
579
|
+
|
|
580
|
+
Toast 提供了智能的用户交互体验:
|
|
581
|
+
|
|
582
|
+
- **Hover 暂停**:当鼠标悬停在 Toast 上时,自动暂停倒计时,让用户有足够时间阅读消息
|
|
583
|
+
- **离开继续**:鼠标移开后,继续倒计时并自动消失
|
|
584
|
+
- **手动关闭**:点击右上角的关闭按钮可立即关闭通知
|
|
585
|
+
- **自动消失**:默认 3 秒后自动消失(可自定义时长)
|
|
586
|
+
|
|
587
|
+
这些特性确保用户不会错过重要提示信息。
|
|
588
|
+
|
|
536
589
|
#### 重置密码流程
|
|
537
590
|
|
|
538
591
|
AuthModal 支持完整的密码重置流程:
|
|
@@ -1152,6 +1205,7 @@ SDK支持以下环境:
|
|
|
1152
1205
|
| `forgotPassword()` | `{ email, frontend_url? }` | `SuccessResponse` | 忘记密码,frontend_url 默认为 window.location.href |
|
|
1153
1206
|
| `resetPassword()` | `{ token, new_password }` | `SuccessResponse` | 重置密码 |
|
|
1154
1207
|
| `setToken()` | `token: string` | `void` | 设置认证 token(OAuth 登录后使用) |
|
|
1208
|
+
| `isInIframe()` | - | `boolean` | 检查应用是否在 iframe 中运行(支持静态方法和实例方法) |
|
|
1155
1209
|
| `getIframeToken()` | `{ timeout? }` | `Promise<string>` | 从父页面获取 token(仅 iframe 场景),timeout 默认 30000ms |
|
|
1156
1210
|
| `getApiServiceToken()` | - | `ApiServiceTokenResponse` | 获取API Token |
|
|
1157
1211
|
|
package/dist/index.cjs
CHANGED
|
@@ -1285,6 +1285,51 @@ class SeaVerseBackendAPIClient {
|
|
|
1285
1285
|
// Update the httpClient's auth
|
|
1286
1286
|
this.httpClient.auth = auth;
|
|
1287
1287
|
}
|
|
1288
|
+
/**
|
|
1289
|
+
* Check if the application is running inside an iframe
|
|
1290
|
+
* This is a utility method to detect iframe context before calling iframe-specific methods
|
|
1291
|
+
*
|
|
1292
|
+
* @returns true if running in an iframe, false otherwise
|
|
1293
|
+
*
|
|
1294
|
+
* @example
|
|
1295
|
+
* // Check if in iframe before requesting token
|
|
1296
|
+
* if (client.isInIframe()) {
|
|
1297
|
+
* const token = await client.getIframeToken();
|
|
1298
|
+
* client.setToken(token);
|
|
1299
|
+
* } else {
|
|
1300
|
+
* console.log('Not running in an iframe');
|
|
1301
|
+
* }
|
|
1302
|
+
*
|
|
1303
|
+
* @example
|
|
1304
|
+
* // Use as a static method without client instance
|
|
1305
|
+
* if (SeaVerseBackendAPIClient.isInIframe()) {
|
|
1306
|
+
* console.log('Application is embedded in an iframe');
|
|
1307
|
+
* }
|
|
1308
|
+
*/
|
|
1309
|
+
static isInIframe() {
|
|
1310
|
+
// Only works in browser environment
|
|
1311
|
+
if (typeof window === 'undefined') {
|
|
1312
|
+
return false;
|
|
1313
|
+
}
|
|
1314
|
+
// Check if window.self is not equal to window.top
|
|
1315
|
+
// This is the standard way to detect if running in an iframe
|
|
1316
|
+
try {
|
|
1317
|
+
return window.self !== window.top;
|
|
1318
|
+
}
|
|
1319
|
+
catch (e) {
|
|
1320
|
+
// If we get a SecurityError (cross-origin iframe), we're definitely in an iframe
|
|
1321
|
+
return true;
|
|
1322
|
+
}
|
|
1323
|
+
}
|
|
1324
|
+
/**
|
|
1325
|
+
* Instance method to check if running in an iframe
|
|
1326
|
+
* Calls the static method for convenience
|
|
1327
|
+
*
|
|
1328
|
+
* @returns true if running in an iframe, false otherwise
|
|
1329
|
+
*/
|
|
1330
|
+
isInIframe() {
|
|
1331
|
+
return SeaVerseBackendAPIClient.isInIframe();
|
|
1332
|
+
}
|
|
1288
1333
|
/**
|
|
1289
1334
|
* Get token from parent window via iframe communication
|
|
1290
1335
|
* This method is designed for scenarios where the application is embedded in an iframe
|
|
@@ -1330,7 +1375,7 @@ class SeaVerseBackendAPIClient {
|
|
|
1330
1375
|
return Promise.reject(new Error('getIframeToken() can only be used in browser environment'));
|
|
1331
1376
|
}
|
|
1332
1377
|
// Check if we're in an iframe
|
|
1333
|
-
if (
|
|
1378
|
+
if (!this.isInIframe()) {
|
|
1334
1379
|
return Promise.reject(new Error('getIframeToken() can only be used inside an iframe'));
|
|
1335
1380
|
}
|
|
1336
1381
|
const timeout = options?.timeout || 30000; // Default 30 seconds
|
|
@@ -2202,6 +2247,7 @@ class Toast {
|
|
|
2202
2247
|
}
|
|
2203
2248
|
// Create toast element
|
|
2204
2249
|
const toast = this.createToast(type, title, message, onClose);
|
|
2250
|
+
const toastId = toast.id;
|
|
2205
2251
|
// Add to container
|
|
2206
2252
|
this.container.appendChild(toast);
|
|
2207
2253
|
this.toasts.push(toast);
|
|
@@ -2209,11 +2255,17 @@ class Toast {
|
|
|
2209
2255
|
requestAnimationFrame(() => {
|
|
2210
2256
|
toast.classList.add('toast-show');
|
|
2211
2257
|
});
|
|
2212
|
-
// Auto-dismiss
|
|
2258
|
+
// Auto-dismiss with hover support
|
|
2213
2259
|
if (duration > 0) {
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2260
|
+
this.scheduleAutoDismiss(toast, duration, onClose);
|
|
2261
|
+
// Pause auto-dismiss on hover
|
|
2262
|
+
toast.addEventListener('mouseenter', () => {
|
|
2263
|
+
this.clearAutoDismiss(toastId);
|
|
2264
|
+
});
|
|
2265
|
+
// Resume auto-dismiss on leave
|
|
2266
|
+
toast.addEventListener('mouseleave', () => {
|
|
2267
|
+
this.scheduleAutoDismiss(toast, duration, onClose);
|
|
2268
|
+
});
|
|
2217
2269
|
}
|
|
2218
2270
|
}
|
|
2219
2271
|
/**
|
|
@@ -2427,6 +2479,30 @@ class Toast {
|
|
|
2427
2479
|
svg.appendChild(path);
|
|
2428
2480
|
return svg;
|
|
2429
2481
|
}
|
|
2482
|
+
/**
|
|
2483
|
+
* Schedule auto-dismiss for a toast
|
|
2484
|
+
*/
|
|
2485
|
+
static scheduleAutoDismiss(toast, duration, onClose) {
|
|
2486
|
+
const toastId = toast.id;
|
|
2487
|
+
// Clear existing timer if any
|
|
2488
|
+
this.clearAutoDismiss(toastId);
|
|
2489
|
+
// Schedule new timer
|
|
2490
|
+
const timer = setTimeout(() => {
|
|
2491
|
+
this.dismiss(toast, onClose);
|
|
2492
|
+
this.timers.delete(toastId);
|
|
2493
|
+
}, duration);
|
|
2494
|
+
this.timers.set(toastId, timer);
|
|
2495
|
+
}
|
|
2496
|
+
/**
|
|
2497
|
+
* Clear auto-dismiss timer for a toast
|
|
2498
|
+
*/
|
|
2499
|
+
static clearAutoDismiss(toastId) {
|
|
2500
|
+
const timer = this.timers.get(toastId);
|
|
2501
|
+
if (timer) {
|
|
2502
|
+
clearTimeout(timer);
|
|
2503
|
+
this.timers.delete(toastId);
|
|
2504
|
+
}
|
|
2505
|
+
}
|
|
2430
2506
|
/**
|
|
2431
2507
|
* Dismiss a toast
|
|
2432
2508
|
*/
|
|
@@ -2719,6 +2795,7 @@ Toast.container = null;
|
|
|
2719
2795
|
Toast.toasts = [];
|
|
2720
2796
|
Toast.nextId = 0;
|
|
2721
2797
|
Toast.cssInjected = false;
|
|
2798
|
+
Toast.timers = new Map();
|
|
2722
2799
|
|
|
2723
2800
|
class AuthModal {
|
|
2724
2801
|
constructor(options) {
|