Skip to content

fix: garbage collect subgraph definitions when SubgraphNode is removed#8187

Merged
christian-byrne merged 1 commit intomainfrom
fix/subgraph-definition-gc
Jan 30, 2026
Merged

fix: garbage collect subgraph definitions when SubgraphNode is removed#8187
christian-byrne merged 1 commit intomainfrom
fix/subgraph-definition-gc

Conversation

@christian-byrne
Copy link
Contributor

@christian-byrne christian-byrne commented Jan 20, 2026

Summary

When removing a SubgraphNode via LGraph.remove():

  • Fire onRemoved for all nodes inside the subgraph
  • Fire onNodeRemoved callback on the subgraph for each inner node
  • Remove subgraph definition from rootGraph.subgraphs when no other nodes reference it (checks both root graph nodes and nodes inside other subgraphs)

This ensures proper cleanup of subgraph definitions and lifecycle callbacks for nested nodes when subgraph nodes are deleted.

Changes

LGraph.ts

Added SubgraphNode-specific cleanup in remove() method that:

  1. Iterates inner nodes and fires their onRemoved callbacks
  2. Fires onNodeRemoved on the subgraph for downstream listeners (e.g., minimap)
  3. Garbage collects the subgraph definition when no other nodes reference it

SubgraphNode.ts

Fixed graph property to match LGraphNode lifecycle contract. Previously it was declared as override readonly graph via constructor parameter promotion, which prevented LGraph.remove() from setting node.graph = null. Changed to a regular mutable property with null guard in rootGraph getter.

LGraph.test.ts

Added 4 tests:

  • removing SubgraphNode fires onRemoved for inner nodes
  • removing SubgraphNode fires onNodeRemoved callback
  • subgraph definition is removed when last referencing node is removed
  • subgraph definition is retained when other nodes still reference it

Related

@christian-byrne christian-byrne requested a review from a team as a code owner January 20, 2026 20:39
@dosubot dosubot bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Jan 20, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 20, 2026

Important

Review skipped

Auto reviews are limited based on label configuration.

🚫 Review skipped — only excluded labels are configured. (1)
  • backport

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

📝 Walkthrough

Walkthrough

Adds subgraph garbage-collection when removing a SubgraphNode: calls inner-node onRemoved handlers, invokes subgraph.onNodeRemoved for each inner node, deletes the subgraph definition from the root graph, and makes SubgraphNode.graph nullable with null guards and tests.

Changes

