@choiceform/shared-auth 0.1.0
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 +452 -0
- package/dist/components/auth-sync.d.ts +9 -0
- package/dist/components/auth-sync.d.ts.map +1 -0
- package/dist/components/auth-sync.js +60 -0
- package/dist/components/protected-route.d.ts +18 -0
- package/dist/components/protected-route.d.ts.map +1 -0
- package/dist/components/protected-route.js +28 -0
- package/dist/components/sign-in-page.d.ts +49 -0
- package/dist/components/sign-in-page.d.ts.map +1 -0
- package/dist/components/sign-in-page.js +33 -0
- package/dist/config.d.ts +50 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +14 -0
- package/dist/core.d.ts +2162 -0
- package/dist/core.d.ts.map +1 -0
- package/dist/core.js +37 -0
- package/dist/hooks/use-auth-init.d.ts +7 -0
- package/dist/hooks/use-auth-init.d.ts.map +1 -0
- package/dist/hooks/use-auth-init.js +41 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +24 -0
- package/dist/init.d.ts +2167 -0
- package/dist/init.d.ts.map +1 -0
- package/dist/init.js +17 -0
- package/dist/lib/auth-client.d.ts +2120 -0
- package/dist/lib/auth-client.d.ts.map +1 -0
- package/dist/lib/auth-client.js +11 -0
- package/dist/store/actions.d.ts +60 -0
- package/dist/store/actions.d.ts.map +1 -0
- package/dist/store/actions.js +234 -0
- package/dist/store/computed.d.ts +12 -0
- package/dist/store/computed.d.ts.map +1 -0
- package/dist/store/computed.js +14 -0
- package/dist/store/state.d.ts +16 -0
- package/dist/store/state.d.ts.map +1 -0
- package/dist/store/state.js +52 -0
- package/dist/store/utils.d.ts +103 -0
- package/dist/store/utils.d.ts.map +1 -0
- package/dist/store/utils.js +198 -0
- package/dist/types.d.ts +37 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +4 -0
- package/package.json +65 -0
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 获取当前用户
|
|
3
|
+
*/
|
|
4
|
+
export function getCurrentUser(authStore) {
|
|
5
|
+
return authStore.user.get();
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* 获取当前用户ID
|
|
9
|
+
*/
|
|
10
|
+
export function getCurrentUserId(authStore) {
|
|
11
|
+
return authStore.user.get()?.id || null;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* 安全获取当前用户ID
|
|
15
|
+
*/
|
|
16
|
+
export function getCurrentUserIdSafe(authStore) {
|
|
17
|
+
return getCurrentUserId(authStore);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* 检查是否已认证
|
|
21
|
+
*/
|
|
22
|
+
export function isAuthenticated(authStore) {
|
|
23
|
+
return authStore.isAuthenticated.get();
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* 检查是否正在加载
|
|
27
|
+
*/
|
|
28
|
+
export function isLoading(authStore) {
|
|
29
|
+
return authStore.loading.get();
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* 检查是否已加载
|
|
33
|
+
*/
|
|
34
|
+
export function isLoaded(authStore) {
|
|
35
|
+
return authStore.isLoaded.get();
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* 等待认证完成
|
|
39
|
+
* 使用轮询方式检查认证状态(简单但有效)
|
|
40
|
+
*
|
|
41
|
+
* 注意:如果长时间未加载,Promise 不会自动 reject
|
|
42
|
+
* 建议在外层添加超时处理
|
|
43
|
+
*/
|
|
44
|
+
export async function waitForAuth(authStore) {
|
|
45
|
+
return new Promise((resolve) => {
|
|
46
|
+
// 如果已经加载,立即 resolve
|
|
47
|
+
if (authStore.isLoaded.get()) {
|
|
48
|
+
resolve();
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
const checkAuth = () => {
|
|
52
|
+
if (authStore.isLoaded.get()) {
|
|
53
|
+
resolve();
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
setTimeout(checkAuth, 100);
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
checkAuth();
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* 获取认证令牌
|
|
64
|
+
*/
|
|
65
|
+
export async function getAuthToken(authStore, tokenStorage, authActions, authClient) {
|
|
66
|
+
// 首先从存储中获取 token
|
|
67
|
+
const storedToken = tokenStorage.get();
|
|
68
|
+
if (storedToken) {
|
|
69
|
+
// 如果有 token 但没有用户信息,尝试获取 session
|
|
70
|
+
if (!authStore.user.get()) {
|
|
71
|
+
await authActions.fetchSessionWithToken(storedToken);
|
|
72
|
+
}
|
|
73
|
+
return storedToken;
|
|
74
|
+
}
|
|
75
|
+
// 如果没有存储的 token,尝试从 session 获取
|
|
76
|
+
const sessionData = await authClient.getSession();
|
|
77
|
+
const sessionToken = sessionData?.data?.session?.token || null;
|
|
78
|
+
if (sessionToken) {
|
|
79
|
+
tokenStorage.save(sessionToken);
|
|
80
|
+
}
|
|
81
|
+
return sessionToken;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* 获取认证头
|
|
85
|
+
*/
|
|
86
|
+
export async function getAuthHeaders(authStore, tokenStorage, authActions, authClient) {
|
|
87
|
+
const token = await getAuthToken(authStore, tokenStorage, authActions, authClient);
|
|
88
|
+
if (!token) {
|
|
89
|
+
return {};
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
Authorization: `Bearer ${encodeURIComponent(token)}`,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* 处理 401 响应
|
|
97
|
+
*/
|
|
98
|
+
export function handle401Response(response, authActions) {
|
|
99
|
+
if (response.status === 401) {
|
|
100
|
+
authActions.handleUnauthorized();
|
|
101
|
+
}
|
|
102
|
+
return response;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* API 客户端工具
|
|
106
|
+
*/
|
|
107
|
+
export function createApiClient(authStore, tokenStorage, authActions, authClient) {
|
|
108
|
+
return {
|
|
109
|
+
async get(url, options) {
|
|
110
|
+
const headers = await getAuthHeaders(authStore, tokenStorage, authActions, authClient);
|
|
111
|
+
const response = await fetch(url, {
|
|
112
|
+
...options,
|
|
113
|
+
method: "GET",
|
|
114
|
+
headers: {
|
|
115
|
+
...headers,
|
|
116
|
+
...options?.headers,
|
|
117
|
+
},
|
|
118
|
+
});
|
|
119
|
+
return handle401Response(response, authActions);
|
|
120
|
+
},
|
|
121
|
+
async post(url, body, options) {
|
|
122
|
+
const headers = await getAuthHeaders(authStore, tokenStorage, authActions, authClient);
|
|
123
|
+
const response = await fetch(url, {
|
|
124
|
+
...options,
|
|
125
|
+
method: "POST",
|
|
126
|
+
headers: {
|
|
127
|
+
"Content-Type": "application/json",
|
|
128
|
+
...headers,
|
|
129
|
+
...options?.headers,
|
|
130
|
+
},
|
|
131
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
132
|
+
});
|
|
133
|
+
return handle401Response(response, authActions);
|
|
134
|
+
},
|
|
135
|
+
async put(url, body, options) {
|
|
136
|
+
const headers = await getAuthHeaders(authStore, tokenStorage, authActions, authClient);
|
|
137
|
+
const response = await fetch(url, {
|
|
138
|
+
...options,
|
|
139
|
+
method: "PUT",
|
|
140
|
+
headers: {
|
|
141
|
+
"Content-Type": "application/json",
|
|
142
|
+
...headers,
|
|
143
|
+
...options?.headers,
|
|
144
|
+
},
|
|
145
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
146
|
+
});
|
|
147
|
+
return handle401Response(response, authActions);
|
|
148
|
+
},
|
|
149
|
+
async delete(url, options) {
|
|
150
|
+
const headers = await getAuthHeaders(authStore, tokenStorage, authActions, authClient);
|
|
151
|
+
const response = await fetch(url, {
|
|
152
|
+
...options,
|
|
153
|
+
method: "DELETE",
|
|
154
|
+
headers: {
|
|
155
|
+
...headers,
|
|
156
|
+
...options?.headers,
|
|
157
|
+
},
|
|
158
|
+
});
|
|
159
|
+
return handle401Response(response, authActions);
|
|
160
|
+
},
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* 用户管理器
|
|
165
|
+
*/
|
|
166
|
+
export function createUserManager(authStore) {
|
|
167
|
+
return {
|
|
168
|
+
getUser() {
|
|
169
|
+
return getCurrentUser(authStore);
|
|
170
|
+
},
|
|
171
|
+
getUserId() {
|
|
172
|
+
return getCurrentUserId(authStore);
|
|
173
|
+
},
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* 从 AuthInstance 创建绑定好的工具函数集合
|
|
178
|
+
* 这样就不需要在每个项目中重复包装工具函数
|
|
179
|
+
*/
|
|
180
|
+
export function createBoundAuthUtils(instance) {
|
|
181
|
+
const { authStore, tokenStorage, authActions, authClient } = instance;
|
|
182
|
+
return {
|
|
183
|
+
// Store 访问
|
|
184
|
+
getCurrentUser: () => getCurrentUser(authStore),
|
|
185
|
+
getCurrentUserId: () => getCurrentUserId(authStore),
|
|
186
|
+
getCurrentUserIdSafe: () => getCurrentUserIdSafe(authStore),
|
|
187
|
+
isAuthenticated: () => isAuthenticated(authStore),
|
|
188
|
+
isLoading: () => isLoading(authStore),
|
|
189
|
+
isLoaded: () => isLoaded(authStore),
|
|
190
|
+
waitForAuth: () => waitForAuth(authStore),
|
|
191
|
+
// 需要多个参数的函数
|
|
192
|
+
getAuthToken: () => getAuthToken(authStore, tokenStorage, authActions, authClient),
|
|
193
|
+
getAuthHeaders: () => getAuthHeaders(authStore, tokenStorage, authActions, authClient),
|
|
194
|
+
// 已创建的实例
|
|
195
|
+
apiClient: createApiClient(authStore, tokenStorage, authActions, authClient),
|
|
196
|
+
userManager: createUserManager(authStore),
|
|
197
|
+
};
|
|
198
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 认证相关的类型定义
|
|
3
|
+
*/
|
|
4
|
+
export type SessionUser = {
|
|
5
|
+
banExpires?: string;
|
|
6
|
+
banReason?: string;
|
|
7
|
+
banned?: boolean;
|
|
8
|
+
createdAt: string;
|
|
9
|
+
email: string;
|
|
10
|
+
emailVerified: boolean;
|
|
11
|
+
id: string;
|
|
12
|
+
image?: string;
|
|
13
|
+
lastLoginAt?: string;
|
|
14
|
+
name: string;
|
|
15
|
+
role?: string;
|
|
16
|
+
updatedAt: string;
|
|
17
|
+
};
|
|
18
|
+
export type Session = {
|
|
19
|
+
createdAt: string;
|
|
20
|
+
expiresAt: string;
|
|
21
|
+
id: string;
|
|
22
|
+
ipAddress?: string;
|
|
23
|
+
token: string;
|
|
24
|
+
updatedAt: string;
|
|
25
|
+
user: SessionUser;
|
|
26
|
+
userAgent?: string;
|
|
27
|
+
userId: string;
|
|
28
|
+
};
|
|
29
|
+
export interface AuthState {
|
|
30
|
+
error: string | null;
|
|
31
|
+
isAuthenticated: boolean;
|
|
32
|
+
isLoaded: boolean;
|
|
33
|
+
loading: boolean;
|
|
34
|
+
token: string | null;
|
|
35
|
+
user: SessionUser | null;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,MAAM,WAAW,GAAG;IACxB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;IACb,aAAa,EAAE,OAAO,CAAA;IACtB,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,MAAM,CAAA;CAClB,CAAA;AAED,MAAM,MAAM,OAAO,GAAG;IACpB,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,EAAE,EAAE,MAAM,CAAA;IACV,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,MAAM,CAAA;IACjB,IAAI,EAAE,WAAW,CAAA;IACjB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,MAAM,EAAE,MAAM,CAAA;CACf,CAAA;AAED,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,eAAe,EAAE,OAAO,CAAA;IACxB,QAAQ,EAAE,OAAO,CAAA;IACjB,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,IAAI,EAAE,WAAW,GAAG,IAAI,CAAA;CACzB"}
|
package/dist/types.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@choiceform/shared-auth",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Shared authentication package for Choiceform projects",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js",
|
|
12
|
+
"default": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"README.md"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsc",
|
|
21
|
+
"dev": "tsc --watch",
|
|
22
|
+
"clean": "rimraf dist",
|
|
23
|
+
"prepublishOnly": "pnpm run build"
|
|
24
|
+
},
|
|
25
|
+
"repository": {
|
|
26
|
+
"type": "git",
|
|
27
|
+
"url": "git+https://github.com/choiceform/automation.git",
|
|
28
|
+
"directory": "packages/shared-auth"
|
|
29
|
+
},
|
|
30
|
+
"keywords": [
|
|
31
|
+
"authentication",
|
|
32
|
+
"auth",
|
|
33
|
+
"better-auth",
|
|
34
|
+
"legend-state",
|
|
35
|
+
"react",
|
|
36
|
+
"oauth",
|
|
37
|
+
"github-oauth",
|
|
38
|
+
"choiceform"
|
|
39
|
+
],
|
|
40
|
+
"license": "MIT",
|
|
41
|
+
"publishConfig": {
|
|
42
|
+
"access": "public"
|
|
43
|
+
},
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"@legendapp/state": "v3.0.0-beta.26",
|
|
46
|
+
"better-auth": "^1.3.8",
|
|
47
|
+
"react": "18.2.0",
|
|
48
|
+
"react-router": "^7.6.3"
|
|
49
|
+
},
|
|
50
|
+
"peerDependencies": {
|
|
51
|
+
"@choiceform/design-system": "^1.2.64",
|
|
52
|
+
"@legendapp/state": "v3.0.0-beta.26",
|
|
53
|
+
"better-auth": "^1.3.8",
|
|
54
|
+
"react": ">=18.0.0",
|
|
55
|
+
"react-dom": ">=18.0.0",
|
|
56
|
+
"react-router": "^7.6.3"
|
|
57
|
+
},
|
|
58
|
+
"devDependencies": {
|
|
59
|
+
"@types/react": "18.2.71",
|
|
60
|
+
"@types/react-dom": "18.2.22",
|
|
61
|
+
"typescript": "^5.5.3",
|
|
62
|
+
"rimraf": "^6.0.1"
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|