@choiceform/shared-auth 0.1.13 → 0.1.15

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.
Files changed (92) hide show
  1. package/README.md +106 -450
  2. package/dist/api/auth-api.d.ts +28 -0
  3. package/dist/api/auth-api.d.ts.map +1 -0
  4. package/dist/api/auth-api.js +133 -0
  5. package/dist/api/client.d.ts +34 -0
  6. package/dist/api/client.d.ts.map +1 -0
  7. package/dist/api/client.js +104 -0
  8. package/dist/api/index.d.ts +12 -0
  9. package/dist/api/index.d.ts.map +1 -0
  10. package/dist/api/index.js +7 -0
  11. package/dist/api/organization-api.d.ts +96 -0
  12. package/dist/api/organization-api.d.ts.map +1 -0
  13. package/dist/api/organization-api.js +228 -0
  14. package/dist/api/team-api.d.ts +57 -0
  15. package/dist/api/team-api.d.ts.map +1 -0
  16. package/dist/api/team-api.js +118 -0
  17. package/dist/config.d.ts +4 -50
  18. package/dist/config.d.ts.map +1 -1
  19. package/dist/config.js +5 -6
  20. package/dist/core.d.ts +307 -1717
  21. package/dist/core.d.ts.map +1 -1
  22. package/dist/core.js +35 -17
  23. package/dist/index.d.ts +11 -14
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +25 -12
  26. package/dist/init.d.ts +326 -1732
  27. package/dist/init.d.ts.map +1 -1
  28. package/dist/init.js +13 -14
  29. package/dist/lib/auth-client.d.ts +232 -1689
  30. package/dist/lib/auth-client.d.ts.map +1 -1
  31. package/dist/lib/auth-client.js +10 -16
  32. package/dist/services/companion-team.d.ts +16 -0
  33. package/dist/services/companion-team.d.ts.map +1 -0
  34. package/dist/services/companion-team.js +73 -0
  35. package/dist/services/index.d.ts +5 -0
  36. package/dist/services/index.d.ts.map +1 -0
  37. package/dist/services/index.js +4 -0
  38. package/dist/store/actions.d.ts +45 -30
  39. package/dist/store/actions.d.ts.map +1 -1
  40. package/dist/store/actions.js +139 -103
  41. package/dist/store/index.d.ts +8 -0
  42. package/dist/store/index.d.ts.map +1 -0
  43. package/dist/store/index.js +7 -0
  44. package/dist/store/state.d.ts +10 -7
  45. package/dist/store/state.d.ts.map +1 -1
  46. package/dist/store/state.js +31 -23
  47. package/dist/store/utils.d.ts +22 -71
  48. package/dist/store/utils.d.ts.map +1 -1
  49. package/dist/store/utils.js +28 -146
  50. package/dist/types/auth.d.ts +107 -0
  51. package/dist/types/auth.d.ts.map +1 -0
  52. package/dist/types/auth.js +4 -0
  53. package/dist/types/index.d.ts +8 -0
  54. package/dist/types/index.d.ts.map +1 -0
  55. package/dist/types/index.js +4 -0
  56. package/dist/types/organization.d.ts +111 -0
  57. package/dist/types/organization.d.ts.map +1 -0
  58. package/dist/types/organization.js +4 -0
  59. package/dist/types/team.d.ts +52 -0
  60. package/dist/types/team.d.ts.map +1 -0
  61. package/dist/types/team.js +4 -0
  62. package/dist/types/user.d.ts +44 -0
  63. package/dist/types/user.d.ts.map +1 -0
  64. package/dist/types/user.js +4 -0
  65. package/dist/utils/date.d.ts +10 -0
  66. package/dist/utils/date.d.ts.map +1 -0
  67. package/dist/utils/date.js +13 -0
  68. package/dist/utils/env.d.ts +20 -0
  69. package/dist/utils/env.d.ts.map +1 -0
  70. package/dist/utils/env.js +23 -0
  71. package/dist/utils/index.d.ts +7 -0
  72. package/dist/utils/index.d.ts.map +1 -0
  73. package/dist/utils/index.js +6 -0
  74. package/dist/utils/user-mapper.d.ts +21 -0
  75. package/dist/utils/user-mapper.d.ts.map +1 -0
  76. package/dist/utils/user-mapper.js +55 -0
  77. package/package.json +3 -4
  78. package/dist/components/auth-sync.d.ts +0 -25
  79. package/dist/components/auth-sync.d.ts.map +0 -1
  80. package/dist/components/auth-sync.js +0 -346
  81. package/dist/components/protected-route.d.ts +0 -18
  82. package/dist/components/protected-route.d.ts.map +0 -1
  83. package/dist/components/protected-route.js +0 -34
  84. package/dist/components/sign-in-page.d.ts +0 -21
  85. package/dist/components/sign-in-page.d.ts.map +0 -1
  86. package/dist/components/sign-in-page.js +0 -31
  87. package/dist/core/init-auth-sync.d.ts +0 -7
  88. package/dist/core/init-auth-sync.d.ts.map +0 -1
  89. package/dist/core/init-auth-sync.js +0 -34
  90. package/dist/types.d.ts +0 -87
  91. package/dist/types.d.ts.map +0 -1
  92. package/dist/types.js +0 -4
