@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.
Files changed (100) hide show
  1. package/README.md +504 -121
  2. package/dist/__tests__/auth-utils.test.d.ts +5 -0
  3. package/dist/__tests__/auth-utils.test.d.ts.map +1 -0
  4. package/dist/__tests__/auth-utils.test.js +96 -0
  5. package/dist/__tests__/store.test.d.ts +5 -0
  6. package/dist/__tests__/store.test.d.ts.map +1 -0
  7. package/dist/__tests__/store.test.js +210 -0
  8. package/dist/__tests__/user-mapper.test.d.ts +5 -0
  9. package/dist/__tests__/user-mapper.test.d.ts.map +1 -0
  10. package/dist/__tests__/user-mapper.test.js +76 -0
  11. package/dist/api/auth-api.d.ts +93 -9
  12. package/dist/api/auth-api.d.ts.map +1 -1
  13. package/dist/api/auth-api.js +219 -80
  14. package/dist/api/client.d.ts +10 -0
  15. package/dist/api/client.d.ts.map +1 -1
  16. package/dist/api/client.js +10 -0
  17. package/dist/api/organization-api.d.ts +2 -7
  18. package/dist/api/organization-api.d.ts.map +1 -1
  19. package/dist/api/organization-api.js +2 -17
  20. package/dist/api/team-api.d.ts +1 -5
  21. package/dist/api/team-api.d.ts.map +1 -1
  22. package/dist/api/team-api.js +5 -11
  23. package/dist/config.js +1 -1
  24. package/dist/core.d.ts +257 -137
  25. package/dist/core.d.ts.map +1 -1
  26. package/dist/core.js +112 -28
  27. package/dist/hooks/index.d.ts +8 -0
  28. package/dist/hooks/index.d.ts.map +1 -0
  29. package/dist/hooks/index.js +7 -0
  30. package/dist/hooks/use-auth-init.d.ts +4 -0
  31. package/dist/hooks/use-auth-init.d.ts.map +1 -1
  32. package/dist/hooks/use-auth-init.js +16 -21
  33. package/dist/hooks/use-auth-sync.d.ts +60 -0
  34. package/dist/hooks/use-auth-sync.d.ts.map +1 -0
  35. package/dist/hooks/use-auth-sync.js +116 -0
  36. package/dist/hooks/use-email-verification.d.ts +85 -0
  37. package/dist/hooks/use-email-verification.d.ts.map +1 -0
  38. package/dist/hooks/use-email-verification.js +145 -0
  39. package/dist/hooks/use-protected-route.d.ts +67 -0
  40. package/dist/hooks/use-protected-route.d.ts.map +1 -0
  41. package/dist/hooks/use-protected-route.js +102 -0
  42. package/dist/index.d.ts +12 -6
  43. package/dist/index.d.ts.map +1 -1
  44. package/dist/index.js +45 -13
  45. package/dist/init.d.ts +236 -136
  46. package/dist/init.d.ts.map +1 -1
  47. package/dist/lib/auth-client.d.ts +108 -66
  48. package/dist/lib/auth-client.d.ts.map +1 -1
  49. package/dist/lib/auth-client.js +75 -2
  50. package/dist/services/auth-service.d.ts +101 -0
  51. package/dist/services/auth-service.d.ts.map +1 -0
  52. package/dist/services/auth-service.js +356 -0
  53. package/dist/services/callback-service.d.ts +33 -0
  54. package/dist/services/callback-service.d.ts.map +1 -0
  55. package/dist/services/callback-service.js +473 -0
  56. package/dist/services/companion-team.d.ts.map +1 -1
  57. package/dist/services/companion-team.js +41 -39
  58. package/dist/services/index.d.ts +3 -0
  59. package/dist/services/index.d.ts.map +1 -1
  60. package/dist/services/index.js +3 -0
  61. package/dist/services/referral-service.d.ts +54 -0
  62. package/dist/services/referral-service.d.ts.map +1 -0
  63. package/dist/services/referral-service.js +54 -0
  64. package/dist/store/actions.d.ts +54 -51
  65. package/dist/store/actions.d.ts.map +1 -1
  66. package/dist/store/actions.js +111 -243
  67. package/dist/store/computed.d.ts +72 -1
  68. package/dist/store/computed.d.ts.map +1 -1
  69. package/dist/store/computed.js +90 -3
  70. package/dist/store/index.d.ts +3 -3
  71. package/dist/store/index.d.ts.map +1 -1
  72. package/dist/store/index.js +2 -2
  73. package/dist/store/state.d.ts +10 -0
  74. package/dist/store/state.d.ts.map +1 -1
  75. package/dist/store/state.js +11 -1
  76. package/dist/store/utils.d.ts +3 -34
  77. package/dist/store/utils.d.ts.map +1 -1
  78. package/dist/store/utils.js +2 -22
  79. package/dist/types/auth.d.ts +106 -0
  80. package/dist/types/auth.d.ts.map +1 -1
  81. package/dist/types/callback.d.ts +35 -0
  82. package/dist/types/callback.d.ts.map +1 -0
  83. package/dist/types/callback.js +1 -0
  84. package/dist/types/index.d.ts +4 -3
  85. package/dist/types/index.d.ts.map +1 -1
  86. package/dist/types/organization.d.ts +19 -3
  87. package/dist/types/organization.d.ts.map +1 -1
  88. package/dist/types/team.d.ts +6 -2
  89. package/dist/types/team.d.ts.map +1 -1
  90. package/dist/types/user.d.ts +11 -3
  91. package/dist/types/user.d.ts.map +1 -1
  92. package/dist/utils/auth-utils.d.ts +60 -0
  93. package/dist/utils/auth-utils.d.ts.map +1 -0
  94. package/dist/utils/auth-utils.js +146 -0
  95. package/dist/utils/index.d.ts +1 -0
  96. package/dist/utils/index.d.ts.map +1 -1
  97. package/dist/utils/index.js +1 -0
  98. package/dist/utils/user-mapper.d.ts.map +1 -1
  99. package/dist/utils/user-mapper.js +4 -1
  100. package/package.json +17 -10
