@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.
- package/README.md +106 -450
- package/dist/api/auth-api.d.ts +28 -0
- package/dist/api/auth-api.d.ts.map +1 -0
- package/dist/api/auth-api.js +133 -0
- package/dist/api/client.d.ts +34 -0
- package/dist/api/client.d.ts.map +1 -0
- package/dist/api/client.js +104 -0
- package/dist/api/index.d.ts +12 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/index.js +7 -0
- package/dist/api/organization-api.d.ts +96 -0
- package/dist/api/organization-api.d.ts.map +1 -0
- package/dist/api/organization-api.js +228 -0
- package/dist/api/team-api.d.ts +57 -0
- package/dist/api/team-api.d.ts.map +1 -0
- package/dist/api/team-api.js +118 -0
- package/dist/config.d.ts +4 -57
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +4 -6
- package/dist/core.d.ts +114 -72
- package/dist/core.d.ts.map +1 -1
- package/dist/core.js +35 -17
- package/dist/hooks/use-auth-init.d.ts +10 -0
- package/dist/hooks/use-auth-init.d.ts.map +1 -1
- package/dist/hooks/use-auth-init.js +59 -31
- package/dist/index.d.ts +12 -15
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +26 -13
- package/dist/init.d.ts +133 -92
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +12 -14
- package/dist/lib/auth-client.d.ts +49 -54
- package/dist/lib/auth-client.d.ts.map +1 -1
- package/dist/lib/auth-client.js +10 -16
- package/dist/services/companion-team.d.ts +16 -0
- package/dist/services/companion-team.d.ts.map +1 -0
- package/dist/services/companion-team.js +73 -0
- package/dist/services/index.d.ts +5 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +4 -0
- package/dist/store/actions.d.ts +45 -33
- package/dist/store/actions.d.ts.map +1 -1
- package/dist/store/actions.js +135 -106
- package/dist/store/index.d.ts +8 -0
- package/dist/store/index.d.ts.map +1 -0
- package/dist/store/index.js +7 -0
- package/dist/store/state.d.ts +10 -7
- package/dist/store/state.d.ts.map +1 -1
- package/dist/store/state.js +31 -23
- package/dist/store/utils.d.ts +22 -71
- package/dist/store/utils.d.ts.map +1 -1
- package/dist/store/utils.js +28 -146
- package/dist/types/auth.d.ts +107 -0
- package/dist/types/auth.d.ts.map +1 -0
- package/dist/types/auth.js +4 -0
- package/dist/types/index.d.ts +8 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +4 -0
- package/dist/types/organization.d.ts +111 -0
- package/dist/types/organization.d.ts.map +1 -0
- package/dist/types/organization.js +4 -0
- package/dist/types/team.d.ts +52 -0
- package/dist/types/team.d.ts.map +1 -0
- package/dist/types/team.js +4 -0
- package/dist/types/user.d.ts +44 -0
- package/dist/types/user.d.ts.map +1 -0
- package/dist/types/user.js +4 -0
- package/dist/utils/date.d.ts +10 -0
- package/dist/utils/date.d.ts.map +1 -0
- package/dist/utils/date.js +13 -0
- package/dist/utils/env.d.ts +20 -0
- package/dist/utils/env.d.ts.map +1 -0
- package/dist/utils/env.js +23 -0
- package/dist/utils/index.d.ts +7 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +6 -0
- package/dist/utils/user-mapper.d.ts +21 -0
- package/dist/utils/user-mapper.d.ts.map +1 -0
- package/dist/utils/user-mapper.js +55 -0
- package/package.json +3 -4
- package/dist/components/auth-sync.d.ts +0 -25
- package/dist/components/auth-sync.d.ts.map +0 -1
- package/dist/components/auth-sync.js +0 -346
- package/dist/components/protected-route.d.ts +0 -18
- package/dist/components/protected-route.d.ts.map +0 -1
- package/dist/components/protected-route.js +0 -34
- package/dist/components/sign-in-page.d.ts +0 -21
- package/dist/components/sign-in-page.d.ts.map +0 -1
- package/dist/components/sign-in-page.js +0 -31
- package/dist/core/init-auth-sync.d.ts +0 -7
- package/dist/core/init-auth-sync.d.ts.map +0 -1
- package/dist/core/init-auth-sync.js +0 -34
- package/dist/types.d.ts +0 -87
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -4
package/dist/store/actions.js
CHANGED
|
@@ -1,67 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* 认证 Actions
|
|
3
3
|
*/
|
|
4
|
-
|
|
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,
|
|
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
|
|
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,21 +66,15 @@ 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
|
|
141
|
-
console.error("[fetchSessionWithToken] Failed to fetch session:", error);
|
|
72
|
+
catch {
|
|
142
73
|
this.handleUnauthorized();
|
|
143
74
|
}
|
|
144
75
|
},
|
|
145
76
|
/**
|
|
146
|
-
*
|
|
147
|
-
* 清理所有认证状态和本地存储
|
|
148
|
-
*
|
|
149
|
-
* 注意:如果启用了 skipTokenCleanupOnError,token 不会被清除
|
|
150
|
-
* 这对于开发环境很有用,避免因网络波动等问题频繁登出
|
|
77
|
+
* 处理未授权
|
|
151
78
|
*/
|
|
152
79
|
handleUnauthorized() {
|
|
153
80
|
authStore.user.set(null);
|
|
@@ -173,37 +100,28 @@ export function createAuthActions(authStore, tokenStorage, config, authClient) {
|
|
|
173
100
|
authStore.error.set(error);
|
|
174
101
|
},
|
|
175
102
|
/**
|
|
176
|
-
*
|
|
103
|
+
* OAuth 登录
|
|
104
|
+
*
|
|
105
|
+
* 直接调用 better-auth 的 signIn.social,传入完整的回调 URL
|
|
177
106
|
*
|
|
178
|
-
* @param provider OAuth
|
|
179
|
-
* @param
|
|
180
|
-
*
|
|
107
|
+
* @param provider - OAuth 提供商(如 github)
|
|
108
|
+
* @param callbackURL - 登录成功后的完整回调 URL
|
|
109
|
+
* @param newUserCallbackURL - 新用户的回调 URL(可选)
|
|
110
|
+
* @param errorCallbackURL - 登录失败后的完整回调 URL(可选)
|
|
181
111
|
*/
|
|
182
|
-
async signIn(provider
|
|
183
|
-
// 防止重复点击
|
|
112
|
+
async signIn(provider, callbackURL, newUserCallbackURL, errorCallbackURL) {
|
|
184
113
|
if (authStore.loading.get()) {
|
|
185
114
|
return;
|
|
186
115
|
}
|
|
187
116
|
try {
|
|
188
117
|
authStore.loading.set(true);
|
|
189
118
|
authStore.error.set(null);
|
|
190
|
-
if (!baseURL) {
|
|
191
|
-
throw new Error("Auth baseURL is not configured");
|
|
192
|
-
}
|
|
193
|
-
// 构建重定向地址:相对路径自动添加 origin
|
|
194
|
-
const finalRedirectTo = redirectTo
|
|
195
|
-
? redirectTo.startsWith("http")
|
|
196
|
-
? redirectTo
|
|
197
|
-
: `${window.location.origin}${redirectTo}`
|
|
198
|
-
: defaultRedirectAfterLogin
|
|
199
|
-
? `${window.location.origin}${defaultRedirectAfterLogin}`
|
|
200
|
-
: `${window.location.origin}/community`;
|
|
201
|
-
const callbackURL = buildCallbackURL(finalRedirectTo, baseURL);
|
|
202
119
|
await authClient.signIn.social({
|
|
203
120
|
provider,
|
|
204
121
|
callbackURL,
|
|
122
|
+
newUserCallbackURL,
|
|
123
|
+
errorCallbackURL,
|
|
205
124
|
});
|
|
206
|
-
// 注意:OAuth 重定向后,loading 状态会在页面刷新时重置
|
|
207
125
|
}
|
|
208
126
|
catch (error) {
|
|
209
127
|
const message = error instanceof Error ? error.message : "Sign in failed";
|
|
@@ -212,12 +130,126 @@ export function createAuthActions(authStore, tokenStorage, config, authClient) {
|
|
|
212
130
|
}
|
|
213
131
|
},
|
|
214
132
|
/**
|
|
215
|
-
*
|
|
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 登录
|
|
172
|
+
*
|
|
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 注册
|
|
216
211
|
*
|
|
217
|
-
* @param
|
|
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
|
+
* 登出
|
|
218
251
|
*/
|
|
219
252
|
async signOut(redirectTo) {
|
|
220
|
-
// 防止重复调用
|
|
221
253
|
if (authStore.loading.get()) {
|
|
222
254
|
return;
|
|
223
255
|
}
|
|
@@ -225,11 +257,9 @@ export function createAuthActions(authStore, tokenStorage, config, authClient) {
|
|
|
225
257
|
authStore.loading.set(true);
|
|
226
258
|
authStore.error.set(null);
|
|
227
259
|
await authClient.signOut();
|
|
228
|
-
// 清理本地状态
|
|
229
260
|
authStore.user.set(null);
|
|
230
261
|
authStore.isAuthenticated.set(false);
|
|
231
262
|
tokenStorage.clear();
|
|
232
|
-
// 如果提供了重定向地址,则执行跳转
|
|
233
263
|
if (redirectTo) {
|
|
234
264
|
window.location.href = redirectTo;
|
|
235
265
|
}
|
|
@@ -237,7 +267,6 @@ export function createAuthActions(authStore, tokenStorage, config, authClient) {
|
|
|
237
267
|
catch (error) {
|
|
238
268
|
const message = error instanceof Error ? error.message : "Sign out failed";
|
|
239
269
|
authStore.error.set(message);
|
|
240
|
-
// 即使出错,也尝试清理本地状态
|
|
241
270
|
authStore.user.set(null);
|
|
242
271
|
authStore.isAuthenticated.set(false);
|
|
243
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";
|
package/dist/store/state.d.ts
CHANGED
|
@@ -1,16 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 认证状态 Store
|
|
3
|
+
*/
|
|
1
4
|
import type { AuthState } from "../types";
|
|
5
|
+
import type { TokenStorage } from "../api";
|
|
6
|
+
/**
|
|
7
|
+
* 创建 Token 存储工具
|
|
8
|
+
*/
|
|
9
|
+
export declare function createTokenStorage(tokenStorageKey: string): TokenStorage;
|
|
2
10
|
/**
|
|
3
|
-
* 创建认证状态
|
|
11
|
+
* 创建认证状态 Store
|
|
4
12
|
*/
|
|
5
13
|
export declare function createAuthStore(config: {
|
|
6
14
|
tokenStorageKey: string;
|
|
7
15
|
}): {
|
|
8
16
|
authStore: import("@legendapp/state").Observable<AuthState>;
|
|
9
|
-
tokenStorage:
|
|
10
|
-
save(token: string | null): void;
|
|
11
|
-
get(): string | null;
|
|
12
|
-
clear(): void;
|
|
13
|
-
};
|
|
17
|
+
tokenStorage: TokenStorage;
|
|
14
18
|
};
|
|
15
|
-
export type TokenStorage = ReturnType<typeof createAuthStore>["tokenStorage"];
|
|
16
19
|
//# sourceMappingURL=state.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../src/store/state.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../src/store/state.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AACzC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAA;AAE1C;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,eAAe,EAAE,MAAM,GAAG,YAAY,CA4BxE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE;IAAE,eAAe,EAAE,MAAM,CAAA;CAAE;;;EA2BlE"}
|
package/dist/store/state.js
CHANGED
|
@@ -1,53 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 认证状态 Store
|
|
3
|
+
*/
|
|
1
4
|
import { observable } from "@legendapp/state";
|
|
2
5
|
/**
|
|
3
|
-
*
|
|
6
|
+
* 创建 Token 存储工具
|
|
4
7
|
*/
|
|
5
|
-
export function
|
|
6
|
-
const { tokenStorageKey } = config;
|
|
7
|
-
// 从 localStorage 读取初始 token
|
|
8
|
+
export function createTokenStorage(tokenStorageKey) {
|
|
8
9
|
const getStoredToken = () => {
|
|
9
10
|
try {
|
|
10
|
-
|
|
11
|
-
if (!stored)
|
|
12
|
-
return null;
|
|
13
|
-
return stored;
|
|
11
|
+
return localStorage.getItem(tokenStorageKey);
|
|
14
12
|
}
|
|
15
13
|
catch {
|
|
16
14
|
return null;
|
|
17
15
|
}
|
|
18
16
|
};
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
isAuthenticated: false,
|
|
22
|
-
isLoaded: false,
|
|
23
|
-
loading: true,
|
|
24
|
-
error: null,
|
|
25
|
-
token: getStoredToken(),
|
|
26
|
-
});
|
|
27
|
-
// 手动管理 token 的 localStorage 存储
|
|
28
|
-
const tokenStorage = {
|
|
17
|
+
return {
|
|
18
|
+
get: getStoredToken,
|
|
29
19
|
save(token) {
|
|
30
20
|
try {
|
|
31
21
|
if (token) {
|
|
32
22
|
localStorage.setItem(tokenStorageKey, token);
|
|
33
|
-
authStore.token.set(token);
|
|
34
23
|
}
|
|
35
24
|
else {
|
|
36
25
|
localStorage.removeItem(tokenStorageKey);
|
|
37
|
-
authStore.token.set(null);
|
|
38
26
|
}
|
|
39
27
|
}
|
|
40
28
|
catch (error) {
|
|
41
29
|
console.error("Failed to save token to localStorage:", error);
|
|
42
30
|
}
|
|
43
31
|
},
|
|
44
|
-
get() {
|
|
45
|
-
return getStoredToken();
|
|
46
|
-
},
|
|
47
32
|
clear() {
|
|
48
33
|
this.save(null);
|
|
49
34
|
},
|
|
50
35
|
};
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* 创建认证状态 Store
|
|
39
|
+
*/
|
|
40
|
+
export function createAuthStore(config) {
|
|
41
|
+
const { tokenStorageKey } = config;
|
|
42
|
+
// 创建 token 存储工具
|
|
43
|
+
const tokenStorage = createTokenStorage(tokenStorageKey);
|
|
44
|
+
// 创建 observable store
|
|
45
|
+
const authStore = observable({
|
|
46
|
+
user: null,
|
|
47
|
+
isAuthenticated: false,
|
|
48
|
+
isLoaded: false,
|
|
49
|
+
loading: true,
|
|
50
|
+
error: null,
|
|
51
|
+
token: tokenStorage.get(),
|
|
52
|
+
});
|
|
53
|
+
// 同步 token 到 store
|
|
54
|
+
const originalSave = tokenStorage.save.bind(tokenStorage);
|
|
55
|
+
tokenStorage.save = (token) => {
|
|
56
|
+
originalSave(token);
|
|
57
|
+
authStore.token.set(token);
|
|
58
|
+
};
|
|
51
59
|
return {
|
|
52
60
|
authStore,
|
|
53
61
|
tokenStorage,
|
package/dist/store/utils.d.ts
CHANGED
|
@@ -1,103 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Store 工具函数
|
|
3
|
+
*/
|
|
1
4
|
import type { Observable } from "@legendapp/state";
|
|
2
5
|
import type { AuthState, SessionUser } from "../types";
|
|
3
|
-
import type { TokenStorage } from "
|
|
6
|
+
import type { ApiClient, TokenStorage } from "../api";
|
|
4
7
|
import type { AuthActions } from "./actions";
|
|
5
|
-
/**
|
|
6
|
-
* 获取当前用户
|
|
7
|
-
*/
|
|
8
8
|
export declare function getCurrentUser(authStore: Observable<AuthState>): SessionUser | null;
|
|
9
|
-
/**
|
|
10
|
-
* 获取当前用户ID
|
|
11
|
-
*/
|
|
12
9
|
export declare function getCurrentUserId(authStore: Observable<AuthState>): string | null;
|
|
13
|
-
/**
|
|
14
|
-
* 安全获取当前用户ID
|
|
15
|
-
*/
|
|
16
|
-
export declare function getCurrentUserIdSafe(authStore: Observable<AuthState>): string | null;
|
|
17
|
-
/**
|
|
18
|
-
* 检查是否已认证
|
|
19
|
-
*/
|
|
20
10
|
export declare function isAuthenticated(authStore: Observable<AuthState>): boolean;
|
|
21
|
-
/**
|
|
22
|
-
* 检查是否正在加载
|
|
23
|
-
*/
|
|
24
11
|
export declare function isLoading(authStore: Observable<AuthState>): boolean;
|
|
25
|
-
/**
|
|
26
|
-
* 检查是否已加载
|
|
27
|
-
*/
|
|
28
12
|
export declare function isLoaded(authStore: Observable<AuthState>): boolean;
|
|
29
|
-
/**
|
|
30
|
-
* 等待认证完成
|
|
31
|
-
* 使用轮询方式检查认证状态(简单但有效)
|
|
32
|
-
*
|
|
33
|
-
* 注意:如果长时间未加载,Promise 不会自动 reject
|
|
34
|
-
* 建议在外层添加超时处理
|
|
35
|
-
*/
|
|
36
13
|
export declare function waitForAuth(authStore: Observable<AuthState>): Promise<void>;
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
export declare function
|
|
41
|
-
getSession: () => Promise<unknown>;
|
|
42
|
-
}): Promise<string | null>;
|
|
43
|
-
/**
|
|
44
|
-
* 获取认证头
|
|
45
|
-
*/
|
|
46
|
-
export declare function getAuthHeaders(authStore: Observable<AuthState>, tokenStorage: TokenStorage, authActions: AuthActions, authClient: {
|
|
47
|
-
getSession: () => Promise<unknown>;
|
|
48
|
-
}): Promise<Record<string, string>>;
|
|
49
|
-
/**
|
|
50
|
-
* 处理 401 响应
|
|
51
|
-
*/
|
|
14
|
+
export declare function getAuthTokenSync(tokenStorage: TokenStorage): string | null;
|
|
15
|
+
export declare function getAuthToken(tokenStorage: TokenStorage): Promise<string | null>;
|
|
16
|
+
export declare function getAuthHeadersSync(tokenStorage: TokenStorage): Record<string, string>;
|
|
17
|
+
export declare function getAuthHeaders(tokenStorage: TokenStorage): Promise<Record<string, string>>;
|
|
52
18
|
export declare function handle401Response(response: Response, authActions: AuthActions): Response;
|
|
53
|
-
/**
|
|
54
|
-
* API 客户端工具
|
|
55
|
-
*/
|
|
56
|
-
export declare function createApiClient(authStore: Observable<AuthState>, tokenStorage: TokenStorage, authActions: AuthActions, authClient: {
|
|
57
|
-
getSession: () => Promise<unknown>;
|
|
58
|
-
}): {
|
|
59
|
-
get(url: string, options?: RequestInit): Promise<Response>;
|
|
60
|
-
post(url: string, body?: unknown, options?: RequestInit): Promise<Response>;
|
|
61
|
-
put(url: string, body?: unknown, options?: RequestInit): Promise<Response>;
|
|
62
|
-
delete(url: string, options?: RequestInit): Promise<Response>;
|
|
63
|
-
};
|
|
64
|
-
/**
|
|
65
|
-
* 用户管理器
|
|
66
|
-
*/
|
|
67
19
|
export declare function createUserManager(authStore: Observable<AuthState>): {
|
|
68
|
-
getUser()
|
|
69
|
-
getUserId()
|
|
20
|
+
getUser: () => SessionUser | null;
|
|
21
|
+
getUserId: () => string | null;
|
|
70
22
|
};
|
|
71
23
|
/**
|
|
72
|
-
*
|
|
73
|
-
* 这样就不需要在每个项目中重复包装工具函数
|
|
24
|
+
* 创建绑定好的工具函数集合
|
|
74
25
|
*/
|
|
75
26
|
export declare function createBoundAuthUtils(instance: {
|
|
27
|
+
apiClient: ApiClient;
|
|
28
|
+
authActions: AuthActions;
|
|
76
29
|
authStore: Observable<AuthState>;
|
|
77
30
|
tokenStorage: TokenStorage;
|
|
78
|
-
authActions: AuthActions;
|
|
79
|
-
authClient: {
|
|
80
|
-
getSession: () => Promise<unknown>;
|
|
81
|
-
};
|
|
82
31
|
}): {
|
|
83
32
|
getCurrentUser: () => SessionUser | null;
|
|
84
33
|
getCurrentUserId: () => string | null;
|
|
85
|
-
getCurrentUserIdSafe: () => string | null;
|
|
86
34
|
isAuthenticated: () => boolean;
|
|
87
35
|
isLoading: () => boolean;
|
|
88
36
|
isLoaded: () => boolean;
|
|
89
37
|
waitForAuth: () => Promise<void>;
|
|
90
38
|
getAuthToken: () => Promise<string | null>;
|
|
39
|
+
getAuthTokenSync: () => string | null;
|
|
91
40
|
getAuthHeaders: () => Promise<Record<string, string>>;
|
|
41
|
+
getAuthHeadersSync: () => Record<string, string>;
|
|
92
42
|
apiClient: {
|
|
93
|
-
get(
|
|
94
|
-
post(
|
|
95
|
-
put(
|
|
96
|
-
delete(
|
|
43
|
+
get<T = unknown>(path: string, options?: RequestInit): Promise<import("..").ApiResponse<T>>;
|
|
44
|
+
post<T = unknown>(path: string, body?: unknown, options?: RequestInit): Promise<import("..").ApiResponse<T>>;
|
|
45
|
+
put<T = unknown>(path: string, body?: unknown, options?: RequestInit): Promise<import("..").ApiResponse<T>>;
|
|
46
|
+
delete<T = unknown>(path: string, options?: RequestInit): Promise<import("..").ApiResponse<T>>;
|
|
47
|
+
fetch(path: string, options?: RequestInit): Promise<Response>;
|
|
97
48
|
};
|
|
98
49
|
userManager: {
|
|
99
|
-
getUser()
|
|
100
|
-
getUserId()
|
|
50
|
+
getUser: () => SessionUser | null;
|
|
51
|
+
getUserId: () => string | null;
|
|
101
52
|
};
|
|
102
53
|
};
|
|
103
54
|
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/store/utils.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,YAAY,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/store/utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAClD,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AACtD,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAA;AACrD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAE5C,wBAAgB,cAAc,CAAC,SAAS,EAAE,UAAU,CAAC,SAAS,CAAC,GAAG,WAAW,GAAG,IAAI,CAEnF;AAED,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,UAAU,CAAC,SAAS,CAAC,GAAG,MAAM,GAAG,IAAI,CAEhF;AAED,wBAAgB,eAAe,CAAC,SAAS,EAAE,UAAU,CAAC,SAAS,CAAC,GAAG,OAAO,CAEzE;AAED,wBAAgB,SAAS,CAAC,SAAS,EAAE,UAAU,CAAC,SAAS,CAAC,GAAG,OAAO,CAEnE;AAED,wBAAgB,QAAQ,CAAC,SAAS,EAAE,UAAU,CAAC,SAAS,CAAC,GAAG,OAAO,CAElE;AAED,wBAAsB,WAAW,CAAC,SAAS,EAAE,UAAU,CAAC,SAAS,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAajF;AAED,wBAAgB,gBAAgB,CAAC,YAAY,EAAE,YAAY,GAAG,MAAM,GAAG,IAAI,CAE1E;AAED,wBAAsB,YAAY,CAAC,YAAY,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAErF;AAED,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAIrF;AAED,wBAAsB,cAAc,CAAC,YAAY,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAEhG;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,GAAG,QAAQ,CAKxF;AAED,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,UAAU,CAAC,SAAS,CAAC;;;EAKjE;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE;IAC7C,SAAS,EAAE,SAAS,CAAA;IACpB,WAAW,EAAE,WAAW,CAAA;IACxB,SAAS,EAAE,UAAU,CAAC,SAAS,CAAC,CAAA;IAChC,YAAY,EAAE,YAAY,CAAA;CAC3B;;;;;;;;;;;;;;;;;;;;;;EAiBA"}
|