Compare commits

...

1 Commits

Author SHA1 Message Date
Connor Byrne
5ce1ce923e refactor(litegraph): delete LiteGraph trigger/action subsystem
Delete the in-browser trigger/action event subsystem (~22 symbols)
confirmed dead by AUDIT-LG.5 + AUDIT-LG.9. ComfyUI's graph mutation
event bus on LGraph.onTrigger / LGraph.trigger(action,param) is
preserved — those are the production event hooks used by
useGraphNodeManager, useErrorClearingHooks, and useMinimapGraph.

LGraphNode: triggerSlot, actionDo, trigger, doExecute,
addOnTriggerInput, addOnExecutedOutput, clearTriggeredSlot,
onAfterExecuteNode, onAction, connect()'s LiteGraph.EVENT branch,
findConnectByTypeSlot's createEventInCase block, ON_TRIGGER case in
changeMode(), and the now-dead-on-arrival readers/writers for
execute_triggered, action_triggered, exec_version, action_call.

LGraph: triggerInput, setCallback, clearTriggeredSlots,
_last_trigger_time, nodes_executing, nodes_actioning,
nodes_executedAction, doExecute call site in runStep().
PRESERVES onTrigger field, trigger() dispatcher, and LGraphTrigger*
types.

globalEnums: LGraphEventMode.ON_TRIGGER.
LiteGraphGlobal: LiteGraph.ON_TRIGGER, LiteGraph.do_add_triggers_slots,
'On Trigger' entry in NODE_MODES.

LLink: _last_time field + LGraphCanvas fade-out reader (dead-on-arrival
per AUDIT-LG.5).

LGraphCanvas: do_add_triggers_slots menu block, _last_trigger_time
dirty-bg-canvas reader, _last_time link fade-out reader,
execute_triggered/action_triggered decrement counters; unused 'now'
locals/params in _renderAllLinkSegments and _renderFloatingLinks
removed in cascade.

CARVE-OUT: LiteGraph.EVENT = -1 and LiteGraph.ACTION = -1 are NOT
deleted. The user's instructions described these as living in
'3 vendored canvas bundles' but in this layout they are referenced
by 12 live TypeScript callers in LGraphCanvas.ts and linkColors.ts
(slot-type filtering, link colors, type-filter menu options) which
the user explicitly directed not to touch. Removing the constants
would break TS compilation. The constants now point to slot types
that no LGraphNode method can produce — the canvas branches are
dead-on-arrival per AUDIT-LG.9.

Closes #12223.
2026-05-13 16:31:41 -07:00
7 changed files with 6 additions and 353 deletions

View File

