@choiceform/shared-auth 0.1.14 → 0.1.16

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 (95) 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 -57
  18. package/dist/config.d.ts.map +1 -1
  19. package/dist/config.js +4 -6
  20. package/dist/core.d.ts +114 -72
  21. package/dist/core.d.ts.map +1 -1
  22. package/dist/core.js +35 -17
  23. package/dist/hooks/use-auth-init.d.ts +10 -0
  24. package/dist/hooks/use-auth-init.d.ts.map +1 -1
  25. package/dist/hooks/use-auth-init.js +59 -31
  26. package/dist/index.d.ts +12 -15
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +26 -13
  29. package/dist/init.d.ts +133 -92
  30. package/dist/init.d.ts.map +1 -1
  31. package/dist/init.js +12 -14
  32. package/dist/lib/auth-client.d.ts +49 -54
  33. package/dist/lib/auth-client.d.ts.map +1 -1
  34. package/dist/lib/auth-client.js +10 -16
  35. package/dist/services/companion-team.d.ts +16 -0
  36. package/dist/services/companion-team.d.ts.map +1 -0
  37. package/dist/services/companion-team.js +73 -0
  38. package/dist/services/index.d.ts +5 -0
  39. package/dist/services/index.d.ts.map +1 -0
  40. package/dist/services/index.js +4 -0
  41. package/dist/store/actions.d.ts +45 -33
  42. package/dist/store/actions.d.ts.map +1 -1
  43. package/dist/store/actions.js +135 -106
  44. package/dist/store/index.d.ts +8 -0
  45. package/dist/store/index.d.ts.map +1 -0
  46. package/dist/store/index.js +7 -0
  47. package/dist/store/state.d.ts +10 -7
  48. package/dist/store/state.d.ts.map +1 -1
  49. package/dist/store/state.js +31 -23
  50. package/dist/store/utils.d.ts +22 -71
  51. package/dist/store/utils.d.ts.map +1 -1
  52. package/dist/store/utils.js +28 -146
  53. package/dist/types/auth.d.ts +107 -0
  54. package/dist/types/auth.d.ts.map +1 -0
  55. package/dist/types/auth.js +4 -0
  56. package/dist/types/index.d.ts +8 -0
  57. package/dist/types/index.d.ts.map +1 -0
  58. package/dist/types/index.js +4 -0
  59. package/dist/types/organization.d.ts +111 -0
  60. package/dist/types/organization.d.ts.map +1 -0
  61. package/dist/types/organization.js +4 -0
  62. package/dist/types/team.d.ts +52 -0
  63. package/dist/types/team.d.ts.map +1 -0
  64. package/dist/types/team.js +4 -0
  65. package/dist/types/user.d.ts +44 -0
  66. package/dist/types/user.d.ts.map +1 -0
  67. package/dist/types/user.js +4 -0
  68. package/dist/utils/date.d.ts +10 -0
  69. package/dist/utils/date.d.ts.map +1 -0
  70. package/dist/utils/date.js +13 -0
  71. package/dist/utils/env.d.ts +20 -0
  72. package/dist/utils/env.d.ts.map +1 -0
  73. package/dist/utils/env.js +23 -0
  74. package/dist/utils/index.d.ts +7 -0
  75. package/dist/utils/index.d.ts.map +1 -0
  76. package/dist/utils/index.js +6 -0
  77. package/dist/utils/user-mapper.d.ts +21 -0
  78. package/dist/utils/user-mapper.d.ts.map +1 -0
  79. package/dist/utils/user-mapper.js +55 -0
  80. package/package.json +3 -4
  81. package/dist/components/auth-sync.d.ts +0 -25
  82. package/dist/components/auth-sync.d.ts.map +0 -1
  83. package/dist/components/auth-sync.js +0 -346
  84. package/dist/components/protected-route.d.ts +0 -18
  85. package/dist/components/protected-route.d.ts.map +0 -1
  86. package/dist/components/protected-route.js +0 -34
  87. package/dist/components/sign-in-page.d.ts +0 -21
  88. package/dist/components/sign-in-page.d.ts.map +0 -1
  89. package/dist/components/sign-in-page.js +0 -31
  90. package/dist/core/init-auth-sync.d.ts +0 -7
  91. package/dist/core/init-auth-sync.d.ts.map +0 -1
  92. package/dist/core/init-auth-sync.js +0 -34
  93. package/dist/types.d.ts +0 -87
  94. package/dist/types.d.ts.map +0 -1
  95. package/dist/types.js +0 -4
