/** * Flow Bridge — bridges arrow data pipes with LayerFlow entries in Automerge. * * When an arrow pipe connects two folk-rapp shapes, a LayerFlow is auto-created * in the Automerge doc. Deleting the arrow removes the LayerFlow. */ import { inferFlowKind } from "./data-types"; import type { LayerFlow, Layer } from "./layer-types"; interface SyncLike { getLayers(): Layer[]; addFlow(flow: LayerFlow): void; removeFlow(flowId: string): void; } /** * Create a LayerFlow when an arrow pipe is created between two folk-rapp shapes. * Returns the new flowId, or null if layers couldn't be matched. */ export function onArrowPipeCreated( arrowId: string, sourcePort: string, targetPort: string, srcModuleId: string, tgtModuleId: string, sync: SyncLike, ): string | null { const layers = sync.getLayers(); // Find layers matching the source and target modules const srcLayer = layers.find(l => l.moduleId === srcModuleId); const tgtLayer = layers.find(l => l.moduleId === tgtModuleId); if (!srcLayer || !tgtLayer) return null; const flowKind = inferFlowKind(sourcePort); const flowId = `flow-${arrowId}`; const flow: LayerFlow = { id: flowId, kind: flowKind, sourceLayerId: srcLayer.id, targetLayerId: tgtLayer.id, label: `${srcModuleId} → ${tgtModuleId}`, strength: 1, active: true, meta: { arrowId, sourcePort, targetPort, }, }; sync.addFlow(flow); return flowId; } /** * Remove a LayerFlow when the corresponding arrow is deleted. */ export function onArrowRemoved(flowId: string, sync: SyncLike): void { if (flowId) { sync.removeFlow(flowId); } }