Cohort / File(s) Summary
Subgraph GC core
src/lib/litegraph/src/LGraph.ts
On removing a SubgraphNode, invoke each inner node's onRemoved(), call subgraph.onNodeRemoved(innerNode) for each, and delete the subgraph definition from rootGraph.subgraphs.
Subgraph tests
src/lib/litegraph/src/LGraph.test.ts
Add "Subgraph Definition Garbage Collection" tests (helper to create subgraphs, assertions that inner-node onRemoved and subgraph.onNodeRemoved run, and that the subgraph definition is deleted). (Suite duplicated in file.)
Subgraph node API
src/lib/litegraph/src/subgraph/SubgraphNode.ts
SubgraphNode.graph becomes nullable (`GraphOrSubgraph
Null guards & callers
src/lib/litegraph/src/subgraph/ExecutableNodeDTO.ts, src/core/graph/subgraph/proxyWidget.test.ts, src/stores/imagePreviewStore.ts
Add explicit null checks / throw NullGraphError before accessing subgraphNode.graph or using graph APIs; guard graph operations.
Test typings tightened
src/lib/litegraph/src/subgraph/SubgraphConversion.test.ts, src/lib/litegraph/src/subgraph/SubgraphNode.test.ts, src/stores/subgraphStore.test.ts
Replace subgraphNode.graph with non-null assertions (subgraphNode.graph!) in tests to reflect stricter typing.

Sequence Diagram(s)

sequenceDiagram
    participant Caller
    participant LGraph
    participant SubgraphNode
    participant RootGraph
    participant InnerNodes

    Caller->>LGraph: remove(node)
    alt node is SubgraphNode
        LGraph->>SubgraphNode: read subgraph id / graph
        LGraph->>RootGraph: check rootGraph.subgraphs and other refs
        alt subgraph still referenced
            LGraph-->>Caller: regular removal path
        else no other references
            LGraph->>InnerNodes: call innerNode.onRemoved() for each
            LGraph->>SubgraphNode: call subgraph.onNodeRemoved(innerNode) for each
            LGraph->>RootGraph: delete rootGraph.subgraphs[subgraphId]
            LGraph-->>Caller: finish removal
        end
    else
        LGraph-->>Caller: regular removal path
    end
Loading

Possibly related PRs

Suggested reviewers

  • DrJKL
  • simula-r
  • Myestery
🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The pull request successfully addresses all coding requirements from issue #8145: fires onRemoved for inner nodes, calls onNodeRemoved callbacks, and garbage-collects subgraph definitions when SubgraphNodes are removed.
Out of Scope Changes check ✅ Passed All changes are directly scoped to implementing the subgraph lifecycle management and garbage collection requirements. No unrelated modifications detected outside the stated objectives.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link

github-actions bot commented Jan 20, 2026

🎭 Playwright Tests: ✅ Passed

Results: 507 passed, 0 failed, 0 flaky, 8 skipped (Total: 515)

📊 Browser Reports
  • chromium: View Report (✅ 495 / ❌ 0 / ⚠️ 0 / ⏭️ 8)
  • chromium-2x: View Report (✅ 2 / ❌ 0 / ⚠️ 0 / ⏭️ 0)
  • chromium-0.5x: View Report (✅ 1 / ❌ 0 / ⚠️ 0 / ⏭️ 0)
  • mobile-chrome: View Report (✅ 9 / ❌ 0 / ⚠️ 0 / ⏭️ 0)

@github-actions
Copy link

github-actions bot commented Jan 20, 2026

🎨 Storybook Build Status

Build completed successfully!

⏰ Completed at: 01/28/2026, 06:06:19 AM UTC

🔗 Links


🎉 Your Storybook is ready for review!

@christian-byrne christian-byrne marked this pull request as draft January 20, 2026 20:52
@christian-byrne christian-byrne marked this pull request as ready for review January 20, 2026 22:13
@coderabbitai coderabbitai bot requested review from AustinMroz and DrJKL January 20, 2026 22:14
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/lib/litegraph/src/LGraph.ts (1)

1026-1029: Replace node.graph = null with node.graph = undefined and ensure SubgraphNode's readonly graph property is handled appropriately.

TS2540 occurs because SubgraphNode.graph is a readonly constructor parameter property override (line 70 of SubgraphNode.ts), while the base LGraphNode.graph is mutable. The assignment at line 1029 fails for SubgraphNode instances. Additionally, per codebase conventions, use undefined instead of null (note line 944 already uses undefined for LGraphGroup). Either:

  • Change line 1029 to node.graph = undefined and provide a setter or cleanup method for SubgraphNode, or
  • Remove the assignment entirely if not needed for SubgraphNode cleanup.
🤖 Fix all issues with AI agents
In `@src/lib/litegraph/src/LGraph.test.ts`:
- Around line 213-251: Replace the hand-crafted ExportedSubgraph JSON in
createSubgraphWithNodes with the shared fixtures: call createTestSubgraph (and
createTestSubgraphNode for inner nodes) to build the subgraph and nodes instead
of manually assembling subgraphData and new LGraphNode instances; update the
function to accept a root LGraph and nodeCount, create the subgraph via
createTestSubgraph(rootGraph) and add nodes using createTestSubgraphNode(...) or
the fixture's helper to keep IDs/config consistent, then return { subgraph,
innerNodes } as before so tests continue to use the same return shape.

In `@src/lib/litegraph/src/LGraph.ts`:
- Around line 988-1023: The current logic fires inner-node
onRemoved/onNodeRemoved and scans nested subgraphs while still counting the node
being removed as a reference; change the flow to first determine whether this
subgraph definition has any references excluding the node being removed (compute
hasOtherReferences by scanning this.rootGraph.nodes and nested
this.rootGraph.subgraphs but skip the current node), and only if no other
references remain call innerNode.onRemoved?.() and
node.subgraph.onNodeRemoved?.(innerNode) for each inner node (also ensure you
skip the node itself when iterating) and then delete the definition from
this.rootGraph.subgraphs; keep the checks using node.isSubgraphNode(),
node.subgraph.id and this.rootGraph.subgraphs.delete(subgraphId) to locate the
relevant code paths.

@github-actions
Copy link

github-actions bot commented Jan 20, 2026

Bundle Size Report

Summary

  • Raw size: 22.1 MB baseline 22.1 MB — 🔴 +100 B
  • Gzip: 4.59 MB baseline 4.59 MB — 🔴 +93 B
  • Brotli: 3.41 MB baseline 3.41 MB — 🔴 +223 B
  • Bundles: 172 current • 172 baseline • 81 added / 81 removed

Category Glance
Data & Services 🔴 +303 B (2.7 MB) · Other 🟢 -195 B (7.05 MB) · Panels & Settings 🟢 -8 B (471 kB) · Vendor & Third-Party ⚪ 0 B (10.7 MB) · Graph Workspace ⚪ 0 B (960 kB) · Views & Navigation ⚪ 0 B (80.7 kB) · + 5 more

Per-category breakdown
App Entry Points — 25.9 kB (baseline 25.9 kB) • ⚪ 0 B

Main entry bundles and manifests

File Before After Δ Raw Δ Gzip Δ Brotli
assets/index-biCCubpz.js (new) 25.9 kB 🔴 +25.9 kB 🔴 +7.46 kB 🔴 +6.54 kB
assets/index-C7ELS-kK.js (removed) 25.9 kB 🟢 -25.9 kB 🟢 -7.46 kB 🟢 -6.55 kB

Status: 1 added / 1 removed

Graph Workspace — 960 kB (baseline 960 kB) • ⚪ 0 B

Graph editor runtime, canvas, workflow orchestration

File Before After Δ Raw Δ Gzip Δ Brotli
assets/GraphView-DFkHYvfL.js (new) 960 kB 🔴 +960 kB 🔴 +194 kB 🔴 +147 kB
assets/GraphView-DzX9NI26.js (removed) 960 kB 🟢 -960 kB 🟢 -194 kB 🟢 -147 kB

Status: 1 added / 1 removed

Views & Navigation — 80.7 kB (baseline 80.7 kB) • ⚪ 0 B

Top-level views, pages, and routed surfaces

File Before After Δ Raw Δ Gzip Δ Brotli
assets/CloudSurveyView-cMN_9chO.js (removed) 17.1 kB 🟢 -17.1 kB 🟢 -3.6 kB 🟢 -3.05 kB
assets/CloudSurveyView-x1fNPQt4.js (new) 17.1 kB 🔴 +17.1 kB 🔴 +3.61 kB 🔴 +3.06 kB
assets/CloudLoginView-2rocmIQJ.js (new) 11.8 kB 🔴 +11.8 kB 🔴 +3.09 kB 🔴 +2.71 kB
assets/CloudLoginView-BDjRdzja.js (removed) 11.8 kB 🟢 -11.8 kB 🟢 -3.09 kB 🟢 -2.71 kB
assets/UserCheckView-Bo76H-vU.js (new) 10.5 kB 🔴 +10.5 kB 🔴 +2.45 kB 🔴 +2.13 kB
assets/UserCheckView-OWIqYcD2.js (removed) 10.5 kB 🟢 -10.5 kB 🟢 -2.44 kB 🟢 -2.13 kB
assets/CloudLayoutView-BRBiYsCw.js (removed) 8.54 kB 🟢 -8.54 kB 🟢 -2.24 kB 🟢 -1.96 kB
assets/CloudLayoutView-CsspOhrw.js (new) 8.54 kB 🔴 +8.54 kB 🔴 +2.24 kB 🔴 +1.96 kB
assets/CloudSignupView-BYMyjdyn.js (removed) 8.18 kB 🟢 -8.18 kB 🟢 -2.33 kB 🟢 -2.01 kB
assets/CloudSignupView-U2WzgK3z.js (new) 8.18 kB 🔴 +8.18 kB 🔴 +2.33 kB 🔴 +2.02 kB
assets/CloudForgotPasswordView--Yis5tP0.js (removed) 6.26 kB 🟢 -6.26 kB 🟢 -1.93 kB 🟢 -1.69 kB
assets/CloudForgotPasswordView-Dww5tini.js (new) 6.26 kB 🔴 +6.26 kB 🔴 +1.93 kB 🔴 +1.69 kB
assets/UserSelectView-8ImFIHsG.js (removed) 5.28 kB 🟢 -5.28 kB 🟢 -1.76 kB 🟢 -1.57 kB
assets/UserSelectView-DE3Dzi_w.js (new) 5.28 kB 🔴 +5.28 kB 🔴 +1.76 kB 🔴 +1.57 kB
assets/CloudSubscriptionRedirectView-D4CBAJhC.js (removed) 5.27 kB 🟢 -5.27 kB 🟢 -1.73 kB 🟢 -1.54 kB
assets/CloudSubscriptionRedirectView-DBu_E5PQ.js (new) 5.27 kB 🔴 +5.27 kB 🔴 +1.73 kB 🔴 +1.54 kB
assets/CloudAuthTimeoutView-8tDg3lcB.js (removed) 5.24 kB 🟢 -5.24 kB 🟢 -1.7 kB 🟢 -1.48 kB
assets/CloudAuthTimeoutView-CHgOvSoc.js (new) 5.24 kB 🔴 +5.24 kB 🔴 +1.7 kB 🔴 +1.48 kB
assets/CloudSorryContactSupportView-BBzzzDkN.js 1.97 kB 1.97 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/layout-Rbze1-VP.js 500 B 500 B ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 9 added / 9 removed

Panels & Settings — 471 kB (baseline 471 kB) • 🟢 -8 B

Configuration panels, inspectors, and settings screens

File Before After Δ Raw Δ Gzip Δ Brotli
assets/WorkspacePanel-BQ0BIqQI.js (removed) 29.8 kB 🟢 -29.8 kB 🟢 -5.89 kB 🟢 -5.15 kB
assets/WorkspacePanel-DIcZVcqY.js (new) 29.8 kB 🔴 +29.8 kB 🔴 +5.89 kB 🔴 +5.15 kB
assets/LegacyCreditsPanel-BGouvEAX.js (new) 23.8 kB 🔴 +23.8 kB 🔴 +5.95 kB 🔴 +5.23 kB
assets/LegacyCreditsPanel-caSwg2W5.js (removed) 23.8 kB 🟢 -23.8 kB 🟢 -5.95 kB 🟢 -5.22 kB
assets/SubscriptionPanel-DowpLWId.js (removed) 21 kB 🟢 -21 kB 🟢 -5.02 kB 🟢 -4.44 kB
assets/SubscriptionPanel-Dp42EWPB.js (new) 21 kB 🔴 +21 kB 🔴 +5.03 kB 🔴 +4.44 kB
assets/KeybindingPanel-DHADNeJn.js (removed) 14.2 kB 🟢 -14.2 kB 🟢 -3.74 kB 🟢 -3.3 kB
assets/KeybindingPanel-DZ9-tlJI.js (new) 14.2 kB 🔴 +14.2 kB 🔴 +3.73 kB 🔴 +3.3 kB
assets/AboutPanel-D8jVw4-o.js (removed) 10.8 kB 🟢 -10.8 kB 🟢 -2.68 kB 🟢 -2.43 kB
assets/AboutPanel-DC95NX8k.js (new) 10.8 kB 🔴 +10.8 kB 🔴 +2.68 kB 🔴 +2.44 kB
assets/ExtensionPanel-CaXagLCy.js (new) 10.2 kB 🔴 +10.2 kB 🔴 +2.71 kB 🔴 +2.4 kB
assets/ExtensionPanel-DFKris-l.js (removed) 10.2 kB 🟢 -10.2 kB 🟢 -2.7 kB 🟢 -2.4 kB
assets/ServerConfigPanel-BByOEqpr.js (new) 7.23 kB 🔴 +7.23 kB 🔴 +2.17 kB 🔴 +1.94 kB
assets/ServerConfigPanel-DIssJ1uA.js (removed) 7.23 kB 🟢 -7.23 kB 🟢 -2.16 kB 🟢 -1.94 kB
assets/UserPanel-BEcN0Kpx.js (removed) 6.58 kB 🟢 -6.58 kB 🟢 -1.9 kB 🟢 -1.67 kB
assets/UserPanel-CXWCkLRq.js (new) 6.58 kB 🔴 +6.58 kB 🔴 +1.9 kB 🔴 +1.67 kB
assets/refreshRemoteConfig-CxH0TEve.js (new) 1.31 kB 🔴 +1.31 kB 🔴 +573 B 🔴 +496 B
assets/refreshRemoteConfig-DLHI51iC.js (removed) 1.31 kB 🟢 -1.31 kB 🟢 -573 B 🟢 -520 B
assets/config-Dc3Xy7IP.js (removed) 1.16 kB 🟢 -1.16 kB 🟢 -609 B 🟢 -538 B
assets/config-DgN4QlMA.js (new) 1.15 kB 🔴 +1.15 kB 🔴 +605 B 🔴 +531 B
assets/cloudRemoteConfig-BFh1IAQG.js (new) 1.08 kB 🔴 +1.08 kB 🔴 +497 B 🔴 +432 B
assets/cloudRemoteConfig-Di3keyVY.js (removed) 1.08 kB 🟢 -1.08 kB 🟢 -494 B 🟢 -428 B
assets/refreshRemoteConfig-BA7hAf4L.js (removed) 169 B 🟢 -169 B 🟢 -108 B 🟢 -103 B
assets/refreshRemoteConfig-Bwp3DSlb.js (new) 169 B 🔴 +169 B 🔴 +108 B 🔴 +111 B
assets/remoteConfig-BrsVXI_d.js 788 B 788 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-B9wKvI1J.js 32 kB 32 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-BmGbe2N6.js 35.2 kB 35.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-Bvo_gE5u.js 29.6 kB 29.6 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-C352ZOFL.js 26.4 kB 26.4 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-CfTcklGM.js 30.2 kB 30.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-DcSPTvwN.js 29.4 kB 29.4 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-DjnBsCcX.js 39.4 kB 39.4 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-DzHQYae7.js 32.9 kB 32.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-kAwy8UoQ.js 25.8 kB 25.8 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-KHOuN10S.js 30.4 kB 30.4 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-Y1z1vZwm.js 31.2 kB 31.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 12 added / 12 removed

User & Accounts — 3.94 kB (baseline 3.94 kB) • ⚪ 0 B

Authentication, profile, and account management bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/auth-CgqGLO-7.js (removed) 3.54 kB 🟢 -3.54 kB 🟢 -1.24 kB 🟢 -1.05 kB
assets/auth-DJrY1oOx.js (new) 3.54 kB 🔴 +3.54 kB 🔴 +1.24 kB 🔴 +1.05 kB
assets/firebaseAuthStore-lhSsfgy3.js (new) 217 B 🔴 +217 B 🔴 +136 B 🔴 +120 B
assets/firebaseAuthStore-my-jLfXx.js (removed) 217 B 🟢 -217 B 🟢 -136 B 🟢 -117 B
assets/auth-CW53H6bW.js (removed) 178 B 🟢 -178 B 🟢 -142 B 🟢 -130 B
assets/auth-U_ENX8sf.js (new) 178 B 🔴 +178 B 🔴 +142 B 🔴 +141 B

Status: 3 added / 3 removed

Editors & Dialogs — 2.86 kB (baseline 2.86 kB) • ⚪ 0 B

Modals, dialogs, drawers, and in-app editors

File Before After Δ Raw Δ Gzip Δ Brotli
assets/useSubscriptionDialog-C1y0TjT5.js (new) 2.68 kB 🔴 +2.68 kB 🔴 +1.27 kB 🔴 +1.12 kB
assets/useSubscriptionDialog-CkU33xFl.js (removed) 2.68 kB 🟢 -2.68 kB 🟢 -1.26 kB 🟢 -1.12 kB
assets/useSubscriptionDialog-BuDQ6mSc.js (removed) 179 B 🟢 -179 B 🟢 -110 B 🟢 -96 B
assets/useSubscriptionDialog-CX1BQMNV.js (new) 179 B 🔴 +179 B 🔴 +110 B 🔴 +98 B

Status: 2 added / 2 removed

UI Components — 33.7 kB (baseline 33.7 kB) • ⚪ 0 B

Reusable component library chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/ComfyQueueButton-D2qnUiNe.js (new) 9.52 kB 🔴 +9.52 kB 🔴 +2.68 kB 🔴 +2.41 kB
assets/ComfyQueueButton-MhXEepuq.js (removed) 9.52 kB 🟢 -9.52 kB 🟢 -2.68 kB 🟢 -2.42 kB
assets/SubscribeButton-CLQO8uLh.js (new) 4.63 kB 🔴 +4.63 kB 🔴 +1.57 kB 🔴 +1.39 kB
assets/SubscribeButton-CYXwUDxM.js (removed) 4.63 kB 🟢 -4.63 kB 🟢 -1.57 kB 🟢 -1.39 kB
assets/cloudFeedbackTopbarButton-BQu-NYcl.js (removed) 1.24 kB 🟢 -1.24 kB 🟢 -674 B 🟢 -562 B
assets/cloudFeedbackTopbarButton-C-uxc5YX.js (new) 1.24 kB 🔴 +1.24 kB 🔴 +674 B 🔴 +567 B
assets/ComfyQueueButton-BJvq2t65.js (new) 181 B 🔴 +181 B 🔴 +118 B 🔴 +105 B
assets/ComfyQueueButton-CqknGBko.js (removed) 181 B 🟢 -181 B 🟢 -118 B 🟢 -117 B
assets/Button-hzNlXzDK.js 3.82 kB 3.82 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/CloudBadge-DOGsbqGn.js 1.85 kB 1.85 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/TopbarBadge-CGy2FpT1.js 8.36 kB 8.36 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/UserAvatar-CWRrnxl9.js 1.73 kB 1.73 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetButton-DUixEvZU.js 2.41 kB 2.41 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 4 added / 4 removed

Data & Services — 2.7 MB (baseline 2.7 MB) • 🔴 +303 B

Stores, services, APIs, and repositories

File Before After Δ Raw Δ Gzip Δ Brotli
assets/dialogService-CaWAXCeX.js (new) 2 MB 🔴 +2 MB 🔴 +423 kB 🔴 +323 kB
assets/dialogService-DcNmlk1x.js (removed) 2 MB 🟢 -2 MB 🟢 -423 kB 🟢 -323 kB
assets/api-DKOOSzqV.js (new) 673 kB 🔴 +673 kB 🔴 +148 kB 🔴 +118 kB
assets/api-Y0NYg0N1.js (removed) 672 kB 🟢 -672 kB 🟢 -148 kB 🟢 -118 kB
assets/releaseStore-BJwDkDPB.js (removed) 8.91 kB 🟢 -8.91 kB 🟢 -2.4 kB 🟢 -2.12 kB
assets/releaseStore-D1rgOQTx.js (new) 8.91 kB 🔴 +8.91 kB 🔴 +2.4 kB 🔴 +2.12 kB
assets/keybindingService-CxjMnuy9.js (new) 6.78 kB 🔴 +6.78 kB 🔴 +1.74 kB 🔴 +1.51 kB
assets/keybindingService-zR9F8YSu.js (removed) 6.78 kB 🟢 -6.78 kB 🟢 -1.74 kB 🟢 -1.51 kB
assets/bootstrapStore-DSBs0Em8.js (new) 2.69 kB 🔴 +2.69 kB 🔴 +1.03 kB 🔴 +957 B
assets/bootstrapStore-uhaEfjnX.js (removed) 2.69 kB 🟢 -2.69 kB 🟢 -1.02 kB 🟢 -952 B
assets/userStore-B5DfjJBB.js (new) 2.16 kB 🔴 +2.16 kB 🔴 +812 B 🔴 +726 B
assets/userStore-D6WicGBx.js (removed) 2.16 kB 🟢 -2.16 kB 🟢 -811 B 🟢 -725 B
assets/audioService-Bs3fiVyC.js (new) 2.03 kB 🔴 +2.03 kB 🔴 +932 B 🔴 +812 B
assets/audioService-DJPTNev1.js (removed) 2.03 kB 🟢 -2.03 kB 🟢 -930 B 🟢 -813 B
assets/releaseStore-BUhbIcRx.js (removed) 140 B 🟢 -140 B 🟢 -106 B 🟢 -106 B
assets/releaseStore-C8hZChv0.js (new) 140 B 🔴 +140 B 🔴 +106 B 🔴 +111 B
assets/serverConfigStore-V1hr6NOk.js 2.64 kB 2.64 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 8 added / 8 removed

Utilities & Hooks — 25.3 kB (baseline 25.3 kB) • ⚪ 0 B

Helpers, composables, and utility bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/useErrorHandling-B28sdytt.js (removed) 5.21 kB 🟢 -5.21 kB 🟢 -1.53 kB 🟢 -1.34 kB
assets/useErrorHandling-DsLcyGah.js (new) 5.21 kB 🔴 +5.21 kB 🔴 +1.53 kB 🔴 +1.35 kB
assets/useWorkspaceUI-C9GHNjRJ.js (removed) 3.42 kB 🟢 -3.42 kB 🟢 -975 B 🟢 -843 B
assets/useWorkspaceUI-DMByV643.js (new) 3.42 kB 🔴 +3.42 kB 🔴 +974 B 🔴 +848 B
assets/useSubscriptionActions-CCLWNdZH.js (new) 2.22 kB 🔴 +2.22 kB 🔴 +868 B 🔴 +758 B
assets/useSubscriptionActions-vdTxOkTs.js (removed) 2.22 kB 🟢 -2.22 kB 🟢 -867 B 🟢 -762 B
assets/subscriptionCheckoutUtil-B0uHDae4.js (removed) 2.03 kB 🟢 -2.03 kB 🟢 -872 B 🟢 -764 B
assets/subscriptionCheckoutUtil-Bp3aNR6n.js (new) 2.03 kB 🔴 +2.03 kB 🔴 +873 B 🔴 +773 B
assets/useSubscriptionCredits-BLIGFJ09.js (new) 1.39 kB 🔴 +1.39 kB 🔴 +599 B 🔴 +530 B
assets/useSubscriptionCredits-C4qqqetI.js (removed) 1.39 kB 🟢 -1.39 kB 🟢 -597 B 🟢 -526 B
assets/audioUtils-Cr7CVP05.js (new) 970 B 🔴 +970 B 🔴 +548 B 🔴 +458 B
assets/audioUtils-D6nZ03e-.js (removed) 970 B 🟢 -970 B 🟢 -547 B 🟢 -457 B
assets/useCurrentUser-D4xu9HGC.js (new) 145 B 🔴 +145 B 🔴 +114 B 🔴 +102 B
assets/useCurrentUser-lw9mqQ8V.js (removed) 145 B 🟢 -145 B 🟢 -114 B 🟢 -99 B
assets/_plugin-vue_export-helper-DuK_Fly3.js 467 B 467 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/colorUtil-DLyjcs70.js 7.2 kB 7.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/markdownRendererUtil-Bi2cfnIy.js 1.78 kB 1.78 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/tailwindUtil-Dm8WXWty.js 488 B 488 B ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 7 added / 7 removed

Vendor & Third-Party — 10.7 MB (baseline 10.7 MB) • ⚪ 0 B

External libraries and shared vendor chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/vendor-chart-dHjzWL-2.js 408 kB 408 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-other-C6rCU2OI.js 4.1 MB 4.1 MB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-primevue-VBlLkufO.js 3.04 MB 3.04 MB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-reka-ui-CR4RbTw1.js 256 kB 256 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-three-BeIVXtul.js 1.83 MB 1.83 MB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-tiptap-DdP0ccEc.js 650 kB 650 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-vue-VB6jWz3M.js 13.6 kB 13.6 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-xterm-Ce2gRtuj.js 398 kB 398 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
Other — 7.05 MB (baseline 7.05 MB) • 🟢 -195 B

Bundles that do not match a named category

File Before After Δ Raw Δ Gzip Δ Brotli
assets/core-BUQOa9Vf.js (removed) 180 kB 🟢 -180 kB 🟢 -43.3 kB 🟢 -36.2 kB
assets/core-D7OxmluU.js (new) 180 kB 🔴 +180 kB 🔴 +43.3 kB 🔴 +36.1 kB
assets/WidgetSelect-Dn7N9g1m.js (new) 51 kB 🔴 +51 kB 🔴 +11.2 kB 🔴 +9.81 kB
assets/WidgetSelect-s848SM_f.js (removed) 51 kB 🟢 -51 kB 🟢 -11.2 kB 🟢 -9.8 kB
assets/Load3DControls-DGTd07qK.js (removed) 35.9 kB 🟢 -35.9 kB 🟢 -5.87 kB 🟢 -5.08 kB
assets/Load3DControls-DkK5bFVa.js (new) 35.9 kB 🔴 +35.9 kB 🔴 +5.87 kB 🔴 +5.08 kB
assets/SubscriptionRequiredDialogContent-K6n5x5Jw.js (removed) 28.7 kB 🟢 -28.7 kB 🟢 -6.78 kB 🟢 -5.92 kB
assets/SubscriptionRequiredDialogContent-zMegd1ze.js (new) 28.7 kB 🔴 +28.7 kB 🔴 +6.78 kB 🔴 +5.91 kB
assets/CurrentUserPopoverWorkspace-Dzlen4Zz.js (removed) 22.2 kB 🟢 -22.2 kB 🟢 -4.99 kB 🟢 -4.42 kB
assets/CurrentUserPopoverWorkspace-nto9M1dg.js (new) 22.2 kB 🔴 +22.2 kB 🔴 +5 kB 🔴 +4.43 kB
assets/Load3D-B7jcVAru.js (new) 19.2 kB 🔴 +19.2 kB 🔴 +4.37 kB 🔴 +3.85 kB
assets/Load3D-CbHL2nq6.js (removed) 19.2 kB 🟢 -19.2 kB 🟢 -4.37 kB 🟢 -3.85 kB
assets/WidgetRecordAudio-Bo4Cgmgs.js (new) 18.3 kB 🔴 +18.3 kB 🔴 +4.97 kB 🔴 +4.44 kB
assets/WidgetRecordAudio-CxqE8hhD.js (removed) 18.3 kB 🟢 -18.3 kB 🟢 -4.97 kB 🟢 -4.43 kB
assets/WidgetInputNumber-BKtWuvHE.js (new) 18.3 kB 🔴 +18.3 kB 🔴 +4.51 kB 🔴 +4.01 kB
assets/WidgetInputNumber-DTk4EILY.js (removed) 18.3 kB 🟢 -18.3 kB 🟢 -4.51 kB 🟢 -4.01 kB
assets/SubscriptionPanelContentWorkspace-BCMZguoR.js (new) 18.2 kB 🔴 +18.2 kB 🔴 +4.47 kB 🔴 +3.91 kB
assets/SubscriptionPanelContentWorkspace-DMNrrLwG.js (removed) 18.2 kB 🟢 -18.2 kB 🟢 -4.47 kB 🟢 -3.91 kB
assets/WidgetImageCrop-B2SF0jo5.js (new) 17.1 kB 🔴 +17.1 kB 🔴 +4.14 kB 🔴 +3.63 kB
assets/WidgetImageCrop-C5deUaPN.js (removed) 17.1 kB 🟢 -17.1 kB 🟢 -4.13 kB 🟢 -3.63 kB
assets/PanelTemplate-B2Pwz6GG.js (new) 16.2 kB 🔴 +16.2 kB 🔴 +5.46 kB 🔴 +4.8 kB
assets/PanelTemplate-ChSokRSm.js (removed) 16.2 kB 🟢 -16.2 kB 🟢 -5.45 kB 🟢 -4.8 kB
assets/AudioPreviewPlayer-BrVso93j.js (new) 10.8 kB 🔴 +10.8 kB 🔴 +2.97 kB 🔴 +2.65 kB
assets/AudioPreviewPlayer-DcNnTD2J.js (removed) 10.8 kB 🟢 -10.8 kB 🟢 -2.97 kB 🟢 -2.65 kB
assets/InviteMemberDialogContent-B0RAUrvT.js (new) 8.36 kB 🔴 +8.36 kB 🔴 +2.51 kB 🔴 +2.17 kB
assets/InviteMemberDialogContent-DlNUUV23.js (removed) 8.36 kB 🟢 -8.36 kB 🟢 -2.5 kB 🟢 -2.17 kB
assets/WidgetWithControl-lY_R9tfg.js (new) 8.04 kB 🔴 +8.04 kB 🔴 +2.66 kB 🔴 +2.4 kB
assets/WidgetWithControl-vpOTSYkx.js (removed) 8.04 kB 🟢 -8.04 kB 🟢 -2.65 kB 🟢 -2.39 kB
assets/CreateWorkspaceDialogContent-BmrBNVBC.js (new) 5.93 kB 🔴 +5.93 kB 🔴 +1.92 kB 🔴 +1.68 kB
assets/CreateWorkspaceDialogContent-CmisBwoQ.js (removed) 5.93 kB 🟢 -5.93 kB 🟢 -1.92 kB 🟢 -1.68 kB
assets/EditWorkspaceDialogContent-CqUP8z5w.js (new) 5.7 kB 🔴 +5.7 kB 🔴 +1.88 kB 🔴 +1.64 kB
assets/EditWorkspaceDialogContent-DeU5Umsq.js (removed) 5.7 kB 🟢 -5.7 kB 🟢 -1.88 kB 🟢 -1.64 kB
assets/ValueControlPopover-A2y9_LIW.js (new) 5.17 kB 🔴 +5.17 kB 🔴 +1.69 kB 🔴 +1.5 kB
assets/ValueControlPopover-CnQS4nca.js (removed) 5.17 kB 🟢 -5.17 kB 🟢 -1.69 kB 🟢 -1.5 kB
assets/DeleteWorkspaceDialogContent-6020RyAE.js (new) 4.59 kB 🔴 +4.59 kB 🔴 +1.56 kB 🔴 +1.35 kB
assets/DeleteWorkspaceDialogContent-BZ6XAGrr.js (removed) 4.59 kB 🟢 -4.59 kB 🟢 -1.56 kB 🟢 -1.35 kB
assets/LeaveWorkspaceDialogContent-Bd9Lj9Zq.js (new) 4.41 kB 🔴 +4.41 kB 🔴 +1.5 kB 🔴 +1.31 kB
assets/LeaveWorkspaceDialogContent-h_eNz-t-.js (removed) 4.41 kB 🟢 -4.41 kB 🟢 -1.5 kB 🟢 -1.3 kB
assets/RemoveMemberDialogContent-BYp0EzTF.js (new) 4.38 kB 🔴 +4.38 kB 🔴 +1.45 kB 🔴 +1.28 kB
assets/RemoveMemberDialogContent-D3GyrAik.js (removed) 4.38 kB 🟢 -4.38 kB 🟢 -1.45 kB 🟢 -1.27 kB
assets/RevokeInviteDialogContent-CoTqRYdS.js (removed) 4.29 kB 🟢 -4.29 kB 🟢 -1.47 kB 🟢 -1.29 kB
assets/RevokeInviteDialogContent-DOWmNmnP.js (new) 4.29 kB 🔴 +4.29 kB 🔴 +1.47 kB 🔴 +1.29 kB
assets/GlobalToast-C-VqbBSo.js (removed) 3.05 kB 🟢 -3.05 kB 🟢 -1.1 kB 🟢 -942 B
assets/GlobalToast-WLmQhAnV.js (new) 3.05 kB 🔴 +3.05 kB 🔴 +1.09 kB 🔴 +938 B
assets/SubscribeToRun-D-1ffbn-.js (removed) 2.96 kB 🟢 -2.96 kB 🟢 -1.15 kB 🟢 -1.01 kB
assets/SubscribeToRun-D12fgaur.js (new) 2.96 kB 🔴 +2.96 kB 🔴 +1.15 kB 🔴 +1.01 kB
assets/cloudSessionCookie-CagcmVQ_.js (removed) 2.94 kB 🟢 -2.94 kB 🟢 -929 B 🟢 -800 B
assets/cloudSessionCookie-DWRQsWjP.js (new) 2.94 kB 🔴 +2.94 kB 🔴 +928 B 🔴 +804 B
assets/BaseViewTemplate-0Q25lHVX.js (new) 2.42 kB 🔴 +2.42 kB 🔴 +1.05 kB 🔴 +941 B
assets/BaseViewTemplate-DkUfjFyf.js (removed) 2.42 kB 🟢 -2.42 kB 🟢 -1.04 kB 🟢 -939 B
assets/CloudRunButtonWrapper-19PfbWUw.js (removed) 1.79 kB 🟢 -1.79 kB 🟢 -638 B 🟢 -562 B
assets/CloudRunButtonWrapper-Dyvt_SMy.js (new) 1.79 kB 🔴 +1.79 kB 🔴 +639 B 🔴 +561 B
assets/cloudBadges-40ghXd5o.js (removed) 1.08 kB 🟢 -1.08 kB 🟢 -533 B 🟢 -476 B
assets/cloudBadges-CFPAXIXv.js (new) 1.08 kB 🔴 +1.08 kB 🔴 +534 B 🔴 +476 B
assets/graphHasMissingNodes-B5KMglXi.js (removed) 1.06 kB 🟢 -1.06 kB 🟢 -461 B 🟢 -412 B
assets/graphHasMissingNodes-BR49c2l8.js (new) 1.06 kB 🔴 +1.06 kB 🔴 +463 B 🔴 +421 B
assets/cloudSubscription-0IyU3aZg.js (removed) 976 B 🟢 -976 B 🟢 -463 B 🟢 -399 B
assets/cloudSubscription-B_LGnxdW.js (new) 976 B 🔴 +976 B 🔴 +461 B 🔴 +398 B
assets/nightlyBadges-BoAhsbzO.js (new) 595 B 🔴 +595 B 🔴 +353 B 🔴 +311 B
assets/nightlyBadges-CqbQJDet.js (removed) 595 B 🟢 -595 B 🟢 -354 B 🟢 -308 B
assets/SubscriptionPanelContentWorkspace-CHqWDU2F.js (new) 266 B 🔴 +266 B 🔴 +136 B 🔴 +117 B
assets/SubscriptionPanelContentWorkspace-VH3fv_3x.js (removed) 266 B 🟢 -266 B 🟢 -136 B 🟢 -112 B
assets/WidgetInputNumber-BNQTEpam.js (removed) 186 B 🟢 -186 B 🟢 -119 B 🟢 -111 B
assets/WidgetInputNumber-DK0HlMQL.js (new) 186 B 🔴 +186 B 🔴 +119 B 🔴 +120 B
assets/WidgetLegacy-BrOnOCW6.js (new) 164 B 🔴 +164 B 🔴 +125 B 🔴 +114 B
assets/WidgetLegacy-DwCCvbyZ.js (removed) 164 B 🟢 -164 B 🟢 -125 B 🟢 -110 B
assets/Load3D-CxF41_5C.js (removed) 131 B 🟢 -131 B 🟢 -107 B 🟢 -110 B
assets/Load3D-DuydSMnq.js (new) 131 B 🔴 +131 B 🔴 +107 B 🔴 +114 B
assets/auto-IxU1eXFy.js 1.73 kB 1.73 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-B5unjTgE.js 18 kB 18 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-BsP-x5ri.js 17.9 kB 17.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-BtcJfAd5.js 17 kB 17 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-CEbEylFJ.js 18.5 kB 18.5 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-CSE42kAA.js 20.6 kB 20.6 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-CX9qSh0Y.js 19.3 kB 19.3 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-DgvoXt0v.js 18.8 kB 18.8 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-Dk-PWJsO.js 17.2 kB 17.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-DKwvlJiD.js 19.3 kB 19.3 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-DQuDUlM5.js 17.8 kB 17.8 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-KhEZ5Fo9.js 18 kB 18 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/i18n-5XJy0DJb.js 188 B 188 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/i18n-Bs4M4fv-.js 496 kB 496 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/LazyImage-D5HGD2sm.js 14.1 kB 14.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-B_7WGGxl.js 126 kB 126 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-B_Vu9vzy.js 173 kB 173 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-b4iGVmcs.js 133 kB 133 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-B9q3FrkM.js 113 kB 113 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-BIXPG4cV.js 155 kB 155 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-BNJh1oFm.js 130 kB 130 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-BOOP4YZP.js 144 kB 144 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-D2eACZJf.js 128 kB 128 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-DuF4FlEC.js 151 kB 151 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-gqIqRxSu.js 126 kB 126 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-mpPhTk-m.js 112 kB 112 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/Media3DTop-B5p5daPP.js 2.38 kB 2.38 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/MediaAudioTop-LOmU6GXe.js 2 kB 2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/MediaImageTop-C7M85A9X.js 2.34 kB 2.34 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/MediaVideoTop-ChOx-pbs.js 2.82 kB 2.82 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/mixpanel.module-DaC789SX.js 143 B 143 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-B8DCf1mS.js 413 kB 413 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-BAFHrj6M.js 366 kB 366 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-BlUt4zjH.js 412 kB 412 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-BuHiqTYg.js 342 kB 342 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-cE9XzsAm.js 363 kB 363 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-DiynUDVW.js 383 kB 383 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-Dk1oqXg6.js 373 kB 373 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-DpRc9McY.js 339 kB 339 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-NvS3ne6s.js 369 kB 369 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-SBfEQMMs.js 369 kB 369 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-W4n6VSIV.js 448 kB 448 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/OBJLoader2WorkerModule-DTMpvldF.js 109 kB 109 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/previousFullPath-0kMFfOzo.js 838 B 838 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/rolldown-runtime-cVp-94Rc.js 1.96 kB 1.96 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/Slider-C5sanYDO.js 4.21 kB 4.21 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/widget-BJiJuR5i.js 518 B 518 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetBoundingBox-CdPxGIkA.js 4.71 kB 4.71 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetBoundingBox-kYf5x876.js 186 B 186 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetChart-BflopHUr.js 2.79 kB 2.79 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetColorPicker-BgT2fava.js 3.71 kB 3.71 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetGalleria-CYuetUyx.js 4.57 kB 4.57 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetImageCompare-DG_IjzLF.js 3.79 kB 3.79 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetInputText-BLB-l7ow.js 2.58 kB 2.58 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetLayoutField-B6sR-d_3.js 2.61 kB 2.61 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetMarkdown-CeUTWczT.js 3.22 kB 3.22 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/widgetPropFilter-BtBp3h_n.js 1.31 kB 1.31 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetTextarea-FfGbecfC.js 3.52 kB 3.52 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetToggleSwitch-Cu4DaH99.js 3.08 kB 3.08 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 34 added / 34 removed

@coderabbitai coderabbitai bot requested a review from Myestery January 21, 2026 00:33
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/stores/imagePreviewStore.ts (1)

300-308: Don’t skip inner preview cleanup when graph is null.

The early return prevents revoking previews for inner nodes, which can leak object URLs when SubgraphNode.graph is cleared during removal. Revoke inner previews unconditionally and guard only the outer-node cleanup.

🛠️ Proposed fix
 function revokeSubgraphPreviews(subgraphNode: SubgraphNode) {
-  const { graph } = subgraphNode
-  if (!graph) return
-
-  const graphId = graph.isRootGraph ? '' : graph.id + ':'
-  revokePreviewsByLocatorId(graphId + subgraphNode.id)
   for (const node of subgraphNode.subgraph.nodes) {
     revokePreviewsByLocatorId(subgraphNode.subgraph.id + node.id)
   }
+
+  const { graph } = subgraphNode
+  if (!graph) return
+
+  const graphId = graph.isRootGraph ? '' : graph.id + ':'
+  revokePreviewsByLocatorId(graphId + subgraphNode.id)
 }
🤖 Fix all issues with AI agents
In `@design-subgraph-lifecycle.md`:
- Around line 1-13: Change the top-level heading "## Subgraph Lifecycle Cleanup
(Issue `#8145`)" to the appropriate level (match surrounding document structure,
e.g., "###" if this is a subsection) and fix the typo "associatred" to
"associated" in the Goals section so the heading level and spelling/readability
issues are corrected; update the heading and the word "associatred" (search for
that exact token) in design-subgraph-lifecycle.md.