package/README.md CHANGED
@@ -1,20 +1,15 @@
1
1
  # @choiceform/shared-auth
2
2
 
3
- 共享认证包 - 用于 Choiceform 项目的统一认证解决方案
3
+ 共享认证包 - 基于 Better Auth 的统一认证解决方案
4
4
 
5
5
  ## 功能特性
6
6
 
7
- - Better Auth 集成
8
- - Legend State 状态管理
9
- - ✅ GitHub OAuth 支持
10
- - Token 自动管理和持久化
11
- - 路由保护组件
12
- - 登录页面组件(可定制)
13
- - ✅ 完整的 TypeScript 类型支持
14
- - ✅ 预配置的 API 客户端(自动添加认证头)
15
- - ✅ 用户管理器工具
16
- - ✅ 响应式状态管理(基于 Legend State)
17
- - ✅ 自动伴生团队设置(登录时自动获取并设置活动组织和团队)
7
+ - Better Auth 集成(OAuth、Magic Link)
8
+ - Legend State 状态管理
9
+ - 自动伴生团队设置
10
+ - Token 自动管理
11
+ - 完整 TypeScript 类型支持
12
+ - 预配置 API 客户端
18
13
 
19
14
  ## 安装
20
15
 
@@ -22,230 +17,119 @@
22
17
  pnpm add @choiceform/shared-auth
23
18
  ```
24
19
 
25
- ## 环境变量配置
26
-
27
- 在使用认证功能前,需要在项目根目录配置环境变量:
20
+ ## 环境变量
28
21
 
29
22
  ```bash
30
- # .env
31
- VITE_AUTH_API_URL=http://localhost:4320
23
+ VITE_ONEAUTH_BASE_URL=https://oneauth.choiceform.io
32
24
  ```
33
25
 
34
- **注意:** 如果你的项目仍在使用 `VITE_CORE_AI_API_URL`,代码会自动向后兼容,但建议迁移到新的 `VITE_AUTH_API_URL`。
35
-
36
- ### 伴生团队功能
37
-
38
- `AuthSync` 组件会在用户登录成功后自动:
39
-
40
- 1. 从 OneAuth API 获取用户的组织信息
41
- 2. 设置活动组织
42
- 3. 设置活动团队(如果存在)
43
-
44
- 此功能需要 `VITE_AUTH_API_URL` 环境变量已配置。如果未配置,功能会静默跳过,不影响登录流程。
45
-
46
26
  ## 快速开始
47
27
 
48
- ### 1. 初始化认证系统
28
+ ### 初始化
49
29
 
50
30
  ```typescript
51
31
  import { initAuth } from "@choiceform/shared-auth"
52
- import { adminClient, organizationClient } from "better-auth/client/plugins"
53
32
 
54
33
  export const auth = initAuth({
55
- baseURL: import.meta.env.VITE_AUTH_API_URL || "http://localhost:4320",
34
+ baseURL: import.meta.env.VITE_ONEAUTH_BASE_URL,
56
35
  tokenStorageKey: "auth-token",
57
- // 可选:如果你想自定义插件
58
- plugins: [adminClient(), organizationClient({ teams: { enabled: true } })],
59
36
  })
60
-
61
- // 注意:导航相关配置已移至组件层面:
62
- // - 登录成功后的导航:在 SignInPage 组件中通过 onAuthSuccess 回调处理
63
- // - 未授权时的导航:在 ProtectedRoute 组件中通过 onUnauthorized 回调处理
64
- // - 登出后的导航:在调用 signOut 时传入 redirectTo 参数
65
37
  ```
66
38
 
67
- ### 2. 在应用中使用
39
+ ### 在应用中使用
68
40
 
69
41
  ```typescript
