Skip to content

refactor: parallelize bootstrap and simplify lifecycle with VueUse#8307

Merged
DrJKL merged 16 commits intomainfrom
drjkl/first-things-first
Jan 27, 2026
Merged

refactor: parallelize bootstrap and simplify lifecycle with VueUse#8307
DrJKL merged 16 commits intomainfrom
drjkl/first-things-first

Conversation

@DrJKL
Copy link
Contributor

@DrJKL DrJKL commented Jan 25, 2026

Summary

Refactors bootstrap and lifecycle management to parallelize initialization, use Vue best practices, and fix a logout state bug.

Changes

Bootstrap Store (bootstrapStore.ts)

  • Extract early bootstrap logic into a dedicated store using useAsyncState
  • Parallelize settings, i18n, and workflow sync loading (previously sequential)
  • Handle multi-user login scenarios by deferring settings/workflows until authenticated

GraphCanvas Refactoring

  • Move non-DOM composables (useGlobalLitegraph, useCopy, usePaste, etc.) to script setup level for earlier initialization
  • Move watch and whenever declarations outside onMounted (Vue best practice)
  • Use until() from VueUse to await bootstrap store readiness instead of direct async calls

GraphView Simplification

  • Replace manual addEventListener/removeEventListener with useEventListener
  • Replace setInterval with useIntervalFn for automatic cleanup
  • Move core command registration to script setup level

Bug Fix

Using router.push() for logout caused isSettingsReady to persist as true, making new users inherit the previous user's cached settings. Reverted to window.location.reload() with TODOs for future store reset implementation.

Testing

  • Verified login/logout cycle clears settings correctly
  • Verified bootstrap sequence completes without errors

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 25, 2026

📝 Walkthrough

Walkthrough

Adds a new Pinia bootstrap store to orchestrate startup (i18n, user init, conditional settings/workflow loading, optional Firebase gating); converts several stores to async readiness APIs, changes keyboard tracking to useMagicKeys, exposes workspace store at runtime, refactors graph/view init to VueUse patterns, updates settings/workflow loading semantics, tests, and docs.

Changes

Cohort / File(s) Summary
Bootstrap orchestration & startup
src/stores/bootstrapStore.ts, src/stores/bootstrapStore.test.ts, src/main.ts
New useBootstrapStore Pinia store and tests; main.ts instantiates and calls startStoreBootstrap() to sequence i18n, user init, conditional settings/workflow loading, and cloud Firebase gating.
Settings store (async)
src/platform/settings/settingStore.ts, src/platform/settings/settingStore.test.ts
Settings loading converted to explicit load() with isReady/isLoading/error; duplicate registration now warns instead of throwing; tests updated.
Workflow store (async sync/load)
src/platform/workflow/management/stores/workflowStore.ts
syncWorkflows wrapped in useAsyncState; new loadWorkflows() added and isSyncReady/isSyncLoading exposed.
App runtime wiring & workspace
src/App.vue, src/stores/workspaceStore.ts, src/main.ts
Removed manual keydown listeners; shiftDown now from useMagicKeys(); App.vue assigns app.extensionManager = useWorkspaceStore() at runtime.
Graph & view initialization
src/components/graph/GraphCanvas.vue, src/views/GraphView.vue
Defer heavy init until bootstrap readiness; replace manual listeners/intervals with VueUse hooks; reorder guarded startup flows and locale handling.
Core commands & tests
src/composables/useCoreCommands.ts, src/composables/useCoreCommands.test.ts
Moved subscription-related destructuring into function scope; test mocks updated to new settings API (load, isReady, isLoading, error).
Minimap & node-badge guards
src/renderer/extensions/minimap/composables/useMinimapGraph.ts, src/renderer/extensions/minimap/composables/useMinimapGraph.test.ts, src/composables/node/useNodeBadge.ts
Minimap cleanup silently no-ops when never-setup; NodeBadge re-registration guarded; tests adjusted accordingly.
Subscription error handling
src/platform/cloud/subscription/composables/useSubscription.ts
Wraps fetchSubscriptionStatus in try/catch inside watcher; logs debug on error and ensures initialization flag is set.
Browser tests / version warnings
browser_tests/tests/versionMismatchWarnings.spec.ts
Tests now explicitly enable version-mismatch warnings (Comfy.VersionCompatibility.DisableWarnings = false).
Docs / Agents guidance
AGENTS.md, src/AGENTS.md
Added Chrome DevTools MCP guidance for verbose snapshots, expanded temporary file locations, and added a state-management guideline in src/AGENTS.md.

Sequence Diagram(s)

sequenceDiagram
    participant App as App (main.ts / App.vue)
    participant Pinia as Pinia
    participant Bootstrap as BootstrapStore
    participant User as UserStore
    participant I18n as i18n Module
    participant Settings as Settings Store
    participant Workflow as Workflow Store
    participant Firebase as Firebase Auth (optional)

    App->>Pinia: createPinia()
    App->>Bootstrap: useBootstrapStore(pinia)
    App->>Bootstrap: startStoreBootstrap()
    activate Bootstrap

    Bootstrap->>User: initialize user store
    User-->>Bootstrap: auth state (needsLogin)

    par load i18n
        Bootstrap->>I18n: load & merge custom nodes i18n
        I18n-->>Bootstrap: ready / error
    and conditional settings & workflows
        alt user authenticated or no-login required
            Bootstrap->>Settings: Settings.load()
            Settings-->>Bootstrap: isReady
            Bootstrap->>Workflow: loadWorkflows()
            Workflow-->>Bootstrap: ready
        else defer until auth
        end
    end

    opt cloud distribution
        Bootstrap->>Firebase: wait for initialization
        Firebase-->>Bootstrap: initialized
    end

    Bootstrap-->>App: bootstrap complete
    deactivate Bootstrap

    App->>Workflow: rely on isReady / loadWorkflows before rendering graphs
    App->>I18n: rely on isI18nReady before node definitions
Loading

Possibly related PRs

Suggested reviewers

  • shinshin86
  • KarryCharon
  • Yorha4D
  • PabloWiedemann
  • christian-byrne
✨ Finishing touches
  • 📝 Generate docstrings

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

@github-actions
Copy link

github-actions bot commented Jan 25, 2026

🎨 Storybook Build Status

Build completed successfully!

⏰ Completed at: 01/27/2026, 08:25:50 PM UTC

🔗 Links


🎉 Your Storybook is ready for review!

@github-actions
Copy link

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

Bundle Size Report

Summary

  • Raw size: 22 MB baseline 22 MB — 🔴 +7.97 kB
  • Gzip: 4.59 MB baseline 4.59 MB — 🔴 +3.05 kB
  • Brotli: 3.41 MB baseline 3.41 MB — 🔴 +3.24 kB
  • Bundles: 173 current • 170 baseline • 171 added / 168 removed

Category Glance
Other 🔴 +496 kB (7.04 MB) · Data & Services 🟢 -492 kB (2.7 MB) · Vendor & Third-Party 🔴 +4.19 kB (10.7 MB) · Graph Workspace 🟢 -384 B (960 kB) · App Entry Points 🔴 +175 B (22.9 kB) · Utilities & Hooks 🔴 +74 B (25.2 kB) · + 5 more

Per-category breakdown
App Entry Points — 22.9 kB (baseline 22.8 kB) • 🔴 +175 B

Main entry bundles and manifests

File Before After Δ Raw Δ Gzip Δ Brotli
assets/index-DIq_ggwd.js (new) 22.9 kB 🔴 +22.9 kB 🔴 +6.89 kB 🔴 +6.05 kB
assets/index-Dhd3nWUb.js (removed) 22.8 kB 🟢 -22.8 kB 🟢 -6.84 kB 🟢 -6.05 kB

Status: 1 added / 1 removed

Graph Workspace — 960 kB (baseline 960 kB) • 🟢 -384 B

Graph editor runtime, canvas, workflow orchestration

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

Status: 1 added / 1 removed

Views & Navigation — 80.7 kB (baseline 80.7 kB) • 🔴 +1 B

Top-level views, pages, and routed surfaces

File Before After Δ Raw Δ Gzip Δ Brotli
assets/CloudSurveyView-CMQoBA8H.js (new) 17.1 kB 🔴 +17.1 kB 🔴 +3.6 kB 🔴 +3.05 kB
assets/CloudSurveyView-CVrPw1S1.js (removed) 17.1 kB 🟢 -17.1 kB 🟢 -3.6 kB 🟢 -3.05 kB
assets/CloudLoginView--t4SkqWr.js (new) 11.8 kB 🔴 +11.8 kB 🔴 +3.09 kB 🔴 +2.72 kB
assets/CloudLoginView-CET3vsoy.js (removed) 11.8 kB 🟢 -11.8 kB 🟢 -3.09 kB 🟢 -2.72 kB
assets/UserCheckView-C_KfBeHX.js (removed) 10.5 kB 🟢 -10.5 kB 🟢 -2.45 kB 🟢 -2.13 kB
assets/UserCheckView-Du5654b8.js (new) 10.5 kB 🔴 +10.5 kB 🔴 +2.44 kB 🔴 +2.13 kB
assets/CloudLayoutView-D7IZNz1m.js (new) 8.54 kB 🔴 +8.54 kB 🔴 +2.24 kB 🔴 +1.95 kB
assets/CloudLayoutView-DUPPDKpg.js (removed) 8.54 kB 🟢 -8.54 kB 🟢 -2.25 kB 🟢 -1.95 kB
assets/CloudSignupView-BIfFYqIj.js (new) 8.18 kB 🔴 +8.18 kB 🔴 +2.33 kB 🔴 +2.02 kB
assets/CloudSignupView-Bv6K0OgK.js (removed) 8.18 kB 🟢 -8.18 kB 🟢 -2.33 kB 🟢 -2.03 kB
assets/CloudForgotPasswordView-Bcpa3zh0.js (new) 6.26 kB 🔴 +6.26 kB 🔴 +1.93 kB 🔴 +1.69 kB
assets/CloudForgotPasswordView-DQ-zCm2W.js (removed) 6.26 kB 🟢 -6.26 kB 🟢 -1.92 kB 🟢 -1.69 kB
assets/UserSelectView-CgHCIHED.js (removed) 5.28 kB 🟢 -5.28 kB 🟢 -1.76 kB 🟢 -1.57 kB
assets/UserSelectView-GSyLt3UQ.js (new) 5.28 kB 🔴 +5.28 kB 🔴 +1.76 kB 🔴 +1.58 kB
assets/CloudSubscriptionRedirectView-BEvnC_sa.js (removed) 5.27 kB 🟢 -5.27 kB 🟢 -1.73 kB 🟢 -1.53 kB
assets/CloudSubscriptionRedirectView-qDCVw0V-.js (new) 5.27 kB 🔴 +5.27 kB 🔴 +1.73 kB 🔴 +1.53 kB
assets/CloudAuthTimeoutView-B2ZGpcRj.js (removed) 5.24 kB 🟢 -5.24 kB 🟢 -1.7 kB 🟢 -1.48 kB
assets/CloudAuthTimeoutView-BPfMwabs.js (new) 5.24 kB 🔴 +5.24 kB 🔴 +1.7 kB 🔴 +1.48 kB
assets/CloudSorryContactSupportView-B5gYo5Lv.js (removed) 1.97 kB 🟢 -1.97 kB 🟢 -702 B 🟢 -625 B
assets/CloudSorryContactSupportView-DLCG-MXA.js (new) 1.97 kB 🔴 +1.97 kB 🔴 +702 B 🔴 +624 B
assets/layout-C3TdDMrB.js (new) 500 B 🔴 +500 B 🔴 +308 B 🔴 +265 B
assets/layout-MvRmLoAK.js (removed) 500 B 🟢 -500 B 🟢 -309 B 🟢 -266 B

