openxiangda 1.0.84 → 1.0.85

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/runtime/react/openxiangdaProvider.tsx","../../src/runtime/core/fetch.ts"],"sourcesContent":["import React, {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useState,\n} from \"react\"\nimport { createBoundFetch } from \"../core/fetch\"\n\nexport type RuntimeErrorType =\n | \"unauthenticated\"\n | \"forbidden\"\n | \"network\"\n | \"unknown\"\n\nexport type RuntimeRequestError = Error & {\n type?: RuntimeErrorType\n status?: number\n code?: number | string\n payload?: unknown\n}\n\nexport interface RuntimeErrorSnapshot {\n type: RuntimeErrorType\n status?: number\n code?: number | string\n message: string\n payload?: unknown\n}\n\nexport class RuntimeHttpError extends Error {\n type: RuntimeErrorType\n status?: number\n code?: number | string\n payload?: unknown\n\n constructor(snapshot: RuntimeErrorSnapshot) {\n super(snapshot.message)\n this.name = \"RuntimeHttpError\"\n this.type = snapshot.type\n this.status = snapshot.status\n this.code = snapshot.code\n this.payload = snapshot.payload\n }\n}\n\nexport interface RuntimeMenuItem {\n id: string\n name: string\n resourceCode?: string | null\n routeCode?: string | null\n path?: string | null\n type?: string\n formUuid?: string | null\n pageId?: string | null\n parentId?: string | null\n sortOrder?: number\n isHidden?: boolean\n icon?: string | null\n children?: RuntimeMenuItem[]\n [key: string]: unknown\n}\n\nexport interface RuntimePagePermissions {\n appType: string\n hasFullAccess: boolean\n roleCodes: string[]\n roleSource?: string\n menuFormUuids: string[]\n menuCodes: string[]\n routeCodes: string[]\n pathPatterns: string[]\n}\n\nexport interface RuntimeBootstrap {\n appType: string\n app?: Record<string, unknown> | null\n user?: Record<string, unknown> | null\n runtime?: {\n mode?: \"legacy\" | \"react-spa\" | string\n settings?: Record<string, unknown>\n activeReleaseId?: string | null\n activeBuildId?: string | null\n indexUrl?: string | null\n assetBaseUrl?: string | null\n }\n permissions?: RuntimePagePermissions\n menus?: RuntimeMenuItem[]\n servicePrefix?: string\n}\n\nexport interface RouteAccessResult {\n appType: string\n canAccess: boolean\n routeCode?: string\n menuCode?: string\n path?: string\n status?: number\n code?: number | string\n message?: string\n errorType?: RuntimeErrorType\n payload?: unknown\n permissions?: RuntimePagePermissions\n}\n\nexport interface RuntimeRequestState<T> {\n data: T | null\n loading: boolean\n error: RuntimeRequestError | null\n}\n\nexport interface OpenXiangdaProviderProps {\n appType?: string\n servicePrefix?: string\n fetchImpl?: typeof fetch\n children: React.ReactNode\n}\n\ninterface OpenXiangdaRuntimeStore extends RuntimeRequestState<RuntimeBootstrap> {\n appType: string\n servicePrefix: string\n fetchImpl: typeof fetch\n reload: () => Promise<void>\n}\n\nconst OpenXiangdaRuntimeContext =\n createContext<OpenXiangdaRuntimeStore | null>(null)\n\nexport const OpenXiangdaProvider: React.FC<OpenXiangdaProviderProps> = ({\n appType,\n servicePrefix = \"/service\",\n fetchImpl,\n children,\n}) => {\n const resolvedFetch = useMemo(() => createBoundFetch(fetchImpl), [fetchImpl])\n const resolvedAppType = useMemo(\n () => appType || resolveAppTypeFromLocation(),\n [appType],\n )\n const [state, setState] = useState<RuntimeRequestState<RuntimeBootstrap>>({\n data: null,\n loading: true,\n error: null,\n })\n\n const reload = useCallback(async () => {\n if (!resolvedAppType) {\n setState({\n data: null,\n loading: false,\n error: createRuntimeError({\n message: \"appType 不能为空\",\n type: \"unknown\",\n }),\n })\n return\n }\n setState(prev => ({ ...prev, loading: true, error: null }))\n try {\n const response = await resolvedFetch(\n buildServiceUrl(\n servicePrefix,\n `/openxiangda-api/v1/apps/${encodeURIComponent(\n resolvedAppType,\n )}/runtime/bootstrap`,\n ),\n {\n credentials: \"include\",\n headers: { accept: \"application/json\" },\n },\n )\n const payload = await readJsonPayload(response)\n if (!response.ok || payload?.code >= 400) {\n throw createRuntimeHttpError(\n response,\n payload,\n payload?.message || `Runtime bootstrap failed: ${response.status}`,\n )\n }\n setState({\n data: payload?.data || null,\n loading: false,\n error: null,\n })\n } catch (error) {\n setState({\n data: null,\n loading: false,\n error: normalizeRuntimeError(error),\n })\n }\n }, [resolvedAppType, resolvedFetch, servicePrefix])\n\n useEffect(() => {\n void reload()\n }, [reload])\n\n const value = useMemo<OpenXiangdaRuntimeStore>(\n () => ({\n ...state,\n appType: resolvedAppType,\n servicePrefix,\n fetchImpl: resolvedFetch,\n reload,\n }),\n [reload, resolvedAppType, resolvedFetch, servicePrefix, state],\n )\n\n return (\n <OpenXiangdaRuntimeContext.Provider value={value}>\n {children}\n </OpenXiangdaRuntimeContext.Provider>\n )\n}\n\nexport const useOpenXiangda = () => {\n const context = useContext(OpenXiangdaRuntimeContext)\n if (!context) {\n throw new Error(\"useOpenXiangda must be used inside OpenXiangdaProvider\")\n }\n return context\n}\n\nexport const useRuntimeBootstrap = () => useOpenXiangda()\n\nexport const useAppMenus = () => {\n const runtime = useOpenXiangda()\n return {\n ...runtime,\n data: runtime.data?.menus || [],\n }\n}\n\nexport const usePermission = () => {\n const runtime = useOpenXiangda()\n return {\n ...runtime,\n data: runtime.data?.permissions || null,\n }\n}\n\nexport interface UseCanAccessRouteInput {\n routeCode?: string\n menuCode?: string\n path?: string\n}\n\nexport const useCanAccessRoute = (input: UseCanAccessRouteInput) => {\n const runtime = useOpenXiangda()\n const [state, setState] = useState<RuntimeRequestState<RouteAccessResult>>({\n data: null,\n loading: true,\n error: null,\n })\n\n useEffect(() => {\n let disposed = false\n const check = async () => {\n const permissions = runtime.data?.permissions\n if (!runtime.appType || runtime.loading) {\n setState(prev => ({ ...prev, loading: runtime.loading }))\n return\n }\n if (runtime.error && !runtime.data) {\n const snapshot = toRuntimeErrorSnapshot(runtime.error)\n setState({\n data: {\n appType: runtime.appType,\n canAccess: false,\n status: snapshot.status,\n code: snapshot.code,\n message: snapshot.message,\n errorType: snapshot.type,\n payload: snapshot.payload,\n },\n loading: false,\n error: runtime.error,\n })\n return\n }\n if (permissions?.hasFullAccess) {\n setState({\n data: { appType: runtime.appType, canAccess: true, permissions },\n loading: false,\n error: null,\n })\n return\n }\n setState(prev => ({ ...prev, loading: true, error: null }))\n try {\n const response = await runtime.fetchImpl(\n buildServiceUrl(\n runtime.servicePrefix,\n `/openxiangda-api/v1/apps/${encodeURIComponent(\n runtime.appType,\n )}/runtime/routes/check`,\n ),\n {\n method: \"POST\",\n credentials: \"include\",\n headers: {\n accept: \"application/json\",\n \"content-type\": \"application/json\",\n },\n body: JSON.stringify(input),\n },\n )\n const payload = await readJsonPayload(response)\n const code = payload?.code ?? response.status\n const canAccess = Boolean(payload?.data?.canAccess)\n const errorType = canAccess\n ? undefined\n : classifyRuntimeError(response.status, code)\n const data: RouteAccessResult = {\n ...(payload?.data || {\n appType: runtime.appType,\n canAccess: false,\n }),\n appType: payload?.data?.appType || runtime.appType,\n canAccess,\n status: response.status,\n code,\n message: payload?.message,\n errorType,\n payload,\n }\n if (!disposed) {\n const shouldTreatAsError =\n !response.ok || (typeof code === \"number\" && code >= 500)\n setState({\n data,\n loading: false,\n error: shouldTreatAsError\n ? createRuntimeHttpError(\n response,\n payload,\n payload?.message || `Route check failed: ${response.status}`,\n )\n : null,\n })\n }\n } catch (error) {\n if (!disposed) {\n setState({\n data: null,\n loading: false,\n error: normalizeRuntimeError(error),\n })\n }\n }\n }\n void check()\n return () => {\n disposed = true\n }\n }, [\n input.menuCode,\n input.path,\n input.routeCode,\n runtime.appType,\n runtime.data?.permissions,\n runtime.fetchImpl,\n runtime.loading,\n runtime.servicePrefix,\n ])\n\n return {\n ...state,\n canAccess: Boolean(state.data?.canAccess),\n }\n}\n\nexport interface PermissionBoundaryProps extends UseCanAccessRouteInput {\n children: React.ReactNode\n fallback?: React.ReactNode | PermissionBoundaryFallback\n loadingFallback?: React.ReactNode | PermissionBoundaryFallback\n}\n\nexport interface PermissionBoundaryFallbackState {\n access: ReturnType<typeof useCanAccessRoute>\n runtime: ReturnType<typeof useOpenXiangda>\n error: RuntimeRequestError | null\n errorType: RuntimeErrorType\n status?: number\n code?: number | string\n message: string\n}\n\nexport type PermissionBoundaryFallback = (\n state: PermissionBoundaryFallbackState,\n) => React.ReactNode\n\nexport const PermissionBoundary: React.FC<PermissionBoundaryProps> = ({\n children,\n fallback = null,\n loadingFallback = null,\n routeCode,\n menuCode,\n path,\n}) => {\n const runtime = useOpenXiangda()\n const access = useCanAccessRoute({ routeCode, menuCode, path })\n const fallbackState = createPermissionFallbackState(access, runtime)\n if (access.loading) {\n return <>{renderBoundaryFallback(loadingFallback, fallbackState)}</>\n }\n if (!access.canAccess) {\n return <>{renderBoundaryFallback(fallback, fallbackState)}</>\n }\n return <>{children}</>\n}\n\nexport interface RuntimeResolveLoginOptions {\n redirectUri?: string\n loginUrl?: string\n domain?: string\n}\n\nexport interface RuntimeRedirectLoginOptions extends RuntimeResolveLoginOptions {\n replace?: boolean\n}\n\nexport interface RuntimeLogoutOptions extends RuntimeRedirectLoginOptions {\n continueOnError?: boolean\n}\n\nexport const useRuntimeAuth = () => {\n const runtime = useOpenXiangda()\n\n const resolveLoginUrl = useCallback(\n async (options: RuntimeResolveLoginOptions = {}) => {\n const redirectUri = options.redirectUri || getCurrentHref()\n const domain = options.domain || getCurrentHostname()\n const appTenantId = getRecordString(runtime.data?.app, \"tenantId\")\n\n try {\n const statusUrl = withQuery(\n buildServiceUrl(runtime.servicePrefix, \"/api/sso/status\"),\n { domain },\n )\n const statusResponse = await runtime.fetchImpl(statusUrl, {\n credentials: \"include\",\n headers: { accept: \"application/json\" },\n })\n const statusPayload = await readJsonPayload(statusResponse)\n const sso = statusPayload?.data || {}\n const enabled = Boolean(sso.enabled)\n const shouldUseSso = Boolean(\n enabled && (sso.forceLogin ?? sso.autoRedirect ?? true),\n )\n if (shouldUseSso) {\n const loginUrlResponse = await runtime.fetchImpl(\n withQuery(buildServiceUrl(runtime.servicePrefix, \"/api/sso/login-url\"), {\n domain,\n redirectUri,\n ...(sso.tenantId || appTenantId\n ? { tenantId: String(sso.tenantId || appTenantId) }\n : {}),\n ...(sso.protocol ? { protocol: String(sso.protocol) } : {}),\n }),\n {\n credentials: \"include\",\n headers: { accept: \"application/json\" },\n },\n )\n const loginUrlPayload = await readJsonPayload(loginUrlResponse)\n const loginUrl =\n loginUrlPayload?.data?.loginUrl ||\n loginUrlPayload?.data?.url ||\n loginUrlPayload?.loginUrl ||\n loginUrlPayload?.url\n if (loginUrl) return String(loginUrl)\n }\n } catch {\n // Login resolution must always have a local fallback so logged-out\n // users are not stranded behind a permission state.\n }\n\n const configuredLoginUrl =\n options.loginUrl ||\n getRuntimeEnv(\"OPENXIANGDA_LOGIN_URL\") ||\n getRuntimeEnv(\"VITE_OPENXIANGDA_LOGIN_URL\") ||\n getRuntimeEnv(\"APP_LOGIN_URL\") ||\n getRuntimeEnv(\"VITE_APP_LOGIN_URL\") ||\n getRuntimeEnv(\"VITE_BATH_AUTH_URL\") ||\n getRuntimeEnv(\"BATH_AUTH_URL\")\n if (configuredLoginUrl) {\n return attachCallback(configuredLoginUrl, redirectUri)\n }\n return attachCallback(\"/platform/login\", redirectUri)\n },\n [runtime.data?.app, runtime.fetchImpl, runtime.servicePrefix],\n )\n\n const redirectToLogin = useCallback(\n async (options: RuntimeRedirectLoginOptions = {}) => {\n const loginUrl = await resolveLoginUrl(options)\n if (typeof window !== \"undefined\") {\n if (options.replace === false) {\n window.location.assign(loginUrl)\n } else {\n window.location.replace(loginUrl)\n }\n }\n return loginUrl\n },\n [resolveLoginUrl],\n )\n\n const logout = useCallback(async () => {\n const response = await runtime.fetchImpl(\n buildServiceUrl(runtime.servicePrefix, \"/api/auth/logout\"),\n {\n method: \"POST\",\n credentials: \"include\",\n headers: { accept: \"application/json\" },\n },\n )\n const payload = await readJsonPayload(response)\n if (!response.ok || payload?.code >= 400) {\n throw createRuntimeHttpError(\n response,\n payload,\n payload?.message || `Logout failed: ${response.status}`,\n )\n }\n return payload\n }, [runtime.fetchImpl, runtime.servicePrefix])\n\n const logoutAndRedirect = useCallback(\n async (options: RuntimeLogoutOptions = {}) => {\n try {\n await logout()\n } catch (error) {\n if (options.continueOnError === false) throw error\n }\n return redirectToLogin(options)\n },\n [logout, redirectToLogin],\n )\n\n return {\n logout,\n logoutAndRedirect,\n redirectToLogin,\n resolveLoginUrl,\n }\n}\n\nconst buildServiceUrl = (servicePrefix: string, path: string) => {\n const prefix = servicePrefix.endsWith(\"/\")\n ? servicePrefix.slice(0, -1)\n : servicePrefix\n const suffix = path.startsWith(\"/\") ? path : `/${path}`\n return `${prefix}${suffix}`\n}\n\nconst readJsonPayload = async (response: Response) => {\n try {\n return await response.json()\n } catch {\n return null\n }\n}\n\nconst createRuntimeHttpError = (\n response: Response,\n payload: unknown,\n fallbackMessage: string,\n): RuntimeRequestError =>\n createRuntimeError({\n type: classifyRuntimeError(\n response.status,\n getRecordValue(payload, \"code\") as number | string | undefined,\n ),\n status: response.status,\n code: getRecordValue(payload, \"code\") as number | string | undefined,\n message:\n (getRecordValue(payload, \"message\") as string | undefined) ||\n fallbackMessage,\n payload,\n })\n\nconst createRuntimeError = (\n snapshot: RuntimeErrorSnapshot,\n): RuntimeRequestError =>\n new RuntimeHttpError({\n ...snapshot,\n type: snapshot.type || \"unknown\",\n message: snapshot.message || \"Runtime request failed\",\n })\n\nconst normalizeRuntimeError = (error: unknown): RuntimeRequestError => {\n if (error instanceof RuntimeHttpError) return error\n if (error instanceof Error) {\n const runtimeError = error as RuntimeRequestError\n runtimeError.type = runtimeError.type || classifyRuntimeError(runtimeError.status, runtimeError.code)\n return runtimeError\n }\n return createRuntimeError({\n type: \"unknown\",\n message: String(error),\n })\n}\n\nconst toRuntimeErrorSnapshot = (\n error: RuntimeRequestError,\n): RuntimeErrorSnapshot => ({\n type: error.type || classifyRuntimeError(error.status, error.code),\n status: error.status,\n code: error.code,\n message: error.message || \"Runtime request failed\",\n payload: error.payload,\n})\n\nconst classifyRuntimeError = (\n status?: number,\n code?: number | string,\n): RuntimeErrorType => {\n const normalizedCode = typeof code === \"string\" ? Number(code) : code\n if (status === 401 || normalizedCode === 401) return \"unauthenticated\"\n if (status === 403 || normalizedCode === 403) return \"forbidden\"\n if (!status && !normalizedCode) return \"network\"\n return \"unknown\"\n}\n\nconst createPermissionFallbackState = (\n access: ReturnType<typeof useCanAccessRoute>,\n runtime: ReturnType<typeof useOpenXiangda>,\n): PermissionBoundaryFallbackState => {\n const error = access.error || runtime.error\n const accessData = access.data\n const errorType =\n accessData?.errorType ||\n error?.type ||\n (!access.canAccess ? \"forbidden\" : \"unknown\")\n return {\n access,\n runtime,\n error,\n errorType,\n status: accessData?.status || error?.status,\n code: accessData?.code || error?.code,\n message:\n accessData?.message ||\n error?.message ||\n (errorType === \"unauthenticated\"\n ? \"当前账号尚未登录\"\n : \"当前账号没有访问权限\"),\n }\n}\n\nconst renderBoundaryFallback = (\n fallback: React.ReactNode | PermissionBoundaryFallback,\n state: PermissionBoundaryFallbackState,\n) => (typeof fallback === \"function\" ? fallback(state) : fallback)\n\nconst withQuery = (\n url: string,\n params: Record<string, string | number | boolean | undefined>,\n) => {\n const query = new URLSearchParams()\n Object.entries(params).forEach(([key, value]) => {\n if (value === undefined || value === \"\") return\n query.set(key, String(value))\n })\n const serialized = query.toString()\n if (!serialized) return url\n return `${url}${url.includes(\"?\") ? \"&\" : \"?\"}${serialized}`\n}\n\nconst attachCallback = (loginUrl: string, callback: string) => {\n if (!callback) return loginUrl\n try {\n const base =\n typeof window !== \"undefined\" ? window.location.origin : \"http://localhost\"\n const parsed = new URL(loginUrl, base)\n if (!parsed.searchParams.has(\"callback\") && !parsed.searchParams.has(\"redirectUri\")) {\n parsed.searchParams.set(\"callback\", callback)\n }\n if (loginUrl.startsWith(\"http://\") || loginUrl.startsWith(\"https://\")) {\n return parsed.toString()\n }\n return `${parsed.pathname}${parsed.search}${parsed.hash}`\n } catch {\n const separator = loginUrl.includes(\"?\") ? \"&\" : \"?\"\n return `${loginUrl}${separator}callback=${encodeURIComponent(callback)}`\n }\n}\n\nconst getCurrentHref = () =>\n typeof window === \"undefined\" ? \"\" : window.location.href\n\nconst getCurrentHostname = () =>\n typeof window === \"undefined\" ? \"\" : window.location.hostname\n\nconst getRuntimeEnv = (key: string) => {\n const env =\n typeof process !== \"undefined\"\n ? (process as unknown as { env?: Record<string, string | undefined> }).env\n : undefined\n return env?.[key]\n}\n\nconst getRecordValue = (value: unknown, key: string) => {\n if (!value || typeof value !== \"object\") return undefined\n return (value as Record<string, unknown>)[key]\n}\n\nconst getRecordString = (value: unknown, key: string) => {\n const result = getRecordValue(value, key)\n return typeof result === \"string\" ? result : undefined\n}\n\nconst resolveAppTypeFromLocation = () => {\n if (typeof window === \"undefined\") return \"\"\n const segments = window.location.pathname.split(\"/\").filter(Boolean)\n const viewIndex = segments[0] === \"view\" ? 1 : 0\n if (segments[viewIndex] === \"submit\") return segments[viewIndex + 1] || \"\"\n if (segments[viewIndex] === \"preview\") return segments[viewIndex + 1] || \"\"\n return segments[viewIndex] || \"\"\n}\n","export const createBoundFetch = (fetchImpl?: typeof fetch): typeof fetch => {\n const baseFetch = fetchImpl || globalThis.fetch;\n return ((input, init) => baseFetch.call(globalThis, input, init)) as typeof fetch;\n};\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/runtime/react/openxiangdaProvider.tsx","../../src/runtime/core/fetch.ts","../../src/runtime/react/auth.tsx","../../src/runtime/core/auth.ts"],"sourcesContent":["import React, {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useState,\n} from \"react\"\nimport { createBoundFetch } from \"../core/fetch\"\n\nexport type RuntimeErrorType =\n | \"unauthenticated\"\n | \"forbidden\"\n | \"network\"\n | \"unknown\"\n\nexport type RuntimeRequestError = Error & {\n type?: RuntimeErrorType\n status?: number\n code?: number | string\n payload?: unknown\n}\n\nexport interface RuntimeErrorSnapshot {\n type: RuntimeErrorType\n status?: number\n code?: number | string\n message: string\n payload?: unknown\n}\n\nexport class RuntimeHttpError extends Error {\n type: RuntimeErrorType\n status?: number\n code?: number | string\n payload?: unknown\n\n constructor(snapshot: RuntimeErrorSnapshot) {\n super(snapshot.message)\n this.name = \"RuntimeHttpError\"\n this.type = snapshot.type\n this.status = snapshot.status\n this.code = snapshot.code\n this.payload = snapshot.payload\n }\n}\n\nexport interface RuntimeMenuItem {\n id: string\n name: string\n resourceCode?: string | null\n routeCode?: string | null\n path?: string | null\n type?: string\n formUuid?: string | null\n pageId?: string | null\n parentId?: string | null\n sortOrder?: number\n isHidden?: boolean\n icon?: string | null\n children?: RuntimeMenuItem[]\n [key: string]: unknown\n}\n\nexport interface RuntimePagePermissions {\n appType: string\n hasFullAccess: boolean\n roleCodes: string[]\n roleSource?: string\n menuFormUuids: string[]\n menuCodes: string[]\n routeCodes: string[]\n pathPatterns: string[]\n}\n\nexport interface RuntimeBootstrap {\n appType: string\n app?: Record<string, unknown> | null\n user?: Record<string, unknown> | null\n runtime?: {\n mode?: \"legacy\" | \"react-spa\" | string\n settings?: Record<string, unknown>\n activeReleaseId?: string | null\n activeBuildId?: string | null\n indexUrl?: string | null\n assetBaseUrl?: string | null\n }\n permissions?: RuntimePagePermissions\n menus?: RuntimeMenuItem[]\n servicePrefix?: string\n}\n\nexport interface RouteAccessResult {\n appType: string\n canAccess: boolean\n routeCode?: string\n menuCode?: string\n path?: string\n status?: number\n code?: number | string\n message?: string\n errorType?: RuntimeErrorType\n payload?: unknown\n permissions?: RuntimePagePermissions\n}\n\nexport interface RuntimeRequestState<T> {\n data: T | null\n loading: boolean\n error: RuntimeRequestError | null\n}\n\nexport interface OpenXiangdaProviderProps {\n appType?: string\n servicePrefix?: string\n fetchImpl?: typeof fetch\n children: React.ReactNode\n}\n\ninterface OpenXiangdaRuntimeStore extends RuntimeRequestState<RuntimeBootstrap> {\n appType: string\n servicePrefix: string\n fetchImpl: typeof fetch\n reload: () => Promise<void>\n}\n\nconst OpenXiangdaRuntimeContext =\n createContext<OpenXiangdaRuntimeStore | null>(null)\n\nexport const OpenXiangdaProvider: React.FC<OpenXiangdaProviderProps> = ({\n appType,\n servicePrefix = \"/service\",\n fetchImpl,\n children,\n}) => {\n const resolvedFetch = useMemo(() => createBoundFetch(fetchImpl), [fetchImpl])\n const resolvedAppType = useMemo(\n () => appType || resolveAppTypeFromLocation(),\n [appType],\n )\n const [state, setState] = useState<RuntimeRequestState<RuntimeBootstrap>>({\n data: null,\n loading: true,\n error: null,\n })\n\n const reload = useCallback(async () => {\n if (!resolvedAppType) {\n setState({\n data: null,\n loading: false,\n error: createRuntimeError({\n message: \"appType 不能为空\",\n type: \"unknown\",\n }),\n })\n return\n }\n setState(prev => ({ ...prev, loading: true, error: null }))\n try {\n const response = await resolvedFetch(\n buildServiceUrl(\n servicePrefix,\n `/openxiangda-api/v1/apps/${encodeURIComponent(\n resolvedAppType,\n )}/runtime/bootstrap`,\n ),\n {\n credentials: \"include\",\n headers: { accept: \"application/json\" },\n },\n )\n const payload = await readJsonPayload(response)\n if (!response.ok || payload?.code >= 400) {\n throw createRuntimeHttpError(\n response,\n payload,\n payload?.message || `Runtime bootstrap failed: ${response.status}`,\n )\n }\n setState({\n data: payload?.data || null,\n loading: false,\n error: null,\n })\n } catch (error) {\n setState({\n data: null,\n loading: false,\n error: normalizeRuntimeError(error),\n })\n }\n }, [resolvedAppType, resolvedFetch, servicePrefix])\n\n useEffect(() => {\n void reload()\n }, [reload])\n\n const value = useMemo<OpenXiangdaRuntimeStore>(\n () => ({\n ...state,\n appType: resolvedAppType,\n servicePrefix,\n fetchImpl: resolvedFetch,\n reload,\n }),\n [reload, resolvedAppType, resolvedFetch, servicePrefix, state],\n )\n\n return (\n <OpenXiangdaRuntimeContext.Provider value={value}>\n {children}\n </OpenXiangdaRuntimeContext.Provider>\n )\n}\n\nexport const useOpenXiangda = () => {\n const context = useContext(OpenXiangdaRuntimeContext)\n if (!context) {\n throw new Error(\"useOpenXiangda must be used inside OpenXiangdaProvider\")\n }\n return context\n}\n\nexport const useRuntimeBootstrap = () => useOpenXiangda()\n\nexport const useAppMenus = () => {\n const runtime = useOpenXiangda()\n return {\n ...runtime,\n data: runtime.data?.menus || [],\n }\n}\n\nexport const usePermission = () => {\n const runtime = useOpenXiangda()\n return {\n ...runtime,\n data: runtime.data?.permissions || null,\n }\n}\n\nexport interface UseCanAccessRouteInput {\n routeCode?: string\n menuCode?: string\n path?: string\n}\n\nexport const useCanAccessRoute = (input: UseCanAccessRouteInput) => {\n const runtime = useOpenXiangda()\n const [state, setState] = useState<RuntimeRequestState<RouteAccessResult>>({\n data: null,\n loading: true,\n error: null,\n })\n\n useEffect(() => {\n let disposed = false\n const check = async () => {\n const permissions = runtime.data?.permissions\n if (!runtime.appType || runtime.loading) {\n setState(prev => ({ ...prev, loading: runtime.loading }))\n return\n }\n if (runtime.error && !runtime.data) {\n const snapshot = toRuntimeErrorSnapshot(runtime.error)\n setState({\n data: {\n appType: runtime.appType,\n canAccess: false,\n status: snapshot.status,\n code: snapshot.code,\n message: snapshot.message,\n errorType: snapshot.type,\n payload: snapshot.payload,\n },\n loading: false,\n error: runtime.error,\n })\n return\n }\n if (permissions?.hasFullAccess) {\n setState({\n data: { appType: runtime.appType, canAccess: true, permissions },\n loading: false,\n error: null,\n })\n return\n }\n setState(prev => ({ ...prev, loading: true, error: null }))\n try {\n const response = await runtime.fetchImpl(\n buildServiceUrl(\n runtime.servicePrefix,\n `/openxiangda-api/v1/apps/${encodeURIComponent(\n runtime.appType,\n )}/runtime/routes/check`,\n ),\n {\n method: \"POST\",\n credentials: \"include\",\n headers: {\n accept: \"application/json\",\n \"content-type\": \"application/json\",\n },\n body: JSON.stringify(input),\n },\n )\n const payload = await readJsonPayload(response)\n const code = payload?.code ?? response.status\n const canAccess = Boolean(payload?.data?.canAccess)\n const errorType = canAccess\n ? undefined\n : classifyRuntimeError(response.status, code)\n const data: RouteAccessResult = {\n ...(payload?.data || {\n appType: runtime.appType,\n canAccess: false,\n }),\n appType: payload?.data?.appType || runtime.appType,\n canAccess,\n status: response.status,\n code,\n message: payload?.message,\n errorType,\n payload,\n }\n if (!disposed) {\n const shouldTreatAsError =\n !response.ok || (typeof code === \"number\" && code >= 500)\n setState({\n data,\n loading: false,\n error: shouldTreatAsError\n ? createRuntimeHttpError(\n response,\n payload,\n payload?.message || `Route check failed: ${response.status}`,\n )\n : null,\n })\n }\n } catch (error) {\n if (!disposed) {\n setState({\n data: null,\n loading: false,\n error: normalizeRuntimeError(error),\n })\n }\n }\n }\n void check()\n return () => {\n disposed = true\n }\n }, [\n input.menuCode,\n input.path,\n input.routeCode,\n runtime.appType,\n runtime.data?.permissions,\n runtime.fetchImpl,\n runtime.loading,\n runtime.servicePrefix,\n ])\n\n return {\n ...state,\n canAccess: Boolean(state.data?.canAccess),\n }\n}\n\nexport interface PermissionBoundaryProps extends UseCanAccessRouteInput {\n children: React.ReactNode\n fallback?: React.ReactNode | PermissionBoundaryFallback\n loadingFallback?: React.ReactNode | PermissionBoundaryFallback\n}\n\nexport interface PermissionBoundaryFallbackState {\n access: ReturnType<typeof useCanAccessRoute>\n runtime: ReturnType<typeof useOpenXiangda>\n error: RuntimeRequestError | null\n errorType: RuntimeErrorType\n status?: number\n code?: number | string\n message: string\n}\n\nexport type PermissionBoundaryFallback = (\n state: PermissionBoundaryFallbackState,\n) => React.ReactNode\n\nexport const PermissionBoundary: React.FC<PermissionBoundaryProps> = ({\n children,\n fallback = null,\n loadingFallback = null,\n routeCode,\n menuCode,\n path,\n}) => {\n const runtime = useOpenXiangda()\n const access = useCanAccessRoute({ routeCode, menuCode, path })\n const fallbackState = createPermissionFallbackState(access, runtime)\n if (access.loading) {\n return <>{renderBoundaryFallback(loadingFallback, fallbackState)}</>\n }\n if (!access.canAccess) {\n return <>{renderBoundaryFallback(fallback, fallbackState)}</>\n }\n return <>{children}</>\n}\n\nexport interface RuntimeResolveLoginOptions {\n redirectUri?: string\n loginUrl?: string\n domain?: string\n}\n\nexport interface RuntimeRedirectLoginOptions extends RuntimeResolveLoginOptions {\n replace?: boolean\n}\n\nexport interface RuntimeLogoutOptions extends RuntimeRedirectLoginOptions {\n continueOnError?: boolean\n}\n\nexport const useRuntimeAuth = () => {\n const runtime = useOpenXiangda()\n\n const resolveLoginUrl = useCallback(\n async (options: RuntimeResolveLoginOptions = {}) => {\n const redirectUri = options.redirectUri || getCurrentHref()\n const domain = options.domain || getCurrentHostname()\n const appTenantId = getRecordString(runtime.data?.app, \"tenantId\")\n\n try {\n const statusUrl = withQuery(\n buildServiceUrl(runtime.servicePrefix, \"/api/sso/status\"),\n { domain },\n )\n const statusResponse = await runtime.fetchImpl(statusUrl, {\n credentials: \"include\",\n headers: { accept: \"application/json\" },\n })\n const statusPayload = await readJsonPayload(statusResponse)\n const sso = statusPayload?.data || {}\n const enabled = Boolean(sso.enabled)\n const shouldUseSso = Boolean(\n enabled && (sso.forceLogin ?? sso.autoRedirect ?? true),\n )\n if (shouldUseSso) {\n const loginUrlResponse = await runtime.fetchImpl(\n withQuery(buildServiceUrl(runtime.servicePrefix, \"/api/sso/login-url\"), {\n domain,\n redirectUri,\n ...(sso.tenantId || appTenantId\n ? { tenantId: String(sso.tenantId || appTenantId) }\n : {}),\n ...(sso.protocol ? { protocol: String(sso.protocol) } : {}),\n }),\n {\n credentials: \"include\",\n headers: { accept: \"application/json\" },\n },\n )\n const loginUrlPayload = await readJsonPayload(loginUrlResponse)\n const loginUrl =\n loginUrlPayload?.data?.loginUrl ||\n loginUrlPayload?.data?.url ||\n loginUrlPayload?.loginUrl ||\n loginUrlPayload?.url\n if (loginUrl) return String(loginUrl)\n }\n } catch {\n // Login resolution must always have a local fallback so logged-out\n // users are not stranded behind a permission state.\n }\n\n const configuredLoginUrl =\n options.loginUrl ||\n getRuntimeEnv(\"OPENXIANGDA_LOGIN_URL\") ||\n getRuntimeEnv(\"VITE_OPENXIANGDA_LOGIN_URL\") ||\n getRuntimeEnv(\"APP_LOGIN_URL\") ||\n getRuntimeEnv(\"VITE_APP_LOGIN_URL\") ||\n getRuntimeEnv(\"VITE_BATH_AUTH_URL\") ||\n getRuntimeEnv(\"BATH_AUTH_URL\")\n if (configuredLoginUrl) {\n return attachCallback(configuredLoginUrl, redirectUri)\n }\n return attachCallback(\"/platform/login\", redirectUri)\n },\n [runtime.data?.app, runtime.fetchImpl, runtime.servicePrefix],\n )\n\n const redirectToLogin = useCallback(\n async (options: RuntimeRedirectLoginOptions = {}) => {\n const loginUrl = await resolveLoginUrl(options)\n if (typeof window !== \"undefined\") {\n if (options.replace === false) {\n window.location.assign(loginUrl)\n } else {\n window.location.replace(loginUrl)\n }\n }\n return loginUrl\n },\n [resolveLoginUrl],\n )\n\n const logout = useCallback(async () => {\n const response = await runtime.fetchImpl(\n buildServiceUrl(runtime.servicePrefix, \"/api/auth/logout\"),\n {\n method: \"POST\",\n credentials: \"include\",\n headers: { accept: \"application/json\" },\n },\n )\n const payload = await readJsonPayload(response)\n if (!response.ok || payload?.code >= 400) {\n throw createRuntimeHttpError(\n response,\n payload,\n payload?.message || `Logout failed: ${response.status}`,\n )\n }\n return payload\n }, [runtime.fetchImpl, runtime.servicePrefix])\n\n const logoutAndRedirect = useCallback(\n async (options: RuntimeLogoutOptions = {}) => {\n try {\n await logout()\n } catch (error) {\n if (options.continueOnError === false) throw error\n }\n return redirectToLogin(options)\n },\n [logout, redirectToLogin],\n )\n\n return {\n logout,\n logoutAndRedirect,\n redirectToLogin,\n resolveLoginUrl,\n }\n}\n\nconst buildServiceUrl = (servicePrefix: string, path: string) => {\n const prefix = servicePrefix.endsWith(\"/\")\n ? servicePrefix.slice(0, -1)\n : servicePrefix\n const suffix = path.startsWith(\"/\") ? path : `/${path}`\n return `${prefix}${suffix}`\n}\n\nconst readJsonPayload = async (response: Response) => {\n try {\n return await response.json()\n } catch {\n return null\n }\n}\n\nconst createRuntimeHttpError = (\n response: Response,\n payload: unknown,\n fallbackMessage: string,\n): RuntimeRequestError =>\n createRuntimeError({\n type: classifyRuntimeError(\n response.status,\n getRecordValue(payload, \"code\") as number | string | undefined,\n ),\n status: response.status,\n code: getRecordValue(payload, \"code\") as number | string | undefined,\n message:\n (getRecordValue(payload, \"message\") as string | undefined) ||\n fallbackMessage,\n payload,\n })\n\nconst createRuntimeError = (\n snapshot: RuntimeErrorSnapshot,\n): RuntimeRequestError =>\n new RuntimeHttpError({\n ...snapshot,\n type: snapshot.type || \"unknown\",\n message: snapshot.message || \"Runtime request failed\",\n })\n\nconst normalizeRuntimeError = (error: unknown): RuntimeRequestError => {\n if (error instanceof RuntimeHttpError) return error\n if (error instanceof Error) {\n const runtimeError = error as RuntimeRequestError\n runtimeError.type = runtimeError.type || classifyRuntimeError(runtimeError.status, runtimeError.code)\n return runtimeError\n }\n return createRuntimeError({\n type: \"unknown\",\n message: String(error),\n })\n}\n\nconst toRuntimeErrorSnapshot = (\n error: RuntimeRequestError,\n): RuntimeErrorSnapshot => ({\n type: error.type || classifyRuntimeError(error.status, error.code),\n status: error.status,\n code: error.code,\n message: error.message || \"Runtime request failed\",\n payload: error.payload,\n})\n\nconst classifyRuntimeError = (\n status?: number,\n code?: number | string,\n): RuntimeErrorType => {\n const normalizedCode = typeof code === \"string\" ? Number(code) : code\n if (status === 401 || normalizedCode === 401) return \"unauthenticated\"\n if (status === 403 || normalizedCode === 403) return \"forbidden\"\n if (!status && !normalizedCode) return \"network\"\n return \"unknown\"\n}\n\nconst createPermissionFallbackState = (\n access: ReturnType<typeof useCanAccessRoute>,\n runtime: ReturnType<typeof useOpenXiangda>,\n): PermissionBoundaryFallbackState => {\n const error = access.error || runtime.error\n const accessData = access.data\n const errorType =\n accessData?.errorType ||\n error?.type ||\n (!access.canAccess ? \"forbidden\" : \"unknown\")\n return {\n access,\n runtime,\n error,\n errorType,\n status: accessData?.status || error?.status,\n code: accessData?.code || error?.code,\n message:\n accessData?.message ||\n error?.message ||\n (errorType === \"unauthenticated\"\n ? \"当前账号尚未登录\"\n : \"当前账号没有访问权限\"),\n }\n}\n\nconst renderBoundaryFallback = (\n fallback: React.ReactNode | PermissionBoundaryFallback,\n state: PermissionBoundaryFallbackState,\n) => (typeof fallback === \"function\" ? fallback(state) : fallback)\n\nconst withQuery = (\n url: string,\n params: Record<string, string | number | boolean | undefined>,\n) => {\n const query = new URLSearchParams()\n Object.entries(params).forEach(([key, value]) => {\n if (value === undefined || value === \"\") return\n query.set(key, String(value))\n })\n const serialized = query.toString()\n if (!serialized) return url\n return `${url}${url.includes(\"?\") ? \"&\" : \"?\"}${serialized}`\n}\n\nconst attachCallback = (loginUrl: string, callback: string) => {\n if (!callback) return loginUrl\n try {\n const base =\n typeof window !== \"undefined\" ? window.location.origin : \"http://localhost\"\n const parsed = new URL(loginUrl, base)\n if (!parsed.searchParams.has(\"callback\") && !parsed.searchParams.has(\"redirectUri\")) {\n parsed.searchParams.set(\"callback\", callback)\n }\n if (loginUrl.startsWith(\"http://\") || loginUrl.startsWith(\"https://\")) {\n return parsed.toString()\n }\n return `${parsed.pathname}${parsed.search}${parsed.hash}`\n } catch {\n const separator = loginUrl.includes(\"?\") ? \"&\" : \"?\"\n return `${loginUrl}${separator}callback=${encodeURIComponent(callback)}`\n }\n}\n\nconst getCurrentHref = () =>\n typeof window === \"undefined\" ? \"\" : window.location.href\n\nconst getCurrentHostname = () =>\n typeof window === \"undefined\" ? \"\" : window.location.hostname\n\nconst getRuntimeEnv = (key: string) => {\n const env =\n typeof process !== \"undefined\"\n ? (process as unknown as { env?: Record<string, string | undefined> }).env\n : undefined\n return env?.[key]\n}\n\nconst getRecordValue = (value: unknown, key: string) => {\n if (!value || typeof value !== \"object\") return undefined\n return (value as Record<string, unknown>)[key]\n}\n\nconst getRecordString = (value: unknown, key: string) => {\n const result = getRecordValue(value, key)\n return typeof result === \"string\" ? result : undefined\n}\n\nconst resolveAppTypeFromLocation = () => {\n if (typeof window === \"undefined\") return \"\"\n const segments = window.location.pathname.split(\"/\").filter(Boolean)\n const viewIndex = segments[0] === \"view\" ? 1 : 0\n if (segments[viewIndex] === \"submit\") return segments[viewIndex + 1] || \"\"\n if (segments[viewIndex] === \"preview\") return segments[viewIndex + 1] || \"\"\n return segments[viewIndex] || \"\"\n}\n\nexport {\n LoginPage,\n useAuth,\n useLoginMethods,\n} from \"./auth\"\nexport type {\n LoginPageProps,\n UseAuthOptions,\n UseLoginMethodsState,\n} from \"./auth\"\nexport {\n AuthClientError,\n createAuthClient,\n} from \"../core/auth\"\nexport type {\n AppAuthClient,\n AuthMethod,\n AuthMethodType,\n AuthTokenData,\n DingTalkLoginInput,\n GuestLoginInput,\n LoginMethodsResult,\n PasswordLoginInput,\n PhoneCodeInput,\n PhoneCodeLoginInput,\n PhoneCodeRegisterInput,\n PhoneCodeSendResult,\n RefreshInput,\n ResolveLoginUrlInput,\n SsoLoginUrlInput,\n SsoLoginUrlResult,\n} from \"../core/auth\"\n","export const createBoundFetch = (fetchImpl?: typeof fetch): typeof fetch => {\n const baseFetch = fetchImpl || globalThis.fetch;\n return ((input, init) => baseFetch.call(globalThis, input, init)) as typeof fetch;\n};\n","import React, {\n type CSSProperties,\n useCallback,\n useEffect,\n useMemo,\n useState,\n} from \"react\"\nimport {\n Alert,\n Button,\n Card,\n Empty,\n Form,\n Input,\n Space,\n Tabs,\n Typography,\n} from \"antd\"\nimport {\n LoginOutlined,\n MobileOutlined,\n QrcodeOutlined,\n SafetyCertificateOutlined,\n UserOutlined,\n} from \"@ant-design/icons\"\nimport {\n type AppAuthClient,\n type AuthClientOptions,\n type AuthMethod,\n type AuthTokenData,\n createAuthClient,\n type LoginMethodsResult,\n} from \"../core/auth\"\nimport { useOpenXiangda } from \"./openxiangdaProvider\"\n\nexport interface UseAuthOptions extends Partial<AuthClientOptions> {}\n\nexport interface UseLoginMethodsState {\n data: LoginMethodsResult | null\n methods: AuthMethod[]\n loading: boolean\n error: Error | null\n reload: () => Promise<void>\n}\n\nexport interface LoginPageProps extends UseAuthOptions {\n title?: React.ReactNode\n subtitle?: React.ReactNode\n className?: string\n style?: CSSProperties\n defaultMethod?: \"password\" | \"phone_code\"\n redirectUrl?: string\n redirectOnSuccess?: boolean\n onSuccess?: (data: AuthTokenData) => void | Promise<void>\n}\n\ninterface PasswordFormValues {\n username: string\n password: string\n}\n\ninterface PhoneCodeFormValues {\n phone: string\n code: string\n}\n\nexport const useAuth = (options: UseAuthOptions = {}) => {\n const runtime = useOpenXiangda()\n const client = useMemo(\n () =>\n createAuthClient({\n appType: options.appType || runtime.appType,\n servicePrefix: options.servicePrefix || runtime.servicePrefix,\n fetchImpl: options.fetchImpl || runtime.fetchImpl,\n }),\n [\n options.appType,\n options.fetchImpl,\n options.servicePrefix,\n runtime.appType,\n runtime.fetchImpl,\n runtime.servicePrefix,\n ],\n )\n\n return useMemo(\n () => ({\n client,\n getMethods: client.getMethods,\n passwordLogin: client.passwordLogin,\n dingtalkLogin: client.dingtalkLogin,\n guestLogin: client.guestLogin,\n sendPhoneCode: client.sendPhoneCode,\n phoneCodeLogin: client.phoneCodeLogin,\n registerWithPhoneCode: client.registerWithPhoneCode,\n getSsoLoginUrl: client.getSsoLoginUrl,\n refresh: client.refresh,\n logout: client.logout,\n resolveLoginUrl: client.resolveLoginUrl,\n }),\n [client],\n )\n}\n\nexport const useLoginMethods = (\n options: UseAuthOptions = {},\n): UseLoginMethodsState => {\n const auth = useAuth(options)\n const [state, setState] = useState<{\n data: LoginMethodsResult | null\n loading: boolean\n error: Error | null\n }>({\n data: null,\n loading: true,\n error: null,\n })\n\n const reload = useCallback(async () => {\n setState(prev => ({ ...prev, loading: true, error: null }))\n try {\n const data = await auth.getMethods()\n setState({ data, loading: false, error: null })\n } catch (error) {\n setState({\n data: null,\n loading: false,\n error: normalizeError(error),\n })\n }\n }, [auth])\n\n useEffect(() => {\n let disposed = false\n const run = async () => {\n setState(prev => ({ ...prev, loading: true, error: null }))\n try {\n const data = await auth.getMethods()\n if (!disposed) setState({ data, loading: false, error: null })\n } catch (error) {\n if (!disposed) {\n setState({\n data: null,\n loading: false,\n error: normalizeError(error),\n })\n }\n }\n }\n void run()\n return () => {\n disposed = true\n }\n }, [auth])\n\n return {\n ...state,\n methods: state.data?.methods || [],\n reload,\n }\n}\n\nexport const LoginPage: React.FC<LoginPageProps> = ({\n title,\n subtitle,\n className,\n style,\n defaultMethod,\n redirectUrl,\n redirectOnSuccess = true,\n onSuccess,\n ...authOptions\n}) => {\n const runtime = useOpenXiangda()\n const auth = useAuth(authOptions)\n const methodsState = useLoginMethods(authOptions)\n const [passwordForm] = Form.useForm<PasswordFormValues>()\n const [phoneForm] = Form.useForm<PhoneCodeFormValues>()\n const [activeMethod, setActiveMethod] = useState<string>(\n defaultMethod || \"password\",\n )\n const [phonePurpose, setPhonePurpose] = useState<\"login\" | \"register\">(\n \"login\",\n )\n const [phoneChallengeId, setPhoneChallengeId] = useState(\"\")\n const [submitting, setSubmitting] = useState(false)\n const [sendingCode, setSendingCode] = useState(false)\n const [error, setError] = useState<string | null>(null)\n\n const methods = methodsState.methods.filter(method => method.enabled !== false)\n const passwordMethod = findMethod(methods, \"password\")\n const phoneMethod = findMethod(methods, \"phone_code\")\n const dingtalkMethod = findMethod(methods, \"dingtalk\")\n const ssoMethod = findMethod(methods, \"sso\")\n const guestMethod = findMethod(methods, \"guest\")\n const allowRegister = methodsState.data?.registration?.mode !== \"reject\"\n\n const tabItems = useMemo(() => {\n const items = []\n if (passwordMethod) {\n items.push({\n key: \"password\",\n label: (\n <Space size={6}>\n <UserOutlined />\n <span>{passwordMethod.label || \"账号密码\"}</span>\n </Space>\n ),\n children: (\n <PasswordLoginForm\n form={passwordForm}\n loading={submitting}\n onFinish={async values => {\n setSubmitting(true)\n setError(null)\n try {\n await handleSuccess(\n await auth.passwordLogin({\n username: values.username,\n password: values.password,\n }),\n )\n } catch (loginError) {\n setError(normalizeError(loginError).message)\n } finally {\n setSubmitting(false)\n }\n }}\n />\n ),\n })\n }\n if (phoneMethod) {\n items.push({\n key: \"phone_code\",\n label: (\n <Space size={6}>\n <MobileOutlined />\n <span>{phoneMethod.label || \"手机号\"}</span>\n </Space>\n ),\n children: (\n <PhoneCodeLoginForm\n allowRegister={allowRegister}\n form={phoneForm}\n loading={submitting}\n phonePurpose={phonePurpose}\n sendingCode={sendingCode}\n onPurposeChange={setPhonePurpose}\n onSendCode={async () => {\n const values = await phoneForm.validateFields([\"phone\"])\n setSendingCode(true)\n setError(null)\n try {\n const result = await auth.sendPhoneCode({\n phone: values.phone,\n purpose: phonePurpose,\n })\n setPhoneChallengeId(result.challengeId)\n } catch (sendError) {\n setError(normalizeError(sendError).message)\n } finally {\n setSendingCode(false)\n }\n }}\n onFinish={async values => {\n setSubmitting(true)\n setError(null)\n try {\n const data =\n phonePurpose === \"register\"\n ? await auth.registerWithPhoneCode({\n phone: values.phone,\n code: values.code,\n challengeId: phoneChallengeId,\n })\n : await auth.phoneCodeLogin({\n phone: values.phone,\n code: values.code,\n challengeId: phoneChallengeId,\n })\n await handleSuccess(data)\n } catch (loginError) {\n setError(normalizeError(loginError).message)\n } finally {\n setSubmitting(false)\n }\n }}\n />\n ),\n })\n }\n return items\n }, [\n allowRegister,\n auth,\n handleSuccess,\n passwordForm,\n passwordMethod,\n phoneChallengeId,\n phoneForm,\n phoneMethod,\n phonePurpose,\n sendingCode,\n submitting,\n ])\n\n useEffect(() => {\n const firstKey = tabItems[0]?.key\n if (firstKey && !tabItems.some(item => item.key === activeMethod)) {\n setActiveMethod(firstKey)\n }\n }, [activeMethod, tabItems])\n\n const handleDingTalkLogin = async () => {\n setSubmitting(true)\n setError(null)\n try {\n const code = await requestDingTalkCode(dingtalkMethod)\n await handleSuccess(\n await auth.dingtalkLogin({\n code,\n corpId: getString(dingtalkMethod, \"corpId\"),\n }),\n )\n } catch (loginError) {\n setError(normalizeError(loginError).message)\n } finally {\n setSubmitting(false)\n }\n }\n\n const handleSsoLogin = async () => {\n setSubmitting(true)\n setError(null)\n try {\n const redirectUri = getCurrentHref()\n const result = await auth.getSsoLoginUrl({\n protocol: getString(ssoMethod, \"protocol\") || \"cas\",\n redirectUri,\n })\n window.location.assign(result.loginUrl)\n } catch (loginError) {\n setError(normalizeError(loginError).message)\n setSubmitting(false)\n }\n }\n\n const handleGuestLogin = async () => {\n setSubmitting(true)\n setError(null)\n try {\n await handleSuccess(\n await auth.guestLogin({\n guestIdentifier: getOrCreateGuestIdentifier(auth.client),\n domain: getCurrentHostname(),\n }),\n )\n } catch (loginError) {\n setError(normalizeError(loginError).message)\n } finally {\n setSubmitting(false)\n }\n }\n\n async function handleSuccess(data: AuthTokenData) {\n await onSuccess?.(data)\n await runtime.reload()\n if (redirectOnSuccess && typeof window !== \"undefined\") {\n window.location.replace(\n redirectUrl || getCallbackUrl() || `/view/${auth.client.appType}`,\n )\n }\n }\n\n return (\n <div\n className={className}\n style={{\n minHeight: \"100vh\",\n display: \"grid\",\n placeItems: \"center\",\n padding: 24,\n background: \"#f6f8fb\",\n ...style,\n }}\n >\n <Card\n style={{\n width: \"min(100%, 420px)\",\n borderRadius: 8,\n boxShadow: \"0 16px 48px rgba(15, 23, 42, 0.10)\",\n }}\n styles={{ body: { padding: 28 } }}\n >\n <Space direction=\"vertical\" size={20} style={{ width: \"100%\" }}>\n <div>\n <Typography.Title level={3} style={{ margin: 0 }}>\n {title || \"应用登录\"}\n </Typography.Title>\n {subtitle ? (\n <Typography.Text type=\"secondary\">{subtitle}</Typography.Text>\n ) : null}\n </div>\n {methodsState.error ? (\n <Alert\n showIcon\n type=\"error\"\n message={methodsState.error.message}\n />\n ) : null}\n {error ? <Alert showIcon type=\"error\" message={error} /> : null}\n {methodsState.loading ? (\n <Button block loading>\n 加载中\n </Button>\n ) : tabItems.length > 0 ? (\n <Tabs\n activeKey={activeMethod}\n items={tabItems}\n onChange={setActiveMethod}\n />\n ) : (\n <Empty description=\"未启用登录方式\" />\n )}\n <Space direction=\"vertical\" size={10} style={{ width: \"100%\" }}>\n {dingtalkMethod ? (\n <Button\n block\n icon={<QrcodeOutlined />}\n loading={submitting}\n onClick={handleDingTalkLogin}\n >\n {dingtalkMethod.label || \"钉钉免登\"}\n </Button>\n ) : null}\n {ssoMethod ? (\n <Button\n block\n icon={<SafetyCertificateOutlined />}\n loading={submitting}\n onClick={handleSsoLogin}\n >\n {ssoMethod.label || \"SSO 登录\"}\n </Button>\n ) : null}\n {guestMethod ? (\n <Button\n block\n icon={<LoginOutlined />}\n loading={submitting}\n onClick={handleGuestLogin}\n >\n {guestMethod.label || \"访客访问\"}\n </Button>\n ) : null}\n </Space>\n </Space>\n </Card>\n </div>\n )\n}\n\nconst PasswordLoginForm: React.FC<{\n form: ReturnType<typeof Form.useForm<PasswordFormValues>>[0]\n loading: boolean\n onFinish: (values: PasswordFormValues) => void\n}> = ({ form, loading, onFinish }) => (\n <Form form={form} layout=\"vertical\" requiredMark={false} onFinish={onFinish}>\n <Form.Item\n label=\"账号\"\n name=\"username\"\n rules={[{ required: true, message: \"请输入账号\" }]}\n >\n <Input autoComplete=\"username\" />\n </Form.Item>\n <Form.Item\n label=\"密码\"\n name=\"password\"\n rules={[{ required: true, message: \"请输入密码\" }]}\n >\n <Input.Password autoComplete=\"current-password\" />\n </Form.Item>\n <Button block htmlType=\"submit\" icon={<LoginOutlined />} loading={loading} type=\"primary\">\n 登录\n </Button>\n </Form>\n)\n\nconst PhoneCodeLoginForm: React.FC<{\n allowRegister: boolean\n form: ReturnType<typeof Form.useForm<PhoneCodeFormValues>>[0]\n loading: boolean\n phonePurpose: \"login\" | \"register\"\n sendingCode: boolean\n onPurposeChange: (purpose: \"login\" | \"register\") => void\n onSendCode: () => Promise<void>\n onFinish: (values: PhoneCodeFormValues) => void\n}> = ({\n allowRegister,\n form,\n loading,\n phonePurpose,\n sendingCode,\n onPurposeChange,\n onSendCode,\n onFinish,\n}) => (\n <Form form={form} layout=\"vertical\" requiredMark={false} onFinish={onFinish}>\n {allowRegister ? (\n <Form.Item style={{ marginBottom: 12 }}>\n <Tabs\n activeKey={phonePurpose}\n items={[\n { key: \"login\", label: \"登录\" },\n { key: \"register\", label: \"注册\" },\n ]}\n onChange={key => onPurposeChange(key === \"register\" ? \"register\" : \"login\")}\n size=\"small\"\n />\n </Form.Item>\n ) : null}\n <Form.Item\n label=\"手机号\"\n name=\"phone\"\n rules={[{ required: true, message: \"请输入手机号\" }]}\n >\n <Input autoComplete=\"tel\" />\n </Form.Item>\n <Form.Item\n label=\"验证码\"\n name=\"code\"\n rules={[{ required: true, message: \"请输入验证码\" }]}\n >\n <Input\n addonAfter={\n <Button\n loading={sendingCode}\n onClick={onSendCode}\n size=\"small\"\n type=\"link\"\n >\n 发送\n </Button>\n }\n autoComplete=\"one-time-code\"\n />\n </Form.Item>\n <Button block htmlType=\"submit\" icon={<MobileOutlined />} loading={loading} type=\"primary\">\n {phonePurpose === \"register\" ? \"注册\" : \"登录\"}\n </Button>\n </Form>\n)\n\nconst findMethod = (methods: AuthMethod[], type: string) =>\n methods.find(method => method.type === type)\n\nconst normalizeError = (error: unknown): Error =>\n error instanceof Error ? error : new Error(String(error || \"请求失败\"))\n\nconst getString = (value: unknown, key: string) => {\n if (!value || typeof value !== \"object\") return undefined\n const result = (value as Record<string, unknown>)[key]\n return typeof result === \"string\" ? result : undefined\n}\n\nconst requestDingTalkCode = (method?: AuthMethod): Promise<string> => {\n const dd =\n typeof window === \"undefined\"\n ? undefined\n : (window as unknown as { dd?: any }).dd\n const corpId = getString(method, \"corpId\")\n return new Promise((resolve, reject) => {\n const requestAuthCode =\n dd?.runtime?.permission?.requestAuthCode || dd?.requestAuthCode\n if (!requestAuthCode) {\n reject(new Error(\"当前环境不支持钉钉免登\"))\n return\n }\n requestAuthCode({\n corpId,\n onSuccess: (result: { code?: string }) => {\n if (result?.code) resolve(result.code)\n else reject(new Error(\"钉钉未返回免登码\"))\n },\n onFail: (error: unknown) => reject(normalizeError(error)),\n })\n })\n}\n\nconst getOrCreateGuestIdentifier = (client: AppAuthClient) => {\n const key = `openxiangda:${client.appType}:guest_id`\n if (typeof window === \"undefined\") return createGuestIdentifier()\n const current = window.localStorage.getItem(key)\n if (current) return current\n const next = createGuestIdentifier()\n window.localStorage.setItem(key, next)\n return next\n}\n\nconst createGuestIdentifier = () =>\n `guest_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`\n\nconst getCurrentHref = () =>\n typeof window === \"undefined\" ? \"\" : window.location.href\n\nconst getCurrentHostname = () =>\n typeof window === \"undefined\" ? \"\" : window.location.hostname\n\nconst getCallbackUrl = () => {\n if (typeof window === \"undefined\") return \"\"\n const query = new URLSearchParams(window.location.search)\n return query.get(\"callback\") || query.get(\"redirectUri\") || \"\"\n}\n","import { createBoundFetch } from \"./fetch\"\n\nexport type AuthMethodType =\n | \"password\"\n | \"dingtalk\"\n | \"sso\"\n | \"guest\"\n | \"phone_code\"\n | string\n\nexport interface AuthMethod {\n type: AuthMethodType\n enabled?: boolean\n label?: string\n protocol?: string\n [key: string]: unknown\n}\n\nexport interface LoginMethodsResult {\n appType: string\n configCode?: string\n methods: AuthMethod[]\n registration?: {\n mode?: string\n [key: string]: unknown\n }\n security?: {\n hideFailureReason?: boolean\n [key: string]: unknown\n }\n defaultRedirectUrl?: string\n}\n\nexport interface AuthUser {\n id: string\n username?: string\n name?: string\n phone?: string | null\n email?: string | null\n avatar?: string | null\n jobNumber?: string | null\n departments?: Array<Record<string, unknown>>\n affiliatedDepartmentId?: string | null\n affiliatedDepartment?: Record<string, unknown> | null\n [key: string]: unknown\n}\n\nexport interface AuthTokenData {\n accessToken: string\n refreshToken: string\n token?: string\n accessTokenExpiresAt?: number\n refreshTokenExpiresAt?: number\n user?: AuthUser\n guestUser?: AuthUser\n [key: string]: unknown\n}\n\nexport interface PhoneCodeSendResult {\n challengeId: string\n expiresAt?: string | Date\n ttlSeconds?: number\n message?: string\n}\n\nexport interface SsoLoginUrlResult {\n loginUrl: string\n protocol?: string\n}\n\nexport interface AuthClientOptions {\n appType: string\n servicePrefix?: string\n fetchImpl?: typeof fetch\n}\n\nexport interface PasswordLoginInput {\n username: string\n password: string\n clientFingerprint?: string\n challengeId?: string\n challengeAnswer?: string\n}\n\nexport interface DingTalkLoginInput {\n code: string\n corpId?: string\n}\n\nexport interface GuestLoginInput {\n guestIdentifier?: string\n domain?: string\n ipAddress?: string\n userAgent?: string\n formUuid?: string\n}\n\nexport interface PhoneCodeInput {\n phone: string\n purpose?: \"login\" | \"register\" | string\n}\n\nexport interface PhoneCodeLoginInput {\n phone: string\n code: string\n challengeId?: string\n}\n\nexport interface PhoneCodeRegisterInput extends PhoneCodeLoginInput {\n name?: string\n email?: string\n}\n\nexport interface SsoLoginUrlInput {\n protocol?: string\n redirectUri?: string\n}\n\nexport interface RefreshInput {\n refreshToken?: string\n}\n\nexport interface ResolveLoginUrlInput {\n callbackUrl?: string\n callbackParamName?: string\n loginUrl?: string\n}\n\nexport interface AppAuthClient {\n appType: string\n servicePrefix: string\n getMethods: () => Promise<LoginMethodsResult>\n passwordLogin: (input: PasswordLoginInput) => Promise<AuthTokenData>\n dingtalkLogin: (input: DingTalkLoginInput) => Promise<AuthTokenData>\n guestLogin: (input?: GuestLoginInput) => Promise<AuthTokenData>\n sendPhoneCode: (input: PhoneCodeInput) => Promise<PhoneCodeSendResult>\n phoneCodeLogin: (input: PhoneCodeLoginInput) => Promise<AuthTokenData>\n registerWithPhoneCode: (\n input: PhoneCodeRegisterInput,\n ) => Promise<AuthTokenData>\n getSsoLoginUrl: (input?: SsoLoginUrlInput) => Promise<SsoLoginUrlResult>\n refresh: (input?: RefreshInput) => Promise<AuthTokenData>\n logout: () => Promise<void>\n resolveLoginUrl: (input?: ResolveLoginUrlInput) => string\n}\n\nexport class AuthClientError extends Error {\n status?: number\n code?: number | string\n payload?: unknown\n\n constructor(message: string, options: { status?: number; code?: number | string; payload?: unknown } = {}) {\n super(message)\n this.name = \"AuthClientError\"\n this.status = options.status\n this.code = options.code\n this.payload = options.payload\n }\n}\n\nexport const createAuthClient = ({\n appType,\n servicePrefix = \"/service\",\n fetchImpl,\n}: AuthClientOptions): AppAuthClient => {\n const normalizedAppType = String(appType || \"\").trim()\n if (!normalizedAppType) {\n throw new Error(\"appType 不能为空\")\n }\n const boundFetch = createBoundFetch(fetchImpl)\n const request = async <T>(\n path: string,\n options: RequestInit = {},\n ): Promise<T> => {\n const response = await boundFetch(buildServiceUrl(servicePrefix, path), {\n credentials: \"include\",\n ...options,\n headers: {\n accept: \"application/json\",\n ...(options.body ? { \"content-type\": \"application/json\" } : {}),\n ...(options.headers || {}),\n },\n })\n const payload = await readPayload(response)\n const code = getRecordValue(payload, \"code\")\n if (!response.ok || (typeof code === \"number\" && code >= 400)) {\n throw new AuthClientError(\n String(getRecordValue(payload, \"message\") || `Auth request failed: ${response.status}`),\n { status: response.status, code: code as number | string | undefined, payload },\n )\n }\n return unwrapPayload<T>(payload)\n }\n\n const appAuthPath = (suffix: string) =>\n `/openxiangda-api/v1/apps/${encodeURIComponent(normalizedAppType)}/auth${suffix}`\n\n return {\n appType: normalizedAppType,\n servicePrefix,\n getMethods: () => request<LoginMethodsResult>(appAuthPath(\"/methods\")),\n passwordLogin: input =>\n request<AuthTokenData>(appAuthPath(\"/password/login\"), postJson(input)),\n dingtalkLogin: input =>\n request<AuthTokenData>(appAuthPath(\"/dingtalk/login\"), postJson(input)),\n guestLogin: input =>\n request<AuthTokenData>(appAuthPath(\"/guest/login\"), postJson(input || {})),\n sendPhoneCode: input =>\n request<PhoneCodeSendResult>(appAuthPath(\"/phone-code/send\"), postJson(input)),\n phoneCodeLogin: input =>\n request<AuthTokenData>(appAuthPath(\"/phone-code/login\"), postJson(input)),\n registerWithPhoneCode: input =>\n request<AuthTokenData>(appAuthPath(\"/phone-code/register\"), postJson(input)),\n getSsoLoginUrl: input =>\n request<SsoLoginUrlResult>(appAuthPath(\"/sso/login-url\"), postJson(input || {})),\n refresh: input =>\n request<AuthTokenData>(appAuthPath(\"/refresh\"), postJson(input || {})),\n logout: async () => {\n await request<null>(appAuthPath(\"/logout\"), { method: \"POST\" })\n },\n resolveLoginUrl: input =>\n resolveLoginUrl(normalizedAppType, input || {}),\n }\n}\n\nconst postJson = (body: unknown): RequestInit => ({\n method: \"POST\",\n body: JSON.stringify(body || {}),\n})\n\nconst buildServiceUrl = (servicePrefix: string, path: string) => {\n const prefix = servicePrefix.endsWith(\"/\")\n ? servicePrefix.slice(0, -1)\n : servicePrefix\n const suffix = path.startsWith(\"/\") ? path : `/${path}`\n return `${prefix}${suffix}`\n}\n\nconst readPayload = async (response: Response) => {\n try {\n return await response.json()\n } catch {\n return null\n }\n}\n\nconst unwrapPayload = <T>(payload: unknown): T => {\n if (!payload || typeof payload !== \"object\") return payload as T\n const record = payload as Record<string, unknown>\n if (\"data\" in record) return record.data as T\n return payload as T\n}\n\nconst getRecordValue = (value: unknown, key: string) => {\n if (!value || typeof value !== \"object\") return undefined\n return (value as Record<string, unknown>)[key]\n}\n\nconst resolveLoginUrl = (\n appType: string,\n {\n callbackUrl = getCurrentHref(),\n callbackParamName = \"callback\",\n loginUrl,\n }: ResolveLoginUrlInput,\n) => {\n const target = loginUrl || `/view/${encodeURIComponent(appType)}/login`\n if (!callbackUrl) return target\n try {\n const base =\n typeof window !== \"undefined\" ? window.location.origin : \"http://localhost\"\n const url = new URL(target, base)\n if (!url.searchParams.has(callbackParamName)) {\n url.searchParams.set(callbackParamName, callbackUrl)\n }\n if (target.startsWith(\"http://\") || target.startsWith(\"https://\")) {\n return url.toString()\n }\n return `${url.pathname}${url.search}${url.hash}`\n } catch {\n const separator = target.includes(\"?\") ? \"&\" : \"?\"\n return `${target}${separator}${callbackParamName}=${encodeURIComponent(callbackUrl)}`\n }\n}\n\nconst getCurrentHref = () =>\n typeof window === \"undefined\" ? \"\" : window.location.href\n"],"mappings":"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","names":["useCallback","useEffect","useMemo","useState","getCurrentHref","jsx","useMemo","useState","useCallback","buildServiceUrl","useEffect","resolveLoginUrl","getCurrentHref","getCurrentHostname","getRecordValue"]}
@@ -6,7 +6,7 @@ import {
6
6
  } from "react-router-dom";
7
7
  import { lazy, Suspense, type ReactNode } from "react";
8
8
  import { Sparkles } from "lucide-react";
9
- import { OpenXiangdaProvider } from "openxiangda/runtime/react";
9
+ import { LoginPage, OpenXiangdaProvider } from "openxiangda/runtime/react";
10
10
 
11
11
  import { AdminShell } from "@/layouts/AdminShell";
12
12
  import { AdminDashboardPage } from "@/pages/admin/AdminDashboardPage";
@@ -69,6 +69,7 @@ export const router = createBrowserRouter([
69
69
  element: <RuntimeRoot />,
70
70
  children: [
71
71
  { index: true, element: <Navigate to="admin" replace /> },
72
+ { path: "login", element: <LoginPage /> },
72
73
  {
73
74
  path: "admin",
74
75
  element: <AdminShell />,