70
- import { AuthSync, ProtectedRoute, useAuthInit } from "@choiceform/shared-auth"
71
- import { useNavigate } from "react-router"
42
+ import { use$ } from "@legendapp/state/react"
72
43
  import { auth } from "./lib/auth"
73
44
 
74
45
  function App() {
75
- const navigate = useNavigate()
76
- useAuthInit(auth)
77
-
78
- return (
79
- <>
80
- <AuthSync auth={auth} />
81
- <Router>
82
- <Route path="/sign-in" element={<SignInPage />} />
83
- <Route
84
- path="/*"
85
- element={
86
- <ProtectedRoute
87
- auth={auth}
88
- onUnauthorized={() => navigate("/sign-in", { replace: true })}
89
- >
90
- <YourApp />
91
- </ProtectedRoute>
92
- }
93
- />
94
- </Router>
95
- </>
96
- )
46
+ const { isAuthenticated, user } = use$(auth.authStore)
47
+
48
+ if (!isAuthenticated) {
49
+ return <SignInPage />
50
+ }
51
+
52
+ return <MainApp user={user} />
97
53
  }
98
54
  ```
99
55
 
100
- ### 3. 使用登录页面组件
56
+ ### 登录
101
57
 
102
58
  ```typescript
103
- import { SignInPage } from "@choiceform/shared-auth"
104
- import { useNavigate } from "react-router"
105
- import { auth } from "./lib/auth"
59
+ // OAuth 登录
60
+ const handleOAuthSignIn = async () => {
61
+ const callbackURL = new URL("/dashboard", window.location.origin)
62
+ const newUserCallbackURL = new URL("/dashboard?isNew=true", window.location.origin)
63
+
64
+ await auth.authActions.signIn(
65
+ "github",
66
+ callbackURL.toString(),
67
+ newUserCallbackURL.toString()
68
+ )
69
+ }
106
70
 
