@yiminlab/authkit 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/dist/index.js ADDED
@@ -0,0 +1,737 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var src_exports = {};
22
+ __export(src_exports, {
23
+ AuthGuard: () => AuthGuard,
24
+ AuthKitClient: () => AuthKitClient,
25
+ AuthRedirect: () => AuthRedirect,
26
+ CallbackHandler: () => CallbackHandler,
27
+ DEFAULT_AUTH_CONFIG: () => DEFAULT_AUTH_CONFIG,
28
+ LocalStorageAdapter: () => LocalStorageAdapter,
29
+ TokenManager: () => TokenManager,
30
+ getAuthKitClient: () => getAuthKitClient,
31
+ getAuthRedirect: () => getAuthRedirect,
32
+ getTokenManager: () => getTokenManager,
33
+ resetAuthKitClient: () => resetAuthKitClient,
34
+ resetAuthRedirect: () => resetAuthRedirect,
35
+ resetTokenManager: () => resetTokenManager,
36
+ useAccessToken: () => useAccessToken,
37
+ useAuth: () => useAuth,
38
+ withAuthGuard: () => withAuthGuard
39
+ });
40
+ module.exports = __toCommonJS(src_exports);
41
+
42
+ // src/core/types.ts
43
+ var DEFAULT_AUTH_CONFIG = {
44
+ portalUrl: typeof process !== "undefined" ? process.env.NEXT_PUBLIC_PORTAL_URL || "https://yiminlab.site" : "https://yiminlab.site",
45
+ apiBaseUrl: typeof process !== "undefined" ? process.env.NEXT_PUBLIC_API_BASE_URL || "https://api.yiminlab.site" : "https://api.yiminlab.site",
46
+ callbackPath: "/auth/callback",
47
+ tokenKeys: {
48
+ accessToken: "authkit_access_token",
49
+ refreshToken: "authkit_refresh_token",
50
+ tokenExpiry: "authkit_token_expiry"
51
+ }
52
+ };
53
+
54
+ // src/core/token-manager.ts
55
+ var LocalStorageAdapter = class {
56
+ getItem(key) {
57
+ if (typeof window === "undefined") return null;
58
+ return localStorage.getItem(key);
59
+ }
60
+ setItem(key, value) {
61
+ if (typeof window === "undefined") return;
62
+ localStorage.setItem(key, value);
63
+ }
64
+ removeItem(key) {
65
+ if (typeof window === "undefined") return;
66
+ localStorage.removeItem(key);
67
+ }
68
+ };
69
+ var TokenManager = class {
70
+ constructor(storage, config) {
71
+ this.storage = storage || new LocalStorageAdapter();
72
+ this.config = { ...DEFAULT_AUTH_CONFIG, ...config };
73
+ }
74
+ /**
75
+ * 保存 tokens
76
+ */
77
+ setTokens(accessToken, refreshToken, expiresIn) {
78
+ const expiryTime = Date.now() + expiresIn * 1e3;
79
+ this.storage.setItem(this.config.tokenKeys.accessToken, accessToken);
80
+ this.storage.setItem(this.config.tokenKeys.refreshToken, refreshToken);
81
+ this.storage.setItem(this.config.tokenKeys.tokenExpiry, expiryTime.toString());
82
+ }
83
+ /**
84
+ * 获取 Access Token
85
+ */
86
+ getAccessToken() {
87
+ return this.storage.getItem(this.config.tokenKeys.accessToken);
88
+ }
89
+ /**
90
+ * 获取 Refresh Token
91
+ */
92
+ getRefreshToken() {
93
+ return this.storage.getItem(this.config.tokenKeys.refreshToken);
94
+ }
95
+ /**
96
+ * 获取 Token 过期时间
97
+ */
98
+ getTokenExpiry() {
99
+ const expiry = this.storage.getItem(this.config.tokenKeys.tokenExpiry);
100
+ return expiry ? parseInt(expiry, 10) : null;
101
+ }
102
+ /**
103
+ * 检查 Access Token 是否过期
104
+ * 提前 60 秒认为过期,留出刷新时间
105
+ */
106
+ isAccessTokenExpired() {
107
+ const expiryTime = this.getTokenExpiry();
108
+ if (!expiryTime) return true;
109
+ const now = Date.now();
110
+ return now >= expiryTime - 6e4;
111
+ }
112
+ /**
113
+ * 清除所有 tokens
114
+ */
115
+ clearTokens() {
116
+ this.storage.removeItem(this.config.tokenKeys.accessToken);
117
+ this.storage.removeItem(this.config.tokenKeys.refreshToken);
118
+ this.storage.removeItem(this.config.tokenKeys.tokenExpiry);
119
+ }
120
+ /**
121
+ * 检查是否有有效的认证信息
122
+ */
123
+ hasValidAuth() {
124
+ const accessToken = this.getAccessToken();
125
+ const refreshToken = this.getRefreshToken();
126
+ return !!(accessToken && !this.isAccessTokenExpired()) || !!refreshToken;
127
+ }
128
+ /**
129
+ * 获取配置
130
+ */
131
+ getConfig() {
132
+ return { ...this.config };
133
+ }
134
+ };
135
+ var instance = null;
136
+ function getTokenManager(config) {
137
+ if (!instance) {
138
+ instance = new TokenManager(void 0, config);
139
+ }
140
+ return instance;
141
+ }
142
+ function resetTokenManager() {
143
+ instance = null;
144
+ }
145
+
146
+ // src/core/auth-redirect.ts
147
+ var ALLOWED_REDIRECT_DOMAINS = [
148
+ "yiminlab.site",
149
+ "jsontailor.yiminlab.site",
150
+ "ai.yiminlab.site",
151
+ "localhost"
152
+ ];
153
+ var AuthRedirect = class {
154
+ constructor(config) {
155
+ this.config = {
156
+ portalUrl: config?.portalUrl || DEFAULT_AUTH_CONFIG.portalUrl,
157
+ callbackPath: config?.callbackPath || DEFAULT_AUTH_CONFIG.callbackPath
158
+ };
159
+ }
160
+ /**
161
+ * 获取当前页面的完整 URL
162
+ */
163
+ getCurrentUrl() {
164
+ if (typeof window === "undefined") return "";
165
+ return window.location.href;
166
+ }
167
+ /**
168
+ * 获取当前页面的 origin
169
+ */
170
+ getCurrentOrigin() {
171
+ if (typeof window === "undefined") return "";
172
+ return window.location.origin;
173
+ }
174
+ /**
175
+ * 构建回调 URL
176
+ */
177
+ buildCallbackUrl() {
178
+ return `${this.getCurrentOrigin()}${this.config.callbackPath}`;
179
+ }
180
+ /**
181
+ * 构建登录跳转 URL
182
+ * @param returnPath 登录成功后返回的路径(默认当前页面)
183
+ */
184
+ buildLoginUrl(returnPath) {
185
+ const callbackUrl = this.buildCallbackUrl();
186
+ const loginUrl = new URL("/login", this.config.portalUrl);
187
+ loginUrl.searchParams.set("redirect", callbackUrl);
188
+ if (returnPath) {
189
+ loginUrl.searchParams.set("return", returnPath);
190
+ }
191
+ return loginUrl.toString();
192
+ }
193
+ /**
194
+ * 跳转到 Portal 登录页
195
+ * @param returnPath 登录成功后返回的路径
196
+ */
197
+ redirectToLogin(returnPath) {
198
+ if (typeof window === "undefined") return;
199
+ const currentPath = window.location.pathname + window.location.search;
200
+ const loginUrl = this.buildLoginUrl(returnPath || currentPath);
201
+ window.location.href = loginUrl;
202
+ }
203
+ /**
204
+ * 从 URL 参数中解析 Token
205
+ */
206
+ parseTokensFromUrl() {
207
+ if (typeof window === "undefined") return null;
208
+ const params = new URLSearchParams(window.location.search);
209
+ const accessToken = params.get("token");
210
+ const refreshToken = params.get("refresh");
211
+ const expiresInStr = params.get("expires");
212
+ const returnPath = params.get("return");
213
+ if (!accessToken || !refreshToken) {
214
+ return null;
215
+ }
216
+ return {
217
+ accessToken,
218
+ refreshToken,
219
+ expiresIn: expiresInStr ? parseInt(expiresInStr, 10) : 3600,
220
+ returnPath
221
+ };
222
+ }
223
+ /**
224
+ * 清除 URL 中的 Token 参数
225
+ */
226
+ clearTokensFromUrl() {
227
+ if (typeof window === "undefined") return;
228
+ const url = new URL(window.location.href);
229
+ url.searchParams.delete("token");
230
+ url.searchParams.delete("refresh");
231
+ url.searchParams.delete("expires");
232
+ url.searchParams.delete("return");
233
+ window.history.replaceState({}, "", url.pathname + url.search);
234
+ }
235
+ /**
236
+ * 验证跳转 URL 是否在白名单中
237
+ */
238
+ isAllowedRedirectUrl(url) {
239
+ try {
240
+ const { hostname } = new URL(url);
241
+ return ALLOWED_REDIRECT_DOMAINS.some(
242
+ (domain) => hostname === domain || hostname.endsWith("." + domain)
243
+ );
244
+ } catch {
245
+ return false;
246
+ }
247
+ }
248
+ };
249
+ var instance2 = null;
250
+ function getAuthRedirect(config) {
251
+ if (!instance2) {
252
+ instance2 = new AuthRedirect(config);
253
+ }
254
+ return instance2;
255
+ }
256
+ function resetAuthRedirect() {
257
+ instance2 = null;
258
+ }
259
+
260
+ // src/core/authkit-client.ts
261
+ var AuthKitClient = class {
262
+ constructor(config) {
263
+ this.config = {
264
+ baseUrl: config.baseUrl || DEFAULT_AUTH_CONFIG.apiBaseUrl,
265
+ getAccessToken: config.getAccessToken
266
+ };
267
+ }
268
+ /**
269
+ * 构建请求头
270
+ */
271
+ buildHeaders() {
272
+ const headers = {
273
+ "Content-Type": "application/json"
274
+ };
275
+ const token = this.config.getAccessToken();
276
+ if (token) {
277
+ headers["Authorization"] = `Bearer ${token}`;
278
+ }
279
+ return headers;
280
+ }
281
+ /**
282
+ * 解析 API 响应为标准格式
283
+ */
284
+ parseTokenResponse(data) {
285
+ if (data.access_token) {
286
+ const expiresAt = new Date(Date.now() + data.expires_in * 1e3).toISOString();
287
+ return {
288
+ token: data.access_token,
289
+ expires_at: expiresAt,
290
+ scopes: data.scopes
291
+ };
292
+ }
293
+ throw new Error("Invalid response format");
294
+ }
295
+ /**
296
+ * 获取当前用户信息
297
+ */
298
+ async getMe() {
299
+ const response = await fetch(`${this.config.baseUrl}/api/auth/me`, {
300
+ method: "GET",
301
+ headers: this.buildHeaders()
302
+ });
303
+ if (!response.ok) {
304
+ const error = await response.json().catch(() => ({}));
305
+ throw new Error(error.error || error.message || `HTTP ${response.status}`);
306
+ }
307
+ return await response.json();
308
+ }
309
+ /**
310
+ * 获取全局 Scoped Token(自动创建/续期)
311
+ *
312
+ * @param scope 权限范围,如 'streamock:stream:read'
313
+ * @returns 短 token,如 'st_7kB2xM9pQr3n'
314
+ */
315
+ async getScopedToken(scope) {
316
+ const response = await fetch(
317
+ `${this.config.baseUrl}/api/auth/token/scoped?scope=${encodeURIComponent(scope)}`,
318
+ {
319
+ method: "GET",
320
+ headers: this.buildHeaders()
321
+ }
322
+ );
323
+ if (!response.ok) {
324
+ const error = await response.json().catch(() => ({}));
325
+ throw new Error(error.error || error.message || `HTTP ${response.status}`);
326
+ }
327
+ const data = await response.json();
328
+ return this.parseTokenResponse(data);
329
+ }
330
+ /**
331
+ * 轮换 Scoped Token(废弃旧的,生成新的)
332
+ *
333
+ * @param scope 权限范围,如 'streamock:stream:read'
334
+ * @returns 新的短 token
335
+ */
336
+ async rotateScopedToken(scope) {
337
+ const response = await fetch(
338
+ `${this.config.baseUrl}/api/auth/token/scoped/rotate?scope=${encodeURIComponent(scope)}`,
339
+ {
340
+ method: "POST",
341
+ headers: this.buildHeaders()
342
+ }
343
+ );
344
+ if (!response.ok) {
345
+ const error = await response.json().catch(() => ({}));
346
+ throw new Error(error.error || error.message || `HTTP ${response.status}`);
347
+ }
348
+ const data = await response.json();
349
+ return this.parseTokenResponse(data);
350
+ }
351
+ /**
352
+ * 创建 Scoped Token(短 token)- 保留兼容性
353
+ *
354
+ * @param scopes 权限范围,如 ['streamock:stream:read']
355
+ * @param expiresIn 过期时间(秒),默认 24 小时
356
+ * @returns 短 token,如 'st_7kB2xM9pQr3n'
357
+ * @deprecated 请使用 getScopedToken 获取全局 token
358
+ */
359
+ async createScopedToken(scopes, expiresIn = 86400) {
360
+ const response = await fetch(`${this.config.baseUrl}/api/auth/token/scoped`, {
361
+ method: "POST",
362
+ headers: this.buildHeaders(),
363
+ body: JSON.stringify({
364
+ scopes,
365
+ expires_in: expiresIn
366
+ })
367
+ });
368
+ if (!response.ok) {
369
+ const error = await response.json().catch(() => ({}));
370
+ throw new Error(error.error || error.message || `HTTP ${response.status}`);
371
+ }
372
+ const data = await response.json();
373
+ return this.parseTokenResponse(data);
374
+ }
375
+ };
376
+ var instance3 = null;
377
+ function getAuthKitClient(getAccessToken) {
378
+ if (!instance3) {
379
+ instance3 = new AuthKitClient({ getAccessToken });
380
+ }
381
+ return instance3;
382
+ }
383
+ function resetAuthKitClient() {
384
+ instance3 = null;
385
+ }
386
+
387
+ // src/react/use-auth.ts
388
+ var import_react = require("react");
389
+ function useAuth(options = {}) {
390
+ const {
391
+ tokenManager = getTokenManager(options.config),
392
+ authRedirect = getAuthRedirect(options.config),
393
+ fetchUser = true
394
+ } = options;
395
+ const [authState, setAuthState] = (0, import_react.useState)({
396
+ isAuthenticated: false,
397
+ isLoading: true,
398
+ user: null,
399
+ error: null
400
+ });
401
+ const fetchUserInfo = (0, import_react.useCallback)(async () => {
402
+ try {
403
+ const client = getAuthKitClient(() => tokenManager.getAccessToken());
404
+ const user = await client.getMe();
405
+ setAuthState((prev) => ({
406
+ ...prev,
407
+ user,
408
+ error: null
409
+ }));
410
+ } catch (error) {
411
+ console.error("Failed to fetch user info:", error);
412
+ }
413
+ }, [tokenManager]);
414
+ const checkAuth = (0, import_react.useCallback)(async () => {
415
+ const hasValidAuth = tokenManager.hasValidAuth();
416
+ const accessToken = tokenManager.getAccessToken();
417
+ if (hasValidAuth && accessToken) {
418
+ setAuthState({
419
+ isAuthenticated: true,
420
+ isLoading: false,
421
+ user: null,
422
+ error: null
423
+ });
424
+ if (fetchUser) {
425
+ await fetchUserInfo();
426
+ }
427
+ } else {
428
+ setAuthState({
429
+ isAuthenticated: false,
430
+ isLoading: false,
431
+ user: null,
432
+ error: null
433
+ });
434
+ }
435
+ }, [tokenManager, fetchUser, fetchUserInfo]);
436
+ const login = (0, import_react.useCallback)(
437
+ (returnPath) => {
438
+ authRedirect.redirectToLogin(returnPath);
439
+ },
440
+ [authRedirect]
441
+ );
442
+ const logout = (0, import_react.useCallback)(() => {
443
+ tokenManager.clearTokens();
444
+ setAuthState({
445
+ isAuthenticated: false,
446
+ isLoading: false,
447
+ user: null,
448
+ error: null
449
+ });
450
+ }, [tokenManager]);
451
+ const getAccessToken = (0, import_react.useCallback)(() => {
452
+ return tokenManager.getAccessToken();
453
+ }, [tokenManager]);
454
+ const refresh = (0, import_react.useCallback)(() => {
455
+ checkAuth();
456
+ }, [checkAuth]);
457
+ const refreshUser = (0, import_react.useCallback)(async () => {
458
+ await fetchUserInfo();
459
+ }, [fetchUserInfo]);
460
+ (0, import_react.useEffect)(() => {
461
+ checkAuth();
462
+ }, [checkAuth]);
463
+ (0, import_react.useEffect)(() => {
464
+ const handleStorageChange = (event) => {
465
+ const config = tokenManager.getConfig();
466
+ if (event.key === config.tokenKeys.accessToken || event.key === config.tokenKeys.refreshToken) {
467
+ checkAuth();
468
+ }
469
+ };
470
+ window.addEventListener("storage", handleStorageChange);
471
+ return () => {
472
+ window.removeEventListener("storage", handleStorageChange);
473
+ };
474
+ }, [tokenManager, checkAuth]);
475
+ return (0, import_react.useMemo)(
476
+ () => ({
477
+ ...authState,
478
+ login,
479
+ logout,
480
+ getAccessToken,
481
+ refresh,
482
+ refreshUser
483
+ }),
484
+ [authState, login, logout, getAccessToken, refresh, refreshUser]
485
+ );
486
+ }
487
+ function useAccessToken() {
488
+ const { getAccessToken } = useAuth({ fetchUser: false });
489
+ return getAccessToken();
490
+ }
491
+
492
+ // src/react/auth-guard.tsx
493
+ var import_react2 = require("react");
494
+ var import_jsx_runtime = require("react/jsx-runtime");
495
+ function DefaultLoading() {
496
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: {
497
+ display: "flex",
498
+ height: "50vh",
499
+ width: "100%",
500
+ alignItems: "center",
501
+ justifyContent: "center"
502
+ }, children: [
503
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: {
504
+ width: "32px",
505
+ height: "32px",
506
+ border: "3px solid #e5e7eb",
507
+ borderTopColor: "#3b82f6",
508
+ borderRadius: "50%",
509
+ animation: "spin 1s linear infinite"
510
+ } }),
511
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: `
512
+ @keyframes spin {
513
+ to { transform: rotate(360deg); }
514
+ }
515
+ ` })
516
+ ] });
517
+ }
518
+ function DefaultLoginPrompt({
519
+ onLogin,
520
+ title = "\u9700\u8981\u767B\u5F55",
521
+ description = "\u8BF7\u767B\u5F55\u4EE5\u7EE7\u7EED\u4F7F\u7528",
522
+ buttonText = "\u767B\u5F55"
523
+ }) {
524
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: {
525
+ display: "flex",
526
+ height: "50vh",
527
+ width: "100%",
528
+ flexDirection: "column",
529
+ alignItems: "center",
530
+ justifyContent: "center",
531
+ gap: "16px"
532
+ }, children: [
533
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { textAlign: "center" }, children: [
534
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { style: {
535
+ fontSize: "1.5rem",
536
+ fontWeight: 600,
537
+ margin: 0
538
+ }, children: title }),
539
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: {
540
+ marginTop: "8px",
541
+ color: "#6b7280"
542
+ }, children: description })
543
+ ] }),
544
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
545
+ "button",
546
+ {
547
+ onClick: onLogin,
548
+ style: {
549
+ display: "inline-flex",
550
+ alignItems: "center",
551
+ justifyContent: "center",
552
+ padding: "10px 20px",
553
+ fontSize: "1rem",
554
+ fontWeight: 500,
555
+ backgroundColor: "#3b82f6",
556
+ color: "white",
557
+ border: "none",
558
+ borderRadius: "6px",
559
+ cursor: "pointer",
560
+ transition: "background-color 0.2s"
561
+ },
562
+ onMouseOver: (e) => e.currentTarget.style.backgroundColor = "#2563eb",
563
+ onMouseOut: (e) => e.currentTarget.style.backgroundColor = "#3b82f6",
564
+ children: buttonText
565
+ }
566
+ )
567
+ ] });
568
+ }
569
+ function AuthGuard({
570
+ children,
571
+ fallback = "prompt",
572
+ returnPath,
573
+ loadingContent,
574
+ promptContent,
575
+ promptTitle,
576
+ promptDescription,
577
+ loginButtonText,
578
+ authOptions
579
+ }) {
580
+ const { isAuthenticated, isLoading, login } = useAuth(authOptions);
581
+ (0, import_react2.useEffect)(() => {
582
+ if (!isLoading && !isAuthenticated && fallback === "redirect") {
583
+ login(returnPath);
584
+ }
585
+ }, [isLoading, isAuthenticated, fallback, login, returnPath]);
586
+ if (isLoading) {
587
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: loadingContent || /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DefaultLoading, {}) });
588
+ }
589
+ if (!isAuthenticated) {
590
+ if (fallback === "redirect") {
591
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: loadingContent || /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DefaultLoading, {}) });
592
+ }
593
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: promptContent || /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
594
+ DefaultLoginPrompt,
595
+ {
596
+ onLogin: () => login(returnPath),
597
+ title: promptTitle,
598
+ description: promptDescription,
599
+ buttonText: loginButtonText
600
+ }
601
+ ) });
602
+ }
603
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children });
604
+ }
605
+ function withAuthGuard(Component, guardProps) {
606
+ return function WrappedComponent(props) {
607
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AuthGuard, { ...guardProps, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Component, { ...props }) });
608
+ };
609
+ }
610
+
611
+ // src/react/callback-handler.tsx
612
+ var import_react3 = require("react");
613
+ var import_jsx_runtime2 = require("react/jsx-runtime");
614
+ function DefaultLoading2() {
615
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: {
616
+ display: "flex",
617
+ height: "100vh",
618
+ width: "100%",
619
+ alignItems: "center",
620
+ justifyContent: "center",
621
+ flexDirection: "column",
622
+ gap: "16px"
623
+ }, children: [
624
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: {
625
+ width: "40px",
626
+ height: "40px",
627
+ border: "3px solid #e5e7eb",
628
+ borderTopColor: "#3b82f6",
629
+ borderRadius: "50%",
630
+ animation: "spin 1s linear infinite"
631
+ } }),
632
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { style: { color: "#6b7280" }, children: "\u6B63\u5728\u5904\u7406\u767B\u5F55..." }),
633
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("style", { children: `
634
+ @keyframes spin {
635
+ to { transform: rotate(360deg); }
636
+ }
637
+ ` })
638
+ ] });
639
+ }
640
+ function DefaultError({ error, onRetry }) {
641
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: {
642
+ display: "flex",
643
+ height: "100vh",
644
+ width: "100%",
645
+ alignItems: "center",
646
+ justifyContent: "center",
647
+ flexDirection: "column",
648
+ gap: "16px"
649
+ }, children: [
650
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: {
651
+ color: "#ef4444",
652
+ fontSize: "48px"
653
+ }, children: "\u26A0\uFE0F" }),
654
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h2", { style: { margin: 0 }, children: "\u767B\u5F55\u5931\u8D25" }),
655
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { style: { color: "#6b7280", margin: 0 }, children: error }),
656
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
657
+ "button",
658
+ {
659
+ onClick: onRetry,
660
+ style: {
661
+ padding: "10px 20px",
662
+ fontSize: "1rem",
663
+ backgroundColor: "#3b82f6",
664
+ color: "white",
665
+ border: "none",
666
+ borderRadius: "6px",
667
+ cursor: "pointer"
668
+ },
669
+ children: "\u91CD\u8BD5"
670
+ }
671
+ )
672
+ ] });
673
+ }
674
+ function CallbackHandler({
675
+ defaultRedirectPath = "/",
676
+ loadingContent,
677
+ errorContent,
678
+ config,
679
+ onSuccess,
680
+ onError
681
+ }) {
682
+ const [error, setError] = (0, import_react3.useState)(null);
683
+ (0, import_react3.useEffect)(() => {
684
+ const handleCallback = () => {
685
+ const tokenManager = getTokenManager(config);
686
+ const authRedirect = getAuthRedirect(config);
687
+ const tokens = authRedirect.parseTokensFromUrl();
688
+ if (!tokens || !tokens.accessToken || !tokens.refreshToken) {
689
+ const errorMsg = "\u672A\u627E\u5230\u8BA4\u8BC1\u4FE1\u606F";
690
+ setError(errorMsg);
691
+ onError?.(errorMsg);
692
+ return;
693
+ }
694
+ tokenManager.setTokens(
695
+ tokens.accessToken,
696
+ tokens.refreshToken,
697
+ tokens.expiresIn || 3600
698
+ );
699
+ authRedirect.clearTokensFromUrl();
700
+ onSuccess?.();
701
+ const redirectPath = tokens.returnPath || defaultRedirectPath;
702
+ window.location.href = redirectPath;
703
+ };
704
+ handleCallback();
705
+ }, [defaultRedirectPath, config, onSuccess, onError]);
706
+ const handleRetry = () => {
707
+ const authRedirect = getAuthRedirect(config);
708
+ authRedirect.redirectToLogin(defaultRedirectPath);
709
+ };
710
+ if (error) {
711
+ if (typeof errorContent === "function") {
712
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children: errorContent(error) });
713
+ }
714
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children: errorContent || /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(DefaultError, { error, onRetry: handleRetry }) });
715
+ }
716
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children: loadingContent || /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(DefaultLoading2, {}) });
717
+ }
718
+ // Annotate the CommonJS export names for ESM import in node:
719
+ 0 && (module.exports = {
720
+ AuthGuard,
721
+ AuthKitClient,
722
+ AuthRedirect,
723
+ CallbackHandler,
724
+ DEFAULT_AUTH_CONFIG,
725
+ LocalStorageAdapter,
726
+ TokenManager,
727
+ getAuthKitClient,
728
+ getAuthRedirect,
729
+ getTokenManager,
730
+ resetAuthKitClient,
731
+ resetAuthRedirect,
732
+ resetTokenManager,
733
+ useAccessToken,
734
+ useAuth,
735
+ withAuthGuard
736
+ });
737
+ //# sourceMappingURL=index.js.map