Status: 11 added / 11 removed

Panels & Settings — 470 kB (baseline 470 kB) • 🔴 +16 B

Configuration panels, inspectors, and settings screens

File Before After Δ Raw Δ Gzip Δ Brotli
assets/settings-B0OU6-pB.js (removed) 39.4 kB 🟢 -39.4 kB 🟢 -9.43 kB 🟢 -7.5 kB
assets/settings-DaS3cSXp.js (new) 39.4 kB 🔴 +39.4 kB 🔴 +9.43 kB 🔴 +7.5 kB
assets/settings-CaVpP3Yk.js (removed) 35.2 kB 🟢 -35.2 kB 🟢 -8.11 kB 🟢 -6.8 kB
assets/settings-DaK-NByz.js (new) 35.2 kB 🔴 +35.2 kB 🔴 +8.11 kB 🔴 +6.79 kB
assets/settings-2UNjEj6k.js (new) 32.9 kB 🔴 +32.9 kB 🔴 +7.85 kB 🔴 +6.37 kB
assets/settings-BG8Zhz_I.js (removed) 32.9 kB 🟢 -32.9 kB 🟢 -7.85 kB 🟢 -6.38 kB
assets/settings-DWbMuaAa.js (new) 32 kB 🔴 +32 kB 🔴 +8.25 kB 🔴 +6.86 kB
assets/settings-DWJH5Rx7.js (removed) 32 kB 🟢 -32 kB 🟢 -8.25 kB 🟢 -6.86 kB
assets/settings-B2OMGvh7.js (new) 31.2 kB 🔴 +31.2 kB 🔴 +7.94 kB 🔴 +6.93 kB
assets/settings-DQtYvoMH.js (removed) 31.2 kB 🟢 -31.2 kB 🟢 -7.94 kB 🟢 -6.91 kB
assets/settings-CT-O-PKz.js (removed) 30.4 kB 🟢 -30.4 kB 🟢 -7.79 kB 🟢 -6.79 kB
assets/settings-S7pA60Hj.js (new) 30.4 kB 🔴 +30.4 kB 🔴 +7.79 kB 🔴 +6.79 kB
assets/settings-Bh7k-ZzJ.js (removed) 30.2 kB 🟢 -30.2 kB 🟢 -7.67 kB 🟢 -6.5 kB
assets/settings-CZ62uO3e.js (new) 30.2 kB 🔴 +30.2 kB 🔴 +7.67 kB 🔴 +6.5 kB
assets/WorkspacePanel-5NI2yOsz.js (removed) 29.8 kB 🟢 -29.8 kB 🟢 -5.89 kB 🟢 -5.14 kB
assets/WorkspacePanel-DCsHiGk-.js (new) 29.8 kB 🔴 +29.8 kB 🔴 +5.89 kB 🔴 +5.13 kB
assets/settings-BcujOfpn.js (new) 29.6 kB 🔴 +29.6 kB 🔴 +7.53 kB 🔴 +6.49 kB
assets/settings-jYq3vZ8H.js (removed) 29.6 kB 🟢 -29.6 kB 🟢 -7.53 kB 🟢 -6.49 kB
assets/settings-BI09_t23.js (new) 29.4 kB 🔴 +29.4 kB 🔴 +7.89 kB 🔴 +6.52 kB
assets/settings-DrFp_k1j.js (removed) 29.4 kB 🟢 -29.4 kB 🟢 -7.89 kB 🟢 -6.52 kB
assets/settings-BlTun9tZ.js (new) 26.4 kB 🔴 +26.4 kB 🔴 +7.78 kB 🔴 +6.27 kB
assets/settings-HIJPcXNb.js (removed) 26.4 kB 🟢 -26.4 kB 🟢 -7.78 kB 🟢 -6.26 kB
assets/settings-BKamuseh.js (new) 25.8 kB 🔴 +25.8 kB 🔴 +7.56 kB 🔴 +5.91 kB
assets/settings-C_BaoiA5.js (removed) 25.8 kB 🟢 -25.8 kB 🟢 -7.56 kB 🟢 -5.9 kB
assets/LegacyCreditsPanel-BX_hmH4x.js (removed) 23.8 kB 🟢 -23.8 kB 🟢 -5.95 kB 🟢 -5.22 kB
assets/LegacyCreditsPanel-Vrrfh-Tv.js (new) 23.8 kB 🔴 +23.8 kB 🔴 +5.95 kB 🔴 +5.23 kB
assets/SubscriptionPanel-BHwcPFRj.js (new) 21 kB 🔴 +21 kB 🔴 +5.02 kB 🔴 +4.44 kB
assets/SubscriptionPanel-Bmn2zc8h.js (removed) 20.9 kB 🟢 -20.9 kB 🟢 -5.01 kB 🟢 -4.43 kB
assets/KeybindingPanel-CpQ3AwRH.js (new) 14.2 kB 🔴 +14.2 kB 🔴 +3.74 kB 🔴 +3.31 kB
assets/KeybindingPanel-DxivXzm3.js (removed) 14.2 kB 🟢 -14.2 kB 🟢 -3.74 kB 🟢 -3.31 kB
assets/AboutPanel-C4VKMANe.js (removed) 10.8 kB 🟢 -10.8 kB 🟢 -2.68 kB 🟢 -2.45 kB
assets/AboutPanel-JlHLFQPA.js (new) 10.8 kB 🔴 +10.8 kB 🔴 +2.68 kB 🔴 +2.44 kB
assets/ExtensionPanel-B60HlIUO.js (removed) 10.2 kB 🟢 -10.2 kB 🟢 -2.71 kB 🟢 -2.4 kB
assets/ExtensionPanel-CXM7rcBc.js (new) 10.2 kB 🔴 +10.2 kB 🔴 +2.71 kB 🔴 +2.4 kB
assets/ServerConfigPanel-BLcdrRFP.js (new) 7.23 kB 🔴 +7.23 kB 🔴 +2.17 kB 🔴 +1.94 kB
assets/ServerConfigPanel-D0nM3Lrk.js (removed) 7.23 kB 🟢 -7.23 kB 🟢 -2.17 kB 🟢 -1.94 kB
assets/UserPanel-BHXviZx2.js (new) 6.58 kB 🔴 +6.58 kB 🔴 +1.91 kB 🔴 +1.67 kB
assets/UserPanel-DmmND9J8.js (removed) 6.58 kB 🟢 -6.58 kB 🟢 -1.9 kB 🟢 -1.67 kB
assets/config-DCS8f76F.js (removed) 1.16 kB 🟢 -1.16 kB 🟢 -610 B 🟢 -533 B
assets/config-B7PCsS9N.js (new) 1.15 kB 🔴 +1.15 kB 🔴 +603 B 🔴 +534 B
assets/refreshRemoteConfig-JcBLrIko.js (new) 1.14 kB 🔴 +1.14 kB 🔴 +520 B 🔴 +485 B
assets/refreshRemoteConfig-yFdHl0oK.js (removed) 1.14 kB 🟢 -1.14 kB 🟢 -521 B 🟢 -453 B
assets/cloudRemoteConfig-B7bx9Ek0.js (new) 1.11 kB 🔴 +1.11 kB 🔴 +508 B 🔴 +446 B
assets/cloudRemoteConfig-tIIBFP7M.js (removed) 1.11 kB 🟢 -1.11 kB 🟢 -508 B 🟢 -434 B
assets/remoteConfig-DlUK-xIk.js (new) 536 B 🔴 +536 B 🔴 +313 B 🔴 +278 B
assets/remoteConfig-w1E3DdAQ.js (removed) 536 B 🟢 -536 B 🟢 -314 B 🟢 -278 B
assets/refreshRemoteConfig-qt8lWdXr.js (removed) 169 B 🟢 -169 B 🟢 -108 B 🟢 -104 B
assets/refreshRemoteConfig-v7atBTaL.js (new) 169 B 🔴 +169 B 🔴 +108 B 🔴 +111 B

Status: 24 added / 24 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-BWXqaV4D.js (new) 3.54 kB 🔴 +3.54 kB 🔴 +1.24 kB 🔴 +1.06 kB
assets/auth-DGPzQ3qM.js (removed) 3.54 kB 🟢 -3.54 kB 🟢 -1.24 kB 🟢 -1.06 kB
assets/firebaseAuthStore-BGz-rEI3.js (new) 217 B 🔴 +217 B 🔴 +136 B 🔴 +118 B
assets/firebaseAuthStore-C_I2ZZHn.js (removed) 217 B 🟢 -217 B 🟢 -136 B 🟢 -116 B
assets/auth-C1OM1spT.js (removed) 178 B 🟢 -178 B 🟢 -142 B 🟢 -127 B
assets/auth-DyjdQrYa.js (new) 178 B 🔴 +178 B 🔴 +142 B 🔴 +130 B

Status: 3 added / 3 removed

Editors & Dialogs — 2.86 kB (baseline 2.83 kB) • 🔴 +24 B

Modals, dialogs, drawers, and in-app editors

File Before After Δ Raw Δ Gzip Δ Brotli
assets/useSubscriptionDialog-BCcJVDmj.js (new) 2.68 kB 🔴 +2.68 kB 🔴 +1.27 kB 🔴 +1.12 kB
assets/useSubscriptionDialog-BWY8z7xL.js (removed) 2.65 kB 🟢 -2.65 kB 🟢 -1.25 kB 🟢 -1.11 kB
assets/useSubscriptionDialog-BSyy49ty.js (new) 179 B 🔴 +179 B 🔴 +110 B 🔴 +98 B
assets/useSubscriptionDialog-eTAB4-ih.js (removed) 179 B 🟢 -179 B 🟢 -110 B 🟢 -97 B