@@ -1 +1 @@
1
- {"version":3,"file":"auth-client.d.ts","sourceRoot":"","sources":["../../src/lib/auth-client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"auth-client.d.ts","sourceRoot":"","sources":["../../src/lib/auth-client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAE3C;;;;;;;;;;;GAWG;AACH,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6BAsB8xE,CAAC;iBAAe,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aAA42C,CAAC;;eAA2D,CAAC;;;;;gBAA8U,CAAC;mBAA8C,CAAC;iBAAmC,CAAC;iBAAmC,CAAC;YAA+B,CAAC;gBAAuC,CAAC;gBAA2C,CAAC;sBAAwC,CAAC;cAAwC,CAAC;cAA8C,CAAC;eAA+B,CAAC;mBAA0G,CAAC;yBAAuB,CAAC;;eAAyC,CAAC;;;aAA2G,CAAC;YAA+B,CAAC;;;;;;;;;;;;YAA+e,CAAC;aAAgB,CAAC;cAAiB,CAAC;cAAiB,CAAC;;aAA8F,CAAC;oBAAkE,CAAC;cAAgC,CAAC;mBAAmG,CAAC;yBAA2E,CAAC;qBAAwC,CAAC;;;uBAAkF,CAAC;+GAAuL,CAAC;;;;;;EAFp/L"}
@@ -6,6 +6,7 @@ import { createAuthClient } from "better-auth/react";
6
6
  * - 使用 Bearer Token 认证模式
7
7
  * - Token 从 localStorage 中动态读取
8
8
  * - 支持服务器端 Bearer Plugin 的 session 管理
9
+ * - basePath 设置为 /v1/auth(与后端 better-auth 配置一致)
9
10
  *
10
11
  * @param config - 认证配置对象
11
12
  * @returns Better Auth 客户端实例
@@ -13,27 +14,20 @@ import { createAuthClient } from "better-auth/react";
13
14
  export function createAuthClientFromConfig(config) {
14
15
  const { baseURL, plugins = [], tokenStorageKey = "auth-token" } = config;
15
16
  return createAuthClient({
16
- baseURL: `${baseURL}/v1/auth`,
17
+ baseURL,
18
+ basePath: "/v1/auth",
17
19
  plugins,
18
20
  fetchOptions: {
19
21
  auth: {
20
22
  type: "Bearer",
21
23
  token: () => {
22
- // localStorage 获取存储的 bearer token
23
- // SSR 环境下 localStorage 不存在,返回空字符串
24
- if (typeof window === "undefined" || typeof localStorage === "undefined") {
25
- return "";
24
+ if (typeof window === "undefined") {
25
+ return undefined;
26
26
  }
27
- try {
28
- const token = localStorage.getItem(tokenStorageKey);
29
- return token || "";
30
- }
31
- catch {
32
- // localStorage 访问失败(如隐私模式),返回空字符串
33
- return "";
34
- }
35
- }
36
- }
37
- }
27
+ return localStorage.getItem(tokenStorageKey) ?? undefined;
28
+ },
29
+ },
30
+ credentials: "include",
31
+ },
38
32
  });
39
33
  }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Companion Team 服务
