{"version":3,"file":"index.mjs","names":[],"sources":["../src/routing/routingContext.ts","../src/routing/useSmartEdgePath.ts","../src/SmartEdge/noProviderWarning.ts","../src/SmartEdge/smartEdgeSelection.ts","../src/routing/obstacleIndex.ts","../src/functions/alignEndpoints.ts","../src/pathfinding/flatGrid.ts","../src/functions/guaranteeWalkablePath.ts","../src/functions/pointConversion.ts","../src/functions/utils.ts","../src/functions/createGrid.ts","../src/functions/edgeHops.ts","../src/functions/drawSvgPath.ts","../src/functions/drawHopPath.ts","../src/pathfinding/binaryHeap.ts","../src/pathfinding/searchScratch.ts","../src/pathfinding/flatAStar.ts","../src/pathfinding/flatJumpPoint.ts","../src/functions/generatePath.ts","../src/functions/getBoundingBoxes.ts","../src/functions/getFloatingEdgeParams.ts","../src/functions/subflow.ts","../src/SmartEdge/smartEdgeHops.ts","../src/SmartEdge/controlPointGeometry.ts","../src/SmartEdge/ControlPoint.tsx","../src/SmartEdge/smartEdgeData.ts","../src/SmartEdge/smartEdgeRouting.ts","../src/SmartEdge/renderDecision.tsx","../src/SmartEdge/index.tsx","../src/smartEdgePresets.ts","../src/createSmartEdge/index.tsx","../src/SmartBezierEdge/index.tsx","../src/SmartStraightEdge/index.tsx","../src/SmartStepEdge/index.tsx","../src/SmartSmoothStepEdge/index.tsx","../src/SmartSimpleBezierEdge/index.tsx","../src/SmartFloatingEdge/index.tsx","../src/SmartEditableEdge/index.tsx","../src/SmartCheckpointEdge/index.tsx","../src/routing/corridor.ts","../src/getSmartEdge/index.ts","../src/SmartFloatingConnectionLine/index.tsx","../src/getSmartEdge/getSmartEdgeWaypoints.ts","../src/routing/providerStore.ts","../src/routing/routeCache.ts","../src/routing/invalidation.ts","../src/routing/invalidationCorridor.ts","../src/routing/schedulerFlush.ts","../src/routing/scheduler.ts","../src/routing/routingRegistry.ts","../src/routing/routeBatch.ts","../src/routing/workerProtocol.ts","../src/routing/workerDispatch.ts","../src/routing/SmartEdgeProvider.tsx"],"sourcesContent":["import { createContext } from \"react\";\nimport type { CSSProperties } from \"react\";\nimport type { Node } from \"@xyflow/react\";\nimport type { SmartEdgePreset } from \"../smartEdgePresets\";\nimport type { SmartEdgeStore } from \"./providerStore\";\nimport type {\n  RegisteredSmartEdge,\n  ResolvedProviderOptions as SchedulerOptions,\n} from \"./scheduler\";\n\n/**\n * Every option a `SmartEdgeProvider` resolves from its props: the scheduler's\n * routing-decision fields (inherited from `SchedulerOptions`, declared once in\n * `scheduler.ts`) plus the presentation fields the provider itself owns\n * (preset, corner radius, drag placeholder style). Extending rather than\n * redeclaring the shared fields keeps them in exactly one place while this\n * type still satisfies `SchedulerDeps[\"options\"]` structurally, with no cast.\n */\nexport interface ResolvedProviderOptions extends SchedulerOptions {\n  preset: SmartEdgePreset;\n  /** Corner radius for the `smoothstep` preset. */\n  borderRadius?: number;\n  /** Extra style merged onto a smart edge's native path while the route is\n   * pending or an endpoint is being dragged. Drag uses a\n   * `react-flow__edge animated` wrapper; pending uses a static dash. */\n  dragFallbackStyle: CSSProperties;\n}\n\n/** Provider-facing options: every field of `ResolvedProviderOptions` is\n * optional, defaulted by `resolveProviderOptions`. */\nexport type SmartEdgeProviderOptions = Partial<ResolvedProviderOptions>;\n\n/** What `SmartEdgeProvider` exposes to descendants through React context. */\nexport interface SmartEdgeContextValue {\n  store: SmartEdgeStore;\n  /** An immutable snapshot of the resolved provider options. The provider\n   * mutates its live options object in place (the scheduler closes over\n   * that reference) and publishes a fresh snapshot on every applied change,\n   * so the identity of this object tracks option value changes exactly. */\n  options: ResolvedProviderOptions;\n  /** Registers one edge's routing geometry, assigning it the next\n   * registration order. Returns an unregister function. */\n  registerEdge: (edge: Omit<RegisteredSmartEdge, \"order\">) => () => void;\n  /** Every currently registered edge, in registration (paint) order — used\n   * to place hop arcs where edges cross (a later task). */\n  getRegistrationsInOrder: () => RegisteredSmartEdge[];\n  /** The latest `nodes` prop, resolved to absolute (subflow-aware)\n   * coordinates — used by floating edges (a later task). */\n  getNodesSnapshot: () => Node[];\n}\n\n/**\n * Holds the active `SmartEdgeProvider` context. `null` when no provider is\n * mounted, in which case consumers should render their non-smart fallback.\n */\nexport const SmartEdgeRoutingContext =\n  createContext<SmartEdgeContextValue | null>(null);\n\nconst DEFAULT_DRAG_FALLBACK_STYLE: CSSProperties = {};\n\n/** Applies every `ResolvedProviderOptions` default to a provider's (partial)\n * `options` prop. */\nexport const resolveProviderOptions = (\n  options: SmartEdgeProviderOptions = {},\n): ResolvedProviderOptions => ({\n  preset: options.preset ?? \"bezier\",\n  gridRatio: options.gridRatio ?? 10,\n  nodePadding: options.nodePadding ?? 10,\n  avoidAreas: options.avoidAreas ?? [],\n  borderRadius: options.borderRadius,\n  routeOnlyWhenBlocked: options.routeOnlyWhenBlocked ?? true,\n  routeWhileDragging: options.routeWhileDragging ?? false,\n  dragFallbackStyle: options.dragFallbackStyle ?? DEFAULT_DRAG_FALLBACK_STYLE,\n  debounceMs: options.debounceMs ?? 16,\n  cacheSize: options.cacheSize ?? 500,\n});\n\nexport interface ProviderOptionsDiff {\n  any: boolean;\n  routing: boolean;\n}\n\nconst routingSnapshot = (options: ResolvedProviderOptions): string =>\n  JSON.stringify({\n    gridRatio: options.gridRatio,\n    nodePadding: options.nodePadding,\n    avoidAreas: options.avoidAreas,\n    routeOnlyWhenBlocked: options.routeOnlyWhenBlocked,\n    routeWhileDragging: options.routeWhileDragging,\n    cacheSize: options.cacheSize,\n    borderRadius: options.borderRadius,\n    preset: options.preset,\n  });\n\nconst presentationSnapshot = (options: ResolvedProviderOptions): string =>\n  JSON.stringify({\n    debounceMs: options.debounceMs,\n    dragFallbackStyle: options.dragFallbackStyle,\n  });\n\nexport const diffResolvedProviderOptions = (\n  previous: ResolvedProviderOptions,\n  next: ResolvedProviderOptions,\n): ProviderOptionsDiff => {\n  const routing = routingSnapshot(previous) !== routingSnapshot(next);\n  const presentation =\n    presentationSnapshot(previous) !== presentationSnapshot(next);\n\n  return { any: routing || presentation, routing };\n};\n","import {\n  useCallback,\n  useContext,\n  useEffect,\n  useRef,\n  useSyncExternalStore,\n} from \"react\";\nimport { SmartEdgeRoutingContext } from \"./routingContext\";\nimport type { SmartEdgeRouteResult } from \"./providerStore\";\nimport type { RegisteredSmartEdge } from \"./scheduler\";\nimport type { SmartEdgeBatchItem } from \"./routeBatch\";\nimport type { SmartEdgePreset } from \"../smartEdgePresets\";\nimport type { Position, XYPosition } from \"@xyflow/react\";\n\n/** Everything an edge component needs to hand `useSmartEdgePath` to register\n * its routing geometry and read back its route. Mirrors `SmartEdgeBatchItem`\n * (Task 10) minus `preset`, which is optional here and defaults to the\n * nearest `SmartEdgeProvider`'s configured preset. */\nexport interface UseSmartEdgePathInput {\n  id: string;\n  source: string;\n  target: string;\n  sourceX: number;\n  sourceY: number;\n  targetX: number;\n  targetY: number;\n  sourcePosition: Position;\n  targetPosition: Position;\n  /** Defaults to the nearest `SmartEdgeProvider`'s `options.preset`. */\n  preset?: SmartEdgePreset;\n  /** Per-edge routing overrides (grid ratio, padding, avoid areas, corner\n   * radius). */\n  options?: NonNullable<SmartEdgeBatchItem[\"options\"]>;\n  waypoints?: XYPosition[];\n}\n\nexport interface UseSmartEdgePathResult {\n  /** `null` while the route is still pending (or when there is no\n   * provider). */\n  route: SmartEdgeRouteResult | null;\n  /** True when this edge's source or target node is being dragged. */\n  isDragging: boolean;\n  /** False outside a `SmartEdgeProvider`; every other field is then inert. */\n  hasProvider: boolean;\n}\n\n/** What a store subscription returns when there is no provider to\n * subscribe to. */\nconst inertUnsubscribe = (): void => {\n  // No provider in context: nothing to unsubscribe from.\n};\n\n/* v8 ignore next 3 -- useSyncExternalStore server snapshot; unused in browser */\nconst getNullRoute = (): null => null;\n\n/* v8 ignore next 3 -- useSyncExternalStore server snapshot; unused in browser */\nconst getIdleDragging = (): boolean => false;\n\n/**\n * Registers one edge's routing geometry with the nearest `SmartEdgeProvider`\n * and subscribes to that edge's routed path and drag state.\n *\n * Mechanics mirror the 4.x `useSmartEdgeRoute`: building the registration\n * object is cheap, so it happens on every render, but a JSON signature of\n * that object gates the registration effect, so `registerEdge` only runs\n * again when the edge's routable geometry actually changed — not on every\n * unrelated re-render. The latest registration is kept in a ref (written in\n * its own effect, never during render) so the signature-gated effect can\n * read the current value without needing the object itself — which is\n * a fresh reference every render — in its dependency array.\n *\n * Every hook runs unconditionally, provider or not: outside a\n * `SmartEdgeProvider` this resolves to inert subscriptions and\n * `{ route: null, isDragging: false, hasProvider: false }`, which is also\n * exactly what a server render (no context, no DOM) produces.\n */\nexport const useSmartEdgePath = (\n  input: UseSmartEdgePathInput,\n): UseSmartEdgePathResult => {\n  const context = useContext(SmartEdgeRoutingContext);\n  const {\n    id,\n    source,\n    target,\n    sourceX,\n    sourceY,\n    targetX,\n    targetY,\n    sourcePosition,\n    targetPosition,\n    preset,\n    options,\n    waypoints,\n  } = input;\n\n  const registration: Omit<RegisteredSmartEdge, \"order\"> | null = context\n    ? {\n        id,\n        source,\n        target,\n        sourceX,\n        sourceY,\n        targetX,\n        targetY,\n        sourcePosition,\n        targetPosition,\n        preset: preset ?? context.options.preset,\n        options,\n        waypoints,\n      }\n    : null;\n\n  const signature = registration ? JSON.stringify(registration) : \"\";\n\n  const registrationRef = useRef(registration);\n  useEffect(() => {\n    registrationRef.current = registration;\n  });\n\n  const registerEdge = context?.registerEdge;\n  useEffect(() => {\n    const current = registrationRef.current;\n    if (!registerEdge || !current) return undefined;\n    return registerEdge(current);\n  }, [registerEdge, signature]);\n\n  const store = context?.store;\n\n  const subscribeEdge = useCallback(\n    (onRouteChange: () => void): (() => void) => {\n      if (!store) return inertUnsubscribe;\n      return store.subscribeEdge(id, onRouteChange);\n    },\n    [store, id],\n  );\n\n  const route = useSyncExternalStore(\n    subscribeEdge,\n    () => store?.getRoute(id) ?? null,\n    getNullRoute,\n  );\n\n  const subscribeNodeState = useCallback(\n    (onNodeStateChange: () => void): (() => void) => {\n      if (!store) return inertUnsubscribe;\n      return store.subscribeNodeState(onNodeStateChange);\n    },\n    [store],\n  );\n\n  const isDragging = useSyncExternalStore(\n    subscribeNodeState,\n    () => {\n      if (!store) return false;\n      const draggingIds = store.getDraggingNodeIds();\n      return draggingIds.has(source) || draggingIds.has(target);\n    },\n    getIdleDragging,\n  );\n\n  return {\n    route,\n    isDragging,\n    hasProvider: context !== null,\n  };\n};\n","const MIGRATION_GUIDE_URL =\n  \"https://tisoap.github.io/react-flow-smart-edge/docs/migration/v5\";\n\nconst NO_PROVIDER_MESSAGE =\n  \"[@tisoap/react-flow-smart-edge] A smart edge rendered without a \" +\n  \"<SmartEdgeProvider> ancestor, so routing is disabled and the edge falls \" +\n  \"back to its non-routed variant. Wrap your flow in <SmartEdgeProvider> to \" +\n  `enable routing. Migration guide: ${MIGRATION_GUIDE_URL}`;\n\nlet hasWarned = false;\n\n/** Narrows an unknown value to a plain, indexable object shape. */\nconst isRecord = (value: unknown): value is Record<PropertyKey, unknown> =>\n  typeof value === \"object\" && value !== null;\n\n/**\n * True when running in a production bundle, where the developer warning must\n * stay silent. Reads the ambient `process` global (if any) through\n * `Reflect.get` rather than referencing the bare `process` identifier, so\n * this file type-checks without a dependency on `@types/node` (the app\n * tsconfig deliberately has no Node types) and so browser ESM builds without\n * a `process` global do not throw.\n */\nconst isProduction = (): boolean => {\n  const maybeProcess: unknown = Reflect.get(globalThis, \"process\");\n  const env: unknown = isRecord(maybeProcess) ? maybeProcess[\"env\"] : undefined;\n  return isRecord(env) && env[\"NODE_ENV\"] === \"production\";\n};\n\n/**\n * Warns exactly once per module lifetime that a smart edge rendered outside a\n * `SmartEdgeProvider`. Silent in production. Repeated calls (e.g. one per\n * unprovided edge) are no-ops after the first warning.\n */\nexport const warnOnceNoProvider = (): void => {\n  if (hasWarned || isProduction()) return;\n  hasWarned = true;\n  console.warn(NO_PROVIDER_MESSAGE);\n};\n\n/**\n * Test hook: clears the module-level \"already warned\" flag so a test can\n * observe the first-warning behavior again.\n */\nexport const __resetNoProviderWarning = (): void => {\n  hasWarned = false;\n};\n","import { useCallback, useSyncExternalStore } from \"react\";\nimport type { SmartEdgeStore } from \"../routing/providerStore\";\n\n/** Inert unsubscribe used when there is no provider store to subscribe to. */\nconst inertUnsubscribe = (): void => {\n  // No store in context: nothing to unsubscribe from.\n};\n\n/* v8 ignore next 3 -- useSyncExternalStore server snapshot; unused in browser */\nconst getIdleSelected = (): boolean => false;\n\n/**\n * Subscribes to the provider store's selected-node set and reports whether\n * this edge's source or target node is currently selected. Used to decide\n * when an editable edge should reveal its draggable control points, without\n * reaching into React Flow's own store. Runs unconditionally; resolves to\n * `false` when there is no provider store.\n */\nexport const useEndpointNodesSelected = (\n  store: SmartEdgeStore | undefined,\n  source: string,\n  target: string,\n): boolean => {\n  const subscribe = useCallback(\n    (onChange: () => void): (() => void) =>\n      store ? store.subscribeNodeState(onChange) : inertUnsubscribe,\n    [store],\n  );\n\n  return useSyncExternalStore(\n    subscribe,\n    () => {\n      if (!store) return false;\n      const selected = store.getSelectedNodeIds();\n      return selected.has(source) || selected.has(target);\n    },\n    getIdleSelected,\n  );\n};\n","import type { Node, Rect, XYPosition, Position } from \"@xyflow/react\";\n\n/** A `Position`-shaped string union, kept local so this module never needs a\n * runtime import of `@xyflow/react` (it must stay reachable from the worker,\n * see `guaranteeWalkablePath.ts` for the same convention). */\ntype Direction = \"top\" | \"bottom\" | \"left\" | \"right\";\n\n/** A padded, axis-aligned obstacle rectangle in graph coordinates. */\nexport interface ObstacleBox {\n  id: string;\n  xMin: number;\n  yMin: number;\n  xMax: number;\n  yMax: number;\n}\n\nconst buildNodeBox = (node: Node, nodePadding: number): ObstacleBox => {\n  const width = Math.max(node.measured?.width ?? 0, 1);\n  const height = Math.max(node.measured?.height ?? 0, 1);\n\n  return {\n    id: node.id,\n    xMin: node.position.x - nodePadding,\n    yMin: node.position.y - nodePadding,\n    xMax: node.position.x + width + nodePadding,\n    yMax: node.position.y + height + nodePadding,\n  };\n};\n\nconst buildAreaBox = (\n  area: Rect,\n  index: number,\n  nodePadding: number,\n): ObstacleBox => {\n  const width = Math.max(area.width, 1);\n  const height = Math.max(area.height, 1);\n\n  return {\n    id: `avoid-${String(index)}`,\n    xMin: area.x - nodePadding,\n    yMin: area.y - nodePadding,\n    xMax: area.x + width + nodePadding,\n    yMax: area.y + height + nodePadding,\n  };\n};\n\n/**\n * Build padded obstacle boxes for every node (and optional `avoidAreas`),\n * using the same measured-size floor as `getBoundingBoxes` (missing\n * dimensions collapse to 1px). Unlike `getBoundingBoxes`, these are exact\n * rectangles — not rounded to a path-finding grid.\n *\n * Positions are expected to be absolute graph coordinates; callers resolve\n * subflow offsets before calling this function.\n */\nexport const buildObstacleBoxes = (\n  nodes: Node[],\n  nodePadding: number,\n  avoidAreas: Rect[] = [],\n): ObstacleBox[] => [\n  ...nodes.map((node) => buildNodeBox(node, nodePadding)),\n  ...avoidAreas.map((area, index) => buildAreaBox(area, index, nodePadding)),\n];\n\n/** Axis-aligned rect vs. obstacle-box overlap test (exclusive bounds — a\n * rect that only touches a box's edge does not count as intersecting). */\nexport const rectIntersectsBox = (\n  xMin: number,\n  yMin: number,\n  xMax: number,\n  yMax: number,\n  box: ObstacleBox,\n): boolean =>\n  xMin < box.xMax && xMax > box.xMin && yMin < box.yMax && yMax > box.yMin;\n\n/**\n * Liang-Barsky slab test for whether the segment from (startX, startY) to\n * (endX, endY) intersects the obstacle box (inclusive bounds — a segment\n * running exactly along a box edge counts as intersecting).\n */\nexport const segmentIntersectsBox = (\n  startX: number,\n  startY: number,\n  endX: number,\n  endY: number,\n  box: ObstacleBox,\n): boolean => {\n  const deltaX = endX - startX;\n  const deltaY = endY - startY;\n  let tMin = 0;\n  let tMax = 1;\n\n  const clip = (direction: number, distance: number): boolean => {\n    if (direction === 0) return distance >= 0;\n    const ratio = distance / direction;\n    if (direction < 0) {\n      if (ratio > tMax) return false;\n      if (ratio > tMin) tMin = ratio;\n    } else {\n      if (ratio < tMin) return false;\n      if (ratio < tMax) tMax = ratio;\n    }\n    return true;\n  };\n\n  return (\n    clip(-deltaX, startX - box.xMin) &&\n    clip(deltaX, box.xMax - startX) &&\n    clip(-deltaY, startY - box.yMin) &&\n    clip(deltaY, box.yMax - startY)\n  );\n};\n\n/**\n * Whether any leg of the polyline intersects any of the given boxes.\n * `excludeIds` skips boxes that should not count as obstacles for this\n * check (typically the polyline's own endpoint nodes).\n */\nexport const isPolylineBlocked = (\n  points: XYPosition[],\n  boxes: ObstacleBox[],\n  excludeIds?: ReadonlySet<string>,\n): boolean => {\n  for (let index = 0; index < points.length - 1; index += 1) {\n    const start = points[index];\n    const end = points[index + 1];\n\n    for (const box of boxes) {\n      if (excludeIds?.has(box.id)) continue;\n      if (segmentIntersectsBox(start.x, start.y, end.x, end.y, box)) {\n        return true;\n      }\n    }\n  }\n\n  return false;\n};\n\nconst isHorizontal = (position: Direction): boolean =>\n  position === \"left\" || position === \"right\";\n\n/**\n * The Z/L skeleton approximating xyflow's built-in step path: exits\n * perpendicular to `sourcePosition`, splits at the midpoint of the axis the\n * handles don't share, and enters perpendicular to `targetPosition`.\n */\nexport const nativeStepPolyline = (\n  sourceX: number,\n  sourceY: number,\n  sourcePosition: Position,\n  targetX: number,\n  targetY: number,\n  targetPosition: Position,\n): XYPosition[] => {\n  const source: XYPosition = { x: sourceX, y: sourceY };\n  const target: XYPosition = { x: targetX, y: targetY };\n  const sourceHorizontal = isHorizontal(sourcePosition);\n  const targetHorizontal = isHorizontal(targetPosition);\n\n  if (sourceHorizontal && targetHorizontal) {\n    const midX = (sourceX + targetX) / 2;\n    return [source, { x: midX, y: sourceY }, { x: midX, y: targetY }, target];\n  }\n\n  if (!sourceHorizontal && !targetHorizontal) {\n    const midY = (sourceY + targetY) / 2;\n    return [source, { x: sourceX, y: midY }, { x: targetX, y: midY }, target];\n  }\n\n  const corner: XYPosition = sourceHorizontal\n    ? { x: targetX, y: sourceY }\n    : { x: sourceX, y: targetY };\n\n  return [source, corner, target];\n};\n\n/** Options for `isDirectPathBlocked`. */\nexport interface DirectPathOptions {\n  nodePadding?: number;\n  avoidAreas?: Rect[];\n  excludeNodeIds?: string[];\n}\n\n/**\n * Public utility: does a straight line between `source` and `target` cross\n * any padded node (or `avoidAreas`)? Useful for skipping path-finding\n * entirely when a direct line is already clear. `excludeNodeIds` should\n * typically include the edge's own source/target node ids, since a handle\n * point normally sits inside its own node's padded box.\n */\nexport const isDirectPathBlocked = (\n  source: XYPosition,\n  target: XYPosition,\n  nodes: Node[],\n  options?: DirectPathOptions,\n): boolean => {\n  const nodePadding = options?.nodePadding ?? 10;\n  const avoidAreas = options?.avoidAreas ?? [];\n  const excludeIds = options?.excludeNodeIds\n    ? new Set(options.excludeNodeIds)\n    : undefined;\n  const boxes = buildObstacleBoxes(nodes, nodePadding, avoidAreas);\n\n  return isPolylineBlocked([source, target], boxes, excludeIds);\n};\n","import type { XYPosition } from \"@xyflow/react\";\n\ntype Direction = \"top\" | \"bottom\" | \"left\" | \"right\";\n\n/**\n * Source/target points carry both their graph coordinates and the side of the\n * node they are attached to (top/bottom/left/right).\n */\nexport interface EndpointInfo extends XYPosition {\n  position: Direction;\n}\n\n/**\n * Returns the index of the path tuple that varies for a given handle position.\n * Vertical handles (top/bottom) leave/enter on the X axis; horizontal handles\n * (left/right) leave/enter on the Y axis.\n */\nconst axisFor = (position: Direction): 0 | 1 =>\n  position === \"top\" || position === \"bottom\" ? 0 : 1;\n\n/**\n * Aligns the leading and trailing runs of the grid-snapped graph path with the\n * actual handle coordinates so the rendered edge enters and leaves each node\n * perpendicular to its handle, with no diagonal or L-shaped jog near the\n * endpoints.\n *\n * The grid path's first cells will all share the same X (for top/bottom\n * handles) or the same Y (for left/right handles) until the path turns. We\n * rewrite that perpendicular axis on each leading cell to match the handle's\n * actual coordinate. The first turn in the path is therefore purely\n * orthogonal: the segment from the last leading cell to the next path cell\n * shares the parallel axis, so it remains a straight horizontal/vertical line\n * even after the shift.\n *\n * The same operation is applied symmetrically to the trailing run for the\n * target. The trailing scan is bounded so it cannot reach into cells already\n * claimed by the leading shift, and the trailing column/row is detected from\n * the original (un-shifted) path so a same-axis leading shift cannot corrupt\n * detection in the common case where source and target share an axis.\n */\nexport const alignEndpoints = (\n  source: EndpointInfo,\n  target: EndpointInfo,\n  graphPath: number[][],\n): number[][] => {\n  if (graphPath.length === 0) return graphPath;\n\n  const result = graphPath.map(([posX, posY]) => [posX, posY]);\n\n  const sourceAxis = axisFor(source.position);\n  const sourceCoord = sourceAxis === 0 ? source.x : source.y;\n  const sourceLeadingValue = result[0][sourceAxis];\n\n  let leadEnd = 0;\n  while (\n    leadEnd < result.length &&\n    result[leadEnd][sourceAxis] === sourceLeadingValue\n  ) {\n    leadEnd++;\n  }\n\n  for (let index = 0; index < leadEnd; index++) {\n    result[index][sourceAxis] = sourceCoord;\n  }\n\n  const targetAxis = axisFor(target.position);\n  const targetCoord = targetAxis === 0 ? target.x : target.y;\n  const targetTrailingValue = graphPath[graphPath.length - 1][targetAxis];\n\n  let trailStart = result.length;\n  while (\n    trailStart > leadEnd &&\n    graphPath[trailStart - 1][targetAxis] === targetTrailingValue\n  ) {\n    trailStart--;\n  }\n\n  for (let index = trailStart; index < result.length; index++) {\n    result[index][targetAxis] = targetCoord;\n  }\n\n  return result;\n};\n","/**\n * Flat typed-array obstacle grid: the v5 replacement for the object-based\n * PathFinding.js grid. One byte per cell, indexed `y * width + x`, so building\n * and cloning are single allocations and pathfinding touches no heap objects.\n */\nexport interface FlatGrid {\n  width: number;\n  height: number;\n  /** `1` = blocked, `0` = walkable; index = `y * width + x`. */\n  blocked: Uint8Array;\n}\n\nexport const createFlatGrid = (width: number, height: number): FlatGrid => ({\n  width,\n  height,\n  blocked: new Uint8Array(width * height),\n});\n\nexport const cloneFlatGrid = (grid: FlatGrid): FlatGrid => ({\n  width: grid.width,\n  height: grid.height,\n  blocked: grid.blocked.slice(),\n});\n\nexport const isInside = (\n  grid: FlatGrid,\n  column: number,\n  row: number,\n): boolean =>\n  column >= 0 && column < grid.width && row >= 0 && row < grid.height;\n\nexport const isWalkable = (\n  grid: FlatGrid,\n  column: number,\n  row: number,\n): boolean =>\n  isInside(grid, column, row) && grid.blocked[row * grid.width + column] === 0;\n\n/** Out-of-bounds writes are silently ignored, like the old `setWalkableAt`. */\nexport const setBlocked = (\n  grid: FlatGrid,\n  column: number,\n  row: number,\n  blocked: boolean,\n): void => {\n  if (!isInside(grid, column, row)) return;\n  grid.blocked[row * grid.width + column] = blocked ? 1 : 0;\n};\n\n/** Blocks every cell in `[columnStart, columnEnd) × [rowStart, rowEnd)`, clamped to bounds. */\nexport const blockCellRange = (\n  grid: FlatGrid,\n  columnStart: number,\n  rowStart: number,\n  columnEnd: number,\n  rowEnd: number,\n): void => {\n  const minColumn = Math.max(0, columnStart);\n  const minRow = Math.max(0, rowStart);\n  const maxColumn = Math.min(grid.width, columnEnd);\n  const maxRow = Math.min(grid.height, rowEnd);\n  for (let row = minRow; row < maxRow; row++) {\n    const rowOffset = row * grid.width;\n    grid.blocked.fill(1, rowOffset + minColumn, rowOffset + maxColumn);\n  }\n};\n","import { isWalkable, setBlocked, isInside } from \"../pathfinding/flatGrid\";\nimport type { FlatGrid } from \"../pathfinding/flatGrid\";\nimport type { XYPosition } from \"@xyflow/react\";\n\n/**\n * A `Position`-shaped string union. `Position`'s enum values are exactly\n * these strings, so working in plain strings here (and letting real\n * `Position` values widen into this type at call sites) avoids importing the\n * `@xyflow/react` runtime — this module must stay reachable from the routing\n * Web Worker. Exported so `createGrid.ts`'s `PointInfo` can reuse it.\n */\nexport type Direction = \"top\" | \"bottom\" | \"left\" | \"right\";\n\nexport const getNextPointFromPosition = (\n  point: XYPosition,\n  position: Direction,\n): XYPosition => {\n  switch (position) {\n    case \"top\":\n      return { x: point.x, y: point.y - 1 };\n    case \"bottom\":\n      return { x: point.x, y: point.y + 1 };\n    case \"left\":\n      return { x: point.x - 1, y: point.y };\n    case \"right\":\n      return { x: point.x + 1, y: point.y };\n  }\n};\n\n/**\n * Guarantee that the path is walkable, even if the point is inside a non\n * walkable area, by carving a walkable lane in the direction of the point's\n * Position. Stops at the grid border.\n */\nexport const guaranteeWalkablePath = (\n  grid: FlatGrid,\n  point: XYPosition,\n  position: Direction,\n): void => {\n  let current = { x: point.x, y: point.y };\n  while (\n    isInside(grid, current.x, current.y) &&\n    !isWalkable(grid, current.x, current.y)\n  ) {\n    setBlocked(grid, current.x, current.y, false);\n    current = getNextPointFromPosition(current, position);\n  }\n};\n","import type { XYPosition } from \"@xyflow/react\";\n\n/**\n * Each bounding box is a collection of X/Y points in a graph, and we\n * need to convert them to \"occupied\" cells in a 2D grid representation.\n *\n * The top most position of the grid (grid[0][0]) needs to be equivalent\n * to the top most point in the graph (the graph.topLeft point).\n *\n * Since the top most point can have X/Y values different than zero,\n * and each cell in a grid represents a 10x10 pixel area in the grid (or a\n * gridRatio area), there's need to be a conversion between a point in a graph\n * to a point in the grid.\n *\n * We do this conversion by dividing a graph point X/Y values by the grid ratio,\n * and \"shifting\" their values up or down, depending on the values of the top\n * most point in the graph. The top most point in the graph will have the\n * smallest values for X and Y.\n *\n * We avoid setting nodes in the border of the grid (x=0 or y=0), so there's\n * always a \"walkable\" area around the grid.\n */\nexport const graphToGridPoint = (\n  graphPoint: XYPosition,\n  smallestX: number,\n  smallestY: number,\n  gridRatio: number,\n): XYPosition => {\n  // Affine transform: translate by top-left, scale by grid size, then offset border (1 cell)\n  const posX = (graphPoint.x - smallestX) / gridRatio + 1;\n  const posY = (graphPoint.y - smallestY) / gridRatio + 1;\n  return { x: posX, y: posY };\n};\n\n/**\n * Converts a grid point back to a graph point, using the reverse logic of\n * graphToGridPoint.\n */\nexport const gridToGraphPoint = (\n  gridPoint: XYPosition,\n  smallestX: number,\n  smallestY: number,\n  gridRatio: number,\n): XYPosition => {\n  // Inverse affine transform: remove border, scale by grid size, then translate by top-left\n  const posX = (gridPoint.x - 1) * gridRatio + smallestX;\n  const posY = (gridPoint.y - 1) * gridRatio + smallestY;\n  return { x: posX, y: posY };\n};\n","export const round = (value: number, multiple = 10) =>\n  Math.round(value / multiple) * multiple;\n\nexport const roundDown = (value: number, multiple = 10) =>\n  Math.floor(value / multiple) * multiple;\n\nexport const roundUp = (value: number, multiple = 10) =>\n  Math.ceil(value / multiple) * multiple;\n\nexport const toInteger = (value: number, min = 0) => {\n  let result = Math.max(Math.round(value), min);\n  result = Number.isInteger(result) ? result : min;\n  result = result >= min ? result : min;\n  return result;\n};\n","import {\n  createFlatGrid,\n  cloneFlatGrid,\n  setBlocked,\n} from \"../pathfinding/flatGrid\";\nimport type { FlatGrid } from \"../pathfinding/flatGrid\";\nimport {\n  guaranteeWalkablePath,\n  getNextPointFromPosition,\n} from \"./guaranteeWalkablePath\";\nimport type { Direction } from \"./guaranteeWalkablePath\";\nimport { graphToGridPoint } from \"./pointConversion\";\nimport { round, roundUp } from \"./utils\";\nimport type { NodeBoundingBox, GraphBoundingBox } from \"./getBoundingBoxes\";\n\nexport interface PointInfo {\n  x: number;\n  y: number;\n  position: Direction;\n}\n\n/** Grid dimensions (in cells) derived from the graph box and grid ratio. */\nconst getGridDimensions = (graph: GraphBoundingBox, gridRatio: number) => ({\n  mapColumns: roundUp(graph.width, gridRatio) / gridRatio + 1,\n  mapRows: roundUp(graph.height, gridRatio) / gridRatio + 1,\n});\n\n/**\n * Visit every grid cell occupied by a node bounding box. Shared by the live\n * grid marking and the cacheable base grid so both stay in sync.\n */\nconst forEachNodeCell = (\n  nodes: NodeBoundingBox[],\n  xMin: number,\n  yMin: number,\n  gridRatio: number,\n  visit: (column: number, row: number) => void,\n) => {\n  nodes.forEach((node) => {\n    const nodeStart = graphToGridPoint(node.topLeft, xMin, yMin, gridRatio);\n    const nodeEnd = graphToGridPoint(node.bottomRight, xMin, yMin, gridRatio);\n\n    for (let column = nodeStart.x; column < nodeEnd.x; column++) {\n      for (let row = nodeStart.y; row < nodeEnd.y; row++) {\n        visit(column, row);\n      }\n    }\n  });\n};\n\n/**\n * Build the base obstacle grid for a graph box: a flat `mapColumns x mapRows`\n * grid where every cell covered by a node is blocked and every other cell is\n * walkable. This is the endpoint-independent part of {@link createGrid}, so it\n * can be computed once per frame and reused across every edge that shares the\n * same nodes and options (see `getSmartEdge`'s shared grid cache).\n */\nexport const buildBaseGrid = (\n  graph: GraphBoundingBox,\n  nodes: NodeBoundingBox[],\n  gridRatio: number,\n): FlatGrid => {\n  const { xMin, yMin } = graph;\n  const { mapColumns, mapRows } = getGridDimensions(graph, gridRatio);\n\n  const grid = createFlatGrid(mapColumns, mapRows);\n\n  // `setBlocked` silently ignores out-of-bounds cells, matching the old\n  // `Grid.setWalkableAt` semantics.\n  forEachNodeCell(nodes, xMin, yMin, gridRatio, (column, row) => {\n    setBlocked(grid, column, row, true);\n  });\n\n  return grid;\n};\n\nexport const createGrid = (\n  graph: GraphBoundingBox,\n  nodes: NodeBoundingBox[],\n  source: PointInfo,\n  target: PointInfo,\n  gridRatio = 2,\n  baseGrid?: FlatGrid,\n) => {\n  const { xMin, yMin } = graph;\n\n  // Create a grid representation of the graph box, where each cell is\n  // equivalent to 10x10 pixels (or the grid ratio) on the graph. We'll use\n  // this simplified grid to do pathfinding. When a precomputed base grid is\n  // supplied (shared across edges in the same frame) we clone it instead of\n  // re-marking every node; otherwise we build it from the node boxes here.\n  const grid = baseGrid\n    ? cloneFlatGrid(baseGrid)\n    : buildBaseGrid(graph, nodes, gridRatio);\n\n  // Convert the starting and ending graph points to grid points\n  const startGrid = graphToGridPoint(\n    {\n      x: round(source.x, gridRatio),\n      y: round(source.y, gridRatio),\n    },\n    xMin,\n    yMin,\n    gridRatio,\n  );\n\n  const endGrid = graphToGridPoint(\n    {\n      x: round(target.x, gridRatio),\n      y: round(target.y, gridRatio),\n    },\n    xMin,\n    yMin,\n    gridRatio,\n  );\n\n  // Guarantee a walkable path between the start and end points, even if the\n  // source or target where covered by another node or by padding\n  guaranteeWalkablePath(grid, startGrid, source.position);\n  guaranteeWalkablePath(grid, endGrid, target.position);\n\n  // Use the next closest points as the start and end points, so\n  // pathfinding does not start too close to the nodes\n  const start = getNextPointFromPosition(startGrid, source.position);\n  const end = getNextPointFromPosition(endGrid, target.position);\n\n  return { grid, start, end };\n};\n","import type { XYPosition } from \"@xyflow/react\";\n\n/**\n * A bridge \"hop\" to draw on a routed orthogonal polyline where it crosses\n * another edge. `segmentIndex` is the polyline segment the crossing lies on and\n * `at` is the (positive) distance from that segment's start point to the\n * crossing.\n */\nexport interface Hop {\n  segmentIndex: number;\n  at: number;\n}\n\n/** Default axis-alignment / crossing tolerance in pixels. */\nexport const DEFAULT_HOP_EPSILON = 0.5;\n\n/**\n * Builds the orthogonal polyline an edge is drawn along, from its source/target\n * handle coordinates and the routed interior points returned by `getSmartEdge`.\n *\n * Consecutive duplicate points are dropped, and collinear midpoints are merged\n * so each straight run becomes a single maximal segment. Merging matters for\n * hop detection: routed paths contain many collinear grid points, so a crossing\n * frequently lands exactly on one of them — which strict-interior detection\n * would otherwise miss because it sits on a segment boundary.\n */\nexport const toPolyline = (\n  source: XYPosition,\n  target: XYPosition,\n  path: number[][],\n): XYPosition[] => {\n  const raw: XYPosition[] = [\n    { x: source.x, y: source.y },\n    ...path.map(([posX, posY]) => ({ x: posX, y: posY })),\n    { x: target.x, y: target.y },\n  ];\n\n  const deduped = raw.filter(\n    (point, index) =>\n      index === 0 ||\n      point.x !== raw[index - 1].x ||\n      point.y !== raw[index - 1].y,\n  );\n\n  const result: XYPosition[] = [];\n  for (let index = 0; index < deduped.length; index++) {\n    const current = deduped[index];\n    const hasNeighbors = index > 0 && index < deduped.length - 1;\n\n    if (hasNeighbors) {\n      const previous = result[result.length - 1];\n      const next = deduped[index + 1];\n      const collinearX = previous.x === current.x && current.x === next.x;\n      const collinearY = previous.y === current.y && current.y === next.y;\n      if (collinearX || collinearY) continue;\n    }\n\n    result.push(current);\n  }\n\n  return result;\n};\n\n/** Whether `value` lies strictly inside the open interval (bound1, bound2). */\nconst strictlyBetween = (\n  value: number,\n  bound1: number,\n  bound2: number,\n  epsilon: number,\n): boolean => {\n  const min = Math.min(bound1, bound2);\n  const max = Math.max(bound1, bound2);\n  return value > min + epsilon && value < max - epsilon;\n};\n\n/**\n * Crossing test for a horizontal segment of \"my\" polyline against a vertical\n * segment of another polyline.\n */\nconst horizontalCrossing = (\n  segmentStart: XYPosition,\n  segmentEnd: XYPosition,\n  otherStart: XYPosition,\n  otherEnd: XYPosition,\n  epsilon: number,\n  segmentIndex: number,\n): Hop | null => {\n  const crossX = otherStart.x;\n  const crossY = segmentStart.y;\n  if (\n    strictlyBetween(crossX, segmentStart.x, segmentEnd.x, epsilon) &&\n    strictlyBetween(crossY, otherStart.y, otherEnd.y, epsilon)\n  ) {\n    return { segmentIndex, at: Math.abs(crossX - segmentStart.x) };\n  }\n  return null;\n};\n\n/**\n * Crossing test for a vertical segment of \"my\" polyline against a horizontal\n * segment of another polyline.\n */\nconst verticalCrossing = (\n  segmentStart: XYPosition,\n  segmentEnd: XYPosition,\n  otherStart: XYPosition,\n  otherEnd: XYPosition,\n  epsilon: number,\n  segmentIndex: number,\n): Hop | null => {\n  const crossY = otherStart.y;\n  const crossX = segmentStart.x;\n  if (\n    strictlyBetween(crossY, segmentStart.y, segmentEnd.y, epsilon) &&\n    strictlyBetween(crossX, otherStart.x, otherEnd.x, epsilon)\n  ) {\n    return { segmentIndex, at: Math.abs(crossY - segmentStart.y) };\n  }\n  return null;\n};\n\n/** A single axis-aligned segment of \"my\" polyline being tested for crossings. */\ninterface MySegment {\n  start: XYPosition;\n  end: XYPosition;\n  index: number;\n  isHorizontal: boolean;\n  isVertical: boolean;\n}\n\n/**\n * Returns the hop where `segment` crosses a single other segment, or `null` for\n * any non-perpendicular pairing.\n */\nconst segmentPairHop = (\n  segment: MySegment,\n  otherStart: XYPosition,\n  otherEnd: XYPosition,\n  epsilon: number,\n): Hop | null => {\n  const otherHorizontal = Math.abs(otherStart.y - otherEnd.y) < epsilon;\n  const otherVertical = Math.abs(otherStart.x - otherEnd.x) < epsilon;\n\n  if (segment.isHorizontal && otherVertical && !otherHorizontal) {\n    return horizontalCrossing(\n      segment.start,\n      segment.end,\n      otherStart,\n      otherEnd,\n      epsilon,\n      segment.index,\n    );\n  }\n  if (segment.isVertical && otherHorizontal && !otherVertical) {\n    return verticalCrossing(\n      segment.start,\n      segment.end,\n      otherStart,\n      otherEnd,\n      epsilon,\n      segment.index,\n    );\n  }\n  return null;\n};\n\n/** Collects every hop where `segment` crosses one other polyline. */\nconst crossingsAgainst = (\n  segment: MySegment,\n  other: XYPosition[],\n  epsilon: number,\n): Hop[] => {\n  const hops: Hop[] = [];\n  for (let index = 0; index < other.length - 1; index++) {\n    const hop = segmentPairHop(\n      segment,\n      other[index],\n      other[index + 1],\n      epsilon,\n    );\n    if (hop) hops.push(hop);\n  }\n  return hops;\n};\n\n/**\n * Detects where an orthogonal polyline crosses other orthogonal polylines and\n * returns the hops to draw on it. Only strictly-interior perpendicular\n * crossings (a horizontal segment meeting a vertical one) produce a hop;\n * collinear overlaps, T-junctions at shared endpoints, and diagonal segments\n * are ignored.\n */\nexport const computeEdgeHops = (\n  polyline: XYPosition[],\n  otherPolylines: XYPosition[][],\n  epsilon: number = DEFAULT_HOP_EPSILON,\n): Hop[] => {\n  const hops: Hop[] = [];\n\n  for (let index = 0; index < polyline.length - 1; index++) {\n    const start = polyline[index];\n    const end = polyline[index + 1];\n    const segment: MySegment = {\n      start,\n      end,\n      index,\n      isHorizontal: Math.abs(start.y - end.y) < epsilon,\n      isVertical: Math.abs(start.x - end.x) < epsilon,\n    };\n    if (!segment.isHorizontal && !segment.isVertical) continue;\n\n    for (const other of otherPolylines) {\n      hops.push(...crossingsAgainst(segment, other, epsilon));\n    }\n  }\n\n  return hops;\n};\n","import type { Position, XYPosition } from \"@xyflow/react\";\nimport type { EndpointInfo } from \"./alignEndpoints\";\n\n/**\n * The four handle sides as plain string literals. `Position`'s enum values are\n * exactly these strings, so comparing against them avoids importing the\n * `@xyflow/react` runtime (and pulling React) into the Web Worker bundle.\n */\ntype HandleSide = \"top\" | \"right\" | \"bottom\" | \"left\";\n\n/**\n * Takes source and target `{x, y}` points, together with an array of number\n * tuples `[x, y]` representing the points along the path, and returns a string\n * to be used as the SVG path.\n */\nexport type SVGDrawFunction = (\n  source: XYPosition,\n  target: XYPosition,\n  path: number[][],\n) => string;\n\n/**\n * Like {@link SVGDrawFunction}, but requires handle positions on the endpoints\n * so cubic control points can mirror React Flow's `SimpleBezierEdge`.\n */\nexport type SVGSimpleBezierDrawFunction = (\n  source: EndpointInfo,\n  target: EndpointInfo,\n  path: number[][],\n) => string;\n\n/** Values accepted by {@link GetSmartEdgeOptions.drawEdge}. */\nexport type DrawEdgeFunction = SVGDrawFunction | SVGSimpleBezierDrawFunction;\n\ninterface SimpleBezierPoint extends XYPosition {\n  position: Position | HandleSide;\n}\n\nconst isHorizontalSide = (position: Position | HandleSide): boolean =>\n  position === \"left\" || position === \"right\";\n\n/**\n * Control point for a cubic segment, ported from xyflow's SimpleBezierEdge.\n * @see https://github.com/xyflow/xyflow/blob/main/packages/react/src/components/Edges/SimpleBezierEdge.tsx\n */\nconst getSimpleBezierControl = (\n  pos: Position | HandleSide,\n  fromX: number,\n  fromY: number,\n  toX: number,\n  toY: number,\n): [number, number] => {\n  if (isHorizontalSide(pos)) {\n    return [0.5 * (fromX + toX), fromY];\n  }\n\n  return [fromX, 0.5 * (fromY + toY)];\n};\n\n/** Infers a handle side from the dominant travel direction between two points. */\nconst inferHandlePosition = (\n  from: XYPosition,\n  toward: XYPosition,\n): HandleSide => {\n  const deltaX = toward.x - from.x;\n  const deltaY = toward.y - from.y;\n\n  if (Math.abs(deltaX) >= Math.abs(deltaY)) {\n    return deltaX >= 0 ? \"right\" : \"left\";\n  }\n\n  return deltaY >= 0 ? \"bottom\" : \"top\";\n};\n\nconst toSimpleBezierPoint = (\n  point: XYPosition,\n  prev: XYPosition,\n  next: XYPosition,\n): SimpleBezierPoint => ({\n  x: point.x,\n  y: point.y,\n  position: inferHandlePosition(prev, next),\n});\n\n/**\n * Draws an SVG path using chained cubic bezier segments with handle-position\n * controls, mirroring React Flow's SimpleBezierEdge.\n */\nexport const svgDrawSimpleBezierLinePath: SVGSimpleBezierDrawFunction = (\n  source,\n  target,\n  path,\n) => {\n  const waypoints = path.map(([posX, posY]) => ({ x: posX, y: posY }));\n  const allPoints: XYPosition[] = [source, ...waypoints, target];\n\n  const points: SimpleBezierPoint[] = allPoints.map((point, index) => {\n    if (index === 0) {\n      return source;\n    }\n    if (index === allPoints.length - 1) {\n      return target;\n    }\n\n    return toSimpleBezierPoint(\n      point,\n      allPoints[index - 1],\n      allPoints[index + 1],\n    );\n  });\n\n  let svgPath = `M${String(points[0].x)},${String(points[0].y)}`;\n\n  for (let index = 0; index < points.length - 1; index++) {\n    const from = points[index];\n    const targetPoint = points[index + 1];\n    const [sourceControlX, sourceControlY] = getSimpleBezierControl(\n      from.position,\n      from.x,\n      from.y,\n      targetPoint.x,\n      targetPoint.y,\n    );\n    const [targetControlX, targetControlY] = getSimpleBezierControl(\n      targetPoint.position,\n      targetPoint.x,\n      targetPoint.y,\n      from.x,\n      from.y,\n    );\n\n    svgPath += ` C${String(sourceControlX)},${String(sourceControlY)} ${String(targetControlX)},${String(targetControlY)} ${String(targetPoint.x)},${String(targetPoint.y)}`;\n  }\n\n  return svgPath;\n};\n\n/**\n * Draws a SVG path from a list of points, using straight lines.\n */\nexport const svgDrawStraightLinePath: SVGDrawFunction = (\n  source,\n  target,\n  path,\n) => {\n  let svgPathString = `M ${String(source.x)}, ${String(source.y)} `;\n\n  path.forEach((point) => {\n    const [posX, posY] = point;\n    svgPathString += `L ${String(posX)}, ${String(posY)} `;\n  });\n\n  svgPathString += `L ${String(target.x)}, ${String(target.y)} `;\n\n  return svgPathString;\n};\n\n/**\n * Draws a SVG path from a list of points, using rounded lines.\n */\nexport const svgDrawSmoothLinePath: SVGDrawFunction = (\n  source,\n  target,\n  path,\n) => {\n  const points = [[source.x, source.y], ...path, [target.x, target.y]];\n  return quadraticBezierCurve(points);\n};\n\nconst quadraticBezierCurve = (points: number[][]) => {\n  const axisX = 0;\n  const axisY = 1;\n  let point = points[0];\n\n  const first = points[0];\n  let svgPath = `M${String(first[axisX])},${String(first[axisY])}M`;\n\n  for (const next of points) {\n    const midPoint = getMidPoint(\n      point[axisX],\n      point[axisY],\n      next[axisX],\n      next[axisY],\n    );\n\n    svgPath += ` ${String(midPoint[axisX])},${String(midPoint[axisY])}`;\n    svgPath += `Q${String(next[axisX])},${String(next[axisY])}`;\n    point = next;\n  }\n\n  const last = points[points.length - 1];\n  svgPath += ` ${String(last[0])},${String(last[1])}`;\n\n  return svgPath;\n};\n\nconst getMidPoint = (\n  pointAx: number,\n  pointAy: number,\n  pointBx: number,\n  pointBy: number,\n) => {\n  const midX = (pointAx - pointBx) / 2 + pointBx;\n  const midY = (pointAy - pointBy) / 2 + pointBy;\n  return [midX, midY];\n};\n\nexport interface SmoothStepOptions {\n  borderRadius?: number;\n}\n\n/**\n * Returns a {@link SVGDrawFunction} that draws an orthogonal (\"step\") path with\n * rounded corners, mirroring React Flow's smooth step edge. The `borderRadius`\n * controls how much each corner is rounded (default `5`, matching React Flow);\n * it is clamped per-corner to half of the adjacent segment lengths so tight\n * grid corners never overshoot.\n *\n * Adapted from https://gist.github.com/holgergp/b95396f8e81abb17add1809c404b163c\n */\nexport const svgDrawSmoothStepLinePath = (\n  options: SmoothStepOptions = {},\n): SVGDrawFunction => {\n  const { borderRadius = 5 } = options;\n\n  return (source, target, path) => {\n    const points: XYPosition[] = dedupePoints([\n      { x: source.x, y: source.y },\n      ...path.map(([posX, posY]) => ({ x: posX, y: posY })),\n      { x: target.x, y: target.y },\n    ]);\n\n    return points.reduce((svgPath, point, index) => {\n      const isInteriorPoint = index > 0 && index < points.length - 1;\n\n      if (isInteriorPoint) {\n        return (\n          svgPath +\n          getBend(points[index - 1], point, points[index + 1], borderRadius)\n        );\n      }\n\n      const command = index === 0 ? \"M\" : \"L\";\n      return svgPath + `${command} ${String(point.x)},${String(point.y)} `;\n    }, \"\");\n  };\n};\n\nconst distance = (first: XYPosition, second: XYPosition) =>\n  Math.sqrt(Math.pow(second.x - first.x, 2) + Math.pow(second.y - first.y, 2));\n\n/**\n * Drops consecutive duplicate points so corner rounding doesn't produce\n * degenerate (zero-length) bends. The endpoint alignment step can repeat the\n * source/target coordinate as the first/last path point.\n */\nconst dedupePoints = (points: XYPosition[]) =>\n  points.filter(\n    (point, index) =>\n      index === 0 ||\n      point.x !== points[index - 1].x ||\n      point.y !== points[index - 1].y,\n  );\n\nconst getBend = (\n  pointA: XYPosition,\n  pointB: XYPosition,\n  pointC: XYPosition,\n  size: number,\n): string => {\n  const bendSize = Math.min(\n    distance(pointA, pointB) / 2,\n    distance(pointB, pointC) / 2,\n    size,\n  );\n  const { x: cornerX, y: cornerY } = pointB;\n\n  // Collinear points: no corner to round.\n  if (\n    (pointA.x === cornerX && cornerX === pointC.x) ||\n    (pointA.y === cornerY && cornerY === pointC.y)\n  ) {\n    return `L ${String(cornerX)},${String(cornerY)} `;\n  }\n\n  // First segment is horizontal.\n  if (pointA.y === cornerY) {\n    const xDir = pointA.x < pointC.x ? -1 : 1;\n    const yDir = pointA.y < pointC.y ? 1 : -1;\n    return `L ${String(cornerX + bendSize * xDir)},${String(cornerY)}Q ${String(cornerX)},${String(cornerY)} ${String(cornerX)},${String(cornerY + bendSize * yDir)} `;\n  }\n\n  // First segment is vertical.\n  const xDir = pointA.x < pointC.x ? 1 : -1;\n  const yDir = pointA.y < pointC.y ? -1 : 1;\n  return `L ${String(cornerX)},${String(cornerY + bendSize * yDir)}Q ${String(cornerX)},${String(cornerY)} ${String(cornerX + bendSize * xDir)},${String(cornerY)} `;\n};\n","import type { XYPosition } from \"@xyflow/react\";\nimport type { Hop } from \"./edgeHops\";\n\n/** Options for {@link drawOrthogonalHopPath}. */\nexport interface OrthogonalHopOptions {\n  /** Radius of the bridge arc drawn at each crossing. Default `6`. */\n  hopRadius?: number;\n  /**\n   * Corner rounding radius. `0` (default) yields sharp step corners; a positive\n   * value rounds corners like React Flow's smooth-step edge.\n   */\n  borderRadius?: number;\n}\n\nconst DEFAULT_HOP_RADIUS = 6;\n\nconst pointDistance = (first: XYPosition, second: XYPosition): number =>\n  Math.sqrt(Math.pow(second.x - first.x, 2) + Math.pow(second.y - first.y, 2));\n\n/**\n * The rounded-corner trim at a vertex, clamped to half of each adjacent\n * segment so corners never overshoot. Returns `0` for collinear points (no\n * corner to round). Mirrors the bend sizing used by the smooth-step drawer.\n */\nconst cornerBendSize = (\n  previous: XYPosition,\n  corner: XYPosition,\n  next: XYPosition,\n  radius: number,\n): number => {\n  const collinear =\n    (previous.x === corner.x && corner.x === next.x) ||\n    (previous.y === corner.y && corner.y === next.y);\n  if (collinear) return 0;\n  return Math.min(\n    pointDistance(previous, corner) / 2,\n    pointDistance(corner, next) / 2,\n    radius,\n  );\n};\n\n/**\n * Returns the point `amount` px from `origin` toward `toward`. Only called with\n * a positive corner bend size, which is itself clamped to half the segment\n * length, so the two points are always distinct.\n */\nconst movePointToward = (\n  origin: XYPosition,\n  toward: XYPosition,\n  amount: number,\n): XYPosition => {\n  const ratio = amount / pointDistance(origin, toward);\n  return {\n    x: origin.x + (toward.x - origin.x) * ratio,\n    y: origin.y + (toward.y - origin.y) * ratio,\n  };\n};\n\n/** SVG arc sweep flag keeping every bump on the same side of the wire. */\nconst sweepFor = (\n  orientation: \"horizontal\" | \"vertical\",\n  direction: 1 | -1,\n): 0 | 1 => {\n  if (orientation === \"horizontal\") return direction === 1 ? 1 : 0;\n  return direction === 1 ? 0 : 1;\n};\n\ninterface AxisSegment {\n  /** The constant coordinate of the segment (y for horizontal, x for vertical). */\n  fixed: number;\n  /** The varying coordinate at the segment's start. */\n  start: number;\n  /** The varying coordinate at the segment's end. */\n  end: number;\n}\n\n/**\n * Draws one axis-aligned segment (already trimmed for rounded corners),\n * inserting a small arc \"bridge\" at each crossing. Hops too close to a trimmed\n * corner or the segment ends are skipped rather than drawn over the rounding.\n */\nconst drawAxisSegment = (\n  line: AxisSegment,\n  segmentHops: Hop[],\n  hopRadius: number,\n  bendStart: number,\n  bendEnd: number,\n  orientation: \"horizontal\" | \"vertical\",\n): string => {\n  const direction: 1 | -1 = line.end >= line.start ? 1 : -1;\n  const drawFrom = line.start + direction * bendStart;\n  const drawTo = line.end - direction * bendEnd;\n\n  const pointAt = (along: number): string =>\n    orientation === \"horizontal\"\n      ? `${String(along)},${String(line.fixed)}`\n      : `${String(line.fixed)},${String(along)}`;\n\n  let svg = \"\";\n  for (const hop of segmentHops) {\n    const crossing = line.start + direction * hop.at;\n    const before = crossing - direction * hopRadius;\n    const after = crossing + direction * hopRadius;\n    const clearsCorners =\n      direction * (before - drawFrom) > 0 && direction * (drawTo - after) > 0;\n    if (clearsCorners) {\n      svg += `L ${pointAt(before)} `;\n      svg += `A ${String(hopRadius)} ${String(hopRadius)} 0 0 ${String(sweepFor(orientation, direction))} ${pointAt(after)} `;\n    }\n  }\n  svg += `L ${pointAt(drawTo)} `;\n  return svg;\n};\n\n/**\n * Draws an orthogonal (\"step\") SVG path through `points`, optionally rounding\n * corners (`borderRadius`) and drawing a small bridge arc at every crossing in\n * `hops`. With an empty `hops` list and `borderRadius` of `0` this is\n * equivalent to a plain step path; with `borderRadius > 0` it matches the\n * smooth-step look while still bridging crossings.\n *\n * `points` must be the full polyline including the source and target endpoints,\n * and each `hop`'s segment index must refer to a segment of that same polyline\n * (see {@link toPolyline} and {@link computeEdgeHops}).\n */\nexport const drawOrthogonalHopPath = (\n  points: XYPosition[],\n  hops: Hop[],\n  options: OrthogonalHopOptions = {},\n): string => {\n  const { hopRadius = DEFAULT_HOP_RADIUS, borderRadius = 0 } = options;\n  if (points.length === 0) return \"\";\n\n  let svgPath = `M ${String(points[0].x)},${String(points[0].y)} `;\n\n  for (let index = 0; index < points.length - 1; index++) {\n    const start = points[index];\n    const end = points[index + 1];\n\n    const bendStart =\n      borderRadius > 0 && index > 0\n        ? cornerBendSize(points[index - 1], start, end, borderRadius)\n        : 0;\n    const bendEnd =\n      borderRadius > 0 && index < points.length - 2\n        ? cornerBendSize(start, end, points[index + 2], borderRadius)\n        : 0;\n\n    const segmentHops = hops\n      .filter((hop) => hop.segmentIndex === index)\n      .sort((first, second) => first.at - second.at);\n\n    const isHorizontal = Math.abs(end.y - start.y) <= Math.abs(end.x - start.x);\n    const line: AxisSegment = isHorizontal\n      ? { fixed: start.y, start: start.x, end: end.x }\n      : { fixed: start.x, start: start.y, end: end.y };\n\n    svgPath += drawAxisSegment(\n      line,\n      segmentHops,\n      hopRadius,\n      bendStart,\n      bendEnd,\n      isHorizontal ? \"horizontal\" : \"vertical\",\n    );\n\n    if (bendEnd > 0) {\n      const exit = movePointToward(end, points[index + 2], bendEnd);\n      svgPath += `Q ${String(end.x)},${String(end.y)} ${String(exit.x)},${String(exit.y)} `;\n    }\n  }\n\n  return svgPath;\n};\n","/**\n * Array-backed binary min-heap of integer ids scored by numbers. Used as the\n * A-star/JPS open list. Decrease-key is handled lazily: callers push a duplicate\n * entry with the better score and skip stale pops via their closed check.\n */\nexport interface MinHeap {\n  push(id: number, score: number): void;\n  /** The id with the lowest score, or `-1` when empty. */\n  pop(): number;\n  readonly size: number;\n}\n\nexport const createMinHeap = (): MinHeap => {\n  const ids: number[] = [];\n  const scores: number[] = [];\n\n  const swap = (indexA: number, indexB: number): void => {\n    const itemId = ids[indexA];\n    ids[indexA] = ids[indexB];\n    ids[indexB] = itemId;\n    const score = scores[indexA];\n    scores[indexA] = scores[indexB];\n    scores[indexB] = score;\n  };\n\n  const siftUp = (start: number): void => {\n    let index = start;\n    while (index > 0) {\n      const parent = (index - 1) >> 1;\n      if (scores[parent] <= scores[index]) break;\n      swap(parent, index);\n      index = parent;\n    }\n  };\n\n  const siftDown = (start: number): void => {\n    let index = start;\n    for (;;) {\n      const left = index * 2 + 1;\n      const right = left + 1;\n      let smallest = index;\n      if (left < ids.length && scores[left] < scores[smallest]) smallest = left;\n      if (right < ids.length && scores[right] < scores[smallest])\n        smallest = right;\n      if (smallest === index) break;\n      swap(smallest, index);\n      index = smallest;\n    }\n  };\n\n  return {\n    push: (itemId, score) => {\n      ids.push(itemId);\n      scores.push(score);\n      siftUp(ids.length - 1);\n    },\n    pop: () => {\n      if (ids.length === 0) return -1;\n      const top = ids[0];\n      const lastItemId = ids[ids.length - 1];\n      const lastItemScore = scores[ids.length - 1];\n      ids.length -= 1;\n      scores.length -= 1;\n      if (ids.length > 0) {\n        ids[0] = lastItemId;\n        scores[0] = lastItemScore;\n        siftDown(0);\n      }\n      return top;\n    },\n    get size() {\n      return ids.length;\n    },\n  };\n};\n","/**\n * Reusable search buffers shared by the flat A* and JPS finders. Buffers are\n * module-level and grown on demand; a per-search `generation` stamp in `mark`\n * makes stale data invisible without clearing, so repeated searches allocate\n * nothing.\n */\nexport interface SearchScratch {\n  /** Cost from start (valid when `mark[i] === generation`). */\n  g: Float64Array;\n  /** Parent cell index, `-1` for the start (valid when marked). */\n  parent: Int32Array;\n  /** 0 = untouched, STATE_OPEN, STATE_CLOSED (valid when marked). */\n  state: Uint8Array;\n  /** Generation stamp per cell. */\n  mark: Int32Array;\n  generation: number;\n}\n\nexport const STATE_OPEN = 1;\nexport const STATE_CLOSED = 2;\n\nlet buffers: SearchScratch = {\n  g: new Float64Array(0),\n  parent: new Int32Array(0),\n  state: new Uint8Array(0),\n  mark: new Int32Array(0),\n  generation: 0,\n};\n\nexport const acquireScratch = (size: number): SearchScratch => {\n  if (buffers.g.length < size) {\n    buffers = {\n      g: new Float64Array(size),\n      parent: new Int32Array(size),\n      state: new Uint8Array(size),\n      // New Int32Array is zero-filled; starting generation at 1 keeps every\n      // cell \"unmarked\" without an explicit fill.\n      mark: new Int32Array(size),\n      generation: buffers.generation,\n    };\n  }\n  buffers.generation += 1;\n  return buffers;\n};\n\n/** Lazily initializes a cell for the current generation. */\nexport const touch = (scratch: SearchScratch, index: number): void => {\n  if (scratch.mark[index] === scratch.generation) return;\n  scratch.mark[index] = scratch.generation;\n  scratch.g[index] = Number.POSITIVE_INFINITY;\n  scratch.parent[index] = -1;\n  scratch.state[index] = 0;\n};\n\n/** Walks `parent` links from the end index back to the start. */\nexport const reconstructPath = (\n  scratch: SearchScratch,\n  endIndex: number,\n  width: number,\n): number[][] => {\n  const path: number[][] = [];\n  let index = endIndex;\n  while (index !== -1) {\n    path.push([index % width, Math.floor(index / width)]);\n    index = scratch.parent[index];\n  }\n  return path.reverse();\n};\n","import { createMinHeap } from \"./binaryHeap\";\nimport { isWalkable } from \"./flatGrid\";\nimport type { FlatGrid } from \"./flatGrid\";\nimport {\n  acquireScratch,\n  reconstructPath,\n  touch,\n  STATE_CLOSED,\n  STATE_OPEN,\n  type SearchScratch,\n} from \"./searchScratch\";\n\nconst manhattan = (deltaX: number, deltaY: number): number => deltaX + deltaY;\n\nconst octile = (deltaX: number, deltaY: number): number => {\n  const diagonalFactor = Math.SQRT2 - 1;\n  return deltaX < deltaY\n    ? diagonalFactor * deltaX + deltaY\n    : diagonalFactor * deltaY + deltaX;\n};\n\n/** Orthogonal neighbors first, then diagonals — same order as the old grid. */\nconst NEIGHBOR_STEPS: readonly (readonly [number, number, number])[] = [\n  [0, -1, 1],\n  [1, 0, 1],\n  [0, 1, 1],\n  [-1, 0, 1],\n  [1, -1, Math.SQRT2],\n  [1, 1, Math.SQRT2],\n  [-1, 1, Math.SQRT2],\n  [-1, -1, Math.SQRT2],\n];\n\ninterface NeighborProcessContext {\n  scratch: SearchScratch;\n  grid: FlatGrid;\n  endX: number;\n  endY: number;\n  width: number;\n  heuristic: (deltaX: number, deltaY: number) => number;\n  open: ReturnType<typeof createMinHeap>;\n}\n\n/** Process a neighbor cell, updating scratch and open list if the path is better. */\nconst processNeighbor = (\n  context: NeighborProcessContext,\n  currentIndex: number,\n  neighborStepIndex: number,\n  currentX: number,\n  currentY: number,\n): void => {\n  const { scratch, grid, endX, endY, width, heuristic, open } = context;\n  const [stepX, stepY, cost] = NEIGHBOR_STEPS[neighborStepIndex];\n  const neighborColumn = currentX + stepX;\n  const neighborRow = currentY + stepY;\n\n  if (!isWalkable(grid, neighborColumn, neighborRow)) return;\n\n  const neighbor = neighborRow * width + neighborColumn;\n  touch(scratch, neighbor);\n\n  if (scratch.state[neighbor] === STATE_CLOSED) return;\n\n  const tentativeG = scratch.g[currentIndex] + cost;\n  if (tentativeG >= scratch.g[neighbor]) return;\n\n  scratch.g[neighbor] = tentativeG;\n  scratch.parent[neighbor] = currentIndex;\n  scratch.state[neighbor] = STATE_OPEN;\n  const estimated =\n    tentativeG +\n    heuristic(Math.abs(neighborColumn - endX), Math.abs(neighborRow - endY));\n  open.push(neighbor, estimated);\n};\n\n/**\n * A* on a flat grid. Returns `[x, y]` pairs from start to end inclusive, or an\n * empty array when unreachable. Heuristics and step costs match the old\n * object-grid finder so routed paths keep their v4 shapes.\n */\nexport const findPathAStar = (\n  grid: FlatGrid,\n  startX: number,\n  startY: number,\n  endX: number,\n  endY: number,\n  diagonal: boolean,\n): number[][] => {\n  if (!isWalkable(grid, startX, startY) || !isWalkable(grid, endX, endY)) {\n    return [];\n  }\n\n  const { width } = grid;\n  const scratch = acquireScratch(width * grid.height);\n  const heuristic = diagonal ? octile : manhattan;\n  const neighborCount = diagonal ? 8 : 4;\n\n  const startIndex = startY * width + startX;\n  const endIndex = endY * width + endX;\n\n  const open = createMinHeap();\n  touch(scratch, startIndex);\n  scratch.g[startIndex] = 0;\n  scratch.state[startIndex] = STATE_OPEN;\n  open.push(startIndex, 0);\n\n  const context: NeighborProcessContext = {\n    scratch,\n    grid,\n    endX,\n    endY,\n    width,\n    heuristic,\n    open,\n  };\n\n  while (open.size > 0) {\n    const current = open.pop();\n    if (scratch.state[current] === STATE_CLOSED) continue; // stale duplicate\n    scratch.state[current] = STATE_CLOSED;\n\n    if (current === endIndex) {\n      return reconstructPath(scratch, endIndex, width);\n    }\n\n    const currentX = current % width;\n    const currentY = Math.floor(current / width);\n\n    for (let idx = 0; idx < neighborCount; idx++) {\n      processNeighbor(context, current, idx, currentX, currentY);\n    }\n  }\n\n  return [];\n};\n","// Orthogonal Jump Point Search on a flat grid.\n// Algorithm based on PathFinding.js (MIT) — https://github.com/qiao/PathFinding.js\n\nimport { createMinHeap } from \"./binaryHeap\";\nimport { isWalkable } from \"./flatGrid\";\nimport type { FlatGrid } from \"./flatGrid\";\nimport {\n  acquireScratch,\n  reconstructPath,\n  touch,\n  STATE_CLOSED,\n  STATE_OPEN,\n} from \"./searchScratch\";\nimport type { SearchScratch } from \"./searchScratch\";\n\nconst manhattan = (deltaX: number, deltaY: number): number => deltaX + deltaY;\n\nconst pushNeighbor = (\n  grid: FlatGrid,\n  out: number[][],\n  column: number,\n  row: number,\n): void => {\n  if (isWalkable(grid, column, row)) out.push([column, row]);\n};\n\n/**\n * Pruned neighbors given the direction of travel from the parent.\n * Returns only walkable cells that are part of the search direction.\n */\nconst findNeighbors = (\n  grid: FlatGrid,\n  scratch: SearchScratch,\n  index: number,\n): number[][] => {\n  const width = grid.width;\n  const column = index % width;\n  const row = Math.floor(index / width);\n  const parent = scratch.parent[index];\n  const neighbors: number[][] = [];\n\n  if (parent === -1) {\n    pushNeighbor(grid, neighbors, column, row - 1);\n    pushNeighbor(grid, neighbors, column + 1, row);\n    pushNeighbor(grid, neighbors, column, row + 1);\n    pushNeighbor(grid, neighbors, column - 1, row);\n    return neighbors;\n  }\n\n  const parentColumn = parent % width;\n  const parentRow = Math.floor(parent / width);\n  const deltaX =\n    (column - parentColumn) / Math.max(Math.abs(column - parentColumn), 1);\n  const deltaY = (row - parentRow) / Math.max(Math.abs(row - parentRow), 1);\n\n  // Movement is orthogonal-only, so a node can only ever differ from its\n  // parent along a single axis: deltaX !== 0 XOR deltaY !== 0. The vertical\n  // case is therefore the unconditional fallback rather than an `else if`.\n  if (deltaX !== 0) {\n    pushNeighbor(grid, neighbors, column, row - 1);\n    pushNeighbor(grid, neighbors, column, row + 1);\n    pushNeighbor(grid, neighbors, column + deltaX, row);\n  } else {\n    pushNeighbor(grid, neighbors, column - 1, row);\n    pushNeighbor(grid, neighbors, column + 1, row);\n    pushNeighbor(grid, neighbors, column, row + deltaY);\n  }\n\n  return neighbors;\n};\n\nconst hasForcedNeighborHorizontal = (\n  grid: FlatGrid,\n  column: number,\n  row: number,\n  deltaX: number,\n): boolean =>\n  (isWalkable(grid, column, row - 1) &&\n    !isWalkable(grid, column - deltaX, row - 1)) ||\n  (isWalkable(grid, column, row + 1) &&\n    !isWalkable(grid, column - deltaX, row + 1));\n\nconst hasForcedNeighborVertical = (\n  grid: FlatGrid,\n  column: number,\n  row: number,\n  deltaY: number,\n): boolean =>\n  (isWalkable(grid, column - 1, row) &&\n    !isWalkable(grid, column - 1, row - deltaY)) ||\n  (isWalkable(grid, column + 1, row) &&\n    !isWalkable(grid, column + 1, row - deltaY));\n\nconst createJump = (grid: FlatGrid, endColumn: number, endRow: number) => {\n  const jump = (\n    column: number,\n    row: number,\n    parentColumn: number,\n    parentRow: number,\n  ): number[] | null => {\n    if (!isWalkable(grid, column, row)) return null;\n    if (column === endColumn && row === endRow) return [column, row];\n\n    const deltaX = column - parentColumn;\n    const deltaY = row - parentRow;\n\n    if (\n      deltaX !== 0 &&\n      hasForcedNeighborHorizontal(grid, column, row, deltaX)\n    ) {\n      return [column, row];\n    }\n\n    if (deltaY !== 0) {\n      if (hasForcedNeighborVertical(grid, column, row, deltaY)) {\n        return [column, row];\n      }\n      if (\n        jump(column + 1, row, column, row) ??\n        jump(column - 1, row, column, row)\n      ) {\n        return [column, row];\n      }\n    }\n\n    return jump(column + deltaX, row + deltaY, column, row);\n  };\n\n  return jump;\n};\n\ninterface ProcessJumpContext {\n  scratch: SearchScratch;\n  endColumn: number;\n  endRow: number;\n  width: number;\n  jump: (\n    col: number,\n    row: number,\n    parentCol: number,\n    parentRow: number,\n  ) => number[] | null;\n  open: ReturnType<typeof createMinHeap>;\n}\n\nconst processJumpNeighbor = (\n  context: ProcessJumpContext,\n  currentIndex: number,\n  neighborColumn: number,\n  neighborRow: number,\n  currentColumn: number,\n  currentRow: number,\n): void => {\n  const { scratch, endColumn, endRow, width, jump, open } = context;\n\n  const jumpPoint = jump(\n    neighborColumn,\n    neighborRow,\n    currentColumn,\n    currentRow,\n  );\n  if (!jumpPoint) return;\n\n  const [jumpColumn, jumpRow] = jumpPoint;\n  const jumpIndex = jumpRow * width + jumpColumn;\n  touch(scratch, jumpIndex);\n  if (scratch.state[jumpIndex] === STATE_CLOSED) return;\n\n  const stepCost = manhattan(\n    Math.abs(jumpColumn - currentColumn),\n    Math.abs(jumpRow - currentRow),\n  );\n  const tentativeG = scratch.g[currentIndex] + stepCost;\n  if (tentativeG >= scratch.g[jumpIndex]) return;\n\n  scratch.g[jumpIndex] = tentativeG;\n  scratch.parent[jumpIndex] = currentIndex;\n  scratch.state[jumpIndex] = STATE_OPEN;\n  open.push(\n    jumpIndex,\n    tentativeG +\n      manhattan(Math.abs(jumpColumn - endColumn), Math.abs(jumpRow - endRow)),\n  );\n};\n\n/**\n * Orthogonal Jump Point Search on a flat grid. Returns jump points only\n * (expanded to full cell sequence downstream by alignEndpoints/draw functions).\n * Empty array when unreachable.\n */\nexport const findPathJumpPoint = (\n  grid: FlatGrid,\n  startColumn: number,\n  startRow: number,\n  endColumn: number,\n  endRow: number,\n): number[][] => {\n  if (\n    !isWalkable(grid, startColumn, startRow) ||\n    !isWalkable(grid, endColumn, endRow)\n  ) {\n    return [];\n  }\n\n  const width = grid.width;\n  const scratch = acquireScratch(width * grid.height);\n  const startIndex = startRow * width + startColumn;\n  const endIndex = endRow * width + endColumn;\n  const open = createMinHeap();\n  const jump = createJump(grid, endColumn, endRow);\n\n  touch(scratch, startIndex);\n  scratch.g[startIndex] = 0;\n  scratch.state[startIndex] = STATE_OPEN;\n  open.push(startIndex, 0);\n\n  const context: ProcessJumpContext = {\n    scratch,\n    endColumn,\n    endRow,\n    width,\n    jump,\n    open,\n  };\n\n  while (open.size > 0) {\n    const current = open.pop();\n    if (scratch.state[current] === STATE_CLOSED) continue;\n    scratch.state[current] = STATE_CLOSED;\n\n    if (current === endIndex) {\n      return reconstructPath(scratch, endIndex, width);\n    }\n\n    const currentColumn = current % width;\n    const currentRow = Math.floor(current / width);\n\n    for (const [neighborColumn, neighborRow] of findNeighbors(\n      grid,\n      scratch,\n      current,\n    )) {\n      processJumpNeighbor(\n        context,\n        current,\n        neighborColumn,\n        neighborRow,\n        currentColumn,\n        currentRow,\n      );\n    }\n  }\n\n  return [];\n};\n","import { findPathAStar } from \"../pathfinding/flatAStar\";\nimport { findPathJumpPoint } from \"../pathfinding/flatJumpPoint\";\nimport type { FlatGrid } from \"../pathfinding/flatGrid\";\nimport type { XYPosition } from \"@xyflow/react\";\n\n/**\n * Takes source and target {x, y} points, together with a flat grid\n * representation of the graph, and returns an array of number tuples [x, y],\n * representing the full path from source to target.\n */\nexport type PathFindingFunction = (\n  grid: FlatGrid,\n  start: XYPosition,\n  end: XYPosition,\n) => number[][];\n\nexport const NO_PATH_FOUND_ERROR = \"No path found\";\n\nexport const pathfindingAStarDiagonal: PathFindingFunction = (\n  grid,\n  start,\n  end,\n) => {\n  const fullPath = findPathAStar(grid, start.x, start.y, end.x, end.y, true);\n  if (fullPath.length === 0) {\n    throw new Error(NO_PATH_FOUND_ERROR);\n  }\n  return fullPath;\n};\n\nexport const pathfindingAStarNoDiagonal: PathFindingFunction = (\n  grid,\n  start,\n  end,\n) => {\n  const fullPath = findPathAStar(grid, start.x, start.y, end.x, end.y, false);\n  if (fullPath.length === 0) {\n    throw new Error(NO_PATH_FOUND_ERROR);\n  }\n  return fullPath;\n};\n\nexport const pathfindingJumpPointNoDiagonal: PathFindingFunction = (\n  grid,\n  start,\n  end,\n) => {\n  const jumpPointPath = findPathJumpPoint(grid, start.x, start.y, end.x, end.y);\n  if (jumpPointPath.length === 0) {\n    throw new Error(NO_PATH_FOUND_ERROR);\n  }\n  return jumpPointPath;\n};\n","import { roundUp, roundDown } from \"./utils\";\nimport type { Node, Rect, XYPosition } from \"@xyflow/react\";\n\nexport interface NodeBoundingBox {\n  id: string;\n  width: number;\n  height: number;\n  topLeft: XYPosition;\n  bottomLeft: XYPosition;\n  topRight: XYPosition;\n  bottomRight: XYPosition;\n}\n\nexport interface GraphBoundingBox {\n  width: number;\n  height: number;\n  topLeft: XYPosition;\n  bottomLeft: XYPosition;\n  topRight: XYPosition;\n  bottomRight: XYPosition;\n  xMax: number;\n  yMax: number;\n  xMin: number;\n  yMin: number;\n}\n\n/**\n * Build the padded corner points of a rectangle, applying the same rounding\n * rules used for both nodes and avoid areas so they create consistent\n * obstacles on the path-finding grid.\n */\nconst buildBox = (\n  originX: number,\n  originY: number,\n  width: number,\n  height: number,\n  nodePadding: number,\n  roundTo: number,\n) => {\n  const topLeft: XYPosition = {\n    x: originX - nodePadding,\n    y: originY - nodePadding,\n  };\n  const bottomLeft: XYPosition = {\n    x: originX - nodePadding,\n    y: originY + height + nodePadding,\n  };\n  const topRight: XYPosition = {\n    x: originX + width + nodePadding,\n    y: originY - nodePadding,\n  };\n  const bottomRight: XYPosition = {\n    x: originX + width + nodePadding,\n    y: originY + height + nodePadding,\n  };\n\n  if (roundTo > 0) {\n    topLeft.x = roundDown(topLeft.x, roundTo);\n    topLeft.y = roundDown(topLeft.y, roundTo);\n    bottomLeft.x = roundDown(bottomLeft.x, roundTo);\n    bottomLeft.y = roundUp(bottomLeft.y, roundTo);\n    topRight.x = roundUp(topRight.x, roundTo);\n    topRight.y = roundDown(topRight.y, roundTo);\n    bottomRight.x = roundUp(bottomRight.x, roundTo);\n    bottomRight.y = roundUp(bottomRight.y, roundTo);\n  }\n\n  return { topLeft, bottomLeft, topRight, bottomRight };\n};\n\n/**\n * Get the bounding box of all nodes and the graph itself, as X/Y coordinates\n * of all corner points. Consumer-provided `avoidAreas` are treated as extra\n * obstacles with the same `nodePadding` clearance as nodes.\n *\n * `extraPoints` are coordinates (e.g. the edge's source/target or any\n * waypoints) that must fall inside the graph box even when they sit beyond the\n * nodes, so the path-finding grid always covers them.\n */\nexport const getBoundingBoxes = (\n  nodes: Node[],\n  nodePadding = 2,\n  roundTo = 2,\n  avoidAreas: Rect[] = [],\n  extraPoints: XYPosition[] = [],\n) => {\n  let xMax = Number.MIN_SAFE_INTEGER;\n  let yMax = Number.MIN_SAFE_INTEGER;\n  let xMin = Number.MAX_SAFE_INTEGER;\n  let yMin = Number.MAX_SAFE_INTEGER;\n\n  const expandBounds = (topLeft: XYPosition, bottomRight: XYPosition) => {\n    if (topLeft.y < yMin) yMin = topLeft.y;\n    if (topLeft.x < xMin) xMin = topLeft.x;\n    if (bottomRight.y > yMax) yMax = bottomRight.y;\n    if (bottomRight.x > xMax) xMax = bottomRight.x;\n  };\n\n  const nodeBoxes: NodeBoundingBox[] = nodes.map((node) => {\n    const width = Math.max(node.measured?.width ?? 0, 1);\n    const height = Math.max(node.measured?.height ?? 0, 1);\n\n    const { topLeft, bottomLeft, topRight, bottomRight } = buildBox(\n      node.position.x,\n      node.position.y,\n      width,\n      height,\n      nodePadding,\n      roundTo,\n    );\n\n    expandBounds(topLeft, bottomRight);\n\n    return {\n      id: node.id,\n      width,\n      height,\n      topLeft,\n      bottomLeft,\n      topRight,\n      bottomRight,\n    };\n  });\n\n  const avoidBoxes: NodeBoundingBox[] = avoidAreas.map((area, index) => {\n    const width = Math.max(area.width, 1);\n    const height = Math.max(area.height, 1);\n\n    const { topLeft, bottomLeft, topRight, bottomRight } = buildBox(\n      area.x,\n      area.y,\n      width,\n      height,\n      nodePadding,\n      roundTo,\n    );\n\n    expandBounds(topLeft, bottomRight);\n\n    return {\n      id: `avoid-${String(index)}`,\n      width,\n      height,\n      topLeft,\n      bottomLeft,\n      topRight,\n      bottomRight,\n    };\n  });\n\n  // Make sure the graph box also contains any explicit points (edge endpoints\n  // and waypoints), even when they sit outside every node.\n  extraPoints.forEach((point) => {\n    expandBounds(point, point);\n  });\n\n  const graphPadding = nodePadding * 2;\n\n  xMax = roundUp(xMax + graphPadding, roundTo);\n  yMax = roundUp(yMax + graphPadding, roundTo);\n  xMin = roundDown(xMin - graphPadding, roundTo);\n  yMin = roundDown(yMin - graphPadding, roundTo);\n\n  const topLeft: XYPosition = {\n    x: xMin,\n    y: yMin,\n  };\n\n  const bottomLeft: XYPosition = {\n    x: xMin,\n    y: yMax,\n  };\n\n  const topRight: XYPosition = {\n    x: xMax,\n    y: yMin,\n  };\n\n  const bottomRight: XYPosition = {\n    x: xMax,\n    y: yMax,\n  };\n\n  const width = Math.abs(topLeft.x - topRight.x);\n  const height = Math.abs(topLeft.y - bottomLeft.y);\n\n  const graphBox: GraphBoundingBox = {\n    topLeft,\n    bottomLeft,\n    topRight,\n    bottomRight,\n    width,\n    height,\n    xMax,\n    yMax,\n    xMin,\n    yMin,\n  };\n\n  return { nodeBoxes, graphBox, avoidBoxes };\n};\n","import { Position } from \"@xyflow/react\";\nimport type { Node, XYPosition } from \"@xyflow/react\";\n\n/**\n * The dynamic connection parameters for a floating edge: the source/target\n * intersection coordinates on each node's border, plus the side (position) of\n * the node those points sit on.\n */\nexport interface FloatingEdgeParams {\n  sx: number;\n  sy: number;\n  tx: number;\n  ty: number;\n  sourcePos: Position;\n  targetPos: Position;\n}\n\nconst getNodeRect = (node: Node) => {\n  const width = Math.max(node.measured?.width ?? 0, 1);\n  const height = Math.max(node.measured?.height ?? 0, 1);\n  return { x: node.position.x, y: node.position.y, width, height };\n};\n\n/**\n * Returns the point where the straight line between the centers of\n * `intersectionNode` and `otherNode` crosses the border of `intersectionNode`.\n *\n * Ported from React Flow's Floating Edges example\n * (https://reactflow.dev/examples/edges/floating-edges), adapted to this\n * library's `Node` shape (`measured` dimensions + absolute `position`).\n */\nexport const getNodeIntersection = (\n  intersectionNode: Node,\n  otherNode: Node,\n): XYPosition => {\n  const intersection = getNodeRect(intersectionNode);\n  const other = getNodeRect(otherNode);\n\n  const halfWidth = intersection.width / 2;\n  const halfHeight = intersection.height / 2;\n\n  const intersectionRight = intersection.x + halfWidth;\n  const intersectionBottom = intersection.y + halfHeight;\n  const otherCenterX = other.x + other.width / 2;\n  const otherCenterY = other.y + other.height / 2;\n\n  const normalizedX =\n    (otherCenterX - intersectionRight) / (2 * halfWidth) -\n    (otherCenterY - intersectionBottom) / (2 * halfHeight);\n  const normalizedY =\n    (otherCenterX - intersectionRight) / (2 * halfWidth) +\n    (otherCenterY - intersectionBottom) / (2 * halfHeight);\n  const scale = 1 / (Math.abs(normalizedX) + Math.abs(normalizedY) || 1);\n  const scaledX = scale * normalizedX;\n  const scaledY = scale * normalizedY;\n  const intersectionX = halfWidth * (scaledX + scaledY) + intersectionRight;\n  const intersectionY = halfHeight * (-scaledX + scaledY) + intersectionBottom;\n\n  return { x: intersectionX, y: intersectionY };\n};\n\n/**\n * Returns the side of `node` (top/right/bottom/left) that `intersectionPoint`\n * sits on, used as the handle position fed into the pathfinding pipeline.\n */\nexport const getEdgePosition = (\n  node: Node,\n  intersectionPoint: XYPosition,\n): Position => {\n  const { x, y, width, height } = getNodeRect(node);\n  const nodeX = Math.round(x);\n  const nodeY = Math.round(y);\n  const pointX = Math.round(intersectionPoint.x);\n  const pointY = Math.round(intersectionPoint.y);\n\n  if (pointX <= nodeX + 1) {\n    return Position.Left;\n  }\n  if (pointX >= nodeX + width - 1) {\n    return Position.Right;\n  }\n  if (pointY <= nodeY + 1) {\n    return Position.Top;\n  }\n  if (pointY >= nodeY + height - 1) {\n    return Position.Bottom;\n  }\n\n  return Position.Top;\n};\n\n/**\n * Computes the floating connection parameters between two nodes: the points\n * where the edge meets each node's border and the corresponding sides. Feed the\n * result into {@link getSmartEdge} to route a floating edge around obstacles.\n *\n * Both nodes are expected to carry absolute `position` coordinates (resolve any\n * subflow offsets with `getAbsoluteNodes` first) and `measured` dimensions.\n */\nexport const getFloatingEdgeParams = (\n  sourceNode: Node,\n  targetNode: Node,\n): FloatingEdgeParams => {\n  const sourceIntersectionPoint = getNodeIntersection(sourceNode, targetNode);\n  const targetIntersectionPoint = getNodeIntersection(targetNode, sourceNode);\n\n  const sourcePos = getEdgePosition(sourceNode, sourceIntersectionPoint);\n  const targetPos = getEdgePosition(targetNode, targetIntersectionPoint);\n\n  return {\n    sx: sourceIntersectionPoint.x,\n    sy: sourceIntersectionPoint.y,\n    tx: targetIntersectionPoint.x,\n    ty: targetIntersectionPoint.y,\n    sourcePos,\n    targetPos,\n  };\n};\n","import type { Node, XYPosition } from \"@xyflow/react\";\n\n/**\n * Build a lookup of nodes by id for parent-chain traversal.\n */\nconst toNodeMap = (nodes: Node[]): Map<string, Node> => {\n  const map = new Map<string, Node>();\n  for (const node of nodes) {\n    map.set(node.id, node);\n  }\n  return map;\n};\n\n/**\n * Resolve a node's absolute position by walking up its `parentId` chain and\n * summing the relative offsets.\n *\n * React Flow stores a child node's `position` relative to its parent (see\n * https://reactflow.dev/examples/grouping/sub-flows), while edge handle\n * coordinates are always absolute. The pathfinding pipeline needs both in the\n * same (absolute) coordinate space, otherwise obstacles inside a subflow are\n * modeled in the wrong place. Assumes the default node `origin` of [0, 0].\n */\nconst getAbsolutePosition = (\n  node: Node,\n  nodeMap: Map<string, Node>,\n): XYPosition => {\n  let posX = node.position.x;\n  let posY = node.position.y;\n\n  let parentId = node.parentId;\n  const visited = new Set<string>([node.id]);\n\n  while (parentId && !visited.has(parentId)) {\n    visited.add(parentId);\n    const parent = nodeMap.get(parentId);\n    if (!parent) break;\n    posX += parent.position.x;\n    posY += parent.position.y;\n    parentId = parent.parentId;\n  }\n\n  return { x: posX, y: posY };\n};\n\n/**\n * Return a copy of the nodes where each `position` is its absolute coordinate\n * in the flow, resolving any `parentId` (subflow) offsets. Nodes without a\n * parent are returned unchanged (aside from being copied).\n */\nexport const getAbsoluteNodes = (nodes: Node[]): Node[] => {\n  const nodeMap = toNodeMap(nodes);\n\n  return nodes.map((node) => {\n    if (!node.parentId) return node;\n    return {\n      ...node,\n      position: getAbsolutePosition(node, nodeMap),\n    };\n  });\n};\n\n/**\n * Collect the ids of a node and all of its ancestors (its `parentId` chain).\n */\nconst collectAncestorIds = (\n  nodeId: string,\n  nodeMap: Map<string, Node>,\n): Set<string> => {\n  const ancestors = new Set<string>();\n  let parentId = nodeMap.get(nodeId)?.parentId;\n\n  while (parentId && !ancestors.has(parentId)) {\n    ancestors.add(parentId);\n    parentId = nodeMap.get(parentId)?.parentId;\n  }\n\n  return ancestors;\n};\n\n/**\n * Remove the container nodes that an edge lives inside from the obstacle set.\n *\n * An edge's own subflow container (and any node further up the chain) should\n * not be treated as a solid obstacle, otherwise the path is forced to route\n * around the container instead of within it. Sibling and unrelated group nodes\n * are kept so the edge still avoids them.\n */\nexport const excludeEdgeAncestorNodes = (\n  nodes: Node[],\n  sourceId: string,\n  targetId: string,\n): Node[] => {\n  const nodeMap = toNodeMap(nodes);\n  const ancestors = collectAncestorIds(sourceId, nodeMap);\n  for (const ancestorId of collectAncestorIds(targetId, nodeMap)) {\n    ancestors.add(ancestorId);\n  }\n\n  if (ancestors.size === 0) return nodes;\n\n  return nodes.filter((node) => !ancestors.has(node.id));\n};\n","import { useCallback, useContext, useSyncExternalStore } from \"react\";\nimport { SmartEdgeRoutingContext } from \"../routing/routingContext\";\nimport { nativeStepPolyline } from \"../routing/obstacleIndex\";\nimport {\n  computeEdgeHops,\n  drawOrthogonalHopPath,\n  toPolyline,\n} from \"../functions\";\nimport type { RegisteredSmartEdge } from \"../routing/scheduler\";\nimport type { SmartEdgeRouteResult } from \"../routing/providerStore\";\nimport type { SmartEdgePreset } from \"../smartEdgePresets\";\nimport type { XYPosition } from \"@xyflow/react\";\n\nconst isStepLikePreset = (preset: SmartEdgePreset): boolean =>\n  preset === \"step\" || preset === \"smoothstep\";\n\n/** Drops duplicate and collinear vertices so a straight native step run is\n * one segment. Needed for hop detection: `nativeStepPolyline` splits at the\n * unused-axis midpoint, which is often exactly where two edges cross. */\nconst simplifyPolyline = (points: XYPosition[]): XYPosition[] => {\n  const last = points[points.length - 1];\n  const interior = points.slice(1, -1).map((point) => [point.x, point.y]);\n  return toPolyline(points[0], last, interior);\n};\n\nconst nativeStepAsPolyline = (\n  source: XYPosition,\n  target: XYPosition,\n  registration: RegisteredSmartEdge,\n): XYPosition[] =>\n  simplifyPolyline(\n    nativeStepPolyline(\n      source.x,\n      source.y,\n      registration.sourcePosition,\n      target.x,\n      target.y,\n      registration.targetPosition,\n    ),\n  );\n\n/**\n * Configuration for circuit-style \"hops\": small bridge arcs drawn where a\n * smart edge crosses another orthogonal smart edge rendered beneath it.\n */\nexport interface HopOptions {\n  /** Radius of the bridge arc drawn at each crossing. Default `6`. */\n  radius?: number;\n  /**\n   * Corner rounding radius applied to the whole edge while hops are active.\n   * `0` (default) keeps sharp step corners; a positive value gives a\n   * smooth-step look. For smooth-step edges set this to match your border\n   * radius (React Flow's default is `5`).\n   */\n  borderRadius?: number;\n  /** Axis-alignment / crossing tolerance in pixels. Default `0.5`. */\n  epsilon?: number;\n}\n\n/** The `hops` value as accepted on options: a flag, a config object, or unset. */\nexport type HopSetting = boolean | HopOptions | undefined;\n\ninterface ResolvedHopConfig {\n  radius: number;\n  borderRadius: number;\n  epsilon: number;\n}\n\nconst DEFAULT_HOP_CONFIG: ResolvedHopConfig = {\n  radius: 6,\n  borderRadius: 0,\n  epsilon: 0.5,\n};\n\nconst resolveHopConfig = (hops: HopSetting): ResolvedHopConfig => {\n  if (!hops || hops === true) return DEFAULT_HOP_CONFIG;\n  return {\n    radius: hops.radius ?? DEFAULT_HOP_CONFIG.radius,\n    borderRadius: hops.borderRadius ?? DEFAULT_HOP_CONFIG.borderRadius,\n    epsilon: hops.epsilon ?? DEFAULT_HOP_CONFIG.epsilon,\n  };\n};\n\nexport interface ComputeHoppedPathParams {\n  /** This edge's own routed polyline, already resolved from its published\n   * route (see `resolveOwnPolyline`). */\n  ownPolyline: XYPosition[];\n  /** The polylines of every same-preset edge painted underneath this one\n   * that currently has a resolvable route. */\n  underneathPolylines: XYPosition[][];\n  /** The hop configuration (`true` for defaults, or an object to tune). */\n  hops: HopSetting;\n}\n\n/**\n * Draws this edge's SVG path with circuit-style hops: a small bridge arc at\n * every crossing between `ownPolyline` and one of `underneathPolylines`.\n * Pure geometry — every polyline is already resolved from published routes\n * by the caller, so this does no pathfinding and no store reads.\n */\nexport const computeHoppedPath = (params: ComputeHoppedPathParams): string => {\n  const config = resolveHopConfig(params.hops);\n  const hops = computeEdgeHops(\n    params.ownPolyline,\n    params.underneathPolylines,\n    config.epsilon,\n  );\n\n  return drawOrthogonalHopPath(params.ownPolyline, hops, {\n    hopRadius: config.radius,\n    borderRadius: config.borderRadius,\n  });\n};\n\n/**\n * Resolves this edge's own rendered polyline from its published route.\n * Routed edges walk their pathfinding points; clear step/smooth-step edges\n * use the native Z/L skeleton so hops still draw when\n * `routeOnlyWhenBlocked` skipped A*. Returns `null` while the route is\n * pending, or for a clear non-step preset (those keep the native fallback\n * with no hop drawing).\n */\nconst resolveOwnPolyline = (\n  source: XYPosition,\n  target: XYPosition,\n  registration: RegisteredSmartEdge,\n  route: SmartEdgeRouteResult | undefined,\n): XYPosition[] | null => {\n  if (route?.kind === \"routed\") {\n    return toPolyline(source, target, route.points);\n  }\n  if (route?.kind === \"clear\" && isStepLikePreset(registration.preset)) {\n    return nativeStepAsPolyline(source, target, registration);\n  }\n  return null;\n};\n\n/**\n * Resolves one underneath registration's rendered polyline from its\n * published route: a routed edge walks its actual path points, a clear edge\n * falls back to the native step skeleton between its registered endpoints\n * (still enough geometry to detect a crossing). Returns `null` when that\n * edge has no published route yet, in which case it contributes no\n * crossing rather than a stale one.\n */\nconst resolveUnderneathPolyline = (\n  registration: RegisteredSmartEdge,\n  route: SmartEdgeRouteResult | undefined,\n): XYPosition[] | null => {\n  /* v8 ignore next -- pending underneath edge; covered by unit tests */\n  if (route === undefined) return null;\n\n  const source: XYPosition = {\n    x: registration.sourceX,\n    y: registration.sourceY,\n  };\n  const target: XYPosition = {\n    x: registration.targetX,\n    y: registration.targetY,\n  };\n\n  if (route.kind === \"routed\") return toPolyline(source, target, route.points);\n\n  return nativeStepAsPolyline(source, target, registration);\n};\n\n/** Every same-preset registration painted strictly underneath `ownOrder`,\n * resolved to a polyline via `getRoute` and filtered down to the ones with a\n * resolvable route. */\nconst collectUnderneathPolylines = (\n  registrations: RegisteredSmartEdge[],\n  ownOrder: number,\n  ownPreset: SmartEdgePreset,\n  getRoute: (edgeId: string) => SmartEdgeRouteResult | undefined,\n): XYPosition[][] => {\n  const isPolyline = (\n    polyline: XYPosition[] | null,\n  ): polyline is XYPosition[] => polyline !== null;\n\n  return registrations\n    .filter(\n      (registration) =>\n        registration.order < ownOrder && registration.preset === ownPreset,\n    )\n    .map((registration) =>\n      resolveUnderneathPolyline(registration, getRoute(registration.id)),\n    )\n    .filter(isPolyline);\n};\n\n/** No provider, hops disabled, or nothing to watch: never notifies. */\nconst inertUnsubscribe = (): void => {\n  // Nothing to unsubscribe from.\n};\n\n/* v8 ignore next 3 -- useSyncExternalStore server snapshot; unused in browser */\nconst getInertRoutesVersion = (): number => 0;\n\nexport interface UseHoppedPathParams {\n  edgeId: string;\n  sourceX: number;\n  sourceY: number;\n  targetX: number;\n  targetY: number;\n  /** The hop configuration (`true` for defaults, or an object to tune). */\n  hops: HopSetting;\n  /** Editable/checkpoint edges use a different draw pipeline and skip hops. */\n  editable?: boolean;\n  checkpoints?: boolean;\n}\n\n/**\n * Returns the hopped SVG path for this edge, or `null` when hops are\n * disabled, there is no provider, this edge's own route is not yet\n * published, a clear non-step edge has nothing to bridge, or its\n * registration cannot be found. Clear step/smooth-step edges still get a\n * path (the native skeleton, with hops if they cross a neighbor).\n *\n * Reads only already-published routes from the provider's store —\n * `getRegistrationsInOrder`/`getRoute` are imperative getters, so a\n * `subscribeAllRoutes` subscription (via `useSyncExternalStore`, keyed off a\n * version counter) drives re-renders whenever any edge's route changes, own\n * or a neighbor's. This makes hop cost pure geometry over cached polylines\n * instead of a per-edge re-route.\n */\nexport const useHoppedPath = (params: UseHoppedPathParams): string | null => {\n  const context = useContext(SmartEdgeRoutingContext);\n  const hopsRequested =\n    Boolean(params.hops) && !params.editable && !params.checkpoints;\n  const store = hopsRequested && context !== null ? context.store : undefined;\n\n  const subscribe = useCallback(\n    (listener: () => void): (() => void) => {\n      if (!store) return inertUnsubscribe;\n      return store.subscribeAllRoutes(listener);\n    },\n    [store],\n  );\n  const getSnapshot = useCallback(\n    () => store?.getRoutesVersion() ?? 0,\n    [store],\n  );\n\n  useSyncExternalStore(subscribe, getSnapshot, getInertRoutesVersion);\n\n  if (!hopsRequested || context === null) return null;\n\n  const registrations = context.getRegistrationsInOrder();\n  const ownRegistration = registrations.find(\n    (registration) => registration.id === params.edgeId,\n  );\n  /* v8 ignore next -- registration race during unmount; covered by unit tests */\n  if (!ownRegistration) return null;\n\n  const source: XYPosition = { x: params.sourceX, y: params.sourceY };\n  const target: XYPosition = { x: params.targetX, y: params.targetY };\n\n  const ownPolyline = resolveOwnPolyline(\n    source,\n    target,\n    ownRegistration,\n    context.store.getRoute(params.edgeId),\n  );\n  if (!ownPolyline) return null;\n\n  const underneathPolylines = collectUnderneathPolylines(\n    registrations,\n    ownRegistration.order,\n    ownRegistration.preset,\n    (edgeId) => context.store.getRoute(edgeId),\n  );\n\n  return computeHoppedPath({\n    ownPolyline,\n    underneathPolylines,\n    hops: params.hops,\n  });\n};\n","import type { XYPosition } from \"@xyflow/react\";\nimport type { ControlPointData } from \"./ControlPoint\";\n\n/**\n * Returns the point at the given fraction (0..1) of a polyline's arc length.\n */\nexport const pointAlongPolyline = (\n  polyline: number[][],\n  fraction: number,\n): XYPosition => {\n  if (polyline.length < 2) {\n    const [posX, posY] = polyline[0] ?? [0, 0];\n    return { x: posX, y: posY };\n  }\n\n  let total = 0;\n  for (let index = 1; index < polyline.length; index++) {\n    total += Math.hypot(\n      polyline[index][0] - polyline[index - 1][0],\n      polyline[index][1] - polyline[index - 1][1],\n    );\n  }\n\n  const targetDistance = total * fraction;\n  let accumulated = 0;\n  for (let index = 1; index < polyline.length; index++) {\n    const segmentLength = Math.hypot(\n      polyline[index][0] - polyline[index - 1][0],\n      polyline[index][1] - polyline[index - 1][1],\n    );\n    if (accumulated + segmentLength >= targetDistance) {\n      const remaining = targetDistance - accumulated;\n      const segmentFraction =\n        segmentLength === 0 ? 0 : remaining / segmentLength;\n      return {\n        x:\n          polyline[index - 1][0] +\n          (polyline[index][0] - polyline[index - 1][0]) * segmentFraction,\n        y:\n          polyline[index - 1][1] +\n          (polyline[index][1] - polyline[index - 1][1]) * segmentFraction,\n      };\n    }\n    accumulated += segmentLength;\n  }\n\n  const [posX, posY] = polyline[polyline.length - 1];\n  return { x: posX, y: posY };\n};\n\n/**\n * Index of the polyline vertex closest to `point`, searching from `from`\n * (exclusive of the endpoints) onward.\n */\nexport const closestVertexIndex = (\n  polyline: number[][],\n  point: ControlPointData,\n  from: number,\n): number => {\n  let bestIndex = from;\n  let bestDistance = Infinity;\n\n  for (let index = from; index < polyline.length - 1; index++) {\n    const distance =\n      (polyline[index][0] - point.x) ** 2 + (polyline[index][1] - point.y) ** 2;\n    if (distance < bestDistance) {\n      bestDistance = distance;\n      bestIndex = index;\n    }\n  }\n\n  return bestIndex;\n};\n\n/**\n * Splits the routed polyline into one sub-polyline per segment, cutting at the\n * vertex nearest each waypoint.\n */\nexport const splitPolylineAtWaypoints = (\n  polyline: number[][],\n  waypoints: ControlPointData[],\n): number[][][] => {\n  if (polyline.length === 0) return [[]];\n  if (waypoints.length === 0) return [polyline];\n\n  const segments: number[][][] = [];\n  let start = 0;\n  let searchFrom = 1;\n\n  for (const waypoint of waypoints) {\n    const cut = closestVertexIndex(polyline, waypoint, searchFrom);\n    segments.push(polyline.slice(start, cut + 1));\n    start = cut;\n    searchFrom = cut + 1;\n  }\n\n  segments.push(polyline.slice(start));\n  return segments;\n};\n\n/**\n * Builds the interleaved control point list `[inactive, active, inactive, ...]`\n * from the active waypoints plus an inactive \"insert\" point at the midpoint of\n * each routed segment.\n */\nexport const buildControlPoints = (\n  source: XYPosition,\n  target: XYPosition,\n  activePoints: ControlPointData[],\n  routedInterior: number[][],\n): ControlPointData[] => {\n  const polyline: number[][] = [\n    [source.x, source.y],\n    ...routedInterior,\n    [target.x, target.y],\n  ];\n  const segments = splitPolylineAtWaypoints(polyline, activePoints);\n  const result: ControlPointData[] = [];\n\n  segments.forEach((segment, segmentIndex) => {\n    const midpoint = pointAlongPolyline(segment, 0.5);\n    result.push({\n      id: `__inactive-${String(segmentIndex)}`,\n      x: midpoint.x,\n      y: midpoint.y,\n      active: false,\n    });\n\n    if (segmentIndex < activePoints.length) {\n      result.push(activePoints[segmentIndex]);\n    }\n  });\n\n  return result;\n};\n","import { useCallback, useEffect, useRef, useState } from \"react\";\nimport { useReactFlow, useStore } from \"@xyflow/react\";\nimport type { XYPosition } from \"@xyflow/react\";\n\n/**\n * A single waypoint of an editable smart edge. Stored (active) points live in\n * `edge.data.points`; inactive points are computed on the fly for adding new\n * waypoints and are not persisted.\n */\nexport type ControlPointData = XYPosition & {\n  id: string;\n  active?: boolean;\n};\n\nexport type SetControlPoints = (\n  update: (points: ControlPointData[]) => ControlPointData[],\n) => void;\n\nexport interface ControlPointProps {\n  id: string;\n  index: number;\n  x: number;\n  y: number;\n  color: string;\n  active?: boolean;\n  setControlPoints: SetControlPoints;\n}\n\nconst NUDGE = 5;\n\nexport function ControlPoint({\n  id,\n  index,\n  x,\n  y,\n  color,\n  active,\n  setControlPoints,\n}: Readonly<ControlPointProps>) {\n  const container = useStore((store) => store.domNode);\n  const { screenToFlowPosition } = useReactFlow();\n  const [dragging, setDragging] = useState(false);\n  const ref = useRef<SVGCircleElement>(null);\n\n  const updatePosition = useCallback(\n    (position: XYPosition) => {\n      setControlPoints((points) => {\n        const shouldActivate = !active;\n\n        if (shouldActivate) {\n          // Promote an inactive (insert) point to a new active waypoint with a\n          // fresh id. Inactive points sit at even visual indices, active points\n          // at odd indices, so the active-list insertion index is `index/2 - 1`.\n          const newPoint: ControlPointData = {\n            ...position,\n            id: crypto.randomUUID(),\n            active: true,\n          };\n\n          if (index !== 0) {\n            const insertAfter = index * 0.5 - 1;\n            return points.flatMap((point, pointIndex) =>\n              pointIndex === insertAfter ? [point, newPoint] : [point],\n            );\n          }\n          return [newPoint, ...points];\n        }\n\n        return points.map((point) =>\n          point.id === id ? { ...point, ...position } : point,\n        );\n      });\n    },\n    [id, active, index, setControlPoints],\n  );\n\n  const deletePoint = useCallback(() => {\n    setControlPoints((points) => points.filter((point) => point.id !== id));\n  }, [id, setControlPoints]);\n\n  const handleKeyDown = useCallback(\n    (event: React.KeyboardEvent) => {\n      switch (event.key) {\n        case \"Enter\":\n        case \" \":\n          if (!active) {\n            event.preventDefault();\n          }\n          updatePosition({ x, y });\n          break;\n        case \"Backspace\":\n        case \"Delete\":\n          event.stopPropagation();\n          deletePoint();\n          break;\n        case \"ArrowLeft\":\n          updatePosition({ x: x - NUDGE, y });\n          break;\n        case \"ArrowRight\":\n          updatePosition({ x: x + NUDGE, y });\n          break;\n        case \"ArrowUp\":\n          updatePosition({ x, y: y - NUDGE });\n          break;\n        case \"ArrowDown\":\n          updatePosition({ x, y: y + NUDGE });\n          break;\n        default:\n          break;\n      }\n    },\n    [x, y, active, updatePosition, deletePoint],\n  );\n\n  useEffect(() => {\n    if (!container || !dragging) {\n      return undefined;\n    }\n\n    const onPointerMove = (event: PointerEvent) => {\n      updatePosition(\n        screenToFlowPosition({ x: event.clientX, y: event.clientY }),\n      );\n    };\n\n    const onPointerUp = (event: PointerEvent) => {\n      setDragging(false);\n      updatePosition(\n        screenToFlowPosition({ x: event.clientX, y: event.clientY }),\n      );\n    };\n\n    container.addEventListener(\"pointermove\", onPointerMove);\n    container.addEventListener(\"pointerup\", onPointerUp, { once: true });\n    container.addEventListener(\"pointerleave\", onPointerUp, { once: true });\n\n    return () => {\n      container.removeEventListener(\"pointermove\", onPointerMove);\n      container.removeEventListener(\"pointerup\", onPointerUp);\n      container.removeEventListener(\"pointerleave\", onPointerUp);\n    };\n  }, [container, dragging, screenToFlowPosition, updatePosition]);\n\n  return (\n    <circle\n      ref={ref}\n      tabIndex={0}\n      data-testid=\"smart-edge-control-point\"\n      className={`nopan nodrag${active ? \" active\" : \"\"}`}\n      cx={x}\n      cy={y}\n      r={active ? 4 : 3}\n      strokeWidth={1}\n      strokeOpacity={active ? 1 : 0.3}\n      stroke={color}\n      fill={active ? color : \"white\"}\n      style={{ pointerEvents: \"all\", cursor: \"pointer\" }}\n      onContextMenu={(event) => {\n        event.preventDefault();\n        if (active) {\n          deletePoint();\n        }\n      }}\n      onPointerDown={(event) => {\n        if (event.button === 2) return;\n        updatePosition({ x, y });\n        // Only active waypoints drag continuously; an inactive point is\n        // promoted in place and can then be dragged on a subsequent gesture.\n        if (active) {\n          setDragging(true);\n        }\n      }}\n      onKeyDown={handleKeyDown}\n      onPointerUp={() => {\n        setDragging(false);\n      }}\n    />\n  );\n}\n","import type { XYPosition } from \"@xyflow/react\";\nimport type { ControlPointData } from \"./ControlPoint\";\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n  typeof value === \"object\" && value !== null;\n\nconst hasStringField = (\n  record: Record<string, unknown>,\n  field: string,\n): boolean => field in record && typeof record[field] === \"string\";\n\nconst hasNumberField = (\n  record: Record<string, unknown>,\n  field: string,\n): boolean => field in record && typeof record[field] === \"number\";\n\nconst isControlPointData = (value: unknown): value is ControlPointData =>\n  isRecord(value) &&\n  hasStringField(value, \"id\") &&\n  hasNumberField(value, \"x\") &&\n  hasNumberField(value, \"y\");\n\nconst isControlPointArray = (value: unknown): value is ControlPointData[] =>\n  Array.isArray(value) && value.every(isControlPointData);\n\nconst isXYPosition = (value: unknown): value is XYPosition =>\n  isRecord(value) && hasNumberField(value, \"x\") && hasNumberField(value, \"y\");\n\n/**\n * Reads the active waypoints from an edge's `data`, tolerating any data shape\n * (returns an empty list when absent or malformed).\n */\nexport const readControlPoints = (data: unknown): ControlPointData[] => {\n  if (\n    isRecord(data) &&\n    \"points\" in data &&\n    isControlPointArray(data[\"points\"])\n  ) {\n    return data[\"points\"];\n  }\n  return [];\n};\n\n/**\n * Reads fixed checkpoints from an edge's `data`, tolerating any data shape\n * (returns an empty list when absent or malformed).\n */\nexport const readCheckpoints = (data: unknown): XYPosition[] => {\n  if (\n    isRecord(data) &&\n    \"checkpoints\" in data &&\n    Array.isArray(data[\"checkpoints\"])\n  ) {\n    return data[\"checkpoints\"].filter(isXYPosition);\n  }\n  return [];\n};\n","import { getFloatingEdgeParams } from \"../functions\";\nimport type { Node, Position } from \"@xyflow/react\";\nimport { readCheckpoints } from \"./smartEdgeData\";\nimport type { ControlPointData } from \"./ControlPoint\";\n\nexport interface WaypointRoutingOptions {\n  editable?: boolean;\n  checkpoints?: boolean;\n}\n\nexport interface EdgeEndpointCoordinates {\n  sourceX: number;\n  sourceY: number;\n  targetX: number;\n  targetY: number;\n  sourcePosition: Position;\n  targetPosition: Position;\n}\n\nexport const applyFloatingEdgeCoordinates = ({\n  floating,\n  sourceNodeId,\n  targetNodeId,\n  absoluteNodes,\n  sourceX,\n  sourceY,\n  targetX,\n  targetY,\n  sourcePosition,\n  targetPosition,\n}: {\n  floating: boolean | undefined;\n  sourceNodeId: string;\n  targetNodeId: string;\n  absoluteNodes: Node[];\n  sourceX: number;\n  sourceY: number;\n  targetX: number;\n  targetY: number;\n  sourcePosition: Position;\n  targetPosition: Position;\n}): EdgeEndpointCoordinates => {\n  if (!floating || sourceNodeId === targetNodeId) {\n    return {\n      sourceX,\n      sourceY,\n      targetX,\n      targetY,\n      sourcePosition,\n      targetPosition,\n    };\n  }\n\n  const sourceNode = absoluteNodes.find((node) => node.id === sourceNodeId);\n  const targetNode = absoluteNodes.find((node) => node.id === targetNodeId);\n\n  if (!sourceNode?.measured || !targetNode?.measured) {\n    return {\n      sourceX,\n      sourceY,\n      targetX,\n      targetY,\n      sourcePosition,\n      targetPosition,\n    };\n  }\n\n  const { sx, sy, tx, ty, sourcePos, targetPos } = getFloatingEdgeParams(\n    sourceNode,\n    targetNode,\n  );\n\n  return {\n    sourceX: sx,\n    sourceY: sy,\n    targetX: tx,\n    targetY: ty,\n    sourcePosition: sourcePos,\n    targetPosition: targetPos,\n  };\n};\n\nexport const resolveWaypointParams = (\n  options: WaypointRoutingOptions,\n  data: unknown,\n  activePoints: ControlPointData[],\n): { x: number; y: number }[] => {\n  if (options.editable) {\n    return activePoints.map((point) => ({ x: point.x, y: point.y }));\n  }\n\n  if (options.checkpoints) {\n    return readCheckpoints(data);\n  }\n\n  return [];\n};\n","import { BaseEdge, useReactFlow } from \"@xyflow/react\";\nimport { useCallback } from \"react\";\nimport type { ComponentType, CSSProperties } from \"react\";\nimport { buildControlPoints } from \"./controlPointGeometry\";\nimport { ControlPoint } from \"./ControlPoint\";\nimport { readControlPoints } from \"./smartEdgeData\";\nimport {\n  applyFloatingEdgeCoordinates,\n  resolveWaypointParams,\n} from \"./smartEdgeRouting\";\nimport type { ControlPointData, SetControlPoints } from \"./ControlPoint\";\nimport type { EdgeEndpointCoordinates } from \"./smartEdgeRouting\";\nimport type { SmartEdgeOptions } from \"./index\";\nimport type { SmartEdgeContextValue } from \"../routing/routingContext\";\nimport type { SmartEdgeRouteResult } from \"../routing/providerStore\";\nimport type { Edge, EdgeProps, Node, XYPosition } from \"@xyflow/react\";\n\n/** The routed variant of a published route (never `clear`). */\nexport type RoutedRoute = Extract<SmartEdgeRouteResult, { kind: \"routed\" }>;\n\nconst DEFAULT_CONTROL_POINT_COLOR = \"#3367d9\";\n\n/** Stable empty node list used when there is no provider. */\nconst EMPTY_NODES: Node[] = [];\n\n/** Prefers the hopped path when hops produced one, else the routed path. */\nconst resolvePath = (hopped: string | null, routed: string): string =>\n  hopped ?? routed;\n\n/**\n * A `RoutedRoute` stand-in so a clear step edge can still render through\n * `RoutedSmartEdge` when hops produced a path (native skeleton plus any\n * bridge arcs). `wasRouted` stays `true` because that field is required on\n * the routed variant; the provider store still records `kind: \"clear\"`.\n */\nexport const hoppedClearRoute = (\n  path: string,\n  endpoints: EdgeEndpointCoordinates,\n): RoutedRoute => ({\n  kind: \"routed\",\n  wasRouted: true,\n  svgPathString: path,\n  edgeCenterX: (endpoints.sourceX + endpoints.targetX) / 2,\n  edgeCenterY: (endpoints.sourceY + endpoints.targetY) / 2,\n  points: [],\n});\n\n/** Static dash used while a route is pending. Matches xyflow's animated\n * stroke visually without running `dashdraw` on every pending path. */\nconst PENDING_PLACEHOLDER_DASHARRAY = \"5 5\";\n\n/**\n * Native fallback used while a route is pending or drag-deferred. Drag\n * wraps the path so xyflow's `.react-flow__edge.animated path` CSS\n * (`dashdraw` 0.5s infinite) applies. Pending uses a static dash instead:\n * infinite SVG path animation on every edge starves the routing worker on\n * large graphs (the 750-node fixture's `batchLatencyMs` jumped from ~6.5s\n * to ~12s on 2-vCPU GitHub runners). Not a public export.\n */\nexport function PlaceholderFallback({\n  FallbackEdge,\n  edgeProps,\n  dragFallbackStyle,\n  animated,\n}: Readonly<{\n  FallbackEdge: ComponentType<EdgeProps>;\n  edgeProps: EdgeProps;\n  dragFallbackStyle: CSSProperties;\n  animated: boolean;\n}>) {\n  const style = {\n    ...(animated ? {} : { strokeDasharray: PENDING_PLACEHOLDER_DASHARRAY }),\n    ...edgeProps.style,\n    ...dragFallbackStyle,\n  };\n  return (\n    <g\n      className={animated ? \"react-flow__edge animated\" : undefined}\n      data-smart-edge-placeholder=\"\"\n    >\n      <FallbackEdge {...edgeProps} style={style} />\n    </g>\n  );\n}\n\n/**\n * Applies a control-point update to the one matching edge in a React Flow edge\n * list, rewriting only its `data.points` and leaving every other edge (and the\n * matched edge's other data) untouched.\n */\nexport const applyControlPointsUpdate = (\n  edges: Edge[],\n  edgeId: string,\n  update: (points: ControlPointData[]) => ControlPointData[],\n): Edge[] =>\n  edges.map((edge) => {\n    if (edge.id !== edgeId) return edge;\n    const points = readControlPoints(edge.data);\n    return { ...edge, data: { ...edge.data, points: update(points) } };\n  });\n\n/** The per-render geometry a smart edge derives from its props and the\n * provider node snapshot: floating-resolved endpoints, the active editable\n * waypoints, and the waypoint list registered for routing. */\nexport interface PreparedEdge {\n  endpoints: EdgeEndpointCoordinates;\n  activePoints: ControlPointData[];\n  waypoints: XYPosition[];\n}\n\n/**\n * Resolves an edge's routable geometry: floating endpoint override (using the\n * provider's absolute node snapshot, empty without a provider) and the\n * editable/checkpoint waypoints. Pure — no hooks — so the component stays a\n * thin orchestrator.\n */\nexport const prepareEdge = (\n  context: SmartEdgeContextValue | null,\n  options: SmartEdgeOptions,\n  edgeProps: EdgeProps,\n): PreparedEdge => {\n  const absoluteNodes = context ? context.getNodesSnapshot() : EMPTY_NODES;\n  const endpoints = applyFloatingEdgeCoordinates({\n    floating: context ? options.floating : false,\n    sourceNodeId: edgeProps.source,\n    targetNodeId: edgeProps.target,\n    absoluteNodes,\n    sourceX: edgeProps.sourceX,\n    sourceY: edgeProps.sourceY,\n    targetX: edgeProps.targetX,\n    targetY: edgeProps.targetY,\n    sourcePosition: edgeProps.sourcePosition,\n    targetPosition: edgeProps.targetPosition,\n  });\n  const activePoints = options.editable\n    ? readControlPoints(edgeProps.data)\n    : [];\n  const waypoints = resolveWaypointParams(\n    options,\n    edgeProps.data,\n    activePoints,\n  );\n\n  return { endpoints, activePoints, waypoints };\n};\n\nexport interface RoutedSmartEdgeProps {\n  edgeProps: EdgeProps;\n  route: RoutedRoute;\n  endpoints: EdgeEndpointCoordinates;\n  hoppedPathString: string | null;\n  options: SmartEdgeOptions;\n  activePoints: ControlPointData[];\n  showControlPoints: boolean;\n}\n\n/**\n * Renders a routed smart edge: the `BaseEdge` with the routed (or hopped) path,\n * plus the draggable control points overlay for editable edges when they are\n * revealed. Owns the `edge.data.points` persistence (via `setEdges`) so its\n * memoized updater only reads this edge's props, never the parent's.\n */\nexport function RoutedSmartEdge({\n  edgeProps,\n  route,\n  endpoints,\n  hoppedPathString,\n  options,\n  activePoints,\n  showControlPoints,\n}: Readonly<RoutedSmartEdgeProps>) {\n  const { id } = edgeProps;\n  const { setEdges } = useReactFlow();\n\n  const setControlPoints = useCallback<SetControlPoints>(\n    (update) => {\n      setEdges((edges) => applyControlPointsUpdate(edges, id, update));\n    },\n    [id, setEdges],\n  );\n\n  const baseEdge = (\n    <BaseEdge\n      path={resolvePath(hoppedPathString, route.svgPathString)}\n      labelX={route.edgeCenterX}\n      labelY={route.edgeCenterY}\n      label={edgeProps.label}\n      labelStyle={edgeProps.labelStyle}\n      labelShowBg={edgeProps.labelShowBg}\n      labelBgStyle={edgeProps.labelBgStyle}\n      labelBgPadding={edgeProps.labelBgPadding}\n      labelBgBorderRadius={edgeProps.labelBgBorderRadius}\n      style={edgeProps.style}\n      markerStart={edgeProps.markerStart}\n      markerEnd={edgeProps.markerEnd}\n      interactionWidth={edgeProps.interactionWidth}\n    />\n  );\n\n  if (!options.editable) {\n    return baseEdge;\n  }\n\n  const controlPoints = buildControlPoints(\n    { x: endpoints.sourceX, y: endpoints.sourceY },\n    { x: endpoints.targetX, y: endpoints.targetY },\n    activePoints,\n    route.points,\n  );\n  const color = options.controlPointColor ?? DEFAULT_CONTROL_POINT_COLOR;\n\n  return (\n    <>\n      {baseEdge}\n      {showControlPoints &&\n        controlPoints.map((point, index) => (\n          <ControlPoint\n            key={point.id}\n            index={index}\n            x={point.x}\n            y={point.y}\n            id={point.id}\n            active={point.active}\n            color={color}\n            setControlPoints={setControlPoints}\n          />\n        ))}\n    </>\n  );\n}\n","import { BezierEdge } from \"@xyflow/react\";\nimport { useContext } from \"react\";\nimport type { ComponentType } from \"react\";\nimport { SmartEdgeRoutingContext } from \"../routing/routingContext\";\nimport { useSmartEdgePath } from \"../routing/useSmartEdgePath\";\nimport type { ControlPointData } from \"./ControlPoint\";\nimport { warnOnceNoProvider } from \"./noProviderWarning\";\nimport { useEndpointNodesSelected } from \"./smartEdgeSelection\";\nimport { useHoppedPath } from \"./smartEdgeHops\";\nimport {\n  prepareEdge,\n  RoutedSmartEdge,\n  hoppedClearRoute,\n  PlaceholderFallback,\n} from \"./renderDecision\";\nimport type { HopOptions } from \"./smartEdgeHops\";\nimport type { SmartEdgeBatchItemOptions } from \"../routing/routeBatch\";\nimport type { SmartEdgePreset } from \"../smartEdgePresets\";\nimport type { GetSmartEdgeOptions } from \"../getSmartEdge\";\nimport type { EdgeProps, Edge, XYPosition } from \"@xyflow/react\";\n\nexport type { HopOptions } from \"./smartEdgeHops\";\n\nexport type SmartEdgeOptions = GetSmartEdgeOptions & {\n  fallback?: ComponentType<EdgeProps<Edge>>;\n  /**\n   * When enabled, the edge's source/target connection points are computed\n   * dynamically from node geometry (the nearest border facing the other node)\n   * instead of using the fixed handle positions, mirroring React Flow's\n   * floating edges. See https://github.com/tisoap/react-flow-smart-edge/issues/13\n   */\n  floating?: boolean;\n  /**\n   * When enabled, the edge renders draggable control points (waypoints) that\n   * the path is routed through, still avoiding nodes between each waypoint.\n   * Waypoints are read from and persisted to `edge.data.points`; the consumer\n   * owns persistence via React Flow's edge state. Click an inactive point to\n   * add a waypoint, drag to move, right-click or press Delete to remove.\n   * See https://github.com/tisoap/react-flow-smart-edge/issues/36\n   */\n  editable?: boolean;\n  /**\n   * When enabled, the edge is routed through fixed waypoints read from\n   * `edge.data.checkpoints` without rendering draggable control points. Each\n   * segment still uses pathfinding. Ignored when `editable` is also `true`.\n   */\n  checkpoints?: boolean;\n  /**\n   * Color used to render the editable control points. Defaults to a blue.\n   */\n  controlPointColor?: string;\n  /**\n   * Corner radius for the `smoothstep` preset. Serializable, so unlike a custom\n   * `drawEdge` it survives the provider's routing pipeline to the worker.\n   */\n  borderRadius?: number;\n  /**\n   * Circuit-style \"hops\": where this edge crosses another smart edge of the\n   * same `type` rendered beneath it, draw a small bridge arc over the crossing\n   * so intersecting wires read cleanly (like a schematic). Only the step and\n   * smooth-step variants are orthogonal enough for this; it is ignored on\n   * editable/checkpoint edges. Pass `true` for defaults or a {@link HopOptions}\n   * object to tune the arc radius, corner rounding, and tolerance.\n   * See https://github.com/tisoap/react-flow-smart-edge/issues/61\n   */\n  hops?: boolean | HopOptions;\n};\n\n/**\n * The `edge.data` shape consumed by editable smart edges: the ordered list of\n * active waypoints the edge is routed through.\n */\nexport interface SmartEditableEdgeData extends Record<string, unknown> {\n  points?: ControlPointData[];\n}\n\n/**\n * The `edge.data` shape consumed by checkpoint smart edges: the ordered list\n * of fixed graph-coordinate points the edge is routed through.\n */\nexport interface SmartCheckpointEdgeData extends Record<string, unknown> {\n  checkpoints?: XYPosition[];\n}\n\nexport interface SmartEdgeProps<\n  EdgeType extends Edge = Edge,\n> extends EdgeProps<EdgeType> {\n  /** Which preset (`bezier`, `step`, …) resolves this edge's draw/pathfinding\n   * on the routing side. Set for you by `createSmartEdge`. */\n  preset: SmartEdgePreset;\n  options: SmartEdgeOptions;\n}\n\n/** Extracts only the structured-clone-safe options the provider pipeline can\n * forward to the routing worker. Function options (`drawEdge`/`generatePath`)\n * cannot cross that boundary and are resolved from `preset` instead. */\nconst toBatchItemOptions = (\n  options: SmartEdgeOptions,\n): SmartEdgeBatchItemOptions => ({\n  gridRatio: options.gridRatio,\n  nodePadding: options.nodePadding,\n  avoidAreas: options.avoidAreas,\n  borderRadius: options.borderRadius,\n});\n\n/**\n * Routes an edge through the nearest `SmartEdgeProvider` and renders its path,\n * falling back to the preset's native edge whenever routing is unavailable\n * (no provider), pending, deferred (an endpoint is dragging and\n * `routeWhileDragging` is off), or the corridor is clear (unless hops are\n * enabled on a step/smooth-step edge, in which case the native skeleton is\n * still drawn so crossings can bridge).\n *\n * Requires a `SmartEdgeProvider` ancestor to route; without one it warns once\n * (in development) and renders the fallback edge. Custom `drawEdge` /\n * `generatePath` functions passed via `options` are ignored here — the\n * provider resolves those from `preset` — and remain available only through\n * the synchronous `getSmartEdge` API.\n */\nexport function SmartEdge<EdgeType extends Edge = Edge>({\n  preset,\n  options,\n  ...edgeProps\n}: Readonly<SmartEdgeProps<EdgeType>>) {\n  const { id, source, target } = edgeProps;\n  const context = useContext(SmartEdgeRoutingContext);\n\n  const { endpoints, activePoints, waypoints } = prepareEdge(\n    context,\n    options,\n    edgeProps,\n  );\n\n  const { route, isDragging } = useSmartEdgePath({\n    id,\n    source,\n    target,\n    sourceX: endpoints.sourceX,\n    sourceY: endpoints.sourceY,\n    targetX: endpoints.targetX,\n    targetY: endpoints.targetY,\n    sourcePosition: endpoints.sourcePosition,\n    targetPosition: endpoints.targetPosition,\n    preset,\n    options: toBatchItemOptions(options),\n    waypoints,\n  });\n\n  const hoppedPathString = useHoppedPath({\n    edgeId: id,\n    sourceX: endpoints.sourceX,\n    sourceY: endpoints.sourceY,\n    targetX: endpoints.targetX,\n    targetY: endpoints.targetY,\n    hops: options.hops,\n    editable: options.editable,\n    checkpoints: options.checkpoints,\n  });\n\n  const endpointsSelected = useEndpointNodesSelected(\n    context?.store,\n    source,\n    target,\n  );\n\n  const FallbackEdge = options.fallback ?? BezierEdge;\n\n  if (context === null) {\n    warnOnceNoProvider();\n    return <FallbackEdge {...edgeProps} />;\n  }\n\n  const dragPlaceholder = isDragging && !context.options.routeWhileDragging;\n\n  if (dragPlaceholder || route === null) {\n    return (\n      <PlaceholderFallback\n        FallbackEdge={FallbackEdge}\n        edgeProps={edgeProps}\n        dragFallbackStyle={context.options.dragFallbackStyle}\n        animated={dragPlaceholder}\n      />\n    );\n  }\n\n  if (route.kind === \"clear\") {\n    if (hoppedPathString === null) {\n      return <FallbackEdge {...edgeProps} />;\n    }\n\n    return (\n      <RoutedSmartEdge\n        edgeProps={edgeProps}\n        route={hoppedClearRoute(hoppedPathString, endpoints)}\n        endpoints={endpoints}\n        hoppedPathString={hoppedPathString}\n        options={options}\n        activePoints={activePoints}\n        showControlPoints={Boolean(edgeProps.selected) || endpointsSelected}\n      />\n    );\n  }\n\n  return (\n    <RoutedSmartEdge\n      edgeProps={edgeProps}\n      route={route}\n      endpoints={endpoints}\n      hoppedPathString={hoppedPathString}\n      options={options}\n      activePoints={activePoints}\n      showControlPoints={Boolean(edgeProps.selected) || endpointsSelected}\n    />\n  );\n}\n\nexport type SmartEdgeFunction = typeof SmartEdge;\n","import {\n  BezierEdge,\n  StraightEdge,\n  StepEdge,\n  SmoothStepEdge,\n  SimpleBezierEdge,\n} from \"@xyflow/react\";\nimport {\n  svgDrawSmoothLinePath,\n  svgDrawStraightLinePath,\n  svgDrawSmoothStepLinePath,\n  svgDrawSimpleBezierLinePath,\n  pathfindingAStarDiagonal,\n  pathfindingJumpPointNoDiagonal,\n} from \"./functions\";\nimport type { SmartEdgeOptions } from \"./SmartEdge\";\n\nexport const smartEdgePresets = {\n  bezier: {\n    drawEdge: svgDrawSmoothLinePath,\n    generatePath: pathfindingAStarDiagonal,\n    fallback: BezierEdge,\n  },\n  straight: {\n    drawEdge: svgDrawStraightLinePath,\n    generatePath: pathfindingAStarDiagonal,\n    fallback: StraightEdge,\n  },\n  step: {\n    drawEdge: svgDrawStraightLinePath,\n    generatePath: pathfindingJumpPointNoDiagonal,\n    fallback: StepEdge,\n  },\n  smoothstep: {\n    drawEdge: svgDrawSmoothStepLinePath(),\n    generatePath: pathfindingJumpPointNoDiagonal,\n    fallback: SmoothStepEdge,\n  },\n  simplebezier: {\n    drawEdge: svgDrawSimpleBezierLinePath,\n    generatePath: pathfindingAStarDiagonal,\n    fallback: SimpleBezierEdge,\n  },\n} as const satisfies Record<string, SmartEdgeOptions>;\n\nexport type SmartEdgePreset = keyof typeof smartEdgePresets;\n","import { SmartEdge } from \"../SmartEdge\";\nimport { smartEdgePresets } from \"../smartEdgePresets\";\nimport type { SmartEdgeOptions } from \"../SmartEdge\";\nimport type { SmartEdgePreset } from \"../smartEdgePresets\";\nimport type { EdgeProps, EdgeTypes } from \"@xyflow/react\";\n\ntype SmartEdgeComponent = EdgeTypes[string];\n\nexport type ConfigureSmartEdgeOptions = Partial<SmartEdgeOptions>;\n\nexport function createSmartEdge(\n  preset: SmartEdgePreset,\n  options?: ConfigureSmartEdgeOptions,\n): SmartEdgeComponent {\n  const mergedOptions: SmartEdgeOptions = {\n    ...smartEdgePresets[preset],\n    ...options,\n  };\n\n  function ConfiguredSmartEdge(props: EdgeProps) {\n    return <SmartEdge {...props} preset={preset} options={mergedOptions} />;\n  }\n\n  ConfiguredSmartEdge.displayName = `SmartEdge(${preset})`;\n\n  return ConfiguredSmartEdge;\n}\n","import { createSmartEdge } from \"../createSmartEdge\";\n\nexport const SmartBezierEdge = createSmartEdge(\"bezier\");\n","import { createSmartEdge } from \"../createSmartEdge\";\n\nexport const SmartStraightEdge = createSmartEdge(\"straight\");\n","import { createSmartEdge } from \"../createSmartEdge\";\n\nexport const SmartStepEdge = createSmartEdge(\"step\");\n","import { createSmartEdge } from \"../createSmartEdge\";\n\nexport const SmartSmoothStepEdge = createSmartEdge(\"smoothstep\");\n","import { createSmartEdge } from \"../createSmartEdge\";\n\nexport const SmartSimpleBezierEdge = createSmartEdge(\"simplebezier\");\n","import { createSmartEdge } from \"../createSmartEdge\";\n\nexport const SmartFloatingEdge = createSmartEdge(\"bezier\", { floating: true });\n","import { createSmartEdge } from \"../createSmartEdge\";\n\nexport const SmartEditableEdge = createSmartEdge(\"bezier\", { editable: true });\n","import { createSmartEdge } from \"../createSmartEdge\";\n\nexport const SmartCheckpointEdge = createSmartEdge(\"bezier\", {\n  checkpoints: true,\n});\n","import { getBoundingBoxes } from \"../functions\";\nimport { buildObstacleBoxes, rectIntersectsBox } from \"./obstacleIndex\";\nimport type {\n  GraphBoundingBox,\n  NodeBoundingBox,\n  PointInfo,\n} from \"../functions\";\nimport type { ObstacleBox } from \"./obstacleIndex\";\nimport type { Node, Rect } from \"@xyflow/react\";\n\n/**\n * Widening margins (in grid cells) tried before falling back to a full-graph\n * routing pass. `getSmartEdge` routes on a small sub-grid cropped to the\n * endpoints first (see `buildCorridorAttempt`), only paying for a bigger grid\n * when the narrower one has no path.\n */\nexport const CORRIDOR_MARGIN_CELLS = [8, 16, 32] as const;\n\n/** Axis-aligned rect (graph coordinates) covering both routing endpoints. */\ninterface EndpointRect {\n  xMin: number;\n  yMin: number;\n  xMax: number;\n  yMax: number;\n}\n\n/**\n * The endpoint bounding box inflated by `marginCells * gridRatio` plus\n * `nodePadding` on every side. Obstacles whose own padded rect intersects\n * this box are considered \"local\" to the corridor attempt.\n */\nconst buildCorridorRect = (\n  source: PointInfo,\n  target: PointInfo,\n  nodePadding: number,\n  gridRatio: number,\n  marginCells: number,\n): EndpointRect => {\n  const inflate = marginCells * gridRatio + nodePadding;\n\n  return {\n    xMin: Math.min(source.x, target.x) - inflate,\n    yMin: Math.min(source.y, target.y) - inflate,\n    xMax: Math.max(source.x, target.x) + inflate,\n    yMax: Math.max(source.y, target.y) + inflate,\n  };\n};\n\n/**\n * Indexes of the items whose corresponding obstacle box (same index) falls\n * inside `rect`. `boxes` must be parallel to the item array (i.e. built from\n * it by `buildObstacleBoxes`).\n */\nconst selectIntersectingIndexes = (\n  boxes: ObstacleBox[],\n  rect: EndpointRect,\n): number[] => {\n  const indexes: number[] = [];\n\n  boxes.forEach((box, index) => {\n    if (rectIntersectsBox(rect.xMin, rect.yMin, rect.xMax, rect.yMax, box)) {\n      indexes.push(index);\n    }\n  });\n\n  return indexes;\n};\n\n/** Bounding-box output for a single corridor (or full-graph) routing attempt. */\nexport interface CorridorAttempt {\n  graphBox: GraphBoundingBox;\n  nodeBoxes: NodeBoundingBox[];\n  avoidBoxes: NodeBoundingBox[];\n}\n\n/** Runs `getBoundingBoxes` over the nodes/areas at `nodeIndexes`/`areaIndexes`. */\nconst buildAttemptFromIndexes = (\n  nodes: Node[],\n  avoidAreas: Rect[],\n  nodeIndexes: number[],\n  areaIndexes: number[],\n  nodePadding: number,\n  gridRatio: number,\n  source: PointInfo,\n  target: PointInfo,\n): CorridorAttempt => {\n  const filteredNodes = nodeIndexes.map((index) => nodes[index]);\n  const filteredAreas = areaIndexes.map((index) => avoidAreas[index]);\n\n  const { graphBox, nodeBoxes, avoidBoxes } = getBoundingBoxes(\n    filteredNodes,\n    nodePadding,\n    gridRatio,\n    filteredAreas,\n    [\n      { x: source.x, y: source.y },\n      { x: target.x, y: target.y },\n    ],\n  );\n\n  return { graphBox, nodeBoxes, avoidBoxes };\n};\n\n/** Whether re-selecting against the latest graph box picked up no new\n * obstacles compared to the previous round, i.e. the selection has reached\n * a fixpoint. */\nconst isStableSelection = (\n  previousNodeCount: number,\n  previousAreaCount: number,\n  nextNodeIndexes: number[],\n  nextAreaIndexes: number[],\n): boolean =>\n  nextNodeIndexes.length === previousNodeCount &&\n  nextAreaIndexes.length === previousAreaCount;\n\n/**\n * Builds the bounding boxes for one rung of the corridor retry ladder: crop\n * `nodes` and `avoidAreas` down to whichever ones are local to the endpoints\n * at this margin, then hand the filtered sets to `getBoundingBoxes` so the\n * grid geometry, rounding, and border padding come out byte-identical to a\n * full-grid run over that same (smaller) obstacle set.\n *\n * A single corridor-rect filter pass is not enough: a large obstacle that\n * merely *touches* the corridor is included whole, which can stretch the\n * resulting graph box well past the corridor's own edge. A second obstacle\n * that didn't intersect the original (smaller) corridor rect can end up\n * sitting inside that stretched box — if it stayed excluded, the grid would\n * silently treat its space as walkable. So after computing the graph box, we\n * re-select every node/area against *that box* and rebuild; each round's\n * selection is always a superset of the previous one (a box built from a\n * given selection necessarily contains every member of it, so re-selecting\n * against that box re-includes them all), so the selected count only grows,\n * bounded by the total obstacle count — the loop always reaches a fixpoint\n * (no new obstacles picked up) within that many rounds, typically the very\n * first one.\n */\nexport const buildCorridorAttempt = (\n  source: PointInfo,\n  target: PointInfo,\n  nodes: Node[],\n  nodePadding: number,\n  gridRatio: number,\n  avoidAreas: Rect[],\n  marginCells: number,\n): CorridorAttempt => {\n  const corridor = buildCorridorRect(\n    source,\n    target,\n    nodePadding,\n    gridRatio,\n    marginCells,\n  );\n\n  const nodeObstacles = buildObstacleBoxes(nodes, nodePadding);\n  const areaObstacles = buildObstacleBoxes([], nodePadding, avoidAreas);\n\n  let nodeIndexes = selectIntersectingIndexes(nodeObstacles, corridor);\n  let areaIndexes = selectIntersectingIndexes(areaObstacles, corridor);\n\n  for (;;) {\n    const attempt = buildAttemptFromIndexes(\n      nodes,\n      avoidAreas,\n      nodeIndexes,\n      areaIndexes,\n      nodePadding,\n      gridRatio,\n      source,\n      target,\n    );\n\n    const nextNodeIndexes = selectIntersectingIndexes(\n      nodeObstacles,\n      attempt.graphBox,\n    );\n    const nextAreaIndexes = selectIntersectingIndexes(\n      areaObstacles,\n      attempt.graphBox,\n    );\n\n    if (\n      isStableSelection(\n        nodeIndexes.length,\n        areaIndexes.length,\n        nextNodeIndexes,\n        nextAreaIndexes,\n      )\n    ) {\n      return attempt;\n    }\n\n    nodeIndexes = nextNodeIndexes;\n    areaIndexes = nextAreaIndexes;\n  }\n};\n","import {\n  alignEndpoints,\n  createGrid,\n  getBoundingBoxes,\n  gridToGraphPoint,\n  pathfindingAStarDiagonal,\n  svgDrawSmoothLinePath,\n  toInteger,\n  NO_PATH_FOUND_ERROR,\n} from \"../functions\";\nimport type {\n  PointInfo,\n  PathFindingFunction,\n  DrawEdgeFunction,\n  GraphBoundingBox,\n  NodeBoundingBox,\n  Direction,\n} from \"../functions\";\nimport {\n  CORRIDOR_MARGIN_CELLS,\n  buildCorridorAttempt,\n} from \"../routing/corridor\";\nimport type { Node, EdgeProps, Rect } from \"@xyflow/react\";\n\n/**\n * `sourceX`/`sourceY`/`targetX`/`targetY` come straight from React Flow's\n * `EdgeProps`. `sourcePosition`/`targetPosition` are widened from `EdgeProps`'\n * nominal `Position` enum to the plain `Direction` string union, so callers\n * that only have a synthetic handle side (no real `Position`, e.g. waypoint\n * routing's `sideFacing`) can supply one too. Every real `Position` value is\n * still assignable here, so this is non-breaking for existing callers.\n */\nexport type EdgeParams = Pick<\n  EdgeProps,\n  \"sourceX\" | \"sourceY\" | \"targetX\" | \"targetY\"\n> & {\n  sourcePosition: Direction;\n  targetPosition: Direction;\n};\n\nexport interface GetSmartEdgeOptions {\n  gridRatio?: number;\n  nodePadding?: number;\n  drawEdge?: DrawEdgeFunction;\n  generatePath?: PathFindingFunction;\n  /**\n   * Extra rectangular areas (in graph coordinates) the path should route\n   * around, in addition to the nodes. Useful for keeping edges clear of edge\n   * labels or any other arbitrary regions. Each area uses the same\n   * `nodePadding` clearance as nodes.\n   */\n  avoidAreas?: Rect[];\n}\n\nexport type GetSmartEdgeParams<\n  NodeDataType extends Record<string, unknown> = Record<string, unknown>,\n> = EdgeParams & {\n  options?: GetSmartEdgeOptions;\n  nodes: Node<NodeDataType>[];\n};\n\nexport interface GetSmartEdgeReturn {\n  svgPathString: string;\n  edgeCenterX: number;\n  edgeCenterY: number;\n  /**\n   * The sequence of graph-coordinate points that make up the routed path\n   * (after endpoint alignment), excluding the source/target handle points.\n   * Used by waypoint routing to stitch multiple segments into a single edge.\n   */\n  points: number[][];\n  /**\n   * Always `true` for a result produced by this synchronous routing pass.\n   * The provider's `SmartEdgeRouteResult` uses `wasRouted: false` on its\n   * `\"clear\"` variant (native path, no A*). Pending provider routes are\n   * `null` from `useSmartEdgePath`, not a `wasRouted: false` placeholder.\n   */\n  wasRouted: true;\n}\n\n/** The output of one routing attempt: the grid geometry it ran on and the\n * raw grid-coordinate path `generatePath` returned. */\ninterface RouteAttempt {\n  graphBox: GraphBoundingBox;\n  fullPath: number[][];\n}\n\n/** Whether `error` is the \"no path found\" failure `generatePath` throws,\n * as opposed to some other error that should abort the retry ladder. */\nconst isNoPathFoundError = (error: unknown): boolean =>\n  error instanceof Error && error.message === NO_PATH_FOUND_ERROR;\n\n/** Builds a grid from a corridor (or full-graph) bounding-box result and\n * routes it, sharing the create-grid-then-generate-path shape across every\n * rung of the ladder and the final full-graph run. */\nconst routeOnBoxes = (\n  graphBox: GraphBoundingBox,\n  nodeBoxes: NodeBoundingBox[],\n  avoidBoxes: NodeBoundingBox[],\n  source: PointInfo,\n  target: PointInfo,\n  gridRatio: number,\n  generatePath: PathFindingFunction,\n): RouteAttempt => {\n  const { grid, start, end } = createGrid(\n    graphBox,\n    [...nodeBoxes, ...avoidBoxes],\n    source,\n    target,\n    gridRatio,\n  );\n\n  return { graphBox, fullPath: generatePath(grid, start, end) };\n};\n\n/** The final rung of the ladder: every node and avoid area, exactly like the\n * pre-corridor behavior (including `extraPoints` endpoint coverage). */\nconst routeFullGraph = (\n  nodes: Node[],\n  nodePadding: number,\n  gridRatio: number,\n  avoidAreas: Rect[],\n  source: PointInfo,\n  target: PointInfo,\n  generatePath: PathFindingFunction,\n): RouteAttempt => {\n  const { graphBox, nodeBoxes, avoidBoxes } = getBoundingBoxes(\n    nodes,\n    nodePadding,\n    gridRatio,\n    avoidAreas,\n    [\n      { x: source.x, y: source.y },\n      { x: target.x, y: target.y },\n    ],\n  );\n\n  return routeOnBoxes(\n    graphBox,\n    nodeBoxes,\n    avoidBoxes,\n    source,\n    target,\n    gridRatio,\n    generatePath,\n  );\n};\n\n/**\n * Routes on a sub-grid cropped around the endpoints first, widening the\n * margin at each rung of `CORRIDOR_MARGIN_CELLS` and finally falling back to\n * the full graph, so routing cost stays proportional to the obstacle density\n * local to the edge instead of the whole canvas. A rung is retried only when\n * `generatePath` reports `NO_PATH_FOUND_ERROR`; any other thrown error aborts\n * the ladder immediately so the outer `try`/`catch` can surface it.\n */\nconst routeWithCorridorLadder = (\n  nodes: Node[],\n  nodePadding: number,\n  gridRatio: number,\n  avoidAreas: Rect[],\n  source: PointInfo,\n  target: PointInfo,\n  generatePath: PathFindingFunction,\n): RouteAttempt => {\n  for (const marginCells of CORRIDOR_MARGIN_CELLS) {\n    const { graphBox, nodeBoxes, avoidBoxes } = buildCorridorAttempt(\n      source,\n      target,\n      nodes,\n      nodePadding,\n      gridRatio,\n      avoidAreas,\n      marginCells,\n    );\n\n    try {\n      return routeOnBoxes(\n        graphBox,\n        nodeBoxes,\n        avoidBoxes,\n        source,\n        target,\n        gridRatio,\n        generatePath,\n      );\n    } catch (error) {\n      if (!isNoPathFoundError(error)) {\n        throw error;\n      }\n    }\n  }\n\n  return routeFullGraph(\n    nodes,\n    nodePadding,\n    gridRatio,\n    avoidAreas,\n    source,\n    target,\n    generatePath,\n  );\n};\n\nexport const getSmartEdge = <\n  NodeDataType extends Record<string, unknown> = Record<string, unknown>,\n>({\n  options = {},\n  nodes,\n  sourceX,\n  sourceY,\n  targetX,\n  targetY,\n  sourcePosition,\n  targetPosition,\n}: GetSmartEdgeParams<NodeDataType>): GetSmartEdgeReturn | Error => {\n  try {\n    const {\n      drawEdge = svgDrawSmoothLinePath,\n      generatePath = pathfindingAStarDiagonal,\n      avoidAreas = [],\n    } = options;\n\n    let { gridRatio = 10, nodePadding = 10 } = options;\n    gridRatio = toInteger(gridRatio);\n    nodePadding = toInteger(nodePadding);\n\n    const source: PointInfo = {\n      x: sourceX,\n      y: sourceY,\n      position: sourcePosition,\n    };\n\n    const target: PointInfo = {\n      x: targetX,\n      y: targetY,\n      position: targetPosition,\n    };\n\n    // Route on a small sub-grid cropped around the endpoints first, widening\n    // the margin at each rung and finally falling back to the full graph, so\n    // routing cost stays proportional to the obstacles local to this edge\n    // instead of the whole canvas (see `routeWithCorridorLadder`).\n    const { graphBox, fullPath } = routeWithCorridorLadder(\n      nodes,\n      nodePadding,\n      gridRatio,\n      avoidAreas,\n      source,\n      target,\n      generatePath,\n    );\n\n    // Here we convert the grid path to a sequence of graph coordinates.\n    const graphPath = fullPath.map((gridPoint) => {\n      const [posX, posY] = gridPoint;\n      const graphPoint = gridToGraphPoint(\n        { x: posX, y: posY },\n        graphBox.xMin,\n        graphBox.yMin,\n        gridRatio,\n      );\n      return [graphPoint.x, graphPoint.y];\n    });\n\n    // Insert orthogonal alignment waypoints between the actual handle\n    // coordinates and the grid-snapped path, so edges leave/enter their nodes\n    // perpendicular to the handle instead of taking a small diagonal toward\n    // the first/last grid cell.\n    const alignedPath = alignEndpoints(source, target, graphPath);\n\n    // Finally, we can use the graph path to draw the edge\n    const svgPathString = drawEdge(source, target, alignedPath);\n\n    // Compute the edge's middle point using the full path, so users can use\n    // it to position their custom labels\n    const index = Math.floor(fullPath.length / 2);\n    const middlePoint = fullPath[index];\n    const [middleX, middleY] = middlePoint;\n    const { x: edgeCenterX, y: edgeCenterY } = gridToGraphPoint(\n      { x: middleX, y: middleY },\n      graphBox.xMin,\n      graphBox.yMin,\n      gridRatio,\n    );\n\n    return {\n      svgPathString,\n      edgeCenterX,\n      edgeCenterY,\n      points: alignedPath,\n      wasRouted: true,\n    };\n  } catch (error) {\n    /* v8 ignore else -- generatePath throws Error; unknown values are not part of the contract */\n    if (error instanceof Error) {\n      return error;\n    } else {\n      return new Error(`Unknown error: ${String(error)}`);\n    }\n  }\n};\n\nexport type GetSmartEdgeFunction = typeof getSmartEdge;\n","import { useNodes } from \"@xyflow/react\";\nimport { getSmartEdge } from \"../getSmartEdge\";\nimport { smartEdgePresets } from \"../smartEdgePresets\";\nimport {\n  getAbsoluteNodes,\n  getFloatingEdgeParams,\n  svgDrawSmoothLinePath,\n} from \"../functions\";\nimport type {\n  ConnectionLineComponentProps,\n  Node,\n  XYPosition,\n} from \"@xyflow/react\";\nimport type { GetSmartEdgeOptions } from \"../getSmartEdge\";\n\nexport type SmartFloatingConnectionLineProps = ConnectionLineComponentProps & {\n  options?: GetSmartEdgeOptions;\n};\n\n/**\n * A connection line component (for React Flow's `connectionLineComponent` prop)\n * that previews a smart, obstacle-avoiding floating edge while the user drags a\n * new connection. The source point is derived from the origin node's geometry\n * (floating), the target follows the cursor, and the line is routed with the\n * same pathfinding as {@link SmartFloatingEdge}.\n *\n * Falls back to a straight preview line when no valid smart path can be found.\n */\nexport function SmartFloatingConnectionLine({\n  fromNode,\n  toX,\n  toY,\n  toPosition,\n  connectionLineStyle,\n  options,\n}: Readonly<SmartFloatingConnectionLineProps>) {\n  const nodes = useNodes();\n  const absoluteNodes = getAbsoluteNodes(nodes);\n\n  const cursorPosition: XYPosition = { x: toX, y: toY };\n  const cursorNode: Node = {\n    id: \"smart-floating-connection-target\",\n    position: cursorPosition,\n    data: {},\n    measured: { width: 1, height: 1 },\n  };\n\n  const sourceNode: Node = {\n    id: fromNode.id,\n    position: fromNode.internals.positionAbsolute,\n    data: {},\n    measured: fromNode.measured,\n  };\n\n  const { sx, sy, sourcePos } = getFloatingEdgeParams(sourceNode, cursorNode);\n\n  const mergedOptions: GetSmartEdgeOptions = {\n    drawEdge: smartEdgePresets.bezier.drawEdge,\n    generatePath: smartEdgePresets.bezier.generatePath,\n    ...options,\n  };\n\n  const smartResponse = getSmartEdge({\n    sourcePosition: sourcePos,\n    targetPosition: toPosition,\n    sourceX: sx,\n    sourceY: sy,\n    targetX: toX,\n    targetY: toY,\n    nodes: absoluteNodes,\n    options: mergedOptions,\n  });\n\n  const svgPathString =\n    smartResponse instanceof Error\n      ? svgDrawSmoothLinePath({ x: sx, y: sy }, cursorPosition, [])\n      : smartResponse.svgPathString;\n\n  return (\n    <g>\n      <path\n        fill=\"none\"\n        className=\"react-flow__connection-path\"\n        style={connectionLineStyle}\n        d={svgPathString}\n      />\n      <circle cx={toX} cy={toY} r={3} stroke=\"black\" strokeWidth={1.5} />\n    </g>\n  );\n}\n\nexport type SmartFloatingConnectionLineFunction =\n  typeof SmartFloatingConnectionLine;\n","import { getSmartEdge } from \".\";\nimport { svgDrawSmoothLinePath, round, toInteger } from \"../functions\";\nimport type { XYPosition, Node } from \"@xyflow/react\";\nimport type { Direction } from \"../functions\";\nimport type {\n  GetSmartEdgeOptions,\n  GetSmartEdgeParams,\n  GetSmartEdgeReturn,\n} from \".\";\n\nexport type GetSmartEdgeWaypointsParams<\n  NodeDataType extends Record<string, unknown> = Record<string, unknown>,\n> = GetSmartEdgeParams<NodeDataType> & {\n  /**\n   * Intermediate points (in graph coordinates) the edge must pass through, in\n   * order from source to target. With no waypoints this behaves exactly like\n   * {@link getSmartEdge}.\n   */\n  waypoints: XYPosition[];\n};\n\n/**\n * Returns the side of `from` (top/right/bottom/left) that faces `to`, used as\n * the synthetic handle position for a free waypoint endpoint so each routed\n * segment leaves/enters the waypoint pointing along the path.\n *\n * Returns plain string literals rather than `Position` enum values: `Position`\n * is only a type import in this module (see the module-level note on worker\n * reachability), and `Position`'s values are exactly these strings, so real\n * `Position` values widen into `Direction` at every call site that mixes them\n * with this function's output (e.g. {@link routeChainSegments}).\n */\nconst sideFacing = (point: XYPosition, toward: XYPosition): Direction => {\n  const deltaX = toward.x - point.x;\n  const deltaY = toward.y - point.y;\n  if (Math.abs(deltaX) >= Math.abs(deltaY)) {\n    return deltaX >= 0 ? \"right\" : \"left\";\n  }\n  return deltaY >= 0 ? \"bottom\" : \"top\";\n};\n\ninterface StitchPoint {\n  x: number;\n  y: number;\n  /** Whether this point is a user waypoint (must lie exactly on the path). */\n  waypoint: boolean;\n}\n\n/**\n * Collapses consecutive duplicate coordinates (segment join artifacts),\n * preserving the waypoint flag if either side of the duplicate was a waypoint.\n */\nconst dedupeStitchPoints = (raw: StitchPoint[]): StitchPoint[] => {\n  const result: StitchPoint[] = [];\n  for (const point of raw) {\n    const lastIndex = result.length - 1;\n    if (\n      lastIndex >= 0 &&\n      result[lastIndex].x === point.x &&\n      result[lastIndex].y === point.y\n    ) {\n      result[lastIndex].waypoint = result[lastIndex].waypoint || point.waypoint;\n    } else {\n      result.push({ ...point });\n    }\n  }\n  return result;\n};\n\n/**\n * Routes each consecutive pair in the endpoint chain with {@link getSmartEdge}\n * and collects the stitched points. Free waypoint endpoints get a synthetic\n * handle position derived from the travel direction, and the waypoint\n * coordinates themselves are flagged so they can be pinned onto the path.\n */\nconst routeChainSegments = <\n  NodeDataType extends Record<string, unknown> = Record<string, unknown>,\n>(\n  chain: XYPosition[],\n  sourcePosition: Direction,\n  targetPosition: Direction,\n  nodes: Node<NodeDataType>[],\n  options: GetSmartEdgeOptions,\n): StitchPoint[] => {\n  const lastIndex = chain.length - 1;\n  const raw: StitchPoint[] = [];\n\n  for (let index = 0; index < lastIndex; index++) {\n    const from = chain[index];\n    const targetPoint = chain[index + 1];\n\n    const fromPosition =\n      index === 0 ? sourcePosition : sideFacing(from, targetPoint);\n    const toPosition =\n      index + 1 === lastIndex ? targetPosition : sideFacing(targetPoint, from);\n\n    const segment = getSmartEdge<NodeDataType>({\n      sourceX: from.x,\n      sourceY: from.y,\n      sourcePosition: fromPosition,\n      targetX: targetPoint.x,\n      targetY: targetPoint.y,\n      targetPosition: toPosition,\n      nodes,\n      options,\n    });\n\n    // On a per-segment failure we omit its routed points; the single\n    // `drawEdge` pass then connects the surrounding endpoints in the edge's own\n    // line style (bezier/straight/step) instead of dropping the edge.\n    if (!(segment instanceof Error)) {\n      for (const [posX, posY] of segment.points) {\n        raw.push({ x: posX, y: posY, waypoint: false });\n      }\n    }\n\n    // Pin the path to the actual waypoint coordinate (the control point\n    // handle). The final target point is the target handle, added by `drawEdge`.\n    if (index + 1 < lastIndex) {\n      raw.push({ x: targetPoint.x, y: targetPoint.y, waypoint: true });\n    }\n  }\n\n  return raw;\n};\n\n/** Fraction of the nearest-neighbor distance used for waypoint tangents. */\nconst STRADDLE_FRACTION = 0.5;\n\n/**\n * The logical routed path: every stitch point once, with waypoints kept at\n * their exact coordinates. Used for the edge center and for placing control\n * points (which match waypoints by exact coordinate).\n */\nconst toLogicalPoints = (points: StitchPoint[]): number[][] =>\n  points.map((point) => [point.x, point.y]);\n\n/**\n * Returns a pair of points straddling a waypoint along the local path tangent,\n * whose midpoint is exactly the waypoint.\n *\n * The smooth (quadratic) draw function passes through the midpoint of each\n * consecutive control pair, so a lone waypoint control would only pull the\n * curve toward it, and a duplicated waypoint would stop the curve dead (a\n * zero-velocity cusp) — both look like a kink rather than a single flow.\n * Emitting two points around the waypoint instead makes the curve pass\n * smoothly through it, tangent to the routed path. The pair is bounded by the\n * neighbor spacing so it never overshoots into a loop, and stays collinear\n * through the waypoint for the straight/step draw functions.\n */\nconst straddleWaypoint = (\n  waypoint: { x: number; y: number },\n  before: { x: number; y: number },\n  after: { x: number; y: number },\n): number[][] => {\n  const dirX = after.x - before.x;\n  const dirY = after.y - before.y;\n  const dirLength = Math.hypot(dirX, dirY);\n\n  if (dirLength === 0) {\n    return [[waypoint.x, waypoint.y]];\n  }\n\n  const unitX = dirX / dirLength;\n  const unitY = dirY / dirLength;\n\n  const distBefore = Math.hypot(waypoint.x - before.x, waypoint.y - before.y);\n  const distAfter = Math.hypot(waypoint.x - after.x, waypoint.y - after.y);\n  const length = Math.min(distBefore, distAfter) * STRADDLE_FRACTION;\n\n  return [\n    [waypoint.x - unitX * length, waypoint.y - unitY * length],\n    [waypoint.x + unitX * length, waypoint.y + unitY * length],\n  ];\n};\n\n/**\n * The points fed to `drawEdge`: identical to the logical path, except each\n * waypoint is replaced by a straddling pair so the rendered curve flows\n * smoothly through it (see {@link straddleWaypoint}).\n */\nconst toDrawPoints = (\n  points: StitchPoint[],\n  source: XYPosition,\n  target: XYPosition,\n): number[][] => {\n  const result: number[][] = [];\n\n  for (let index = 0; index < points.length; index++) {\n    const point = points[index];\n\n    if (!point.waypoint) {\n      result.push([point.x, point.y]);\n      continue;\n    }\n\n    const before = index > 0 ? points[index - 1] : source;\n    const after = index < points.length - 1 ? points[index + 1] : target;\n    result.push(...straddleWaypoint(point, before, after));\n  }\n\n  return result;\n};\n\n/**\n * Routes a smart edge that passes through a set of user-defined waypoints.\n *\n * Each consecutive pair in `[source, ...waypoints, target]` is routed\n * independently with {@link getSmartEdge} (so every segment still avoids\n * nodes), then the resulting point lists are stitched together and drawn as a\n * single continuous SVG path. Free waypoint endpoints are given a synthetic\n * handle position derived from the travel direction.\n *\n * If an individual segment fails to route (for example a waypoint dropped\n * inside a node), that segment degrades to a straight line between its\n * endpoints instead of blanking the whole edge.\n */\nexport const getSmartEdgeWaypoints = <\n  NodeDataType extends Record<string, unknown> = Record<string, unknown>,\n>(\n  params: GetSmartEdgeWaypointsParams<NodeDataType>,\n): GetSmartEdgeReturn | Error => {\n  const {\n    waypoints,\n    options = {},\n    nodes,\n    sourceX,\n    sourceY,\n    targetX,\n    targetY,\n    sourcePosition,\n    targetPosition,\n  } = params;\n\n  // No waypoints: identical to a plain smart edge.\n  if (waypoints.length === 0) {\n    return getSmartEdge(params);\n  }\n\n  try {\n    const { drawEdge = svgDrawSmoothLinePath } = options;\n    const gridRatio = Math.max(toInteger(options.gridRatio ?? 10), 1);\n\n    const source: XYPosition = { x: sourceX, y: sourceY };\n    const target: XYPosition = { x: targetX, y: targetY };\n\n    // Snap each waypoint to the nearest path-finding grid coordinate. The\n    // routed path is always grid-aligned, so routing/drawing through the exact\n    // (off-grid) drag position would force a sub-grid jog where the path meets\n    // the waypoint (a visible \"bump\"). Snapping keeps the path on the grid; the\n    // draggable control point itself still renders at the exact drag position.\n    const snappedWaypoints = waypoints.map((point) => ({\n      x: round(point.x, gridRatio),\n      y: round(point.y, gridRatio),\n    }));\n    const chain: XYPosition[] = [source, ...snappedWaypoints, target];\n\n    const segmentOptions = options;\n\n    const raw = routeChainSegments(\n      chain,\n      sourcePosition,\n      targetPosition,\n      nodes,\n      segmentOptions,\n    );\n\n    const stitched = dedupeStitchPoints(raw);\n    const points = toLogicalPoints(stitched);\n    const svgPathString = drawEdge(\n      { x: sourceX, y: sourceY, position: sourcePosition },\n      { x: targetX, y: targetY, position: targetPosition },\n      toDrawPoints(stitched, source, target),\n    );\n\n    const fullPath = [[source.x, source.y], ...points, [target.x, target.y]];\n    const middle = fullPath[Math.floor(fullPath.length / 2)];\n    const [edgeCenterX, edgeCenterY] = middle;\n\n    return { svgPathString, edgeCenterX, edgeCenterY, points, wasRouted: true };\n  } catch (error) {\n    /* v8 ignore else -- drawEdge throws Error; unknown values are not part of the contract */\n    if (error instanceof Error) {\n      return error;\n    } else {\n      return new Error(`Unknown error: ${String(error)}`);\n    }\n  }\n};\n\nexport type GetSmartEdgeWaypointsFunction = typeof getSmartEdgeWaypoints;\n","import type { GetSmartEdgeReturn } from \"../getSmartEdge\";\n\n/**\n * One edge's routing outcome as tracked by the provider store. `\"routed\"`\n * carries a full `getSmartEdge` result; `\"clear\"` tells the edge component\n * to render its native (non-smart) path locally instead, e.g. while an\n * async route is still pending or after routing failed.\n */\nexport type SmartEdgeRouteResult =\n  | ({ kind: \"routed\"; wasRouted: true } & GetSmartEdgeReturn)\n  | { kind: \"clear\"; wasRouted: false };\n\n/**\n * Keyed external store for smart-edge routes plus graph-wide node\n * drag/selection state, shaped for `useSyncExternalStore`: every getter\n * returns a stable reference until the slice it reads actually changes, so\n * React can skip re-rendering subscribers whose data was untouched.\n */\nexport interface SmartEdgeStore {\n  /** Subscribes to changes for one edge's route. Returns an unsubscribe\n   * function. */\n  subscribeEdge(edgeId: string, listener: () => void): () => void;\n  /** The edge's current route, or `undefined` if none has been set (or it\n   * was removed). Stable by reference until that edge's route changes. */\n  getRoute(edgeId: string): SmartEdgeRouteResult | undefined;\n  /** Applies a batch of route updates, notifying only the listeners of ids\n   * whose stored value reference actually changed. */\n  mergeRoutes(patch: Record<string, SmartEdgeRouteResult>): void;\n  /** Deletes the stored route for each id and notifies its listeners (who\n   * will then read `undefined` from `getRoute`). */\n  removeRoutes(edgeIds: string[]): void;\n  /** Subscribes to every route change: any `mergeRoutes`/`removeRoutes` call\n   * that actually changed at least one stored route. Coarser than\n   * `subscribeEdge` (fires for any edge's change, not just one id) — used by\n   * consumers that need to react to a neighbor's route without tracking\n   * every neighbor individually (e.g. hop bridges). Returns an unsubscribe\n   * function. */\n  subscribeAllRoutes(listener: () => void): () => void;\n  /** A counter incremented once per actual route change (any id). Read\n   * through `useSyncExternalStore` alongside `subscribeAllRoutes`: a bare\n   * number is trivially stable-by-value, so snapshots never need a custom\n   * equality check. */\n  getRoutesVersion(): number;\n  /** Subscribes to changes in dragging/selected node state. Returns an\n   * unsubscribe function. */\n  subscribeNodeState(listener: () => void): () => void;\n  /** The current set of dragging node ids. Stable by reference until the\n   * set's contents change. */\n  getDraggingNodeIds(): ReadonlySet<string>;\n  /** The current set of selected node ids. Stable by reference until the\n   * set's contents change. */\n  getSelectedNodeIds(): ReadonlySet<string>;\n  /** Replaces the dragging/selected node sets, notifying node-state\n   * listeners only if either set's contents actually changed. */\n  setNodeState(dragging: Set<string>, selected: Set<string>): void;\n}\n\n/**\n * True when two sets contain exactly the same elements, regardless of\n * insertion order. Used to decide whether a node-state update actually\n * changed anything, so `useSyncExternalStore` snapshots stay referentially\n * stable across no-op updates and React does not loop re-rendering.\n */\nconst setsEqual = (\n  first: ReadonlySet<string>,\n  second: ReadonlySet<string>,\n): boolean => {\n  if (first.size !== second.size) return false;\n\n  for (const item of first) {\n    if (!second.has(item)) return false;\n  }\n\n  return true;\n};\n\n/** Calls every listener currently in a set, if any are registered. Shared\n * by the per-edge and node-state notification paths. */\nconst notifyAll = (listeners: Set<() => void> | undefined): void => {\n  if (listeners === undefined) return;\n\n  listeners.forEach((listener) => {\n    listener();\n  });\n};\n\n/**\n * Creates a fresh, isolated `SmartEdgeStore`. One instance is meant to live\n * for the lifetime of a `SmartEdgeProvider`; this factory holds no shared\n * module-level state, so multiple providers never interfere.\n */\nexport const createSmartEdgeStore = (): SmartEdgeStore => {\n  const routes = new Map<string, SmartEdgeRouteResult>();\n  const edgeListeners = new Map<string, Set<() => void>>();\n  const allRoutesListeners = new Set<() => void>();\n  const nodeStateListeners = new Set<() => void>();\n\n  let draggingNodeIds: ReadonlySet<string> = new Set();\n  let selectedNodeIds: ReadonlySet<string> = new Set();\n  let routesVersion = 0;\n\n  /** Bumps `routesVersion` and notifies `subscribeAllRoutes` listeners.\n   * Called once per `mergeRoutes`/`removeRoutes` call that changed at least\n   * one route — never per individual id — so a batch touching many edges\n   * still only produces one version bump. */\n  const notifyRoutesChanged = (): void => {\n    routesVersion += 1;\n    notifyAll(allRoutesListeners);\n  };\n\n  return {\n    subscribeEdge(edgeId, listener) {\n      let listeners = edgeListeners.get(edgeId);\n      if (listeners === undefined) {\n        listeners = new Set();\n        edgeListeners.set(edgeId, listeners);\n      }\n      listeners.add(listener);\n\n      return () => {\n        listeners.delete(listener);\n        if (listeners.size === 0) edgeListeners.delete(edgeId);\n      };\n    },\n\n    getRoute(edgeId) {\n      return routes.get(edgeId);\n    },\n\n    mergeRoutes(patch) {\n      let changed = false;\n\n      for (const [edgeId, value] of Object.entries(patch)) {\n        if (routes.get(edgeId) === value) continue;\n\n        routes.set(edgeId, value);\n        notifyAll(edgeListeners.get(edgeId));\n        changed = true;\n      }\n\n      if (changed) notifyRoutesChanged();\n    },\n\n    removeRoutes(edgeIds) {\n      let changed = false;\n\n      for (const edgeId of edgeIds) {\n        if (routes.has(edgeId)) changed = true;\n        routes.delete(edgeId);\n        notifyAll(edgeListeners.get(edgeId));\n      }\n\n      if (changed) notifyRoutesChanged();\n    },\n\n    subscribeAllRoutes(listener) {\n      allRoutesListeners.add(listener);\n\n      return () => {\n        allRoutesListeners.delete(listener);\n      };\n    },\n\n    getRoutesVersion() {\n      return routesVersion;\n    },\n\n    subscribeNodeState(listener) {\n      nodeStateListeners.add(listener);\n\n      return () => {\n        nodeStateListeners.delete(listener);\n      };\n    },\n\n    getDraggingNodeIds() {\n      return draggingNodeIds;\n    },\n\n    getSelectedNodeIds() {\n      return selectedNodeIds;\n    },\n\n    setNodeState(dragging, selected) {\n      let changed = false;\n\n      if (!setsEqual(draggingNodeIds, dragging)) {\n        draggingNodeIds = dragging;\n        changed = true;\n      }\n\n      if (!setsEqual(selectedNodeIds, selected)) {\n        selectedNodeIds = selected;\n        changed = true;\n      }\n\n      if (changed) notifyAll(nodeStateListeners);\n    },\n  };\n};\n","import type { ObstacleBox } from \"./obstacleIndex\";\n\n/** A generic least-recently-used cache keyed by string. `get` marks its key\n * as most recently used; `set` evicts the single oldest (least recently\n * used) entry once the cache holds more than `maxEntries`. Kept free of any\n * routing-result type so it can be shared before that type exists. */\nexport interface RouteCache<T> {\n  get(key: string): T | undefined;\n  set(key: string, value: T): void;\n  clear(): void;\n  readonly size: number;\n}\n\nconst DEFAULT_MAX_ENTRIES = 500;\n\n/**\n * Creates an LRU cache backed by a `Map` (whose keys iterate in insertion\n * order): `get` re-inserts its key so it sorts last, and `set` reads the\n * map's first key back out once capacity is exceeded to evict it.\n */\nexport const createRouteCache = <T>(\n  maxEntries: number = DEFAULT_MAX_ENTRIES,\n): RouteCache<T> => {\n  const store = new Map<string, T>();\n\n  return {\n    get(key) {\n      const value = store.get(key);\n      if (value === undefined) return undefined;\n\n      store.delete(key);\n      store.set(key, value);\n      return value;\n    },\n    set(key, value) {\n      store.delete(key);\n      store.set(key, value);\n\n      if (store.size <= maxEntries) return;\n      const [oldestKey] = store.keys();\n      store.delete(oldestKey);\n    },\n    clear() {\n      store.clear();\n    },\n    get size() {\n      return store.size;\n    },\n  };\n};\n\n/**\n * djb2 string hash, returned as a base-36 string. Used to compress the\n * corridor's obstacle list into a short, stable cache-key segment instead of\n * hashing the raw obstacle data on every lookup.\n */\nexport const hashString = (input: string): string => {\n  let hash = 5381;\n\n  for (let index = 0; index < input.length; index += 1) {\n    hash = (hash * 33 + input.charCodeAt(index)) | 0;\n  }\n\n  return (hash >>> 0).toString(36);\n};\n\n/** The subset of a routed edge's props that determine its route. Typed\n * locally (rather than imported from `@xyflow/react`) to keep this module\n * dependency-light. */\ninterface RouteCacheEdge {\n  sourceX: number;\n  sourceY: number;\n  targetX: number;\n  targetY: number;\n  sourcePosition: string;\n  targetPosition: string;\n  preset: string;\n  waypoints?: { x: number; y: number }[];\n  options?: {\n    gridRatio?: number;\n    nodePadding?: number;\n    avoidAreas?: { x: number; y: number; width: number; height: number }[];\n    borderRadius?: number;\n  };\n}\n\nconst quantize = (value: number): number => Math.round(value);\n\nconst obstacleKeyPart = (box: ObstacleBox): string =>\n  [box.id, box.xMin, box.yMin, box.xMax, box.yMax].join(\",\");\n\nconst waypointKeyPart = (point: { x: number; y: number }): string =>\n  `${String(quantize(point.x))}:${String(quantize(point.y))}`;\n\n/**\n * Builds a route-cache key for one edge. Endpoint and waypoint coordinates\n * are quantized with `Math.round` so sub-pixel layout jitter still hits the\n * cache, while the corridor's obstacle list is hashed so any change to the\n * *local* obstacle set (an added, removed, or moved node) busts it.\n * Per-edge options (`gridRatio`, `nodePadding`, `avoidAreas`, `borderRadius`)\n * are serialized so `createSmartEdge(..., { gridRatio: 5 })` cannot reuse a\n * path computed under different overrides. `corridorObstacles` is expected\n * to already be filtered to the routing corridor by the caller — an obstacle\n * outside it is simply absent from the list and cannot affect the key.\n */\nexport const routeCacheKey = (\n  edge: RouteCacheEdge,\n  optionsKey: string,\n  corridorObstacles: ObstacleBox[],\n): string => {\n  const waypointsKey = (edge.waypoints ?? []).map(waypointKeyPart).join(\";\");\n  const obstaclesKey = hashString(\n    corridorObstacles.map(obstacleKeyPart).join(\"|\"),\n  );\n\n  return [\n    quantize(edge.sourceX),\n    quantize(edge.sourceY),\n    quantize(edge.targetX),\n    quantize(edge.targetY),\n    edge.sourcePosition,\n    edge.targetPosition,\n    edge.preset,\n    waypointsKey,\n    optionsKey,\n    JSON.stringify(edge.options ?? null),\n    obstaclesKey,\n  ].join(\"|\");\n};\n","import type { Node } from \"@xyflow/react\";\n\n/**\n * A per-node snapshot of the state that can affect routing: absolute\n * position, measured size, and the dragging/selected flags. Absolute\n * positions are the caller's responsibility — this module only reads\n * `node.position` verbatim, so a provider resolving subflow offsets (see\n * `getAbsoluteNodes`) must do so before snapshotting.\n */\nexport interface NodeSnapshot {\n  id: string;\n  x: number;\n  y: number;\n  width: number;\n  height: number;\n  dragging: boolean;\n  selected: boolean;\n}\n\n/**\n * Captures every node's routing-relevant state, using the same\n * measured-size floor as `getBoundingBoxes`/`buildObstacleBoxes` (missing\n * dimensions collapse to 1px) so a snapshot's rect lines up with the\n * obstacle boxes built from the same nodes.\n */\nexport const snapshotNodes = (nodes: Node[]): NodeSnapshot[] =>\n  nodes.map((node) => ({\n    id: node.id,\n    x: node.position.x,\n    y: node.position.y,\n    width: Math.max(node.measured?.width ?? 0, 1),\n    height: Math.max(node.measured?.height ?? 0, 1),\n    dragging: node.dragging ?? false,\n    selected: node.selected ?? false,\n  }));\n\n/** Axis-aligned rect in graph coordinates (an `ObstacleBox` minus its `id`:\n * a changed rect no longer needs to identify an owning node). */\ninterface ChangedRect {\n  xMin: number;\n  yMin: number;\n  xMax: number;\n  yMax: number;\n}\n\n/**\n * Result of comparing two node snapshots: whether anything routing-relevant\n * changed, the padded rects touched by any moved/resized/added/removed node\n * (a moved/resized node contributes both its old and new rect, since a\n * cached route can be invalidated by either the space it vacated or the\n * space it now occupies), and the dragging/selected id sets read from\n * `next` — populated regardless of `changed`, so drag-preview fast paths\n * can key off them directly.\n */\nexport interface NodeDiff {\n  changed: boolean;\n  changedRects: ChangedRect[];\n  draggingNodeIds: Set<string>;\n  selectedNodeIds: Set<string>;\n}\n\nconst paddedRect = (\n  snapshot: NodeSnapshot,\n  nodePadding: number,\n): ChangedRect => ({\n  xMin: snapshot.x - nodePadding,\n  yMin: snapshot.y - nodePadding,\n  xMax: snapshot.x + snapshot.width + nodePadding,\n  yMax: snapshot.y + snapshot.height + nodePadding,\n});\n\nconst hasMoved = (previous: NodeSnapshot, current: NodeSnapshot): boolean =>\n  previous.x !== current.x ||\n  previous.y !== current.y ||\n  previous.width !== current.width ||\n  previous.height !== current.height;\n\n/**\n * Handles one previously-known node: pushes its old rect if it was removed,\n * both its old and new rect if it moved/resized, or nothing if it is still\n * present and unchanged. Returns whether this node contributed a change.\n */\nconst collectPreviousNodeRects = (\n  previousSnapshot: NodeSnapshot,\n  nextSnapshot: NodeSnapshot | undefined,\n  nodePadding: number,\n  changedRects: ChangedRect[],\n): boolean => {\n  if (nextSnapshot === undefined) {\n    changedRects.push(paddedRect(previousSnapshot, nodePadding));\n    return true;\n  }\n\n  if (hasMoved(previousSnapshot, nextSnapshot)) {\n    changedRects.push(paddedRect(previousSnapshot, nodePadding));\n    changedRects.push(paddedRect(nextSnapshot, nodePadding));\n    return true;\n  }\n\n  return false;\n};\n\n/**\n * Compares two node snapshots (matched by id) and reports what changed. A\n * node that neither moved nor resized contributes no rects; a moved/resized\n * node contributes both its old and new padded rect; an added or removed\n * node contributes the one rect it has.\n */\nexport const diffNodeSnapshots = (\n  previous: NodeSnapshot[],\n  next: NodeSnapshot[],\n  nodePadding: number,\n): NodeDiff => {\n  const previousById = new Map(\n    previous.map((snapshot) => [snapshot.id, snapshot]),\n  );\n  const nextById = new Map(next.map((snapshot) => [snapshot.id, snapshot]));\n\n  const changedRects: ChangedRect[] = [];\n  let changed = false;\n\n  previousById.forEach((previousSnapshot, nodeId) => {\n    const contributed = collectPreviousNodeRects(\n      previousSnapshot,\n      nextById.get(nodeId),\n      nodePadding,\n      changedRects,\n    );\n    if (contributed) changed = true;\n  });\n\n  nextById.forEach((nextSnapshot, nodeId) => {\n    if (previousById.has(nodeId)) return;\n    changedRects.push(paddedRect(nextSnapshot, nodePadding));\n    changed = true;\n  });\n\n  const draggingNodeIds = new Set<string>();\n  const selectedNodeIds = new Set<string>();\n\n  next.forEach((snapshot) => {\n    if (snapshot.dragging) draggingNodeIds.add(snapshot.id);\n    if (snapshot.selected) selectedNodeIds.add(snapshot.id);\n  });\n\n  return { changed, changedRects, draggingNodeIds, selectedNodeIds };\n};\n\n/**\n * Straightforward axis-aligned overlap test (exclusive bounds, same\n * convention as `rectIntersectsBox`) between a routing corridor and a\n * diff's changed rects: true as soon as any rect overlaps the corridor's\n * interior.\n */\nexport const corridorTouchesRects = (\n  corridor: ChangedRect,\n  rects: ChangedRect[],\n): boolean =>\n  rects.some(\n    (rect) =>\n      corridor.xMin < rect.xMax &&\n      corridor.xMax > rect.xMin &&\n      corridor.yMin < rect.yMax &&\n      corridor.yMax > rect.yMin,\n  );\n","import { rectIntersectsBox } from \"./obstacleIndex\";\nimport type { ObstacleBox } from \"./obstacleIndex\";\nimport type { XYPosition } from \"@xyflow/react\";\n\n/** Axis-aligned rect in graph coordinates — an `ObstacleBox` without the id\n * it doesn't need here. */\nexport type EdgeRect = Omit<ObstacleBox, \"id\">;\n\n/**\n * The bounding box of a polyline (graph coordinates), inflated by `pad` on\n * every side. Used to turn an edge's actual rendered path — the routed\n * `points`, or the native (unrouted) polyline it draws while clear — into\n * the region that determines whether that specific path is still valid: any\n * node entering or leaving this region can plausibly change it, so this is\n * the edge's real invalidation corridor, as opposed to a fixed guess based\n * only on its endpoints (see `schedulerFlush.ts`'s `buildEdgeCorridor`, kept\n * only to bucket the route cache's key, not to decide correctness).\n */\nexport const boundsOfPolyline = (\n  points: readonly XYPosition[],\n  pad: number,\n): EdgeRect => {\n  const xValues = points.map((point) => point.x);\n  const yValues = points.map((point) => point.y);\n\n  return {\n    xMin: Math.min(...xValues) - pad,\n    yMin: Math.min(...yValues) - pad,\n    xMax: Math.max(...xValues) + pad,\n    yMax: Math.max(...yValues) + pad,\n  };\n};\n\n/** Every obstacle box whose rect overlaps `corridor`. */\nexport const filterObstaclesInCorridor = (\n  corridor: EdgeRect,\n  boxes: ObstacleBox[],\n): ObstacleBox[] =>\n  boxes.filter((box) =>\n    rectIntersectsBox(\n      corridor.xMin,\n      corridor.yMin,\n      corridor.xMax,\n      corridor.yMax,\n      box,\n    ),\n  );\n\n/**\n * Raw obstacle signature (before hashing): an exact, order-sensitive string\n * two obstacle lists only share when every entry has the same id and rect.\n * Comparing this — rather than just a hashed cache key — catches the rare\n * hash collision a key alone can't detect, and, recomputed against an edge's\n * actual-path corridor instead of the cache key's rung-0 one, is what\n * actually re-validates a cache hit against the current obstacle set.\n */\nexport const obstaclesSignatureOf = (boxes: ObstacleBox[]): string =>\n  boxes\n    .map((box) => [box.id, box.xMin, box.yMin, box.xMax, box.yMax].join(\",\"))\n    .join(\"|\");\n","import {\n  buildObstacleBoxes,\n  isPolylineBlocked,\n  nativeStepPolyline,\n} from \"./obstacleIndex\";\nimport { routeCacheKey } from \"./routeCache\";\nimport { CORRIDOR_MARGIN_CELLS } from \"./corridor\";\nimport { diffNodeSnapshots, corridorTouchesRects } from \"./invalidation\";\nimport {\n  boundsOfPolyline,\n  filterObstaclesInCorridor,\n  obstaclesSignatureOf,\n} from \"./invalidationCorridor\";\nimport type { RouteCache } from \"./routeCache\";\nimport type { ObstacleBox } from \"./obstacleIndex\";\nimport type { EdgeRect } from \"./invalidationCorridor\";\nimport type { SmartEdgeRouteResult } from \"./providerStore\";\nimport type {\n  SchedulerDeps,\n  SchedulerState,\n  RegisteredSmartEdge,\n  ResolvedProviderOptions,\n  SmartEdgeMetrics,\n} from \"./scheduler\";\nimport type { XYPosition } from \"@xyflow/react\";\n\n/** A cached route plus enough to detect a cache-key hash collision (the raw\n * obstacle signature the key's hash was built from) and to re-validate the\n * hit against the current graph: `corridor` is the bbox of the actual path\n * this route drew (not the fixed rung-0 guess used only to bucket the\n * cache's key — see `buildEdgeCorridor`), and `obstaclesSignature` is the\n * raw signature of the obstacles that were local to that corridor when this\n * entry was stored. */\nexport interface CachedRoute {\n  result: SmartEdgeRouteResult;\n  obstaclesSignature: string;\n  corridor: EdgeRect;\n}\n\ntype SchedulerCounts = Pick<\n  SmartEdgeMetrics,\n  \"routed\" | \"cacheHits\" | \"clear\" | \"deferred\" | \"unchanged\"\n>;\n\n/** Everything one flush's per-edge decisions need that stays constant across\n * the whole flush, bundled so helpers take one argument instead of several. */\ninterface FlushContext {\n  draggingNodeIds: ReadonlySet<string>;\n  changedRects: EdgeRect[];\n  forcedEdgeIds: ReadonlySet<string>;\n  obstacleBoxes: ObstacleBox[];\n  optionsKey: string;\n  options: ResolvedProviderOptions;\n  cache: RouteCache<CachedRoute>;\n  signatures: Map<string, string>;\n  /** Each edge's actual-path invalidation corridor, mirroring `signatures`'\n   * lifecycle: set whenever a route is produced (clear, cache hit, or\n   * dispatch), left untouched for deferred/unchanged edges, and read by\n   * `isEdgeUnchanged` instead of a freshly-guessed one. */\n  pathCorridors: Map<string, EdgeRect>;\n}\n\ninterface FlushAccumulators {\n  nextDeferredIds: Set<string>;\n  dispatchItems: RegisteredSmartEdge[];\n  routeMerges: Record<string, SmartEdgeRouteResult>;\n  counts: SchedulerCounts;\n}\n\nconst STEP_LIKE_PRESETS = new Set([\"step\", \"smoothstep\"]);\n\n/** The subset of an edge's registration that determines its route. Distinct\n * from `routeCacheKey`'s (rounded, obstacle-hashed) key: this is an exact\n * comparison used only to detect \"nothing changed since last processed\". */\nconst edgeSignature = (edge: RegisteredSmartEdge): string =>\n  JSON.stringify({\n    sourceX: edge.sourceX,\n    sourceY: edge.sourceY,\n    targetX: edge.targetX,\n    targetY: edge.targetY,\n    sourcePosition: edge.sourcePosition,\n    targetPosition: edge.targetPosition,\n    preset: edge.preset,\n    options: edge.options,\n    waypoints: edge.waypoints,\n  });\n\n/** The endpoint bounding box inflated by the first (narrowest) corridor\n * rung's margin. Kept only to bucket the route cache's key: a wider search\n * that succeeds on a bigger rung can physically traverse space well outside\n * this box, so it is deliberately NOT used as an invalidation region (see\n * `pathCorridors` / `actualPathCorridor` for the region that actually is). */\nconst buildEdgeCorridor = (\n  edge: RegisteredSmartEdge,\n  gridRatio: number,\n): EdgeRect => {\n  const inflate = CORRIDOR_MARGIN_CELLS[0] * gridRatio;\n\n  return {\n    xMin: Math.min(edge.sourceX, edge.targetX) - inflate,\n    yMin: Math.min(edge.sourceY, edge.targetY) - inflate,\n    xMax: Math.max(edge.sourceX, edge.targetX) + inflate,\n    yMax: Math.max(edge.sourceY, edge.targetY) + inflate,\n  };\n};\n\n/** The bbox of an edge's actual rendered path (routed points or the native\n * polyline), inflated by `nodePadding` plus one grid cell — the edge's real\n * invalidation corridor. */\nconst actualPathCorridor = (\n  points: readonly XYPosition[],\n  context: FlushContext,\n): EdgeRect =>\n  boundsOfPolyline(\n    points,\n    context.options.nodePadding + context.options.gridRatio,\n  );\n\n/** Builds the route-cache key for one edge: coordinates/options plus a hash\n * of the obstacles local to the rung-0 corridor (a fast bucket only — a\n * cache-key hit is re-validated against the actual-path corridor by\n * `findCacheHit` before being trusted). */\nconst buildCacheKey = (\n  edge: RegisteredSmartEdge,\n  context: FlushContext,\n): string => {\n  const corridor = buildEdgeCorridor(edge, context.options.gridRatio);\n  const corridorObstacles = filterObstaclesInCorridor(\n    corridor,\n    context.obstacleBoxes,\n  );\n\n  return routeCacheKey(edge, context.optionsKey, corridorObstacles);\n};\n\n/** A cache-key hit only counts if the obstacles local to the cached route's\n * actual-path corridor still match what it was stored with — this is what\n * catches both a (extremely rare) djb2 hash collision the key can't detect\n * on its own, and a real obstacle change in the band the path traverses\n * that the rung-0 key bucket never saw. */\nconst findCacheHit = (\n  edge: RegisteredSmartEdge,\n  context: FlushContext,\n): CachedRoute | undefined => {\n  const cached = context.cache.get(buildCacheKey(edge, context));\n  if (cached === undefined) return undefined;\n\n  const currentObstacles = filterObstaclesInCorridor(\n    cached.corridor,\n    context.obstacleBoxes,\n  );\n  return cached.obstaclesSignature === obstaclesSignatureOf(currentObstacles)\n    ? cached\n    : undefined;\n};\n\n/** Whether either endpoint of `edge` is currently being dragged. */\nconst isEdgeDragging = (\n  edge: RegisteredSmartEdge,\n  draggingNodeIds: ReadonlySet<string>,\n): boolean =>\n  draggingNodeIds.has(edge.source) || draggingNodeIds.has(edge.target);\n\n/** Whether `edge` can skip this flush entirely: it has a stored actual-path\n * corridor from a previous flush (absent means it was never routed, or its\n * last result never produced one — e.g. a non-routed dispatch response —\n * either way it cannot be \"unchanged\"), it isn't forced past this check\n * (e.g. by a just-ended drag), its registration signature is exactly what it\n * was last time it was processed, and no changed rect this flush touches\n * that stored corridor. */\nconst isEdgeUnchanged = (\n  edgeId: string,\n  currentSignature: string,\n  context: FlushContext,\n): boolean => {\n  const corridor = context.pathCorridors.get(edgeId);\n\n  return (\n    corridor !== undefined &&\n    !context.forcedEdgeIds.has(edgeId) &&\n    context.signatures.get(edgeId) === currentSignature &&\n    !corridorTouchesRects(corridor, context.changedRects)\n  );\n};\n\n/** The polyline this edge would render natively (no smart routing): a\n * straight segment for bezier/straight/simplebezier presets, the Z/L step\n * skeleton for step/smoothstep. Used to answer \"is it already clear?\" and,\n * when it is, doubles as its actual-path corridor. */\nconst nativePolylineFor = (edge: RegisteredSmartEdge): XYPosition[] =>\n  STEP_LIKE_PRESETS.has(edge.preset)\n    ? nativeStepPolyline(\n        edge.sourceX,\n        edge.sourceY,\n        edge.sourcePosition,\n        edge.targetX,\n        edge.targetY,\n        edge.targetPosition,\n      )\n    : [\n        { x: edge.sourceX, y: edge.sourceY },\n        { x: edge.targetX, y: edge.targetY },\n      ];\n\n/** Decides and folds one edge's fate into the flush's running totals, in the\n * fixed priority order: deferred (still dragging) → unchanged (nothing\n * relevant moved, and not forced past this check) → cache hit → clear\n * (unblocked and only routed when blocked) → dispatch. Every outcome except\n * `deferred` and `unchanged` updates the edge's last-processed signature;\n * leaving it stale while deferred is what lets a drag-end force a real\n * re-decision even though the edge's own registration never changed while\n * it was being skipped. Every outcome that produces a route (cache hit,\n * clear) also records its actual-path corridor for the next flush; a\n * dispatched edge's corridor is recorded later, once its route arrives (see\n * `dispatchAndMerge`). */\nconst processEdge = (\n  edge: RegisteredSmartEdge,\n  context: FlushContext,\n  accumulators: FlushAccumulators,\n): void => {\n  if (\n    isEdgeDragging(edge, context.draggingNodeIds) &&\n    !context.options.routeWhileDragging\n  ) {\n    accumulators.counts.deferred += 1;\n    accumulators.nextDeferredIds.add(edge.id);\n    return;\n  }\n\n  const currentSignature = edgeSignature(edge);\n  if (isEdgeUnchanged(edge.id, currentSignature, context)) {\n    accumulators.counts.unchanged += 1;\n    return;\n  }\n\n  context.signatures.set(edge.id, currentSignature);\n\n  const cachedRoute = findCacheHit(edge, context);\n  if (cachedRoute) {\n    accumulators.counts.cacheHits += 1;\n    accumulators.routeMerges[edge.id] = cachedRoute.result;\n    context.pathCorridors.set(edge.id, cachedRoute.corridor);\n    return;\n  }\n\n  if (context.options.routeOnlyWhenBlocked) {\n    const polyline = nativePolylineFor(edge);\n    const excludeIds = new Set([edge.source, edge.target]);\n    if (!isPolylineBlocked(polyline, context.obstacleBoxes, excludeIds)) {\n      accumulators.counts.clear += 1;\n      accumulators.routeMerges[edge.id] = { kind: \"clear\", wasRouted: false };\n      context.pathCorridors.set(edge.id, actualPathCorridor(polyline, context));\n      return;\n    }\n  }\n\n  accumulators.counts.routed += 1;\n  accumulators.dispatchItems.push(edge);\n};\n\nconst buildFlushContext = (\n  deps: SchedulerDeps,\n  state: SchedulerState,\n): FlushContext => {\n  const diff = diffNodeSnapshots(\n    state.flushedSnapshot,\n    state.snapshot,\n    deps.options.nodePadding,\n  );\n  const draggingActive = diff.draggingNodeIds.size > 0;\n  const dragJustEnded = state.draggingWasActive && !draggingActive;\n  state.draggingWasActive = draggingActive;\n\n  return {\n    draggingNodeIds: diff.draggingNodeIds,\n    changedRects: diff.changedRects,\n    forcedEdgeIds: dragJustEnded ? state.deferredEdgeIds : new Set<string>(),\n    obstacleBoxes: buildObstacleBoxes(\n      state.absoluteNodes,\n      deps.options.nodePadding,\n      deps.options.avoidAreas,\n    ),\n    optionsKey: JSON.stringify({\n      nodePadding: deps.options.nodePadding,\n      gridRatio: deps.options.gridRatio,\n      avoidAreas: deps.options.avoidAreas,\n    }),\n    options: deps.options,\n    cache: state.cache,\n    signatures: state.signatures,\n    pathCorridors: state.pathCorridors,\n  };\n};\n\nconst emitMetrics = (\n  deps: SchedulerDeps,\n  batchId: number,\n  executedOn: \"worker\" | \"main\",\n  batchLatencyMs: number,\n  mainThreadBlockingMs: number,\n  counts: SchedulerCounts,\n): void => {\n  deps.onMetrics?.({\n    batchId,\n    executedOn,\n    batchLatencyMs,\n    mainThreadBlockingMs,\n    ...counts,\n  });\n};\n\nconst dispatchAndMerge = async (\n  deps: SchedulerDeps,\n  state: SchedulerState,\n  context: FlushContext,\n  accumulators: FlushAccumulators,\n  batchId: number,\n): Promise<void> => {\n  if (Object.keys(accumulators.routeMerges).length > 0) {\n    deps.store.mergeRoutes(accumulators.routeMerges);\n  }\n\n  if (accumulators.dispatchItems.length === 0) {\n    emitMetrics(deps, batchId, \"main\", 0, 0, accumulators.counts);\n    return;\n  }\n\n  const outcome = await deps.dispatch(\n    state.rawNodes,\n    accumulators.dispatchItems,\n  );\n  if (state.disposed || batchId !== state.batchId) return;\n\n  const dispatchMerges: Record<string, SmartEdgeRouteResult> = {};\n  Object.entries(outcome.results).forEach(([edgeId, result]) => {\n    dispatchMerges[edgeId] = result;\n    const dispatchedEdge = state.edges.get(edgeId);\n    if (!dispatchedEdge || result.kind !== \"routed\") return;\n\n    const corridor = actualPathCorridor(\n      result.points.map(([pointX, pointY]) => ({ x: pointX, y: pointY })),\n      context,\n    );\n    state.pathCorridors.set(edgeId, corridor);\n    state.cache.set(buildCacheKey(dispatchedEdge, context), {\n      result,\n      corridor,\n      obstaclesSignature: obstaclesSignatureOf(\n        filterObstaclesInCorridor(corridor, context.obstacleBoxes),\n      ),\n    });\n  });\n\n  if (Object.keys(dispatchMerges).length > 0) {\n    deps.store.mergeRoutes(dispatchMerges);\n  }\n\n  emitMetrics(\n    deps,\n    batchId,\n    outcome.executedOn,\n    outcome.durationMs,\n    outcome.executedOn === \"main\" ? outcome.durationMs : 0,\n    accumulators.counts,\n  );\n};\n\n/** Runs one flush to completion: decides every registered edge's fate,\n * merges cache/clear results into the store immediately, then (if anything\n * needs it) dispatches the remainder and merges/caches the response — unless\n * a later flush has already superseded this one's `batchId` by the time the\n * response arrives. */\nexport const runFlush = async (\n  deps: SchedulerDeps,\n  state: SchedulerState,\n): Promise<void> => {\n  if (state.disposed) return;\n\n  const context = buildFlushContext(deps, state);\n  const accumulators: FlushAccumulators = {\n    nextDeferredIds: new Set(),\n    dispatchItems: [],\n    routeMerges: {},\n    counts: { routed: 0, cacheHits: 0, clear: 0, deferred: 0, unchanged: 0 },\n  };\n  state.edges.forEach((edge) => {\n    processEdge(edge, context, accumulators);\n  });\n\n  state.deferredEdgeIds = accumulators.nextDeferredIds;\n  state.flushedSnapshot = state.snapshot;\n  state.batchId += 1;\n\n  await dispatchAndMerge(deps, state, context, accumulators, state.batchId);\n};\n","import { getAbsoluteNodes } from \"../functions\";\nimport { createRouteCache } from \"./routeCache\";\nimport { snapshotNodes, diffNodeSnapshots } from \"./invalidation\";\nimport { runFlush } from \"./schedulerFlush\";\nimport type { CachedRoute } from \"./schedulerFlush\";\nimport type { RouteCache } from \"./routeCache\";\nimport type { EdgeRect } from \"./invalidationCorridor\";\nimport type { SmartEdgeStore, SmartEdgeRouteResult } from \"./providerStore\";\nimport type { SmartEdgeBatchItem } from \"./routeBatch\";\nimport type { Node, Rect } from \"@xyflow/react\";\n\n/** Aggregate counters for one completed flush, reported via `onMetrics`. */\nexport interface SmartEdgeMetrics {\n  batchId: number;\n  executedOn: \"worker\" | \"main\";\n  batchLatencyMs: number;\n  /** Time spent running the batch on the main thread. `0` when the batch\n   * ran on the worker, and `0` when the flush dispatched no edges. */\n  mainThreadBlockingMs: number;\n  routed: number;\n  cacheHits: number;\n  clear: number;\n  deferred: number;\n  unchanged: number;\n}\n\n/** One edge registered with the scheduler: everything a routing batch needs,\n * plus its registration order (hop paint order, a later task). */\nexport interface RegisteredSmartEdge extends SmartEdgeBatchItem {\n  order: number;\n}\n\n/** The scheduling/routing options a provider resolves from its props (a\n * later task). Declared locally so this module has no dependency on that\n * provider; any structurally compatible object works here. */\nexport interface ResolvedProviderOptions {\n  routeOnlyWhenBlocked: boolean;\n  routeWhileDragging: boolean;\n  debounceMs: number;\n  nodePadding: number;\n  gridRatio: number;\n  avoidAreas: Rect[];\n  cacheSize: number;\n}\n\nexport interface SchedulerDeps {\n  store: SmartEdgeStore;\n  /** Executes a batch (worker or main thread) and resolves with results. */\n  dispatch: (\n    nodes: Node[],\n    edges: SmartEdgeBatchItem[],\n  ) => Promise<{\n    results: Record<string, SmartEdgeRouteResult>;\n    executedOn: \"worker\" | \"main\";\n    durationMs: number;\n  }>;\n  options: ResolvedProviderOptions;\n  onMetrics?: (metrics: SmartEdgeMetrics) => void;\n}\n\nexport interface RoutingScheduler {\n  registerEdge(edge: RegisteredSmartEdge): () => void;\n  setNodes(nodes: Node[]): void;\n  /** Drops cached routes and per-edge signatures so the next flush\n   * re-decides every registered edge (used when provider options that\n   * affect routing change). */\n  invalidateRoutes(): void;\n  /** Test hook: run the pending flush immediately. */\n  flush(): Promise<void>;\n  dispose(): void;\n}\n\ntype NodeSnapshotList = ReturnType<typeof snapshotNodes>;\n\n/** The scheduler's full mutable state, threaded through the free functions\n * below (and through `schedulerFlush.ts`'s flush pipeline) instead of\n * captured by closures — keeps every function short. */\nexport interface SchedulerState {\n  edges: Map<string, RegisteredSmartEdge>;\n  signatures: Map<string, string>;\n  /** Each edge's actual-path invalidation corridor (bbox of the path it last\n   * routed or cleared to, inflated by nodePadding + one grid cell), keyed by\n   * edge id and kept alongside `signatures` for the same lifetime: set\n   * whenever a route is produced, read by `isEdgeUnchanged` instead of a\n   * fixed guess based only on the endpoints. See `schedulerFlush.ts`. */\n  pathCorridors: Map<string, EdgeRect>;\n  cache: RouteCache<CachedRoute>;\n  deferredEdgeIds: Set<string>;\n  draggingWasActive: boolean;\n  rawNodes: Node[];\n  absoluteNodes: Node[];\n  snapshot: NodeSnapshotList;\n  flushedSnapshot: NodeSnapshotList;\n  batchId: number;\n  disposed: boolean;\n  flushScheduled: boolean;\n  timerHandle: ReturnType<typeof setTimeout> | null;\n  frameHandle: number | null;\n}\n\nconst setsEqual = (\n  first: ReadonlySet<string>,\n  second: ReadonlySet<string>,\n): boolean => {\n  if (first.size !== second.size) return false;\n  for (const item of first) {\n    if (!second.has(item)) return false;\n  }\n  return true;\n};\n\nconst cancelScheduledFlush = (state: SchedulerState): void => {\n  state.flushScheduled = false;\n  if (state.timerHandle !== null) {\n    clearTimeout(state.timerHandle);\n    state.timerHandle = null;\n  }\n  if (state.frameHandle !== null) {\n    cancelAnimationFrame(state.frameHandle);\n    state.frameHandle = null;\n  }\n};\n\n/** Arms the debounce timer that actually runs the flush. Only ever called\n * while `flushScheduled` is true and immediately before this same timer\n * would be the next thing to fire, so once it fires there is nothing left\n * to guard: `cancelScheduledFlush` always clears this timer in the same\n * synchronous step it flips `flushScheduled` back to false, so a fired\n * callback can only ever observe `flushScheduled` still true. */\nconst armTimer = (deps: SchedulerDeps, state: SchedulerState): void => {\n  state.timerHandle = setTimeout(() => {\n    state.timerHandle = null;\n    state.flushScheduled = false;\n    void runFlush(deps, state);\n  }, deps.options.debounceMs);\n};\n\n/** Coalesces same-tick registrations/node updates into one flush: the first\n * call after a flush arms a microtask → (frame →) timer chain; every call\n * while one is already pending is a no-op, since the eventual flush reads\n * live state and picks up every change made before it runs. */\nconst scheduleFlush = (deps: SchedulerDeps, state: SchedulerState): void => {\n  if (state.disposed || state.flushScheduled) return;\n  state.flushScheduled = true;\n\n  void Promise.resolve().then(() => {\n    if (!state.flushScheduled) return;\n\n    if (typeof requestAnimationFrame === \"undefined\") {\n      armTimer(deps, state);\n      return;\n    }\n\n    state.frameHandle = requestAnimationFrame(() => {\n      state.frameHandle = null;\n      armTimer(deps, state);\n    });\n  });\n};\n\nconst registerEdge = (\n  deps: SchedulerDeps,\n  state: SchedulerState,\n  edge: RegisteredSmartEdge,\n): (() => void) => {\n  state.edges.set(edge.id, edge);\n  scheduleFlush(deps, state);\n\n  return () => {\n    state.edges.delete(edge.id);\n    state.signatures.delete(edge.id);\n    state.pathCorridors.delete(edge.id);\n    state.deferredEdgeIds.delete(edge.id);\n  };\n};\n\nconst setNodes = (\n  deps: SchedulerDeps,\n  state: SchedulerState,\n  nodes: Node[],\n): void => {\n  if (state.disposed) return;\n\n  const previousDragging = new Set(\n    state.snapshot.filter((node) => node.dragging).map((node) => node.id),\n  );\n  const absoluteNodes = getAbsoluteNodes(nodes);\n  const nextSnapshot = snapshotNodes(absoluteNodes);\n  const diff = diffNodeSnapshots(\n    state.flushedSnapshot,\n    nextSnapshot,\n    deps.options.nodePadding,\n  );\n\n  state.rawNodes = nodes;\n  state.absoluteNodes = absoluteNodes;\n  state.snapshot = nextSnapshot;\n\n  deps.store.setNodeState(diff.draggingNodeIds, diff.selectedNodeIds);\n\n  if (!diff.changed && setsEqual(previousDragging, diff.draggingNodeIds)) {\n    return;\n  }\n\n  scheduleFlush(deps, state);\n};\n\nconst invalidateRoutes = (deps: SchedulerDeps, state: SchedulerState): void => {\n  if (state.disposed) return;\n\n  state.cache = createRouteCache<CachedRoute>(deps.options.cacheSize);\n  state.signatures.clear();\n  state.pathCorridors.clear();\n  scheduleFlush(deps, state);\n};\n\n/**\n * Coordinates routing for a set of registered smart edges as nodes change:\n * debounces registrations/node updates into one flush, decides per-edge\n * whether to defer, skip, serve from cache, mark clear, or dispatch to the\n * injected `dispatch`, then merges results, populates the cache, and reports\n * metrics. Pure — no React, no `Worker` construction; `dispatch` is supplied\n * by the caller (a provider wires the real worker/main-thread choice). The\n * per-flush decision pipeline lives in `schedulerFlush.ts`.\n */\nexport const createRoutingScheduler = (\n  deps: SchedulerDeps,\n): RoutingScheduler => {\n  const state: SchedulerState = {\n    edges: new Map(),\n    signatures: new Map(),\n    pathCorridors: new Map(),\n    cache: createRouteCache<CachedRoute>(deps.options.cacheSize),\n    deferredEdgeIds: new Set(),\n    draggingWasActive: false,\n    rawNodes: [],\n    absoluteNodes: [],\n    snapshot: [],\n    flushedSnapshot: [],\n    batchId: 0,\n    disposed: false,\n    flushScheduled: false,\n    timerHandle: null,\n    frameHandle: null,\n  };\n\n  return {\n    registerEdge: (edge) => registerEdge(deps, state, edge),\n    setNodes: (nodes) => {\n      setNodes(deps, state, nodes);\n    },\n    invalidateRoutes: () => {\n      invalidateRoutes(deps, state);\n    },\n    flush: () => {\n      cancelScheduledFlush(state);\n      return runFlush(deps, state);\n    },\n    dispose: () => {\n      state.disposed = true;\n      cancelScheduledFlush(state);\n    },\n  };\n};\n","import {\n  svgDrawSmoothLinePath,\n  svgDrawStraightLinePath,\n  svgDrawSmoothStepLinePath,\n  svgDrawSimpleBezierLinePath,\n  pathfindingAStarDiagonal,\n  pathfindingJumpPointNoDiagonal,\n} from \"../functions\";\nimport type { DrawEdgeFunction, PathFindingFunction } from \"../functions\";\nimport type { SmartEdgePreset } from \"../smartEdgePresets\";\n\n/** The pure routing functions a preset resolves to (no React fallback). */\nexport interface PresetRouting {\n  drawEdge: DrawEdgeFunction;\n  generatePath: PathFindingFunction;\n}\n\n/** All preset names the worker can route. Kept in sync with `SmartEdgePreset`. */\nexport const SMART_EDGE_PRESETS = [\n  \"bezier\",\n  \"straight\",\n  \"step\",\n  \"smoothstep\",\n  \"simplebezier\",\n] as const satisfies readonly SmartEdgePreset[];\n\n/** Type guard for a valid preset name coming from untrusted edge `data`. */\nexport const isSmartEdgePreset = (value: unknown): value is SmartEdgePreset =>\n  SMART_EDGE_PRESETS.some((preset) => preset === value);\n\n/**\n * Resolve a preset name to its `drawEdge`/`generatePath` functions, mirroring\n * `smartEdgePresets` but without the React fallback components. This keeps the\n * Web Worker bundle free of `@xyflow/react`/React, which cannot run off the\n * main thread. Kept in sync with `src/smartEdgePresets.ts`.\n */\nexport const resolvePresetRouting = (\n  preset: SmartEdgePreset,\n  borderRadius?: number,\n): PresetRouting => {\n  switch (preset) {\n    case \"bezier\":\n      return {\n        drawEdge: svgDrawSmoothLinePath,\n        generatePath: pathfindingAStarDiagonal,\n      };\n    case \"straight\":\n      return {\n        drawEdge: svgDrawStraightLinePath,\n        generatePath: pathfindingAStarDiagonal,\n      };\n    case \"step\":\n      return {\n        drawEdge: svgDrawStraightLinePath,\n        generatePath: pathfindingJumpPointNoDiagonal,\n      };\n    case \"smoothstep\":\n      return {\n        drawEdge: svgDrawSmoothStepLinePath({ borderRadius }),\n        generatePath: pathfindingJumpPointNoDiagonal,\n      };\n    case \"simplebezier\":\n      return {\n        drawEdge: svgDrawSimpleBezierLinePath,\n        generatePath: pathfindingAStarDiagonal,\n      };\n  }\n};\n","import { getSmartEdge } from \"../getSmartEdge\";\nimport { getSmartEdgeWaypoints } from \"../getSmartEdge/getSmartEdgeWaypoints\";\nimport { getAbsoluteNodes, excludeEdgeAncestorNodes } from \"../functions\";\nimport { resolvePresetRouting } from \"./routingRegistry\";\nimport type { SmartEdgeRouteResult } from \"./providerStore\";\nimport type { SmartEdgePreset } from \"../smartEdgePresets\";\nimport type { Node, Position, Rect, XYPosition } from \"@xyflow/react\";\n\n/**\n * The subset of `GetSmartEdgeOptions` that can be sent to the routing Web\n * Worker. Function options (`drawEdge`/`generatePath`) are excluded because\n * functions cannot cross the `postMessage` boundary; the worker resolves\n * those from the edge's `preset` instead.\n */\nexport interface SmartEdgeBatchItemOptions {\n  gridRatio?: number;\n  nodePadding?: number;\n  avoidAreas?: Rect[];\n  /** Corner radius for the `smoothstep` preset. */\n  borderRadius?: number;\n}\n\n/**\n * One edge to route, with endpoints already resolved on the main thread and\n * everything else stripped to structured-clone-safe data (no functions), so\n * the whole batch can cross the `postMessage` boundary to the routing worker.\n */\nexport interface SmartEdgeBatchItem {\n  id: string;\n  source: string;\n  target: string;\n  sourceX: number;\n  sourceY: number;\n  targetX: number;\n  targetY: number;\n  sourcePosition: Position;\n  targetPosition: Position;\n  preset: SmartEdgePreset;\n  options?: SmartEdgeBatchItemOptions;\n  /**\n   * Intermediate points (in graph coordinates) the edge must pass through,\n   * in order from source to target. Routes through `getSmartEdgeWaypoints`\n   * instead of plain `getSmartEdge` when present and non-empty.\n   */\n  waypoints?: XYPosition[];\n}\n\n/**\n * A batch of edges to route against one shared node set, tagged with a\n * monotonically increasing `requestId` so the caller can ignore responses\n * for superseded requests.\n */\nexport interface SmartEdgeBatchRequest {\n  requestId: number;\n  nodes: Node[];\n  edges: SmartEdgeBatchItem[];\n}\n\n/** The worker's reply: routed results keyed by edge id, plus how long\n * routing took. Edges that failed to route are omitted from `results`. */\nexport interface SmartEdgeBatchResponse {\n  requestId: number;\n  results: Record<string, SmartEdgeRouteResult>;\n  durationMs: number;\n}\n\n/**\n * Routes many smart edges against a shared node set in one pass. This is the\n * pure core used both inside the Web Worker and as the main-thread fallback,\n * so it must not depend on the DOM or React. Nodes resolve to absolute\n * (subflow-aware) coordinates once for the whole batch; each edge then\n * excludes its own ancestor containers from the obstacle set, resolves its\n * preset to the matching `drawEdge`/`generatePath`, and routes through\n * `getSmartEdgeWaypoints` when it carries waypoints or plain `getSmartEdge`\n * otherwise. Edges that fail to route are omitted so the edge component keeps\n * rendering its fallback.\n */\nexport const routeSmartEdgeBatch = (\n  nodes: Node[],\n  edges: SmartEdgeBatchItem[],\n): Record<string, SmartEdgeRouteResult> => {\n  const absoluteNodes = getAbsoluteNodes(nodes);\n  const results: Record<string, SmartEdgeRouteResult> = {};\n\n  for (const edge of edges) {\n    const preparedNodes = excludeEdgeAncestorNodes(\n      absoluteNodes,\n      edge.source,\n      edge.target,\n    );\n    const { drawEdge, generatePath } = resolvePresetRouting(\n      edge.preset,\n      edge.options?.borderRadius,\n    );\n\n    const params = {\n      sourceX: edge.sourceX,\n      sourceY: edge.sourceY,\n      targetX: edge.targetX,\n      targetY: edge.targetY,\n      sourcePosition: edge.sourcePosition,\n      targetPosition: edge.targetPosition,\n      nodes: preparedNodes,\n      options: {\n        drawEdge,\n        generatePath,\n        gridRatio: edge.options?.gridRatio,\n        nodePadding: edge.options?.nodePadding,\n        avoidAreas: edge.options?.avoidAreas,\n      },\n    };\n\n    const result = edge.waypoints?.length\n      ? getSmartEdgeWaypoints({ ...params, waypoints: edge.waypoints })\n      : getSmartEdge(params);\n\n    if (!(result instanceof Error)) {\n      results[edge.id] = { ...result, kind: \"routed\", wasRouted: true };\n    }\n  }\n\n  return results;\n};\n","import { routeSmartEdgeBatch } from \"./routeBatch\";\nimport type {\n  SmartEdgeBatchRequest,\n  SmartEdgeBatchResponse,\n} from \"./routeBatch\";\n\n/**\n * True when `data` is a routing batch we can run. Webpack's HMR runtime\n * posts its own messages (`{ type: \"webpackOk\" }`, etc.) into every worker;\n * those have no `nodes` array, and treating them as batches throws inside\n * `toNodeMap`.\n */\nexport const isSmartEdgeBatchRequest = (\n  data: unknown,\n): data is SmartEdgeBatchRequest => {\n  if (typeof data !== \"object\" || data === null) return false;\n  if (!(\"requestId\" in data) || !(\"nodes\" in data) || !(\"edges\" in data)) {\n    return false;\n  }\n\n  return (\n    typeof data.requestId === \"number\" &&\n    Array.isArray(data.nodes) &&\n    Array.isArray(data.edges)\n  );\n};\n\n/**\n * Pure request/response mapping run inside the routing Web Worker. Kept\n * separate from the worker bootstrap so it can be unit tested on the main\n * thread. Uses `Date.now()` rather than `performance.now()` for `durationMs`\n * since the High Resolution Time API is not guaranteed to be available in\n * every worker runtime this library targets.\n */\nexport const handleBatchRequest = (\n  request: SmartEdgeBatchRequest,\n): SmartEdgeBatchResponse => {\n  const startedAt = Date.now();\n  const results = routeSmartEdgeBatch(request.nodes, request.edges);\n\n  return {\n    requestId: request.requestId,\n    results,\n    durationMs: Date.now() - startedAt,\n  };\n};\n","import { handleBatchRequest } from \"./workerProtocol\";\nimport type {\n  SmartEdgeBatchItem,\n  SmartEdgeBatchRequest,\n  SmartEdgeBatchResponse,\n} from \"./routeBatch\";\nimport type { SmartEdgeRouteResult } from \"./providerStore\";\nimport type { Node } from \"@xyflow/react\";\n\n/** What one dispatch resolves with: the routed results plus where and how\n * long routing took, forwarded to the scheduler's `onMetrics`. */\nexport interface DispatchOutcome {\n  results: Record<string, SmartEdgeRouteResult>;\n  executedOn: \"worker\" | \"main\";\n  durationMs: number;\n}\n\n/**\n * Runs one batch synchronously on the calling thread: used both when no\n * `Worker` is available and as the fallback after a worker construction or\n * runtime error. Reuses `handleBatchRequest` — the same pure routing core the\n * worker itself runs — so main-thread and worker routing can never diverge.\n */\nexport const dispatchOnMainThread = (\n  nodes: Node[],\n  edges: SmartEdgeBatchItem[],\n): DispatchOutcome => {\n  const response = handleBatchRequest({ requestId: 0, nodes, edges });\n\n  return {\n    results: response.results,\n    executedOn: \"main\",\n    durationMs: response.durationMs,\n  };\n};\n\n/** The minimal `Worker` surface this module needs, small enough to fake in\n * tests without depending on the DOM's `Worker` global. A real `Worker`\n * instance satisfies this structurally. */\nexport interface WorkerLike {\n  postMessage: (request: SmartEdgeBatchRequest) => void;\n  terminate: () => void;\n  onmessage: ((event: MessageEvent<SmartEdgeBatchResponse>) => void) | null;\n  onerror: ((event: ErrorEvent) => void) | null;\n}\n\n/** One in-flight worker request: its own dispatch arguments (needed to\n * replay it on the main thread if the worker dies before responding) plus\n * the resolver for the promise `dispatch` handed back to its caller. */\ninterface PendingRequest {\n  nodes: Node[];\n  edges: SmartEdgeBatchItem[];\n  resolve: (outcome: DispatchOutcome) => void;\n}\n\nexport interface WorkerDispatcher {\n  /** Posts one batch to the worker and resolves once its matching response\n   * arrives — or immediately on the main thread, once the worker has\n   * errored. */\n  dispatch: (\n    nodes: Node[],\n    edges: SmartEdgeBatchItem[],\n  ) => Promise<DispatchOutcome>;\n}\n\n/**\n * Wraps a live `Worker` instance with request/response id matching. Once the\n * worker reports an error, every currently pending request is immediately\n * resolved on the main thread (so no caller is ever left hanging), the\n * worker is terminated, and every subsequent `dispatch` call also runs on\n * the main thread for the rest of this dispatcher's life.\n */\nexport const createWorkerDispatcher = (\n  worker: WorkerLike,\n): WorkerDispatcher => {\n  const pending = new Map<number, PendingRequest>();\n  let nextRequestId = 0;\n  let broken = false;\n\n  worker.onmessage = (event) => {\n    const request = pending.get(event.data.requestId);\n    if (!request) return;\n\n    pending.delete(event.data.requestId);\n    request.resolve({\n      results: event.data.results,\n      executedOn: \"worker\",\n      durationMs: event.data.durationMs,\n    });\n  };\n\n  worker.onerror = () => {\n    broken = true;\n    worker.terminate();\n    pending.forEach((request) => {\n      request.resolve(dispatchOnMainThread(request.nodes, request.edges));\n    });\n    pending.clear();\n  };\n\n  return {\n    dispatch: (nodes, edges) => {\n      if (broken) return Promise.resolve(dispatchOnMainThread(nodes, edges));\n\n      const requestId = (nextRequestId += 1);\n      return new Promise<DispatchOutcome>((resolve) => {\n        pending.set(requestId, { nodes, edges, resolve });\n        worker.postMessage({ requestId, nodes, edges });\n      });\n    },\n  };\n};\n","import { useEffect, useMemo, useState, useSyncExternalStore } from \"react\";\nimport { getAbsoluteNodes } from \"../functions\";\nimport RoutingWorker from \"./routing.worker?worker&inline\";\nimport { createSmartEdgeStore } from \"./providerStore\";\nimport { createRoutingScheduler } from \"./scheduler\";\nimport {\n  SmartEdgeRoutingContext,\n  diffResolvedProviderOptions,\n  resolveProviderOptions,\n} from \"./routingContext\";\nimport { dispatchOnMainThread, createWorkerDispatcher } from \"./workerDispatch\";\nimport type { DispatchOutcome, WorkerLike } from \"./workerDispatch\";\nimport type {\n  ResolvedProviderOptions,\n  SmartEdgeContextValue,\n  SmartEdgeProviderOptions,\n} from \"./routingContext\";\nimport type {\n  RegisteredSmartEdge,\n  RoutingScheduler,\n  SmartEdgeMetrics,\n} from \"./scheduler\";\nimport type { SmartEdgeBatchItem } from \"./routeBatch\";\nimport type { Node } from \"@xyflow/react\";\nimport type { ReactNode } from \"react\";\n\nexport interface SmartEdgeProviderProps {\n  /** All flow nodes (controlled pattern). Used as routing obstacles and as\n   * the source of drag/selection state. */\n  nodes: Node[];\n  options?: SmartEdgeProviderOptions;\n  onMetrics?: (metrics: SmartEdgeMetrics) => void;\n  children: ReactNode;\n}\n\n/**\n * Projects React Flow nodes to the minimal shape routing needs — id,\n * position, size, parent, and the drag/selection flags the scheduler tracks\n * for its defer/invalidate decisions — dropping consumer `data` so the\n * payload posted to the worker is small and always structured-clone safe.\n */\nconst toRoutingNodes = (nodes: Node[]): Node[] =>\n  nodes.map((node) => ({\n    id: node.id,\n    position: node.position,\n    measured: node.measured,\n    parentId: node.parentId,\n    dragging: node.dragging,\n    selected: node.selected,\n    data: {},\n  }));\n\n/** Wraps the synchronous main-thread routing core in a resolved promise, so\n * it matches `SchedulerDeps[\"dispatch\"]`'s async signature — the same shape\n * a worker dispatch resolves with, just without ever yielding to a worker. */\nconst dispatchOnMainThreadAsync = (\n  nodes: Node[],\n  edges: SmartEdgeBatchItem[],\n): Promise<DispatchOutcome> =>\n  Promise.resolve(dispatchOnMainThread(nodes, edges));\n\ntype DispatchFn = (\n  nodes: Node[],\n  edges: SmartEdgeBatchItem[],\n) => Promise<DispatchOutcome>;\n\n/**\n * One provider mount's whole mutable world, built once by `createController`\n * (held in `useState` so it survives strict-mode's double render) and\n * mutated only through its own methods afterward — the same encapsulation\n * style `createRoutingScheduler` uses.\n *\n * The scheduler itself is deliberately NOT a fixed field: React's Strict Mode\n * runs every effect's setup, then its cleanup, then its setup again, once\n * right after the initial mount — and `RoutingScheduler.dispose()` has no\n * undo. A scheduler tied to a plain \"dispose on cleanup\" effect would go\n * permanently dead after that one extra cleanup, silently breaking routing\n * for the rest of the component's real lifetime. `activateScheduler` /\n * `deactivateScheduler` instead give the scheduler the same \"create in\n * effect, tear down in cleanup, safe to repeat\" lifecycle already used for\n * the worker: each activation builds a fresh scheduler and immediately\n * replays every currently tracked registration and the latest routing nodes\n * into it, so nothing is lost across a strict-mode reset.\n */\ninterface Controller extends SmartEdgeContextValue {\n  /** Creates a fresh scheduler, seeds it with every current registration and\n   * the latest routing nodes, and makes it the active target for\n   * `registerEdge`/`setRoutingNodes`. Returns the new instance so the caller\n   * can dispose exactly that one later. */\n  activateScheduler: () => RoutingScheduler;\n  /** Disposes `scheduler` and, if it is still the active one, clears it. */\n  deactivateScheduler: (scheduler: RoutingScheduler) => void;\n  /** Replaces the routing-projected nodes forwarded to the active\n   * scheduler's `setNodes`. */\n  setRoutingNodes: (nodes: Node[]) => void;\n  /** Swaps the live worker/main-thread dispatch implementation. */\n  setDispatch: (dispatch: DispatchFn) => void;\n  /** Replaces the callback `onMetrics` forwards each completed flush to. */\n  setOnMetrics: (\n    onMetrics: ((metrics: SmartEdgeMetrics) => void) | undefined,\n  ) => void;\n  /** Replaces the absolute-node snapshot `getNodesSnapshot` returns. */\n  setAbsoluteNodes: (nodes: Node[]) => void;\n  /** Applies a newly resolved options object in place. Returns true when\n   * anything changed (so React context can re-render). Routing-affecting\n   * changes also drop the route cache. */\n  setOptions: (options: ResolvedProviderOptions) => boolean;\n  /** Subscribes to options changes applied by `setOptions`, in the shape\n   * `useSyncExternalStore` expects: the listener runs synchronously right\n   * after the live object is mutated, with no payload. Returns an\n   * unsubscribe function. */\n  subscribeOptions: (listener: () => void) => () => void;\n  /** Returns the cached options snapshot for `useSyncExternalStore`. The\n   * reference only changes when `setOptions` applies a real change, which\n   * is what makes a context re-render fire exactly then. */\n  getOptionsSnapshot: () => ResolvedProviderOptions;\n}\n\nconst createController = (\n  resolvedOptions: ResolvedProviderOptions,\n): Controller => {\n  let dispatchImpl: DispatchFn = dispatchOnMainThreadAsync;\n  let onMetricsImpl: ((metrics: SmartEdgeMetrics) => void) | undefined;\n  let absoluteNodes: Node[] = [];\n  let routingNodes: Node[] = [];\n  let nextOrder = 0;\n  let activeScheduler: RoutingScheduler | null = null;\n  // Immutable copy of `resolvedOptions` for React consumption. The live\n  // object keeps its identity across `setOptions` (the scheduler closes\n  // over it), so this snapshot is the only identity that tracks value\n  // changes; `useSyncExternalStore` compares it with `Object.is`.\n  let optionsSnapshot: ResolvedProviderOptions = { ...resolvedOptions };\n  const optionsListeners = new Set<() => void>();\n  const registrations = new Map<string, RegisteredSmartEdge>();\n  const schedulerUnregisterFns = new Map<string, () => void>();\n  // First-seen paint order per edge id. Never evicted for the lifetime of\n  // this provider: edge ids are expected to be stable within a flow, so an\n  // edge that unregisters (endpoint change, brief unmount) and re-registers\n  // under the same id keeps its original hop layering instead of jumping to\n  // the end — re-minting on every call would flip Task 15's hop order every\n  // time an edge's props merely change.\n  const orders = new Map<string, number>();\n\n  const store = createSmartEdgeStore();\n\n  const registerWithActiveScheduler = (edge: RegisteredSmartEdge): void => {\n    /* v8 ignore next -- register before activateScheduler; covered by unit tests */\n    if (!activeScheduler) return;\n    schedulerUnregisterFns.set(edge.id, activeScheduler.registerEdge(edge));\n  };\n\n  const orderFor = (edgeId: string): number => {\n    const existing = orders.get(edgeId);\n    if (existing !== undefined) return existing;\n\n    nextOrder += 1;\n    orders.set(edgeId, nextOrder);\n    return nextOrder;\n  };\n\n  const registerEdge = (\n    edge: Omit<RegisteredSmartEdge, \"order\">,\n  ): (() => void) => {\n    const registered: RegisteredSmartEdge = {\n      ...edge,\n      order: orderFor(edge.id),\n    };\n    registrations.set(registered.id, registered);\n    registerWithActiveScheduler(registered);\n\n    return () => {\n      registrations.delete(registered.id);\n      schedulerUnregisterFns.get(registered.id)?.();\n      schedulerUnregisterFns.delete(registered.id);\n    };\n  };\n\n  const activateScheduler = (): RoutingScheduler => {\n    const scheduler = createRoutingScheduler({\n      store,\n      options: resolvedOptions,\n      dispatch: (nodes, edges) => dispatchImpl(nodes, edges),\n      onMetrics: (metrics) => {\n        onMetricsImpl?.(metrics);\n      },\n    });\n\n    activeScheduler = scheduler;\n    schedulerUnregisterFns.clear();\n    registrations.forEach(registerWithActiveScheduler);\n    scheduler.setNodes(routingNodes);\n\n    return scheduler;\n  };\n\n  /** Disposes the given scheduler and clears it as the active one. Only ever\n   * called from the activation effect's own cleanup, which — because React\n   * always runs an effect's cleanup before that same effect's next setup —\n   * is always still targeting the current `activeScheduler` when it fires. */\n  const deactivateScheduler = (scheduler: RoutingScheduler): void => {\n    scheduler.dispose();\n    activeScheduler = null;\n  };\n\n  return {\n    store,\n    options: resolvedOptions,\n    registerEdge,\n    getRegistrationsInOrder: () =>\n      [...registrations.values()].sort(\n        (left, right) => left.order - right.order,\n      ),\n    getNodesSnapshot: () => absoluteNodes,\n    activateScheduler,\n    deactivateScheduler,\n    setRoutingNodes: (nodes) => {\n      routingNodes = nodes;\n      activeScheduler?.setNodes(nodes);\n    },\n    setDispatch: (dispatch) => {\n      dispatchImpl = dispatch;\n    },\n    setOnMetrics: (onMetrics) => {\n      onMetricsImpl = onMetrics;\n    },\n    setAbsoluteNodes: (nodes) => {\n      absoluteNodes = nodes;\n    },\n    setOptions: (next) => {\n      const diff = diffResolvedProviderOptions(resolvedOptions, next);\n      if (!diff.any) return false;\n      Object.assign(resolvedOptions, next);\n      if (diff.routing) activeScheduler?.invalidateRoutes();\n      optionsSnapshot = { ...resolvedOptions };\n      optionsListeners.forEach((listener) => {\n        listener();\n      });\n      return true;\n    },\n    subscribeOptions: (listener) => {\n      optionsListeners.add(listener);\n      return () => {\n        optionsListeners.delete(listener);\n      };\n    },\n    getOptionsSnapshot: () => optionsSnapshot,\n  };\n};\n\n/**\n * Owns one `SmartEdgeStore`, one `RoutingScheduler`, and one inline routing\n * Web Worker for its lifetime, exposing them to descendants through\n * `SmartEdgeRoutingContext`. Falls back to synchronous main-thread routing\n * whenever `Worker` is unavailable, its construction throws, or it reports a\n * runtime error — edges keep routing either way. The `nodes` prop drives both\n * the scheduler's obstacle/drag state and `getNodesSnapshot` (absolute,\n * subflow-resolved coordinates for floating edges).\n */\nexport function SmartEdgeProvider({\n  nodes,\n  options,\n  onMetrics,\n  children,\n}: Readonly<SmartEdgeProviderProps>) {\n  const [controller] = useState(() =>\n    createController(resolveProviderOptions(options)),\n  );\n\n  useEffect(() => {\n    controller.setOnMetrics(onMetrics);\n  }, [controller, onMetrics]);\n\n  // The controller's options object is external, mutable state from React's\n  // perspective (the scheduler closes over that exact reference, and\n  // `setOptions` mutates it in place), so syncing the `options` prop into\n  // it is a genuine effect.\n  useEffect(() => {\n    controller.setOptions(resolveProviderOptions(options));\n  }, [controller, options]);\n\n  // Identity of the snapshot changes exactly when `setOptions` applies a\n  // real change, which re-renders this component and refreshes the context\n  // value below; same-value inline `options={{...}}` props never notify.\n  const optionsSnapshot = useSyncExternalStore(\n    controller.subscribeOptions,\n    controller.getOptionsSnapshot,\n    // Server rendering never subscribes, and the snapshot is immutable until\n    // a real options change (which effects-only `setOptions` cannot cause on\n    // the server), so the same getter is a valid server snapshot.\n    controller.getOptionsSnapshot,\n  );\n\n  useEffect(() => {\n    controller.setAbsoluteNodes(getAbsoluteNodes(nodes));\n    controller.setRoutingNodes(toRoutingNodes(nodes));\n  }, [controller, nodes]);\n\n  useEffect(() => {\n    const scheduler = controller.activateScheduler();\n\n    return () => {\n      controller.deactivateScheduler(scheduler);\n    };\n  }, [controller]);\n\n  useEffect(() => {\n    if (typeof Worker === \"undefined\") return undefined;\n\n    let worker: WorkerLike;\n    try {\n      worker = new RoutingWorker();\n    } catch {\n      /* v8 ignore next -- Worker construction failures are embed-specific */\n      return undefined;\n    }\n\n    controller.setDispatch(createWorkerDispatcher(worker).dispatch);\n\n    return () => {\n      controller.setDispatch(dispatchOnMainThreadAsync);\n      worker.terminate();\n    };\n  }, [controller]);\n\n  const contextValue = useMemo<SmartEdgeContextValue>(\n    () => ({\n      store: controller.store,\n      options: optionsSnapshot,\n      registerEdge: controller.registerEdge,\n      getRegistrationsInOrder: controller.getRegistrationsInOrder,\n      getNodesSnapshot: controller.getNodesSnapshot,\n    }),\n    [controller, optionsSnapshot],\n  );\n\n  return (\n    <SmartEdgeRoutingContext.Provider value={contextValue}>\n      {children}\n    </SmartEdgeRoutingContext.Provider>\n  );\n}\n"],"mappings":"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"}