Status: 2 added / 2 removed

UI Components — 33.7 kB (baseline 33.7 kB) • 🔴 +2 B

Reusable component library chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/ComfyQueueButton-B9iEIRT5.js (new) 9.52 kB 🔴 +9.52 kB 🔴 +2.69 kB 🔴 +2.42 kB
assets/ComfyQueueButton-CZ-EZI_2.js (removed) 9.52 kB 🟢 -9.52 kB 🟢 -2.69 kB 🟢 -2.43 kB
assets/TopbarBadge-CQOyP9e6.js (new) 8.36 kB 🔴 +8.36 kB 🔴 +1.97 kB 🔴 +1.76 kB
assets/TopbarBadge-DHZYSmi1.js (removed) 8.36 kB 🟢 -8.36 kB 🟢 -1.98 kB 🟢 -1.77 kB
assets/SubscribeButton-BnJPzbRA.js (new) 4.63 kB 🔴 +4.63 kB 🔴 +1.57 kB 🔴 +1.39 kB
assets/SubscribeButton-CplyUOkr.js (removed) 4.63 kB 🟢 -4.63 kB 🟢 -1.57 kB 🟢 -1.39 kB
assets/Button-B9mYP1x0.js (removed) 3.82 kB 🟢 -3.82 kB 🟢 -1.39 kB 🟢 -1.23 kB
assets/Button-hAiu8SbW.js (new) 3.82 kB 🔴 +3.82 kB 🔴 +1.38 kB 🔴 +1.23 kB
assets/WidgetButton-B3A83HE9.js (new) 2.41 kB 🔴 +2.41 kB 🔴 +982 B 🔴 +891 B
assets/WidgetButton-BFtcBv-z.js (removed) 2.41 kB 🟢 -2.41 kB 🟢 -980 B 🟢 -885 B
assets/CloudBadge-BEFjYgmd.js (new) 1.85 kB 🔴 +1.85 kB 🔴 +719 B 🔴 +643 B
assets/CloudBadge-DWHNRPHI.js (removed) 1.85 kB 🟢 -1.85 kB 🟢 -723 B 🟢 -648 B
assets/UserAvatar-CIuPULbC.js (removed) 1.73 kB 🟢 -1.73 kB 🟢 -726 B 🟢 -637 B
assets/UserAvatar-CndbQENT.js (new) 1.73 kB 🔴 +1.73 kB 🔴 +725 B 🔴 +635 B
assets/cloudFeedbackTopbarButton-B_53HtQJ.js (new) 1.24 kB 🔴 +1.24 kB 🔴 +678 B 🔴 +574 B
assets/cloudFeedbackTopbarButton-B8M_wweO.js (removed) 1.24 kB 🟢 -1.24 kB 🟢 -675 B 🟢 -578 B
assets/ComfyQueueButton-CKTPbvY3.js (new) 181 B 🔴 +181 B 🔴 +118 B 🔴 +115 B
assets/ComfyQueueButton-DEu6ovjP.js (removed) 181 B 🟢 -181 B 🟢 -118 B 🟢 -112 B

Status: 9 added / 9 removed

Data & Services — 2.7 MB (baseline 3.19 MB) • 🟢 -492 kB

Stores, services, APIs, and repositories

File Before After Δ Raw Δ Gzip Δ Brotli
assets/dialogService-CVmjDkKG.js (new) 2 MB 🔴 +2 MB 🔴 +424 kB 🔴 +323 kB
assets/dialogService-Cv-Ao3ol.js (removed) 2 MB 🟢 -2 MB 🟢 -423 kB 🟢 -323 kB
assets/api-C4kluqLB.js (removed) 1.17 MB 🟢 -1.17 MB 🟢 -244 kB 🟢 -189 kB
assets/api-DMC-pR6e.js (new) 672 kB 🔴 +672 kB 🔴 +148 kB 🔴 +118 kB
assets/releaseStore-CAau93PM.js (removed) 8.91 kB 🟢 -8.91 kB 🟢 -2.4 kB 🟢 -2.12 kB
assets/releaseStore-x_ZJiDkN.js (new) 8.91 kB 🔴 +8.91 kB 🔴 +2.4 kB 🔴 +2.12 kB
assets/keybindingService-hlELq80E.js (removed) 6.78 kB 🟢 -6.78 kB 🟢 -1.74 kB 🟢 -1.52 kB
assets/keybindingService-nxx144co.js (new) 6.78 kB 🔴 +6.78 kB 🔴 +1.74 kB 🔴 +1.51 kB
assets/serverConfigStore-B2LzN8g1.js (removed) 2.64 kB 🟢 -2.64 kB 🟢 -879 B 🟢 -778 B
assets/serverConfigStore-rKMIA1W-.js (new) 2.64 kB 🔴 +2.64 kB 🔴 +877 B 🔴 +778 B
assets/bootstrapStore-jt5qjpTm.js (new) 2.48 kB 🔴 +2.48 kB 🔴 +963 B 🔴 +887 B
assets/userStore-BPZD4dCU.js (removed) 2.16 kB 🟢 -2.16 kB 🟢 -814 B 🟢 -724 B
assets/userStore-DXkoKP63.js (new) 2.16 kB 🔴 +2.16 kB 🔴 +811 B 🔴 +725 B
assets/audioService-C2dTJzkh.js (removed) 2.03 kB 🟢 -2.03 kB 🟢 -931 B 🟢 -822 B
assets/audioService-rQJ47lwN.js (new) 2.03 kB 🔴 +2.03 kB 🔴 +930 B 🔴 +810 B
assets/teamWorkspaceStore-ClxFGi8d.js (new) 165 B 🔴 +165 B 🔴 +123 B 🔴 +107 B
assets/teamWorkspaceStore-CPW-4azI.js (removed) 165 B 🟢 -165 B 🟢 -123 B 🟢 -108 B
assets/releaseStore-CIvrjVhW.js (removed) 140 B 🟢 -140 B 🟢 -106 B 🟢 -106 B
assets/releaseStore-DpAOn3aL.js (new) 140 B 🔴 +140 B 🔴 +106 B 🔴 +105 B

Status: 10 added / 9 removed

Utilities & Hooks — 25.2 kB (baseline 25.2 kB) • 🔴 +74 B

Helpers, composables, and utility bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/colorUtil-8brfHtOx.js (removed) 7.2 kB 🟢 -7.2 kB 🟢 -2.22 kB 🟢 -1.96 kB
assets/colorUtil-D7p0CfP9.js (new) 7.2 kB 🔴 +7.2 kB 🔴 +2.22 kB 🔴 +1.96 kB
assets/useErrorHandling-6x9MmC6-.js (new) 5.12 kB 🔴 +5.12 kB 🔴 +1.51 kB 🔴 +1.32 kB
assets/useErrorHandling-CHz5Ype7.js (removed) 5.08 kB 🟢 -5.08 kB 🟢 -1.5 kB 🟢 -1.3 kB
assets/useWorkspaceUI-B8y7Gkck.js (new) 3.42 kB 🔴 +3.42 kB 🔴 +974 B 🔴 +835 B
assets/useWorkspaceUI-D-BA4WXF.js (removed) 3.42 kB 🟢 -3.42 kB 🟢 -974 B 🟢 -843 B
assets/useSubscriptionActions-CgU6nuqr.js (new) 2.22 kB 🔴 +2.22 kB 🔴 +867 B 🔴 +762 B
assets/useSubscriptionActions-Dw9dBXqr.js (removed) 2.22 kB 🟢 -2.22 kB 🟢 -868 B 🟢 -760 B
assets/subscriptionCheckoutUtil-KAEvLLzz.js (new) 2.03 kB 🔴 +2.03 kB 🔴 +874 B 🔴 +769 B
assets/subscriptionCheckoutUtil-gUv5S-SX.js (removed) 2 kB 🟢 -2 kB 🟢 -862 B 🟢 -751 B
assets/markdownRendererUtil-DA-MRGt6.js (new) 1.78 kB 🔴 +1.78 kB 🔴 +884 B 🔴 +774 B
assets/markdownRendererUtil-DBMaRy6q.js (removed) 1.78 kB 🟢 -1.78 kB 🟢 -886 B 🟢 -773 B
assets/useSubscriptionCredits-Bb2RN7mh.js (removed) 1.39 kB 🟢 -1.39 kB 🟢 -597 B 🟢 -530 B
assets/useSubscriptionCredits-gxaUWNBY.js (new) 1.39 kB 🔴 +1.39 kB 🔴 +597 B 🔴 +532 B
assets/audioUtils-CEaPXanL.js (removed) 970 B 🟢 -970 B 🟢 -546 B 🟢 -457 B
assets/audioUtils-CThmjSDs.js (new) 970 B 🔴 +970 B 🔴 +547 B 🔴 +482 B
assets/tailwindUtil-DUjvWRx4.js (new) 488 B 🔴 +488 B 🔴 +293 B 🔴 +265 B
assets/tailwindUtil-Hy0jY5OA.js (removed) 488 B 🟢 -488 B 🟢 -298 B 🟢 -267 B
assets/_plugin-vue_export-helper-DLRTaeJK.js (removed) 467 B 🟢 -467 B 🟢 -270 B 🟢 -243 B
assets/_plugin-vue_export-helper-DuK_Fly3.js (new) 467 B 🔴 +467 B 🔴 +270 B 🔴 +243 B
assets/useCurrentUser-BpX8Cb_R.js (removed) 145 B 🟢 -145 B 🟢 -114 B 🟢 -102 B
assets/useCurrentUser-D457Xgdr.js (new) 145 B 🔴 +145 B 🔴 +114 B 🔴 +101 B

Status: 11 added / 11 removed

Vendor & Third-Party — 10.7 MB (baseline 10.7 MB) • 🔴 +4.19 kB