@christian-byrne christian-byrne force-pushed the fix/subgraph-definition-gc branch from c116372 to 6a2eb38 Compare January 21, 2026 00:40
@coderabbitai coderabbitai bot requested review from ltdrdata and viva-jinyi January 21, 2026 00:41
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@src/lib/litegraph/src/LGraph.test.ts`:
- Around line 4-7: The import path for createTestSubgraphData and
createTestSubgraphNode is using an unresolved alias causing ESLint
import-x/no-unresolved; update the import in LGraph.test.ts to use a relative
path to the fixture module (replace
'@/lib/litegraph/src/subgraph/__fixtures__/subgraphHelpers' with the correct
relative path from this test file) so createTestSubgraphData and
createTestSubgraphNode resolve correctly, or alternatively adjust the project
resolver if the alias should be supported.

In `@src/lib/litegraph/src/LGraph.ts`:
- Around line 988-996: The removal currently only deletes the immediate subgraph
registry entry; update the SubgraphNode cleanup in the block guarded by
node.isSubgraphNode() to perform a depth-first recursion over
node.subgraph.nodes: for each innerNode call innerNode.onRemoved?.() and
node.subgraph.onNodeRemoved?.(innerNode), and if innerNode.isSubgraphNode() also
delete its registry entry from this.rootGraph.subgraphs
(this.rootGraph.subgraphs.delete(innerNode.subgraph.id)) and recurse into
innerNode.subgraph.nodes to repeat the same cleanup so nested subgraph
definitions are removed and no orphaned entries remain.
♻️ Duplicate comments (1)
src/lib/litegraph/src/LGraph.test.ts (1)

216-227: Prefer createTestSubgraph for fixture setup.

The subgraph test guidance prefers createTestSubgraph to keep IDs/state consistent and reduce brittle fixture wiring. Based on learnings, please use the shared subgraph helpers in tests.

♻️ Proposed refactor
-import {
-  createTestSubgraphData,
-  createTestSubgraphNode
-} from './subgraph/__fixtures__/subgraphHelpers'
+import {
+  createTestSubgraph,
+  createTestSubgraphNode
+} from './subgraph/__fixtures__/subgraphHelpers'
@@
   function createSubgraphWithNodes(rootGraph: LGraph, nodeCount: number) {
-    const subgraph = rootGraph.createSubgraph(createTestSubgraphData())
+    const subgraph = createTestSubgraph(rootGraph)

Comment on lines 988 to 996
// Handle SubgraphNode-specific cleanup
// Each SubgraphNode owns a unique Subgraph definition (no linked subgraphs)
if (node.isSubgraphNode()) {
for (const innerNode of node.subgraph.nodes) {
innerNode.onRemoved?.()
node.subgraph.onNodeRemoved?.(innerNode)
}
this.rootGraph.subgraphs.delete(node.subgraph.id)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Check for nested subgraph scenarios in tests
rg -n -A5 -B5 'nested.*subgraph|subgraph.*nested' --type=ts src/

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 28681


🏁 Script executed:

# Look at the remove() method and surrounding context
sed -n '970,1010p' src/lib/litegraph/src/LGraph.ts

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 1206


🏁 Script executed:

# Find all SubgraphNode-related files to understand architecture
fd -e ts -e tsx 'SubgraphNode|subgraph' src/lib/litegraph/

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 460


🏁 Script executed:

# Check if onRemoved callbacks handle subgraph cleanup
rg -n 'onRemoved' --type=ts src/lib/litegraph/

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 1936


🏁 Script executed:

# Look for SubgraphNode class definition and constructor
ast-grep --pattern 'class SubgraphNode {
  $$$
}'

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 52


🏁 Script executed:

# Get SubgraphNode.onRemoved() implementation
sed -n '557,590p' src/lib/litegraph/src/subgraph/SubgraphNode.ts

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 998


🏁 Script executed:

# Also check the test that validates this behavior
sed -n '230,280p' src/lib/litegraph/src/LGraph.test.ts

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 1678


🏁 Script executed:

# Search for any periodic cleanup or garbage collection of orphaned subgraphs
rg -n 'orphan|cleanup.*subgraph|prune' --type=ts src/lib/litegraph/

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 52


🏁 Script executed:

# Check if nested subgraph removal is tested in the edge cases
grep -n -A20 'should.*nested.*remov\|remov.*nested' src/lib/litegraph/src/subgraph/SubgraphEdgeCases.test.ts

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 52


🏁 Script executed:

# Search broadly for any nested subgraph removal tests
rg -n 'remove.*nested|nested.*remove|removeSubgraph' --type=ts src/lib/litegraph/

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 52


🏁 Script executed:

# Check what happens when you remove a node that's inside a subgraph
sed -n '225,280p' src/lib/litegraph/src/LGraph.ts

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 1606


Handle recursive cleanup for nested SubgraphNodes during removal.

The current cleanup logic only handles the immediate subgraph definition. If an innerNode is itself a SubgraphNode, its nested subgraph definition is not removed from rootGraph.subgraphs, leaving orphaned entries in the registry. While innerNode.onRemoved?.() cleans up event listeners and widgets, it does not handle subgraph definition cleanup (which only occurs in the remove() method).

Since nested subgraphs are architecturally supported (see Subgraph.MAX_NESTED_SUBGRAPHS = 1000), this should be handled recursively:

🔧 Suggested fix
 if (node.isSubgraphNode()) {
   for (const innerNode of node.subgraph.nodes) {
+    // Recursively clean up nested SubgraphNodes
+    if (innerNode.isSubgraphNode()) {
+      this.rootGraph.subgraphs.delete(innerNode.subgraph.id)
+    }
     innerNode.onRemoved?.()
     node.subgraph.onNodeRemoved?.(innerNode)
   }
   this.rootGraph.subgraphs.delete(node.subgraph.id)
 }
🤖 Prompt for AI Agents
In `@src/lib/litegraph/src/LGraph.ts` around lines 988 - 996, The removal
currently only deletes the immediate subgraph registry entry; update the
SubgraphNode cleanup in the block guarded by node.isSubgraphNode() to perform a
depth-first recursion over node.subgraph.nodes: for each innerNode call
innerNode.onRemoved?.() and node.subgraph.onNodeRemoved?.(innerNode), and if
innerNode.isSubgraphNode() also delete its registry entry from
this.rootGraph.subgraphs
(this.rootGraph.subgraphs.delete(innerNode.subgraph.id)) and recurse into
innerNode.subgraph.nodes to repeat the same cleanup so nested subgraph
definitions are removed and no orphaned entries remain.

@coderabbitai coderabbitai bot requested a review from simula-r January 21, 2026 06:23
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/lib/litegraph/src/LGraph.test.ts`:
- Around line 230-277: Add a test that ensures a subgraph definition is retained
when another SubgraphNode still references it: create an LGraph, call
createSubgraphWithNodes(rootGraph, n) to get a subgraph, then create two
SubgraphNode instances for that same subgraph via
createTestSubgraphNode(subgraph, ...), add both to rootGraph, remove one with
rootGraph.remove(theFirstSubgraphNode), and assert that
rootGraph.subgraphs.has(subgraph.id) is still true; use the existing test style
and the same helpers (LGraph, createSubgraphWithNodes, createTestSubgraphNode,
rootGraph.subgraphs) so the new test covers the “definition retained when other
references exist” branch.
♻️ Duplicate comments (2)
src/lib/litegraph/src/LGraph.test.ts (2)