@@ -263,14 +263,10 @@ export class LGraph
errors_in_execution?: boolean
/** @deprecated Unused */
execution_time!: number
_last_trigger_time?: number
filter?: string
/** Must contain serialisable values, e.g. primitive types */
config: LGraphConfig = {}
vars: Dictionary<unknown> = {}
nodes_executing: boolean[] = []
nodes_actioning: (string | boolean)[] = []
nodes_executedAction: string[] = []
extra: LGraphExtra = {}
/** @deprecated Deserialising a workflow sets this unused property. */
@@ -442,10 +438,6 @@ export class LGraph
this.catch_errors = true
this.nodes_executing = []
this.nodes_actioning = []
this.nodes_executedAction = []
// notify canvas to redraw
this.change()
@@ -586,10 +578,8 @@ export class LGraph
for (let i = 0; i < num; i++) {
for (let j = 0; j < limit; ++j) {
const node = nodes[j]
// FIXME: Looks like copy/paste broken logic - checks for "on", executes "do"
if (node.mode == LGraphEventMode.ALWAYS && node.onExecute) {
// wrap node.onExecute();
node.doExecute?.()
if (node.mode == LGraphEventMode.ALWAYS) {
node.onExecute?.()
}
}
@@ -633,9 +623,6 @@ export class LGraph
this.iteration += 1
this.elapsed_time = (now - this.last_update_time) * 0.001
this.last_update_time = now
this.nodes_executing = []
this.nodes_actioning = []
this.nodes_executedAction = []
}
/**
@@ -1372,24 +1359,6 @@ export class LGraph
// Don't handle unknown events - just ignore them
}
/** @todo Clean up - never implemented. */
triggerInput(name: string, value: unknown): void {
const nodes = this.findNodesByTitle(name)
for (const node of nodes) {
// @ts-expect-error - onTrigger method may not exist on all node types
node.onTrigger(value)
}
}
/** @todo Clean up - never implemented. */
setCallback(name: string, func?: () => void): void {
const nodes = this.findNodesByTitle(name)
for (const node of nodes) {
// @ts-expect-error - setTrigger method may not exist on all node types
node.setTrigger(func)
}
}
// used for undo, called before any change is made to the graph
beforeChange(info?: LGraphNode): void {
this.onBeforeChange?.(this, info)
@@ -1402,17 +1371,6 @@ export class LGraph
this.canvasAction((c) => c.onAfterChange?.(this))
}
/**
* clears the triggered slot animation in all links (stop visual animation)
*/
clearTriggeredSlots(): void {
for (const link_info of this._links.values()) {
if (!link_info) continue
if (link_info._last_time) link_info._last_time = 0
}
}
/* Called when something visually changed (not the graph!) */
change(): void {
this.canvasAction((c) => c.setDirty(true, true))

View File

@@ -1283,16 +1283,6 @@ export class LGraphCanvas implements CustomEventDispatcher<LGraphCanvasEventMap>
let entries: (IContextMenuValue<INodeSlotContextItem> | null)[] = []
if (
LiteGraph.do_add_triggers_slots &&
node.findOutputSlot('onExecuted') == -1
) {
entries.push({
content: 'On Executed',
value: ['onExecuted', LiteGraph.EVENT, { nameLocked: true }],
className: 'event'
})
}
// add callback for modifying the menu elements onMenuNodeOutputs
const retEntries = node.onMenuNodeOutputs?.(entries)
if (retEntries) entries = retEntries
@@ -5022,9 +5012,7 @@ export class LGraphCanvas implements CustomEventDispatcher<LGraphCanvasEventMap>
if (
this.dirty_bgcanvas ||
force_bgcanvas ||
this.always_render_background ||
(this.graph?._last_trigger_time &&
now - this.graph._last_trigger_time < 1000)
this.always_render_background
) {
this.drawBackCanvas()
}
@@ -5906,12 +5894,6 @@ export class LGraphCanvas implements CustomEventDispatcher<LGraphCanvasEventMap>
}
node.drawProgressBar(ctx)
// these counter helps in conditioning drawing based on if the node has been executed or an action occurred
if (node.execute_triggered != null && node.execute_triggered > 0)
node.execute_triggered--
if (node.action_triggered != null && node.action_triggered > 0)
node.action_triggered--
}
/**
@@ -5985,7 +5967,6 @@ export class LGraphCanvas implements CustomEventDispatcher<LGraphCanvasEventMap>
const visibleReroutes: Reroute[] = []
const now = LiteGraph.getTime()
const { visible_area } = this
margin_area[0] = visible_area[0] - 20
margin_area[1] = visible_area[1] - 20
@@ -6050,7 +6031,6 @@ export class LGraphCanvas implements CustomEventDispatcher<LGraphCanvasEventMap>
startPos,
endPos,
visibleReroutes,
now,
output.dir,
input.dir
)
@@ -6079,7 +6059,6 @@ export class LGraphCanvas implements CustomEventDispatcher<LGraphCanvasEventMap>
output.pos,
endPos,
visibleReroutes,
now,
input.dir,
input.dir
)
@@ -6106,7 +6085,6 @@ export class LGraphCanvas implements CustomEventDispatcher<LGraphCanvasEventMap>
startPos,
input.pos,
visibleReroutes,
now,
output.dir,
input.dir
)
@@ -6114,7 +6092,7 @@ export class LGraphCanvas implements CustomEventDispatcher<LGraphCanvasEventMap>
}
if (graph.floatingLinks.size > 0) {
this._renderFloatingLinks(ctx, graph, visibleReroutes, now)
this._renderFloatingLinks(ctx, graph, visibleReroutes)
}
const rerouteSet = this._visibleReroutes
@@ -6160,8 +6138,7 @@ export class LGraphCanvas implements CustomEventDispatcher<LGraphCanvasEventMap>
private _renderFloatingLinks(
ctx: CanvasRenderingContext2D,
graph: LGraph,
visibleReroutes: Reroute[],
now: number
visibleReroutes: Reroute[]
) {
// Render floating links with 3/4 current alpha
const { globalAlpha } = ctx
@@ -6192,7 +6169,6 @@ export class LGraphCanvas implements CustomEventDispatcher<LGraphCanvasEventMap>
startPos,
endPos,
visibleReroutes,
now,
LinkDirection.CENTER,
endDirection,
true
@@ -6214,7 +6190,6 @@ export class LGraphCanvas implements CustomEventDispatcher<LGraphCanvasEventMap>
startPos,
endPos,
visibleReroutes,
now,
startDirection,
LinkDirection.CENTER,
true
@@ -6230,7 +6205,6 @@ export class LGraphCanvas implements CustomEventDispatcher<LGraphCanvasEventMap>
startPos: Point,
endPos: Point,
visibleReroutes: Reroute[],
now: number,
startDirection?: LinkDirection,
endDirection?: LinkDirection,
disabled: boolean = false
@@ -6351,25 +6325,6 @@ export class LGraphCanvas implements CustomEventDispatcher<LGraphCanvasEventMap>
)
}
renderedPaths.add(link)
// event triggered rendered on top
if (link?._last_time && now - link._last_time < 1000) {
const f = 2.0 - (now - link._last_time) * 0.002
const tmp = ctx.globalAlpha
ctx.globalAlpha = tmp * f
this.renderLink(
ctx,
startPos,
endPos,
link,
true,
f,
'white',
start_dir,
end_dir
)
ctx.globalAlpha = tmp
}
}
/**

View File

@@ -214,7 +214,6 @@ supported callbacks:
+ onDropFile : file dropped over the node
+ onConnectInput : if returns false the incoming connection will be canceled
+ onConnectionsChange : a connection changed (new one or removed) (NodeSlotType.INPUT or NodeSlotType.OUTPUT, slot, true if connected, link_info, input_info )
+ onAction: action slot triggered
+ getExtraMenuOptions: to add option to context menu
*/
@@ -353,11 +352,6 @@ export class LGraphNode
get renderingBoxColor(): string {
if (this.boxcolor) return this.boxcolor
if (LiteGraph.node_box_coloured_when_on) {
if (this.action_triggered) return '#FFF'
if (this.execute_triggered) return '#AAA'
}
if (LiteGraph.node_box_coloured_by_mode) {
const modeColour =
LiteGraph.NODE_MODES_COLORS[this.mode ?? LGraphEventMode.ALWAYS]
@@ -401,10 +395,6 @@ export class LGraphNode
*/
progress?: number
exec_version?: number
action_call?: string
execute_triggered?: number
action_triggered?: number
/**
* @deprecated This property is unsupported and will be removed in a future release.
* Use `widgets_start_y` or a custom `arrange()` override instead.
@@ -631,12 +621,6 @@ export class LGraphNode
param?: unknown,
options?: { action_call?: string }
): void
onAction?(
this: LGraphNode,
action: string,
param: unknown,
options: { action_call?: string }
): void
onDrawBackground?(this: LGraphNode, ctx: CanvasRenderingContext2D): void
onNodeCreated?(this: LGraphNode): void
/**
@@ -1349,45 +1333,11 @@ export class LGraphNode
return r
}
addOnTriggerInput(): number {
const trigS = this.findInputSlot('onTrigger')
if (trigS == -1) {
this.addInput('onTrigger', LiteGraph.EVENT, {
nameLocked: true
})
return this.findInputSlot('onTrigger')
}
return trigS
}
addOnExecutedOutput(): number {
const trigS = this.findOutputSlot('onExecuted')
if (trigS == -1) {
this.addOutput('onExecuted', LiteGraph.ACTION, {
nameLocked: true
})
return this.findOutputSlot('onExecuted')
}
return trigS
}
onAfterExecuteNode(param: unknown, options?: { action_call?: string }) {
const trigS = this.findOutputSlot('onExecuted')
if (trigS != -1) {
this.triggerSlot(trigS, param, null, options)
}
}
changeMode(modeTo: number): boolean {
switch (modeTo) {
case LGraphEventMode.ON_EVENT:
break
case LGraphEventMode.ON_TRIGGER:
this.addOnTriggerInput()
this.addOnExecutedOutput()
break
case LGraphEventMode.NEVER:
break
@@ -1406,189 +1356,6 @@ export class LGraphNode
return true
}
/**
* Triggers the node code execution, place a boolean/counter to mark the node as being executed
*/
doExecute(param?: unknown, options?: { action_call?: string }): void {
options = options || {}
if (this.onExecute) {
// enable this to give the event an ID
options.action_call ||= `${this.id}_exec_${Math.floor(Math.random() * 9999)}`
if (!this.graph) throw new NullGraphError()
// @ts-expect-error Technically it works when id is a string. Array gets props.
this.graph.nodes_executing[this.id] = true
this.onExecute(param, options)
// @ts-expect-error deprecated
this.graph.nodes_executing[this.id] = false
// save execution/action ref
this.exec_version = this.graph.iteration
if (options?.action_call) {
this.action_call = options.action_call
// @ts-expect-error deprecated
this.graph.nodes_executedAction[this.id] = options.action_call
}
}
// the nFrames it will be used (-- each step), means "how old" is the event
this.execute_triggered = 2
this.onAfterExecuteNode?.(param, options)
}
/**
* Triggers an action, wrapped by logics to control execution flow
* @param action name
*/
actionDo(
action: string,
param: unknown,
options: { action_call?: string }
): void {
options = options || {}
if (this.onAction) {
// enable this to give the event an ID
options.action_call ||= `${this.id}_${action || 'action'}_${Math.floor(Math.random() * 9999)}`
if (!this.graph) throw new NullGraphError()
// @ts-expect-error deprecated
this.graph.nodes_actioning[this.id] = action || 'actioning'
this.onAction(action, param, options)
// @ts-expect-error deprecated
this.graph.nodes_actioning[this.id] = false
// save execution/action ref
if (options?.action_call) {
this.action_call = options.action_call
// @ts-expect-error deprecated
this.graph.nodes_executedAction[this.id] = options.action_call
}
}
// the nFrames it will be used (-- each step), means "how old" is the event
this.action_triggered = 2
this.onAfterExecuteNode?.(param, options)
}
/**
* Triggers an event in this node, this will trigger any output with the same name
* @param action name ( "on_play", ... ) if action is equivalent to false then the event is send to all
*/
trigger(
action: string,
param: unknown,
options: { action_call?: string }
): void {
const { outputs } = this
if (!outputs || !outputs.length) {
return
}
if (this.graph) this.graph._last_trigger_time = LiteGraph.getTime()
for (const [i, output] of outputs.entries()) {
if (
!output ||
output.type !== LiteGraph.EVENT ||
(action && output.name != action)
) {
continue
}
this.triggerSlot(i, param, null, options)
}
}
/**
* Triggers a slot event in this node: cycle output slots and launch execute/action on connected nodes
* @param slot the index of the output slot
* @param link_id [optional] in case you want to trigger and specific output link in a slot
*/
triggerSlot(
slot: number,
param: unknown,
link_id: number | null,
options?: { action_call?: string }
): void {
options = options || {}
if (!this.outputs) return
if (slot == null) {
console.error('slot must be a number')
return
}
if (typeof slot !== 'number')
console.warn(
"slot must be a number, use node.trigger('name') if you want to use a string"
)
const output = this.outputs[slot]
if (!output) return
const links = output.links
if (!links || !links.length) return
if (!this.graph) throw new NullGraphError()
this.graph._last_trigger_time = LiteGraph.getTime()
// for every link attached here
for (const id of links) {
// to skip links
if (link_id != null && link_id != id) continue
const link_info = this.graph._links.get(id)
// not connected
if (!link_info) continue
link_info._last_time = LiteGraph.getTime()
const node = this.graph.getNodeById(link_info.target_id)
// node not found?
if (!node) continue
if (node.mode === LGraphEventMode.ON_TRIGGER) {
// generate unique trigger ID if not present
if (!options.action_call)
options.action_call = `${this.id}_trigg_${Math.floor(Math.random() * 9999)}`
// -- wrapping node.onExecute(param); --
node.doExecute?.(param, options)
} else if (node.onAction) {
// generate unique action ID if not present
if (!options.action_call)
options.action_call = `${this.id}_act_${Math.floor(Math.random() * 9999)}`
// pass the action name
const target_connection = node.inputs[link_info.target_slot]
node.actionDo(target_connection.name, param, options)
}
}
}
/**
* clears the trigger slot animation
* @param slot the index of the output slot
* @param link_id [optional] in case you want to trigger and specific output link in a slot
*/
clearTriggeredSlot(slot: number, link_id: number): void {
if (!this.outputs) return
const output = this.outputs[slot]
if (!output) return
const links = output.links
if (!links || !links.length) return
if (!this.graph) throw new NullGraphError()
// for every link attached here
for (const id of links) {
// to skip links
if (link_id != null && link_id != id) continue
const link_info = this.graph._links.get(id)
// not connected
if (!link_info) continue
link_info._last_time = 0
}
}
/**
* changes node size and triggers callback
*/
@@ -2614,12 +2381,6 @@ export class LGraphNode
const slot = node.findSlotByType(findInputs, slotType, false, true)
if (slot >= 0 && slot !== null) return slot
// TODO: Remove or reimpl. events. WILL CREATE THE onTrigger IN SLOT
if (opts.createEventInCase && slotType == LiteGraph.EVENT) {
if (findInputs) return -1
if (LiteGraph.do_add_triggers_slots) return node.addOnExecutedOutput()
}
// connect to the first general output slot if not found a specific type and
if (opts.typedToWildcard) {
const generalSlot = node.findSlotByType(findInputs, 0, false, true, true)
@@ -2813,14 +2574,6 @@ export class LGraphNode
console.error(`Connect: Error, no slot of name ${targetIndex}`)
return null
}
} else if (target_slot === LiteGraph.EVENT) {
// TODO: Events
if (LiteGraph.do_add_triggers_slots) {
target_node.changeMode(LGraphEventMode.ON_TRIGGER)
targetIndex = target_node.findInputSlot('onTrigger')
} else {
return null
}
} else if (typeof target_slot === 'number') {
targetIndex = target_slot
} else {

View File

@@ -109,8 +109,6 @@ export class LLink implements LinkSegment, Serialisable<SerialisableLLink> {
_data?: unknown
/** Centre point of the link, calculated during render only - can be inaccurate */
_pos: Point
/** @todo Clean up - never implemented in comfy. */
_last_time?: number
/** The last canvas 2D path that was used to render this link */
path?: Path2D
/** @inheritdoc */

View File

@@ -118,13 +118,12 @@ export class LiteGraphGlobal {
ACTION = -1 as const
/** helper, will add "On Request" and more in the future */
NODE_MODES = ['Always', 'On Event', 'Never', 'On Trigger']
NODE_MODES = ['Always', 'On Event', 'Never']
/** use with node_box_coloured_by_mode */
NODE_MODES_COLORS = ['#666', '#422', '#333', '#224', '#626']
ALWAYS = LGraphEventMode.ALWAYS
ON_EVENT = LGraphEventMode.ON_EVENT
NEVER = LGraphEventMode.NEVER
ON_TRIGGER = LGraphEventMode.ON_TRIGGER
UP = LinkDirection.UP
DOWN = LinkDirection.DOWN
@@ -243,12 +242,6 @@ export class LiteGraphGlobal {
/** [true!] very handy, ALT click to clone and drag the new node */
alt_drag_do_clone_nodes = false
/**
* [true!] will create and connect event slots when using action/events connections,
* !WILL CHANGE node mode when using onTrigger (enable mode colors), onExecuted does not need this
*/
do_add_triggers_slots = false
/** [false!] being events, it is strongly recommended to use them sequentially, one by one */
allow_multi_output_for_events = true

View File

@@ -70,7 +70,6 @@ LiteGraphGlobal {
"Always",
"On Event",
"Never",
"On Trigger",
],
"NODE_MODES_COLORS": [
"#666",
@@ -95,7 +94,6 @@ LiteGraphGlobal {
"NO_TITLE": 1,
"Nodes": {},
"ON_EVENT": 1,
"ON_TRIGGER": 3,
"OUTPUT": 2,
"RIGHT": 4,
"ROUND_RADIUS": 8,
@@ -154,7 +152,6 @@ LiteGraphGlobal {
"dialog_close_on_mouse_leave": false,
"dialog_close_on_mouse_leave_delay": 500,
"distance": [Function],
"do_add_triggers_slots": false,
"highlight_selected_group": true,
"isInsideRectangle": [Function],
"leftMouseClickBehavior": "panning",

View File

@@ -84,7 +84,6 @@ export enum LGraphEventMode {
ALWAYS = 0,
ON_EVENT = 1,
NEVER = 2,
ON_TRIGGER = 3,
BYPASS = 4
}