@amaster.ai/auth-client 1.1.0-beta.7 → 1.1.0-beta.71
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 +90 -121
- package/dist/auth.d.cts +20 -4
- package/dist/auth.d.ts +20 -4
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/oauth.d.cts +1 -1
- package/dist/oauth.d.ts +1 -1
- package/dist/permissions.d.cts +1 -1
- package/dist/permissions.d.ts +1 -1
- package/dist/sessions.d.cts +1 -1
- package/dist/sessions.d.ts +1 -1
- package/dist/{types-C56GAJKY.d.cts → types-B76rOTYH.d.cts} +20 -1
- package/dist/{types-C56GAJKY.d.ts → types-B76rOTYH.d.ts} +20 -1
- package/dist/user.d.cts +1 -1
- package/dist/user.d.ts +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -8,6 +8,7 @@ Authentication SDK for Amaster Platform - Complete client-side authentication so
|
|
|
8
8
|
- 🔄 **Automatic Token Refresh**: JWT token auto-refresh before expiration
|
|
9
9
|
- 📦 **Token Storage**: localStorage or sessionStorage with SSR support
|
|
10
10
|
- 🎯 **Permission System**: Role-based and permission-based access control
|
|
11
|
+
- 👤 **Anonymous Access**: Automatic support for anonymous users with configurable permissions
|
|
11
12
|
- 🔗 **OAuth Integration**: Google, GitHub, WeChat OAuth, WeChat Mini Program, and custom OAuth providers
|
|
12
13
|
- 📡 **Event System**: Listen to login, logout, and token events
|
|
13
14
|
- 💾 **Session Management**: View and revoke active sessions
|
|
@@ -58,7 +59,7 @@ if (result.data) {
|
|
|
58
59
|
const user = await authClient.getMe();
|
|
59
60
|
|
|
60
61
|
// Check permissions
|
|
61
|
-
if (authClient.hasPermission("user
|
|
62
|
+
if (authClient.hasPermission("user", "read")) {
|
|
62
63
|
// Show user list
|
|
63
64
|
}
|
|
64
65
|
```
|
|
@@ -82,10 +83,10 @@ const authClient = createAuthClient();
|
|
|
82
83
|
|
|
83
84
|
```typescript
|
|
84
85
|
interface AuthClientOptions {
|
|
85
|
-
baseURL?: string;
|
|
86
|
+
baseURL?: string; // API base URL, defaults to window.location.origin
|
|
86
87
|
headers?: Record<string, string>; // Custom headers for all requests
|
|
87
|
-
onTokenExpired?: () => void;
|
|
88
|
-
onUnauthorized?: () => void;
|
|
88
|
+
onTokenExpired?: () => void; // Token expiration callback
|
|
89
|
+
onUnauthorized?: () => void; // Unauthorized (401) callback
|
|
89
90
|
}
|
|
90
91
|
```
|
|
91
92
|
|
|
@@ -94,19 +95,18 @@ interface AuthClientOptions {
|
|
|
94
95
|
```typescript
|
|
95
96
|
const authClient = createAuthClient({
|
|
96
97
|
baseURL: "https://api.example.com",
|
|
97
|
-
onTokenExpired: () => window.location.href = "/login",
|
|
98
|
+
onTokenExpired: () => (window.location.href = "/login"),
|
|
98
99
|
onUnauthorized: () => alert("Session expired"),
|
|
99
100
|
});
|
|
100
101
|
```
|
|
101
102
|
|
|
102
103
|
**Built-in Features (Zero Config):**
|
|
103
104
|
|
|
104
|
-
- ✅
|
|
105
|
-
- ✅
|
|
106
|
-
- ✅
|
|
107
|
-
- ✅
|
|
108
|
-
- ✅
|
|
109
|
-
- ✅ **On-Demand DataScope**: Loads only when needed
|
|
105
|
+
- ✅ Auto environment detection (browser, WeChat Mini Program, SSR)
|
|
106
|
+
- ✅ Auto token refresh (5 minutes before expiry)
|
|
107
|
+
- ✅ Auto permission sync
|
|
108
|
+
- ✅ Auto anonymous support
|
|
109
|
+
- ✅ Smart storage (localStorage, wx.storage, no-op for SSR)
|
|
110
110
|
|
|
111
111
|
## Authentication
|
|
112
112
|
|
|
@@ -180,15 +180,16 @@ const redirectUrl = sessionStorage.getItem("oauth_redirect") || "/";
|
|
|
180
180
|
window.location.href = redirectUrl;
|
|
181
181
|
```
|
|
182
182
|
|
|
183
|
+
If the callback page URL already carries `?redirect=...` such as
|
|
184
|
+
`/login?redirect=%2Fapi%2Foauth%2Fauthorize...`, the SDK will reuse that
|
|
185
|
+
redirect target automatically after a successful OAuth callback. Both
|
|
186
|
+
`#access_token=...` and `#accessToken=...` callback hash formats are supported.
|
|
187
|
+
|
|
183
188
|
**Popup window:**
|
|
184
189
|
|
|
185
190
|
```typescript
|
|
186
191
|
// Main page
|
|
187
|
-
const popup = window.open(
|
|
188
|
-
"/api/auth/oauth/google",
|
|
189
|
-
"oauth-login",
|
|
190
|
-
"width=600,height=700"
|
|
191
|
-
);
|
|
192
|
+
const popup = window.open("/api/auth/oauth/google", "oauth-login", "width=600,height=700");
|
|
192
193
|
|
|
193
194
|
window.addEventListener("message", (event) => {
|
|
194
195
|
if (event.data.type === "oauth-success") {
|
|
@@ -213,7 +214,7 @@ import { createAuthClient } from "@amaster.ai/auth-client";
|
|
|
213
214
|
|
|
214
215
|
// Zero configuration - auto-detects WeChat environment
|
|
215
216
|
const authClient = createAuthClient({
|
|
216
|
-
baseURL: "https://api.yourdomain.com"
|
|
217
|
+
baseURL: "https://api.yourdomain.com",
|
|
217
218
|
});
|
|
218
219
|
|
|
219
220
|
// Login with WeChat code
|
|
@@ -221,22 +222,22 @@ wx.login({
|
|
|
221
222
|
success: async (res) => {
|
|
222
223
|
if (res.code) {
|
|
223
224
|
const result = await authClient.loginWithMiniProgram(res.code);
|
|
224
|
-
|
|
225
|
+
|
|
225
226
|
if (result.data) {
|
|
226
227
|
console.log("Logged in:", result.data.user);
|
|
227
228
|
// Token automatically saved to wx.storage
|
|
228
|
-
wx.switchTab({ url:
|
|
229
|
+
wx.switchTab({ url: "/pages/index/index" });
|
|
229
230
|
} else if (result.error) {
|
|
230
231
|
wx.showToast({
|
|
231
|
-
title: result.error.message ||
|
|
232
|
-
icon:
|
|
232
|
+
title: result.error.message || "Login failed",
|
|
233
|
+
icon: "none",
|
|
233
234
|
});
|
|
234
235
|
}
|
|
235
236
|
}
|
|
236
237
|
},
|
|
237
238
|
fail: (err) => {
|
|
238
239
|
console.error("wx.login failed:", err);
|
|
239
|
-
}
|
|
240
|
+
},
|
|
240
241
|
});
|
|
241
242
|
```
|
|
242
243
|
|
|
@@ -244,8 +245,8 @@ wx.login({
|
|
|
244
245
|
|
|
245
246
|
```xml
|
|
246
247
|
<!-- WXML -->
|
|
247
|
-
<button
|
|
248
|
-
open-type="getPhoneNumber"
|
|
248
|
+
<button
|
|
249
|
+
open-type="getPhoneNumber"
|
|
249
250
|
bindgetphonenumber="onGetPhoneNumber"
|
|
250
251
|
>
|
|
251
252
|
Get Phone Number
|
|
@@ -256,14 +257,14 @@ wx.login({
|
|
|
256
257
|
// JS
|
|
257
258
|
async onGetPhoneNumber(e) {
|
|
258
259
|
const { code } = e.detail;
|
|
259
|
-
|
|
260
|
+
|
|
260
261
|
if (code) {
|
|
261
262
|
const result = await authClient.getMiniProgramPhoneNumber(code);
|
|
262
|
-
|
|
263
|
+
|
|
263
264
|
if (result.data) {
|
|
264
265
|
console.log("Phone number:", result.data.phone);
|
|
265
266
|
console.log("Verified:", result.data.phoneVerified);
|
|
266
|
-
|
|
267
|
+
|
|
267
268
|
// Update UI with phone number
|
|
268
269
|
this.setData({
|
|
269
270
|
phone: result.data.phone
|
|
@@ -288,13 +289,13 @@ async onGetPhoneNumber(e) {
|
|
|
288
289
|
import { createAuthClient } from "@amaster.ai/auth-client";
|
|
289
290
|
|
|
290
291
|
const authClient = createAuthClient({
|
|
291
|
-
baseURL: "https://api.yourdomain.com"
|
|
292
|
+
baseURL: "https://api.yourdomain.com",
|
|
292
293
|
});
|
|
293
294
|
|
|
294
295
|
Page({
|
|
295
296
|
data: {
|
|
296
297
|
userInfo: null,
|
|
297
|
-
hasPhone: false
|
|
298
|
+
hasPhone: false,
|
|
298
299
|
},
|
|
299
300
|
|
|
300
301
|
// Auto-login on page load
|
|
@@ -304,26 +305,26 @@ Page({
|
|
|
304
305
|
|
|
305
306
|
// WeChat Mini Program login
|
|
306
307
|
async handleLogin() {
|
|
307
|
-
wx.showLoading({ title:
|
|
308
|
-
|
|
308
|
+
wx.showLoading({ title: "Logging in..." });
|
|
309
|
+
|
|
309
310
|
wx.login({
|
|
310
311
|
success: async (res) => {
|
|
311
312
|
if (res.code) {
|
|
312
313
|
const result = await authClient.loginWithMiniProgram(res.code);
|
|
313
|
-
|
|
314
|
+
|
|
314
315
|
wx.hideLoading();
|
|
315
|
-
|
|
316
|
+
|
|
316
317
|
if (result.data) {
|
|
317
318
|
this.setData({
|
|
318
|
-
userInfo: result.data.user
|
|
319
|
+
userInfo: result.data.user,
|
|
319
320
|
});
|
|
320
|
-
|
|
321
|
+
|
|
321
322
|
// Navigate to home
|
|
322
|
-
wx.switchTab({ url:
|
|
323
|
+
wx.switchTab({ url: "/pages/index/index" });
|
|
323
324
|
} else {
|
|
324
325
|
wx.showToast({
|
|
325
|
-
title:
|
|
326
|
-
icon:
|
|
326
|
+
title: "Login failed",
|
|
327
|
+
icon: "none",
|
|
327
328
|
});
|
|
328
329
|
}
|
|
329
330
|
}
|
|
@@ -331,47 +332,47 @@ Page({
|
|
|
331
332
|
fail: () => {
|
|
332
333
|
wx.hideLoading();
|
|
333
334
|
wx.showToast({
|
|
334
|
-
title:
|
|
335
|
-
icon:
|
|
335
|
+
title: "Login failed",
|
|
336
|
+
icon: "none",
|
|
336
337
|
});
|
|
337
|
-
}
|
|
338
|
+
},
|
|
338
339
|
});
|
|
339
340
|
},
|
|
340
341
|
|
|
341
342
|
// Get phone number with user authorization
|
|
342
343
|
async onGetPhoneNumber(e) {
|
|
343
344
|
const { code } = e.detail;
|
|
344
|
-
|
|
345
|
+
|
|
345
346
|
if (!code) {
|
|
346
347
|
wx.showToast({
|
|
347
|
-
title:
|
|
348
|
-
icon:
|
|
348
|
+
title: "Authorization cancelled",
|
|
349
|
+
icon: "none",
|
|
349
350
|
});
|
|
350
351
|
return;
|
|
351
352
|
}
|
|
352
353
|
|
|
353
|
-
wx.showLoading({ title:
|
|
354
|
-
|
|
354
|
+
wx.showLoading({ title: "Getting phone..." });
|
|
355
|
+
|
|
355
356
|
const result = await authClient.getMiniProgramPhoneNumber(code);
|
|
356
|
-
|
|
357
|
+
|
|
357
358
|
wx.hideLoading();
|
|
358
|
-
|
|
359
|
+
|
|
359
360
|
if (result.data) {
|
|
360
361
|
this.setData({
|
|
361
|
-
hasPhone: true
|
|
362
|
+
hasPhone: true,
|
|
362
363
|
});
|
|
363
|
-
|
|
364
|
+
|
|
364
365
|
wx.showToast({
|
|
365
|
-
title:
|
|
366
|
-
icon:
|
|
366
|
+
title: "Phone number obtained",
|
|
367
|
+
icon: "success",
|
|
367
368
|
});
|
|
368
369
|
} else {
|
|
369
370
|
wx.showToast({
|
|
370
|
-
title: result.error?.message ||
|
|
371
|
-
icon:
|
|
371
|
+
title: result.error?.message || "Failed to get phone",
|
|
372
|
+
icon: "none",
|
|
372
373
|
});
|
|
373
374
|
}
|
|
374
|
-
}
|
|
375
|
+
},
|
|
375
376
|
});
|
|
376
377
|
```
|
|
377
378
|
|
|
@@ -412,67 +413,50 @@ await authClient.changePassword({
|
|
|
412
413
|
|
|
413
414
|
## Permission Checks
|
|
414
415
|
|
|
415
|
-
###
|
|
416
|
+
### Anonymous Access Support
|
|
416
417
|
|
|
417
|
-
|
|
418
|
+
The SDK automatically supports anonymous users with **zero configuration**:
|
|
418
419
|
|
|
419
420
|
```typescript
|
|
420
|
-
//
|
|
421
|
-
|
|
422
|
-
// Admin only
|
|
423
|
-
}
|
|
421
|
+
// Create client
|
|
422
|
+
const authClient = createAuthClient();
|
|
424
423
|
|
|
425
|
-
//
|
|
426
|
-
if (authClient.hasPermission("
|
|
427
|
-
|
|
424
|
+
// Permission checks work for both authenticated and anonymous users
|
|
425
|
+
if (authClient.hasPermission("article", "read")) {
|
|
426
|
+
showArticleList();
|
|
428
427
|
}
|
|
429
428
|
|
|
430
|
-
// Check
|
|
431
|
-
if (authClient.
|
|
432
|
-
|
|
429
|
+
// Check if user is anonymous
|
|
430
|
+
if (authClient.isAnonymous()) {
|
|
431
|
+
showLoginPrompt();
|
|
433
432
|
}
|
|
434
433
|
|
|
435
|
-
//
|
|
436
|
-
|
|
437
|
-
// Has all permissions
|
|
438
|
-
}
|
|
434
|
+
// After login, permissions automatically update
|
|
435
|
+
await authClient.login({ ... });
|
|
439
436
|
```
|
|
440
437
|
|
|
441
|
-
###
|
|
438
|
+
### Local Permission Checks (Fast)
|
|
442
439
|
|
|
443
|
-
|
|
440
|
+
Permissions are cached locally for fast UI checks:
|
|
444
441
|
|
|
445
442
|
```typescript
|
|
446
|
-
//
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
const { dataScope } = result.data;
|
|
450
|
-
|
|
451
|
-
if (dataScope.scopeType === "department") {
|
|
452
|
-
// Filter users by department
|
|
453
|
-
const users = await api.getUsers({
|
|
454
|
-
departmentId: dataScope.scopeFilter.departmentId
|
|
455
|
-
});
|
|
456
|
-
} else if (dataScope.scopeType === "all") {
|
|
457
|
-
// Show all users
|
|
458
|
-
const users = await api.getUsers();
|
|
459
|
-
}
|
|
443
|
+
// Check role
|
|
444
|
+
if (authClient.hasRole("admin")) {
|
|
445
|
+
showAdminPanel();
|
|
460
446
|
}
|
|
461
|
-
```
|
|
462
447
|
|
|
463
|
-
|
|
448
|
+
if (authClient.isAnonymous()) {
|
|
449
|
+
showLoginPrompt();
|
|
450
|
+
}
|
|
464
451
|
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
uid: "xxx",
|
|
469
|
-
email: "user@example.com",
|
|
470
|
-
roles: ["admin", "user"], // Only role codes
|
|
471
|
-
permissions: ["user.read", "user.write", "order.read"], // Only permission names
|
|
472
|
-
// NO dataScopes - loaded on demand
|
|
452
|
+
// Check permission
|
|
453
|
+
if (authClient.hasPermission("user", "read")) {
|
|
454
|
+
showUserList();
|
|
473
455
|
}
|
|
474
456
|
```
|
|
475
457
|
|
|
458
|
+
````
|
|
459
|
+
|
|
476
460
|
## OAuth Bindings
|
|
477
461
|
|
|
478
462
|
### Get Bindings
|
|
@@ -613,48 +597,32 @@ if (result.error) {
|
|
|
613
597
|
|
|
614
598
|
### Token Management
|
|
615
599
|
|
|
616
|
-
-
|
|
617
|
-
- Access Token
|
|
618
|
-
-
|
|
619
|
-
- Token is automatically refreshed 5 minutes before expiration (configurable)
|
|
620
|
-
|
|
621
|
-
### Permission Sync
|
|
622
|
-
|
|
623
|
-
- **On Page Load**: User info and permissions automatically sync from backend
|
|
624
|
-
- **On Token Refresh**: Permissions re-sync every 5 minutes when token refreshes
|
|
625
|
-
- **Manual Sync**: Call `await authClient.getMe()` to force sync anytime
|
|
626
|
-
|
|
627
|
-
**Behavior:**
|
|
628
|
-
- Permissions always stay fresh without any configuration
|
|
629
|
-
- Page refresh loads latest permissions from backend
|
|
630
|
-
- Background sync happens automatically every 5 minutes
|
|
600
|
+
- Tokens are automatically managed by the SDK
|
|
601
|
+
- Access Token refreshes 5 minutes before expiration
|
|
602
|
+
- No manual token handling required
|
|
631
603
|
|
|
632
604
|
### Permission Checks
|
|
633
605
|
|
|
634
|
-
-
|
|
635
|
-
-
|
|
636
|
-
-
|
|
606
|
+
- Use permission checks for UI control (show/hide buttons, menus)
|
|
607
|
+
- Frontend checks are NOT security measures
|
|
608
|
+
- Backend must always verify permissions
|
|
637
609
|
|
|
638
610
|
### SSR Support
|
|
639
611
|
|
|
640
|
-
The SDK
|
|
612
|
+
The SDK works in both browser and SSR environments:
|
|
641
613
|
|
|
642
614
|
```typescript
|
|
643
|
-
// Safe in both browser and SSR
|
|
644
615
|
const authClient = createAuthClient();
|
|
645
616
|
```
|
|
646
617
|
|
|
647
618
|
## TypeScript
|
|
648
619
|
|
|
649
|
-
Full TypeScript support
|
|
620
|
+
Full TypeScript support:
|
|
650
621
|
|
|
651
622
|
```typescript
|
|
652
623
|
import type {
|
|
653
624
|
User,
|
|
654
625
|
LoginResponse,
|
|
655
|
-
Permission,
|
|
656
|
-
Role,
|
|
657
|
-
DataScope,
|
|
658
626
|
Session,
|
|
659
627
|
OAuthBinding,
|
|
660
628
|
} from "@amaster.ai/auth-client";
|
|
@@ -667,3 +635,4 @@ MIT
|
|
|
667
635
|
## Contributing
|
|
668
636
|
|
|
669
637
|
Contributions are welcome! Please read our contributing guidelines before submitting PRs.
|
|
638
|
+
````
|
package/dist/auth.d.cts
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* ============================================================================
|
|
15
15
|
*/
|
|
16
16
|
import { HttpClient, ClientResult } from '@amaster.ai/http-client';
|
|
17
|
-
import { q as User, i as RegisterParams, e as LoginResponse, L as LoginParams, c as CodeLoginParams, S as SendCodeParams, p as SuccessResponse, b as CaptchaResponse, g as OAuthProvider, M as MiniProgramPhoneResponse, R as RefreshTokenResponse } from './types-
|
|
17
|
+
import { q as User, i as RegisterParams, e as LoginResponse, L as LoginParams, c as CodeLoginParams, S as SendCodeParams, p as SuccessResponse, b as CaptchaResponse, g as OAuthProvider, M as MiniProgramPhoneResponse, R as RefreshTokenResponse } from './types-B76rOTYH.cjs';
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
20
|
* Authentication Module
|
|
@@ -30,11 +30,15 @@ import { q as User, i as RegisterParams, e as LoginResponse, L as LoginParams, c
|
|
|
30
30
|
* - Logout and token refresh
|
|
31
31
|
*/
|
|
32
32
|
|
|
33
|
+
declare const browserNavigation: {
|
|
34
|
+
replace(url: string): void;
|
|
35
|
+
};
|
|
33
36
|
interface AuthModuleDeps {
|
|
34
37
|
http: HttpClient;
|
|
35
38
|
onLoginSuccess: (user: User, accessToken: string) => void;
|
|
36
39
|
storage: {
|
|
37
40
|
getItem: (key: string) => string | null;
|
|
41
|
+
setItem: (key: string, value: string) => void;
|
|
38
42
|
};
|
|
39
43
|
clearAuth: () => void;
|
|
40
44
|
}
|
|
@@ -59,8 +63,14 @@ declare function createAuthModule(deps: AuthModuleDeps): {
|
|
|
59
63
|
* @category Authentication
|
|
60
64
|
* @example
|
|
61
65
|
* ```typescript
|
|
66
|
+
* // Auto-detect loginType from username
|
|
67
|
+
* await auth.login({
|
|
68
|
+
* username: "john_doe",
|
|
69
|
+
* password: "Password@123",
|
|
70
|
+
* });
|
|
71
|
+
*
|
|
72
|
+
* // Auto-detect loginType from email
|
|
62
73
|
* await auth.login({
|
|
63
|
-
* loginType: "email",
|
|
64
74
|
* email: "user@example.com",
|
|
65
75
|
* password: "Password@123",
|
|
66
76
|
* });
|
|
@@ -73,11 +83,17 @@ declare function createAuthModule(deps: AuthModuleDeps): {
|
|
|
73
83
|
* @category Authentication
|
|
74
84
|
* @example
|
|
75
85
|
* ```typescript
|
|
86
|
+
* // Auto-detect loginType from email
|
|
76
87
|
* await auth.loginWithCode({
|
|
77
|
-
* loginType: "email",
|
|
78
88
|
* email: "user@example.com",
|
|
79
89
|
* code: "123456",
|
|
80
90
|
* });
|
|
91
|
+
*
|
|
92
|
+
* // Auto-detect loginType from phone
|
|
93
|
+
* await auth.loginWithCode({
|
|
94
|
+
* phone: "13800138000",
|
|
95
|
+
* code: "123456",
|
|
96
|
+
* });
|
|
81
97
|
* ```
|
|
82
98
|
*/
|
|
83
99
|
loginWithCode(params: CodeLoginParams): Promise<ClientResult<LoginResponse>>;
|
|
@@ -180,4 +196,4 @@ declare function createAuthModule(deps: AuthModuleDeps): {
|
|
|
180
196
|
};
|
|
181
197
|
type AuthModule = ReturnType<typeof createAuthModule>;
|
|
182
198
|
|
|
183
|
-
export { type AuthModule, type AuthModuleDeps, createAuthModule };
|
|
199
|
+
export { type AuthModule, type AuthModuleDeps, browserNavigation, createAuthModule };
|
package/dist/auth.d.ts
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* ============================================================================
|
|
15
15
|
*/
|
|
16
16
|
import { HttpClient, ClientResult } from '@amaster.ai/http-client';
|
|
17
|
-
import { q as User, i as RegisterParams, e as LoginResponse, L as LoginParams, c as CodeLoginParams, S as SendCodeParams, p as SuccessResponse, b as CaptchaResponse, g as OAuthProvider, M as MiniProgramPhoneResponse, R as RefreshTokenResponse } from './types-
|
|
17
|
+
import { q as User, i as RegisterParams, e as LoginResponse, L as LoginParams, c as CodeLoginParams, S as SendCodeParams, p as SuccessResponse, b as CaptchaResponse, g as OAuthProvider, M as MiniProgramPhoneResponse, R as RefreshTokenResponse } from './types-B76rOTYH.js';
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
20
|
* Authentication Module
|
|
@@ -30,11 +30,15 @@ import { q as User, i as RegisterParams, e as LoginResponse, L as LoginParams, c
|
|
|
30
30
|
* - Logout and token refresh
|
|
31
31
|
*/
|
|
32
32
|
|
|
33
|
+
declare const browserNavigation: {
|
|
34
|
+
replace(url: string): void;
|
|
35
|
+
};
|
|
33
36
|
interface AuthModuleDeps {
|
|
34
37
|
http: HttpClient;
|
|
35
38
|
onLoginSuccess: (user: User, accessToken: string) => void;
|
|
36
39
|
storage: {
|
|
37
40
|
getItem: (key: string) => string | null;
|
|
41
|
+
setItem: (key: string, value: string) => void;
|
|
38
42
|
};
|
|
39
43
|
clearAuth: () => void;
|
|
40
44
|
}
|
|
@@ -59,8 +63,14 @@ declare function createAuthModule(deps: AuthModuleDeps): {
|
|
|
59
63
|
* @category Authentication
|
|
60
64
|
* @example
|
|
61
65
|
* ```typescript
|
|
66
|
+
* // Auto-detect loginType from username
|
|
67
|
+
* await auth.login({
|
|
68
|
+
* username: "john_doe",
|
|
69
|
+
* password: "Password@123",
|
|
70
|
+
* });
|
|
71
|
+
*
|
|
72
|
+
* // Auto-detect loginType from email
|
|
62
73
|
* await auth.login({
|
|
63
|
-
* loginType: "email",
|
|
64
74
|
* email: "user@example.com",
|
|
65
75
|
* password: "Password@123",
|
|
66
76
|
* });
|
|
@@ -73,11 +83,17 @@ declare function createAuthModule(deps: AuthModuleDeps): {
|
|
|
73
83
|
* @category Authentication
|
|
74
84
|
* @example
|
|
75
85
|
* ```typescript
|
|
86
|
+
* // Auto-detect loginType from email
|
|
76
87
|
* await auth.loginWithCode({
|
|
77
|
-
* loginType: "email",
|
|
78
88
|
* email: "user@example.com",
|
|
79
89
|
* code: "123456",
|
|
80
90
|
* });
|
|
91
|
+
*
|
|
92
|
+
* // Auto-detect loginType from phone
|
|
93
|
+
* await auth.loginWithCode({
|
|
94
|
+
* phone: "13800138000",
|
|
95
|
+
* code: "123456",
|
|
96
|
+
* });
|
|
81
97
|
* ```
|
|
82
98
|
*/
|
|
83
99
|
loginWithCode(params: CodeLoginParams): Promise<ClientResult<LoginResponse>>;
|
|
@@ -180,4 +196,4 @@ declare function createAuthModule(deps: AuthModuleDeps): {
|
|
|
180
196
|
};
|
|
181
197
|
type AuthModule = ReturnType<typeof createAuthModule>;
|
|
182
198
|
|
|
183
|
-
export { type AuthModule, type AuthModuleDeps, createAuthModule };
|
|
199
|
+
export { type AuthModule, type AuthModuleDeps, browserNavigation, createAuthModule };
|
package/dist/index.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
'use strict';var httpClient=require('@amaster.ai/http-client');var y=class{constructor(){this.events={};}on(e,r){this.events[e]||(this.events[e]=[]),this.events[e].push(r);}off(e,r){this.events[e]&&(this.events[e]=this.events[e].filter(t=>t!==r));}emit(e,...r){this.events[e]&&this.events[e].forEach(t=>{try{t(...r);}catch(a){console.error(`[AuthClient] Error in event handler for "${e}":`,a);}});}removeAllListeners(){this.events={};}};var l={ACCESS_TOKEN:"amaster_access_token",REFRESH_TOKEN:"amaster_refresh_token",USER:"amaster_user"};function N(){return typeof wx<"u"&&wx.getStorageSync?"wechat-miniprogram":typeof window<"u"&&typeof window.localStorage<"u"?"browser":"node"}function S(){switch(N()){case "wechat-miniprogram":return $();case "browser":return L();case "node":return q()}}function L(){let s=window.localStorage;return {getItem(e){try{return s.getItem(e)}catch(r){return console.error("[AuthClient] Failed to get item from localStorage:",r),null}},setItem(e,r){try{s.setItem(e,r);}catch(t){console.error("[AuthClient] Failed to set item in localStorage:",t);}},removeItem(e){try{s.removeItem(e);}catch(r){console.error("[AuthClient] Failed to remove item from localStorage:",r);}},clear(){try{s.removeItem(l.ACCESS_TOKEN),s.removeItem(l.REFRESH_TOKEN),s.removeItem(l.USER);}catch(e){console.error("[AuthClient] Failed to clear localStorage:",e);}}}}function $(){return {getItem(s){try{return wx.getStorageSync(s)||null}catch(e){return console.error("[AuthClient] Failed to get item from WeChat storage:",e),null}},setItem(s,e){try{wx.setStorageSync(s,e);}catch(r){console.error("[AuthClient] Failed to set item in WeChat storage:",r);}},removeItem(s){try{wx.removeStorageSync(s);}catch(e){console.error("[AuthClient] Failed to remove item from WeChat storage:",e);}},clear(){try{wx.removeStorageSync(l.ACCESS_TOKEN),wx.removeStorageSync(l.REFRESH_TOKEN),wx.removeStorageSync(l.USER);}catch(s){console.error("[AuthClient] Failed to clear WeChat storage:",s);}}}}function q(){let s=new Map;return {getItem(e){return s.get(e)??null},setItem(e,r){s.set(e,r);},removeItem(e){s.delete(e);},clear(){s.clear();}}}function B(s){try{let e=s.split(".");if(e.length!==3)return null;let t=(e[1]||"").replace(/-/g,"+").replace(/_/g,"/");if(typeof atob<"u"){let a=decodeURIComponent(atob(t).split("").map(o=>"%"+("00"+o.charCodeAt(0).toString(16)).slice(-2)).join(""));return JSON.parse(a)}if(typeof Buffer<"u"){let a=Buffer.from(t,"base64").toString("utf-8");return JSON.parse(a)}return null}catch(e){return console.error("[AuthClient] Failed to parse JWT token:",e),null}}var C=class{constructor(){this.refreshTimer=null;this.isRefreshing=false;this.refreshCallback=null;}setRefreshCallback(e){this.refreshCallback=e;}scheduleRefresh(e){this.clearSchedule(),!(e<=0)&&(this.refreshTimer=setTimeout(()=>{this.refresh();},e));}scheduleRefreshFromToken(e,r=300){let t=B(e);if(!t||!t.exp){console.warn("[AuthClient] Cannot schedule refresh: invalid token or missing exp claim");return}let a=t.exp*1e3,o=Date.now(),c=a-o-r*1e3;c<=0?(console.warn("[AuthClient] Token already expired or expiring soon, refreshing immediately"),this.refresh()):this.scheduleRefresh(c);}async refresh(){if(!this.isRefreshing){if(!this.refreshCallback){console.error("[AuthClient] No refresh callback set");return}this.isRefreshing=true;try{await this.refreshCallback();}catch(e){console.error("[AuthClient] Token refresh failed:",e);}finally{this.isRefreshing=false;}}}clearSchedule(){this.refreshTimer&&(clearTimeout(this.refreshTimer),this.refreshTimer=null);}isCurrentlyRefreshing(){return this.isRefreshing}destroy(){this.clearSchedule(),this.refreshCallback=null,this.isRefreshing=false;}};function v(s){return s&&typeof s=="object"&&("statusCode"in s||"status"in s)&&"data"in s?s.data:s}var R={transformResponse:v,logErrors:true};function k(s){let{http:e,onLoginSuccess:r,storage:t,clearAuth:a}=s;return {async register(o){let n=await e.request({url:"/api/auth/register",method:"post",headers:{"Content-Type":"application/json"},data:o});return n.data?.user&&n.data?.accessToken&&r(n.data.user,n.data.accessToken),n},async login(o){let n=await e.request({url:"/api/auth/login",method:"post",headers:{"Content-Type":"application/json"},data:o});return n.data?.user&&n.data?.accessToken&&r(n.data.user,n.data.accessToken),n},async loginWithCode(o){let n=await e.request({url:"/api/auth/login-with-code",method:"post",headers:{"Content-Type":"application/json"},data:o});return n.data?.user&&n.data?.accessToken&&r(n.data.user,n.data.accessToken),n},async sendCode(o){return e.request({url:"/api/auth/send-code",method:"post",headers:{"Content-Type":"application/json"},data:o})},async getCaptcha(){return e.request({url:"/api/auth/captcha",method:"get"})},loginWithOAuth(o,n){if(typeof window>"u"){console.error("[AuthClient] OAuth login is only available in browser environment");return}let c=n?`/api/auth/oauth/${o}?redirect_url=${encodeURIComponent(n)}`:`/api/auth/oauth/${o}`;window.location.href=c;},async handleOAuthCallback(){if(typeof window>"u")return {data:null,error:{message:"OAuth callback is only available in browser environment",status:400},status:400};try{let o=window.location.hash.substring(1),n=new URLSearchParams(o),c=n.get("access_token"),h=n.get("user");if(!c||!h)return {data:null,error:{message:"OAuth callback failed: missing token or user data",status:400},status:400};let u=JSON.parse(decodeURIComponent(h));return r(u,c),{data:{user:u,accessToken:c},error:null,status:200}}catch(o){return {data:null,error:{message:`OAuth callback failed: ${o instanceof Error?o.message:String(o)}`,status:400},status:400}}},async loginWithMiniProgram(o){let n=await e.request({url:"/api/auth/miniprogram/login",method:"post",headers:{"Content-Type":"application/json"},data:{code:o}});return n.data?.user&&n.data?.accessToken&&r(n.data.user,n.data.accessToken),n},async getMiniProgramPhoneNumber(o){let n=t.getItem("amaster_access_token");return n?e.request({url:"/api/auth/miniprogram/phone",method:"post",headers:{"Content-Type":"application/json",Authorization:`Bearer ${n}`},data:{code:o}}):{data:null,error:{message:"Not authenticated",status:401},status:401}},async logout(){let o=t.getItem("amaster_access_token"),n=await e.request({url:"/api/auth/logout",method:"post",headers:o?{Authorization:`Bearer ${o}`}:void 0});return a(),n},async refreshToken(){return e.request({url:"/api/auth/refresh",method:"post"})}}}function P(s){let{getCurrentUser:e}=s;return {hasRole(r){let t=e();return !t||!t.roles?false:t.roles.includes(r)},hasPermission(r,t){let a=e();if(!a||!a.permissions)return false;let o=`${r}:${t}`;return a.permissions.includes(o)},hasAnyPermission(r){return r.some(({resource:t,action:a})=>this.hasPermission(t,a))},hasAllPermissions(r){return r.every(({resource:t,action:a})=>this.hasPermission(t,a))}}}function T(s){let{http:e,storage:r,onUserUpdate:t}=s;return {async getMe(){let a=r.getItem("amaster_access_token");if(!a)return {data:null,error:{message:"Not authenticated",status:401},status:401};let o=await e.request({url:"/api/auth/me",method:"get",headers:{Authorization:`Bearer ${a}`}});return o.data&&t(o.data),o},async updateMe(a){let o=r.getItem("amaster_access_token");if(!o)return {data:null,error:{message:"Not authenticated",status:401},status:401};let n=await e.request({url:"/api/auth/me",method:"put",headers:{Authorization:`Bearer ${o}`,"Content-Type":"application/json"},data:a});return n.data&&t(n.data),n},async changePassword(a){let o=r.getItem("amaster_access_token");return o?e.request({url:"/api/auth/change-password",method:"post",headers:{Authorization:`Bearer ${o}`,"Content-Type":"application/json"},data:a}):{data:null,error:{message:"Not authenticated",status:401},status:401}}}}function w(s){let{http:e,storage:r}=s;return {async getOAuthBindings(){let t=r.getItem("amaster_access_token");return t?e.request({url:"/api/auth/oauth-bindings",method:"get",headers:{Authorization:`Bearer ${t}`}}):{data:null,error:{message:"Not authenticated",status:401},status:401}},bindOAuth(t){if(typeof window>"u"){console.error("[AuthClient] OAuth binding is only available in browser environment");return}window.location.href=`/api/auth/oauth/${t}/bind`;},async unbindOAuth(t){let a=r.getItem("amaster_access_token");return a?e.request({url:`/api/auth/oauth/${t}/unbind`,method:"delete",headers:{Authorization:`Bearer ${a}`}}):{data:null,error:{message:"Not authenticated",status:401},status:401}}}}function E(s){let{http:e,storage:r}=s;return {async getSession(){let t=r.getItem("amaster_access_token");return t?e.request({url:"/api/auth/sessions/current",method:"get",headers:{Authorization:`Bearer ${t}`}}):{data:null,error:{message:"Not authenticated",status:401},status:401}},async getSessions(){let t=r.getItem("amaster_access_token");return t?e.request({url:"/api/auth/sessions",method:"get",headers:{Authorization:`Bearer ${t}`}}):{data:null,error:{message:"Not authenticated",status:401},status:401}},async revokeSession(t){let a=r.getItem("amaster_access_token");return a?t?e.request({url:`/api/auth/sessions/${t}`,method:"delete",headers:{Authorization:`Bearer ${a}`}}):{data:null,error:{message:"Session ID is required",status:400},status:400}:{data:null,error:{message:"Not authenticated",status:401},status:401}},async revokeAllSessions(){let t=r.getItem("amaster_access_token");return t?e.request({url:"/api/auth/sessions",method:"delete",headers:{Authorization:`Bearer ${t}`}}):{data:null,error:{message:"Not authenticated",status:401},status:401}}}}function z(s={},e){let {baseURL:r,headers:t,onTokenExpired:a,onUnauthorized:o}=s,n=e||httpClient.createHttpClient({...R,baseURL:r,headers:t}),h=300,u=S(),m=new y,f=new C,g=null;try{let i=u.getItem(l.USER);i&&(g=JSON.parse(i));}catch(i){console.error("[AuthClient] Failed to load user from storage:",i);}let d;f.setRefreshCallback(async()=>{let i=await d.refreshToken();i.data?(await d.getMe(),m.emit("tokenRefreshed",i.data.accessToken)):(m.emit("tokenExpired"),a?.());});function M(i,p){u.setItem(l.ACCESS_TOKEN,p),u.setItem(l.USER,JSON.stringify(i)),g=i,f.scheduleRefreshFromToken(p,h),m.emit("login",i);}function O(i){g=i,u.setItem(l.USER,JSON.stringify(i));}function A(){u.clear(),g=null,f.clearSchedule();}function U(){return g}let b=k({http:n,onLoginSuccess:M,storage:u,clearAuth:A}),x=P({getCurrentUser:U}),I=T({http:n,storage:u,onUserUpdate:O}),_=w({http:n,storage:u}),H=E({http:n,storage:u});return d={...b,...x,...I,..._,...H,on(i,p){m.on(i,p);},off(i,p){m.off(i,p);},isAuthenticated(){return !!u.getItem(l.ACCESS_TOKEN)},getAccessToken(){return u.getItem(l.ACCESS_TOKEN)},setAccessToken(i){u.setItem(l.ACCESS_TOKEN,i),f.scheduleRefreshFromToken(i,h);},clearAuth:A},d.on("unauthorized",()=>{o?.();}),d.isAuthenticated()&&d.getMe().catch(i=>{console.warn("[AuthClient] Failed to sync user info on init:",i);}),d}exports.createAuthClient=z;exports.defaultHttpClientOptions=R;exports.transformAmasterResponse=v;//# sourceMappingURL=index.cjs.map
|
|
1
|
+
'use strict';var httpClient=require('@amaster.ai/http-client');var C=class{constructor(){this.events={};}on(e,n){this.events[e]||(this.events[e]=[]),this.events[e].push(n);}off(e,n){this.events[e]&&(this.events[e]=this.events[e].filter(r=>r!==n));}emit(e,...n){this.events[e]&&this.events[e].forEach(r=>{try{r(...n);}catch(a){console.error(`[AuthClient] Error in event handler for "${e}":`,a);}});}removeAllListeners(){this.events={};}};var d={ACCESS_TOKEN:"amaster_access_token",REFRESH_TOKEN:"amaster_refresh_token",USER:"amaster_user"};function N(){return typeof wx<"u"&&wx.getStorageSync?"wechat-miniprogram":typeof window<"u"&&typeof window.localStorage<"u"?"browser":"node"}function v(){switch(N()){case "wechat-miniprogram":return q();case "browser":return $();case "node":return B()}}function $(){let t=window.localStorage;return {getItem(e){try{return t.getItem(e)}catch(n){return console.error("[AuthClient] Failed to get item from localStorage:",n),null}},setItem(e,n){try{t.setItem(e,n);}catch(r){console.error("[AuthClient] Failed to set item in localStorage:",r);}},removeItem(e){try{t.removeItem(e);}catch(n){console.error("[AuthClient] Failed to remove item from localStorage:",n);}},clear(){try{t.removeItem(d.ACCESS_TOKEN),t.removeItem(d.REFRESH_TOKEN),t.removeItem(d.USER);}catch(e){console.error("[AuthClient] Failed to clear localStorage:",e);}}}}function q(){return {getItem(t){try{return wx.getStorageSync(t)||null}catch(e){return console.error("[AuthClient] Failed to get item from WeChat storage:",e),null}},setItem(t,e){try{wx.setStorageSync(t,e);}catch(n){console.error("[AuthClient] Failed to set item in WeChat storage:",n);}},removeItem(t){try{wx.removeStorageSync(t);}catch(e){console.error("[AuthClient] Failed to remove item from WeChat storage:",e);}},clear(){try{wx.removeStorageSync(d.ACCESS_TOKEN),wx.removeStorageSync(d.REFRESH_TOKEN),wx.removeStorageSync(d.USER);}catch(t){console.error("[AuthClient] Failed to clear WeChat storage:",t);}}}}function B(){let t=new Map;return {getItem(e){return t.get(e)??null},setItem(e,n){t.set(e,n);},removeItem(e){t.delete(e);},clear(){t.clear();}}}function F(t){try{let e=t.split(".");if(e.length!==3)return null;let r=(e[1]||"").replace(/-/g,"+").replace(/_/g,"/");if(typeof atob<"u"){let a=decodeURIComponent(atob(r).split("").map(s=>"%"+("00"+s.charCodeAt(0).toString(16)).slice(-2)).join(""));return JSON.parse(a)}if(typeof Buffer<"u"){let a=Buffer.from(r,"base64").toString("utf-8");return JSON.parse(a)}return null}catch(e){return console.error("[AuthClient] Failed to parse JWT token:",e),null}}var A=class{constructor(){this.refreshTimer=null;this.isRefreshing=false;this.refreshCallback=null;}setRefreshCallback(e){this.refreshCallback=e;}scheduleRefresh(e){this.clearSchedule(),!(e<=0)&&(this.refreshTimer=setTimeout(()=>{this.refresh();},e));}scheduleRefreshFromToken(e,n=300){let r=F(e);if(!r||!r.exp){console.warn("[AuthClient] Cannot schedule refresh: invalid token or missing exp claim");return}let a=r.exp*1e3,s=Date.now(),c=a-s-n*1e3;c<=0?(console.warn("[AuthClient] Token already expired or expiring soon, refreshing immediately"),this.refresh()):this.scheduleRefresh(c);}async refresh(){if(!this.isRefreshing){if(!this.refreshCallback){console.error("[AuthClient] No refresh callback set");return}this.isRefreshing=true;try{await this.refreshCallback();}catch(e){console.error("[AuthClient] Token refresh failed:",e);}finally{this.isRefreshing=false;}}}clearSchedule(){this.refreshTimer&&(clearTimeout(this.refreshTimer),this.refreshTimer=null);}isCurrentlyRefreshing(){return this.isRefreshing}destroy(){this.clearSchedule(),this.refreshCallback=null,this.isRefreshing=false;}};function k(t){return t&&typeof t=="object"&&("statusCode"in t||"status"in t)&&"data"in t?t.data:t}var R={transformResponse:k,logErrors:true};function z(t){if(t.email)return "email";if(t.username)return "username";if(t.phone)return "phone"}function K(t){if(t.email)return "email";if(t.phone)return "phone"}function j(t){let e=new URLSearchParams(t);return e.get("access_token")||e.get("accessToken")}function J(t){return new URLSearchParams(t).get("user")}function D(){if(typeof window>"u")return null;try{let t=new URLSearchParams(window.location.search).get("redirect");if(!t)return null;let e=new URL(t,window.location.origin);return e.origin!==window.location.origin?(console.warn("[AuthClient] Ignored cross-origin redirect target:",t),null):`${e.pathname}${e.search}${e.hash}`}catch(t){return console.warn("[AuthClient] Failed to resolve redirect target:",t),null}}var W={replace(t){window.location.replace(t);}};function w(t){let{http:e,onLoginSuccess:n,storage:r,clearAuth:a}=t;return {async register(s){let o=await e.request({url:"/api/auth/register",method:"post",headers:{"Content-Type":"application/json"},data:s});return o.data?.user&&o.data?.accessToken&&n(o.data.user,o.data.accessToken),o},async login(s){let o=s.loginType||z(s);if(!o)return {data:null,error:{message:"Unable to determine login type. Please provide email, username, or phone.",status:400},status:400};let c={...s,loginType:o},l=await e.request({url:"/api/auth/login",method:"post",headers:{"Content-Type":"application/json"},data:c});return l.data?.user&&l.data?.accessToken&&n(l.data.user,l.data.accessToken),l},async loginWithCode(s){let o=s.loginType||K(s);if(!o)return {data:null,error:{message:"Unable to determine login type. Please provide email or phone.",status:400},status:400};let c={...s,loginType:o},l=await e.request({url:"/api/auth/login-with-code",method:"post",headers:{"Content-Type":"application/json"},data:c});return l.data?.user&&l.data?.accessToken&&n(l.data.user,l.data.accessToken),l},async sendCode(s){return e.request({url:"/api/auth/send-code",method:"post",headers:{"Content-Type":"application/json"},data:s})},async getCaptcha(){return e.request({url:"/api/auth/captcha",method:"get"})},loginWithOAuth(s,o){if(typeof window>"u"){console.error("[AuthClient] OAuth login is only available in browser environment");return}let c=o?`/api/auth/oauth/${s}?redirect_url=${encodeURIComponent(o)}`:`/api/auth/oauth/${s}`;window.location.href=c;},async handleOAuthCallback(){if(typeof window>"u")return {data:null,error:{message:"OAuth callback is only available in browser environment",status:400},status:400};try{let s=window.location.hash.substring(1),o=j(s),c=J(s);if(!o)return {data:null,error:{message:"OAuth callback failed: missing access token",status:400},status:400};let l;if(c)l=JSON.parse(decodeURIComponent(c));else {r.setItem(d.ACCESS_TOKEN,o);let u=await e.request({url:"/api/auth/me",method:"get",headers:{Authorization:`Bearer ${o}`}});if(!u.data)return {data:null,error:{message:"OAuth callback failed: unable to fetch user info",status:u.status||500},status:u.status||500};l=u.data;}if(n(l,o),window.history&&window.history.replaceState){let u=window.location.pathname+window.location.search;window.history.replaceState(null,"",u);}else window.location.hash="";let m=D();return m&&!window.opener&&W.replace(m),{data:{user:l,accessToken:o},error:null,status:200}}catch(s){return {data:null,error:{message:`OAuth callback failed: ${s instanceof Error?s.message:String(s)}`,status:400},status:400}}},async loginWithMiniProgram(s){let o=await e.request({url:"/api/auth/miniprogram/login",method:"post",headers:{"Content-Type":"application/json"},data:{code:s}});return o.data?.user&&o.data?.accessToken&&n(o.data.user,o.data.accessToken),o},async getMiniProgramPhoneNumber(s){let o=r.getItem("amaster_access_token");return o?e.request({url:"/api/auth/miniprogram/phone",method:"post",headers:{"Content-Type":"application/json",Authorization:`Bearer ${o}`},data:{code:s}}):{data:null,error:{message:"Not authenticated",status:401},status:401}},async logout(){let s=r.getItem("amaster_access_token"),o=await e.request({url:"/api/auth/logout",method:"post",headers:s?{Authorization:`Bearer ${s}`}:void 0});return a(),o},async refreshToken(){let s=await e.request({url:"/api/auth/refresh",method:"post"});return s.data?.accessToken&&r.setItem("amaster_access_token",s.data.accessToken),s}}}function T(t){let{getCurrentUser:e}=t;return {hasRole(n){let r=e();return !r||!r.roles?false:r.roles.includes(n)},hasPermission(n,r){let a=e();if(!a||!a.permissions)return false;let s=`${n}.${r}`;return a.permissions.includes(s)},hasAnyPermission(n){return n.some(({resource:r,action:a})=>this.hasPermission(r,a))},hasAllPermissions(n){return n.every(({resource:r,action:a})=>this.hasPermission(r,a))}}}function P(t){let{http:e,storage:n,onUserUpdate:r}=t;return {async getMe(){let a=n.getItem("amaster_access_token");if(!a)return {data:null,error:{message:"Not authenticated",status:401},status:401};let s=await e.request({url:"/api/auth/me",method:"get",headers:{Authorization:`Bearer ${a}`}});return s.data&&r(s.data),s},async updateMe(a){let s=n.getItem("amaster_access_token");if(!s)return {data:null,error:{message:"Not authenticated",status:401},status:401};let o=await e.request({url:"/api/auth/me",method:"put",headers:{Authorization:`Bearer ${s}`,"Content-Type":"application/json"},data:a});return o.data&&r(o.data),o},async changePassword(a){let s=n.getItem("amaster_access_token");return s?e.request({url:"/api/auth/change-password",method:"post",headers:{Authorization:`Bearer ${s}`,"Content-Type":"application/json"},data:a}):{data:null,error:{message:"Not authenticated",status:401},status:401}}}}function E(t){let{http:e,storage:n}=t;return {async getOAuthBindings(){let r=n.getItem("amaster_access_token");return r?e.request({url:"/api/auth/oauth-bindings",method:"get",headers:{Authorization:`Bearer ${r}`}}):{data:null,error:{message:"Not authenticated",status:401},status:401}},bindOAuth(r){if(typeof window>"u"){console.error("[AuthClient] OAuth binding is only available in browser environment");return}window.location.href=`/api/auth/oauth/${r}/bind`;},async unbindOAuth(r){let a=n.getItem("amaster_access_token");return a?e.request({url:`/api/auth/oauth/${r}/unbind`,method:"delete",headers:{Authorization:`Bearer ${a}`}}):{data:null,error:{message:"Not authenticated",status:401},status:401}}}}function O(t){let{http:e,storage:n}=t;return {async getSession(){let r=n.getItem("amaster_access_token");return r?e.request({url:"/api/auth/sessions/current",method:"get",headers:{Authorization:`Bearer ${r}`}}):{data:null,error:{message:"Not authenticated",status:401},status:401}},async getSessions(){let r=n.getItem("amaster_access_token");return r?e.request({url:"/api/auth/sessions",method:"get",headers:{Authorization:`Bearer ${r}`}}):{data:null,error:{message:"Not authenticated",status:401},status:401}},async revokeSession(r){let a=n.getItem("amaster_access_token");return a?r?e.request({url:`/api/auth/sessions/${r}`,method:"delete",headers:{Authorization:`Bearer ${a}`}}):{data:null,error:{message:"Session ID is required",status:400},status:400}:{data:null,error:{message:"Not authenticated",status:401},status:401}},async revokeAllSessions(){let r=n.getItem("amaster_access_token");return r?e.request({url:"/api/auth/sessions",method:"delete",headers:{Authorization:`Bearer ${r}`}}):{data:null,error:{message:"Not authenticated",status:401},status:401}}}}function Y(t={},e){let {baseURL:n,headers:r,onTokenExpired:a,onUnauthorized:s,autoHandleOAuthCallback:o=true}=t,c=e||httpClient.createHttpClient({...R,baseURL:n,headers:r}),m=300,u=v(),g=new C,y=new A,f=null;try{let i=u.getItem(d.USER);i&&(f=JSON.parse(i));}catch(i){console.error("[AuthClient] Failed to load user from storage:",i);}let p;y.setRefreshCallback(async()=>{let i=await p.refreshToken();i.data?(await p.getMe(),g.emit("tokenRefreshed",i.data.accessToken)):(g.emit("tokenExpired"),a?.());});function M(i,h){u.setItem(d.ACCESS_TOKEN,h),u.setItem(d.USER,JSON.stringify(i)),f=i,y.scheduleRefreshFromToken(h,m),g.emit("login",i);}function U(i){f=i,u.setItem(d.USER,JSON.stringify(i));}function S(){u.clear(),f=null,y.clearSchedule();}function b(){return f}let I=w({http:c,onLoginSuccess:M,storage:u,clearAuth:S}),x=T({getCurrentUser:b}),_=P({http:c,storage:u,onUserUpdate:U}),L=E({http:c,storage:u}),H=O({http:c,storage:u});if(p={...I,...x,..._,...L,...H,on(i,h){g.on(i,h);},off(i,h){g.off(i,h);},isAuthenticated(){return !!u.getItem(d.ACCESS_TOKEN)},getAccessToken(){return u.getItem(d.ACCESS_TOKEN)},setAccessToken(i){u.setItem(d.ACCESS_TOKEN,i),y.scheduleRefreshFromToken(i,m);},clearAuth:S},p.on("unauthorized",()=>{s?.();}),p.isAuthenticated()&&p.getMe().catch(i=>{console.warn("[AuthClient] Failed to sync user info on init:",i);}),o&&typeof window<"u"){let i=window.location.hash;i&&(i.includes("access_token")||i.includes("accessToken"))&&p.handleOAuthCallback().then(h=>{h.error&&console.error("[AuthClient] Auto OAuth callback failed:",h.error);}).catch(h=>{console.error("[AuthClient] Auto OAuth callback error:",h);});}return p}exports.createAuthClient=Y;exports.defaultHttpClientOptions=R;exports.transformAmasterResponse=k;//# sourceMappingURL=index.cjs.map
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|