@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 @@
1
+ {"version":3,"sources":["../src/core/types.ts","../src/core/token-manager.ts","../src/core/auth-redirect.ts","../src/core/authkit-client.ts","../src/react/use-auth.ts","../src/react/auth-guard.tsx","../src/react/callback-handler.tsx"],"sourcesContent":["/**\n * 认证相关类型定义\n */\n\n/**\n * 用户信息(来自 /api/auth/me)\n */\nexport interface User {\n id: string;\n email?: string;\n username?: string;\n display_name?: string;\n avatar_url?: string;\n is_active: boolean;\n email_verified: boolean;\n sync_enabled: boolean;\n}\n\n/**\n * Token 响应\n */\nexport interface TokenResponse {\n access_token: string;\n refresh_token: string;\n expires_in: number;\n token_type: string;\n}\n\n/**\n * 认证响应(登录/注册)\n */\nexport interface AuthResponse extends TokenResponse {\n user: User;\n}\n\n/**\n * Token 存储数据\n */\nexport interface StoredTokens {\n accessToken: string;\n refreshToken: string;\n expiresAt: number; // timestamp in ms\n}\n\n/**\n * 认证状态\n */\nexport interface AuthState {\n isAuthenticated: boolean;\n isLoading: boolean;\n user: User | null;\n error: string | null;\n}\n\n/**\n * Token 管理器接口(依赖注入)\n */\nexport interface ITokenManager {\n setTokens(accessToken: string, refreshToken: string, expiresIn: number): void;\n getAccessToken(): string | null;\n getRefreshToken(): string | null;\n isAccessTokenExpired(): boolean;\n clearTokens(): void;\n hasValidAuth(): boolean;\n}\n\n/**\n * 认证配置\n */\nexport interface AuthConfig {\n portalUrl: string;\n apiBaseUrl: string;\n callbackPath: string;\n tokenKeys: {\n accessToken: string;\n refreshToken: string;\n tokenExpiry: string;\n };\n}\n\n/**\n * 默认认证配置\n */\nexport const DEFAULT_AUTH_CONFIG: AuthConfig = {\n portalUrl: typeof process !== 'undefined' \n ? process.env.NEXT_PUBLIC_PORTAL_URL || 'https://yiminlab.site'\n : 'https://yiminlab.site',\n apiBaseUrl: typeof process !== 'undefined'\n ? process.env.NEXT_PUBLIC_API_BASE_URL || 'https://api.yiminlab.site'\n : 'https://api.yiminlab.site',\n callbackPath: '/auth/callback',\n tokenKeys: {\n accessToken: 'authkit_access_token',\n refreshToken: 'authkit_refresh_token',\n tokenExpiry: 'authkit_token_expiry',\n },\n};\n","/**\n * Token 管理器\n * 提供 token 的存储、获取、验证和清除功能\n * \n * 设计原则:\n * - 依赖注入:支持自定义 storage 和配置\n * - 与 Portal 共享相同的 localStorage key\n * - 支持 SSR(检查 window 对象)\n */\n\nimport type { ITokenManager, AuthConfig } from './types';\nimport { DEFAULT_AUTH_CONFIG } from './types';\n\n/**\n * Storage 接口(依赖注入)\n */\nexport interface IStorage {\n getItem(key: string): string | null;\n setItem(key: string, value: string): void;\n removeItem(key: string): void;\n}\n\n/**\n * 浏览器 localStorage 适配器\n */\nexport class LocalStorageAdapter implements IStorage {\n getItem(key: string): string | null {\n if (typeof window === 'undefined') return null;\n return localStorage.getItem(key);\n }\n\n setItem(key: string, value: string): void {\n if (typeof window === 'undefined') return;\n localStorage.setItem(key, value);\n }\n\n removeItem(key: string): void {\n if (typeof window === 'undefined') return;\n localStorage.removeItem(key);\n }\n}\n\n/**\n * Token 管理器实现\n */\nexport class TokenManager implements ITokenManager {\n private storage: IStorage;\n private config: AuthConfig;\n\n constructor(storage?: IStorage, config?: Partial<AuthConfig>) {\n this.storage = storage || new LocalStorageAdapter();\n this.config = { ...DEFAULT_AUTH_CONFIG, ...config };\n }\n\n /**\n * 保存 tokens\n */\n setTokens(accessToken: string, refreshToken: string, expiresIn: number): void {\n const expiryTime = Date.now() + expiresIn * 1000;\n\n this.storage.setItem(this.config.tokenKeys.accessToken, accessToken);\n this.storage.setItem(this.config.tokenKeys.refreshToken, refreshToken);\n this.storage.setItem(this.config.tokenKeys.tokenExpiry, expiryTime.toString());\n }\n\n /**\n * 获取 Access Token\n */\n getAccessToken(): string | null {\n return this.storage.getItem(this.config.tokenKeys.accessToken);\n }\n\n /**\n * 获取 Refresh Token\n */\n getRefreshToken(): string | null {\n return this.storage.getItem(this.config.tokenKeys.refreshToken);\n }\n\n /**\n * 获取 Token 过期时间\n */\n getTokenExpiry(): number | null {\n const expiry = this.storage.getItem(this.config.tokenKeys.tokenExpiry);\n return expiry ? parseInt(expiry, 10) : null;\n }\n\n /**\n * 检查 Access Token 是否过期\n * 提前 60 秒认为过期,留出刷新时间\n */\n isAccessTokenExpired(): boolean {\n const expiryTime = this.getTokenExpiry();\n if (!expiryTime) return true;\n\n const now = Date.now();\n // 提前 60 秒认为过期\n return now >= expiryTime - 60000;\n }\n\n /**\n * 清除所有 tokens\n */\n clearTokens(): void {\n this.storage.removeItem(this.config.tokenKeys.accessToken);\n this.storage.removeItem(this.config.tokenKeys.refreshToken);\n this.storage.removeItem(this.config.tokenKeys.tokenExpiry);\n }\n\n /**\n * 检查是否有有效的认证信息\n */\n hasValidAuth(): boolean {\n const accessToken = this.getAccessToken();\n const refreshToken = this.getRefreshToken();\n\n // 有 access token 且未过期,或有 refresh token 可以刷新\n return !!(accessToken && !this.isAccessTokenExpired()) || !!refreshToken;\n }\n\n /**\n * 获取配置\n */\n getConfig(): AuthConfig {\n return { ...this.config };\n }\n}\n\n// 单例实例\nlet instance: TokenManager | null = null;\n\n/**\n * 获取 TokenManager 单例\n */\nexport function getTokenManager(config?: Partial<AuthConfig>): TokenManager {\n if (!instance) {\n instance = new TokenManager(undefined, config);\n }\n return instance;\n}\n\n/**\n * 重置单例(用于测试)\n */\nexport function resetTokenManager(): void {\n instance = null;\n}\n","/**\n * 认证跳转工具\n * 处理跳转到 Portal 登录和回调处理\n */\n\nimport type { AuthConfig } from './types';\nimport { DEFAULT_AUTH_CONFIG } from './types';\n\n/**\n * 允许的跳转域名白名单\n */\nconst ALLOWED_REDIRECT_DOMAINS = [\n 'yiminlab.site',\n 'jsontailor.yiminlab.site',\n 'ai.yiminlab.site',\n 'localhost',\n];\n\n/**\n * 认证跳转配置\n */\nexport interface AuthRedirectConfig {\n portalUrl: string;\n callbackPath: string;\n}\n\n/**\n * 认证跳转工具类\n */\nexport class AuthRedirect {\n private config: AuthRedirectConfig;\n\n constructor(config?: Partial<AuthRedirectConfig>) {\n this.config = {\n portalUrl: config?.portalUrl || DEFAULT_AUTH_CONFIG.portalUrl,\n callbackPath: config?.callbackPath || DEFAULT_AUTH_CONFIG.callbackPath,\n };\n }\n\n /**\n * 获取当前页面的完整 URL\n */\n private getCurrentUrl(): string {\n if (typeof window === 'undefined') return '';\n return window.location.href;\n }\n\n /**\n * 获取当前页面的 origin\n */\n private getCurrentOrigin(): string {\n if (typeof window === 'undefined') return '';\n return window.location.origin;\n }\n\n /**\n * 构建回调 URL\n */\n private buildCallbackUrl(): string {\n return `${this.getCurrentOrigin()}${this.config.callbackPath}`;\n }\n\n /**\n * 构建登录跳转 URL\n * @param returnPath 登录成功后返回的路径(默认当前页面)\n */\n buildLoginUrl(returnPath?: string): string {\n const callbackUrl = this.buildCallbackUrl();\n const loginUrl = new URL('/login', this.config.portalUrl);\n\n // 设置回调 URL,Portal 登录成功后会跳转到这里\n loginUrl.searchParams.set('redirect', callbackUrl);\n // 设置最终返回路径,callback 页面处理完 token 后跳转到这里\n if (returnPath) {\n loginUrl.searchParams.set('return', returnPath);\n }\n\n return loginUrl.toString();\n }\n\n /**\n * 跳转到 Portal 登录页\n * @param returnPath 登录成功后返回的路径\n */\n redirectToLogin(returnPath?: string): void {\n if (typeof window === 'undefined') return;\n\n const currentPath = window.location.pathname + window.location.search;\n const loginUrl = this.buildLoginUrl(returnPath || currentPath);\n\n window.location.href = loginUrl;\n }\n\n /**\n * 从 URL 参数中解析 Token\n */\n parseTokensFromUrl(): {\n accessToken: string | null;\n refreshToken: string | null;\n expiresIn: number | null;\n returnPath: string | null;\n } | null {\n if (typeof window === 'undefined') return null;\n\n const params = new URLSearchParams(window.location.search);\n const accessToken = params.get('token');\n const refreshToken = params.get('refresh');\n const expiresInStr = params.get('expires');\n const returnPath = params.get('return');\n\n if (!accessToken || !refreshToken) {\n return null;\n }\n\n return {\n accessToken,\n refreshToken,\n expiresIn: expiresInStr ? parseInt(expiresInStr, 10) : 3600,\n returnPath,\n };\n }\n\n /**\n * 清除 URL 中的 Token 参数\n */\n clearTokensFromUrl(): void {\n if (typeof window === 'undefined') return;\n\n const url = new URL(window.location.href);\n url.searchParams.delete('token');\n url.searchParams.delete('refresh');\n url.searchParams.delete('expires');\n url.searchParams.delete('return');\n\n // 使用 replaceState 避免产生历史记录\n window.history.replaceState({}, '', url.pathname + url.search);\n }\n\n /**\n * 验证跳转 URL 是否在白名单中\n */\n isAllowedRedirectUrl(url: string): boolean {\n try {\n const { hostname } = new URL(url);\n return ALLOWED_REDIRECT_DOMAINS.some(\n (domain) => hostname === domain || hostname.endsWith('.' + domain)\n );\n } catch {\n return false;\n }\n }\n}\n\n// 单例实例\nlet instance: AuthRedirect | null = null;\n\n/**\n * 获取 AuthRedirect 单例\n */\nexport function getAuthRedirect(config?: Partial<AuthRedirectConfig>): AuthRedirect {\n if (!instance) {\n instance = new AuthRedirect(config);\n }\n return instance;\n}\n\n/**\n * 重置单例(用于测试)\n */\nexport function resetAuthRedirect(): void {\n instance = null;\n}\n","/**\n * AuthKit API 客户端\n * \n * 用于调用 AuthKit 服务的 API\n */\n\nimport { DEFAULT_AUTH_CONFIG, type User } from './types';\n\n/**\n * Scoped Token 请求\n */\nexport interface CreateScopedTokenRequest {\n scopes: string[];\n expires_in?: number; // 秒,默认 24 小时\n}\n\n/**\n * Scoped Token 响应(API 原始格式)\n */\ninterface ScopedTokenApiResponse {\n access_token: string;\n token_type: string;\n expires_in: number;\n scopes: string[];\n}\n\n/**\n * Scoped Token 响应(标准化格式)\n */\nexport interface ScopedTokenResponse {\n token: string;\n expires_at: string;\n scopes: string[];\n}\n\n/**\n * AuthKit 客户端配置\n */\nexport interface AuthKitClientConfig {\n baseUrl: string;\n getAccessToken: () => string | null;\n}\n\n/**\n * AuthKit API 客户端\n */\nexport class AuthKitClient {\n private config: AuthKitClientConfig;\n\n constructor(config: Partial<AuthKitClientConfig> & { getAccessToken: () => string | null }) {\n this.config = {\n baseUrl: config.baseUrl || DEFAULT_AUTH_CONFIG.apiBaseUrl,\n getAccessToken: config.getAccessToken,\n };\n }\n\n /**\n * 构建请求头\n */\n private buildHeaders(): HeadersInit {\n const headers: HeadersInit = {\n 'Content-Type': 'application/json',\n };\n\n const token = this.config.getAccessToken();\n if (token) {\n headers['Authorization'] = `Bearer ${token}`;\n }\n\n return headers;\n }\n\n /**\n * 解析 API 响应为标准格式\n */\n private parseTokenResponse(data: ScopedTokenApiResponse): ScopedTokenResponse {\n if (data.access_token) {\n const expiresAt = new Date(Date.now() + data.expires_in * 1000).toISOString();\n return {\n token: data.access_token,\n expires_at: expiresAt,\n scopes: data.scopes,\n };\n }\n throw new Error('Invalid response format');\n }\n\n /**\n * 获取当前用户信息\n */\n async getMe(): Promise<User> {\n const response = await fetch(`${this.config.baseUrl}/api/auth/me`, {\n method: 'GET',\n headers: this.buildHeaders(),\n });\n\n if (!response.ok) {\n const error = await response.json().catch(() => ({}));\n throw new Error(error.error || error.message || `HTTP ${response.status}`);\n }\n\n return await response.json() as User;\n }\n\n /**\n * 获取全局 Scoped Token(自动创建/续期)\n * \n * @param scope 权限范围,如 'streamock:stream:read'\n * @returns 短 token,如 'st_7kB2xM9pQr3n'\n */\n async getScopedToken(scope: string): Promise<ScopedTokenResponse> {\n const response = await fetch(\n `${this.config.baseUrl}/api/auth/token/scoped?scope=${encodeURIComponent(scope)}`,\n {\n method: 'GET',\n headers: this.buildHeaders(),\n }\n );\n\n if (!response.ok) {\n const error = await response.json().catch(() => ({}));\n throw new Error(error.error || error.message || `HTTP ${response.status}`);\n }\n\n const data = await response.json() as ScopedTokenApiResponse;\n return this.parseTokenResponse(data);\n }\n\n /**\n * 轮换 Scoped Token(废弃旧的,生成新的)\n * \n * @param scope 权限范围,如 'streamock:stream:read'\n * @returns 新的短 token\n */\n async rotateScopedToken(scope: string): Promise<ScopedTokenResponse> {\n const response = await fetch(\n `${this.config.baseUrl}/api/auth/token/scoped/rotate?scope=${encodeURIComponent(scope)}`,\n {\n method: 'POST',\n headers: this.buildHeaders(),\n }\n );\n\n if (!response.ok) {\n const error = await response.json().catch(() => ({}));\n throw new Error(error.error || error.message || `HTTP ${response.status}`);\n }\n\n const data = await response.json() as ScopedTokenApiResponse;\n return this.parseTokenResponse(data);\n }\n\n /**\n * 创建 Scoped Token(短 token)- 保留兼容性\n * \n * @param scopes 权限范围,如 ['streamock:stream:read']\n * @param expiresIn 过期时间(秒),默认 24 小时\n * @returns 短 token,如 'st_7kB2xM9pQr3n'\n * @deprecated 请使用 getScopedToken 获取全局 token\n */\n async createScopedToken(\n scopes: string[],\n expiresIn: number = 86400\n ): Promise<ScopedTokenResponse> {\n const response = await fetch(`${this.config.baseUrl}/api/auth/token/scoped`, {\n method: 'POST',\n headers: this.buildHeaders(),\n body: JSON.stringify({\n scopes,\n expires_in: expiresIn,\n }),\n });\n\n if (!response.ok) {\n const error = await response.json().catch(() => ({}));\n throw new Error(error.error || error.message || `HTTP ${response.status}`);\n }\n\n const data = await response.json() as ScopedTokenApiResponse;\n return this.parseTokenResponse(data);\n }\n}\n\n// 单例\nlet instance: AuthKitClient | null = null;\n\n/**\n * 获取 AuthKit 客户端单例\n */\nexport function getAuthKitClient(getAccessToken: () => string | null): AuthKitClient {\n if (!instance) {\n instance = new AuthKitClient({ getAccessToken });\n }\n return instance;\n}\n\n/**\n * 重置单例(用于测试)\n */\nexport function resetAuthKitClient(): void {\n instance = null;\n}\n","'use client';\n\n/**\n * 认证状态 Hook\n * \n * 提供认证状态管理和登录/登出功能\n */\n\nimport { useState, useEffect, useCallback, useMemo } from 'react';\nimport type { AuthState, User, AuthConfig } from '../core/types';\nimport { TokenManager, getTokenManager } from '../core/token-manager';\nimport { AuthRedirect, getAuthRedirect } from '../core/auth-redirect';\nimport { AuthKitClient, getAuthKitClient } from '../core/authkit-client';\n\n/**\n * Hook 配置\n */\nexport interface UseAuthOptions {\n tokenManager?: TokenManager;\n authRedirect?: AuthRedirect;\n config?: Partial<AuthConfig>;\n /**\n * 是否自动获取用户信息\n * @default true\n */\n fetchUser?: boolean;\n}\n\n/**\n * Hook 返回值\n */\nexport interface UseAuthReturn extends AuthState {\n /**\n * 登录(跳转到 Portal)\n */\n login: (returnPath?: string) => void;\n /**\n * 登出\n */\n logout: () => void;\n /**\n * 获取 access token\n */\n getAccessToken: () => string | null;\n /**\n * 刷新认证状态\n */\n refresh: () => void;\n /**\n * 刷新用户信息\n */\n refreshUser: () => Promise<void>;\n}\n\n/**\n * 认证状态 Hook\n */\nexport function useAuth(options: UseAuthOptions = {}): UseAuthReturn {\n const {\n tokenManager = getTokenManager(options.config),\n authRedirect = getAuthRedirect(options.config),\n fetchUser = true,\n } = options;\n\n const [authState, setAuthState] = useState<AuthState>({\n isAuthenticated: false,\n isLoading: true,\n user: null,\n error: null,\n });\n\n /**\n * 获取用户信息\n */\n const fetchUserInfo = useCallback(async () => {\n try {\n const client = getAuthKitClient(() => tokenManager.getAccessToken());\n const user = await client.getMe();\n setAuthState((prev) => ({\n ...prev,\n user,\n error: null,\n }));\n } catch (error) {\n console.error('Failed to fetch user info:', error);\n // 不改变认证状态,只是用户信息获取失败\n }\n }, [tokenManager]);\n\n /**\n * 检查认证状态\n */\n const checkAuth = useCallback(async () => {\n const hasValidAuth = tokenManager.hasValidAuth();\n const accessToken = tokenManager.getAccessToken();\n\n if (hasValidAuth && accessToken) {\n setAuthState({\n isAuthenticated: true,\n isLoading: false,\n user: null,\n error: null,\n });\n\n // 获取用户信息\n if (fetchUser) {\n await fetchUserInfo();\n }\n } else {\n setAuthState({\n isAuthenticated: false,\n isLoading: false,\n user: null,\n error: null,\n });\n }\n }, [tokenManager, fetchUser, fetchUserInfo]);\n\n /**\n * 登录(跳转到 Portal)\n */\n const login = useCallback(\n (returnPath?: string) => {\n authRedirect.redirectToLogin(returnPath);\n },\n [authRedirect]\n );\n\n /**\n * 登出\n */\n const logout = useCallback(() => {\n tokenManager.clearTokens();\n setAuthState({\n isAuthenticated: false,\n isLoading: false,\n user: null,\n error: null,\n });\n }, [tokenManager]);\n\n /**\n * 获取 access token\n */\n const getAccessToken = useCallback(() => {\n return tokenManager.getAccessToken();\n }, [tokenManager]);\n\n /**\n * 刷新认证状态\n */\n const refresh = useCallback(() => {\n checkAuth();\n }, [checkAuth]);\n\n /**\n * 刷新用户信息\n */\n const refreshUser = useCallback(async () => {\n await fetchUserInfo();\n }, [fetchUserInfo]);\n\n // 初始化时检查认证状态\n useEffect(() => {\n checkAuth();\n }, [checkAuth]);\n\n // 监听 storage 变化(跨标签页同步)\n useEffect(() => {\n const handleStorageChange = (event: StorageEvent) => {\n const config = tokenManager.getConfig();\n if (\n event.key === config.tokenKeys.accessToken ||\n event.key === config.tokenKeys.refreshToken\n ) {\n checkAuth();\n }\n };\n\n window.addEventListener('storage', handleStorageChange);\n return () => {\n window.removeEventListener('storage', handleStorageChange);\n };\n }, [tokenManager, checkAuth]);\n\n return useMemo(\n () => ({\n ...authState,\n login,\n logout,\n getAccessToken,\n refresh,\n refreshUser,\n }),\n [authState, login, logout, getAccessToken, refresh, refreshUser]\n );\n}\n\n/**\n * 简化版 Hook:只获取 token\n */\nexport function useAccessToken(): string | null {\n const { getAccessToken } = useAuth({ fetchUser: false });\n return getAccessToken();\n}\n","'use client';\n\n/**\n * 认证守卫组件\n * \n * 包装需要认证的页面,未登录时显示登录提示或自动跳转\n */\n\nimport { useEffect, type ReactNode } from 'react';\nimport { useAuth, type UseAuthOptions } from './use-auth';\n\nexport interface AuthGuardProps {\n children: ReactNode;\n /**\n * 未登录时的行为\n * - 'redirect': 自动跳转到登录页\n * - 'prompt': 显示登录提示\n * @default 'prompt'\n */\n fallback?: 'redirect' | 'prompt';\n /**\n * 登录后返回的路径\n */\n returnPath?: string;\n /**\n * 加载中显示的内容\n */\n loadingContent?: ReactNode;\n /**\n * 未登录提示内容\n */\n promptContent?: ReactNode;\n /**\n * 提示标题\n */\n promptTitle?: string;\n /**\n * 提示描述\n */\n promptDescription?: string;\n /**\n * 登录按钮文字\n */\n loginButtonText?: string;\n /**\n * useAuth 配置\n */\n authOptions?: UseAuthOptions;\n}\n\n/**\n * 默认加载中组件\n */\nfunction DefaultLoading() {\n return (\n <div style={{ \n display: 'flex', \n height: '50vh', \n width: '100%', \n alignItems: 'center', \n justifyContent: 'center' \n }}>\n <div style={{ \n width: '32px', \n height: '32px', \n border: '3px solid #e5e7eb',\n borderTopColor: '#3b82f6',\n borderRadius: '50%',\n animation: 'spin 1s linear infinite',\n }} />\n <style>{`\n @keyframes spin {\n to { transform: rotate(360deg); }\n }\n `}</style>\n </div>\n );\n}\n\n/**\n * 默认登录提示组件\n */\nfunction DefaultLoginPrompt({ \n onLogin, \n title = '需要登录',\n description = '请登录以继续使用',\n buttonText = '登录',\n}: { \n onLogin: () => void;\n title?: string;\n description?: string;\n buttonText?: string;\n}) {\n return (\n <div style={{ \n display: 'flex', \n height: '50vh', \n width: '100%', \n flexDirection: 'column',\n alignItems: 'center', \n justifyContent: 'center',\n gap: '16px',\n }}>\n <div style={{ textAlign: 'center' }}>\n <h2 style={{ \n fontSize: '1.5rem', \n fontWeight: 600, \n margin: 0,\n }}>{title}</h2>\n <p style={{ \n marginTop: '8px',\n color: '#6b7280',\n }}>{description}</p>\n </div>\n <button \n onClick={onLogin} \n style={{\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n padding: '10px 20px',\n fontSize: '1rem',\n fontWeight: 500,\n backgroundColor: '#3b82f6',\n color: 'white',\n border: 'none',\n borderRadius: '6px',\n cursor: 'pointer',\n transition: 'background-color 0.2s',\n }}\n onMouseOver={(e) => e.currentTarget.style.backgroundColor = '#2563eb'}\n onMouseOut={(e) => e.currentTarget.style.backgroundColor = '#3b82f6'}\n >\n {buttonText}\n </button>\n </div>\n );\n}\n\n/**\n * 认证守卫组件\n */\nexport function AuthGuard({\n children,\n fallback = 'prompt',\n returnPath,\n loadingContent,\n promptContent,\n promptTitle,\n promptDescription,\n loginButtonText,\n authOptions,\n}: AuthGuardProps) {\n const { isAuthenticated, isLoading, login } = useAuth(authOptions);\n\n // 自动跳转模式\n useEffect(() => {\n if (!isLoading && !isAuthenticated && fallback === 'redirect') {\n login(returnPath);\n }\n }, [isLoading, isAuthenticated, fallback, login, returnPath]);\n\n // 加载中\n if (isLoading) {\n return <>{loadingContent || <DefaultLoading />}</>;\n }\n\n // 未登录\n if (!isAuthenticated) {\n if (fallback === 'redirect') {\n // 正在跳转中,显示加载状态\n return <>{loadingContent || <DefaultLoading />}</>;\n }\n // 显示登录提示\n return (\n <>\n {promptContent || (\n <DefaultLoginPrompt \n onLogin={() => login(returnPath)} \n title={promptTitle}\n description={promptDescription}\n buttonText={loginButtonText}\n />\n )}\n </>\n );\n }\n\n // 已登录,渲染子组件\n return <>{children}</>;\n}\n\n/**\n * HOC 版本:withAuthGuard\n */\nexport function withAuthGuard<P extends object>(\n Component: React.ComponentType<P>,\n guardProps?: Omit<AuthGuardProps, 'children'>\n) {\n return function WrappedComponent(props: P) {\n return (\n <AuthGuard {...guardProps}>\n <Component {...props} />\n </AuthGuard>\n );\n };\n}\n","'use client';\n\n/**\n * 认证回调处理组件\n * \n * 处理从 Portal 登录后的回调,解析 token 并存储\n */\n\nimport { useEffect, useState, type ReactNode } from 'react';\nimport { getTokenManager } from '../core/token-manager';\nimport { getAuthRedirect } from '../core/auth-redirect';\nimport type { AuthConfig } from '../core/types';\n\nexport interface CallbackHandlerProps {\n /**\n * 默认跳转路径(如果 URL 中没有 return 参数)\n * @default '/'\n */\n defaultRedirectPath?: string;\n /**\n * 处理中显示的内容\n */\n loadingContent?: ReactNode;\n /**\n * 错误时显示的内容\n */\n errorContent?: ReactNode | ((error: string) => ReactNode);\n /**\n * 认证配置\n */\n config?: Partial<AuthConfig>;\n /**\n * 成功后的回调\n */\n onSuccess?: () => void;\n /**\n * 失败后的回调\n */\n onError?: (error: string) => void;\n}\n\n/**\n * 默认加载中组件\n */\nfunction DefaultLoading() {\n return (\n <div style={{ \n display: 'flex', \n height: '100vh', \n width: '100%', \n alignItems: 'center', \n justifyContent: 'center',\n flexDirection: 'column',\n gap: '16px',\n }}>\n <div style={{ \n width: '40px', \n height: '40px', \n border: '3px solid #e5e7eb',\n borderTopColor: '#3b82f6',\n borderRadius: '50%',\n animation: 'spin 1s linear infinite',\n }} />\n <p style={{ color: '#6b7280' }}>正在处理登录...</p>\n <style>{`\n @keyframes spin {\n to { transform: rotate(360deg); }\n }\n `}</style>\n </div>\n );\n}\n\n/**\n * 默认错误组件\n */\nfunction DefaultError({ error, onRetry }: { error: string; onRetry: () => void }) {\n return (\n <div style={{ \n display: 'flex', \n height: '100vh', \n width: '100%', \n alignItems: 'center', \n justifyContent: 'center',\n flexDirection: 'column',\n gap: '16px',\n }}>\n <div style={{ \n color: '#ef4444',\n fontSize: '48px',\n }}>⚠️</div>\n <h2 style={{ margin: 0 }}>登录失败</h2>\n <p style={{ color: '#6b7280', margin: 0 }}>{error}</p>\n <button \n onClick={onRetry}\n style={{\n padding: '10px 20px',\n fontSize: '1rem',\n backgroundColor: '#3b82f6',\n color: 'white',\n border: 'none',\n borderRadius: '6px',\n cursor: 'pointer',\n }}\n >\n 重试\n </button>\n </div>\n );\n}\n\n/**\n * 认证回调处理组件\n */\nexport function CallbackHandler({\n defaultRedirectPath = '/',\n loadingContent,\n errorContent,\n config,\n onSuccess,\n onError,\n}: CallbackHandlerProps) {\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n const handleCallback = () => {\n const tokenManager = getTokenManager(config);\n const authRedirect = getAuthRedirect(config);\n\n // 解析 URL 中的 token\n const tokens = authRedirect.parseTokensFromUrl();\n\n if (!tokens || !tokens.accessToken || !tokens.refreshToken) {\n const errorMsg = '未找到认证信息';\n setError(errorMsg);\n onError?.(errorMsg);\n return;\n }\n\n // 存储 tokens\n tokenManager.setTokens(\n tokens.accessToken,\n tokens.refreshToken,\n tokens.expiresIn || 3600\n );\n\n // 清除 URL 中的敏感参数\n authRedirect.clearTokensFromUrl();\n\n // 触发成功回调\n onSuccess?.();\n\n // 跳转到目标页面\n const redirectPath = tokens.returnPath || defaultRedirectPath;\n window.location.href = redirectPath;\n };\n\n handleCallback();\n }, [defaultRedirectPath, config, onSuccess, onError]);\n\n const handleRetry = () => {\n const authRedirect = getAuthRedirect(config);\n authRedirect.redirectToLogin(defaultRedirectPath);\n };\n\n if (error) {\n if (typeof errorContent === 'function') {\n return <>{errorContent(error)}</>;\n }\n return <>{errorContent || <DefaultError error={error} onRetry={handleRetry} />}</>;\n }\n\n return <>{loadingContent || <DefaultLoading />}</>;\n}\n"],"mappings":"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","names":["instance","instance","useEffect","useEffect","useEffect","useState","Fragment","jsx","jsxs","DefaultLoading","useState","useEffect"]}
@@ -0,0 +1,3 @@
1
+ export { m as AuthGuard, n as AuthGuardProps, C as CallbackHandler, o as CallbackHandlerProps, k as UseAuthOptions, l as UseAuthReturn, j as useAccessToken, u as useAuth, w as withAuthGuard } from '../index-jde0aIND.mjs';
2
+ import 'react/jsx-runtime';
3
+ import 'react';
@@ -0,0 +1,3 @@
1
+ export { m as AuthGuard, n as AuthGuardProps, C as CallbackHandler, o as CallbackHandlerProps, k as UseAuthOptions, l as UseAuthReturn, j as useAccessToken, u as useAuth, w as withAuthGuard } from '../index-jde0aIND.js';
2
+ import 'react/jsx-runtime';
3
+ import 'react';