package/README.md CHANGED
@@ -1,207 +1,590 @@
1
1
  # @choiceform/shared-auth
2
2
 
3
- 共享认证包 - 基于 Better Auth 的统一认证解决方案
3
+ A shared authentication library based on Better Auth + Legend State.
4
4
 
5
- ## 功能特性
5
+ ## Architecture
6
6
 
7
- - Better Auth 集成(OAuth、Magic Link)
8
- - Legend State 状态管理
9
- - 自动伴生团队设置
10
- - Token 自动管理
11
- - 完整 TypeScript 类型支持
12
- - 预配置 API 客户端
7
+ ```
8
+ ┌─────────────────────────────────────────────────────────────┐
9
+ │ createAuth() / initAuth() │
10
+ │ (core.ts) │
11
+ ├─────────────────────────────────────────────────────────────┤
12
+ │ │
13
+ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌─────────────┐ │
14
+ │ │ Store │ │ Service │ │ API │ │ Hooks │ │
15
+ │ │ Layer │ │ Layer │ │ Layer │ │ Layer │ │
16
+ │ │ │ │ │ │ │ │ │ │
17
+ │ │authStore │ │authServ. │ │apiClient │ │useAuthSync │ │
18
+ │ │storeAct. │ │callback │ │authApi │ │useProtected │ │
19
+ │ │computed │ │companion │ │orgApi │ │useEmailVer. │ │
20
+ │ └──────────┘ └──────────┘ └──────────┘ └─────────────┘ │
21
+ │ │
22
+ └─────────────────────────────────────────────────────────────┘
23
+ ```
24
+
25
+ ### Four-Layer Architecture
26
+
27
+ | Layer | Responsibility | Files |
28
+ |-------|----------------|-------|
29
+ | **Store Layer** | Reactive state management | `store/state.ts`, `store/actions.ts`, `store/computed.ts`, `store/utils.ts` |
30
+ | **Service Layer** | Business logic | `services/auth-service.ts`, `services/callback-service.ts`, `services/companion-team.ts` |
31
+ | **API Layer** | HTTP requests | `api/client.ts`, `api/auth-api.ts`, `api/organization-api.ts`, `api/team-api.ts` |
32
+ | **Hooks Layer** | React-specific | `hooks/use-auth-sync.ts`, `hooks/use-protected-route.ts`, `hooks/use-email-verification.ts` |
13
33
 
14
- ## 安装
34
+ ## Installation
15
35
 
16
36
  ```bash
17
37
  pnpm add @choiceform/shared-auth
18
38
  ```
19
39
 
20
- ## 环境变量
40
+ ### Peer Dependencies
21
41
 