External libraries and shared vendor chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/vendor-other-BXkWx9kc.js (new) 4.1 MB 🔴 +4.1 MB 🔴 +869 kB 🔴 +674 kB
assets/vendor-other-Dk4vQph5.js (removed) 4.1 MB 🟢 -4.1 MB 🟢 -867 kB 🟢 -673 kB
assets/vendor-primevue-BK91gQps.js (removed) 3.04 MB 🟢 -3.04 MB 🟢 -560 kB 🟢 -329 kB
assets/vendor-primevue-bkmKwsUf.js (new) 3.04 MB 🔴 +3.04 MB 🔴 +560 kB 🔴 +329 kB
assets/vendor-three-BeIVXtul.js (new) 1.83 MB 🔴 +1.83 MB 🔴 +391 kB 🔴 +283 kB
assets/vendor-three-BKpliY5_.js (removed) 1.83 MB 🟢 -1.83 MB 🟢 -391 kB 🟢 -283 kB
assets/vendor-tiptap-BFRBT3RT.js (removed) 650 kB 🟢 -650 kB 🟢 -152 kB 🟢 -122 kB
assets/vendor-tiptap-DdP0ccEc.js (new) 650 kB 🔴 +650 kB 🔴 +152 kB 🔴 +122 kB
assets/vendor-chart-BD4LLnJB.js (new) 408 kB 🔴 +408 kB 🔴 +98.6 kB 🔴 +80.6 kB
assets/vendor-chart-DdBDBwvF.js (removed) 408 kB 🟢 -408 kB 🟢 -98.6 kB 🟢 -80.6 kB
assets/vendor-xterm-Ce2gRtuj.js (new) 398 kB 🔴 +398 kB 🔴 +79.3 kB 🔴 +63.5 kB
assets/vendor-xterm-PDw3y6Aq.js (removed) 398 kB 🟢 -398 kB 🟢 -79.3 kB 🟢 -63.5 kB
assets/vendor-reka-ui-Bh_PdEOO.js (removed) 256 kB 🟢 -256 kB 🟢 -50.6 kB 🟢 -42.1 kB
assets/vendor-reka-ui-DCUHeuwM.js (new) 256 kB 🔴 +256 kB 🔴 +50.6 kB 🔴 +42.1 kB
assets/vendor-vue-BiXzLAAm.js (new) 13.6 kB 🔴 +13.6 kB 🔴 +4.38 kB 🔴 +3.92 kB
assets/vendor-vue-DMjbEcx7.js (removed) 13.6 kB 🟢 -13.6 kB 🟢 -4.38 kB 🟢 -3.92 kB

Status: 8 added / 8 removed

Other — 7.04 MB (baseline 6.55 MB) • 🔴 +496 kB

Bundles that do not match a named category