4-7: Fix unresolved fixture import to avoid CI failure.

ESLint reports import-x/no-unresolved for this path, which will fail linting. Confirm the file location and resolver settings; if the file exists, update the import to the correct relative path or configure the resolver for .ts fixtures.

Run this to verify the file location and current import resolution:

#!/bin/bash
# Locate the fixture file(s) and show the current import line.
fd -a 'subgraphHelpers\.ts$'
rg -n "subgraphHelpers" src/lib/litegraph/src/LGraph.test.ts

If the file is at src/lib/litegraph/src/subgraph/__fixtures__/subgraphHelpers.ts but the resolver still fails, consider an explicit extension:

💡 Possible fix (if resolver requires extensions)
-import {
-  createTestSubgraphData,
-  createTestSubgraphNode
-} from './subgraph/__fixtures__/subgraphHelpers'
+import {
+  createTestSubgraphData,
+  createTestSubgraphNode
+} from './subgraph/__fixtures__/subgraphHelpers.ts'

216-228: Use the shared subgraph fixture helper for setup consistency.

createSubgraphWithNodes builds a subgraph via createTestSubgraphData() + rootGraph.createSubgraph(...). Repo guidance for subgraph tests prefers the createTestSubgraph(...) helper to keep subgraph definitions consistent.