107
- function LoginPage() {
108
- const navigate = useNavigate()
71
+ // Magic Link 登录
72
+ const handleMagicLink = async (email: string) => {
73
+ const callbackURL = new URL("/dashboard", window.location.origin)
109
74
 
110
- return (
111
- <SignInPage
112
- auth={auth}
113
- title="Your App Title"
114
- description="Your app description"
115
- provider="github"
116
- redirectUrl="/dashboard"
117
- onAuthSuccess={() => navigate("/dashboard")}
118
- githubButton={(isSigningIn) => (
119
- <button disabled={isSigningIn}>
120
- {isSigningIn ? "Redirecting to GitHub..." : "Sign in with GitHub"}
121
- </button>
122
- )}
123
- />
75
+ await auth.authActions.signInWithMagicLink(
76
+ email,
77
+ callbackURL.toString()
124
78
  )
125
79
  }
126
80
  ```
127
81
 
128
- ## API 文档
129
-
130
- ### `initAuth(config)`
131
-
132
- 快速初始化认证系统(使用默认配置)。
133
-
134
- **参数:**
135
-
136
- - `baseURL`: Better Auth API 基础 URL(必需)
137
- - `tokenStorageKey?`: Token 存储的 localStorage key(默认: `'auth-token'`)
138
- - `plugins?`: Better Auth 插件列表(默认包含 `organizationClient()`)
139
- - ~~`defaultRedirectAfterLogin?`~~: (已废弃) 建议在 SignInPage 组件中通过 `redirectUrl` prop 传入
140
- - ~~`signInPath?`~~: (已废弃) 建议在 ProtectedRoute 组件中通过 `onUnauthorized` 回调处理导航
141
-
142
- **返回:** `AuthInstance`
143
-
144
- ### `createAuth(config)`
145
-
146
- 创建认证系统实例(更灵活的配置选项)。
147
-
148
- **参数:**
149
-
150
- - `baseURL`: Better Auth API 基础 URL(必需)
151
- - `tokenStorageKey?`: Token 存储的 localStorage key(默认: `'auth-token'`)
152
- - `plugins?`: Better Auth 插件列表
153
- - `callbackURLBuilder?`: 自定义回调 URL 构建函数
154
- - `getSessionEndpoint?`: 获取 session 的端点路径(默认: `'/v1/auth/get-session'`)
155
- - ~~`defaultRedirectAfterLogin?`~~: (已废弃) 建议在 SignInPage 组件中通过 `redirectUrl` prop 传入
156
- - ~~`signInPath?`~~: (已废弃) 建议在 ProtectedRoute 组件中通过 `onUnauthorized` 回调处理导航
157
-
158
- **返回:** `AuthInstance`
159
-
160
- ### `AuthInstance`
161
-
162
- 认证实例包含以下属性和方法:
163
-
164
- **核心属性:**
165
-
166
- - `authStore`: Legend State store(响应式状态)
167
- - `authActions`: 认证操作(signIn, signOut, initialize 等)
168
- - `authComputed`: 计算属性(isInitializing 等)
169
- - `authClient`: Better Auth 客户端
170
- - `tokenStorage`: Token 存储工具
171
-
172
- **工具方法(已绑定到实例):**
173
-
174
- - `getCurrentUser()`: 获取当前用户
175
- - `getCurrentUserId()`: 获取当前用户ID
176
- - `getCurrentUserIdSafe()`: 安全获取当前用户ID
177
- - `isAuthenticated()`: 检查是否已认证
178
- - `isLoading()`: 检查是否正在加载
179
- - `isLoaded()`: 检查是否已加载
180
- - `waitForAuth()`: 等待认证完成
181
- - `getAuthToken()`: 获取认证 Token
182
- - `getAuthHeaders()`: 获取认证 Headers
183
- - `apiClient`: 预配置的 API 客户端(包含 get/post/put/delete 方法)
184
- - `userManager`: 用户管理器(包含 getUser/getUserId 方法)
185
-
186
- ### `AuthSync`
187
-
188
- Better Auth 认证状态同步组件。
189
-
190
- **功能:**
82
+ ### 认证状态同步
191
83
 
192
- - 同步 better-auth 的 session 状态到应用 store
193
- - 在用户登录成功后自动设置伴生团队(活动组织和团队)
194
- - 使用响应式状态监听,确保状态同步的实时性
84
+ 新用户登录后,使用 `setupCompanionTeam` 设置伴生组织和团队:
195
85
 
196
- **Props:**
197
-
198
- - `auth`: AuthInstance
199
-
200
- **注意:** 此组件需要在应用的根组件中渲染,通常与 `ProtectedRoute` 一起使用。
201
-
202
- ### `ProtectedRoute`
203
-
204
- 路由保护组件。
86
+ ```typescript
87
+ import { setupCompanionTeam } from "@choiceform/shared-auth"
88
+
89
+ // 在认证成功后调用
90
+ setupCompanionTeam(auth, token, {
91
+ isNewUser: searchParams.get("isNew") === "true",
92
+ onComplete: () => {
93
+ // 刷新 session
94
+ },
95
+ })
96
+ ```
205
97
 
206
- **Props:**
98
+ ## API
207
99
 
208
- - `auth`: AuthInstance
209
- - `children`: React.ReactNode
210
- - `onUnauthorized`: () => void - 当用户未认证时的回调函数(用于导航到登录页)
211
- - `loadingComponent?`: React.ComponentType<{ message?: string }> - 自定义加载组件
212
- - `loadingMessage?`: string - 加载中消息(默认: `'Checking authentication...'`)
100
+ ### `initAuth(config)`
213
101
 
214
- ### `SignInPage`
102
+ 快速初始化(使用默认配置)。
215
103
 
216
- 登录页面组件。
104
+ | 参数 | 类型 | 说明 |
105
+ |------|------|------|
106
+ | baseURL | string | OneAuth API 地址 |
107
+ | tokenStorageKey | string | localStorage key(默认 `auth-token`) |
108
+ | plugins | BetterAuthPlugin[] | Better Auth 插件 |
217
109
 
218
- **Props:**
110
+ ### `createAuth(config)`
219
111
 
220
- - `auth`: AuthInstance
221
- - `className?`: string - 自定义样式类名
222
- - `title?`: string - 标题
223
- - `description?`: string - 描述
224
- - `provider?`: string - OAuth 提供商(默认: `'github'`)
225
- - `redirectUrl?`: string - OAuth 回调重定向地址(默认: `'/explore'`)
226
- - `onAuthSuccess?`: () => void - 认证成功后的回调函数(用于导航)
227
- - `githubButton?`: (isSigningIn: boolean) => React.ReactNode - 自定义 GitHub 登录按钮渲染函数
228
- - `beforeElement?`: React.ReactNode - 在登录表单之前渲染的元素
229
- - `afterElement?`: React.ReactNode - 在登录表单之后渲染的元素
230
- - `footerText?`: React.ReactNode - 页脚文本
112
+ 创建认证实例(完整配置)。
231
113
 
232
- ## 工具函数
114
+ ### AuthInstance
233
115
 
234
- ### 使用已绑定的工具方法(推荐)
116
+ | 属性 | 说明 |
117
+ |------|------|
118
+ | authStore | Legend State store |
119
+ | authActions | 认证操作(signIn, signOut 等) |
120
+ | authApi | 认证 API |
121
+ | organizationApi | 组织 API |
122
+ | teamApi | 团队 API |
123
+ | tokenStorage | Token 存储工具 |
235
124
 
236
- 认证实例已包含所有工具方法,可以直接使用:
125
+ ### 工具方法
237
126
 
238
127
  ```typescript
239
- import { auth } from "./lib/auth"
240
-
241
- // 获取当前用户
128
+ // 获取用户
242
129
  const user = auth.getCurrentUser()
243
-
244
- // 获取当前用户ID
245
130
  const userId = auth.getCurrentUserId()
246
- const userIdSafe = auth.getCurrentUserIdSafe()
247
131
 
248
- // 检查认证状态
132
+ // 认证状态
249
133
  const authenticated = auth.isAuthenticated()
250
134
  const loading = auth.isLoading()
251
135
  const loaded = auth.isLoaded()
@@ -253,300 +137,72 @@ const loaded = auth.isLoaded()
253
137
  // 等待认证完成
254
138
  await auth.waitForAuth()
255
139
 
256
- // 获取认证 Token
257
- const token = await auth.getAuthToken()
258
-
259
- // 获取认证 Headers
260
- const headers = await auth.getAuthHeaders()
261
-
262
- // 使用预配置的 API 客户端
263
- const response = await auth.apiClient.get("/api/users")
264
- const data = await auth.apiClient.post("/api/data", { name: "test" })
265
-
266
- // 使用用户管理器
267
- const user = auth.userManager.getUser()
268
- const userId = auth.userManager.getUserId()
140
+ // Token
141
+ const token = auth.getAuthTokenSync()
142
+ const headers = auth.getAuthHeadersSync()
269
143
  ```
270
144
 
271
- ### 使用独立的工具函数
272
-
273
- 如果需要独立的工具函数(需要手动传入参数),可以从包中导入:
274
-
275
- ```typescript
276
- import {
277
- getCurrentUser,
278
- getCurrentUserId,
279
- isAuthenticated,
280
- getAuthToken,
281
- getAuthHeaders,
282
- createApiClient,
283
- createUserManager,
284
- } from "@choiceform/shared-auth"
285
-
286
- // 使用独立的工具函数(需要传入 authStore 等参数)
287
- const user = getCurrentUser(auth.authStore)
288
- const userId = getCurrentUserId(auth.authStore)
289
- const authenticated = isAuthenticated(auth.authStore)
290
-
291
- // 创建 API 客户端
292
- const apiClient = createApiClient(
293
- auth.authStore,
294
- auth.tokenStorage,
295
- auth.authActions,
296
- auth.authClient
297
- )
298
-
299
- // 创建用户管理器
300
- const userManager = createUserManager(auth.authStore)
301
- ```
302
-
303
- ## 类型定义
145
+ ## 类型
304
146
 
305
147
  ```typescript
306
148
  import type {
307
149
  SessionUser,
308
- Session,
309
150
  AuthState,
310
151
  AuthConfig,
311
- AuthInstance,
312
- AuthActions,
313
- TokenStorage,
152
+ Organization,
153
+ Team,
154
+ Member,
314
155
  } from "@choiceform/shared-auth"
315
156
  ```
316
157
 
317
- ### 类型说明
318
-
319
- - `SessionUser`: 用户信息类型
320
- - `Session`: 会话信息类型
321
- - `AuthState`: 认证状态类型(包含 user, isAuthenticated, loading 等)
322
- - `AuthConfig`: 认证配置类型
323
- - `AuthInstance`: 认证实例类型(`initAuth` 或 `createAuth` 的返回值)
324
- - `AuthActions`: 认证操作类型
325
- - `TokenStorage`: Token 存储工具类型
326
-
327
- ## 环境变量
328
-
329
- ### 必需的环境变量
330
-
331
- - `VITE_AUTH_API_URL`: Better Auth API 基础 URL
332
-
333
- ### 示例配置
334
-
335
- 参考项目根目录的 `.env.example` 文件:
336
-
337
- ```bash
338
- # .env
339
- VITE_AUTH_API_URL=http://localhost:4320
340
- ```
341
-
342
- ### 向后兼容
343
-
344
- 如果你的项目仍在使用 `VITE_CORE_AI_API_URL`,代码会自动向后兼容:
158
+ ### SessionUser
345
159
 
346
160
  ```typescript
347
- baseURL: import.meta.env.VITE_AUTH_API_URL || import.meta.env.VITE_CORE_AI_API_URL || "http://localhost:4320"
161
+ interface SessionUser {
162
+ id: string
163
+ email: string
164
+ name: string
165
+ image?: string
166
+ metadata?: { color?: string }
167
+ inherentOrganizationId?: string // 伴生组织
168
+ inherentTeamId?: string // 伴生团队
169
+ activeOrganizationId?: string
170
+ activeTeamId?: string
171
+ // ...
172
+ }
348
173
  ```
349
174
 
350
- 但建议迁移到新的 `VITE_AUTH_API_URL`。
351
-
352
- ## 响应式状态使用
353
-
354
- 由于认证状态使用 Legend State 管理,你可以在 React 组件中使用 `use$` hook 来响应式地访问状态:
175
+ ## 响应式状态
355
176
 
356
177
  ```typescript
357
178
  import { use$ } from "@legendapp/state/react"
358
179
  import { auth } from "./lib/auth"
359
180
 
360
- function UserProfile() {
361
- // 响应式获取用户信息
181
+ function Profile() {
362
182
  const user = use$(auth.authStore.user)
363
- const isAuthenticated = use$(auth.authStore.isAuthenticated)
364
183
  const loading = use$(auth.authStore.loading)
365
184
 
366
- if (loading) {
367
- return <div>Loading...</div>
368
- }
185
+ if (loading) return <Loading />
186
+ if (!user) return <SignIn />
369
187
 
370
- if (!isAuthenticated) {
371
- return <div>Please sign in</div>
372
- }
373
-
374
- return (
375
- <div>
376
- <h1>Welcome, {user?.name}</h1>
377
- <p>Email: {user?.email}</p>
378
- </div>
379
- )
380
- }
381
- ```
382
-
383
- ### 使用计算属性
384
-
385
- ```typescript
386
- import { use$ } from "@legendapp/state/react"
387
- import { auth } from "./lib/auth"
388
-
389
- function AuthStatus() {
390
- // 使用计算属性检查初始化状态
391
- const isInitializing = use$(auth.authComputed.isInitializing)
392
-
393
- if (isInitializing) {
394
- return <div>Initializing...</div>
395
- }
396
-
397
- return <div>Ready</div>
188
+ return <div>Hello, {user.name}</div>
398
189
  }
399
190
  ```
400
191
 
401
- ## 最佳实践
402
-
403
- ### 1. 在组件中使用响应式状态
404
-
405
- 优先使用 `use$` hook 来访问响应式状态,而不是直接调用 `getCurrentUser()` 等方法:
406
-
407
- ```typescript
408
- // ✅ 推荐:响应式更新
409
- const user = use$(auth.authStore.user)
410
-
411
- // ❌ 不推荐:非响应式
412
- const user = auth.getCurrentUser()
413
- ```
414
-
415
- ### 2. 使用 API 客户端进行 API 调用
416
-
417
- 使用预配置的 `apiClient` 可以自动处理认证头和处理 401 响应:
418
-
419
- ```typescript
420
- // ✅ 推荐:使用 apiClient
421
- const response = await auth.apiClient.get("/api/users")
422
- const data = await response.json()
423
-
424
- // ❌ 不推荐:手动添加认证头
425
- const headers = await auth.getAuthHeaders()
426
- const response = await fetch("/api/users", { headers })
427
- ```
428
-
429
- ### 3. 等待认证完成
430
-
431
- 在进行需要认证的操作前,使用 `waitForAuth()` 确保认证已初始化:
432
-
433
- ```typescript
434
- // ✅ 推荐:等待认证完成
435
- await auth.waitForAuth()
436
- if (auth.isAuthenticated()) {
437
- // 执行需要认证的操作
438
- }
439
-
440
- // ❌ 不推荐:直接检查状态(可能尚未初始化)
441
- if (auth.isAuthenticated()) {
442
- // 可能不准确
443
- }
444
- ```
445
-
446
- ### 4. 错误处理
447
-
448
- 认证操作可能会失败,确保适当处理错误:
449
-
450
- ```typescript
451
- try {
452
- await auth.authActions.signIn("github", redirectUrl)
453
- } catch (error) {
454
- console.error("Sign in failed:", error)
455
- // 显示错误提示给用户
456
- }
457
- ```
458
-
459
- ### 5. 退出登录
460
-
461
- 退出登录时使用 `signOut` 方法,可以选择性地传入重定向地址:
462
-
463
- ```typescript
464
- async function handleSignOut() {
465
- try {
466
- // 传入重定向地址,登出后会自动跳转
467
- await auth.authActions.signOut("/sign-in")
468
-
469
- // 或者不传入地址,由调用方手动处理后续导航
470
- // await auth.authActions.signOut()
471
- // navigate("/sign-in")
472
- } catch (error) {
473
- console.error("Sign out failed:", error)
474
- }
475
- }
476
- ```
477
-
478
- ## 常见问题
479
-
480
- ### Q: 如何在非 React 环境中使用?
481
-
482
- A: 可以使用独立的工具函数,它们不依赖 React:
483
-
484
- ```typescript
485
- import { getCurrentUser, isAuthenticated } from "@choiceform/shared-auth"
486
-
487
- const user = getCurrentUser(auth.authStore)
488
- const authenticated = isAuthenticated(auth.authStore)
489
- ```
490
-
491
- ### Q: 如何处理 Token 过期?
492
-
493
- A: `apiClient` 会自动处理 401 响应,当检测到未授权时会调用 `handleUnauthorized`,通常会清除认证状态并重定向到登录页面。
494
-
495
- ### Q: 如何自定义认证流程?
496
-
497
- A: 可以使用 `createAuth` 替代 `initAuth`,它提供更多配置选项,包括自定义回调 URL 构建函数等。
498
-
499
- ### Q: 伴生团队功能是什么?
500
-
501
- A: 在用户登录成功后,`AuthSync` 组件会自动:
502
-
503
- - 从 OneAuth API (`/v1/organizations/me`) 获取用户的组织信息
504
- - 调用 better-auth API 设置活动组织 (`/v1/auth/organization/set-active`)
505
- - 调用 better-auth API 设置活动团队 (`/v1/auth/organization/set-active-team`)
506
-
507
- 这确保了用户在登录后拥有正确的权限上下文。如果此功能失败,不会影响登录流程,只会在控制台记录错误信息。
508
-
509
- ### Q: 如何禁用伴生团队功能?
510
-
511
- A: 不配置 `VITE_AUTH_API_URL` 环境变量即可。功能会静默跳过。
512
-
513
- ## Token 存储机制
514
-
515
- ### Token 编码
516
-
517
- 为了确保 token 在 localStorage 中安全存储,系统会在存储时自动使用 `encodeURIComponent` 进行编码:
518
-
519
- - **存储时**:token 会自动编码后存储到 localStorage
520
- - **读取时**:token 从 localStorage 读取后直接使用(编码后的值)
521
- - **发送请求时**:在构建 Authorization header 时会再次使用 `encodeURIComponent` 编码
522
-
523
- 这种双重编码机制确保了:
524
-
525
- 1. localStorage 中存储的是编码后的安全值
526
- 2. API 请求时 token 会被正确编码传输
527
-
528
- ### Token 存储位置
529
-
530
- Token 默认存储在 localStorage 中,key 为 `auth-token`(可通过 `tokenStorageKey` 配置项自定义)。
531
-
532
192
  ## 更新日志
533
193
 
534
- ### v0.1.6
535
-
536
- - 🔧 改进:Token 存储时使用 `encodeURIComponent` 编码,确保 localStorage 中安全存储
537
- - 📝 改进:完善 Token 存储机制文档说明
538
-
539
- ### v0.1.2
194
+ ### v0.2.0
540
195
 
541
- - 新增:登录时自动获取并设置伴生团队功能
542
- - 🔧 改进:优化错误处理和边缘情况处理
543
- - 📝 改进:完善代码文档和注释
544
- - 🐛 修复:修复 token 编码问题,确保 API 调用正常工作
196
+ - 服务器地址更换为 `https://oneauth.choiceform.io`
197
+ - 伴生组织/团队改从 session 获取(`inherentOrganizationId`、`inherentTeamId`)
198
+ - 新增 `onboard` API、Magic Link 支持
199
+ - 移除 UI 组件(`AuthSync`、`ProtectedRoute`、`SignInPage`),由业务端实现
200
+ - 代码清理和优化
545
201
 
546
- ### v0.1.1
202
+ ### v0.1.x
547
203
 
548
204
  - 初始版本
549
205
 
550
- ## 许可证
206
+ ## License
551
207
 
552
208
  MIT
@@ -0,0 +1,28 @@
1
+ /**
2
+ * 认证 API
3
+ */
4
+ import type { MagicLinkRequest, SessionUser, SetActiveOrganizationRequest, SetActiveTeamRequest, UpdateUserRequest } from "../types";
5
+ import { type ApiClient } from "./client";
6
+ export declare function createAuthApi(apiClient: ApiClient, baseURL: string): {
7
+ getSession(token?: string): Promise<SessionUser | null>;
8
+ getSessionWithToken(token: string): Promise<SessionUser | null>;
9
+ setActiveOrganization(params: SetActiveOrganizationRequest, token?: string): Promise<void>;
10
+ setActiveTeam(params: SetActiveTeamRequest, token?: string): Promise<void>;
11
+ onboard(token: string): Promise<void>;
12
+ updateUser(data: UpdateUserRequest): Promise<SessionUser | null>;
13
+ sendMagicLink(params: MagicLinkRequest): Promise<{
14
+ status: boolean;
15
+ }>;
16
+ /**
17
+ * 为已登录用户绑定密码
18
+ * 用于通过 OAuth 或 Magic Link 登录的用户设置密码
19
+ */
20
+ linkCredential(newPassword: string, token?: string): Promise<void>;
21
+ /**
22
+ * 检查邮箱是否已注册
23
+ * 注意:此 API 可能不存在,调用时需要处理错误
24
+ */
25
+ checkEmailExists(email: string): Promise<boolean>;
26
+ };
27
+ export type AuthApi = ReturnType<typeof createAuthApi>;
28
+ //# sourceMappingURL=auth-api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-api.d.ts","sourceRoot":"","sources":["../../src/api/auth-api.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EACV,gBAAgB,EAChB,WAAW,EACX,4BAA4B,EAC5B,oBAAoB,EACpB,iBAAiB,EAClB,MAAM,UAAU,CAAA;AAEjB,OAAO,EAAsB,KAAK,SAAS,EAAE,MAAM,UAAU,CAAA;AAE7D,wBAAgB,aAAa,CAAC,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM;uBAEtC,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;+BAe5B,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;kCAgBjC,4BAA4B,UAAU,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;0BAepE,oBAAoB,UAAU,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;mBAe3D,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;qBAcpB,iBAAiB,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;0BAQ1C,gBAAgB,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,OAAO,CAAA;KAAE,CAAC;IAc3E;;;OAGG;gCAC+B,MAAM,UAAU,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAgBxE;;;OAGG;4BAC2B,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;EAqB1D;AAED,MAAM,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAA"}