Skip to content

Conversation

@DrJKL
Copy link
Contributor

@DrJKL DrJKL commented Jan 29, 2026

Summary

Migrates ECMAScript private fields (#) to TypeScript private (private) across LiteGraph to fix Vue Proxy reactivity incompatibility.

Problem

ES private fields (#field) are incompatible with Vue's Proxy-based reactivity system - accessing #field through a Proxy throws TypeError: Cannot read private member from an object whose class did not declare it.

Solution

  • Converted all #field to private _field across 10 phases
  • Added toJSON() methods to LGraph, NodeSlot, NodeInputSlot, and NodeOutputSlot to prevent circular reference errors during serialization (TypeScript private fields are visible to JSON.stringify unlike true ES private fields)
  • Made DragAndScale.element.data non-enumerable to break canvas circular reference chain

Testing

  • All 4027 unit tests pass
  • Added 9 new serialization tests to catch future circular reference issues
  • Browser tests (undo/redo, save workflows) verified working

┆Issue is synchronized with this Notion page by Unito

DrJKL and others added 12 commits January 29, 2026 12:12
- Rectangle.ts: #pos, #size

- ConstrainedSize.ts: #width, #height, #desiredWidth, #desiredHeight

- DragAndScale.ts: #stateHasChanged

Amp-Thread-ID: https://ampcode.com/threads/T-019c0b60-f152-749f-9e38-4a67034ea58e
Co-authored-by: Amp <amp@ampcode.com>
NodeSlot: #node → protected _node, #centreOffset → private _centreOffset

NodeOutputSlot: removed redundant #node (uses inherited _node)

NodeInputSlot: #widget → private _widgetRef

BaseWidget: #node → private _node, #value → private _value
Amp-Thread-ID: https://ampcode.com/threads/T-019c0b63-f429-755f-88db-0092230d4158
Co-authored-by: Amp <amp@ampcode.com>
Convert ECMAScript private fields (#) to TypeScript private (_) in:

- src/lib/litegraph/src/canvas/LinkConnector.ts

- src/lib/litegraph/src/LGraphCanvas.ts

Amp-Thread-ID: https://ampcode.com/threads/T-019c0b6f-2e60-76df-8acf-9aca8f1f6bff
Co-authored-by: Amp <amp@ampcode.com>
LGraphNode.ts: #concreteInputs, #concreteOutputs, #renderArea, #boundingRect, #getErrorStrokeStyle, #getSelectedStrokeStyle, #findFreeSlot, #findSlotByType, #defaultVerticalInputs, #defaultVerticalOutputs, #getSlotPositionContext, #measureSlot, #measureSlots, #getMouseOverSlot, #isMouseOverSlot, #isMouseOverWidget, #arrangeWidgets, #arrangeWidgetInputSlots

Amp-Thread-ID: https://ampcode.com/threads/T-019c0b7a-1a5c-72af-bcc8-8070d47afd82
Co-authored-by: Amp <amp@ampcode.com>
- widgetInputs.ts: #onFirstConnection, #createWidget, #mergeWidgetConfig, #isValidConnection, #removeWidgets

- groupNode.ts: #convertedToProcess

Amp-Thread-ID: https://ampcode.com/threads/T-019c0b8a-b7c8-727c-ab6b-b178fbd3d5c7
Co-authored-by: Amp <amp@ampcode.com>
Add toJSON() methods to LGraph, LGraphCanvas, NodeSlot, NodeInputSlot,
and NodeOutputSlot to break circular reference chains when class
instances are accidentally passed to JSON.stringify().

Also make HTMLCanvasElement.data non-enumerable to prevent the
LGraphCanvas back-reference from being traversed during serialization.

These fixes address circular reference errors that appeared after
migrating ES private fields (#) to TypeScript private (_), since
TypeScript private fields are visible to JSON.stringify unlike
true ES private fields.

Amp-Thread-ID: https://ampcode.com/threads/T-019c0bba-2a2e-7281-997b-5fc25957c932
Co-authored-by: Amp <amp@ampcode.com>
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 29, 2026

📝 Walkthrough

Walkthrough

Refactors many internal class members from TypeScript private-field syntax (#name) to conventional private members with an underscore prefix (_name) across core extensions, litegraph internals, UI scripts, and migration utilities. Adds public toJSON() hooks for several litegraph classes and a public isTrackpadGesture() on CanvasPointer. Tests for serialization were added.

Changes

Cohort / File(s) Summary
Core extensions
src/extensions/core/groupNode.ts, src/extensions/core/widgetInputs.ts
Renamed private fields/methods from #... to _... (including callback accumulator and multiple widget-related methods). Updated all internal call sites; no logic changes beyond access/name shifts.
LiteGraph core & canvas
src/lib/litegraph/src/LGraph.ts, src/lib/litegraph/src/LGraphCanvas.ts, src/lib/litegraph/src/CanvasPointer.ts, src/lib/litegraph/src/DragAndScale.ts
Converted many # private members to _ equivalents. Added toJSON() to LGraph and LGraphCanvas. Added public isTrackpadGesture() on CanvasPointer. Updated internal state/backing-field usages and getters/setters.
LiteGraph nodes & slots
src/lib/litegraph/src/LGraphNode.ts, src/lib/litegraph/src/LGraphNodeProperties.ts, src/lib/litegraph/src/node/...
Migrated private # fields/methods to _ names. Introduced/updated toJSON() on NodeSlot, NodeInputSlot, NodeOutputSlot to avoid circular refs. Changed widget backing to WeakRef in NodeInputSlot. Adjusted #nodeprotected _node in NodeSlot.
LiteGraph subgraph & DTOs
src/lib/litegraph/src/subgraph/...
Renamed private # fields/methods to _ equivalents (execution id backing, slot-resolution helpers, bounding rects, menu handlers). Updated all internal usages.
Infrastructure & utilities
src/lib/litegraph/src/infrastructure/..., src/utils/migration/migrateReroute.ts
Replaced private # fields with _-prefixed private fields across Rectangle, ConstrainedSize, and migration utilities. Updated accessors and internal logic to use new names.
Widgets & canvas helpers
src/lib/litegraph/src/widgets/BaseWidget.ts, src/lib/litegraph/src/canvas/...
Converted private members from # to _ naming in BaseWidget and canvas components (InputIndicators, LinkConnector). Updated event wiring and internal handlers accordingly; keyup listener scope changed from document to canvas in InputIndicators.
UI & scripts
src/scripts/api.ts, src/scripts/ui.ts, src/scripts/ui/components/*, src/scripts/ui/dialog.ts
Replaced private # fields/methods with _-prefixed private members across ComfyApi, ComfyList and UI components (asyncDialog, button, popup, dialog). Updated registrations, state, and handler references.
Testing
src/lib/litegraph/src/serialization.test.ts
Added tests verifying toJSON()/JSON.stringify do not throw and that serialization avoids circular references (graphs, nodes, slots).

Possibly related PRs

Suggested reviewers

  • simula-r
  • Myestery
  • christian-byrne
  • AustinMroz
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch drjkl/privacy-concerns

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

@github-actions
Copy link

github-actions bot commented Jan 29, 2026

🎨 Storybook Build Status

Build completed successfully!

⏰ Completed at: 01/30/2026, 12:37:00 AM UTC

🔗 Links


🎉 Your Storybook is ready for review!

@github-actions
Copy link

github-actions bot commented Jan 29, 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 29, 2026

Bundle Size Report

Summary

  • Raw size: 22.1 MB baseline 22.1 MB — 🔴 +548 B
  • Gzip: 4.61 MB baseline 4.61 MB — 🔴 +63 B
  • Brotli: 3.42 MB baseline 3.42 MB — 🔴 +142 B
  • Bundles: 173 current • 173 baseline • 81 added / 81 removed

Category Glance
Data & Services 🔴 +754 B (2.71 MB) · Other 🟢 -198 B (7.1 MB) · Panels & Settings 🟢 -8 B (471 kB) · Vendor & Third-Party ⚪ 0 B (10.7 MB) · Graph Workspace ⚪ 0 B (974 kB) · Views & Navigation ⚪ 0 B (80.7 kB) · + 5 more

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

Main entry bundles and manifests

File Before After Δ Raw Δ Gzip Δ Brotli
assets/index-B8BoGvvV.js (removed) 26 kB 🟢 -26 kB 🟢 -7.51 kB 🟢 -6.61 kB
assets/index-D4Y1BDqz.js (new) 26 kB 🔴 +26 kB 🔴 +7.51 kB 🔴 +6.61 kB

Status: 1 added / 1 removed

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

Graph editor runtime, canvas, workflow orchestration

File Before After Δ Raw Δ Gzip Δ Brotli
assets/GraphView-CCfXlR06.js (new) 974 kB 🔴 +974 kB 🔴 +197 kB 🔴 +149 kB
assets/GraphView-OqG5I-Q1.js (removed) 974 kB 🟢 -974 kB 🟢 -197 kB 🟢 -149 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-CWFRQU81.js (new) 17.1 kB 🔴 +17.1 kB 🔴 +3.6 kB 🔴 +3.05 kB
assets/CloudSurveyView-DLbX7w_v.js (removed) 17.1 kB 🟢 -17.1 kB 🟢 -3.6 kB 🟢 -3.05 kB
assets/CloudLoginView-BBpGnBoA.js (new) 11.8 kB 🔴 +11.8 kB 🔴 +3.09 kB 🔴 +2.71 kB
assets/CloudLoginView-BPP6Razq.js (removed) 11.8 kB 🟢 -11.8 kB 🟢 -3.09 kB 🟢 -2.71 kB
assets/UserCheckView-CqbRVkwR.js (new) 10.5 kB 🔴 +10.5 kB 🔴 +2.45 kB 🔴 +2.13 kB
assets/UserCheckView-DceH8OCs.js (removed) 10.5 kB 🟢 -10.5 kB 🟢 -2.44 kB 🟢 -2.13 kB
assets/CloudLayoutView-BJtba192.js (removed) 8.54 kB 🟢 -8.54 kB 🟢 -2.24 kB 🟢 -1.96 kB
assets/CloudLayoutView-BSh_5hXT.js (new) 8.54 kB 🔴 +8.54 kB 🔴 +2.24 kB 🔴 +1.96 kB
assets/CloudSignupView-oJ1D3GhR.js (new) 8.18 kB 🔴 +8.18 kB 🔴 +2.33 kB 🔴 +2.02 kB
assets/CloudSignupView-yq1ESUXW.js (removed) 8.18 kB 🟢 -8.18 kB 🟢 -2.33 kB 🟢 -2.02 kB
assets/CloudForgotPasswordView-BFOnmsSp.js (removed) 6.26 kB 🟢 -6.26 kB 🟢 -1.93 kB 🟢 -1.69 kB
assets/CloudForgotPasswordView-D_oFjK03.js (new) 6.26 kB 🔴 +6.26 kB 🔴 +1.93 kB 🔴 +1.68 kB
assets/UserSelectView-Br841Xhr.js (new) 5.28 kB 🔴 +5.28 kB 🔴 +1.76 kB 🔴 +1.57 kB
assets/UserSelectView-BVXiNB63.js (removed) 5.28 kB 🟢 -5.28 kB 🟢 -1.76 kB 🟢 -1.58 kB
assets/CloudSubscriptionRedirectView-Bblnb_k5.js (new) 5.27 kB 🔴 +5.27 kB 🔴 +1.73 kB 🔴 +1.54 kB
assets/CloudSubscriptionRedirectView-C_RhR6Fq.js (removed) 5.27 kB 🟢 -5.27 kB 🟢 -1.73 kB 🟢 -1.55 kB
assets/CloudAuthTimeoutView-BWKjYVGF.js (removed) 5.24 kB 🟢 -5.24 kB 🟢 -1.71 kB 🟢 -1.48 kB
assets/CloudAuthTimeoutView-DUWTs-jF.js (new) 5.24 kB 🔴 +5.24 kB 🔴 +1.71 kB 🔴 +1.48 kB
assets/CloudSorryContactSupportView-n5f-fGMz.js 1.97 kB 1.97 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/layout-V93lMUpe.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-BTQJRQRq.js (new) 29.8 kB 🔴 +29.8 kB 🔴 +5.89 kB 🔴 +5.14 kB
assets/WorkspacePanel-cSBGDuKt.js (removed) 29.8 kB 🟢 -29.8 kB 🟢 -5.89 kB 🟢 -5.14 kB
assets/LegacyCreditsPanel-CurmF-C8.js (removed) 23.8 kB 🟢 -23.8 kB 🟢 -5.94 kB 🟢 -5.22 kB
assets/LegacyCreditsPanel-CwK7dKvV.js (new) 23.8 kB 🔴 +23.8 kB 🔴 +5.94 kB 🔴 +5.22 kB
assets/SubscriptionPanel-BfT4O7Pw.js (removed) 21 kB 🟢 -21 kB 🟢 -5.04 kB 🟢 -4.44 kB
assets/SubscriptionPanel-Dnx2XZpm.js (new) 21 kB 🔴 +21 kB 🔴 +5.04 kB 🔴 +4.45 kB
assets/KeybindingPanel-C6QWM5xk.js (removed) 14.3 kB 🟢 -14.3 kB 🟢 -3.74 kB 🟢 -3.32 kB
assets/KeybindingPanel-D3AVKffS.js (new) 14.3 kB 🔴 +14.3 kB 🔴 +3.74 kB 🔴 +3.33 kB
assets/AboutPanel-CB3nL7Gx.js (new) 10.8 kB 🔴 +10.8 kB 🔴 +2.68 kB 🔴 +2.43 kB
assets/AboutPanel-LhHAHRfK.js (removed) 10.8 kB 🟢 -10.8 kB 🟢 -2.68 kB 🟢 -2.43 kB
assets/ExtensionPanel-BBoOYMsv.js (new) 10.2 kB 🔴 +10.2 kB 🔴 +2.71 kB 🔴 +2.4 kB
assets/ExtensionPanel-CXDUXQkw.js (removed) 10.2 kB 🟢 -10.2 kB 🟢 -2.71 kB 🟢 -2.4 kB
assets/ServerConfigPanel-C7eJPLUf.js (removed) 7.23 kB 🟢 -7.23 kB 🟢 -2.17 kB 🟢 -1.94 kB
assets/ServerConfigPanel-F0Y5dVlS.js (new) 7.23 kB 🔴 +7.23 kB 🔴 +2.16 kB 🔴 +1.94 kB
assets/UserPanel-CCejdomj.js (new) 6.58 kB 🔴 +6.58 kB 🔴 +1.9 kB 🔴 +1.67 kB
assets/UserPanel-ZuECulXk.js (removed) 6.58 kB 🟢 -6.58 kB 🟢 -1.9 kB 🟢 -1.67 kB
assets/refreshRemoteConfig-9IE36XS8.js (removed) 1.31 kB 🟢 -1.31 kB 🟢 -574 B 🟢 -499 B
assets/refreshRemoteConfig-C38y7A82.js (new) 1.31 kB 🔴 +1.31 kB 🔴 +571 B 🔴 +499 B
assets/config-CY8nFoyq.js (removed) 1.16 kB 🟢 -1.16 kB 🟢 -611 B 🟢 -543 B
assets/config-DvKu9iXA.js (new) 1.15 kB 🔴 +1.15 kB 🔴 +603 B 🔴 +534 B
assets/cloudRemoteConfig-Be-ChPMf.js (new) 1.11 kB 🔴 +1.11 kB 🔴 +510 B 🔴 +449 B
assets/cloudRemoteConfig-CZEw3NCY.js (removed) 1.11 kB 🟢 -1.11 kB 🟢 -512 B 🟢 -450 B
assets/refreshRemoteConfig-13OOZedp.js (new) 169 B 🔴 +169 B 🔴 +108 B 🔴 +104 B
assets/refreshRemoteConfig-ByZfZbWo.js (removed) 169 B 🟢 -169 B 🟢 -108 B 🟢 -102 B
assets/remoteConfig-B0mlVvm7.js 788 B 788 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-2UNjEj6k.js 32.9 kB 32.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-B2OMGvh7.js 31.2 kB 31.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-BcujOfpn.js 29.6 kB 29.6 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-BI09_t23.js 29.4 kB 29.4 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-BKamuseh.js 25.8 kB 25.8 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-BlTun9tZ.js 26.4 kB 26.4 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-CZ62uO3e.js 30.2 kB 30.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-DaK-NByz.js 35.2 kB 35.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-DaS3cSXp.js 39.4 kB 39.4 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-DWbMuaAa.js 32 kB 32 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-S7pA60Hj.js 30.4 kB 30.4 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-DTYaJcmL.js (new) 3.54 kB 🔴 +3.54 kB 🔴 +1.24 kB 🔴 +1.06 kB
assets/auth-DXIjklI5.js (removed) 3.54 kB 🟢 -3.54 kB 🟢 -1.24 kB 🟢 -1.07 kB
assets/firebaseAuthStore-BAGxD41o.js (removed) 217 B 🟢 -217 B 🟢 -138 B 🟢 -117 B
assets/firebaseAuthStore-KKGjrTJj.js (new) 217 B 🔴 +217 B 🔴 +138 B 🔴 +118 B
assets/auth-BF-6VwT5.js (new) 178 B 🔴 +178 B 🔴 +142 B 🔴 +133 B
assets/auth-xtrHtn6I.js (removed) 178 B 🟢 -178 B 🟢 -142 B 🟢 -144 B

Status: 3 added / 3 removed

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

Modals, dialogs, drawers, and in-app editors

File Before After Δ Raw Δ Gzip Δ Brotli
assets/useSubscriptionDialog-BqFVOMn5.js (new) 2.71 kB 🔴 +2.71 kB 🔴 +1.29 kB 🔴 +1.13 kB
assets/useSubscriptionDialog-Chzg7_Ef.js (removed) 2.71 kB 🟢 -2.71 kB 🟢 -1.29 kB 🟢 -1.13 kB
assets/useSubscriptionDialog-B7WaTQMA.js (removed) 179 B 🟢 -179 B 🟢 -110 B 🟢 -95 B
assets/useSubscriptionDialog-CD7Ccq07.js (new) 179 B 🔴 +179 B 🔴 +110 B 🔴 +104 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-B9EepWuf.js (new) 9.52 kB 🔴 +9.52 kB 🔴 +2.68 kB 🔴 +2.41 kB
assets/ComfyQueueButton-MPAF7aDT.js (removed) 9.52 kB 🟢 -9.52 kB 🟢 -2.69 kB 🟢 -2.41 kB
assets/SubscribeButton-0Q1ocUi0.js (new) 4.63 kB 🔴 +4.63 kB 🔴 +1.56 kB 🔴 +1.39 kB
assets/SubscribeButton-u1adibXa.js (removed) 4.63 kB 🟢 -4.63 kB 🟢 -1.57 kB 🟢 -1.39 kB
assets/cloudFeedbackTopbarButton-Bq7ROY3f.js (new) 1.24 kB 🔴 +1.24 kB 🔴 +676 B 🔴 +573 B
assets/cloudFeedbackTopbarButton-DccvfEDa.js (removed) 1.24 kB 🟢 -1.24 kB 🟢 -674 B 🟢 -571 B
assets/ComfyQueueButton-DYaJ_uxc.js (new) 181 B 🔴 +181 B 🔴 +118 B 🔴 +122 B
assets/ComfyQueueButton-Wim-ibl_.js (removed) 181 B 🟢 -181 B 🟢 -118 B 🟢 -114 B
assets/Button-Bb_i0j7c.js 3.82 kB 3.82 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/CloudBadge-CzKMhVcP.js 1.85 kB 1.85 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/TopbarBadge-qACg_vGT.js 8.36 kB 8.36 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/UserAvatar-D80lITos.js 1.73 kB 1.73 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetButton-DSv9NFvF.js 2.41 kB 2.41 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 4 added / 4 removed

Data & Services — 2.71 MB (baseline 2.71 MB) • 🔴 +754 B

Stores, services, APIs, and repositories

File Before After Δ Raw Δ Gzip Δ Brotli
assets/dialogService-C23fG8O6.js (removed) 2.01 MB 🟢 -2.01 MB 🟢 -424 kB 🟢 -324 kB
assets/dialogService-CbIGso7F.js (new) 2.01 MB 🔴 +2.01 MB 🔴 +424 kB 🔴 +324 kB
assets/api-Uead4b8e.js (new) 675 kB 🔴 +675 kB 🔴 +149 kB 🔴 +119 kB
assets/api-CWzHVoQl.js (removed) 674 kB 🟢 -674 kB 🟢 -149 kB 🟢 -118 kB
assets/releaseStore-BXAVQxOQ.js (new) 8.91 kB 🔴 +8.91 kB 🔴 +2.4 kB 🔴 +2.12 kB
assets/releaseStore-Cn4Qv9nd.js (removed) 8.91 kB 🟢 -8.91 kB 🟢 -2.4 kB 🟢 -2.12 kB
assets/keybindingService-BW0WXChi.js (new) 6.78 kB 🔴 +6.78 kB 🔴 +1.74 kB 🔴 +1.52 kB
assets/keybindingService-zmPfrxnY.js (removed) 6.78 kB 🟢 -6.78 kB 🟢 -1.75 kB 🟢 -1.51 kB
assets/bootstrapStore-BWHx6cZW.js (removed) 2.69 kB 🟢 -2.69 kB 🟢 -1.03 kB 🟢 -967 B
assets/bootstrapStore-C1lZAU5g.js (new) 2.69 kB 🔴 +2.69 kB 🔴 +1.03 kB 🔴 +966 B
assets/userStore-Be0dSxSD.js (new) 2.16 kB 🔴 +2.16 kB 🔴 +809 B 🔴 +723 B
assets/userStore-BePFrLvJ.js (removed) 2.16 kB 🟢 -2.16 kB 🟢 -811 B 🟢 -723 B
assets/audioService-DA__wjJX.js (new) 2.03 kB 🔴 +2.03 kB 🔴 +929 B 🔴 +810 B
assets/audioService-dRCkKY2j.js (removed) 2.03 kB 🟢 -2.03 kB 🟢 -932 B 🟢 -812 B
assets/releaseStore-bcyVkMT2.js (removed) 140 B 🟢 -140 B 🟢 -106 B 🟢 -106 B
assets/releaseStore-D3Z5wreY.js (new) 140 B 🔴 +140 B 🔴 +106 B 🔴 +105 B
assets/serverConfigStore-DOoqLe5c.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-Cv0hm5AV.js (removed) 5.21 kB 🟢 -5.21 kB 🟢 -1.53 kB 🟢 -1.35 kB
assets/useErrorHandling-YAbHufdM.js (new) 5.21 kB 🔴 +5.21 kB 🔴 +1.53 kB 🔴 +1.34 kB
assets/useWorkspaceUI-B2BSUFf0.js (new) 3.42 kB 🔴 +3.42 kB 🔴 +976 B 🔴 +839 B
assets/useWorkspaceUI-B8oeeVss.js (removed) 3.42 kB 🟢 -3.42 kB 🟢 -976 B 🟢 -834 B
assets/useSubscriptionActions-BUtDsrmY.js (new) 2.22 kB 🔴 +2.22 kB 🔴 +868 B 🔴 +765 B
assets/useSubscriptionActions-Dy4r1xGb.js (removed) 2.22 kB 🟢 -2.22 kB 🟢 -873 B 🟢 -764 B
assets/subscriptionCheckoutUtil-B4P94LNX.js (new) 2.03 kB 🔴 +2.03 kB 🔴 +871 B 🔴 +761 B
assets/subscriptionCheckoutUtil-BxKTV29A.js (removed) 2.03 kB 🟢 -2.03 kB 🟢 -873 B 🟢 -761 B
assets/useSubscriptionCredits-BIt8I8s9.js (removed) 1.39 kB 🟢 -1.39 kB 🟢 -595 B 🟢 -517 B
assets/useSubscriptionCredits-C_9yRrsc.js (new) 1.39 kB 🔴 +1.39 kB 🔴 +592 B 🔴 +516 B
assets/audioUtils-BGx9KTkM.js (new) 970 B 🔴 +970 B 🔴 +548 B 🔴 +487 B
assets/audioUtils-DPF2qhnH.js (removed) 970 B 🟢 -970 B 🟢 -548 B 🟢 -458 B
assets/useCurrentUser-Bc-rQqoz.js (new) 145 B 🔴 +145 B 🔴 +114 B 🔴 +98 B
assets/useCurrentUser-Cfl6GyhN.js (removed) 145 B 🟢 -145 B 🟢 -114 B 🟢 -98 B
assets/_plugin-vue_export-helper-DuK_Fly3.js 467 B 467 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/colorUtil-GMAsfHxw.js 7.2 kB 7.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/markdownRendererUtil-ivqHoiOs.js 1.78 kB 1.78 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/tailwindUtil-CJjrIEVR.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-DHGfk3hn.js 408 kB 408 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-other-jpGqhHNG.js 4.1 MB 4.1 MB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-primevue-4Jj8eU28.js 3.04 MB 3.04 MB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-reka-ui-aCG649nF.js 263 kB 263 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-three-CERwhPwK.js 1.83 MB 1.83 MB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-tiptap-BxrEVL6s.js 650 kB 650 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-vue-Dwii0E-t.js 13.6 kB 13.6 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-xterm-IX6P8SWv.js 398 kB 398 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
Other — 7.1 MB (baseline 7.1 MB) • 🟢 -198 B

Bundles that do not match a named category

File Before After Δ Raw Δ Gzip Δ Brotli
assets/core-BZ9tDby6.js (removed) 180 kB 🟢 -180 kB 🟢 -43.3 kB 🟢 -36.2 kB
assets/core-Dgs29goB.js (new) 180 kB 🔴 +180 kB 🔴 +43.3 kB 🔴 +36.2 kB
assets/WidgetSelect-C0Fp_R1X.js (new) 52.2 kB 🔴 +52.2 kB 🔴 +11.5 kB 🔴 +10 kB
assets/WidgetSelect-CTvO_aUT.js (removed) 52.2 kB 🟢 -52.2 kB 🟢 -11.5 kB 🟢 -10 kB
assets/Load3DControls-Col4SX6H.js (removed) 35.9 kB 🟢 -35.9 kB 🟢 -5.87 kB 🟢 -5.08 kB
assets/Load3DControls-CTzszdDC.js (new) 35.9 kB 🔴 +35.9 kB 🔴 +5.87 kB 🔴 +5.08 kB
assets/SubscriptionRequiredDialogContent-DkBMOxyk.js (removed) 28.7 kB 🟢 -28.7 kB 🟢 -6.78 kB 🟢 -5.92 kB
assets/SubscriptionRequiredDialogContent-qR4fj5WL.js (new) 28.7 kB 🔴 +28.7 kB 🔴 +6.78 kB 🔴 +5.91 kB
assets/CurrentUserPopoverWorkspace-00GbN1aB.js (removed) 22.2 kB 🟢 -22.2 kB 🟢 -4.99 kB 🟢 -4.42 kB
assets/CurrentUserPopoverWorkspace-BIUrfjx4.js (new) 22.2 kB 🔴 +22.2 kB 🔴 +4.99 kB 🔴 +4.43 kB
assets/Load3D-CIZeyVVm.js (removed) 19.2 kB 🟢 -19.2 kB 🟢 -4.37 kB 🟢 -3.85 kB
assets/Load3D-ClJLV57K.js (new) 19.2 kB 🔴 +19.2 kB 🔴 +4.37 kB 🔴 +3.84 kB
assets/WidgetInputNumber-fTgEogks.js (removed) 18.3 kB 🟢 -18.3 kB 🟢 -4.52 kB 🟢 -4.03 kB
assets/WidgetInputNumber-mQQdMhIG.js (new) 18.3 kB 🔴 +18.3 kB 🔴 +4.53 kB 🔴 +4.03 kB
assets/WidgetRecordAudio-czXF6Bbu.js (removed) 18.3 kB 🟢 -18.3 kB 🟢 -4.97 kB 🟢 -4.44 kB
assets/WidgetRecordAudio-D9rV-Hiw.js (new) 18.3 kB 🔴 +18.3 kB 🔴 +4.97 kB 🔴 +4.44 kB
assets/SubscriptionPanelContentWorkspace-BtMD5zaM.js (new) 18.2 kB 🔴 +18.2 kB 🔴 +4.47 kB 🔴 +3.9 kB
assets/SubscriptionPanelContentWorkspace-CJNHr6C9.js (removed) 18.2 kB 🟢 -18.2 kB 🟢 -4.47 kB 🟢 -3.9 kB
assets/WidgetImageCrop-C_n49czp.js (removed) 17.1 kB 🟢 -17.1 kB 🟢 -4.14 kB 🟢 -3.63 kB
assets/WidgetImageCrop-DqDIrFMW.js (new) 17.1 kB 🔴 +17.1 kB 🔴 +4.14 kB 🔴 +3.63 kB
assets/PanelTemplate-BTRgva23.js (new) 16.2 kB 🔴 +16.2 kB 🔴 +5.45 kB 🔴 +4.8 kB
assets/PanelTemplate-C75prV7c.js (removed) 16.2 kB 🟢 -16.2 kB 🟢 -5.45 kB 🟢 -4.8 kB
assets/AudioPreviewPlayer-Bo_BtpPC.js (removed) 10.8 kB 🟢 -10.8 kB 🟢 -2.97 kB 🟢 -2.65 kB
assets/AudioPreviewPlayer-LxI_FD-g.js (new) 10.8 kB 🔴 +10.8 kB 🔴 +2.98 kB 🔴 +2.66 kB
assets/InviteMemberDialogContent-BVcjsX4u.js (new) 8.36 kB 🔴 +8.36 kB 🔴 +2.5 kB 🔴 +2.17 kB
assets/InviteMemberDialogContent-CHnZnM-Q.js (removed) 8.36 kB 🟢 -8.36 kB 🟢 -2.5 kB 🟢 -2.17 kB
assets/WidgetWithControl-BmBjGpve.js (new) 8.07 kB 🔴 +8.07 kB 🔴 +2.67 kB 🔴 +2.41 kB
assets/WidgetWithControl-Duvr_QlF.js (removed) 8.07 kB 🟢 -8.07 kB 🟢 -2.68 kB 🟢 -2.41 kB
assets/CreateWorkspaceDialogContent-BQkk-UXP.js (new) 5.93 kB 🔴 +5.93 kB 🔴 +1.93 kB 🔴 +1.68 kB
assets/CreateWorkspaceDialogContent-DdH3l3R9.js (removed) 5.93 kB 🟢 -5.93 kB 🟢 -1.93 kB 🟢 -1.68 kB
assets/EditWorkspaceDialogContent-C2XvvgY3.js (new) 5.7 kB 🔴 +5.7 kB 🔴 +1.88 kB 🔴 +1.64 kB
assets/EditWorkspaceDialogContent-D4-RuFvO.js (removed) 5.7 kB 🟢 -5.7 kB 🟢 -1.88 kB 🟢 -1.64 kB
assets/ValueControlPopover-0onOshcb.js (new) 5.17 kB 🔴 +5.17 kB 🔴 +1.68 kB 🔴 +1.5 kB
assets/ValueControlPopover-C7CzlL9n.js (removed) 5.17 kB 🟢 -5.17 kB 🟢 -1.68 kB 🟢 -1.49 kB
assets/DeleteWorkspaceDialogContent-BkoOwYcp.js (new) 4.59 kB 🔴 +4.59 kB 🔴 +1.56 kB 🔴 +1.35 kB
assets/DeleteWorkspaceDialogContent-Cnkxe0_T.js (removed) 4.59 kB 🟢 -4.59 kB 🟢 -1.56 kB 🟢 -1.35 kB
assets/LeaveWorkspaceDialogContent-BAaNxLEc.js (new) 4.41 kB 🔴 +4.41 kB 🔴 +1.5 kB 🔴 +1.3 kB
assets/LeaveWorkspaceDialogContent-CkMRezIY.js (removed) 4.41 kB 🟢 -4.41 kB 🟢 -1.5 kB 🟢 -1.3 kB
assets/RemoveMemberDialogContent-Caf4tL1_.js (removed) 4.38 kB 🟢 -4.38 kB 🟢 -1.45 kB 🟢 -1.27 kB
assets/RemoveMemberDialogContent-Cdjd7DxT.js (new) 4.38 kB 🔴 +4.38 kB 🔴 +1.45 kB 🔴 +1.27 kB
assets/RevokeInviteDialogContent-B9MjZmKK.js (new) 4.29 kB 🔴 +4.29 kB 🔴 +1.47 kB 🔴 +1.29 kB
assets/RevokeInviteDialogContent-Cv6z6cJF.js (removed) 4.29 kB 🟢 -4.29 kB 🟢 -1.47 kB 🟢 -1.29 kB
assets/GlobalToast-BXnpN1Fx.js (new) 3.05 kB 🔴 +3.05 kB 🔴 +1.1 kB 🔴 +942 B
assets/GlobalToast-DfmV2ARq.js (removed) 3.05 kB 🟢 -3.05 kB 🟢 -1.1 kB 🟢 -945 B
assets/SubscribeToRun-BUpzag9Q.js (new) 2.96 kB 🔴 +2.96 kB 🔴 +1.15 kB 🔴 +1.03 kB
assets/SubscribeToRun-D3o893lu.js (removed) 2.96 kB 🟢 -2.96 kB 🟢 -1.16 kB 🟢 -1.01 kB
assets/cloudSessionCookie-7FABp-oW.js (removed) 2.94 kB 🟢 -2.94 kB 🟢 -929 B 🟢 -802 B
assets/cloudSessionCookie-BunRJqeR.js (new) 2.94 kB 🔴 +2.94 kB 🔴 +927 B 🔴 +796 B
assets/BaseViewTemplate-D9cCcmwi.js (new) 2.42 kB 🔴 +2.42 kB 🔴 +1.04 kB 🔴 +941 B
assets/BaseViewTemplate-Dyiv9Vp_.js (removed) 2.42 kB 🟢 -2.42 kB 🟢 -1.04 kB 🟢 -941 B
assets/CloudRunButtonWrapper-CCyZVrai.js (new) 1.79 kB 🔴 +1.79 kB 🔴 +643 B 🔴 +564 B
assets/CloudRunButtonWrapper-D5vO5YVt.js (removed) 1.79 kB 🟢 -1.79 kB 🟢 -647 B 🟢 -563 B
assets/cloudBadges-Bw6b4FL2.js (new) 1.08 kB 🔴 +1.08 kB 🔴 +537 B 🔴 +491 B
assets/cloudBadges-DQsArL7q.js (removed) 1.08 kB 🟢 -1.08 kB 🟢 -538 B 🟢 -498 B
assets/graphHasMissingNodes-CjLCvVuu.js (new) 1.06 kB 🔴 +1.06 kB 🔴 +460 B 🔴 +418 B
assets/graphHasMissingNodes-W0T4o18_.js (removed) 1.06 kB 🟢 -1.06 kB 🟢 -462 B 🟢 -418 B
assets/cloudSubscription-Az_B5Pb_.js (removed) 976 B 🟢 -976 B 🟢 -466 B 🟢 -399 B
assets/cloudSubscription-D2n_3YXi.js (new) 976 B 🔴 +976 B 🔴 +465 B 🔴 +399 B
assets/nightlyBadges-B6aNYDXi.js (removed) 595 B 🟢 -595 B 🟢 -356 B 🟢 -310 B
assets/nightlyBadges-DNQYAll9.js (new) 595 B 🔴 +595 B 🔴 +355 B 🔴 +308 B
assets/SubscriptionPanelContentWorkspace-Bh4758MC.js (new) 266 B 🔴 +266 B 🔴 +136 B 🔴 +110 B
assets/SubscriptionPanelContentWorkspace-Bk-TWVyy.js (removed) 266 B 🟢 -266 B 🟢 -136 B 🟢 -125 B
assets/WidgetInputNumber-DRxjeDhT.js (new) 186 B 🔴 +186 B 🔴 +119 B 🔴 +116 B
assets/WidgetInputNumber-N-9uf4J6.js (removed) 186 B 🟢 -186 B 🟢 -119 B 🟢 -115 B
assets/WidgetLegacy-BAWtA-xa.js (new) 164 B 🔴 +164 B 🔴 +125 B 🔴 +108 B
assets/WidgetLegacy-TZAEbz-e.js (removed) 164 B 🟢 -164 B 🟢 -125 B 🟢 -111 B
assets/Load3D-Bxnln7SX.js (removed) 131 B 🟢 -131 B 🟢 -107 B 🟢 -107 B
assets/Load3D-Djy2M63q.js (new) 131 B 🔴 +131 B 🔴 +107 B 🔴 +110 B
assets/auto-DWs2ctGL.js 1.73 kB 1.73 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-BEw5ErI4.js 18.5 kB 18.5 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-BGeHkplA.js 17.9 kB 17.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-BV0l36Iz.js 17.2 kB 17.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-C_Y3D6Cn.js 17.8 kB 17.8 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-C6piRza5.js 19.3 kB 19.3 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-Cf8Zq1td.js 18.8 kB 18.8 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-CiziP3Xs.js 18 kB 18 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-D1595tOr.js 19.3 kB 19.3 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-DXauvccL.js 20.6 kB 20.6 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-P5QCEfZc.js 18 kB 18 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-WbYP_D61.js 17 kB 17 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/i18n-BlyhGDPa.js 500 kB 500 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/i18n-byadgsvD.js 188 B 188 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/LazyImage-DHwPdKGO.js 14.1 kB 14.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-BHtk4Fg_.js 174 kB 174 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-BMSlgLcp.js 155 kB 155 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-BQCWi9e4.js 112 kB 112 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-CJicmTR7.js 113 kB 113 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-CNOkBy-u.js 126 kB 126 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-CySb1R5_.js 151 kB 151 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-D0g10ZKf.js 131 kB 131 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-DMUPIFMF.js 133 kB 133 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-DpsGU4si.js 126 kB 126 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-Dz6IPJXM.js 144 kB 144 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-lrEzMywH.js 128 kB 128 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/Media3DTop-DUmUhXD6.js 2.38 kB 2.38 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/MediaAudioTop-CD66_Mw_.js 2 kB 2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/MediaImageTop-Bqe7yvm_.js 2.34 kB 2.34 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/MediaVideoTop-De3MzVmp.js 2.82 kB 2.82 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/mixpanel.module-CC2-PIpB.js 143 B 143 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-A7pvB7zM.js 370 kB 370 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-BIVjUijC.js 345 kB 345 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-Chkn0HaI.js 343 kB 343 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-CK_6GHao.js 452 kB 452 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-CToVAwnT.js 373 kB 373 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-DDabdWgx.js 417 kB 417 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-DgvJyE3d.js 386 kB 386 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-DjxaeFt_.js 416 kB 416 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-DslnWEGg.js 377 kB 377 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-EPAM3kwk.js 373 kB 373 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-NrulhNyH.js 366 kB 366 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/OBJLoader2WorkerModule-DTMpvldF.js 109 kB 109 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/previousFullPath-CmezY7As.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-D4lsf6Ob.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-CUtab2CB.js 4.71 kB 4.71 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetBoundingBox-D79nBMxa.js 186 B 186 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetChart-CiXfBVBH.js 2.79 kB 2.79 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetColorPicker-BxNqMlFv.js 3.71 kB 3.71 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetGalleria-DDD96zwa.js 4.57 kB 4.57 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetImageCompare-A6pZMGtc.js 3.79 kB 3.79 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetInputText-DSMUKRnt.js 2.58 kB 2.58 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetLayoutField-MDImyvc3.js 2.7 kB 2.7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetMarkdown-a8bZhyc5.js 3.49 kB 3.49 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/widgetPropFilter-ERx8czR8.js 1.31 kB 1.31 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetTextarea-CV3BoahN.js 3.87 kB 3.87 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetToggleSwitch-ZdaYkxkD.js 3.26 kB 3.26 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/widgetTypes-KPj-zM0O.js 573 B 573 B ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 34 added / 34 removed

@DrJKL DrJKL marked this pull request as ready for review January 29, 2026 23:27
@DrJKL DrJKL requested a review from a team as a code owner January 29, 2026 23:27
@dosubot dosubot bot added the size:XXL This PR changes 1000+ lines, ignoring generated files. label Jan 29, 2026
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/LGraphCanvas.ts`:
- Around line 324-331: The setter subgraph incorrectly uses this._subgraph after
it's been updated for the 'litegraph:set-graph' dispatch; capture the previous
value into a temp (e.g., const previous = this._subgraph) before assigning
this._subgraph = value, then dispatch with oldGraph: previous and newGraph:
value so listeners receive the correct old and new graphs (references: setter
subgraph, property _subgraph, and the 'litegraph:set-graph' dispatch payload
keys oldGraph/newGraph).

In `@src/lib/litegraph/src/LGraphNode.ts`:
- Around line 3958-3976: The _measureSlots method currently returns null when
there are no measured slots; change it to return undefined instead to follow
project conventions—update the return statement in LGraphNode::_measureSlots so
it returns undefined (or simply omits a return) when slots.length is falsy,
leaving the rest of the logic (calls to this._measureSlot and
createBounds(slots, 0)) unchanged so callers that check truthiness keep working.

Comment on lines 324 to 331
set subgraph(value: Subgraph | undefined) {
if (value !== this.#subgraph) {
this.#subgraph = value
if (value !== this._subgraph) {
this._subgraph = value
if (value)
this.dispatch('litegraph:set-graph', {
oldGraph: this.#subgraph,
oldGraph: this._subgraph,
newGraph: value
})
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

Fix oldGraph in the litegraph:set-graph event payload.

oldGraph is read after _subgraph is updated, so listeners get the new graph as the old one. Capture the previous value before assignment.

💡 Proposed fix
  set subgraph(value: Subgraph | undefined) {
-    if (value !== this._subgraph) {
-      this._subgraph = value
-      if (value)
-        this.dispatch('litegraph:set-graph', {
-          oldGraph: this._subgraph,
-          newGraph: value
-        })
-    }
+    if (value !== this._subgraph) {
+      const previous = this._subgraph
+      this._subgraph = value
+      if (value)
+        this.dispatch('litegraph:set-graph', {
+          oldGraph: previous,
+          newGraph: value
+        })
+    }
  }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
set subgraph(value: Subgraph | undefined) {
if (value !== this.#subgraph) {
this.#subgraph = value
if (value !== this._subgraph) {
this._subgraph = value
if (value)
this.dispatch('litegraph:set-graph', {
oldGraph: this.#subgraph,
oldGraph: this._subgraph,
newGraph: value
})
set subgraph(value: Subgraph | undefined) {
if (value !== this._subgraph) {
const previous = this._subgraph
this._subgraph = value
if (value)
this.dispatch('litegraph:set-graph', {
oldGraph: previous,
newGraph: value
})
}
}
🤖 Prompt for AI Agents
In `@src/lib/litegraph/src/LGraphCanvas.ts` around lines 324 - 331, The setter
subgraph incorrectly uses this._subgraph after it's been updated for the
'litegraph:set-graph' dispatch; capture the previous value into a temp (e.g.,
const previous = this._subgraph) before assigning this._subgraph = value, then
dispatch with oldGraph: previous and newGraph: value so listeners receive the
correct old and new graphs (references: setter subgraph, property _subgraph, and
the 'litegraph:set-graph' dispatch payload keys oldGraph/newGraph).

Comment on lines +3958 to 3976
private _measureSlots(): ReadOnlyRect | null {
const slots: (NodeInputSlot | NodeOutputSlot)[] = []

for (const [slotIndex, slot] of this.#concreteInputs.entries()) {
for (const [slotIndex, slot] of this._concreteInputs.entries()) {
// Unrecognized nodes (Nodes with error) has inputs but no widgets. Treat
// converted inputs as normal inputs.
/** Widget input slots are handled in {@link layoutWidgetInputSlots} */
if (this.widgets?.length && isWidgetInputSlot(slot)) continue

this.#measureSlot(slot, slotIndex, true)
this._measureSlot(slot, slotIndex, true)
slots.push(slot)
}
for (const [slotIndex, slot] of this.#concreteOutputs.entries()) {
this.#measureSlot(slot, slotIndex, false)
for (const [slotIndex, slot] of this._concreteOutputs.entries()) {
this._measureSlot(slot, slotIndex, false)
slots.push(slot)
}

return slots.length ? createBounds(slots, 0) : null
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Return undefined instead of null from _measureSlots.

Callers already branch on truthiness, so returning undefined aligns with litegraph conventions without changing behavior.

♻️ Proposed diff
-  private _measureSlots(): ReadOnlyRect | null {
+  private _measureSlots(): ReadOnlyRect | undefined {
     const slots: (NodeInputSlot | NodeOutputSlot)[] = []
@@
-    return slots.length ? createBounds(slots, 0) : null
+    return slots.length ? createBounds(slots, 0) : undefined
   }
As per coding guidelines, prefer returning `undefined` over `null`.
🤖 Prompt for AI Agents
In `@src/lib/litegraph/src/LGraphNode.ts` around lines 3958 - 3976, The
_measureSlots method currently returns null when there are no measured slots;
change it to return undefined instead to follow project conventions—update the
return statement in LGraphNode::_measureSlots so it returns undefined (or simply
omits a return) when slots.length is falsy, leaving the rest of the logic (calls
to this._measureSlot and createBounds(slots, 0)) unchanged so callers that check
truthiness keep working.

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/scripts/ui/components/popup.ts (1)

92-112: Consider fixing the type annotations (optional, outside PR scope).

The @ts-expect-error comments suppress type errors that could be fixed by properly typing the event parameters. As per coding guidelines, @ts-expect-error should be avoided in favor of fixing the underlying type issue.

♻️ Proposed fix to remove `@ts-expect-error`
-  // `@ts-expect-error` fixme ts strict error
-  private _escHandler = (e) => {
+  private _escHandler = (e: KeyboardEvent) => {
     if (e.key === 'Escape') {
       this.open = false
       e.preventDefault()
       e.stopImmediatePropagation()
     }
   }

-  // `@ts-expect-error` fixme ts strict error
-  private _clickHandler = (e) => {
-    /** `@type` {any} */
-    const target = e.target
+  private _clickHandler = (e: MouseEvent) => {
+    const target = e.target as Node | null
     if (
-      !this.element.contains(target) &&
+      target &&
+      !this.element.contains(target) &&
       this.ignoreTarget &&
       !this.target.contains(target)
     ) {
       this.open = false
     }
   }
🤖 Fix all issues with AI agents
In `@src/lib/litegraph/src/LGraphCanvas.ts`:
- Around line 453-463: The maximumFps getter in LGraphCanvas currently returns
seconds-per-frame because it computes _maximumFrameGap / 1000; change it to
return FPS by inverting the millisecond gap: when _maximumFrameGap >
Number.EPSILON return 1000 / this._maximumFrameGap, otherwise return 0; keep the
setter as-is (it already sets _maximumFrameGap = value > Number.EPSILON ? 1000 /
value : 0). Also update the other occurrence noted (around the other maximumFps
block) to the same logic so both getters consistently return FPS.

In `@src/lib/litegraph/src/serialization.test.ts`:
- Around line 1-3: Move the LiteGraph test file from its current location to the
designated test folder and update its imports accordingly: relocate the file
containing the test that imports LGraph, LGraphNode, and LiteGraph into the
src/lib/litegraph/test/ directory, then adjust the import paths for LGraph,
LGraphNode, and LiteGraph (from './litegraph' to the correct relative path) so
the test resolves modules from the new location and CI/test runner picks it up.

Comment on lines +453 to 463
private _maximumFrameGap = 0
/** Maximum frames per second to render. 0: unlimited. Default: 0 */
public get maximumFps() {
return this.#maximumFrameGap > Number.EPSILON
? this.#maximumFrameGap / 1000
return this._maximumFrameGap > Number.EPSILON
? this._maximumFrameGap / 1000
: 0
}

public set maximumFps(value) {
this.#maximumFrameGap = value > Number.EPSILON ? 1000 / value : 0
this._maximumFrameGap = value > Number.EPSILON ? 1000 / value : 0
}
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

maximumFps getter returns seconds-per-frame instead of FPS.

_maximumFrameGap is treated as milliseconds between frames in the render loop, so the getter should invert that value to expose FPS.

🛠️ Proposed fix
  public get maximumFps() {
-    return this._maximumFrameGap > Number.EPSILON
-      ? this._maximumFrameGap / 1000
-      : 0
+    return this._maximumFrameGap > Number.EPSILON
+      ? 1000 / this._maximumFrameGap
+      : 0
  }

Also applies to: 2082-2085

🤖 Prompt for AI Agents
In `@src/lib/litegraph/src/LGraphCanvas.ts` around lines 453 - 463, The maximumFps
getter in LGraphCanvas currently returns seconds-per-frame because it computes
_maximumFrameGap / 1000; change it to return FPS by inverting the millisecond
gap: when _maximumFrameGap > Number.EPSILON return 1000 / this._maximumFrameGap,
otherwise return 0; keep the setter as-is (it already sets _maximumFrameGap =
value > Number.EPSILON ? 1000 / value : 0). Also update the other occurrence
noted (around the other maximumFps block) to the same logic so both getters
consistently return FPS.

Comment on lines +1 to +3
import { describe, expect, it } from 'vitest'

import { LGraph, LGraphNode, LiteGraph } from './litegraph'
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

Relocate LiteGraph tests to the designated test directory.
This new suite is under src/lib/litegraph/src, but LiteGraph-specific tests are expected in src/lib/litegraph/test/. Please move it there and update imports if needed.

Based on learnings: Applies to src/lib/litegraph/test/** : Place Litegraph-specific tests in src/lib/litegraph/test/.

🧰 Tools
🪛 ESLint

[error] 1-1: Resolve error: EACCES: permission denied, open '/flTiJtKKkm'
at Object.writeFileSync (node:fs:2409:20)
at l (file:///home/jailuser/git/node_modules/.pnpm/get-tsconfig@4.10.1/node_modules/get-tsconfig/dist/index.mjs:7:13670)
at createFilesMatcher (file:///home/jailuser/git/node_modules/.pnpm/get-tsconfig@4.10.1/node_modules/get-tsconfig/dist/index.mjs:7:14422)
at resolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-import-resolver-typescript@4.4.4_eslint-plugin-import-x@4.16.1_@typescript-eslin_44eddb5b99ae4bce470e6fb9a90221ee/node_modules/eslint-import-resolver-typescript/lib/index.js:70:65)
at Object.resolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-import-resolver-typescript@4.4.4_eslint-plugin-import-x@4.16.1_@typescript-eslin_44eddb5b99ae4bce470e6fb9a90221ee/node_modules/eslint-import-resolver-typescript/lib/index.js:147:20)
at file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.50.0_eslint@9.39.1_jiti@2.6.1__eacac87f98d760f1781d40e8519857dc/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:170:69
at setRuleContext (/home/jailuser/git/node_modules/.pnpm/eslint-import-context@0.1.9_unrs-resolver@1.11.1/node_modules/eslint-import-context/lib/index.js:23:20)
at fullResolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.50.0_eslint@9.39.1_jiti@2.6.1__eacac87f98d760f1781d40e8519857dc/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:170:30)
at relative (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.50.0_eslint@9.39.1_jiti@2.6.1__eacac87f98d760f1781d40e8519857dc/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:215:12)
at resolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.50.0_eslint@9.39.1_jiti@2.6.1__eacac87f98d760f1781d40e8519857dc/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:220:16)

(import-x/no-unresolved)


[error] 1-1: Resolve error: EACCES: permission denied, open '/iJxVOgyKil'
at Object.writeFileSync (node:fs:2409:20)
at l (file:///home/jailuser/git/node_modules/.pnpm/get-tsconfig@4.10.1/node_modules/get-tsconfig/dist/index.mjs:7:13670)
at createFilesMatcher (file:///home/jailuser/git/node_modules/.pnpm/get-tsconfig@4.10.1/node_modules/get-tsconfig/dist/index.mjs:7:14422)
at resolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-import-resolver-typescript@4.4.4_eslint-plugin-import-x@4.16.1_@typescript-eslin_44eddb5b99ae4bce470e6fb9a90221ee/node_modules/eslint-import-resolver-typescript/lib/index.js:70:65)
at Object.resolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-import-resolver-typescript@4.4.4_eslint-plugin-import-x@4.16.1_@typescript-eslin_44eddb5b99ae4bce470e6fb9a90221ee/node_modules/eslint-import-resolver-typescript/lib/index.js:147:20)
at file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.50.0_eslint@9.39.1_jiti@2.6.1__eacac87f98d760f1781d40e8519857dc/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:170:69
at setRuleContext (/home/jailuser/git/node_modules/.pnpm/eslint-import-context@0.1.9_unrs-resolver@1.11.1/node_modules/eslint-import-context/lib/index.js:23:20)
at fullResolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.50.0_eslint@9.39.1_jiti@2.6.1__eacac87f98d760f1781d40e8519857dc/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:170:30)
at relative (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.50.0_eslint@9.39.1_jiti@2.6.1__eacac87f98d760f1781d40e8519857dc/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:215:12)
at resolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.50.0_eslint@9.39.1_jiti@2.6.1__eacac87f98d760f1781d40e8519857dc/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:220:16)

(import-x/no-relative-packages)


[error] 1-1: Resolve error: EACCES: permission denied, open '/OowACkYMGx'
at Object.writeFileSync (node:fs:2409:20)
at l (file:///home/jailuser/git/node_modules/.pnpm/get-tsconfig@4.10.1/node_modules/get-tsconfig/dist/index.mjs:7:13670)
at createFilesMatcher (file:///home/jailuser/git/node_modules/.pnpm/get-tsconfig@4.10.1/node_modules/get-tsconfig/dist/index.mjs:7:14422)
at resolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-import-resolver-typescript@4.4.4_eslint-plugin-import-x@4.16.1_@typescript-eslin_44eddb5b99ae4bce470e6fb9a90221ee/node_modules/eslint-import-resolver-typescript/lib/index.js:70:65)
at Object.resolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-import-resolver-typescript@4.4.4_eslint-plugin-import-x@4.16.1_@typescript-eslin_44eddb5b99ae4bce470e6fb9a90221ee/node_modules/eslint-import-resolver-typescript/lib/index.js:147:20)
at file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.50.0_eslint@9.39.1_jiti@2.6.1__eacac87f98d760f1781d40e8519857dc/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:170:69
at setRuleContext (/home/jailuser/git/node_modules/.pnpm/eslint-import-context@0.1.9_unrs-resolver@1.11.1/node_modules/eslint-import-context/lib/index.js:23:20)
at fullResolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.50.0_eslint@9.39.1_jiti@2.6.1__eacac87f98d760f1781d40e8519857dc/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:170:30)
at relative (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.50.0_eslint@9.39.1_jiti@2.6.1__eacac87f98d760f1781d40e8519857dc/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:215:12)
at resolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.50.0_eslint@9.39.1_jiti@2.6.1__eacac87f98d760f1781d40e8519857dc/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:220:16)

(import-x/no-useless-path-segments)


[error] 1-1: Unable to resolve path to module 'vitest'.

(import-x/no-unresolved)


[error] 3-3: Unable to resolve path to module './litegraph'.

(import-x/no-unresolved)

🤖 Prompt for AI Agents
In `@src/lib/litegraph/src/serialization.test.ts` around lines 1 - 3, Move the
LiteGraph test file from its current location to the designated test folder and
update its imports accordingly: relocate the file containing the test that
imports LGraph, LGraphNode, and LiteGraph into the src/lib/litegraph/test/
directory, then adjust the import paths for LGraph, LGraphNode, and LiteGraph
(from './litegraph' to the correct relative path) so the test resolves modules
from the new location and CI/test runner picks it up.

Copy link
Contributor

@christian-byrne christian-byrne left a comment

Choose a reason for hiding this comment

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

Only concern previously was with shadowing properties added by 3P code. Using underscore prefix should solve that. See no other issues. LGTM

Comment on lines +83 to +89
override toJSON(): INodeInputSlot {
return {
...super.toJSON(),
link: this.link,
widget: this.widget
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Were there other things you considered for this?

Copy link
Collaborator

Choose a reason for hiding this comment

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

I was pondering the same. Would it break things if we made all the toJSON calls just return serialize?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, a few things.
The best solution would be to remove the circular references, but that would be a much larger undertaking and likely™️ cause issues with existing extensions.
Another option is to replace our internal calls to JSON.stringify with a serialize that does much the same thing here, but that has the same issue of not working for existing external callers who would then hit the circular dereference bug at runtime.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@AustinMroz We'd need to implement serialize on each of these still, then call it from toJSON, right?

Copy link
Collaborator

Choose a reason for hiding this comment

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

🤔 Probably best we don't implement new serialize methods. The smaller places you added it (like NodeSlot) won't have toJSON called if the parent classes are using their (already safe) serialize methods. And your newly written toJSON methods are still an improvement when debugging with console.log

@christian-byrne christian-byrne removed their assignment Jan 30, 2026
@DrJKL DrJKL added the preview label Jan 30, 2026
@DrJKL DrJKL merged commit 067d80c into main Jan 30, 2026
32 checks passed
@DrJKL DrJKL deleted the drjkl/privacy-concerns branch January 30, 2026 02:18
AustinMroz added a commit that referenced this pull request Jan 30, 2026
Fixes a bug where canvas functionality is lost if a multitype input
(like the native switch) is added to the graph in litegraph mode.

This issue is properly fixed by #8440, but this single revision is
easier and safer to backport

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8477-Revert-matchtype-slot-reactivity-on-cloud-1-38-2f86d73d365081279285e6d86ded9e43)
by [Unito](https://www.unito.io)
snomiao pushed a commit that referenced this pull request Jan 30, 2026
…xy compatibility (#8440)

## Summary

Migrates ECMAScript private fields (`#`) to TypeScript private
(`private`) across LiteGraph to fix Vue Proxy reactivity
incompatibility.

## Problem

ES private fields (`#field`) are incompatible with Vue's Proxy-based
reactivity system - accessing `#field` through a Proxy throws
`TypeError: Cannot read private member from an object whose class did
not declare it`.

## Solution

- Converted all `#field` to `private _field` across 10 phases
- Added `toJSON()` methods to `LGraph`, `NodeSlot`, `NodeInputSlot`, and
`NodeOutputSlot` to prevent circular reference errors during
serialization (TypeScript private fields are visible to `JSON.stringify`
unlike true ES private fields)
- Made `DragAndScale.element.data` non-enumerable to break canvas
circular reference chain

## Testing

- All 4027 unit tests pass
- Added 9 new serialization tests to catch future circular reference
issues
- Browser tests (undo/redo, save workflows) verified working

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8440-refactor-migrate-ES-private-fields-to-TypeScript-private-for-Vue-Proxy-compatibility-2f76d73d365081a3bd82d429a3e0fcb7)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Amp <amp@ampcode.com>
DrJKL added a commit that referenced this pull request Jan 31, 2026
…xy compatibility (#8440)

## Summary

Migrates ECMAScript private fields (`#`) to TypeScript private
(`private`) across LiteGraph to fix Vue Proxy reactivity
incompatibility.

## Problem

ES private fields (`#field`) are incompatible with Vue's Proxy-based
reactivity system - accessing `#field` through a Proxy throws
`TypeError: Cannot read private member from an object whose class did
not declare it`.

## Solution

- Converted all `#field` to `private _field` across 10 phases
- Added `toJSON()` methods to `LGraph`, `NodeSlot`, `NodeInputSlot`, and
`NodeOutputSlot` to prevent circular reference errors during
serialization (TypeScript private fields are visible to `JSON.stringify`
unlike true ES private fields)
- Made `DragAndScale.element.data` non-enumerable to break canvas
circular reference chain

## Testing

- All 4027 unit tests pass
- Added 9 new serialization tests to catch future circular reference
issues
- Browser tests (undo/redo, save workflows) verified working

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8440-refactor-migrate-ES-private-fields-to-TypeScript-private-for-Vue-Proxy-compatibility-2f76d73d365081a3bd82d429a3e0fcb7)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Amp <amp@ampcode.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

preview size:XXL This PR changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants