/** * @fileoverview V2/V3 Flow 双向转换工具 * @description 桥接 Builder V2 Flow 类型与 V3 RPC FlowV3 类型 * * 设计说明: * - Builder store 目前仍使用 V2 类型 (type, version, steps) * - RPC 层使用 V3 类型 (kind, schemaVersion, entryNodeId) * - 本模块提供 UI 层的类型转换,封装底层转换器 */ import type { Flow as FlowV2 } from '@/entrypoints/background/record-replay/types'; import type { FlowV3 } from '@/entrypoints/background/record-replay-v3/domain/flow'; import { convertFlowV2ToV3, convertFlowV3ToV2, } from '@/entrypoints/background/record-replay-v3/storage/import/v2-to-v3'; // ==================== Types ==================== export interface FlowConversionResult { flow: T; warnings: string[]; } // ==================== V2 -> V3 (for RPC calls) ==================== /** * 将 V2 Flow 转换为 V3 格式,用于 RPC 保存 * @param flowV2 Builder store 中的 V2 Flow * @returns V3 Flow 和警告信息 * @throws 转换失败时抛出错误 */ export function flowV2ToV3ForRpc(flowV2: FlowV2): FlowConversionResult { const result = convertFlowV2ToV3(flowV2 as unknown as Parameters[0]); if (!result.success || !result.data) { const errorMsg = result.errors.length > 0 ? result.errors.join('; ') : 'Unknown conversion error'; throw new Error(`V2→V3 conversion failed: ${errorMsg}`); } return { flow: result.data, warnings: result.warnings, }; } // ==================== V3 -> V2 (for Builder display) ==================== /** * 将 V3 Flow 转换为 V2 格式,用于 Builder 显示和编辑 * @param flowV3 从 RPC 获取的 V3 Flow * @returns V2 Flow 和警告信息 * @throws 转换失败时抛出错误 */ export function flowV3ToV2ForBuilder(flowV3: FlowV3): FlowConversionResult { const result = convertFlowV3ToV2(flowV3); if (!result.success || !result.data) { const errorMsg = result.errors.length > 0 ? result.errors.join('; ') : 'Unknown conversion error'; throw new Error(`V3→V2 conversion failed: ${errorMsg}`); } return { flow: result.data as unknown as FlowV2, warnings: result.warnings, }; } // ==================== Type Guards ==================== /** * 判断是否为 V3 Flow * @description 用于导入时判断 JSON 格式 */ export function isFlowV3(value: unknown): value is FlowV3 { if (!value || typeof value !== 'object' || Array.isArray(value)) { return false; } const obj = value as Record; return ( obj.schemaVersion === 3 && typeof obj.id === 'string' && typeof obj.name === 'string' && typeof obj.entryNodeId === 'string' && Array.isArray(obj.nodes) ); } /** * 判断是否为 V2 Flow * @description 用于导入时判断 JSON 格式 */ export function isFlowV2(value: unknown): value is FlowV2 { if (!value || typeof value !== 'object' || Array.isArray(value)) { return false; } const obj = value as Record; return ( typeof obj.id === 'string' && typeof obj.name === 'string' && // V2 有 version 字段(数字),且没有 schemaVersion typeof obj.version === 'number' && obj.schemaVersion === undefined && // V2 可能有 steps 或 nodes (Array.isArray(obj.steps) || Array.isArray(obj.nodes)) ); } // ==================== Import Helpers ==================== /** * 从导入的 JSON 中提取 Flow 候选列表 * @description 支持单个 Flow、Flow 数组、或 { flows: Flow[] } 格式 */ export function extractFlowCandidates(parsed: unknown): unknown[] { // 数组格式 if (Array.isArray(parsed)) { return parsed; } // 对象格式 if (parsed && typeof parsed === 'object') { const obj = parsed as Record; // { flows: [...] } 格式 if (Array.isArray(obj.flows)) { return obj.flows; } // 单个 Flow 对象 if (obj.id && (Array.isArray(obj.steps) || Array.isArray(obj.nodes))) { return [obj]; } } return []; }