@choiceform/shared-auth 0.1.17 → 0.1.19
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 +504 -121
- package/dist/__tests__/auth-utils.test.d.ts +5 -0
- package/dist/__tests__/auth-utils.test.d.ts.map +1 -0
- package/dist/__tests__/auth-utils.test.js +96 -0
- package/dist/__tests__/store.test.d.ts +5 -0
- package/dist/__tests__/store.test.d.ts.map +1 -0
- package/dist/__tests__/store.test.js +210 -0
- package/dist/__tests__/user-mapper.test.d.ts +5 -0
- package/dist/__tests__/user-mapper.test.d.ts.map +1 -0
- package/dist/__tests__/user-mapper.test.js +76 -0
- package/dist/api/auth-api.d.ts +93 -9
- package/dist/api/auth-api.d.ts.map +1 -1
- package/dist/api/auth-api.js +219 -80
- package/dist/api/client.d.ts +10 -0
- package/dist/api/client.d.ts.map +1 -1
- package/dist/api/client.js +10 -0
- package/dist/api/organization-api.d.ts +2 -7
- package/dist/api/organization-api.d.ts.map +1 -1
- package/dist/api/organization-api.js +2 -17
- package/dist/api/team-api.d.ts +1 -5
- package/dist/api/team-api.d.ts.map +1 -1
- package/dist/api/team-api.js +5 -11
- package/dist/config.js +1 -1
- package/dist/core.d.ts +257 -137
- package/dist/core.d.ts.map +1 -1
- package/dist/core.js +112 -28
- package/dist/hooks/index.d.ts +8 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +7 -0
- package/dist/hooks/use-auth-init.d.ts +4 -0
- package/dist/hooks/use-auth-init.d.ts.map +1 -1
- package/dist/hooks/use-auth-init.js +16 -21
- package/dist/hooks/use-auth-sync.d.ts +60 -0
- package/dist/hooks/use-auth-sync.d.ts.map +1 -0
- package/dist/hooks/use-auth-sync.js +116 -0
- package/dist/hooks/use-email-verification.d.ts +85 -0
- package/dist/hooks/use-email-verification.d.ts.map +1 -0
- package/dist/hooks/use-email-verification.js +145 -0
- package/dist/hooks/use-protected-route.d.ts +67 -0
- package/dist/hooks/use-protected-route.d.ts.map +1 -0
- package/dist/hooks/use-protected-route.js +102 -0
- package/dist/index.d.ts +12 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +45 -13
- package/dist/init.d.ts +236 -136
- package/dist/init.d.ts.map +1 -1
- package/dist/lib/auth-client.d.ts +108 -66
- package/dist/lib/auth-client.d.ts.map +1 -1
- package/dist/lib/auth-client.js +75 -2
- package/dist/services/auth-service.d.ts +101 -0
- package/dist/services/auth-service.d.ts.map +1 -0
- package/dist/services/auth-service.js +356 -0
- package/dist/services/callback-service.d.ts +33 -0
- package/dist/services/callback-service.d.ts.map +1 -0
- package/dist/services/callback-service.js +473 -0
- package/dist/services/companion-team.d.ts.map +1 -1
- package/dist/services/companion-team.js +41 -39
- package/dist/services/index.d.ts +3 -0
- package/dist/services/index.d.ts.map +1 -1
- package/dist/services/index.js +3 -0
- package/dist/services/referral-service.d.ts +54 -0
- package/dist/services/referral-service.d.ts.map +1 -0
- package/dist/services/referral-service.js +54 -0
- package/dist/store/actions.d.ts +54 -51
- package/dist/store/actions.d.ts.map +1 -1
- package/dist/store/actions.js +111 -243
- package/dist/store/computed.d.ts +72 -1
- package/dist/store/computed.d.ts.map +1 -1
- package/dist/store/computed.js +90 -3
- package/dist/store/index.d.ts +3 -3
- package/dist/store/index.d.ts.map +1 -1
- package/dist/store/index.js +2 -2
- package/dist/store/state.d.ts +10 -0
- package/dist/store/state.d.ts.map +1 -1
- package/dist/store/state.js +11 -1
- package/dist/store/utils.d.ts +3 -34
- package/dist/store/utils.d.ts.map +1 -1
- package/dist/store/utils.js +2 -22
- package/dist/types/auth.d.ts +106 -0
- package/dist/types/auth.d.ts.map +1 -1
- package/dist/types/callback.d.ts +35 -0
- package/dist/types/callback.d.ts.map +1 -0
- package/dist/types/callback.js +1 -0
- package/dist/types/index.d.ts +4 -3
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/organization.d.ts +19 -3
- package/dist/types/organization.d.ts.map +1 -1
- package/dist/types/team.d.ts +6 -2
- package/dist/types/team.d.ts.map +1 -1
- package/dist/types/user.d.ts +11 -3
- package/dist/types/user.d.ts.map +1 -1
- package/dist/utils/auth-utils.d.ts +60 -0
- package/dist/utils/auth-utils.d.ts.map +1 -0
- package/dist/utils/auth-utils.js +146 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1 -0
- package/dist/utils/user-mapper.d.ts.map +1 -1
- package/dist/utils/user-mapper.js +4 -1
- package/package.json +17 -10
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 邀请码服务
|
|
3
|
+
*
|
|
4
|
+
* 提供邀请码相关的业务逻辑:
|
|
5
|
+
* - 提交邀请码
|
|
6
|
+
* - 检查用户是否需要填写邀请码
|
|
7
|
+
* - 提取用户邀请码字段
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* 创建邀请码服务
|
|
11
|
+
*/
|
|
12
|
+
export function createReferralService(apiClient) {
|
|
13
|
+
async function submitReferralCode(referralCode) {
|
|
14
|
+
const response = await apiClient.post("/v1/auth/referral", { referralCode });
|
|
15
|
+
if (response.ok) {
|
|
16
|
+
return { success: true, error: undefined };
|
|
17
|
+
}
|
|
18
|
+
let error = "unknown";
|
|
19
|
+
if (response.status === 400) {
|
|
20
|
+
error = "already_referred";
|
|
21
|
+
}
|
|
22
|
+
else if (response.status === 404) {
|
|
23
|
+
error = "not_found";
|
|
24
|
+
}
|
|
25
|
+
return { success: false, error };
|
|
26
|
+
}
|
|
27
|
+
return { submitReferralCode };
|
|
28
|
+
}
|
|
29
|
+
// ===== Utilities =====
|
|
30
|
+
/**
|
|
31
|
+
* 检查用户是否需要完成邀请码步骤
|
|
32
|
+
*
|
|
33
|
+
* 仅检查用户状态,不包含 feature flag 判断(由应用层控制)
|
|
34
|
+
*/
|
|
35
|
+
export function needsReferral(user, options) {
|
|
36
|
+
if (!user)
|
|
37
|
+
return false;
|
|
38
|
+
if (user.emailVerified !== true)
|
|
39
|
+
return false;
|
|
40
|
+
const skipRoles = options?.skipRoles ?? ["admin"];
|
|
41
|
+
if (user.role && skipRoles.includes(user.role))
|
|
42
|
+
return false;
|
|
43
|
+
const { referredBy } = user;
|
|
44
|
+
return !referredBy || referredBy.trim() === "";
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* 提取用户的邀请码相关字段
|
|
48
|
+
*/
|
|
49
|
+
export function getReferralFields(user) {
|
|
50
|
+
return {
|
|
51
|
+
referralCode: user?.referralCode,
|
|
52
|
+
referredBy: user?.referredBy,
|
|
53
|
+
};
|
|
54
|
+
}
|
package/dist/store/actions.d.ts
CHANGED
|
@@ -1,85 +1,88 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* 认证状态 Actions
|
|
3
|
+
*
|
|
4
|
+
* 只负责状态管理,不包含业务逻辑
|
|
5
|
+
* 业务逻辑在 services/auth-service.ts 中
|
|
3
6
|
*/
|
|
4
7
|
import type { Observable } from "@legendapp/state";
|
|
5
|
-
import type {
|
|
8
|
+
import type { AuthState, SessionUser } from "../types";
|
|
6
9
|
import type { TokenStorage } from "../api";
|
|
7
10
|
/**
|
|
8
|
-
*
|
|
11
|
+
* 创建状态管理 Actions
|
|
12
|
+
*
|
|
13
|
+
* 这些是纯粹的状态操作,不涉及 API 调用或业务逻辑
|
|
9
14
|
*/
|
|
10
|
-
export declare function
|
|
15
|
+
export declare function createStoreActions(authStore: Observable<AuthState>, tokenStorage: TokenStorage): {
|
|
11
16
|
/**
|
|
12
|
-
*
|
|
17
|
+
* 获取当前用户
|
|
13
18
|
*/
|
|
14
|
-
|
|
19
|
+
getUser(): SessionUser | null;
|
|
15
20
|
/**
|
|
16
|
-
*
|
|
21
|
+
* 获取当前用户 ID
|
|
17
22
|
*/
|
|
18
|
-
|
|
23
|
+
getUserId(): string | null;
|
|
19
24
|
/**
|
|
20
|
-
*
|
|
25
|
+
* 检查是否已认证
|
|
21
26
|
*/
|
|
22
|
-
|
|
27
|
+
isAuthenticated(): boolean;
|
|
28
|
+
/**
|
|
29
|
+
* 检查是否正在加载
|
|
30
|
+
*/
|
|
31
|
+
isLoading(): boolean;
|
|
32
|
+
/**
|
|
33
|
+
* 检查是否已加载完成
|
|
34
|
+
*/
|
|
35
|
+
isLoaded(): boolean;
|
|
36
|
+
/**
|
|
37
|
+
* 设置用户
|
|
38
|
+
*/
|
|
39
|
+
setUser(user: SessionUser | null): void;
|
|
40
|
+
/**
|
|
41
|
+
* 更新用户(合并)
|
|
42
|
+
*/
|
|
43
|
+
updateUser(updates: Partial<SessionUser>): void;
|
|
23
44
|
/**
|
|
24
45
|
* 设置加载状态
|
|
25
46
|
*/
|
|
26
47
|
setLoading(loading: boolean): void;
|
|
27
48
|
/**
|
|
28
|
-
*
|
|
49
|
+
* 设置已加载状态
|
|
29
50
|
*/
|
|
30
|
-
|
|
51
|
+
setLoaded(loaded: boolean): void;
|
|
31
52
|
/**
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
* 直接调用 better-auth 的 signIn.social,传入完整的回调 URL
|
|
35
|
-
*
|
|
36
|
-
* @param provider - OAuth 提供商(如 github)
|
|
37
|
-
* @param callbackURL - 登录成功后的完整回调 URL
|
|
38
|
-
* @param newUserCallbackURL - 新用户的回调 URL(可选)
|
|
39
|
-
* @param errorCallbackURL - 登录失败后的完整回调 URL(可选)
|
|
53
|
+
* 设置错误
|
|
40
54
|
*/
|
|
41
|
-
|
|
55
|
+
setError(error: string | null): void;
|
|
42
56
|
/**
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
* 发送 Magic Link 到用户邮箱
|
|
46
|
-
*
|
|
47
|
-
* @param email - 用户邮箱
|
|
48
|
-
* @param callbackURL - 登录成功后的完整回调 URL
|
|
49
|
-
* @param name - 用户名称(可选,用于新用户)
|
|
50
|
-
* @param newUserCallbackURL - 新用户的回调 URL(可选)
|
|
51
|
-
* @returns 是否发送成功
|
|
57
|
+
* 设置认证成功状态
|
|
52
58
|
*/
|
|
53
|
-
|
|
59
|
+
setAuthenticated(user: SessionUser): void;
|
|
54
60
|
/**
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
* @param email - 邮箱
|
|
58
|
-
* @param password - 密码
|
|
59
|
-
* @returns 是否登录成功
|
|
61
|
+
* 清除认证状态
|
|
60
62
|
*/
|
|
61
|
-
|
|
63
|
+
clearAuth(): void;
|
|
62
64
|
/**
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
* @param email - 邮箱
|
|
66
|
-
* @param password - 密码
|
|
67
|
-
* @param name - 用户名
|
|
68
|
-
* @returns 是否注册成功
|
|
65
|
+
* 处理未授权
|
|
69
66
|
*/
|
|
70
|
-
|
|
67
|
+
handleUnauthorized(): void;
|
|
71
68
|
/**
|
|
72
|
-
*
|
|
69
|
+
* 更新活跃组织 ID
|
|
73
70
|
*/
|
|
74
|
-
|
|
71
|
+
setActiveOrganizationId(organizationId: string | null | undefined): void;
|
|
75
72
|
/**
|
|
76
|
-
*
|
|
73
|
+
* 更新活跃团队 ID
|
|
77
74
|
*/
|
|
78
|
-
|
|
75
|
+
setActiveTeamId(teamId: string | null | undefined): void;
|
|
79
76
|
/**
|
|
80
|
-
*
|
|
77
|
+
* 初始化认证状态
|
|
81
78
|
*/
|
|
82
|
-
|
|
79
|
+
initialize(user: SessionUser | null, isLoaded: boolean): void;
|
|
83
80
|
};
|
|
84
|
-
export type
|
|
81
|
+
export type StoreActions = ReturnType<typeof createStoreActions>;
|
|
82
|
+
/**
|
|
83
|
+
* @deprecated 使用 createStoreActions 代替
|
|
84
|
+
* 保留此函数以保持向后兼容性
|
|
85
|
+
*/
|
|
86
|
+
export { createStoreActions as createAuthActions };
|
|
87
|
+
export type { StoreActions as AuthActions };
|
|
85
88
|
//# sourceMappingURL=actions.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../../src/store/actions.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../../src/store/actions.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAClD,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAA;AAE1C;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,UAAU,CAAC,SAAS,CAAC,EAChC,YAAY,EAAE,YAAY;IAOxB;;OAEG;eACQ,WAAW,GAAG,IAAI;IAI7B;;OAEG;iBACU,MAAM,GAAG,IAAI;IAI1B;;OAEG;uBACgB,OAAO;IAI1B;;OAEG;iBACU,OAAO;IAIpB;;OAEG;gBACS,OAAO;IAQnB;;OAEG;kBACW,WAAW,GAAG,IAAI;IAKhC;;OAEG;wBACiB,OAAO,CAAC,WAAW,CAAC;IAOxC;;OAEG;wBACiB,OAAO;IAI3B;;OAEG;sBACe,OAAO;IAOzB;;OAEG;oBACa,MAAM,GAAG,IAAI;IAI7B;;OAEG;2BACoB,WAAW;IAQlC;;OAEG;;IASH;;OAEG;;IASH;;OAEG;4CACqC,MAAM,GAAG,IAAI,GAAG,SAAS;IAUjE;;OAEG;4BACqB,MAAM,GAAG,IAAI,GAAG,SAAS;IAcjD;;OAEG;qBACc,WAAW,GAAG,IAAI,YAAY,OAAO;EAWzD;AAED,MAAM,MAAM,YAAY,GAAG,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAA;AAMhE;;;GAGG;AACH,OAAO,EAAE,kBAAkB,IAAI,iBAAiB,EAAE,CAAA;AAClD,YAAY,EAAE,YAAY,IAAI,WAAW,EAAE,CAAA"}
|
package/dist/store/actions.js
CHANGED
|
@@ -1,91 +1,67 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* 认证状态 Actions
|
|
3
|
+
*
|
|
4
|
+
* 只负责状态管理,不包含业务逻辑
|
|
5
|
+
* 业务逻辑在 services/auth-service.ts 中
|
|
3
6
|
*/
|
|
4
|
-
import { extractSessionUser } from "../utils";
|
|
5
7
|
/**
|
|
6
|
-
*
|
|
8
|
+
* 创建状态管理 Actions
|
|
9
|
+
*
|
|
10
|
+
* 这些是纯粹的状态操作,不涉及 API 调用或业务逻辑
|
|
7
11
|
*/
|
|
8
|
-
export function
|
|
9
|
-
const { baseURL, getSessionEndpoint = "/v1/auth/get-session", skipTokenCleanupOnError = false, } = config;
|
|
12
|
+
export function createStoreActions(authStore, tokenStorage) {
|
|
10
13
|
return {
|
|
14
|
+
// ============================================================
|
|
15
|
+
// 状态读取
|
|
16
|
+
// ============================================================
|
|
11
17
|
/**
|
|
12
|
-
*
|
|
18
|
+
* 获取当前用户
|
|
13
19
|
*/
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
if (!user && storedToken) {
|
|
17
|
-
await this.fetchSessionWithToken(storedToken);
|
|
18
|
-
}
|
|
19
|
-
else if (user) {
|
|
20
|
-
authStore.user.set(user);
|
|
21
|
-
authStore.isAuthenticated.set(true);
|
|
22
|
-
}
|
|
23
|
-
else {
|
|
24
|
-
authStore.user.set(null);
|
|
25
|
-
authStore.isAuthenticated.set(false);
|
|
26
|
-
}
|
|
27
|
-
authStore.isLoaded.set(isLoaded);
|
|
28
|
-
authStore.loading.set(!isLoaded);
|
|
20
|
+
getUser() {
|
|
21
|
+
return authStore.user.get();
|
|
29
22
|
},
|
|
30
23
|
/**
|
|
31
|
-
*
|
|
24
|
+
* 获取当前用户 ID
|
|
32
25
|
*/
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
if (!token) {
|
|
36
|
-
throw new Error("Token is required");
|
|
37
|
-
}
|
|
38
|
-
tokenStorage.save(token);
|
|
39
|
-
const endpoint = `${baseURL}${getSessionEndpoint}`;
|
|
40
|
-
const response = await fetch(endpoint, {
|
|
41
|
-
method: "GET",
|
|
42
|
-
headers: {
|
|
43
|
-
Authorization: `Bearer ${token}`,
|
|
44
|
-
"Content-Type": "application/json",
|
|
45
|
-
},
|
|
46
|
-
});
|
|
47
|
-
if (!response.ok) {
|
|
48
|
-
throw new Error(`Failed to fetch session: ${response.status}`);
|
|
49
|
-
}
|
|
50
|
-
const responseText = await response.text();
|
|
51
|
-
let sessionData = null;
|
|
52
|
-
try {
|
|
53
|
-
if (responseText && responseText !== "null" && responseText !== "") {
|
|
54
|
-
sessionData = JSON.parse(responseText);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
catch {
|
|
58
|
-
this.handleUnauthorized();
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
const userData = extractSessionUser(sessionData);
|
|
62
|
-
if (userData) {
|
|
63
|
-
authStore.user.set(userData);
|
|
64
|
-
authStore.isAuthenticated.set(true);
|
|
65
|
-
authStore.isLoaded.set(true);
|
|
66
|
-
authStore.loading.set(false);
|
|
67
|
-
}
|
|
68
|
-
else {
|
|
69
|
-
this.handleUnauthorized();
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
catch {
|
|
73
|
-
this.handleUnauthorized();
|
|
74
|
-
}
|
|
26
|
+
getUserId() {
|
|
27
|
+
return authStore.user.get()?.id ?? null;
|
|
75
28
|
},
|
|
76
29
|
/**
|
|
77
|
-
*
|
|
30
|
+
* 检查是否已认证
|
|
78
31
|
*/
|
|
79
|
-
|
|
80
|
-
authStore.
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
32
|
+
isAuthenticated() {
|
|
33
|
+
return authStore.isAuthenticated.get();
|
|
34
|
+
},
|
|
35
|
+
/**
|
|
36
|
+
* 检查是否正在加载
|
|
37
|
+
*/
|
|
38
|
+
isLoading() {
|
|
39
|
+
return authStore.loading.get();
|
|
40
|
+
},
|
|
41
|
+
/**
|
|
42
|
+
* 检查是否已加载完成
|
|
43
|
+
*/
|
|
44
|
+
isLoaded() {
|
|
45
|
+
return authStore.isLoaded.get();
|
|
46
|
+
},
|
|
47
|
+
// ============================================================
|
|
48
|
+
// 状态更新
|
|
49
|
+
// ============================================================
|
|
50
|
+
/**
|
|
51
|
+
* 设置用户
|
|
52
|
+
*/
|
|
53
|
+
setUser(user) {
|
|
54
|
+
authStore.user.set(user);
|
|
55
|
+
authStore.isAuthenticated.set(user !== null);
|
|
56
|
+
},
|
|
57
|
+
/**
|
|
58
|
+
* 更新用户(合并)
|
|
59
|
+
*/
|
|
60
|
+
updateUser(updates) {
|
|
61
|
+
const currentUser = authStore.user.get();
|
|
62
|
+
if (currentUser) {
|
|
63
|
+
authStore.user.set({ ...currentUser, ...updates });
|
|
87
64
|
}
|
|
88
|
-
tokenStorage.clear();
|
|
89
65
|
},
|
|
90
66
|
/**
|
|
91
67
|
* 设置加载状态
|
|
@@ -94,205 +70,97 @@ export function createAuthActions(authStore, tokenStorage, config, authClient) {
|
|
|
94
70
|
authStore.loading.set(loading);
|
|
95
71
|
},
|
|
96
72
|
/**
|
|
97
|
-
*
|
|
73
|
+
* 设置已加载状态
|
|
74
|
+
*/
|
|
75
|
+
setLoaded(loaded) {
|
|
76
|
+
authStore.isLoaded.set(loaded);
|
|
77
|
+
if (loaded) {
|
|
78
|
+
authStore.loading.set(false);
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
/**
|
|
82
|
+
* 设置错误
|
|
98
83
|
*/
|
|
99
84
|
setError(error) {
|
|
100
85
|
authStore.error.set(error);
|
|
101
86
|
},
|
|
102
87
|
/**
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
* 直接调用 better-auth 的 signIn.social,传入完整的回调 URL
|
|
106
|
-
*
|
|
107
|
-
* @param provider - OAuth 提供商(如 github)
|
|
108
|
-
* @param callbackURL - 登录成功后的完整回调 URL
|
|
109
|
-
* @param newUserCallbackURL - 新用户的回调 URL(可选)
|
|
110
|
-
* @param errorCallbackURL - 登录失败后的完整回调 URL(可选)
|
|
88
|
+
* 设置认证成功状态
|
|
111
89
|
*/
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
authStore.error.set(null);
|
|
119
|
-
await authClient.signIn.social({
|
|
120
|
-
provider,
|
|
121
|
-
callbackURL,
|
|
122
|
-
newUserCallbackURL,
|
|
123
|
-
errorCallbackURL,
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
|
-
catch (error) {
|
|
127
|
-
const message = error instanceof Error ? error.message : "Sign in failed";
|
|
128
|
-
authStore.error.set(message);
|
|
129
|
-
authStore.loading.set(false);
|
|
130
|
-
}
|
|
90
|
+
setAuthenticated(user) {
|
|
91
|
+
authStore.user.set(user);
|
|
92
|
+
authStore.isAuthenticated.set(true);
|
|
93
|
+
authStore.isLoaded.set(true);
|
|
94
|
+
authStore.loading.set(false);
|
|
95
|
+
authStore.error.set(null);
|
|
131
96
|
},
|
|
132
97
|
/**
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
* 发送 Magic Link 到用户邮箱
|
|
136
|
-
*
|
|
137
|
-
* @param email - 用户邮箱
|
|
138
|
-
* @param callbackURL - 登录成功后的完整回调 URL
|
|
139
|
-
* @param name - 用户名称(可选,用于新用户)
|
|
140
|
-
* @param newUserCallbackURL - 新用户的回调 URL(可选)
|
|
141
|
-
* @returns 是否发送成功
|
|
98
|
+
* 清除认证状态
|
|
142
99
|
*/
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
return false;
|
|
150
|
-
}
|
|
151
|
-
try {
|
|
152
|
-
authStore.loading.set(true);
|
|
153
|
-
authStore.error.set(null);
|
|
154
|
-
await authClient.signIn.magicLink({
|
|
155
|
-
email,
|
|
156
|
-
name,
|
|
157
|
-
callbackURL,
|
|
158
|
-
newUserCallbackURL,
|
|
159
|
-
});
|
|
160
|
-
authStore.loading.set(false);
|
|
161
|
-
return true;
|
|
162
|
-
}
|
|
163
|
-
catch (error) {
|
|
164
|
-
const message = error instanceof Error ? error.message : "Failed to send magic link";
|
|
165
|
-
authStore.error.set(message);
|
|
166
|
-
authStore.loading.set(false);
|
|
167
|
-
return false;
|
|
168
|
-
}
|
|
100
|
+
clearAuth() {
|
|
101
|
+
authStore.user.set(null);
|
|
102
|
+
authStore.isAuthenticated.set(false);
|
|
103
|
+
authStore.isLoaded.set(true);
|
|
104
|
+
authStore.loading.set(false);
|
|
105
|
+
tokenStorage.clear();
|
|
169
106
|
},
|
|
170
107
|
/**
|
|
171
|
-
*
|
|
172
|
-
*
|
|
173
|
-
* @param email - 邮箱
|
|
174
|
-
* @param password - 密码
|
|
175
|
-
* @returns 是否登录成功
|
|
108
|
+
* 处理未授权
|
|
176
109
|
*/
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
return false;
|
|
180
|
-
}
|
|
181
|
-
if (!authClient.signIn.email) {
|
|
182
|
-
authStore.error.set("Email sign in is not available.");
|
|
183
|
-
return false;
|
|
184
|
-
}
|
|
185
|
-
try {
|
|
186
|
-
authStore.loading.set(true);
|
|
187
|
-
authStore.error.set(null);
|
|
188
|
-
await authClient.signIn.email({ email, password }, {
|
|
189
|
-
onSuccess: (context) => {
|
|
190
|
-
const token = context.response.headers.get("set-auth-token");
|
|
191
|
-
if (token) {
|
|
192
|
-
tokenStorage.save(token);
|
|
193
|
-
}
|
|
194
|
-
},
|
|
195
|
-
onError: (context) => {
|
|
196
|
-
authStore.error.set(context.error.message || "Login failed");
|
|
197
|
-
},
|
|
198
|
-
});
|
|
199
|
-
authStore.loading.set(false);
|
|
200
|
-
return true;
|
|
201
|
-
}
|
|
202
|
-
catch (error) {
|
|
203
|
-
const message = error instanceof Error ? error.message : "Login failed";
|
|
204
|
-
authStore.error.set(message);
|
|
205
|
-
authStore.loading.set(false);
|
|
206
|
-
return false;
|
|
207
|
-
}
|
|
110
|
+
handleUnauthorized() {
|
|
111
|
+
this.clearAuth();
|
|
208
112
|
},
|
|
113
|
+
// ============================================================
|
|
114
|
+
// Active 状态更新
|
|
115
|
+
// ============================================================
|
|
209
116
|
/**
|
|
210
|
-
*
|
|
211
|
-
*
|
|
212
|
-
* @param email - 邮箱
|
|
213
|
-
* @param password - 密码
|
|
214
|
-
* @param name - 用户名
|
|
215
|
-
* @returns 是否注册成功
|
|
117
|
+
* 更新活跃组织 ID
|
|
216
118
|
*/
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
return false;
|
|
224
|
-
}
|
|
225
|
-
try {
|
|
226
|
-
authStore.loading.set(true);
|
|
227
|
-
authStore.error.set(null);
|
|
228
|
-
await authClient.signUp.email({ email, password, name }, {
|
|
229
|
-
onSuccess: (context) => {
|
|
230
|
-
const token = context.response.headers.get("set-auth-token");
|
|
231
|
-
if (token) {
|
|
232
|
-
tokenStorage.save(token);
|
|
233
|
-
}
|
|
234
|
-
},
|
|
235
|
-
onError: (context) => {
|
|
236
|
-
authStore.error.set(context.error.message || "Sign up failed");
|
|
237
|
-
},
|
|
119
|
+
setActiveOrganizationId(organizationId) {
|
|
120
|
+
const currentUser = authStore.user.get();
|
|
121
|
+
if (currentUser) {
|
|
122
|
+
authStore.user.set({
|
|
123
|
+
...currentUser,
|
|
124
|
+
activeOrganizationId: organizationId ?? undefined,
|
|
238
125
|
});
|
|
239
|
-
authStore.loading.set(false);
|
|
240
|
-
return true;
|
|
241
|
-
}
|
|
242
|
-
catch (error) {
|
|
243
|
-
const message = error instanceof Error ? error.message : "Sign up failed";
|
|
244
|
-
authStore.error.set(message);
|
|
245
|
-
authStore.loading.set(false);
|
|
246
|
-
return false;
|
|
247
126
|
}
|
|
248
127
|
},
|
|
249
128
|
/**
|
|
250
|
-
*
|
|
129
|
+
* 更新活跃团队 ID
|
|
251
130
|
*/
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
await authClient.signOut();
|
|
260
|
-
authStore.user.set(null);
|
|
261
|
-
authStore.isAuthenticated.set(false);
|
|
262
|
-
tokenStorage.clear();
|
|
263
|
-
if (redirectTo) {
|
|
264
|
-
window.location.href = redirectTo;
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
catch (error) {
|
|
268
|
-
const message = error instanceof Error ? error.message : "Sign out failed";
|
|
269
|
-
authStore.error.set(message);
|
|
270
|
-
authStore.user.set(null);
|
|
271
|
-
authStore.isAuthenticated.set(false);
|
|
272
|
-
tokenStorage.clear();
|
|
273
|
-
}
|
|
274
|
-
finally {
|
|
275
|
-
authStore.loading.set(false);
|
|
131
|
+
setActiveTeamId(teamId) {
|
|
132
|
+
const currentUser = authStore.user.get();
|
|
133
|
+
if (currentUser) {
|
|
134
|
+
authStore.user.set({
|
|
135
|
+
...currentUser,
|
|
136
|
+
activeTeamId: teamId ?? undefined,
|
|
137
|
+
});
|
|
276
138
|
}
|
|
277
139
|
},
|
|
140
|
+
// ============================================================
|
|
141
|
+
// 初始化
|
|
142
|
+
// ============================================================
|
|
278
143
|
/**
|
|
279
|
-
*
|
|
144
|
+
* 初始化认证状态
|
|
280
145
|
*/
|
|
281
|
-
|
|
146
|
+
initialize(user, isLoaded) {
|
|
282
147
|
if (user) {
|
|
283
|
-
|
|
284
|
-
authStore.isAuthenticated.set(true);
|
|
148
|
+
this.setAuthenticated(user);
|
|
285
149
|
}
|
|
286
150
|
else {
|
|
287
151
|
authStore.user.set(null);
|
|
288
152
|
authStore.isAuthenticated.set(false);
|
|
289
153
|
}
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
* 获取当前用户
|
|
293
|
-
*/
|
|
294
|
-
getUser() {
|
|
295
|
-
return authStore.user.get();
|
|
154
|
+
authStore.isLoaded.set(isLoaded);
|
|
155
|
+
authStore.loading.set(!isLoaded);
|
|
296
156
|
},
|
|
297
157
|
};
|
|
298
158
|
}
|
|
159
|
+
// ============================================================
|
|
160
|
+
// 兼容性导出(保持向后兼容)
|
|
161
|
+
// ============================================================
|
|
162
|
+
/**
|
|
163
|
+
* @deprecated 使用 createStoreActions 代替
|
|
164
|
+
* 保留此函数以保持向后兼容性
|
|
165
|
+
*/
|
|
166
|
+
export { createStoreActions as createAuthActions };
|