File Before After Δ Raw Δ Gzip Δ Brotli
assets/i18n-BW6XFQ8M.js (new) 495 kB 🔴 +495 kB 🔴 +95.7 kB 🔴 +71.2 kB
assets/nodeDefs-Bg1UEeRw.js (new) 448 kB 🔴 +448 kB 🔴 +69.9 kB 🔴 +45.2 kB
assets/nodeDefs-C3-BImCp.js (removed) 448 kB 🟢 -448 kB 🟢 -69.9 kB 🟢 -45.2 kB
assets/nodeDefs-B68z80AD.js (new) 413 kB 🔴 +413 kB 🔴 +63.4 kB 🔴 +41.8 kB
assets/nodeDefs-ChGhVGtO.js (removed) 413 kB 🟢 -413 kB 🟢 -63.4 kB 🟢 -41.8 kB
assets/nodeDefs-75iqoHK1.js (removed) 412 kB 🟢 -412 kB 🟢 -65.4 kB 🟢 -43.1 kB
assets/nodeDefs-qCfy7PeV.js (new) 412 kB 🔴 +412 kB 🔴 +65.4 kB 🔴 +43.1 kB
assets/nodeDefs-BgIXRnZk.js (removed) 383 kB 🟢 -383 kB 🟢 -63.8 kB 🟢 -41.6 kB
assets/nodeDefs-DxR-7ogK.js (new) 383 kB 🔴 +383 kB 🔴 +63.8 kB 🔴 +41.6 kB
assets/nodeDefs-CeaH9-p6.js (removed) 373 kB 🟢 -373 kB 🟢 -62.5 kB 🟢 -41.3 kB
assets/nodeDefs-CinCueZ7.js (new) 373 kB 🔴 +373 kB 🔴 +62.5 kB 🔴 +41.2 kB
assets/nodeDefs-ClsEmImE.js (removed) 369 kB 🟢 -369 kB 🟢 -60.9 kB 🟢 -41.7 kB
assets/nodeDefs-xDY-sSQw.js (new) 369 kB 🔴 +369 kB 🔴 +60.9 kB 🔴 +41.7 kB
assets/nodeDefs-CUgTHcSh.js (removed) 369 kB 🟢 -369 kB 🟢 -62.2 kB 🟢 -42.6 kB
assets/nodeDefs-DKHHBXVW.js (new) 369 kB 🔴 +369 kB 🔴 +62.2 kB 🔴 +42.6 kB
assets/nodeDefs-CCnfIwZD.js (removed) 366 kB 🟢 -366 kB 🟢 -59.8 kB 🟢 -41 kB
assets/nodeDefs-DgzjkU5p.js (new) 366 kB 🔴 +366 kB 🔴 +59.8 kB 🔴 +41 kB
assets/nodeDefs-B0UaQKt6.js (new) 363 kB 🔴 +363 kB 🔴 +59 kB 🔴 +40.3 kB
assets/nodeDefs-DaayC8qD.js (removed) 363 kB 🟢 -363 kB 🟢 -59 kB 🟢 -40.3 kB
assets/nodeDefs-BkQR1m9D.js (removed) 342 kB 🟢 -342 kB 🟢 -61.2 kB 🟢 -40.3 kB
assets/nodeDefs-Dn1Haq99.js (new) 342 kB 🔴 +342 kB 🔴 +61.2 kB 🔴 +40.3 kB
assets/nodeDefs-CC3d1IX6.js (removed) 339 kB 🟢 -339 kB 🟢 -60.2 kB 🟢 -39 kB
assets/nodeDefs-CicFSATk.js (new) 339 kB 🔴 +339 kB 🔴 +60.2 kB 🔴 +39 kB
assets/core-BP-fPALf.js (removed) 180 kB 🟢 -180 kB 🟢 -43.3 kB 🟢 -36.2 kB
assets/core-DymTviOU.js (new) 180 kB 🔴 +180 kB 🔴 +43.3 kB 🔴 +36.2 kB
assets/main-d4ZcTV7L.js (removed) 172 kB 🟢 -172 kB 🟢 -45.5 kB 🟢 -36.1 kB
assets/main-DVGct6t3.js (new) 172 kB 🔴 +172 kB 🔴 +45.5 kB 🔴 +36 kB
assets/main-mdvCJJpq.js (new) 154 kB 🔴 +154 kB 🔴 +41 kB 🔴 +33.1 kB
assets/main-sT768wiI.js (removed) 154 kB 🟢 -154 kB 🟢 -41 kB 🟢 -33.2 kB
assets/main-Do-oawDh.js (new) 150 kB 🔴 +150 kB 🔴 +41.1 kB 🔴 +32.8 kB
assets/main-oCqMFbo3.js (removed) 150 kB 🟢 -150 kB 🟢 -41.1 kB 🟢 -32.8 kB
assets/main-akhLOzys.js (removed) 143 kB 🟢 -143 kB 🟢 -40.9 kB 🟢 -32.7 kB
assets/main-DpM2tcEq.js (new) 143 kB 🔴 +143 kB 🔴 +40.9 kB 🔴 +32.7 kB
assets/main-Cu50a8UC.js (removed) 132 kB 🟢 -132 kB 🟢 -39.6 kB 🟢 -33.2 kB
assets/main-DcPG2fUX.js (new) 132 kB 🔴 +132 kB 🔴 +39.6 kB 🔴 +33.2 kB
assets/main-B-fN60cC.js (new) 129 kB 🔴 +129 kB 🔴 +38.9 kB 🔴 +31.4 kB
assets/main-DvfWsSBh.js (removed) 129 kB 🟢 -129 kB 🟢 -38.9 kB 🟢 -31.4 kB
assets/main-DQY0Poqn.js (new) 128 kB 🔴 +128 kB 🔴 +38.4 kB 🔴 +31.8 kB
assets/main-RPBRc45Y.js (removed) 128 kB 🟢 -128 kB 🟢 -38.4 kB 🟢 -31.8 kB
assets/main-Dyymoku4.js (removed) 125 kB 🟢 -125 kB 🟢 -38.6 kB 🟢 -32.3 kB
assets/main-Fbu5slCi.js (new) 125 kB 🔴 +125 kB 🔴 +38.6 kB 🔴 +32.3 kB
assets/main-_Vi60AGa.js (new) 125 kB 🔴 +125 kB 🔴 +38 kB 🔴 +31.9 kB
assets/main-DhCVcHpP.js (removed) 125 kB 🟢 -125 kB 🟢 -38 kB 🟢 -31.9 kB
assets/main-3xQXroMq.js (new) 112 kB 🔴 +112 kB 🔴 +38.1 kB 🔴 +30.3 kB
assets/main-rcgwfJJa.js (removed) 112 kB 🟢 -112 kB 🟢 -38.1 kB 🟢 -30.3 kB
assets/main-B7nu0wu4.js (new) 111 kB 🔴 +111 kB 🔴 +38.1 kB 🔴 +30 kB
assets/main-BAD0AZuf.js (removed) 111 kB 🟢 -111 kB 🟢 -38.1 kB 🟢 -30.1 kB
assets/WidgetSelect-Dbc6ZmXo.js (new) 51 kB 🔴 +51 kB 🔴 +11.2 kB 🔴 +9.81 kB
assets/WidgetSelect-unofi1zO.js (removed) 51 kB 🟢 -51 kB 🟢 -11.2 kB 🟢 -9.79 kB
assets/Load3DControls-DTLh-C3q.js (new) 35.9 kB 🔴 +35.9 kB 🔴 +5.87 kB 🔴 +5.08 kB
assets/Load3DControls-DxWEPuGD.js (removed) 35.9 kB 🟢 -35.9 kB 🟢 -5.87 kB 🟢 -5.08 kB
assets/SubscriptionRequiredDialogContent-DfhStq3M.js (new) 28.7 kB 🔴 +28.7 kB 🔴 +6.79 kB 🔴 +5.93 kB
assets/SubscriptionRequiredDialogContent-DM6QbCXs.js (removed) 28.7 kB 🟢 -28.7 kB 🟢 -6.78 kB 🟢 -5.92 kB
assets/CurrentUserPopoverWorkspace-CG01qq1d.js (new) 22.2 kB 🔴 +22.2 kB 🔴 +5 kB 🔴 +4.43 kB
assets/CurrentUserPopoverWorkspace-Fd_vlGrK.js (removed) 22.2 kB 🟢 -22.2 kB 🟢 -5 kB 🟢 -4.43 kB
assets/Load3D-C_LiSE2H.js (new) 20.9 kB 🔴 +20.9 kB 🔴 +4.59 kB 🔴 +4.01 kB
assets/Load3D-_Bv8_C79.js (removed) 20.9 kB 🟢 -20.9 kB 🟢 -4.59 kB 🟢 -4.01 kB
assets/commands-Dmj47WTl.js (removed) 20.6 kB 🟢 -20.6 kB 🟢 -3.96 kB 🟢 -3.07 kB
assets/commands-DXauvccL.js (new) 20.6 kB 🔴 +20.6 kB 🔴 +3.96 kB 🔴 +3.09 kB
assets/commands-BC_Q8we6.js (removed) 19.3 kB 🟢 -19.3 kB 🟢 -3.68 kB 🟢 -2.83 kB
assets/commands-C6piRza5.js (new) 19.3 kB 🔴 +19.3 kB 🔴 +3.68 kB 🔴 +2.87 kB
assets/commands-CuidUnsD.js (removed) 19.3 kB 🟢 -19.3 kB 🟢 -3.69 kB 🟢 -2.9 kB
assets/commands-D1595tOr.js (new) 19.3 kB 🔴 +19.3 kB 🔴 +3.69 kB 🔴 +2.9 kB
assets/commands-B52_zgXW.js (removed) 18.8 kB 🟢 -18.8 kB 🟢 -3.79 kB 🟢 -2.93 kB
assets/commands-Cf8Zq1td.js (new) 18.8 kB 🔴 +18.8 kB 🔴 +3.79 kB 🔴 +2.93 kB
assets/commands-BEw5ErI4.js (new) 18.5 kB 🔴 +18.5 kB 🔴 +3.52 kB 🔴 +2.92 kB
assets/commands-D5OfZ3bv.js (removed) 18.5 kB 🟢 -18.5 kB 🟢 -3.52 kB 🟢 -2.91 kB
assets/WidgetRecordAudio-9Rni2BZ9.js (new) 18.3 kB 🔴 +18.3 kB 🔴 +4.97 kB 🔴 +4.44 kB
assets/WidgetInputNumber-D8tX6K9a.js (new) 18.3 kB 🔴 +18.3 kB 🔴 +4.51 kB 🔴 +4.02 kB
assets/WidgetInputNumber-rTVc86e_.js (removed) 18.3 kB 🟢 -18.3 kB 🟢 -4.51 kB 🟢 -4.02 kB
assets/WidgetRecordAudio-BxsjpLOP.js (removed) 18.2 kB 🟢 -18.2 kB 🟢 -4.96 kB 🟢 -4.43 kB
assets/SubscriptionPanelContentWorkspace-BQ6Wb-NQ.js (removed) 18.2 kB 🟢 -18.2 kB 🟢 -4.47 kB 🟢 -3.91 kB
assets/SubscriptionPanelContentWorkspace-CXRe6jTy.js (new) 18.2 kB 🔴 +18.2 kB 🔴 +4.47 kB 🔴 +3.89 kB
assets/commands-MVcGSIbM.js (removed) 18 kB 🟢 -18 kB 🟢 -3.51 kB 🟢 -2.9 kB
assets/commands-P5QCEfZc.js (new) 18 kB 🔴 +18 kB 🔴 +3.51 kB 🔴 +2.88 kB
assets/commands-CiziP3Xs.js (new) 18 kB 🔴 +18 kB 🔴 +3.39 kB 🔴 +2.78 kB
assets/commands-K3soE7da.js (removed) 18 kB 🟢 -18 kB 🟢 -3.4 kB 🟢 -2.78 kB
assets/commands-BGeHkplA.js (new) 17.9 kB 🔴 +17.9 kB 🔴 +3.35 kB 🔴 +2.77 kB
assets/commands-CgVf6wUK.js (removed) 17.9 kB 🟢 -17.9 kB 🟢 -3.36 kB 🟢 -2.77 kB
assets/commands-BZlNQPg2.js (removed) 17.8 kB 🟢 -17.8 kB 🟢 -3.65 kB 🟢 -2.84 kB
assets/commands-C_Y3D6Cn.js (new) 17.8 kB 🔴 +17.8 kB 🔴 +3.65 kB 🔴 +2.84 kB
assets/commands-BV0l36Iz.js (new) 17.2 kB 🔴 +17.2 kB 🔴 +3.57 kB 🔴 +2.73 kB
assets/commands-DUK2nLuH.js (removed) 17.2 kB 🟢 -17.2 kB 🟢 -3.57 kB 🟢 -2.73 kB
assets/WidgetImageCrop-C-YElMXh.js (removed) 17.1 kB 🟢 -17.1 kB 🟢 -4.14 kB 🟢 -3.63 kB
assets/WidgetImageCrop-pI9a9ASD.js (new) 17.1 kB 🔴 +17.1 kB 🔴 +4.14 kB 🔴 +3.62 kB
assets/commands-27PChCGl.js (removed) 17 kB 🟢 -17 kB 🟢 -3.54 kB 🟢 -2.64 kB
assets/commands-WbYP_D61.js (new) 17 kB 🔴 +17 kB 🔴 +3.54 kB 🔴 +2.64 kB
assets/PanelTemplate-CmZV1Xsu.js (new) 16.2 kB 🔴 +16.2 kB 🔴 +5.46 kB 🔴 +4.8 kB
assets/PanelTemplate-XqkCNxJ4.js (removed) 16.2 kB 🟢 -16.2 kB 🟢 -5.45 kB 🟢 -4.79 kB
assets/LazyImage-IwnwT4xo.js (new) 14.1 kB 🔴 +14.1 kB 🔴 +4 kB 🔴 +3.54 kB
assets/LazyImage-rWQpxwnM.js (removed) 14.1 kB 🟢 -14.1 kB 🟢 -4 kB 🟢 -3.54 kB
assets/AudioPreviewPlayer-Be-oG_tg.js (new) 10.8 kB 🔴 +10.8 kB 🔴 +2.97 kB 🔴 +2.65 kB
assets/AudioPreviewPlayer-GF2k-UuD.js (removed) 10.8 kB 🟢 -10.8 kB 🟢 -2.97 kB 🟢 -2.65 kB
assets/InviteMemberDialogContent-DDVIiF-v.js (removed) 8.36 kB 🟢 -8.36 kB 🟢 -2.5 kB 🟢 -2.17 kB
assets/InviteMemberDialogContent-MaN_341n.js (new) 8.36 kB 🔴 +8.36 kB 🔴 +2.5 kB 🔴 +2.17 kB
assets/WidgetWithControl-DVDiP-dG.js (new) 8.04 kB 🔴 +8.04 kB 🔴 +2.66 kB 🔴 +2.39 kB
assets/WidgetWithControl-D4qilL5P.js (removed) 8.02 kB 🟢 -8.02 kB 🟢 -2.65 kB 🟢 -2.38 kB
assets/CreateWorkspaceDialogContent-BvDRVJsb.js (removed) 5.93 kB 🟢 -5.93 kB 🟢 -1.93 kB 🟢 -1.68 kB
assets/CreateWorkspaceDialogContent-DDiVeDqv.js (new) 5.93 kB 🔴 +5.93 kB 🔴 +1.93 kB 🔴 +1.68 kB
assets/EditWorkspaceDialogContent-BAK7VRyb.js (new) 5.7 kB 🔴 +5.7 kB 🔴 +1.88 kB 🔴 +1.65 kB
assets/EditWorkspaceDialogContent-CZtMaIFc.js (removed) 5.7 kB 🟢 -5.7 kB 🟢 -1.88 kB 🟢 -1.64 kB
assets/ValueControlPopover-C5dJx3eD.js (new) 5.17 kB 🔴 +5.17 kB 🔴 +1.69 kB 🔴 +1.5 kB
assets/ValueControlPopover-Dykk_Rt1.js (removed) 5.17 kB 🟢 -5.17 kB 🟢 -1.69 kB 🟢 -1.5 kB
assets/WidgetBoundingBox-CgNPbPqq.js (removed) 4.71 kB 🟢 -4.71 kB 🟢 -1.13 kB 🟢 -1.02 kB
assets/WidgetBoundingBox-DClY9LmH.js (new) 4.71 kB 🔴 +4.71 kB 🔴 +1.13 kB 🔴 +1.01 kB
assets/DeleteWorkspaceDialogContent-C2cfHJun.js (new) 4.59 kB 🔴 +4.59 kB 🔴 +1.56 kB 🔴 +1.35 kB
assets/DeleteWorkspaceDialogContent-DOdlCe3Z.js (removed) 4.59 kB 🟢 -4.59 kB 🟢 -1.56 kB 🟢 -1.35 kB
assets/WidgetGalleria-BLlLOmBF.js (new) 4.57 kB 🔴 +4.57 kB 🔴 +1.57 kB 🔴 +1.42 kB
assets/WidgetGalleria-f72WaoQY.js (removed) 4.57 kB 🟢 -4.57 kB 🟢 -1.57 kB 🟢 -1.42 kB
assets/LeaveWorkspaceDialogContent-Cfri96Vc.js (removed) 4.41 kB 🟢 -4.41 kB 🟢 -1.5 kB 🟢 -1.3 kB
assets/LeaveWorkspaceDialogContent-ChB3NhTv.js (new) 4.41 kB 🔴 +4.41 kB 🔴 +1.5 kB 🔴 +1.31 kB
assets/RemoveMemberDialogContent-Bu_wwy8Q.js (removed) 4.38 kB 🟢 -4.38 kB 🟢 -1.45 kB 🟢 -1.26 kB
assets/RemoveMemberDialogContent-XKqeogg2.js (new) 4.38 kB 🔴 +4.38 kB 🔴 +1.45 kB 🔴 +1.26 kB
assets/RevokeInviteDialogContent-BgdBcdtX.js (removed) 4.29 kB 🟢 -4.29 kB 🟢 -1.47 kB 🟢 -1.29 kB
assets/RevokeInviteDialogContent-DhvIi1uv.js (new) 4.29 kB 🔴 +4.29 kB 🔴 +1.47 kB 🔴 +1.29 kB
assets/Slider-BAEfKuro.js (removed) 4.21 kB 🟢 -4.21 kB 🟢 -1.52 kB 🟢 -1.34 kB
assets/Slider-DzLWdCCy.js (new) 4.21 kB 🔴 +4.21 kB 🔴 +1.52 kB 🔴 +1.34 kB
assets/WidgetImageCompare-CsU_f4OX.js (new) 3.79 kB 🔴 +3.79 kB 🔴 +1.28 kB 🔴 +1.12 kB
assets/WidgetImageCompare-Dd0p7l7V.js (removed) 3.79 kB 🟢 -3.79 kB 🟢 -1.28 kB 🟢 -1.12 kB
assets/WidgetColorPicker-DUps6Ysx.js (new) 3.71 kB 🔴 +3.71 kB 🔴 +1.38 kB 🔴 +1.25 kB
assets/WidgetColorPicker-x8L_rIAb.js (removed) 3.71 kB 🟢 -3.71 kB 🟢 -1.38 kB 🟢 -1.25 kB
assets/WidgetTextarea-B-qJz4nH.js (new) 3.52 kB 🔴 +3.52 kB 🔴 +1.33 kB 🔴 +1.17 kB
assets/WidgetTextarea-DwdEJ3mA.js (removed) 3.52 kB 🟢 -3.52 kB 🟢 -1.33 kB 🟢 -1.17 kB
assets/WidgetMarkdown-0wCpEh7b.js (new) 3.22 kB 🔴 +3.22 kB 🔴 +1.28 kB 🔴 +1.13 kB
assets/WidgetMarkdown-bP5F2-qx.js (removed) 3.22 kB 🟢 -3.22 kB 🟢 -1.28 kB 🟢 -1.13 kB
assets/WidgetToggleSwitch-BIK7gguT.js (removed) 3.08 kB 🟢 -3.08 kB 🟢 -1.19 kB 🟢 -1.06 kB
assets/WidgetToggleSwitch-BWZeDExo.js (new) 3.08 kB 🔴 +3.08 kB 🔴 +1.19 kB 🔴 +1.06 kB
assets/GlobalToast-CQC3PSVr.js (new) 3.05 kB 🔴 +3.05 kB 🔴 +1.1 kB 🔴 +937 B
assets/GlobalToast-x5Aleg_4.js (removed) 3.05 kB 🟢 -3.05 kB 🟢 -1.09 kB 🟢 -942 B
assets/SubscribeToRun-BPyuUoXg.js (removed) 2.96 kB 🟢 -2.96 kB 🟢 -1.15 kB 🟢 -1.04 kB
assets/SubscribeToRun-zD72J4nr.js (new) 2.96 kB 🔴 +2.96 kB 🔴 +1.15 kB 🔴 +1.04 kB
assets/cloudSessionCookie-BjT2vcls.js (removed) 2.94 kB 🟢 -2.94 kB 🟢 -933 B 🟢 -808 B
assets/cloudSessionCookie-DltfDkEY.js (new) 2.94 kB 🔴 +2.94 kB 🔴 +927 B 🔴 +800 B
assets/MediaVideoTop-WHbgZ4CI.js (new) 2.82 kB 🔴 +2.82 kB 🔴 +1.05 kB 🔴 +910 B
assets/MediaVideoTop-yhq80asg.js (removed) 2.82 kB 🟢 -2.82 kB 🟢 -1.05 kB 🟢 -910 B
assets/WidgetChart-3mC7A_va.js (removed) 2.79 kB 🟢 -2.79 kB 🟢 -1.06 kB 🟢 -962 B
assets/WidgetChart-c8c4iM6B.js (new) 2.79 kB 🔴 +2.79 kB 🔴 +1.06 kB 🔴 +971 B
assets/WidgetLayoutField-CZXFB71F.js (removed) 2.61 kB 🟢 -2.61 kB 🟢 -1.01 kB 🟢 -892 B
assets/WidgetLayoutField-JtfEFo3H.js (new) 2.61 kB 🔴 +2.61 kB 🔴 +1 kB 🔴 +893 B
assets/WidgetInputText-DOFSeOZG.js (removed) 2.58 kB 🟢 -2.58 kB 🟢 -1.01 kB 🟢 -912 B
assets/WidgetInputText-K05lnTiH.js (new) 2.58 kB 🔴 +2.58 kB 🔴 +1.01 kB 🔴 +909 B
assets/BaseViewTemplate-C4Vu5BMi.js (removed) 2.42 kB 🟢 -2.42 kB 🟢 -1.04 kB 🟢 -940 B
assets/BaseViewTemplate-CGsg6uKM.js (new) 2.42 kB 🔴 +2.42 kB 🔴 +1.04 kB 🔴 +938 B
assets/Media3DTop-8_T22Isd.js (removed) 2.38 kB 🟢 -2.38 kB 🟢 -1.02 kB 🟢 -876 B
assets/Media3DTop-CUbzOuTJ.js (new) 2.38 kB 🔴 +2.38 kB 🔴 +1.02 kB 🔴 +873 B
assets/MediaImageTop-1THG_DJM.js (removed) 2.34 kB 🟢 -2.34 kB 🟢 -1 kB 🟢 -869 B
assets/MediaImageTop-Djn8fGD3.js (new) 2.34 kB 🔴 +2.34 kB 🔴 +1 kB 🔴 +887 B
assets/MediaAudioTop-BYIydMOt.js (new) 2 kB 🔴 +2 kB 🔴 +882 B 🔴 +760 B
assets/MediaAudioTop-CBP8th-j.js (removed) 2 kB 🟢 -2 kB 🟢 -881 B 🟢 -759 B
assets/CloudRunButtonWrapper-Dq6qVmsk.js (new) 1.79 kB 🔴 +1.79 kB 🔴 +645 B 🔴 +563 B
assets/CloudRunButtonWrapper-r1XjwG70.js (removed) 1.79 kB 🟢 -1.79 kB 🟢 -644 B 🟢 -561 B
assets/auto-BmypP-XQ.js (removed) 1.73 kB 🟢 -1.73 kB 🟢 -636 B 🟢 -580 B
assets/auto-RHVQpwL9.js (new) 1.73 kB 🔴 +1.73 kB 🔴 +637 B 🔴 +565 B
assets/widgetPropFilter-DOe9Bb1I.js (removed) 1.31 kB 🟢 -1.31 kB 🟢 -568 B 🟢 -508 B
assets/widgetPropFilter-ERx8czR8.js (new) 1.31 kB 🔴 +1.31 kB 🔴 +569 B 🔴 +506 B
assets/cloudBadges-CeFxN0CI.js (new) 1.08 kB 🔴 +1.08 kB 🔴 +538 B 🔴 +481 B
assets/cloudBadges-j2IwjFNm.js (removed) 1.08 kB 🟢 -1.08 kB 🟢 -539 B 🟢 -504 B
assets/graphHasMissingNodes-BB8Cw-Nb.js (removed) 1.06 kB 🟢 -1.06 kB 🟢 -460 B 🟢 -421 B
assets/graphHasMissingNodes-BQuJwTW0.js (new) 1.06 kB 🔴 +1.06 kB 🔴 +462 B 🔴 +422 B
assets/cloudSubscription-BWdWrq-h.js (new) 976 B 🔴 +976 B 🔴 +459 B 🔴 +395 B
assets/cloudSubscription-Cc9ZvTLw.js (removed) 976 B 🟢 -976 B 🟢 -460 B 🟢 -401 B
assets/previousFullPath-B-XG7lU7.js (removed) 838 B 🟢 -838 B 🟢 -415 B 🟢 -346 B
assets/previousFullPath-CmezY7As.js (new) 838 B 🔴 +838 B 🔴 +414 B 🔴 +380 B
assets/nightlyBadges-DBeLMZjn.js (new) 595 B 🔴 +595 B 🔴 +358 B 🔴 +309 B
assets/nightlyBadges-CG9e-Pr-.js (removed) 594 B 🟢 -594 B 🟢 -356 B 🟢 -311 B
assets/widget-BJiJuR5i.js (new) 518 B 🔴 +518 B 🔴 +342 B 🔴 +290 B
assets/widget-CD3JnB1i.js (removed) 518 B 🟢 -518 B 🟢 -343 B 🟢 -289 B
assets/SubscriptionPanelContentWorkspace-Bunez9yk.js (removed) 266 B 🟢 -266 B 🟢 -136 B 🟢 -115 B
assets/SubscriptionPanelContentWorkspace-VmA37pmk.js (new) 266 B 🔴 +266 B 🔴 +136 B 🔴 +118 B
assets/i18n-C5SEP1UO.js (new) 188 B 🔴 +188 B 🔴 +152 B 🔴 +132 B
assets/WidgetBoundingBox-Bp7B7z1s.js (removed) 186 B 🟢 -186 B 🟢 -119 B 🟢 -114 B
assets/WidgetBoundingBox-BTNRImOa.js (new) 186 B 🔴 +186 B 🔴 +119 B 🔴 +114 B
assets/WidgetInputNumber-CbuD1S9c.js (new) 186 B 🔴 +186 B 🔴 +119 B 🔴 +110 B
assets/WidgetInputNumber-DxC6RxdT.js (removed) 186 B 🟢 -186 B 🟢 -119 B 🟢 -112 B
assets/WidgetLegacy-0xdckIag.js (new) 164 B 🔴 +164 B 🔴 +125 B 🔴 +107 B
assets/WidgetLegacy-DWAvmBBW.js (removed) 164 B 🟢 -164 B 🟢 -125 B 🟢 -111 B
assets/mixpanel.module-BGx3HLNV.js (new) 143 B 🔴 +143 B 🔴 +125 B 🔴 +111 B
assets/mixpanel.module-BiPjOPVW.js (removed) 143 B 🟢 -143 B 🟢 -125 B 🟢 -107 B
assets/Load3D-C4YsyTz4.js (new) 131 B 🔴 +131 B 🔴 +107 B 🔴 +117 B
assets/Load3D-D0KSk_Gf.js (removed) 131 B 🟢 -131 B 🟢 -107 B 🟢 -107 B
assets/OBJLoader2WorkerModule-DTMpvldF.js 109 kB 109 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/rolldown-runtime-cVp-94Rc.js 1.96 kB 1.96 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 91 added / 89 removed

