"use client"; /** * 拉取并缓存 /api/node-types 节点目录(每会话一次,模块级缓存)。 * 对齐 dograh 的 useNodeSpecs:规格随后端 + 刷新生效。 */ import { useEffect, useRef, useState } from "react"; import { nodeTypesApi, type NodeTypesResponse } from "@/lib/api"; import { toRuntimeSpec, type NodeSpecMap, type RuntimeNodeSpec, } from "./specs"; let _cache: NodeTypesResponse | null = null; type State = { specs: RuntimeNodeSpec[]; byType: NodeSpecMap; loading: boolean; error: string | null; }; function build(data: NodeTypesResponse | null): { specs: RuntimeNodeSpec[]; byType: NodeSpecMap; } { const specs = (data?.nodeTypes ?? []).map(toRuntimeSpec); const byType: NodeSpecMap = {}; for (const spec of specs) byType[spec.type] = spec; return { specs, byType }; } export function useNodeSpecs(): State { const fetched = useRef(false); const [state, setState] = useState(() => { const { specs, byType } = build(_cache); return { specs, byType, loading: !_cache, error: null }; }); useEffect(() => { if (_cache || fetched.current) return; fetched.current = true; nodeTypesApi .list() .then((data) => { _cache = data; const { specs, byType } = build(data); setState({ specs, byType, loading: false, error: null }); }) .catch((err: unknown) => { const message = err instanceof Error ? err.message : String(err); setState((s) => ({ ...s, loading: false, error: message })); }); }, []); return state; }