[assert]

♻️ Suggested refactor
-import {
-  createTestSubgraphData,
-  createTestSubgraphNode
-} from './subgraph/__fixtures__/subgraphHelpers'
+import {
+  createTestSubgraph,
+  createTestSubgraphNode
+} from './subgraph/__fixtures__/subgraphHelpers'
 
 function createSubgraphWithNodes(rootGraph: LGraph, nodeCount: number) {
-  const subgraph = rootGraph.createSubgraph(createTestSubgraphData())
+  const subgraph = createTestSubgraph(rootGraph)

Based on learnings, please use the shared subgraph helpers in tests.

Comment on lines +230 to +277
it('removing SubgraphNode fires onRemoved for inner nodes', () => {
const rootGraph = new LGraph()
const { subgraph, innerNodes } = createSubgraphWithNodes(rootGraph, 2)
const removedNodeIds = new Set<string>()

for (const node of innerNodes) {
node.onRemoved = () => removedNodeIds.add(String(node.id))
}

const subgraphNode = createTestSubgraphNode(subgraph, { pos: [100, 100] })
rootGraph.add(subgraphNode)

expect(subgraph.nodes.length).toBe(2)

rootGraph.remove(subgraphNode)

expect(removedNodeIds.size).toBe(2)
})

it('removing SubgraphNode fires onNodeRemoved callback', () => {
const rootGraph = new LGraph()
const { subgraph } = createSubgraphWithNodes(rootGraph, 2)
const graphRemovedNodeIds = new Set<string>()

subgraph.onNodeRemoved = (node) => graphRemovedNodeIds.add(String(node.id))

const subgraphNode = createTestSubgraphNode(subgraph, { pos: [100, 100] })
rootGraph.add(subgraphNode)

rootGraph.remove(subgraphNode)

expect(graphRemovedNodeIds.size).toBe(2)
})

it('subgraph definition is removed when SubgraphNode is removed', () => {
const rootGraph = new LGraph()
const { subgraph } = createSubgraphWithNodes(rootGraph, 1)
const subgraphId = subgraph.id

const subgraphNode = createTestSubgraphNode(subgraph, { pos: [100, 100] })
rootGraph.add(subgraphNode)

expect(rootGraph.subgraphs.has(subgraphId)).toBe(true)

rootGraph.remove(subgraphNode)

expect(rootGraph.subgraphs.has(subgraphId)).toBe(false)
})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Add coverage for “definition retained when other references exist.”

The suite covers removal and callback behavior, but it doesn’t exercise the retention case where another SubgraphNode still references the same subgraph definition. That’s part of the stated objectives and is a key branch in the new GC logic.

Based on learnings, add a test that:

  1. creates two SubgraphNodes referencing the same subgraph definition,
  2. removes one, and
  3. asserts rootGraph.subgraphs still contains the definition.
🤖 Prompt for AI Agents
In `@src/lib/litegraph/src/LGraph.test.ts` around lines 230 - 277, Add a test that
ensures a subgraph definition is retained when another SubgraphNode still
references it: create an LGraph, call createSubgraphWithNodes(rootGraph, n) to
get a subgraph, then create two SubgraphNode instances for that same subgraph
via createTestSubgraphNode(subgraph, ...), add both to rootGraph, remove one
with rootGraph.remove(theFirstSubgraphNode), and assert that
rootGraph.subgraphs.has(subgraph.id) is still true; use the existing test style
and the same helpers (LGraph, createSubgraphWithNodes, createTestSubgraphNode,
rootGraph.subgraphs) so the new test covers the “definition retained when other
references exist” branch.

@christian-byrne christian-byrne force-pushed the fix/subgraph-definition-gc branch from 104e2e3 to 12ed001 Compare January 24, 2026 05:04
@dosubot dosubot bot added size:M This PR changes 30-99 lines, ignoring generated files. and removed size:L This PR changes 100-499 lines, ignoring generated files. labels Jan 24, 2026
@AustinMroz AustinMroz removed their assignment Jan 26, 2026
@christian-byrne christian-byrne force-pushed the fix/subgraph-definition-gc branch from 12ed001 to eed245b Compare January 28, 2026 06:04
@christian-byrne
Copy link
Contributor Author

Merging now so we can test on 1.39

@christian-byrne christian-byrne merged commit f1cf807 into main Jan 30, 2026
27 checks passed
@christian-byrne christian-byrne deleted the fix/subgraph-definition-gc branch January 30, 2026 00:19
christian-byrne added a commit that referenced this pull request Jan 30, 2026
#8187)

## Summary

When removing a SubgraphNode via `LGraph.remove()`:
- Fire `onRemoved` for all nodes inside the subgraph
- Fire `onNodeRemoved` callback on the subgraph for each inner node
- Remove subgraph definition from `rootGraph.subgraphs` when no other
nodes reference it (checks both root graph nodes and nodes inside other
subgraphs)

This ensures proper cleanup of subgraph definitions and lifecycle
callbacks for nested nodes when subgraph nodes are deleted.

## Changes

### LGraph.ts
Added SubgraphNode-specific cleanup in `remove()` method that:
1. Iterates inner nodes and fires their `onRemoved` callbacks
2. Fires `onNodeRemoved` on the subgraph for downstream listeners (e.g.,
minimap)
3. Garbage collects the subgraph definition when no other nodes
reference it

### SubgraphNode.ts
Fixed `graph` property to match `LGraphNode` lifecycle contract.
Previously it was declared as `override readonly graph` via constructor
parameter promotion, which prevented `LGraph.remove()` from setting
`node.graph = null`. Changed to a regular mutable property with null
guard in `rootGraph` getter.

### LGraph.test.ts
Added 4 tests:
- `removing SubgraphNode fires onRemoved for inner nodes`
- `removing SubgraphNode fires onNodeRemoved callback`
- `subgraph definition is removed when last referencing node is removed`
- `subgraph definition is retained when other nodes still reference it`

## Related

- Fixes #8145
- Part of the subgraph lifecycle cleanup plan (Slice 2: Definition
garbage collection)
snomiao pushed a commit that referenced this pull request Jan 30, 2026
#8187)

## Summary

When removing a SubgraphNode via `LGraph.remove()`:
- Fire `onRemoved` for all nodes inside the subgraph
- Fire `onNodeRemoved` callback on the subgraph for each inner node
- Remove subgraph definition from `rootGraph.subgraphs` when no other
nodes reference it (checks both root graph nodes and nodes inside other
subgraphs)

This ensures proper cleanup of subgraph definitions and lifecycle
callbacks for nested nodes when subgraph nodes are deleted.

## Changes

### LGraph.ts
Added SubgraphNode-specific cleanup in `remove()` method that:
1. Iterates inner nodes and fires their `onRemoved` callbacks
2. Fires `onNodeRemoved` on the subgraph for downstream listeners (e.g.,
minimap)
3. Garbage collects the subgraph definition when no other nodes
reference it

### SubgraphNode.ts
Fixed `graph` property to match `LGraphNode` lifecycle contract.
Previously it was declared as `override readonly graph` via constructor
parameter promotion, which prevented `LGraph.remove()` from setting
`node.graph = null`. Changed to a regular mutable property with null
guard in `rootGraph` getter.

### LGraph.test.ts
Added 4 tests:
- `removing SubgraphNode fires onRemoved for inner nodes`
- `removing SubgraphNode fires onNodeRemoved callback`
- `subgraph definition is removed when last referencing node is removed`
- `subgraph definition is retained when other nodes still reference it`

## Related

- Fixes #8145
- Part of the subgraph lifecycle cleanup plan (Slice 2: Definition
garbage collection)
DrJKL pushed a commit that referenced this pull request Jan 31, 2026
#8187)

## Summary

When removing a SubgraphNode via `LGraph.remove()`:
- Fire `onRemoved` for all nodes inside the subgraph
- Fire `onNodeRemoved` callback on the subgraph for each inner node
- Remove subgraph definition from `rootGraph.subgraphs` when no other
nodes reference it (checks both root graph nodes and nodes inside other
subgraphs)

This ensures proper cleanup of subgraph definitions and lifecycle
callbacks for nested nodes when subgraph nodes are deleted.

## Changes

### LGraph.ts
Added SubgraphNode-specific cleanup in `remove()` method that:
1. Iterates inner nodes and fires their `onRemoved` callbacks
2. Fires `onNodeRemoved` on the subgraph for downstream listeners (e.g.,
minimap)
3. Garbage collects the subgraph definition when no other nodes
reference it

### SubgraphNode.ts
Fixed `graph` property to match `LGraphNode` lifecycle contract.
Previously it was declared as `override readonly graph` via constructor
parameter promotion, which prevented `LGraph.remove()` from setting
`node.graph = null`. Changed to a regular mutable property with null
guard in `rootGraph` getter.

### LGraph.test.ts
Added 4 tests:
- `removing SubgraphNode fires onRemoved for inner nodes`
- `removing SubgraphNode fires onNodeRemoved callback`
- `subgraph definition is removed when last referencing node is removed`
- `subgraph definition is retained when other nodes still reference it`

## Related

- Fixes #8145
- Part of the subgraph lifecycle cleanup plan (Slice 2: Definition
garbage collection)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M This PR changes 30-99 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

node.onRemoved isn't called for nodes inside of subgraphs and node missing graphs sub-subgraphs

2 participants