@DrJKL DrJKL force-pushed the drjkl/first-things-first branch 2 times, most recently from 549f3f5 to 14a6a9a Compare January 25, 2026 08:43
DrJKL and others added 3 commits January 25, 2026 01:03
- Add useBootstrapStore to centralize early initialization (api.init, fetchNodeDefs)
- Move settings loading and custom nodes i18n loading to store bootstrap phase
- Use VueUse's `until` to coordinate async dependencies in GraphCanvas
- Load settings, i18n, and newUserService initialization in parallel where possible
- Add unit tests for bootstrapStore

Amp-Thread-ID: https://ampcode.com/threads/T-019bf48d-af90-738f-99ce-46309e4be688
Co-authored-by: Amp <amp@ampcode.com>
@DrJKL DrJKL force-pushed the drjkl/first-things-first branch from 14a6a9a to 326154f Compare January 25, 2026 09:51
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.

No multi layered DI containers and bootstrap.ts per distribution? 😭

- Replace manual keydown/keyup listeners with useMagicKeys for shiftDown

- Move app.extensionManager assignment to App.vue

- Remove init() wrapper function in GraphView.vue

Amp-Thread-ID: https://ampcode.com/threads/T-019bf90e-1cd0-71de-b23f-ea6cb0f99a87
Co-authored-by: Amp <amp@ampcode.com>
@DrJKL DrJKL changed the title perf: parallelize bootstrap and fix logout state bug refactor: parallelize bootstrap and simplify lifecycle with VueUse Jan 26, 2026
@DrJKL DrJKL force-pushed the drjkl/first-things-first branch from 39a7ecb to 3c0b227 Compare January 26, 2026 07:51
- Move useCopy, usePaste, useWorkflowAutoSave to top level

