import { ArrowLeft, PlugZap } from "lucide-react"; import * as React from "react"; import { useCallback, useEffect, useState, type ComponentType } from "react"; import { platformApiClient } from "../api/client"; import type { GamePluginResponse } from "../api/types"; import { PageFrame } from "../components/PageFrame"; import { EmptyState, ErrorState, LoadingState } from "../components/StateViews"; import type { PageComponentProps } from "../contracts/page"; import { pluginBridgeManifestContractFromResponse } from "../contracts/pluginBridge"; import { createPluginBridgeHostContext } from "../utils/pluginBridgeHost"; import { loadPluginPageBundle } from "../utils/pluginPageBundles"; type PluginPageState = | { status: "loading" } | { status: "error"; reason: string } | { status: "ready"; plugin: GamePluginResponse }; interface PluginPageHostPageProps extends PageComponentProps { initialPlugin?: GamePluginResponse; } export function PluginPageHostPage({ params, onNavigate, initialPlugin }: PluginPageHostPageProps) { const pluginId = params.pluginId ?? ""; const routeKey = params.routeKey ?? ""; const serverId = params.serverId ?? ""; const [state, setState] = useState(() => initialPlugin ? { status: "ready", plugin: initialPlugin } : { status: "loading" }); const [bundle, setBundle] = useState; workspace?: unknown; availability: { available: boolean; reason?: string } }> | null>(null); const [bundleError, setBundleError] = useState(""); const [availability, setAvailability] = useState<{ available: boolean; reason?: string }>({ available: false, reason: "正在验证 Companion 可用性。" }); const load = useCallback(async () => { if (!pluginId || !routeKey) { setState({ status: "error", reason: "插件页面路由缺少 pluginId 或 routeKey。" }); return; } setState({ status: "loading" }); try { const response = await platformApiClient.listGamePlugins(); const plugin = response.items.find((candidate) => candidate.id === pluginId); setState(plugin ? { status: "ready", plugin } : { status: "error", reason: "未找到已注册的插件声明。" }); } catch (error) { setState({ status: "error", reason: error instanceof Error ? error.message : "插件页面声明加载失败。" }); } }, [pluginId, routeKey]); useEffect(() => { if (!initialPlugin) { void load(); } }, [initialPlugin, load]); const readyPlugin = state.status === "ready" ? state.plugin : undefined; const declaredPage = readyPlugin?.pages.find((candidate) => candidate.key === routeKey); const declaredBundlePage = readyPlugin ? pluginBridgeManifestContractFromResponse(readyPlugin).pages.find((candidate) => candidate.key === routeKey) : undefined; useEffect(() => { let active = true; if (!declaredBundlePage) return () => { active = false; }; globalThis.__PLUGIN_PAGE_REACT__ = React; setBundle(null); setBundleError(""); void loadPluginPageBundle(declaredBundlePage).then((loaded) => { if (active) setBundle(() => loaded); }).catch((error) => { if (active) setBundleError(error instanceof Error ? error.message : "插件页面 bundle 加载失败。"); }); if (!serverId) { setAvailability({ available: false, reason: "插件页面没有绑定服务器。" }); return () => { active = false; }; } void platformApiClient.getGameClientBridgeStatus(serverId).then((status) => { if (active) setAvailability({ available: status.available, reason: status.reason }); }).catch((error) => { if (active) setAvailability({ available: false, reason: error instanceof Error ? error.message : "无法验证 Companion 可用性。" }); }); return () => { active = false; }; }, [declaredBundlePage, serverId]); if (state.status === "loading") { return ; } if (state.status === "error") { return void load()} />; } const page = declaredPage; if (!page) { return ; } const manifestContract = pluginBridgeManifestContractFromResponse(state.plugin); const hostContext = createPluginBridgeHostContext({ plugin: manifestContract, routeKey, serverInstanceId: serverId || undefined, themeTokens: { colorScheme: "dark", accentColor: "#7dd3fc" } }); return (
0 ? "success" : "warning" }, { label: "桥接动作", value: String(hostContext.bridgeActions.length), tone: hostContext.bridgeActions.length > 0 ? "success" : "warning" }, { label: "页面路由", value: routeKey, tone: "neutral" } ]} />

Bundle {page.bundleKey ? `${page.bundleKey}@${page.bundleVersion}` : "未声明"}完整性 {page.bundleIntegritySha256 ? `${page.bundleIntegritySha256.slice(0, 18)}…` : "未声明"}Companion {availability.available ? "可用" : "不可用"}
{bundleError && } {!bundle && !bundleError && } {bundle && React.createElement(bundle, { context: hostContext, workspace: state.plugin.fileWorkspace, availability })}
); }