diff --git a/src/lib/litegraph/src/LGraph.ts b/src/lib/litegraph/src/LGraph.ts index 139919c60..b10ec18d0 100644 --- a/src/lib/litegraph/src/LGraph.ts +++ b/src/lib/litegraph/src/LGraph.ts @@ -574,7 +574,7 @@ export class LGraph const S: LGraphNode[] = [] const M: Dictionary = {} // to avoid repeating links - const visited_links: Record = {} + const visited_links: Record = {} const remaining_links: Record = {} // search for the nodes without inputs (starting nodes) @@ -1341,9 +1341,9 @@ export class LGraph createReroute(pos: Point, before: LinkSegment): Reroute { const layoutMutations = useLayoutMutations() const rerouteId = ++this.state.lastRerouteId - const linkIds = before instanceof Reroute ? before.linkIds : [before.id] + const linkIds = before instanceof Reroute ? before.linkIds : [] const floatingLinkIds = - before instanceof Reroute ? before.floatingLinkIds : [before.id] + before instanceof Reroute ? before.floatingLinkIds : [] const reroute = new Reroute( rerouteId, this, diff --git a/src/lib/litegraph/src/LGraphCanvas.ts b/src/lib/litegraph/src/LGraphCanvas.ts index 83ce47660..1915b75dc 100644 --- a/src/lib/litegraph/src/LGraphCanvas.ts +++ b/src/lib/litegraph/src/LGraphCanvas.ts @@ -6168,14 +6168,19 @@ export class LGraphCanvas case 'Delete': { // segment can be a Reroute object, in which case segment.id is the reroute id - const linkId = + if (!(segment instanceof Reroute) && !(segment instanceof LLink)) + // FIXME: Need better way of determining if segment is a Link or Reroute + throw new Error('Unimplemented link type') + const linkIds = segment instanceof Reroute - ? segment.linkIds.values().next().value - : segment.id - if (linkId !== undefined) { - graph.removeLink(linkId) - // Clean up layout store - layoutStore.deleteLinkLayout(linkId) + ? segment.linkIds + : [segment.id satisfies LinkId] + for (const linkId of linkIds) { + if (linkId !== undefined) { + graph.removeLink(linkId) + // Clean up layout store + layoutStore.deleteLinkLayout(linkId) + } } break } diff --git a/src/lib/litegraph/src/LGraphNode.ts b/src/lib/litegraph/src/LGraphNode.ts index 20e26e211..22c831f5c 100644 --- a/src/lib/litegraph/src/LGraphNode.ts +++ b/src/lib/litegraph/src/LGraphNode.ts @@ -90,7 +90,9 @@ import { type WidgetTypeMap, toConcreteWidget } from './widgets/widgetMap' // #region Types -export type NodeId = number | string +export type NodeId = + | (number & { type?: 'NodeId' }) + | (string & { type?: 'NodeId' }) export type NodeProperty = string | number | boolean | object diff --git a/src/lib/litegraph/src/LLink.ts b/src/lib/litegraph/src/LLink.ts index 71b41f23d..97825d1db 100644 --- a/src/lib/litegraph/src/LLink.ts +++ b/src/lib/litegraph/src/LLink.ts @@ -24,7 +24,7 @@ import type { const layoutMutations = useLayoutMutations() -export type LinkId = number +export type LinkId = number & { type?: 'LinkId' } export type SerialisedLLinkArray = [ id: LinkId, diff --git a/src/lib/litegraph/src/Reroute.ts b/src/lib/litegraph/src/Reroute.ts index 4ac682599..885d4a8d7 100644 --- a/src/lib/litegraph/src/Reroute.ts +++ b/src/lib/litegraph/src/Reroute.ts @@ -20,7 +20,7 @@ import type { Serialisable, SerialisableReroute } from './types/serialisation' const layoutMutations = useLayoutMutations() -export type RerouteId = number +export type RerouteId = number & { type?: 'RerouteId' } /** The input or output slot that an incomplete reroute link is connected to. */ export interface FloatingRerouteSlot { diff --git a/src/platform/workflow/management/stores/workflowStore.ts b/src/platform/workflow/management/stores/workflowStore.ts index 02b48c55b..8ed6d90a5 100644 --- a/src/platform/workflow/management/stores/workflowStore.ts +++ b/src/platform/workflow/management/stores/workflowStore.ts @@ -592,7 +592,7 @@ export const useWorkflowStore = defineStore('workflow', () => { ): NodeLocatorId | null => { // Handle simple node IDs (root graph - no colons) if (!nodeExecutionId.includes(':')) { - return nodeExecutionId + return nodeExecutionId as NodeLocatorId } const parts = parseNodeExecutionId(nodeExecutionId) diff --git a/src/types/nodeIdentification.ts b/src/types/nodeIdentification.ts index d9a299c39..90871bfd1 100644 --- a/src/types/nodeIdentification.ts +++ b/src/types/nodeIdentification.ts @@ -15,7 +15,7 @@ import type { NodeId } from '@/platform/workflow/validation/schemas/workflowSche * Unlike execution IDs which change based on the instance path, * NodeLocatorId remains the same for all instances of a particular node. */ -export type NodeLocatorId = string +export type NodeLocatorId = string & { type?: 'LocatorId' } /** * An execution identifier representing a node's position in nested subgraphs. @@ -24,7 +24,7 @@ export type NodeLocatorId = string * Format: Colon-separated path of node IDs * Example: "123:456:789" (node 789 in subgraph 456 in subgraph 123) */ -export type NodeExecutionId = string +export type NodeExecutionId = string & { type?: 'ExecutionId' } /** * Type guard to check if a value is a NodeLocatorId diff --git a/src/utils/graphTraversalUtil.ts b/src/utils/graphTraversalUtil.ts index 4a573ed24..9e30acfce 100644 --- a/src/utils/graphTraversalUtil.ts +++ b/src/utils/graphTraversalUtil.ts @@ -1,3 +1,4 @@ +import type { NodeId } from '@/lib/litegraph/src/LGraphNode' import type { LGraph, LGraphNode, @@ -9,7 +10,7 @@ import { parseNodeLocatorId } from '@/types/nodeIdentification' import { isSubgraphIoNode } from './typeGuardUtil' interface NodeWithId { - id: string | number + id: NodeId subgraphId?: string | null } @@ -19,7 +20,7 @@ interface NodeWithId { * @param nodeData - Node data containing id and optional subgraphId * @returns The locator ID string */ -export function getLocatorIdFromNodeData(nodeData: NodeWithId): string { +export function getLocatorIdFromNodeData(nodeData: NodeWithId): NodeLocatorId { return nodeData.subgraphId ? `${nodeData.subgraphId}:${String(nodeData.id)}` : String(nodeData.id) @@ -31,7 +32,9 @@ export function getLocatorIdFromNodeData(nodeData: NodeWithId): string { * @param executionId - The execution ID (e.g., "123:456:789" or "789") * @returns Array of node IDs in the path, or null if invalid */ -export function parseExecutionId(executionId: string): string[] | null { +export function parseExecutionId( + executionId: NodeExecutionId +): string[] | null { if (!executionId || typeof executionId !== 'string') return null return executionId.split(':').filter((part) => part.length > 0) } @@ -55,7 +58,9 @@ export function getLocalNodeIdFromExecutionId( * @param executionId - The execution ID (e.g., "123:456:789" or "789") * @returns Array of subgraph node IDs (excluding the final node ID), or empty array */ -export function getSubgraphPathFromExecutionId(executionId: string): string[] { +export function getSubgraphPathFromExecutionId( + executionId: NodeExecutionId +): string[] { const parts = parseExecutionId(executionId) return parts ? parts.slice(0, -1) : [] } @@ -196,7 +201,7 @@ export function collectAllNodes( */ export function findNodeInHierarchy( graph: LGraph | Subgraph, - nodeId: string | number + nodeId: NodeId ): LGraphNode | null { // Check current graph const node = graph.getNodeById(nodeId) @@ -284,7 +289,7 @@ export function findSubgraphPathById( */ export function getNodeByExecutionId( rootGraph: LGraph, - executionId: string + executionId: NodeExecutionId ): LGraphNode | null { if (!rootGraph) return null @@ -316,7 +321,7 @@ export function getNodeByExecutionId( */ export function getNodeByLocatorId( rootGraph: LGraph, - locatorId: NodeLocatorId | string + locatorId: NodeLocatorId ): LGraphNode | null { if (!rootGraph) return null diff --git a/src/utils/linkFixer.ts b/src/utils/linkFixer.ts index 1c26afb29..f259888d2 100644 --- a/src/utils/linkFixer.ts +++ b/src/utils/linkFixer.ts @@ -25,7 +25,7 @@ * SOFTWARE. */ import type { NodeId } from '@/lib/litegraph/src/LGraphNode' -import type { SerialisedLLinkArray } from '@/lib/litegraph/src/LLink' +import type { LinkId, SerialisedLLinkArray } from '@/lib/litegraph/src/LLink' import type { LGraph, LGraphNode, LLink } from '@/lib/litegraph/src/litegraph' import type { ISerialisedGraph, @@ -105,7 +105,7 @@ export function fixBadLinks( const data: { patchedNodes: Array - deletedLinks: number[] + deletedLinks: LinkId[] } = { patchedNodes: [], deletedLinks: [] @@ -419,7 +419,7 @@ export function fixBadLinks( for (let i = data.deletedLinks.length - 1; i >= 0; i--) { logger.log(`Deleting link #${data.deletedLinks[i]}.`) if ((graph as LGraph).getNodeById) { - delete graph.links[data.deletedLinks[i]!] + delete (graph as LGraph).links[data.deletedLinks[i]!] } else { graph = graph as ISerialisedGraph // Sometimes we got objects for links if passed after ComfyUI's loadGraphData modifies the