- Move locale change watcher outside onMounted with proper guard

- Move litegraph:set-graph event listener to top level

Amp-Thread-ID: https://ampcode.com/threads/T-019bf94d-b905-77ee-965d-a9c2a327dc2a
Co-authored-by: Amp <amp@ampcode.com>
@DrJKL DrJKL force-pushed the drjkl/first-things-first branch from 8cfa4bd to 80d58dd Compare January 26, 2026 07:58
@DrJKL DrJKL marked this pull request as ready for review January 26, 2026 17:31
@DrJKL DrJKL requested review from a team, Myestery and jtydhr88 as code owners January 26, 2026 17:31
@dosubot dosubot bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Jan 26, 2026
@DrJKL DrJKL requested a review from christian-byrne January 26, 2026 17:31
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: 5

Caution

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

⚠️ Outside diff range comments (2)
src/composables/node/useNodeBadge.ts (1)

73-85: Guard skips pricing watcher on remount.

If the composable remounts while the extension is already installed, the early return prevents the pricing watch from being re-registered, which can leave badges stale. Consider moving the guard after the pricing watch setup.

🔧 Suggested adjustment
-  onMounted(() => {
-    if (extensionStore.isExtensionInstalled('Comfy.NodeBadge')) return
-
-    // TODO: Fix the composables and watchers being setup in onMounted
-    const nodePricing = useNodePricing()
-
-    watch(
-      () => nodePricing.pricingRevision.value,
-      () => {
-        if (!showApiPricingBadge.value) return
-        app.canvas?.setDirty(true, true)
-      }
-    )
+  onMounted(() => {
+    // TODO: Fix the composables and watchers being setup in onMounted
+    const nodePricing = useNodePricing()
+
+    watch(
+      () => nodePricing.pricingRevision.value,
+      () => {
+        if (!showApiPricingBadge.value) return
+        app.canvas?.setDirty(true, true)
+      }
+    )
+
+    if (extensionStore.isExtensionInstalled('Comfy.NodeBadge')) return
src/views/GraphView.vue (1)

304-360: Close BroadcastChannel and dispose of runWhenGlobalIdle on unmount.

The BroadcastChannel created inside onGraphReady is never closed, causing a resource leak. Additionally, the runWhenGlobalIdle return value is never captured or disposed. If the component remounts (via route changes), stale idle tasks could execute. Capture the idle task disposable and channel reference, then clean them up in onBeforeUnmount.

🧹 One way to handle explicit cleanup
 const onGraphReady = () => {
-  runWhenGlobalIdle(() => {
+  const idleDisposable = runWhenGlobalIdle(() => {
     if (isCloud && telemetry) {
       const tabCountChannel = new BroadcastChannel('comfyui-tab-count')
       const activeTabs = new Map<string, number>()
       const currentTabId = crypto.randomUUID()

       // ... existing code ...

       tabCountChannel.postMessage({ type: 'heartbeat', tabId: currentTabId })
+
+      onBeforeUnmount(() => {
+        tabCountChannel.close()
+      })
     }
-  }, 1000)
+  }, 1000)
+
+  return { idleDisposable }
 }

 onBeforeUnmount(() => {
   executionStore.unbindExecutionEvents()
+  const { idleDisposable } = onGraphReady()
+  idleDisposable?.dispose()
 })

Better approach: store the idle disposable and channel reference as component-level variables and dispose them in onBeforeUnmount.

🤖 Fix all issues with AI agents
In `@src/components/graph/GraphCanvas.vue`:
- Around line 404-409: The second invocation of the composable
useVueFeatureFlags in GraphCanvas.vue is redundant (it was already called
earlier to compute shouldRenderVueNodes) and can create duplicate watchers;
remove the extra call from the bottom composable calls (the listed
useVueFeatureFlags() alongside
useGlobalLitegraph/useContextMenuTranslation/etc.) and ensure any
feature-flag-dependent logic continues to reference the single earlier return
value used for shouldRenderVueNodes so no other code relies on the removed
invocation.
- Around line 411-424: The watch handler for settingStore.get('Comfy.Locale')
must short-circuit when settings failed: check settingsError (and/or
isSettingsReady) after awaiting the initial until and if settingsError is truthy
return early (or call the existing Unauthorized handling) before proceeding to
await isI18nReady/i18nError, calling newUserService().initializeIfNewUser,
useCommandStore().execute('Comfy.RefreshNodeDefinitions'), or
useWorkflowService().reloadCurrentWorkflow; update the watcher logic around
isSettingsReady and settingsError to abort when settingsError is set to avoid
operating on invalid state.

In `@src/platform/settings/settingStore.ts`:
- Around line 172-177: When a duplicate registration is detected at the `if
(setting.id in settingsById.value)` check, update the stored SettingParams
instead of returning immediately so remounts that pass new callbacks/options
don't keep stale references; locate the block that references
`settingsById.value[setting.id]` and assign or merge the incoming `setting` (or
at minimum its callbacks/options) into the existing entry before returning
(e.g., replace or shallow-merge into `settingsById.value[setting.id]`) so the
store reflects the latest definition.

In `@src/stores/bootstrapStore.test.ts`:
- Around line 6-31: The test is missing a mock for the user store dependency,
causing startStoreBootstrap() (which awaits useUserStore().initialize() and
branches on needsLogin) to be flaky; add a vi.mock for the module that exports
useUserStore so the mocked useUserStore returns an object with initialize:
vi.fn().mockResolvedValue(undefined) and needsLogin explicitly set (e.g., false)
so startStoreBootstrap() behaves deterministically when invoking
useUserStore().initialize() and checking needsLogin.

In `@src/stores/bootstrapStore.ts`:
- Around line 61-78: The async workflow sync currently ignores errors;
destructure the error ref from the useAsyncState call (e.g., const { isReady:
isWorkflowsReady, isLoading: isWorkflowsLoading, execute: executeSyncWorkflows,
error: syncWorkflowsError } = useAsyncState(...)) and add syncWorkflowsError to
the bootstrap store's returned object so callers can observe failures from
syncWorkflows; keep the existing
isWorkflowsReady/isWorkflowsLoading/executeSyncWorkflows and syncWorkflows logic
unchanged.

@DrJKL DrJKL force-pushed the drjkl/first-things-first branch from c491857 to 35eb028 Compare January 27, 2026 00:48
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/platform/workflow/management/stores/workflowStore.ts`:
- Line 872: The exported WorkflowStore interface is missing the newly returned
loadWorkflows function; update the WorkflowStore interface to include a
loadWorkflows signature alongside syncWorkflows so the exposed store type
matches the actual returned store. Locate the WorkflowStore interface
declaration and add a loadWorkflows: (...) => ... signature consistent with the
existing syncWorkflows method (use the same parameter/return conventions as
syncWorkflows) and update any related type exports if necessary.

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: 3

🤖 Fix all issues with AI agents
In `@src/main.ts`:
- Around line 93-96: The code currently fire-and-forgets
bootstrapStore.startStoreBootstrap() which can swallow startup errors; change it
to await or explicitly handle rejections so the app only mounts after successful
bootstrap. Replace the void call with awaiting the promise (e.g., call
startStoreBootstrap() inside an async init function and await it before
app.mount('#vue-app')) or attach a .catch that logs the error and prevents
mounting (using useBootstrapStore and its startStoreBootstrap() result), and
ensure any lower-level failures like userStore.initialize() propagate so you can
abort mount on failure.

In `@src/stores/bootstrapStore.test.ts`:
- Around line 62-76: Add a test that mocks useUserStore to return needsLogin:
true so store.startStoreBootstrap() exercises the login-required branch; import
useUserStore, stub its initialize to resolve and set needsLogin: true via
vi.mocked(useUserStore).mockReturnValueOnce(...), then call
store.startStoreBootstrap() and assert that useSettingStore().isReady remains
false and that workflowStore.loadWorkflows was not invoked, while
store.isI18nReady still becomes true (use vi.waitFor to wait for i18n
readiness).

In `@src/stores/bootstrapStore.ts`:
- Around line 36-39: The sequential awaits for settingStore.load() and
workflowStore.loadWorkflows() inside the userStore.needsLogin check should be
parallelized: instead of awaiting them one after the other, start both calls and
await them together (e.g., with Promise.all) so settingStore.load and
workflowStore.loadWorkflows run concurrently; locate the block guarded by
userStore.needsLogin and replace the sequential awaits with a combined await to
run both promises in parallel while preserving existing error propagation.

@coderabbitai coderabbitai bot requested a review from PabloWiedemann January 27, 2026 01:53
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: 0

Caution

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

⚠️ Outside diff range comments (1)
browser_tests/tests/versionMismatchWarnings.spec.ts (1)

106-109: Consider using a more robust locator.

The .nth(3) index-based selector is fragile and could break silently if the DOM structure changes. Consider using a more specific selector like a data-testid attribute or a more targeted locator chain.

♻️ Suggested improvement
-    const warningToast = comfyPage.page
-      .locator('div')
-      .filter({ hasText: 'Version Compatibility' })
-      .nth(3)
+    const warningToast = comfyPage.page
+      .locator('[data-testid="version-mismatch-toast"]')
+      // Or use a more specific semantic locator:
+      // .getByRole('alert').filter({ hasText: 'Version Compatibility' })

This would require adding a data-testid to the toast component, but would make the test more resilient to UI refactoring.

@DrJKL DrJKL added the preview label Jan 27, 2026
@christian-byrne christian-byrne linked an issue Jan 27, 2026 that may be closed by this pull request
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: 3

🤖 Fix all issues with AI agents
In `@src/platform/settings/settingStore.ts`:
- Around line 263-266: Remove the exported async-state symbols from the public
API: stop exporting isReady, isLoading, and error from the setting store and
keep only load() as the public method; keep the variables (isReady, isLoading,
error) as internal/local bindings returned/used inside the store implementation
(e.g., within the same closure that defines useAsyncState in settingStore.ts) so
consumers only see and use load(), and update any internal references to those
symbols to use the now-internal bindings rather than exported names.
- Around line 74-78: The load() function currently returns undefined when
isLoading.value is true, breaking awaitability; change load() to cache the
in-flight Promise returned by loadSettingValues() (e.g. store it in a local
variable like pendingLoadPromise) and return that same Promise for any
concurrent calls while isLoading is true, and ensure the cached promise is
cleared (set to null) when the promise resolves or rejects; reference load(),
loadSettingValues(), isReady and isLoading to locate where to store, return, and
clear the pending promise so multiple callers properly await the same
initialization.

In `@src/stores/bootstrapStore.ts`:
- Around line 29-47: startStoreBootstrap only loads settingStore.load() and
workflowStore.loadWorkflows() when userStore.needsLogin is false at bootstrap,
so stores never initialize when the user logs in later; add a post-auth hook
that observes the needsLogin flag from useUserStore (or call from the login
flow) and triggers settingStore.load() and workflowStore.loadWorkflows() when
needsLogin transitions to false. Specifically, add a watcher / effect that
watches useUserStore().needsLogin (or use storeToRefs on the user store) and, on
change to false, calls settingStore.load() and workflowStore.loadWorkflows();
ensure this logic coexists with the existing bootstrap conditional in
startStoreBootstrap so loads occur either at bootstrap or after login.

Comment on lines +29 to +47
async function startStoreBootstrap() {
// Defer settings and workflows if multi-user login is required
// (settings API requires authentication in multi-user mode)
const userStore = useUserStore()
await userStore.initialize()

if (isCloud) {
const { isInitialized } = storeToRefs(useFirebaseAuthStore())
await until(isInitialized).toBe(true)
}

// i18n can load without authentication
void loadI18n()

if (!userStore.needsLogin) {
void settingStore.load()
void workflowStore.loadWorkflows()
}
}
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 | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# Find all usages of settingStore.load()
rg -n --type=ts --type=vue -C3 'settingStore\.load\(' src

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 97


🏁 Script executed:

# Find all usages of workflowStore.loadWorkflows()
rg -n --type=ts --type=vue -C3 'workflowStore\.loadWorkflows\(' src

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 97


🏁 Script executed:

# Look for post-login/auth initialization in user store and related flows
rg -n --type=ts -C5 'initialize\|logout\|needsLogin' src/stores

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 52


🏁 Script executed:

# Search for any watchers or effects on needsLogin in bootstrap or related files
rg -n --type=ts -C3 'needsLogin' src/stores/bootstrapStore.ts

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 266


🏁 Script executed:

# Check if there are any login flow handlers in userStore
fd -e ts src/stores | xargs rg -l 'login' | head -5

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 555


🏁 Script executed:

# Find all usages of settingStore.load() - corrected syntax
rg -n 'settingStore\.load\(' src --type ts

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 132


🏁 Script executed:

# Find all usages of workflowStore.loadWorkflows()
rg -n 'workflowStore\.loadWorkflows\(' src --type ts

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 142


🏁 Script executed:

# Check userStore for needsLogin and related logic
fd . src/stores -name "*userStore*" -o -name "*user*"

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 300


🏁 Script executed:

# Look at bootstrap file more carefully
cat -n src/stores/bootstrapStore.ts | head -60

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 2025


🏁 Script executed:

# Search for any watchers or effects on needsLogin in the stores
rg -n 'needsLogin' src/stores --type ts -B2 -A2

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 1185


🏁 Script executed:

# Check if login completion triggers anything
rg -n 'watch.*needsLogin\|watchEffect.*needsLogin' src --type ts

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 52


🏁 Script executed:

# Read the userStore to understand the complete implementation
cat -n src/stores/userStore.ts

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 3340


🏁 Script executed:

# Look for where currentUserId is set/updated
rg -n 'currentUserId' src/stores/userStore.ts -B2 -A2

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 1153


🏁 Script executed:

# Search for any side effects or watchers on currentUserId change
rg -n 'watch.*currentUserId\|effect.*currentUserId' src --type ts

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 52


🏁 Script executed:

# Check router.ts to see if login flow triggers any loads
rg -n 'settingStore\|workflowStore\|load' src/router.ts -B2 -A2

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 52


🏁 Script executed:

# Check app.ts for any post-login initialization
rg -n 'settingStore\|workflowStore\|needsLogin\|login' src/scripts/app.ts -B2 -A2

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 52


🏁 Script executed:

# Search for UserSelectView handling
rg -n 'settingStore\|workflowStore' src/views/UserSelectView.vue -B2 -A2

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 52


🏁 Script executed:

# Check if UserSelectView or login-related views manually trigger loads after login
fd . src/views -type f | xargs rg -l 'login\|settingStore\|workflowStore' --type ts

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 242


🏁 Script executed:

# Look at UserSelectView in detail to see what happens after login
cat src/views/UserSelectView.vue | head -100

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 2930


🏁 Script executed:

# Search the entire codebase for any effect/watch that responds to login completion
rg -n 'login.*then\|\.login\(' src --type ts -A5 | head -50

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 52


🏁 Script executed:

# Find where startStoreBootstrap is called
rg -n 'startStoreBootstrap' src --type ts -B2 -A2

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 1186


🏁 Script executed:

# Check main.ts or app initialization
fd . src -name "main.ts" -o -name "App.vue" | head -5

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 300


🏁 Script executed:

# Look at main.ts to see bootstrap flow
cat src/main.ts | head -80

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 2465


🏁 Script executed:

# Check if there's any router navigation guard or effect that re-triggers loads
rg -n 'beforeEach\|afterEach\|router\.' src/main.ts -A3 -B1

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 52


🏁 Script executed:

# Look for any component-level effects that check needsLogin
rg -n 'watch.*needsLogin' src --type ts

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 52


Implement post-auth hook to load deferred settings and workflows.

Settings and workflows are only loaded during initial bootstrap if login is not required. When a user logs in after bootstrap (making needsLogin false), there is no mechanism to trigger settingStore.load() and workflowStore.loadWorkflows(). Add a watcher or effect on needsLogin change, or trigger these loads in the login flow, to ensure stores are initialized after authentication completes.

🤖 Prompt for AI Agents
In `@src/stores/bootstrapStore.ts` around lines 29 - 47, startStoreBootstrap only
loads settingStore.load() and workflowStore.loadWorkflows() when
userStore.needsLogin is false at bootstrap, so stores never initialize when the
user logs in later; add a post-auth hook that observes the needsLogin flag from
useUserStore (or call from the login flow) and triggers settingStore.load() and
workflowStore.loadWorkflows() when needsLogin transitions to false.
Specifically, add a watcher / effect that watches useUserStore().needsLogin (or
use storeToRefs on the user store) and, on change to false, calls
settingStore.load() and workflowStore.loadWorkflows(); ensure this logic
coexists with the existing bootstrap conditional in startStoreBootstrap so loads
occur either at bootstrap or after login.

@DrJKL DrJKL assigned AustinMroz and christian-byrne and unassigned DrJKL Jan 27, 2026
- Return early if already loaded (isReady/isSyncReady)
- Use VueUse `until()` to await in-progress loading instead of returning undefined
- Ensures all callers properly wait for initialization to complete

Amp-Thread-ID: https://ampcode.com/threads/T-019bfdee-7166-76c3-8c5f-473717a9148b
Co-authored-by: Amp <amp@ampcode.com>
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/platform/settings/settingStore.ts`:
- Around line 74-83: The current load() can silently succeed for concurrent
callers because they await until(isLoading).toBe(false) then return even if
loadSettingValues() failed; change load() to track and await the actual
in-flight promise instead of just waiting for isLoading to flip: introduce (or
reuse) a loadPromise variable set when starting loadSettingValues() (e.g., let
loadPromise: Promise<void>), assign loadPromise = loadSettingValues() inside
load(), set isLoading appropriately, await loadPromise for concurrent callers
(await loadPromise) and clear it when done, so callers receive any thrown errors
and isReady is set only on success. Ensure references to isLoading, isReady,
loadSettingValues(), and loadPromise are used consistently.

In `@src/platform/workflow/management/stores/workflowStore.ts`:
- Around line 561-570: loadWorkflows can return silently if a concurrent sync
fails: after awaiting until(isSyncLoading).toBe(false) check whether the sync
actually succeeded (inspect isSyncReady.value) and if not either re-attempt the
sync by calling syncWorkflows() or throw/reject to surface the failure; update
the function (referencing loadWorkflows, isSyncLoading, isSyncReady, until and
syncWorkflows) so callers don’t proceed under a false assumption that workflows
were loaded.

AustinMroz
AustinMroz previously approved these changes Jan 27, 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: 0

Caution

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

⚠️ Outside diff range comments (1)
src/renderer/extensions/minimap/composables/useMinimapGraph.test.ts (1)

105-109: Consider removing commented-out code.

The originalCallbacks block is commented out and not used in this test. If it's no longer needed for the test logic, consider removing it to keep the test clean.

🧹 Suggested cleanup
   const graphRef = ref(mockGraph) as Ref<LGraph | null>
   const graphManager = useMinimapGraph(graphRef, onGraphChangedMock)

-  // Store original callbacks for comparison
-  // const originalCallbacks = {
-  //   onNodeAdded: mockGraph.onNodeAdded,
-  //   onNodeRemoved: mockGraph.onNodeRemoved,
-  //   onConnectionChange: mockGraph.onConnectionChange
-  // }
-
   graphManager.setupEventListeners()

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.

LGTM

throw new Error(`Setting ${setting.id} must have a unique ID.`)
// Setting already registered - skip to allow component remounting
// TODO: Add store reset methods to bootstrapStore and settingStore, then
// replace window.location.reload() with router.push() in SidebarLogoutIcon.vue
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we add this aspect to the comment/todo? Or make an Issue?

@DrJKL DrJKL merged commit 14369c0 into main Jan 27, 2026
27 checks passed
@DrJKL DrJKL deleted the drjkl/first-things-first branch January 27, 2026 20:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

preview size:XL This PR changes 500-999 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Stale status indicators on workflow tabs

3 participants