3
+ *
4
+ * 在用户登录成功后自动设置组织和团队上下文
5
+ */
6
+ import type { AuthInstance } from "../core";
7
+ import type { CompanionTeamOptions } from "../types";
8
+ /**
9
+ * 设置 Companion Team
10
+ *
11
+ * @param auth - Auth 实例
12
+ * @param token - 认证 token
13
+ * @param options - 选项
14
+ */
15
+ export declare function setupCompanionTeam(auth: AuthInstance, token: string, options?: CompanionTeamOptions): Promise<void>;
16
+ //# sourceMappingURL=companion-team.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"companion-team.d.ts","sourceRoot":"","sources":["../../src/services/companion-team.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAC3C,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAA;AAIpD;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,YAAY,EAClB,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,IAAI,CAAC,CAwDf"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Companion Team 服务
3
+ *
4
+ * 在用户登录成功后自动设置组织和团队上下文
5
+ */
6
+ import { createAuthApi } from "../api";
7
+ import { getAuthBaseUrl } from "../utils";
8
+ /**
9
+ * 设置 Companion Team
10
+ *
11
+ * @param auth - Auth 实例
12
+ * @param token - 认证 token
13
+ * @param options - 选项
14
+ */
15
+ export async function setupCompanionTeam(auth, token, options = {}) {
16
+ const { isNewUser, onComplete, onError } = options;
17
+ try {
18
+ if (!token?.trim())
19
+ return;
20
+ const baseURL = getAuthBaseUrl();
21
+ const authApi = createAuthApi(auth.apiClient, baseURL);
22
+ let session = await authApi.getSessionWithToken(token);
23
+ // 新用户或没有 inherent 字段时需要 onboard
24
+ const needsOnboard = isNewUser ||
25
+ (!session?.inherentOrganizationId && !session?.inherentTeamId);
26
+ if (needsOnboard) {
27
+ try {
28
+ await authApi.onboard(token);
29
+ session = await authApi.getSessionWithToken(token);
30
+ }
31
+ catch {
32
+ // onboard 失败不阻塞流程
33
+ }
34
+ }
35
+ if (!session)
36
+ return;
37
+ // 已有活动组织和团队,只需更新 store
38
+ if (session.activeOrganizationId && session.activeTeamId) {
39
+ updateAuthStore(auth, session);
40
+ onComplete?.();
41
+ return;
42
+ }
43
+ // 设置活动组织
44
+ if (!session.activeOrganizationId && session.inherentOrganizationId) {
45
+ await authApi.setActiveOrganization({ organizationId: session.inherentOrganizationId }, token);
46
+ }
47
+ // 设置活动团队
48
+ if (!session.activeTeamId && session.inherentTeamId) {
49
+ await authApi.setActiveTeam({ teamId: session.inherentTeamId }, token);
50
+ }
51
+ // 刷新并更新 store
52
+ const updated = await authApi.getSessionWithToken(token);
53
+ if (updated) {
54
+ updateAuthStore(auth, updated);
55
+ }
56
+ onComplete?.();
57
+ }
58
+ catch (error) {
59
+ onError?.(error instanceof Error ? error : new Error(String(error)));
60
+ }
61
+ }
62
+ function updateAuthStore(auth, session) {
63
+ const user = auth.authStore.user.get();
64
+ if (user) {
65
+ auth.authStore.user.set({
66
+ ...user,
67
+ activeOrganizationId: session.activeOrganizationId,
68
+ activeTeamId: session.activeTeamId,
69
+ inherentOrganizationId: session.inherentOrganizationId,
70
+ inherentTeamId: session.inherentTeamId,
71
+ });
72
+ }
73
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * 服务导出
3
+ */
4
+ export { setupCompanionTeam } from "./companion-team";
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/services/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA"}
@@ -0,0 +1,4 @@
1
+ /**
2
+ * 服务导出
3
+ */
4
+ export { setupCompanionTeam } from "./companion-team";
@@ -1,38 +1,23 @@
1
+ /**
2
+ * 认证 Actions
3
+ */
1
4
  import type { Observable } from "@legendapp/state";
2
- import type { AuthState, SessionUser } from "../types";
3
- import type { AuthConfig } from "../config";
4
- import type { TokenStorage } from "./state";
5
+ import type { AuthClientMethods, AuthConfig, AuthState, SessionUser } from "../types";
6
+ import type { TokenStorage } from "../api";
5
7
  /**
6
- * 创建认证 actions
8
+ * 创建认证 Actions
7
9
  */
8
- export declare function createAuthActions(authStore: Observable<AuthState>, tokenStorage: TokenStorage, config: AuthConfig, authClient: {
9
- signIn: {
10
- social: (options: {
11
- callbackURL: string;
12
- provider: string;
13
- }) => Promise<unknown>;
14
- };
15
- signOut: () => Promise<unknown>;
16
- }): {
10
+ export declare function createAuthActions(authStore: Observable<AuthState>, tokenStorage: TokenStorage, config: AuthConfig, authClient: AuthClientMethods): {
17
11
  /**
18
12
  * 初始化认证状态
19
13
  */
20
14
  initialize(user: SessionUser | null, isLoaded: boolean): Promise<void>;
21
15
  /**
22
16
  * 使用 Bearer Token 获取 session
23
- *
24
- * 流程:
25
- * 1. 保存 token 到 localStorage
26
- * 2. 使用 Bearer Token 请求 session endpoint
27
- * 3. 解析响应数据并提取用户信息
28
- * 4. 更新 authStore 状态
29
- *
30
- * @param token - Bearer Token
31
17
  */
32
18
  fetchSessionWithToken(token: string): Promise<void>;
33
19
  /**
34
- * 处理未授权错误(401 或其他认证失败)
35
- * 清理所有认证状态和本地存储
20
+ * 处理未授权
36
21
  */
37
22
  handleUnauthorized(): void;
38
23
  /**
@@ -44,17 +29,47 @@ export declare function createAuthActions(authStore: Observable<AuthState>, toke
44
29
  */
45
30
  setError(error: string | null): void;
46
31
  /**
47
- * 登录 - 使用 OAuth(默认 GitHub)
32
+ * OAuth 登录
48
33
  *
49
- * @param provider OAuth 提供商,默认为 'github'
50
- * @param redirectTo 登录成功后的重定向地址(完整 URL 或相对路径)
51
- * 如果未提供,将使用 defaultRedirectAfterLogin 配置
34
+ * 直接调用 better-auth signIn.social,传入完整的回调 URL
35
+ *
36
+ * @param provider - OAuth 提供商(如 github)
37
+ * @param callbackURL - 登录成功后的完整回调 URL
38
+ * @param newUserCallbackURL - 新用户的回调 URL(可选)
39
+ * @param errorCallbackURL - 登录失败后的完整回调 URL(可选)
52
40
  */
53
- signIn(provider?: string, redirectTo?: string): Promise<void>;
41
+ signIn(provider: string, callbackURL: string, newUserCallbackURL?: string, errorCallbackURL?: string): Promise<void>;
54
42
  /**
55
- * 登出
43
+ * Magic Link 登录
44
+ *
45
+ * 发送 Magic Link 到用户邮箱
46
+ *
47
+ * @param email - 用户邮箱
48
+ * @param callbackURL - 登录成功后的完整回调 URL
49
+ * @param name - 用户名称(可选,用于新用户)
50
+ * @param newUserCallbackURL - 新用户的回调 URL(可选)
51
+ * @returns 是否发送成功
52
+ */
53
+ signInWithMagicLink(email: string, callbackURL: string, name?: string, newUserCallbackURL?: string): Promise<boolean>;
54
+ /**
55
+ * Email/Password 登录
56
+ *
57
+ * @param email - 邮箱
58
+ * @param password - 密码
59
+ * @returns 是否登录成功
60
+ */
61
+ signInWithEmail(email: string, password: string): Promise<boolean>;
62
+ /**
63
+ * Email/Password 注册
56
64
  *
57
- * @param redirectTo 登出后的重定向地址(可选),如果不提供则不执行自动跳转
65
+ * @param email - 邮箱
66
+ * @param password - 密码
67
+ * @param name - 用户名
68
+ * @returns 是否注册成功
69
+ */
70
+ signUpWithEmail(email: string, password: string, name: string): Promise<boolean>;
71
+ /**
72
+ * 登出
58
73
  */
59
74
  signOut(redirectTo?: string): Promise<void>;
60
75
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../../src/store/actions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAClD,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AACtD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAC3C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAgE3C;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,UAAU,CAAC,SAAS,CAAC,EAChC,YAAY,EAAE,YAAY,EAC1B,MAAM,EAAE,UAAU,EAClB,UAAU,EAAE;IACV,MAAM,EAAE;QACN,MAAM,EAAE,CAAC,OAAO,EAAE;YAAE,WAAW,EAAE,MAAM,CAAC;YAAC,QAAQ,EAAE,MAAM,CAAA;SAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;KACjF,CAAA;IACD,OAAO,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAA;CAChC;IAcC;;OAEG;qBACoB,WAAW,GAAG,IAAI,YAAY,OAAO;IAe5D;;;;;;;;;;OAUG;iCACgC,MAAM;IAuDzC;;;OAGG;;IASH;;OAEG;wBACiB,OAAO;IAI3B;;OAEG;oBACa,MAAM,GAAG,IAAI;IAI7B;;;;;;OAMG;sBACoB,MAAM,eAA0B,MAAM;IAqC7D;;;;OAIG;yBACwB,MAAM;IAiCjC;;OAEG;qBACc,WAAW,GAAG,IAAI;IAUnC;;OAEG;eACQ,WAAW,GAAG,IAAI;EAIhC;AAED,MAAM,MAAM,WAAW,GAAG,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAA"}
1
+ {"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../../src/store/actions.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAClD,OAAO,KAAK,EAAE,iBAAiB,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AACrF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAA;AAG1C;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,UAAU,CAAC,SAAS,CAAC,EAChC,YAAY,EAAE,YAAY,EAC1B,MAAM,EAAE,UAAU,EAClB,UAAU,EAAE,iBAAiB;IAS3B;;OAEG;qBACoB,WAAW,GAAG,IAAI,YAAY,OAAO;IAe5D;;OAEG;iCACgC,MAAM;IAgDzC;;OAEG;;IAcH;;OAEG;wBACiB,OAAO;IAI3B;;OAEG;oBACa,MAAM,GAAG,IAAI;IAI7B;;;;;;;;;OASG;qBACoB,MAAM,eAAe,MAAM,uBAAuB,MAAM,qBAAqB,MAAM;IAsB1G;;;;;;;;;;OAUG;+BAEM,MAAM,eACA,MAAM,SACZ,MAAM,uBACQ,MAAM,GAC1B,OAAO,CAAC,OAAO,CAAC;IA+BnB;;;;;;OAMG;2BAC0B,MAAM,YAAY,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAuCxE;;;;;;;OAOG;2BAEM,MAAM,YACH,MAAM,QACV,MAAM,GACX,OAAO,CAAC,OAAO,CAAC;IAuCnB;;OAEG;yBACwB,MAAM;IA6BjC;;OAEG;qBACc,WAAW,GAAG,IAAI;IAUnC;;OAEG;eACQ,WAAW,GAAG,IAAI;EAIhC;AAED,MAAM,MAAM,WAAW,GAAG,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAA"}
@@ -1,67 +1,12 @@
1
1
  /**
2
- * 将日期转换为 ISO 字符串
2
+ * 认证 Actions
3
3
  */
4
- function toISOString(date) {
5
- if (!date)
6
- return undefined;
7
- return typeof date === "string" ? date : new Date(date).toISOString();
8
- }
4
+ import { extractSessionUser } from "../utils";
9
5
  /**
10
- * 从服务器响应中提取用户数据
11
- *
12
- * 支持多种数据结构格式以提供更好的兼容性:
13
- * - 标准格式: { user: {...}, session: {...} }
14
- * - 嵌套格式: { session: { user: {...} } }
15
- * - 包装格式: { data: { user: {...} } }
16
- * - 扁平格式: { id, email, ... }
17
- *
18
- * @param sessionData - 服务器返回的 session 数据
19
- * @returns 映射后的 SessionUser 对象,失败返回 null
20
- */
21
- function extractUserData(sessionData) {
22
- if (!sessionData || typeof sessionData !== "object")
23
- return null;
24
- const data = sessionData;
25
- // 尝试从不同的数据结构中提取用户信息
26
- const rawUserData = data.user || // 标准格式
27
- data.session?.user || // 嵌套格式
28
- data.data?.user || // 包装格式
29
- (data.id && data.email ? data : null); // 扁平格式
30
- if (!rawUserData || typeof rawUserData !== "object")
31
- return null;
32
- const user = rawUserData;
33
- // 提取 session 相关数据(activeOrganizationId 和 activeTeamId 存储在 session 中)
34
- const sessionInfo = data.session;
35
- const sessionCreatedAt = sessionInfo?.createdAt
36
- ? toISOString(sessionInfo.createdAt)
37
- : undefined;
38
- const activeOrganizationId = sessionInfo?.activeOrganizationId;
39
- const activeTeamId = sessionInfo?.activeTeamId;
40
- return {
41
- banExpires: user.banExpires,
42
- banReason: user.banReason,
43
- banned: user.banned,
44
- createdAt: toISOString(user.createdAt) ?? "",
45
- email: user.email,
46
- emailVerified: user.emailVerified ?? false,
47
- id: user.id,
48
- image: user.image || undefined,
49
- lastLoginAt: sessionCreatedAt,
50
- name: user.name,
51
- role: user.role,
52
- updatedAt: toISOString(user.updatedAt) ?? "",
53
- activeOrganizationId,
54
- activeTeamId,
55
- };
56
- }
57
- /**
58
- * 创建认证 actions
6
+ * 创建认证 Actions
59
7
  */
60
8
  export function createAuthActions(authStore, tokenStorage, config, authClient) {
61
- const { baseURL, defaultRedirectAfterLogin, getSessionEndpoint = "/v1/auth/get-session", callbackURLBuilder, } = config;
62
- const buildCallbackURL = callbackURLBuilder || ((redirectTo, baseURL) => {
63
- return `${baseURL}/v1/auth/redirect?to=${encodeURIComponent(redirectTo)}`;
64
- });
9
+ const { baseURL, getSessionEndpoint = "/v1/auth/get-session", skipTokenCleanupOnError = false, } = config;
65
10
  return {
66
11
  /**
67
12
  * 初始化认证状态
@@ -84,21 +29,12 @@ export function createAuthActions(authStore, tokenStorage, config, authClient) {
84
29
  },
85
30
  /**
86
31
  * 使用 Bearer Token 获取 session
87
- *
88
- * 流程:
89
- * 1. 保存 token 到 localStorage
90
- * 2. 使用 Bearer Token 请求 session endpoint
91
- * 3. 解析响应数据并提取用户信息
92
- * 4. 更新 authStore 状态
93
- *
94
- * @param token - Bearer Token
95
32
  */
96
33
  async fetchSessionWithToken(token) {
97
34
  try {
98
35
  if (!token) {
99
36
  throw new Error("Token is required");
100
37
  }
101
- // 保存 token 到 localStorage(供 authClient 使用)
102
38
  tokenStorage.save(token);
103
39
  const endpoint = `${baseURL}${getSessionEndpoint}`;
104
40
  const response = await fetch(endpoint, {
@@ -112,20 +48,17 @@ export function createAuthActions(authStore, tokenStorage, config, authClient) {
112
48
  throw new Error(`Failed to fetch session: ${response.status}`);
113
49
  }
114
50
  const responseText = await response.text();
115
- // 解析响应数据
116
51
  let sessionData = null;
117
52
  try {
118
53
  if (responseText && responseText !== "null" && responseText !== "") {
119
54
  sessionData = JSON.parse(responseText);
120
55
  }
121
56
  }
122
- catch (error) {
123
- console.error("[fetchSessionWithToken] Failed to parse session response:", error);
57
+ catch {
124
58
  this.handleUnauthorized();
125
59
  return;
126
60
  }
127
- // 提取并映射用户数据
128
- const userData = extractUserData(sessionData);
61
+ const userData = extractSessionUser(sessionData);
129
62
  if (userData) {
130
63
  authStore.user.set(userData);
131
64
  authStore.isAuthenticated.set(true);
@@ -133,24 +66,25 @@ export function createAuthActions(authStore, tokenStorage, config, authClient) {
133
66
  authStore.loading.set(false);
134
67
  }
135
68
  else {
136
- console.error("[fetchSessionWithToken] Invalid session data received");
137
69
  this.handleUnauthorized();
138
70
  }
139
71
  }
140
- catch (error) {
141
- console.error("[fetchSessionWithToken] Failed to fetch session:", error);
72
+ catch {
142
73
  this.handleUnauthorized();
143
74
  }
144
75
  },
145
76
  /**
146
- * 处理未授权错误(401 或其他认证失败)
147
- * 清理所有认证状态和本地存储
77
+ * 处理未授权
148
78
  */
149
79
  handleUnauthorized() {
150
80
  authStore.user.set(null);
151
81
  authStore.isAuthenticated.set(false);
152
82
  authStore.isLoaded.set(true);
153
83
  authStore.loading.set(false);
84
+ if (skipTokenCleanupOnError) {
85
+ console.warn("[Auth] Token cleanup skipped (skipTokenCleanupOnError is enabled)");
86
+ return;
87
+ }
154
88
  tokenStorage.clear();
155
89
  },
156
90
  /**
@@ -166,37 +100,28 @@ export function createAuthActions(authStore, tokenStorage, config, authClient) {
166
100
  authStore.error.set(error);
167
101
  },
168
102
  /**
169
- * 登录 - 使用 OAuth(默认 GitHub)
103
+ * OAuth 登录
104
+ *
105
+ * 直接调用 better-auth 的 signIn.social,传入完整的回调 URL
170
106
  *
171
- * @param provider OAuth 提供商,默认为 'github'
172
- * @param redirectTo 登录成功后的重定向地址(完整 URL 或相对路径)
173
- * 如果未提供,将使用 defaultRedirectAfterLogin 配置
107
+ * @param provider - OAuth 提供商(如 github
108
+ * @param callbackURL - 登录成功后的完整回调 URL
109
+ * @param newUserCallbackURL - 新用户的回调 URL(可选)
110
+ * @param errorCallbackURL - 登录失败后的完整回调 URL(可选)
174
111
  */
175
- async signIn(provider = "github", redirectTo) {
176
- // 防止重复点击
112
+ async signIn(provider, callbackURL, newUserCallbackURL, errorCallbackURL) {
177
113
  if (authStore.loading.get()) {
178
114
  return;
179
115
  }
180
116
  try {
181
117
  authStore.loading.set(true);
182
118
  authStore.error.set(null);
183
- if (!baseURL) {
184
- throw new Error("Auth baseURL is not configured");
185
- }
186
- // 构建重定向地址:相对路径自动添加 origin
187
- const finalRedirectTo = redirectTo
188
- ? redirectTo.startsWith("http")
189
- ? redirectTo
190
- : `${window.location.origin}${redirectTo}`
191
- : defaultRedirectAfterLogin
192
- ? `${window.location.origin}${defaultRedirectAfterLogin}`
193
- : `${window.location.origin}/explore`;
194
- const callbackURL = buildCallbackURL(finalRedirectTo, baseURL);
195
119
  await authClient.signIn.social({
196
120
  provider,
197
121
  callbackURL,
122
+ newUserCallbackURL,
123
+ errorCallbackURL,
198
124
  });
199
- // 注意:OAuth 重定向后,loading 状态会在页面刷新时重置
200
125
  }
201
126
  catch (error) {
202
127
  const message = error instanceof Error ? error.message : "Sign in failed";
@@ -205,12 +130,126 @@ export function createAuthActions(authStore, tokenStorage, config, authClient) {
205
130
  }
206
131
  },
207
132
  /**
208
- * 登出
133
+ * Magic Link 登录
134
+ *
135
+ * 发送 Magic Link 到用户邮箱
136
+ *
137
+ * @param email - 用户邮箱
138
+ * @param callbackURL - 登录成功后的完整回调 URL
139
+ * @param name - 用户名称(可选,用于新用户)
140
+ * @param newUserCallbackURL - 新用户的回调 URL(可选)
141
+ * @returns 是否发送成功
142
+ */
143
+ async signInWithMagicLink(email, callbackURL, name, newUserCallbackURL) {
144
+ if (authStore.loading.get()) {
145
+ return false;
146
+ }
147
+ if (!authClient.signIn.magicLink) {
148
+ authStore.error.set("Magic link is not available. Please add magicLinkClient() plugin.");
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
+ }
169
+ },
170
+ /**
171
+ * Email/Password 登录
209
172
  *
210
- * @param redirectTo 登出后的重定向地址(可选),如果不提供则不执行自动跳转
173
+ * @param email - 邮箱
174
+ * @param password - 密码
175
+ * @returns 是否登录成功
176
+ */
177
+ async signInWithEmail(email, password) {
178
+ if (authStore.loading.get()) {
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
+ }
208
+ },
209
+ /**
210
+ * Email/Password 注册
211
+ *
212
+ * @param email - 邮箱
213
+ * @param password - 密码
214
+ * @param name - 用户名
215
+ * @returns 是否注册成功
216
+ */
217
+ async signUpWithEmail(email, password, name) {
218
+ if (authStore.loading.get()) {
219
+ return false;
220
+ }
221
+ if (!authClient.signUp?.email) {
222
+ authStore.error.set("Email sign up is not available.");
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
+ },
238
+ });
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
+ }
248
+ },
249
+ /**
250
+ * 登出
211
251
  */
212
252
  async signOut(redirectTo) {
213
- // 防止重复调用
214
253
  if (authStore.loading.get()) {
215
254
  return;
216
255
  }
@@ -218,11 +257,9 @@ export function createAuthActions(authStore, tokenStorage, config, authClient) {
218
257
  authStore.loading.set(true);
219
258
  authStore.error.set(null);
220
259
  await authClient.signOut();
221
- // 清理本地状态
222
260
  authStore.user.set(null);
223
261
  authStore.isAuthenticated.set(false);
224
262
  tokenStorage.clear();
225
- // 如果提供了重定向地址,则执行跳转
226
263
  if (redirectTo) {
227
264
  window.location.href = redirectTo;
228
265
  }
@@ -230,7 +267,6 @@ export function createAuthActions(authStore, tokenStorage, config, authClient) {
230
267
  catch (error) {
231
268
  const message = error instanceof Error ? error.message : "Sign out failed";
232
269
  authStore.error.set(message);
233
- // 即使出错,也尝试清理本地状态
234
270
  authStore.user.set(null);
235
271
  authStore.isAuthenticated.set(false);
236
272
  tokenStorage.clear();
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Store 导出
3
+ */
4
+ export { createAuthStore, createTokenStorage } from "./state";
5
+ export { createAuthActions, type AuthActions } from "./actions";
6
+ export { createAuthComputed } from "./computed";
7
+ export { getCurrentUser, getCurrentUserId, isAuthenticated, isLoading, isLoaded, waitForAuth, getAuthToken, getAuthTokenSync, getAuthHeaders, getAuthHeadersSync, handle401Response, createUserManager, createBoundAuthUtils, } from "./utils";
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/store/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAA;AAC7D,OAAO,EAAE,iBAAiB,EAAE,KAAK,WAAW,EAAE,MAAM,WAAW,CAAA;AAC/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AAC/C,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,eAAe,EACf,SAAS,EACT,QAAQ,EACR,WAAW,EACX,YAAY,EACZ,gBAAgB,EAChB,cAAc,EACd,kBAAkB,EAClB,iBAAiB,EACjB,iBAAiB,EACjB,oBAAoB,GACrB,MAAM,SAAS,CAAA"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Store 导出
3
+ */
4
+ export { createAuthStore, createTokenStorage } from "./state";
5
+ export { createAuthActions } from "./actions";
6
+ export { createAuthComputed } from "./computed";
7
+ export { getCurrentUser, getCurrentUserId, isAuthenticated, isLoading, isLoaded, waitForAuth, getAuthToken, getAuthTokenSync, getAuthHeaders, getAuthHeadersSync, handle401Response, createUserManager, createBoundAuthUtils, } from "./utils";