22
- ```bash
23
- VITE_ONEAUTH_BASE_URL=https://oneauth.choiceform.io
42
+ ```json
43
+ {
44
+ "@legendapp/state": "v3.0.0-beta.30",
45
+ "better-auth": "^1.4.4",
46
+ "react": ">=18.0.0",
47
+ "react-dom": ">=18.0.0"
48
+ }
24
49
  ```
25
50
 
26
- ## 快速开始
51
+ ## Quick Start
52
+
53
+ ### Option 1: initAuth (Recommended)
27
54
 
28
- ### 初始化
55
+ Quick initialization with default configuration, automatically includes `magicLinkClient` and `organizationClient` plugins:
29
56
 
30
57
  ```typescript
31
58
  import { initAuth } from "@choiceform/shared-auth"
32
59
 
33
- export const auth = initAuth({
34
- baseURL: import.meta.env.VITE_ONEAUTH_BASE_URL,
60
+ const auth = initAuth({
61
+ baseURL: "https://api.example.com",
62
+ // Optional configuration
63
+ tokenStorageKey: "auth-token", // localStorage key, defaults to "auth-token"
64
+ skipTokenCleanupOnError: false, // Set to true for development
65
+ })
66
+
67
+ export { auth }
68
+ ```
69
+
70
+ ### Option 2: createAuth (Custom Configuration)
71
+
72
+ Use when you need custom Better Auth plugins:
73
+
74
+ ```typescript
75
+ import { createAuth } from "@choiceform/shared-auth"
76
+ import { magicLinkClient, organizationClient } from "better-auth/client/plugins"
77
+
78
+ const auth = createAuth({
79
+ baseURL: "https://api.example.com",
80
+ plugins: [
81
+ magicLinkClient(),
82
+ organizationClient({ teams: { enabled: true } }),
83
+ // Other plugins...
84
+ ],
35
85
  tokenStorageKey: "auth-token",
36
86
  })
87
+
88
+ export { auth }
37
89
  ```
38
90
 
39
- ### 在应用中使用
91
+ ## AuthInstance API
92
+
93
+ The instance returned by `createAuth()` / `initAuth()` includes:
40
94
 
41
95
  ```typescript
42
- import { use$ } from "@legendapp/state/react"
43
- import { auth } from "./lib/auth"
96
+ const auth = initAuth({ baseURL: "..." })
97
+
98
+ // API Layer
99
+ auth.apiClient // HTTP client
100
+ auth.authApi // Auth API
101
+ auth.organizationApi // Organization API
102
+ auth.teamApi // Team API
103
+
104
+ // Store Layer
105
+ auth.authStore // Legend State Observable
106
+ auth.authComputed // Computed properties
107
+ auth.tokenStorage // Token storage
108
+ auth.storeActions // State actions
109
+
110
+ // Service Layer
111
+ auth.authService // Auth business logic
112
+
113
+ // Active State Management
114
+ auth.setActiveOrganization(request)
115
+ auth.setActiveTeam(request)
116
+ auth.setActiveOrganizationAndTeam(orgId, teamId)
117
+
118
+ // Shortcut Methods
119
+ auth.getCurrentUser() // Get current user
120
+ auth.getCurrentUserId() // Get current user ID
121
+ auth.isAuthenticated() // Check if authenticated
122
+ auth.isLoading() // Check if loading
123
+ auth.isLoaded() // Check if loaded
124
+ auth.getAuthToken() // Get token
125
+ auth.getAuthHeaders() // Get auth headers
126
+ auth.waitForAuth() // Wait for auth to complete
127
+ auth.userManager // User manager
128
+
129
+ // Better Auth Client (Advanced)
130
+ auth.authClient // Raw Better Auth client
131
+ ```
132
+
133
+ ## Hooks (Recommended)
134
+
135
+ ### useAuthSync
136
+
137
+ Sync authentication state, replaces manual Better Auth session sync:
138
+
139
+ ```typescript
140
+ import { useAuthSync } from "@choiceform/shared-auth"
44
141
 
45
142
  function App() {
46
- const { isAuthenticated, user } = use$(auth.authStore)
143
+ useAuthSync(auth, {
144
+ skipCompanionTeamPaths: ['/auth/callback', '/auth/delete-success'],
145
+ onAuthChange: (isAuthenticated) => {
146
+ if (isAuthenticated) {
147
+ syncTheme()
148
+ syncLanguage()
149
+ }
150
+ }
151
+ })
152
+
153
+ return <YourApp />
154
+ }
155
+ ```
156
+
157
+ ### useProtectedRoute
158
+
159
+ Route protection, checks authentication status and email verification:
47
160
 
48
- if (!isAuthenticated) {
49
- return <SignInPage />
161
+ ```typescript
162
+ import { useProtectedRoute } from "@choiceform/shared-auth"
163
+
164
+ function ProtectedRoute({ children }) {
165
+ const navigate = useNavigate()
166
+ const location = useLocation()
167
+
168
+ const { status, shouldRender, redirectPath } = useProtectedRoute(auth, {
169
+ pathname: location.pathname,
170
+ publicRoutePrefixes: ['/resources', '/public'],
171
+ requireEmailVerified: true,
172
+ lang: 'us'
173
+ })
174
+
175
+ useEffect(() => {
176
+ if (redirectPath) {
177
+ navigate(redirectPath, { replace: true })
178
+ }
179
+ }, [redirectPath])
180
+
181
+ if (!shouldRender) {
182
+ return <Loading />
50
183
  }
51
184
 
52
- return <MainApp user={user} />
185
+ return <>{children}</>
53
186
  }
54
187
  ```
55
188
 
56
- ### 登录
189
+ ### useEmailVerification
190
+
191
+ Email verification flow:
57
192
 
58
193
  ```typescript
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()
194
+ import { useEmailVerification } from "@choiceform/shared-auth"
195
+
196
+ function VerifyEmailPage({ email, lang }) {
197
+ const navigate = useNavigate()
198
+
199
+ const {
200
+ isLoading,
201
+ isAlreadyVerified,
202
+ isCountingDown,
203
+ countdown,
204
+ resendVerification,
205
+ changeEmail
206
+ } = useEmailVerification(auth, {
207
+ email,
208
+ lang,
209
+ onRedirect: (path) => navigate(path),
210
+ onSendSuccess: (email) => toast.success(`Verification email sent to ${email}`),
211
+ onSendError: () => toast.error('Failed to send'),
212
+ onAlreadyVerified: () => navigate('/community')
213
+ })
214
+
215
+ return (
216
+ <div>
217
+ {isAlreadyVerified ? (
218
+ <p>Email verified, redirecting...</p>
219
+ ) : (
220
+ <>
221
+ <button onClick={resendVerification} disabled={isLoading || isCountingDown}>
222
+ {isCountingDown ? `Retry in ${countdown}s` : 'Resend'}
223
+ </button>
224
+ <button onClick={changeEmail}>Use different email</button>
225
+ </>
226
+ )}
227
+ </div>
68
228
  )
69
229
  }
230
+ ```
70
231
 
71
- // Magic Link 登录
72
- const handleMagicLink = async (email: string) => {
73
- const callbackURL = new URL("/dashboard", window.location.origin)
74
-
75
- await auth.authActions.signInWithMagicLink(
76
- email,
77
- callbackURL.toString()
78
- )
232
+ ### useAuthInit
233
+
234
+ Initialize authentication state:
235
+
236
+ ```typescript
237
+ import { useAuthInit, initializeAuth } from "@choiceform/shared-auth"
238
+
239
+ // Hook approach
240
+ function App() {
241
+ useAuthInit(auth)
242
+ return <YourApp />
79
243
  }
244
+
245
+ // Or manual call
246
+ await initializeAuth(auth)
80
247
  ```
81
248
 
82
- ### 认证状态同步
249
+ ## Service Layer
250
+
251
+ ### authService
83
252
 
84
- 新用户登录后,使用 `setupCompanionTeam` 设置伴生组织和团队:
253
+ Auth business logic wrapper:
85
254
 
86
255
  ```typescript
87
- import { setupCompanionTeam } from "@choiceform/shared-auth"
256
+ // OAuth sign in
257
+ await auth.authService.signInWithOAuth("github", callbackURL, newUserCallbackURL, errorCallbackURL)
88
258
 
89
- // 在认证成功后调用
90
- setupCompanionTeam(auth, token, {
91
- isNewUser: searchParams.get("isNew") === "true",
92
- onComplete: () => {
93
- // 刷新 session
94
- },
95
- })
259
+ // Magic Link sign in
260
+ await auth.authService.signInWithMagicLink(email, callbackURL, name, newUserCallbackURL)
261
+
262
+ // Email/password sign in
263
+ const result = await auth.authService.signInWithEmail(email, password)
264
+
265
+ // Email/password sign up
266
+ const result = await auth.authService.signUpWithEmail(email, password, name, callbackURL)
267
+
268
+ // Sign out
269
+ await auth.authService.signOut("/sign-in")
270
+
271
+ // Delete account
272
+ await auth.authService.deleteUser(callbackURL, password)
273
+
274
+ // Fetch session with token
275
+ await auth.authService.fetchAndSetSession(token)
96
276
  ```
97
277
 
98
- ## API
278
+ ### callbackService
99
279
 
100
- ### `initAuth(config)`
280
+ Handle various auth callbacks (OAuth, email verification, user deletion, etc.):
101
281
 
102
- 快速初始化(使用默认配置)。
282
+ ```typescript
283
+ import { createCallbackService } from "@choiceform/shared-auth"
284
+
285
+ const callbackService = createCallbackService(auth, {
286
+ lang: 'us',
287
+ defaultRedirect: '/',
288
+ signInPath: '/sign-in',
289
+ linkExpiredPath: '/auth/link-expired',
290
+ deleteSuccessPath: '/auth/delete-success',
291
+ })
103
292
 
104
- | 参数 | 类型 | 说明 |
105
- |------|------|------|
106
- | baseURL | string | OneAuth API 地址 |
107
- | tokenStorageKey | string | localStorage key(默认 `auth-token`) |
108
- | plugins | BetterAuthPlugin[] | Better Auth 插件 |
293
+ // Handle OAuth callback
294
+ const result = await callbackService.handleOAuthCallback(token, isNewUser)
109
295
 
110
- ### `createAuth(config)`
296
+ // Handle email verification callback
297
+ const result = await callbackService.handleEmailVerificationCallback(token)
111
298
 
112
- 创建认证实例(完整配置)。
299
+ // Handle delete user callback
300
+ const result = await callbackService.handleDeleteUserCallback(token, userEmail)
113
301
 
114
- ### AuthInstance
302
+ // Unified handler
303
+ const result = await callbackService.handleCallback(type, token, { isNewUser, userEmail, invitationId })
304
+ ```
115
305
 
116
- | 属性 | 说明 |
117
- |------|------|
118
- | authStore | Legend State store |
119
- | authActions | 认证操作(signIn, signOut 等) |
120
- | authApi | 认证 API |
121
- | organizationApi | 组织 API |
122
- | teamApi | 团队 API |
123
- | tokenStorage | Token 存储工具 |
306
+ ### companionTeam
124
307
 
125
- ### 工具方法
308
+ Companion team setup:
126
309
 
127
310
  ```typescript
128
- // 获取用户
129
- const user = auth.getCurrentUser()
130
- const userId = auth.getCurrentUserId()
311
+ import { setupCompanionTeam } from "@choiceform/shared-auth"
312
+
313
+ await setupCompanionTeam(auth, options)
314
+ ```
315
+
316
+ ## Store Layer
131
317
 
132
- // 认证状态
133
- const authenticated = auth.isAuthenticated()
134
- const loading = auth.isLoading()
135
- const loaded = auth.isLoaded()
318
+ ### authStore (Legend State Observable)
136
319
 
137
- // 等待认证完成
138
- await auth.waitForAuth()
320
+ Reactive state, can be used in React components:
139
321
 
140
- // Token
141
- const token = auth.getAuthTokenSync()
142
- const headers = auth.getAuthHeadersSync()
322
+ ```typescript
323
+ import { use$ } from "@legendapp/state/react"
324
+
325
+ function MyComponent() {
326
+ const user = use$(auth.authStore.user)
327
+ const isAuthenticated = use$(auth.authStore.isAuthenticated)
328
+ const loading = use$(auth.authStore.loading)
329
+ const error = use$(auth.authStore.error)
330
+ const isLoaded = use$(auth.authStore.isLoaded)
331
+
332
+ // Computed state
333
+ const isReady = use$(auth.authComputed.isReady)
334
+ const activeOrganizationId = use$(auth.authComputed.activeOrganizationId)
335
+ }
143
336
  ```
144
337
 
145
- ## 类型
338
+ ### storeActions
339
+
340
+ State management actions:
146
341
 
147
342
  ```typescript
148
- import type {
149
- SessionUser,
150
- AuthState,
151
- AuthConfig,
152
- Organization,
153
- Team,
154
- Member,
343
+ // Read
344
+ auth.storeActions.getUser()
345
+ auth.storeActions.getUserId()
346
+ auth.storeActions.isAuthenticated()
347
+ auth.storeActions.isLoading()
348
+ auth.storeActions.isLoaded()
349
+
350
+ // Update
351
+ auth.storeActions.setUser(user)
352
+ auth.storeActions.updateUser({ name: "New Name" })
353
+ auth.storeActions.setLoading(true)
354
+ auth.storeActions.setError("Error message")
355
+ auth.storeActions.clearAuth()
356
+ auth.storeActions.handleUnauthorized()
357
+
358
+ // Active state
359
+ auth.storeActions.setActiveOrganizationId(orgId)
360
+ auth.storeActions.setActiveTeamId(teamId)
361
+ ```
362
+
363
+ ### Store Utilities
364
+
365
+ Standalone utility functions for non-component scenarios:
366
+
367
+ ```typescript
368
+ import {
369
+ getCurrentUser,
370
+ getCurrentUserId,
371
+ isAuthenticated,
372
+ isLoading,
373
+ isLoaded,
374
+ waitForAuth,
375
+ getAuthToken,
376
+ getAuthTokenSync,
377
+ getAuthHeaders,
378
+ getAuthHeadersSync,
379
+ handle401Response,
380
+ createUserManager,
155
381
  } from "@choiceform/shared-auth"
382
+
383
+ // Wait for auth to complete
384
+ await waitForAuth(auth.authStore)
385
+
386
+ // Get auth headers (sync)
387
+ const headers = getAuthHeadersSync(auth.tokenStorage)
388
+
389
+ // Handle 401 response
390
+ handle401Response(response, auth.storeActions)
156
391
  ```
157
392
 
158
- ### SessionUser
393
+ ## Utilities
159
394
 
160
395
  ```typescript
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
396
+ import {
397
+ // Environment
398
+ getEnvVar,
399
+ getAuthBaseUrl,
400
+
401
+ // Validation
402
+ isValidEmail,
403
+
404
+ // Error parsing
405
+ parseAuthError,
406
+ isTokenExpiredError,
407
+ AUTH_ERROR_CODES,
408
+
409
+ // URL utilities
410
+ getNameFromEmail,
411
+ buildAuthUrl,
412
+ buildAuthPath,
413
+ clearAuthParams,
414
+
415
+ // User mapping
416
+ extractSessionUser,
417
+ } from "@choiceform/shared-auth"
418
+
419
+ // Validate email
420
+ if (isValidEmail(email)) {
171
421
  // ...
172
422
  }
423
+
424
+ // Parse error
425
+ const { code, message, isKnownError } = parseAuthError(error)
426
+
427
+ // Check if token expired
428
+ if (isTokenExpiredError(error)) {
429
+ // Re-authenticate
430
+ }
431
+
432
+ // Build URL
433
+ const url = buildAuthPath('/verify-email', { lang: 'us', email })
173
434
  ```
174
435
 
175
- ## 响应式状态
436
+ ## API Layer
437
+
438
+ Low-level API access:
176
439
 
177
440
  ```typescript
178
- import { use$ } from "@legendapp/state/react"
179
- import { auth } from "./lib/auth"
441
+ import {
442
+ createApiClient,
443
+ createAuthApi,
444
+ createOrganizationApi,
445
+ createTeamApi,
446
+ parseErrorResponse,
447
+ } from "@choiceform/shared-auth"
180
448
 
181
- function Profile() {
182
- const user = use$(auth.authStore.user)
183
- const loading = use$(auth.authStore.loading)
449
+ // Use APIs directly
450
+ const response = await auth.authApi.getSession()
451
+ const orgs = await auth.organizationApi.listOrganizations()
452
+ const teams = await auth.teamApi.listTeams()
453
+ ```
184
454
 
185
- if (loading) return <Loading />
186
- if (!user) return <SignIn />
455
+ ## Directory Structure
187
456
 
188
- return <div>Hello, {user.name}</div>
189
- }
457
+ ```
458
+ src/
459
+ ├── api/ # API Layer
460
+ │ ├── client.ts # HTTP client
461
+ │ ├── auth-api.ts # Auth API
462
+ │ ├── organization-api.ts # Organization API
463
+ │ ├── team-api.ts # Team API
464
+ │ └── index.ts
465
+ ├── services/ # Service Layer
466
+ │ ├── auth-service.ts # Auth business logic
467
+ │ ├── callback-service.ts # Callback handling
468
+ │ ├── companion-team.ts # Companion team setup
469
+ │ └── index.ts
470
+ ├── store/ # Store Layer
471
+ │ ├── state.ts # State definition
472
+ │ ├── actions.ts # State actions
473
+ │ ├── computed.ts # Computed properties
474
+ │ ├── utils.ts # Utility functions
475
+ │ └── index.ts
476
+ ├── hooks/ # React Hooks
477
+ │ ├── use-auth-init.ts # Auth initialization
478
+ │ ├── use-auth-sync.ts # State sync
479
+ │ ├── use-protected-route.ts
480
+ │ ├── use-email-verification.ts
481
+ │ └── index.ts
482
+ ├── utils/ # Utilities
483
+ │ ├── auth-utils.ts # Auth utilities
484
+ │ ├── user-mapper.ts # User mapping
485
+ │ ├── date.ts # Date utilities
486
+ │ ├── env.ts # Environment variables
487
+ │ └── index.ts
488
+ ├── types/ # Type definitions
489
+ │ ├── auth.ts
490
+ │ ├── callback.ts
491
+ │ ├── organization.ts
492
+ │ ├── team.ts
493
+ │ ├── user.ts
494
+ │ └── index.ts
495
+ ├── lib/ # Better Auth client
496
+ │ └── auth-client.ts
497
+ ├── core.ts # Core entry (createAuth)
498
+ ├── init.ts # Quick init (initAuth)
499
+ ├── config.ts # Default config
500
+ └── index.ts # Export entry
501
+ ```
502
+
503
+ ## Type Exports
504
+
505
+ ```typescript
506
+ import type {
507
+ // Core
508
+ AuthInstance,
509
+ AuthState,
510
+ AuthConfig,
511
+ SessionUser,
512
+ SessionUserMetadata,
513
+ Session,
514
+
515
+ // Services
516
+ AuthService,
517
+ AuthServiceConfig,
518
+ CallbackService,
519
+ CallbackType,
520
+ CallbackResult,
521
+ CallbackConfig,
522
+
523
+ // Hooks
524
+ UseAuthSyncConfig,
525
+ UseAuthSyncResult,
526
+ UseProtectedRouteConfig,
527
+ UseProtectedRouteResult,
528
+ ProtectionStatus,
529
+ UseEmailVerificationConfig,
530
+ UseEmailVerificationResult,
531
+
532
+ // Organization
533
+ Organization,
534
+ OrganizationMetadata,
535
+ FullOrganization,
536
+ CreateOrganizationRequest,
537
+ UpdateOrganizationRequest,
538
+ Member,
539
+ MemberWithUser,
540
+ MemberRole,
541
+ Invitation,
542
+ InvitationDetail,
543
+ InvitationStatus,
544
+
545
+ // Team
546
+ Team,
547
+ TeamMetadata,
548
+ TeamMember,
549
+ CreateTeamRequest,
550
+ UpdateTeamRequest,
551
+
552
+ // API
553
+ ApiClient,
554
+ ApiClientConfig,
555
+ ApiResponse,
556
+ TokenStorage,
557
+ AuthApi,
558
+ OrganizationApi,
559
+ TeamApi,
560
+
561
+ // Store
562
+ StoreActions,
563
+
564
+ // Utilities
565
+ AuthErrorCode,
566
+ ParsedAuthError,
567
+ } from "@choiceform/shared-auth"
190
568
  ```
191
569
 
192
- ## 更新日志
570
+ ## Development
193
571
 
194
- ### v0.2.0
572
+ ```bash
573
+ # Install dependencies
574
+ pnpm install
575
+
576
+ # Development mode
577
+ pnpm dev
195
578
 
196
- - 服务器地址更换为 `https://oneauth.choiceform.io`
197
- - 伴生组织/团队改从 session 获取(`inherentOrganizationId`、`inherentTeamId`)
198
- - 新增 `onboard` API、Magic Link 支持
199
- - 移除 UI 组件(`AuthSync`、`ProtectedRoute`、`SignInPage`),由业务端实现
200
- - 代码清理和优化
579
+ # Build
580
+ pnpm build
201
581
 
202
- ### v0.1.x
582
+ # Test
583
+ pnpm test
203
584
 
204
- - 初始版本
585
+ # Watch tests
586
+ pnpm test:watch
587
+ ```
205
588
 
206
589
  ## License
207
590