@choiceform/shared-auth 0.1.16 → 0.1.18
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 +286 -134
- package/dist/__tests__/auth-utils.test.d.ts +5 -0
- package/dist/__tests__/auth-utils.test.d.ts.map +1 -0
- package/dist/__tests__/auth-utils.test.js +96 -0
- package/dist/__tests__/store.test.d.ts +5 -0
- package/dist/__tests__/store.test.d.ts.map +1 -0
- package/dist/__tests__/store.test.js +210 -0
- package/dist/__tests__/user-mapper.test.d.ts +5 -0
- package/dist/__tests__/user-mapper.test.d.ts.map +1 -0
- package/dist/__tests__/user-mapper.test.js +76 -0
- package/dist/api/auth-api.d.ts +93 -9
- package/dist/api/auth-api.d.ts.map +1 -1
- package/dist/api/auth-api.js +219 -80
- package/dist/api/client.d.ts +10 -0
- package/dist/api/client.d.ts.map +1 -1
- package/dist/api/client.js +10 -0
- package/dist/api/organization-api.d.ts +2 -7
- package/dist/api/organization-api.d.ts.map +1 -1
- package/dist/api/organization-api.js +2 -17
- package/dist/api/team-api.d.ts +1 -5
- package/dist/api/team-api.d.ts.map +1 -1
- package/dist/api/team-api.js +5 -11
- package/dist/components/auth-sync.d.ts +27 -0
- package/dist/components/auth-sync.d.ts.map +1 -0
- package/dist/components/auth-sync.js +117 -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 +34 -0
- package/dist/components/sign-in-page.d.ts +21 -0
- package/dist/components/sign-in-page.d.ts.map +1 -0
- package/dist/components/sign-in-page.js +31 -0
- package/dist/config.js +1 -1
- package/dist/core.d.ts +148 -71
- package/dist/core.d.ts.map +1 -1
- package/dist/core.js +109 -28
- package/dist/hooks/index.d.ts +8 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +7 -0
- package/dist/hooks/use-auth-init.d.ts +4 -3
- package/dist/hooks/use-auth-init.d.ts.map +1 -1
- package/dist/hooks/use-auth-init.js +18 -30
- package/dist/hooks/use-auth-sync.d.ts +60 -0
- package/dist/hooks/use-auth-sync.d.ts.map +1 -0
- package/dist/hooks/use-auth-sync.js +116 -0
- package/dist/hooks/use-email-verification.d.ts +85 -0
- package/dist/hooks/use-email-verification.d.ts.map +1 -0
- package/dist/hooks/use-email-verification.js +145 -0
- package/dist/hooks/use-protected-route.d.ts +67 -0
- package/dist/hooks/use-protected-route.d.ts.map +1 -0
- package/dist/hooks/use-protected-route.js +102 -0
- package/dist/index.d.ts +12 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +43 -13
- package/dist/init.d.ts +127 -70
- package/dist/init.d.ts.map +1 -1
- package/dist/lib/auth-client.d.ts.map +1 -1
- package/dist/lib/auth-client.js +75 -2
- package/dist/services/auth-service.d.ts +101 -0
- package/dist/services/auth-service.d.ts.map +1 -0
- package/dist/services/auth-service.js +356 -0
- package/dist/services/callback-service.d.ts +33 -0
- package/dist/services/callback-service.d.ts.map +1 -0
- package/dist/services/callback-service.js +473 -0
- package/dist/services/companion-team.d.ts.map +1 -1
- package/dist/services/companion-team.js +41 -39
- package/dist/services/index.d.ts +2 -0
- package/dist/services/index.d.ts.map +1 -1
- package/dist/services/index.js +2 -0
- package/dist/store/actions.d.ts +54 -51
- package/dist/store/actions.d.ts.map +1 -1
- package/dist/store/actions.js +111 -243
- package/dist/store/computed.d.ts +72 -1
- package/dist/store/computed.d.ts.map +1 -1
- package/dist/store/computed.js +90 -3
- package/dist/store/index.d.ts +3 -3
- package/dist/store/index.d.ts.map +1 -1
- package/dist/store/index.js +2 -2
- package/dist/store/state.d.ts +10 -0
- package/dist/store/state.d.ts.map +1 -1
- package/dist/store/state.js +11 -1
- package/dist/store/utils.d.ts +3 -34
- package/dist/store/utils.d.ts.map +1 -1
- package/dist/store/utils.js +2 -22
- package/dist/types/auth.d.ts +106 -0
- package/dist/types/auth.d.ts.map +1 -1
- package/dist/types/callback.d.ts +35 -0
- package/dist/types/callback.d.ts.map +1 -0
- package/dist/types/callback.js +1 -0
- package/dist/types/index.d.ts +4 -3
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/organization.d.ts +19 -3
- package/dist/types/organization.d.ts.map +1 -1
- package/dist/types/team.d.ts +6 -2
- package/dist/types/team.d.ts.map +1 -1
- package/dist/types/user.d.ts +7 -3
- package/dist/types/user.d.ts.map +1 -1
- package/dist/utils/auth-utils.d.ts +60 -0
- package/dist/utils/auth-utils.d.ts.map +1 -0
- package/dist/utils/auth-utils.js +146 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1 -0
- package/dist/utils/user-mapper.d.ts.map +1 -1
- package/dist/utils/user-mapper.js +2 -1
- package/package.json +10 -2
package/dist/api/auth-api.js
CHANGED
|
@@ -1,75 +1,69 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 认证 API
|
|
3
|
+
*
|
|
4
|
+
* 所有认证相关的 HTTP 请求
|
|
5
|
+
* 统一使用 apiClient 发送请求
|
|
3
6
|
*/
|
|
4
7
|
import { extractSessionUser } from "../utils";
|
|
5
|
-
|
|
6
|
-
|
|
8
|
+
/**
|
|
9
|
+
* 创建认证 API
|
|
10
|
+
*
|
|
11
|
+
* @param apiClient - API 客户端实例
|
|
12
|
+
*/
|
|
13
|
+
export function createAuthApi(apiClient) {
|
|
7
14
|
return {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
15
|
+
// ============================================================
|
|
16
|
+
// Session 管理
|
|
17
|
+
// ============================================================
|
|
18
|
+
/**
|
|
19
|
+
* 获取当前 session
|
|
20
|
+
* 使用 tokenStorage 中的 token
|
|
21
|
+
*/
|
|
22
|
+
async getSession() {
|
|
23
|
+
const response = await apiClient.get("/v1/auth/get-session");
|
|
13
24
|
if (!response.ok)
|
|
14
25
|
return null;
|
|
15
26
|
try {
|
|
16
|
-
return extractSessionUser(
|
|
27
|
+
return extractSessionUser(response.data);
|
|
17
28
|
}
|
|
18
29
|
catch {
|
|
19
30
|
return null;
|
|
20
31
|
}
|
|
21
32
|
},
|
|
33
|
+
/**
|
|
34
|
+
* 使用指定 token 获取 session
|
|
35
|
+
* 用于 OAuth 回调等场景
|
|
36
|
+
*/
|
|
22
37
|
async getSessionWithToken(token) {
|
|
23
|
-
const response = await
|
|
24
|
-
|
|
25
|
-
headers: {
|
|
26
|
-
Authorization: `Bearer ${token}`,
|
|
27
|
-
"Content-Type": "application/json",
|
|
28
|
-
},
|
|
29
|
-
});
|
|
30
|
-
if (!response.ok) {
|
|
31
|
-
throw new Error(`Failed to fetch session: ${await parseErrorResponse(response)}`);
|
|
32
|
-
}
|
|
33
|
-
return extractSessionUser(await response.json());
|
|
34
|
-
},
|
|
35
|
-
async setActiveOrganization(params, token) {
|
|
36
|
-
const headers = { "Content-Type": "application/json" };
|
|
37
|
-
if (token)
|
|
38
|
-
headers.Authorization = `Bearer ${token}`;
|
|
39
|
-
const response = await fetch(`${baseURL}/v1/auth/organization/set-active`, {
|
|
40
|
-
method: "POST",
|
|
41
|
-
headers,
|
|
42
|
-
body: JSON.stringify(params),
|
|
38
|
+
const response = await apiClient.get("/v1/auth/get-session", {
|
|
39
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
43
40
|
});
|
|
44
41
|
if (!response.ok) {
|
|
45
|
-
throw new Error(`Failed to
|
|
46
|
-
}
|
|
47
|
-
},
|
|
48
|
-
async setActiveTeam(params, token) {
|
|
49
|
-
const headers = { "Content-Type": "application/json" };
|
|
50
|
-
if (token)
|
|
51
|
-
headers.Authorization = `Bearer ${token}`;
|
|
52
|
-
const response = await fetch(`${baseURL}/v1/auth/organization/set-active-team`, {
|
|
53
|
-
method: "POST",
|
|
54
|
-
headers,
|
|
55
|
-
body: JSON.stringify(params),
|
|
56
|
-
});
|
|
57
|
-
if (!response.ok) {
|
|
58
|
-
throw new Error(`Failed to set active team: ${await parseErrorResponse(response)}`);
|
|
42
|
+
throw new Error(`Failed to fetch session: ${response.status}`);
|
|
59
43
|
}
|
|
44
|
+
return extractSessionUser(response.data);
|
|
60
45
|
},
|
|
46
|
+
// ============================================================
|
|
47
|
+
// 用户 Onboarding
|
|
48
|
+
// ============================================================
|
|
49
|
+
/**
|
|
50
|
+
* 用户 Onboard
|
|
51
|
+
* 创建默认的伴生组织和团队
|
|
52
|
+
*/
|
|
61
53
|
async onboard(token) {
|
|
62
|
-
const response = await
|
|
63
|
-
|
|
64
|
-
headers: {
|
|
65
|
-
"Content-Type": "application/json",
|
|
66
|
-
Authorization: `Bearer ${token}`,
|
|
67
|
-
},
|
|
54
|
+
const response = await apiClient.post("/v1/auth/onboard", undefined, {
|
|
55
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
68
56
|
});
|
|
69
57
|
if (!response.ok) {
|
|
70
|
-
throw new Error(`Failed to onboard: ${
|
|
58
|
+
throw new Error(`Failed to onboard: ${response.status}`);
|
|
71
59
|
}
|
|
72
60
|
},
|
|
61
|
+
// ============================================================
|
|
62
|
+
// 用户信息
|
|
63
|
+
// ============================================================
|
|
64
|
+
/**
|
|
65
|
+
* 更新用户信息
|
|
66
|
+
*/
|
|
73
67
|
async updateUser(data) {
|
|
74
68
|
const response = await apiClient.post("/v1/auth/update-user", data);
|
|
75
69
|
if (!response.ok) {
|
|
@@ -77,57 +71,202 @@ export function createAuthApi(apiClient, baseURL) {
|
|
|
77
71
|
}
|
|
78
72
|
return this.getSession();
|
|
79
73
|
},
|
|
74
|
+
// ============================================================
|
|
75
|
+
// Magic Link
|
|
76
|
+
// ============================================================
|
|
77
|
+
/**
|
|
78
|
+
* 发送 Magic Link
|
|
79
|
+
*/
|
|
80
80
|
async sendMagicLink(params) {
|
|
81
|
-
const response = await
|
|
82
|
-
method: "POST",
|
|
83
|
-
headers: { "Content-Type": "application/json" },
|
|
84
|
-
body: JSON.stringify(params),
|
|
85
|
-
});
|
|
81
|
+
const response = await apiClient.post("/v1/auth/sign-in/magic-link", params);
|
|
86
82
|
if (!response.ok) {
|
|
87
|
-
throw new Error(`Failed to send magic link: ${
|
|
83
|
+
throw new Error(`Failed to send magic link: ${response.status}`);
|
|
88
84
|
}
|
|
89
|
-
return response.
|
|
85
|
+
return response.data;
|
|
90
86
|
},
|
|
87
|
+
// ============================================================
|
|
88
|
+
// 邮箱验证
|
|
89
|
+
// ============================================================
|
|
91
90
|
/**
|
|
92
|
-
*
|
|
93
|
-
* 用于通过 OAuth 或 Magic Link 登录的用户设置密码
|
|
91
|
+
* 重新发送验证邮件
|
|
94
92
|
*/
|
|
95
|
-
async
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
headers,
|
|
102
|
-
credentials: "include",
|
|
103
|
-
body: JSON.stringify({ newPassword }),
|
|
104
|
-
});
|
|
93
|
+
async resendVerificationEmail(email, callbackURL) {
|
|
94
|
+
const finalCallbackURL = callbackURL ||
|
|
95
|
+
(typeof window !== "undefined"
|
|
96
|
+
? `${window.location.origin}/auth/callback?type=signup&email=${encodeURIComponent(email)}`
|
|
97
|
+
: `/auth/callback?type=signup&email=${encodeURIComponent(email)}`);
|
|
98
|
+
const response = await apiClient.post("/v1/auth/send-verification-email", { email, callbackURL: finalCallbackURL });
|
|
105
99
|
if (!response.ok) {
|
|
106
|
-
throw new Error(`Failed to
|
|
100
|
+
throw new Error(`Failed to resend verification email: ${response.status}`);
|
|
107
101
|
}
|
|
102
|
+
return response.data;
|
|
108
103
|
},
|
|
109
104
|
/**
|
|
110
|
-
*
|
|
111
|
-
*
|
|
105
|
+
* 检查邮箱是否已被注册
|
|
106
|
+
*
|
|
107
|
+
* @returns true 表示邮箱已被注册,false 表示可用
|
|
112
108
|
*/
|
|
113
109
|
async checkEmailExists(email) {
|
|
114
110
|
try {
|
|
115
|
-
const response = await
|
|
116
|
-
method: "POST",
|
|
117
|
-
headers: { "Content-Type": "application/json" },
|
|
118
|
-
body: JSON.stringify({ email }),
|
|
119
|
-
});
|
|
111
|
+
const response = await apiClient.get(`/v1/auth/check-email?email=${encodeURIComponent(email)}`);
|
|
120
112
|
if (!response.ok) {
|
|
121
|
-
// API 不存在或其他错误,返回 false 让流程继续
|
|
122
113
|
return false;
|
|
123
114
|
}
|
|
124
|
-
|
|
125
|
-
return data.
|
|
115
|
+
// 后端返回 success: true 表示邮箱可用(未注册)
|
|
116
|
+
return response.data.success === false;
|
|
126
117
|
}
|
|
127
118
|
catch {
|
|
128
|
-
// 网络错误等,返回 false 让流程继续
|
|
129
119
|
return false;
|
|
130
120
|
}
|
|
131
121
|
},
|
|
122
|
+
// ============================================================
|
|
123
|
+
// 密码管理
|
|
124
|
+
// ============================================================
|
|
125
|
+
/**
|
|
126
|
+
* 为已登录用户绑定密码
|
|
127
|
+
* 用于通过 OAuth 或 Magic Link 登录的用户设置密码
|
|
128
|
+
*/
|
|
129
|
+
async linkCredential(newPassword, token) {
|
|
130
|
+
const options = token
|
|
131
|
+
? { headers: { Authorization: `Bearer ${token}` } }
|
|
132
|
+
: undefined;
|
|
133
|
+
const response = await apiClient.post("/v1/auth/link-credential", { newPassword }, options);
|
|
134
|
+
if (!response.ok) {
|
|
135
|
+
throw new Error(`Failed to link credential: ${response.status}`);
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
/**
|
|
139
|
+
* 更改密码
|
|
140
|
+
*/
|
|
141
|
+
async changePassword(currentPassword, newPassword, token) {
|
|
142
|
+
const options = token
|
|
143
|
+
? { headers: { Authorization: `Bearer ${token}` } }
|
|
144
|
+
: undefined;
|
|
145
|
+
const response = await apiClient.post("/v1/auth/change-password", { currentPassword, newPassword }, options);
|
|
146
|
+
if (!response.ok) {
|
|
147
|
+
throw new Error(`Failed to change password: ${response.status}`);
|
|
148
|
+
}
|
|
149
|
+
return response.data;
|
|
150
|
+
},
|
|
151
|
+
// ============================================================
|
|
152
|
+
// 邮箱更改
|
|
153
|
+
// ============================================================
|
|
154
|
+
/**
|
|
155
|
+
* 更改邮箱
|
|
156
|
+
*/
|
|
157
|
+
async changeEmail(newEmail, callbackURL, token) {
|
|
158
|
+
const options = token
|
|
159
|
+
? { headers: { Authorization: `Bearer ${token}` } }
|
|
160
|
+
: undefined;
|
|
161
|
+
const response = await apiClient.post("/v1/auth/change-email", { newEmail, callbackURL }, options);
|
|
162
|
+
if (!response.ok) {
|
|
163
|
+
// 提取服务器返回的错误代码
|
|
164
|
+
const errorData = response.data;
|
|
165
|
+
if (errorData?.code) {
|
|
166
|
+
throw new Error(JSON.stringify({ code: errorData.code, message: errorData.message }));
|
|
167
|
+
}
|
|
168
|
+
throw new Error(`Failed to change email: ${response.status}`);
|
|
169
|
+
}
|
|
170
|
+
return response.data;
|
|
171
|
+
},
|
|
172
|
+
// ============================================================
|
|
173
|
+
// 账户管理
|
|
174
|
+
// ============================================================
|
|
175
|
+
/**
|
|
176
|
+
* 获取用户关联的所有账户
|
|
177
|
+
*
|
|
178
|
+
* 返回用户通过不同方式登录的账户列表
|
|
179
|
+
* - credential: 邮箱密码登录
|
|
180
|
+
* - github: GitHub OAuth 登录
|
|
181
|
+
* - 其他 OAuth 提供商
|
|
182
|
+
*/
|
|
183
|
+
async listAccounts(token) {
|
|
184
|
+
const options = token
|
|
185
|
+
? { headers: { Authorization: `Bearer ${token}` } }
|
|
186
|
+
: undefined;
|
|
187
|
+
const response = await apiClient.get("/v1/auth/list-accounts", options);
|
|
188
|
+
if (!response.ok) {
|
|
189
|
+
throw new Error(`Failed to list accounts: ${response.status}`);
|
|
190
|
+
}
|
|
191
|
+
return response.data;
|
|
192
|
+
},
|
|
193
|
+
/**
|
|
194
|
+
* 获取 OAuth 账户详细信息
|
|
195
|
+
*
|
|
196
|
+
* 通过 accountId 获取 OAuth 提供商的用户详细信息
|
|
197
|
+
* 如 GitHub 用户的 email、name、avatar 等
|
|
198
|
+
*/
|
|
199
|
+
async getOAuthAccountInfo(accountId, token) {
|
|
200
|
+
const options = token
|
|
201
|
+
? { headers: { Authorization: `Bearer ${token}` } }
|
|
202
|
+
: undefined;
|
|
203
|
+
try {
|
|
204
|
+
const response = await apiClient.get(`/v1/auth/account-info?accountId=${encodeURIComponent(accountId)}`, options);
|
|
205
|
+
if (!response.ok) {
|
|
206
|
+
return null;
|
|
207
|
+
}
|
|
208
|
+
return response.data;
|
|
209
|
+
}
|
|
210
|
+
catch {
|
|
211
|
+
return null;
|
|
212
|
+
}
|
|
213
|
+
},
|
|
214
|
+
/**
|
|
215
|
+
* 取消关联 OAuth 账户
|
|
216
|
+
*
|
|
217
|
+
* 解除用户与 OAuth 提供商的关联
|
|
218
|
+
*/
|
|
219
|
+
async unlinkAccount(providerId, accountId, token) {
|
|
220
|
+
const options = token
|
|
221
|
+
? { headers: { Authorization: `Bearer ${token}` } }
|
|
222
|
+
: undefined;
|
|
223
|
+
const response = await apiClient.post("/v1/auth/unlink-account", { accountId, providerId }, options);
|
|
224
|
+
if (!response.ok) {
|
|
225
|
+
throw new Error(`Failed to unlink account: ${response.status}`);
|
|
226
|
+
}
|
|
227
|
+
return response.data;
|
|
228
|
+
},
|
|
229
|
+
/**
|
|
230
|
+
* 删除用户账户
|
|
231
|
+
*/
|
|
232
|
+
async deleteUser(password, callbackURL, token) {
|
|
233
|
+
const options = token
|
|
234
|
+
? { headers: { Authorization: `Bearer ${token}` } }
|
|
235
|
+
: undefined;
|
|
236
|
+
const response = await apiClient.post("/v1/auth/delete-user", { password, callbackURL }, options);
|
|
237
|
+
if (!response.ok) {
|
|
238
|
+
throw new Error(`Failed to delete user: ${response.status}`);
|
|
239
|
+
}
|
|
240
|
+
return response.data;
|
|
241
|
+
},
|
|
242
|
+
// ============================================================
|
|
243
|
+
// 会话管理
|
|
244
|
+
// ============================================================
|
|
245
|
+
/**
|
|
246
|
+
* 获取当前用户的所有会话
|
|
247
|
+
*/
|
|
248
|
+
async listSessions(token) {
|
|
249
|
+
const options = token
|
|
250
|
+
? { headers: { Authorization: `Bearer ${token}` } }
|
|
251
|
+
: undefined;
|
|
252
|
+
const response = await apiClient.get("/v1/auth/list-sessions", options);
|
|
253
|
+
if (!response.ok) {
|
|
254
|
+
throw new Error(`Failed to list sessions: ${response.status}`);
|
|
255
|
+
}
|
|
256
|
+
return response.data;
|
|
257
|
+
},
|
|
258
|
+
/**
|
|
259
|
+
* 撤销指定会话
|
|
260
|
+
*/
|
|
261
|
+
async revokeSession(params, token) {
|
|
262
|
+
const options = token
|
|
263
|
+
? { headers: { Authorization: `Bearer ${token}` } }
|
|
264
|
+
: undefined;
|
|
265
|
+
const response = await apiClient.post("/v1/auth/revoke-session", params, options);
|
|
266
|
+
if (!response.ok) {
|
|
267
|
+
throw new Error(`Failed to revoke session: ${response.status}`);
|
|
268
|
+
}
|
|
269
|
+
return response.data;
|
|
270
|
+
},
|
|
132
271
|
};
|
|
133
272
|
}
|
package/dist/api/client.d.ts
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 基础 HTTP 客户端
|
|
3
|
+
*
|
|
4
|
+
* 职责:
|
|
5
|
+
* - 封装 fetch API,提供统一的 HTTP 请求方法
|
|
6
|
+
* - 自动添加认证 Header(Authorization: Bearer xxx)
|
|
7
|
+
* - 处理 401 未授权响应(自动清除认证状态)
|
|
8
|
+
* - 解析 JSON 响应
|
|
9
|
+
*
|
|
10
|
+
* 使用:
|
|
11
|
+
* - 所有 API 请求都应通过 apiClient 发送
|
|
12
|
+
* - 不应直接使用原生 fetch
|
|
3
13
|
*/
|
|
4
14
|
import type { Observable } from "@legendapp/state";
|
|
5
15
|
import type { AuthState } from "../types";
|
package/dist/api/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAClD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAEzC,MAAM,WAAW,YAAY;IAC3B,KAAK,IAAI,IAAI,CAAA;IACb,GAAG,IAAI,MAAM,GAAG,IAAI,CAAA;IACpB,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAA;CACjC;AAED,MAAM,WAAW,mBAAmB;IAClC,kBAAkB,IAAI,IAAI,CAAA;CAC3B;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,UAAU,CAAC,SAAS,CAAC,CAAA;IAChC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,YAAY,EAAE,YAAY,CAAA;IAC1B,mBAAmB,EAAE,mBAAmB,CAAA;CACzC;AAED,MAAM,WAAW,WAAW,CAAC,CAAC,GAAG,OAAO;IACtC,IAAI,EAAE,CAAC,CAAA;IACP,EAAE,EAAE,OAAO,CAAA;IACX,MAAM,EAAE,MAAM,CAAA;CACf;AA2BD,wBAAsB,kBAAkB,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAmB5E;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,eAAe;QAMzC,CAAC,kBAAkB,MAAM,YAAY,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;SASzE,CAAC,kBAAkB,MAAM,SAAS,OAAO,YAAY,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;QAc3F,CAAC,kBAAkB,MAAM,SAAS,OAAO,YAAY,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;WAcvF,CAAC,kBAAkB,MAAM,YAAY,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;gBASrE,MAAM,YAAY,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC;EAWtE;AAED,MAAM,MAAM,SAAS,GAAG,UAAU,CAAC,OAAO,eAAe,CAAC,CAAA"}
|
package/dist/api/client.js
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 基础 HTTP 客户端
|
|
3
|
+
*
|
|
4
|
+
* 职责:
|
|
5
|
+
* - 封装 fetch API,提供统一的 HTTP 请求方法
|
|
6
|
+
* - 自动添加认证 Header(Authorization: Bearer xxx)
|
|
7
|
+
* - 处理 401 未授权响应(自动清除认证状态)
|
|
8
|
+
* - 解析 JSON 响应
|
|
9
|
+
*
|
|
10
|
+
* 使用:
|
|
11
|
+
* - 所有 API 请求都应通过 apiClient 发送
|
|
12
|
+
* - 不应直接使用原生 fetch
|
|
3
13
|
*/
|
|
4
14
|
function getAuthHeaders(tokenStorage) {
|
|
5
15
|
const token = tokenStorage.get();
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* 封装所有组织管理的 API 调用
|
|
5
5
|
* 基于 Core AI Auth API 文档
|
|
6
6
|
*/
|
|
7
|
-
import type { Organization, FullOrganization, CreateOrganizationRequest, UpdateOrganizationRequest, DeleteOrganizationRequest,
|
|
7
|
+
import type { Organization, FullOrganization, CreateOrganizationRequest, UpdateOrganizationRequest, DeleteOrganizationRequest, CheckSlugRequest, Member, RemoveMemberRequest, UpdateMemberRoleRequest, Invitation, InvitationDetail, InviteMemberRequest, CancelInvitationRequest, AcceptInvitationRequest, RejectInvitationRequest, InvitationResponse } from "../types/organization";
|
|
8
8
|
import type { ApiClient } from "./client";
|
|
9
9
|
/**
|
|
10
10
|
* 创建组织 API
|
|
@@ -33,10 +33,6 @@ export declare function createOrganizationApi(apiClient: ApiClient, _baseURL: st
|
|
|
33
33
|
* 获取当前活跃组织详情(包含成员列表和用户信息)
|
|
34
34
|
*/
|
|
35
35
|
getFullOrganization(): Promise<FullOrganization | null>;
|
|
36
|
-
/**
|
|
37
|
-
* 设置活跃组织
|
|
38
|
-
*/
|
|
39
|
-
setActive(request: SetActiveOrganizationRequest): Promise<Organization>;
|
|
40
36
|
/**
|
|
41
37
|
* 检查 slug 可用性
|
|
42
38
|
*/
|
|
@@ -62,9 +58,8 @@ export declare function createOrganizationApi(apiClient: ApiClient, _baseURL: st
|
|
|
62
58
|
/**
|
|
63
59
|
* 邀请成员
|
|
64
60
|
* @param request 邀请请求参数
|
|
65
|
-
* @param inviteLink 邀请链接(会添加到 Choiceform-Invite-Link header 中)
|
|
66
61
|
*/
|
|
67
|
-
inviteMember(request: InviteMemberRequest
|
|
62
|
+
inviteMember(request: InviteMemberRequest): Promise<Invitation>;
|
|
68
63
|
/**
|
|
69
64
|
* 获取邀请列表
|
|
70
65
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"organization-api.d.ts","sourceRoot":"","sources":["../../src/api/organization-api.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EACV,YAAY,EACZ,gBAAgB,EAChB,yBAAyB,EACzB,yBAAyB,EACzB,yBAAyB,EACzB,
|
|
1
|
+
{"version":3,"file":"organization-api.d.ts","sourceRoot":"","sources":["../../src/api/organization-api.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EACV,YAAY,EACZ,gBAAgB,EAChB,yBAAyB,EACzB,yBAAyB,EACzB,yBAAyB,EACzB,gBAAgB,EAChB,MAAM,EACN,mBAAmB,EACnB,uBAAuB,EACvB,UAAU,EACV,gBAAgB,EAChB,mBAAmB,EACnB,uBAAuB,EACvB,uBAAuB,EACvB,uBAAuB,EACvB,kBAAkB,EACnB,MAAM,uBAAuB,CAAA;AAC9B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAEzC;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM;IAQxE;;OAEG;oBACmB,yBAAyB,GAAG,OAAO,CAAC,YAAY,CAAC;IAQvE;;OAEG;oBACmB,yBAAyB,GAAG,OAAO,CAAC,YAAY,CAAC;IAQvE;;OAEG;oBACmB,yBAAyB,GAAG,OAAO,CAAC,MAAM,CAAC;IAQjE;;OAEG;YACW,OAAO,CAAC,YAAY,EAAE,CAAC;IAQrC;;OAEG;2BAC0B,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC;IAW7D;;OAEG;uBACsB,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC;IAgB5D;;OAEG;uBACsB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAW/C;;OAEG;2BAC0B,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAW7D;;OAEG;0BACyB,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC;IAQjE;;OAEG;8BAC6B,uBAAuB,GAAG,OAAO,CAAC,MAAM,CAAC;IAYzE;;;OAGG;0BACyB,mBAAmB,GAAG,OAAO,CAAC,UAAU,CAAC;IAWrE;;OAEG;uBACsB,OAAO,CAAC,UAAU,EAAE,CAAC;IAQ9C;;OAEG;gCAC+B,MAAM,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC;IAa3E;;OAEG;8BAC6B,uBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC;IAOvE;;OAEG;8BAC6B,uBAAuB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAQrF;;OAEG;8BAC6B,uBAAuB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAQrF;;;;OAIG;0BACyB,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;EAOrD;AAED,MAAM,MAAM,eAAe,GAAG,UAAU,CAAC,OAAO,qBAAqB,CAAC,CAAA"}
|
|
@@ -69,16 +69,6 @@ export function createOrganizationApi(apiClient, _baseURL) {
|
|
|
69
69
|
}
|
|
70
70
|
return response.data;
|
|
71
71
|
},
|
|
72
|
-
/**
|
|
73
|
-
* 设置活跃组织
|
|
74
|
-
*/
|
|
75
|
-
async setActive(request) {
|
|
76
|
-
const response = await apiClient.post(`${basePath}/set-active`, request);
|
|
77
|
-
if (!response.ok) {
|
|
78
|
-
throw new Error(`Failed to set active organization: ${response.status}`);
|
|
79
|
-
}
|
|
80
|
-
return response.data;
|
|
81
|
-
},
|
|
82
72
|
/**
|
|
83
73
|
* 检查 slug 可用性
|
|
84
74
|
*/
|
|
@@ -148,14 +138,9 @@ export function createOrganizationApi(apiClient, _baseURL) {
|
|
|
148
138
|
/**
|
|
149
139
|
* 邀请成员
|
|
150
140
|
* @param request 邀请请求参数
|
|
151
|
-
* @param inviteLink 邀请链接(会添加到 Choiceform-Invite-Link header 中)
|
|
152
141
|
*/
|
|
153
|
-
async inviteMember(request
|
|
154
|
-
const
|
|
155
|
-
if (inviteLink) {
|
|
156
|
-
headers["Choiceform-Invite-Link"] = inviteLink;
|
|
157
|
-
}
|
|
158
|
-
const response = await apiClient.post(`${basePath}/invite-member`, request, { headers });
|
|
142
|
+
async inviteMember(request) {
|
|
143
|
+
const response = await apiClient.post(`${basePath}/invite-member`, request);
|
|
159
144
|
if (!response.ok) {
|
|
160
145
|
throw new Error(`Failed to invite member: ${response.status}`);
|
|
161
146
|
}
|
package/dist/api/team-api.d.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* 封装所有团队管理的 API 调用
|
|
5
5
|
* 基于 Core AI Auth API 文档
|
|
6
6
|
*/
|
|
7
|
-
import type { AddTeamMemberRequest, CreateTeamRequest, DeleteTeamRequest, RemoveTeamMemberRequest,
|
|
7
|
+
import type { AddTeamMemberRequest, CreateTeamRequest, DeleteTeamRequest, RemoveTeamMemberRequest, Team, TeamMember, UpdateTeamRequest } from "../types/team";
|
|
8
8
|
import type { ApiClient } from "./client";
|
|
9
9
|
/**
|
|
10
10
|
* 创建团队 API
|
|
@@ -28,10 +28,6 @@ export declare function createTeamApi(apiClient: ApiClient): {
|
|
|
28
28
|
* 删除团队
|
|
29
29
|
*/
|
|
30
30
|
delete(request: DeleteTeamRequest): Promise<void>;
|
|
31
|
-
/**
|
|
32
|
-
* 设置活跃团队
|
|
33
|
-
*/
|
|
34
|
-
setActive(request: SetActiveTeamRequest): Promise<void>;
|
|
35
31
|
/**
|
|
36
32
|
* 获取用户所属的团队列表
|
|
37
33
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"team-api.d.ts","sourceRoot":"","sources":["../../src/api/team-api.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EACV,oBAAoB,EACpB,iBAAiB,EACjB,iBAAiB,EACjB,uBAAuB,EACvB,
|
|
1
|
+
{"version":3,"file":"team-api.d.ts","sourceRoot":"","sources":["../../src/api/team-api.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EACV,oBAAoB,EACpB,iBAAiB,EACjB,iBAAiB,EACjB,uBAAuB,EACvB,IAAI,EACJ,UAAU,EACV,iBAAiB,EAClB,MAAM,eAAe,CAAA;AACtB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAEzC;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,SAAS;IAQ9C;;OAEG;oBACmB,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAWvD;;OAEG;YACW,OAAO,CAAC,IAAI,EAAE,CAAC;IAQ7B;;OAEG;oBACmB,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAQvD;;OAEG;oBACmB,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAOvD;;OAEG;qBACoB,OAAO,CAAC,IAAI,EAAE,CAAC;IAYtC;;OAEG;wBACuB,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;IAUxD;;OAEG;uBACsB,oBAAoB,GAAG,OAAO,CAAC,UAAU,CAAC;IAQnE;;OAEG;0BACyB,uBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC;IAOnE;;OAEG;sBACqB,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;EAOjD;AAED,MAAM,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAA"}
|
package/dist/api/team-api.js
CHANGED
|
@@ -19,7 +19,10 @@ export function createTeamApi(apiClient) {
|
|
|
19
19
|
* 创建团队
|
|
20
20
|
*/
|
|
21
21
|
async create(request) {
|
|
22
|
-
const response = await apiClient.post(`${basePath}/create-team`,
|
|
22
|
+
const response = await apiClient.post(`${basePath}/create-team`, {
|
|
23
|
+
...request,
|
|
24
|
+
metadata: request.metadata ?? {},
|
|
25
|
+
});
|
|
23
26
|
if (!response.ok) {
|
|
24
27
|
throw new Error(`Failed to create team: ${response.status}`);
|
|
25
28
|
}
|
|
@@ -54,15 +57,6 @@ export function createTeamApi(apiClient) {
|
|
|
54
57
|
throw new Error(`Failed to delete team: ${response.status}`);
|
|
55
58
|
}
|
|
56
59
|
},
|
|
57
|
-
/**
|
|
58
|
-
* 设置活跃团队
|
|
59
|
-
*/
|
|
60
|
-
async setActive(request) {
|
|
61
|
-
const response = await apiClient.post(`${basePath}/set-active-team`, request);
|
|
62
|
-
if (!response.ok) {
|
|
63
|
-
throw new Error(`Failed to set active team: ${response.status}`);
|
|
64
|
-
}
|
|
65
|
-
},
|
|
66
60
|
/**
|
|
67
61
|
* 获取用户所属的团队列表
|
|
68
62
|
*/
|
|
@@ -109,7 +103,7 @@ export function createTeamApi(apiClient) {
|
|
|
109
103
|
* 离开团队(普通成员可自行调用)
|
|
110
104
|
*/
|
|
111
105
|
async leaveTeam(teamId) {
|
|
112
|
-
const response = await apiClient.post(
|
|
106
|
+
const response = await apiClient.post("/v1/auth/leave-team", { teamId });
|
|
113
107
|
if (!response.ok) {
|
|
114
108
|
throw new Error(`Failed to leave team: ${response.status}`);
|
|
115
109
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Better Auth 认证状态同步组件
|
|
3
|
+
*
|
|
4
|
+
* 功能说明:
|
|
5
|
+
* - 同步 better-auth 的 session 状态到 Legend State store
|
|
6
|
+
* - 在用户登录成功后自动设置组织/团队上下文
|
|
7
|
+
* - 使用响应式状态监听,确保状态同步的实时性
|
|
8
|
+
*
|
|
9
|
+
* 边缘情况处理:
|
|
10
|
+
* - Session 加载中:设置 loading 状态
|
|
11
|
+
* - Session 错误:清空用户信息,重置团队设置状态
|
|
12
|
+
* - 无 Session 但有用户:保持用户信息(可能从 token 加载)
|
|
13
|
+
* - 用户登出:重置团队设置状态,允许下次登录时重新设置
|
|
14
|
+
*/
|
|
15
|
+
import type { AuthInstance } from "../core";
|
|
16
|
+
/**
|
|
17
|
+
* AuthSync 组件 Props
|
|
18
|
+
*/
|
|
19
|
+
interface AuthSyncProps {
|
|
20
|
+
auth: AuthInstance;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* AuthSync 组件
|
|
24
|
+
*/
|
|
25
|
+
export declare function AuthSync({ auth }: AuthSyncProps): null;
|
|
26
|
+
export {};
|
|
27
|
+
//# sourceMappingURL=auth-sync.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-sync.d.ts","sourceRoot":"","sources":["../../src/components/auth-sync.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAK3C;;GAEG;AACH,UAAU,aAAa;IACrB,IAAI,EAAE,YAAY,CAAA;CACnB;AAsED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,EAAE,IAAI,EAAE,EAAE,aAAa,QAwF/C"}
|