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