Skip to content

Road to No Explicit Any Part 11#8565

Merged
AustinMroz merged 13 commits intomainfrom
fix/penultimate-any-files
Feb 6, 2026
Merged

Road to No Explicit Any Part 11#8565
AustinMroz merged 13 commits intomainfrom
fix/penultimate-any-files

Conversation

@Myestery
Copy link
Contributor

@Myestery Myestery commented Feb 3, 2026

Summary

This PR removes any types from widgets, services, stores, and test files, replacing them with proper TypeScript types.

Key Changes

Type Safety Improvements

  • Replaced any with unknown, explicit types, or proper interfaces across widgets and services
  • Added proper type imports (TgpuRoot, Point, StyleValue, etc.)
  • Created typed interfaces (NumericWidgetOptions, TestWindow, ImportFailureDetail, etc.)
  • Fixed function return types to be non-nullable where appropriate
  • Added type guards and null checks instead of non-null assertions
  • Used ComponentProps from vue-component-type-helpers for component testing

Widget System

  • Added index signature to IWidgetOptions for Record compatibility
  • Centralized disabled logic in WidgetInputNumberInput
  • Moved template type assertions to computed properties
  • Fixed ComboWidget getOptionLabel type assertions
  • Improved remote widget type handling with runtime checks

Services & Stores

  • Fixed getOrCreateViewer to return non-nullable values
  • Updated addNodeOnGraph to use specific options type { pos?: Point }
  • Added proper type assertions for settings store retrieval
  • Fixed executionIdToCurrentId return type (string | undefined)

Test Infrastructure

  • Exported GraphOrSubgraph from litegraph barrel to avoid circular dependencies
  • Updated test fixtures with proper TypeScript types (TestInfo, LGraphNode)
  • Replaced loose Record types with ComponentProps in tests
  • Added proper error handling in WebSocket fixture

Code Organization

  • Created shared i18n-types module for locale data types
  • Made ImportFailureDetail non-exported (internal use only)
  • Added @public JSDoc tag to ElectronWindow type
  • Fixed console.log usage in scripts to use allowed methods

Files Changed

Widgets & Components:

  • src/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberInput.vue
  • src/renderer/extensions/vueNodes/widgets/components/WidgetSelectDefault.vue
  • src/renderer/extensions/vueNodes/widgets/components/WidgetSelectDropdown.vue
  • src/renderer/extensions/vueNodes/widgets/components/WidgetTextarea.vue
  • src/renderer/extensions/vueNodes/widgets/composables/useRemoteWidget.ts
  • src/lib/litegraph/src/widgets/ComboWidget.ts
  • src/lib/litegraph/src/types/widgets.ts
  • src/components/common/LazyImage.vue
  • src/components/load3d/Load3dViewerContent.vue

Services & Stores:

  • src/services/litegraphService.ts
  • src/services/load3dService.ts
  • src/services/colorPaletteService.ts
  • src/stores/maskEditorStore.ts
  • src/stores/nodeDefStore.ts
  • src/platform/settings/settingStore.ts
  • src/platform/workflow/management/stores/workflowStore.ts

Composables & Utils:

  • src/composables/node/useWatchWidget.ts
  • src/composables/useCanvasDrop.ts
  • src/utils/widgetPropFilter.ts
  • src/utils/queueDisplay.ts
  • src/utils/envUtil.ts

Test Files:

  • browser_tests/fixtures/ComfyPage.ts
  • browser_tests/fixtures/ws.ts
  • browser_tests/tests/actionbar.spec.ts
  • src/workbench/extensions/manager/components/manager/skeleton/PackCardGridSkeleton.test.ts
  • src/lib/litegraph/src/subgraph/subgraphUtils.test.ts
  • src/components/rightSidePanel/shared.test.ts
  • src/platform/cloud/subscription/composables/useSubscription.test.ts
  • src/platform/workflow/persistence/composables/useWorkflowPersistence.test.ts

Scripts & Types:

  • scripts/i18n-types.ts (new shared module)
  • scripts/diff-i18n.ts
  • scripts/check-unused-i18n-keys.ts
  • src/workbench/extensions/manager/types/conflictDetectionTypes.ts
  • src/types/algoliaTypes.ts
  • src/types/simplifiedWidget.ts

Infrastructure:

  • src/lib/litegraph/src/litegraph.ts (added GraphOrSubgraph export)
  • src/lib/litegraph/src/infrastructure/CustomEventTarget.ts
  • src/platform/assets/services/assetService.ts

Stories:

  • apps/desktop-ui/src/views/InstallView.stories.ts
  • src/components/queue/job/JobDetailsPopover.stories.ts

Extension Manager:

  • src/workbench/extensions/manager/composables/useConflictDetection.ts
  • src/workbench/extensions/manager/composables/useManagerQueue.ts
  • src/workbench/extensions/manager/services/comfyManagerService.ts
  • src/workbench/extensions/manager/utils/conflictMessageUtil.ts

Testing

  • All TypeScript type checking passes (pnpm typecheck)
  • ESLint passes without errors (pnpm lint)
  • Format checks pass (pnpm format:check)
  • Knip (unused exports) passes (pnpm knip)
  • Pre-commit and pre-push hooks pass

Part of the "Road to No Explicit Any" initiative.

Previous PRs in this series:

Fixes multiple TypeScript errors across the codebase to improve type safety:

- Add TgpuRoot type import for maskEditorStore
- Add Point type annotation for useCanvasDrop position array
- Add proper type assertions for settings store retrieval
- Add index signature to IWidgetOptions for Record compatibility
- Add NumericWidgetOptions interface for widget numeric properties
- Add type guards for widget option callbacks and properties
- Add null checks for load3dService viewer access
- Replace any types with proper unknown or specific types
- Fix console.log usage in scripts to use allowed methods
- Move template type assertions to computed properties
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 3, 2026

📝 Walkthrough

Walkthrough

This pull request refactors the codebase's type safety by systematically replacing permissive any types with stricter alternatives like unknown or explicit interfaces. It introduces new shared type definitions, updates function signatures, and adds new optional properties to the IWidgetOptions interface while maintaining runtime behavior.

Changes

Cohort / File(s) Summary
Type definitions and imports
scripts/i18n-types.ts, src/workbench/extensions/manager/types/conflictDetectionTypes.ts, src/utils/envUtil.ts
Added new exported types: LocaleData (recursive locale dictionary), ImportFailureMap (package failure mapping), and made ElectronWindow public with JSDoc documentation.
I18n script type narrowing
scripts/check-unused-i18n-keys.ts, scripts/diff-i18n.ts
Imported and applied LocaleData type to replace local any definitions. Updated findAdditions and extractKeys signatures. Changed log outputs from console.log to console.warn for consistency.
StoryBook and test mocking
apps/desktop-ui/src/views/InstallView.stories.ts, browser_tests/fixtures/ws.ts, src/components/queue/job/JobDetailsPopover.stories.ts
Replaced generic any casts with typed interfaces (ElectronWindow, TestWindow). Removed explicit as any assertions. Updated trigger function signatures from any to unknown.
Widget options interface expansion
src/lib/litegraph/src/types/widgets.ts
Added six new optional properties to IWidgetOptions: disabled, useGrouping, placeholder, showThumbnails, showItemNavigators, hidden.
Widget component type refinement
src/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberInput.vue, src/renderer/extensions/vueNodes/widgets/components/WidgetTextarea.vue, src/renderer/extensions/vueNodes/widgets/components/WidgetColorPicker.vue, src/renderer/extensions/vueNodes/widgets/components/WidgetChart.vue
Introduced NumericWidgetOptions interface and isDisabled computed property. Replaced inline widget option types with IWidgetOptions. Added explicit type constraints via satisfies.
Select widget null-safety
src/renderer/extensions/vueNodes/widgets/components/WidgetSelectDefault.vue, src/renderer/extensions/vueNodes/widgets/components/WidgetSelectDropdown.vue
Changed model value defaulting to use nullish coalescing (??) instead of logical OR. Updated option label handling and added explicit `string
Remote widget and cache typing
src/renderer/extensions/vueNodes/widgets/composables/useRemoteWidget.ts, src/composables/node/useWatchWidget.ts
Changed CacheEntry from any to unknown. Updated onFirstLoad to handle `T
Service layer type narrowing
src/services/litegraphService.ts, src/services/load3dService.ts, src/services/colorPaletteService.ts
Narrowed addNodeOnGraph options to Record<string, unknown> & { pos?: Point }. Made viewerInstances map and getOrCreateViewerSync generically typed. Refined Zod object generic constraint.
Store type refinement
src/platform/settings/settingStore.ts, src/platform/workflow/management/stores/workflowStore.ts, src/stores/nodeDefStore.ts, src/stores/maskEditorStore.ts
Updated internal store state from Record<string, any> to Partial<Settings> or specific types. Added generic constraints to exists() and get(). Narrowed hidden field to Record<string, boolean>.
Manager extension types
src/workbench/extensions/manager/composables/useConflictDetection.ts, src/workbench/extensions/manager/services/comfyManagerService.ts, src/workbench/extensions/manager/utils/conflictMessageUtil.ts
Imported and applied ImportFailureMap type to replace generic Record<string, any>. Updated fetchImportFailInfo return type. Narrowed translation function parameters to Record<string, unknown>.
Component prop and return types
src/components/common/LazyImage.vue, src/platform/assets/services/assetService.ts, src/utils/queueDisplay.ts, src/utils/widgetPropFilter.ts, src/types/algoliaTypes.ts
Changed imageStyle from any to StyleValue. Narrowed user_metadata parameters. Tightened generic constraints from Record<string, any> to object or unknown. Updated analytics field type.
Composite widget and graph types
src/types/simplifiedWidget.ts, src/composables/graph/useGraphNodeManager.ts, src/composables/useCanvasDrop.ts
Constrained generic O in SimplifiedWidget to IWidgetOptions. Updated SafeWidgetEnhancements.options to IWidgetOptions. Added Point type constraint for canvas position variable.
Canvas and load 3D updates
src/components/load3d/Load3dViewerContent.vue
Updated drag-and-drop disabled state check to use explicit boolean coercion (!!).
Test updates
src/components/rightSidePanel/shared.test.ts, src/lib/litegraph/src/subgraph/subgraphUtils.test.ts, src/platform/cloud/subscription/composables/useSubscription.test.ts, src/platform/workflow/persistence/composables/useWorkflowPersistence.test.ts, src/workbench/extensions/manager/components/manager/skeleton/PackCardGridSkeleton.test.ts, src/renderer/extensions/vueNodes/widgets/components/WidgetInputText.test.ts, src/renderer/extensions/vueNodes/widgets/components/WidgetSelectDropdown.test.ts
Removed/updated test assertions and type casts. Changed registry types from Map<UUID, any> to Map<UUID, LGraph>. Tightened test helper signatures with explicit parameter typing. Updated mock function signatures to accept optional parameters.
Locale updates
src/locales/fa/nodeDefs.json, src/locales/pt-BR/nodeDefs.json
Added localized labels for Load3D node inputs (clear, upload 3d model, upload extra resources). Restructured outputs from object-based to array-based format with new output entry model_3d.
DOM and combo widget refinements
src/lib/litegraph/src/infrastructure/CustomEventTarget.ts, src/lib/litegraph/src/widgets/ComboWidget.ts, src/renderer/extensions/vueNodes/components/LGraphNodePreview.vue
Changed event listener return type from any to unknown. Extracted getOptionLabel to local constant with try/catch guard. Added type constraint using satisfies IWidgetOptions.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes


Poem

🐰 Hops of type, so spry and true,
From murky any, fresh unknown breaks through,
Each interface named, each generic refined,
Type safety blooms across the codebase intertwined,
No logic harmed, just stricter bounds—
This rabbit's refactor makes TypeScript sing its sounds!

🚥 Pre-merge checks | ✅ 3 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 57.14% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Linked Issues check ❓ Inconclusive While the PR description references being part of the 'Road to No Explicit Any' series with prior related PRs listed, no specific issue number is linked (the template includes an optional '# ISSUE_NUMBER' line that appears unused). Consider linking to an issue if this PR addresses a specific tracked issue, or ensure the series tracking is documented elsewhere.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Road to No Explicit Any Part 11' accurately reflects the PR's main objective of removing explicit 'any' types throughout the codebase and replacing them with proper TypeScript types.
Description check ✅ Passed The PR description is comprehensive and follows the template structure with a clear summary, detailed changes, files changed, and testing verification, covering all major modifications across widgets, services, stores, and tests.
Out of Scope Changes check ✅ Passed All changes focus on type safety improvements (replacing 'any' with 'unknown', explicit types, and interfaces) across widgets, services, and tests. No unrelated functional logic changes beyond type refinements and necessary type guards.

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

✨ 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 fix/penultimate-any-files

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

❤️ Share

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

@github-actions
Copy link

github-actions bot commented Feb 3, 2026

🎭 Playwright Tests: ✅ Passed

Results: 511 passed, 0 failed, 0 flaky, 8 skipped (Total: 519)

📊 Browser Reports
  • chromium: View Report (✅ 499 / ❌ 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 Feb 3, 2026

🎨 Storybook Build Status

Build completed successfully!

⏰ Completed at: 02/05/2026, 10:03:50 PM UTC

🔗 Links


🎉 Your Storybook is ready for review!

@github-actions
Copy link

github-actions bot commented Feb 3, 2026

Bundle Size Report

Summary

  • Raw size: 20.2 MB baseline 20.2 MB — 🔴 +1.02 kB
  • Gzip: 4.32 MB baseline 4.32 MB — 🔴 +134 B
  • Brotli: 3.34 MB baseline 3.34 MB — 🔴 +8 B
  • Bundles: 233 current • 233 baseline • 120 added / 120 removed

Category Glance
Other 🔴 +738 B (7.08 MB) · Data & Services 🔴 +279 B (2.1 MB) · Vendor & Third-Party ⚪ 0 B (9.37 MB) · Graph Workspace ⚪ 0 B (840 kB) · Panels & Settings ⚪ 0 B (410 kB) · Utilities & Hooks ⚪ 0 B (234 kB) · + 5 more

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

Main entry bundles and manifests

File Before After Δ Raw Δ Gzip Δ Brotli
assets/index-BxJh6Htb.js (removed) 22.5 kB 🟢 -22.5 kB 🟢 -7.18 kB 🟢 -6.27 kB
assets/index-DX9kGKag.js (new) 22.5 kB 🔴 +22.5 kB 🔴 +7.18 kB 🔴 +6.25 kB

Status: 1 added / 1 removed

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

Graph editor runtime, canvas, workflow orchestration

File Before After Δ Raw Δ Gzip Δ Brotli
assets/GraphView-BUtjXrxr.js (new) 840 kB 🔴 +840 kB 🔴 +180 kB 🔴 +137 kB
assets/GraphView-CH--ZSma.js (removed) 840 kB 🟢 -840 kB 🟢 -180 kB 🟢 -137 kB

Status: 1 added / 1 removed

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

Top-level views, pages, and routed surfaces

File Before After Δ Raw Δ Gzip Δ Brotli
assets/CloudSurveyView-BO66kDe-.js (removed) 15.8 kB 🟢 -15.8 kB 🟢 -3.46 kB 🟢 -2.95 kB
assets/CloudSurveyView-DvaCuFvf.js (new) 15.8 kB 🔴 +15.8 kB 🔴 +3.46 kB 🔴 +2.93 kB
assets/CloudLoginView-2eyjobGD.js (removed) 10 kB 🟢 -10 kB 🟢 -2.93 kB 🟢 -2.56 kB
assets/CloudLoginView-sTPkh9PA.js (new) 10 kB 🔴 +10 kB 🔴 +2.93 kB 🔴 +2.56 kB
assets/UserCheckView-0vucNJY5.js (new) 8.39 kB 🔴 +8.39 kB 🔴 +2.23 kB 🔴 +1.94 kB
assets/UserCheckView-oCyGS9my.js (removed) 8.39 kB 🟢 -8.39 kB 🟢 -2.23 kB 🟢 -1.94 kB
assets/CloudSignupView-BHhGBVUt.js (removed) 7.38 kB 🟢 -7.38 kB 🟢 -2.31 kB 🟢 -2.02 kB
assets/CloudSignupView-CeYF6mIk.js (new) 7.38 kB 🔴 +7.38 kB 🔴 +2.31 kB 🔴 +2.03 kB
assets/CloudLayoutView-B4SV_kIk.js (removed) 6.43 kB 🟢 -6.43 kB 🟢 -2.11 kB 🟢 -1.83 kB
assets/CloudLayoutView-w71RwjnM.js (new) 6.43 kB 🔴 +6.43 kB 🔴 +2.11 kB 🔴 +1.83 kB
assets/CloudForgotPasswordView-C6-9m45i.js (new) 5.56 kB 🔴 +5.56 kB 🔴 +1.94 kB 🔴 +1.7 kB
assets/CloudForgotPasswordView-CLkXVhij.js (removed) 5.56 kB 🟢 -5.56 kB 🟢 -1.94 kB 🟢 -1.71 kB
assets/CloudAuthTimeoutView-BMZQz6dC.js (new) 4.91 kB 🔴 +4.91 kB 🔴 +1.77 kB 🔴 +1.55 kB
assets/CloudAuthTimeoutView-D_S9Fylr.js (removed) 4.91 kB 🟢 -4.91 kB 🟢 -1.77 kB 🟢 -1.55 kB
assets/CloudSubscriptionRedirectView-C4dcknkJ.js (removed) 4.71 kB 🟢 -4.71 kB 🟢 -1.77 kB 🟢 -1.57 kB
assets/CloudSubscriptionRedirectView-DUBv4z62.js (new) 4.71 kB 🔴 +4.71 kB 🔴 +1.77 kB 🔴 +1.57 kB
assets/UserSelectView-BOmO8XyF.js (new) 4.49 kB 🔴 +4.49 kB 🔴 +1.63 kB 🔴 +1.46 kB
assets/UserSelectView-Dfdq2xhQ.js (removed) 4.49 kB 🟢 -4.49 kB 🟢 -1.64 kB 🟢 -1.47 kB
assets/CloudSorryContactSupportView-BPXBOTez.js 1.02 kB 1.02 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/layout-ncetNFDR.js 296 B 296 B ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 9 added / 9 removed

Panels & Settings — 410 kB (baseline 410 kB) • ⚪ 0 B

Configuration panels, inspectors, and settings screens

File Before After Δ Raw Δ Gzip Δ Brotli
assets/WorkspacePanel-5pIURN-U.js (new) 26.9 kB 🔴 +26.9 kB 🔴 +5.66 kB 🔴 +4.98 kB
assets/WorkspacePanel-CwhGscD8.js (removed) 26.9 kB 🟢 -26.9 kB 🟢 -5.66 kB 🟢 -4.96 kB
assets/SecretsPanel-C8X8IKq6.js (removed) 21.5 kB 🟢 -21.5 kB 🟢 -5.31 kB 🟢 -4.65 kB
assets/SecretsPanel-rCCizxBb.js (new) 21.5 kB 🔴 +21.5 kB 🔴 +5.31 kB 🔴 +4.66 kB
assets/LegacyCreditsPanel-Baf-izbx.js (removed) 20.8 kB 🟢 -20.8 kB 🟢 -5.62 kB 🟢 -4.93 kB
assets/LegacyCreditsPanel-DqA6anje.js (new) 20.8 kB 🔴 +20.8 kB 🔴 +5.62 kB 🔴 +4.94 kB
assets/SubscriptionPanel--WFhpSTI.js (removed) 18.8 kB 🟢 -18.8 kB 🟢 -4.77 kB 🟢 -4.21 kB
assets/SubscriptionPanel-Bf9A4yoS.js (new) 18.8 kB 🔴 +18.8 kB 🔴 +4.76 kB 🔴 +4.21 kB
assets/KeybindingPanel-BYEFVzQ0.js (new) 12.6 kB 🔴 +12.6 kB 🔴 +3.63 kB 🔴 +3.22 kB
assets/KeybindingPanel-DpUChvaS.js (removed) 12.6 kB 🟢 -12.6 kB 🟢 -3.62 kB 🟢 -3.21 kB
assets/ExtensionPanel-Cy3_JGtr.js (removed) 9.49 kB 🟢 -9.49 kB 🟢 -2.69 kB 🟢 -2.4 kB
assets/ExtensionPanel-f2QNGkdf.js (new) 9.49 kB 🔴 +9.49 kB 🔴 +2.69 kB 🔴 +2.38 kB
assets/AboutPanel-1NDOV5q7.js (new) 8.62 kB 🔴 +8.62 kB 🔴 +2.46 kB 🔴 +2.21 kB
assets/AboutPanel-qEDivQHD.js (removed) 8.62 kB 🟢 -8.62 kB 🟢 -2.46 kB 🟢 -2.21 kB
assets/ServerConfigPanel-COOJqOjd.js (new) 6.64 kB 🔴 +6.64 kB 🔴 +2.15 kB 🔴 +1.93 kB
assets/ServerConfigPanel-DcYemXfL.js (removed) 6.64 kB 🟢 -6.64 kB 🟢 -2.15 kB 🟢 -1.93 kB
assets/UserPanel-7p__oG4c.js (new) 6.28 kB 🔴 +6.28 kB 🔴 +2.02 kB 🔴 +1.77 kB
assets/UserPanel-CC8-S4fF.js (removed) 6.28 kB 🟢 -6.28 kB 🟢 -2.02 kB 🟢 -1.78 kB
assets/cloudRemoteConfig-DXj5wKH9.js (removed) 1.44 kB 🟢 -1.44 kB 🟢 -702 B 🟢 -606 B
assets/cloudRemoteConfig-waD642Bk.js (new) 1.44 kB 🔴 +1.44 kB 🔴 +699 B 🔴 +608 B
assets/refreshRemoteConfig-6iINa6it.js (removed) 1.13 kB 🟢 -1.13 kB 🟢 -509 B 🟢 -458 B
assets/refreshRemoteConfig-DTFjuQg_.js (new) 1.13 kB 🔴 +1.13 kB 🔴 +512 B 🔴 +447 B
assets/refreshRemoteConfig-CgM0kq2O.js (removed) 345 B 🟢 -345 B 🟢 -201 B 🟢 -201 B
assets/refreshRemoteConfig-DgfityCq.js (new) 345 B 🔴 +345 B 🔴 +203 B 🔴 +205 B
assets/config-HAvaVehF.js 1.01 kB 1.01 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/remoteConfig-CUBB_j_I.js 581 B 581 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-BgcR6REE.js 25 kB 25 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-BmEXiKRV.js 32 kB 32 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-BNs5rnMt.js 24.1 kB 24.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-C5jqELHS.js 23.6 kB 23.6 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-CKCscONF.js 28.1 kB 28.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-CzcL_U24.js 20.8 kB 20.8 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-D95NIw0v.js 26.8 kB 26.8 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-DmYc-PH9.js 24.2 kB 24.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-DQe4OZm2.js 25.7 kB 25.7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-Dxocpd_-.js 20.3 kB 20.3 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-f2yAwEpW.js 23.3 kB 23.3 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 12 added / 12 removed

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

Authentication, profile, and account management bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/auth-DbcTWJMJ.js (removed) 3.4 kB 🟢 -3.4 kB 🟢 -1.18 kB 🟢 -996 B
assets/auth-DLLyuykg.js (new) 3.4 kB 🔴 +3.4 kB 🔴 +1.18 kB 🔴 +994 B
assets/SignUpForm-BNbrkeS0.js (new) 3.01 kB 🔴 +3.01 kB 🔴 +1.23 kB 🔴 +1.09 kB
assets/SignUpForm-DhtG6BZb.js (removed) 3.01 kB 🟢 -3.01 kB 🟢 -1.24 kB 🟢 -1.1 kB
assets/UpdatePasswordContent-Ckoe8Piv.js (removed) 2.37 kB 🟢 -2.37 kB 🟢 -1.07 kB 🟢 -948 B
assets/UpdatePasswordContent-CXj7Irls.js (new) 2.37 kB 🔴 +2.37 kB 🔴 +1.07 kB 🔴 +948 B
assets/firebaseAuthStore-CE1CAHVI.js (removed) 790 B 🟢 -790 B 🟢 -389 B 🟢 -351 B
assets/firebaseAuthStore-DNBOs6Xd.js (new) 790 B 🔴 +790 B 🔴 +387 B 🔴 +340 B
assets/auth-DSXSZQIz.js (removed) 347 B 🟢 -347 B 🟢 -221 B 🟢 -190 B
assets/auth-elt0yUhZ.js (new) 347 B 🔴 +347 B 🔴 +220 B 🔴 +185 B
assets/PasswordFields-BAi3GPM-.js 4.51 kB 4.51 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WorkspaceProfilePic-B0BztYjc.js 1.57 kB 1.57 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 5 added / 5 removed

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

Modals, dialogs, drawers, and in-app editors

File Before After Δ Raw Δ Gzip Δ Brotli
assets/useSubscriptionDialog-Bd-qOoP9.js (new) 2.68 kB 🔴 +2.68 kB 🔴 +1.32 kB 🔴 +1.17 kB
assets/useSubscriptionDialog-CVdavmn4.js (removed) 2.68 kB 🟢 -2.68 kB 🟢 -1.32 kB 🟢 -1.17 kB
assets/useSubscriptionDialog-3u1QLHQo.js (new) 783 B 🔴 +783 B 🔴 +384 B 🔴 +335 B
assets/useSubscriptionDialog-DVc37k3B.js (removed) 783 B 🟢 -783 B 🟢 -386 B 🟢 -345 B

Status: 2 added / 2 removed

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

Reusable component library chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/useTerminalTabs-DMEPEEyp.js (removed) 9.9 kB 🟢 -9.9 kB 🟢 -3.4 kB 🟢 -3 kB
assets/useTerminalTabs-Dv4R9Dxz.js (new) 9.9 kB 🔴 +9.9 kB 🔴 +3.4 kB 🔴 +2.99 kB
assets/ComfyQueueButton-C2uE2t5W.js (new) 7.13 kB 🔴 +7.13 kB 🔴 +2.31 kB 🔴 +2.06 kB
assets/ComfyQueueButton-DlwJnD1W.js (removed) 7.13 kB 🟢 -7.13 kB 🟢 -2.31 kB 🟢 -2.06 kB
assets/SubscribeButton-C8P5BwxN.js (removed) 3.68 kB 🟢 -3.68 kB 🟢 -1.38 kB 🟢 -1.24 kB
assets/SubscribeButton-DhNcQOr7.js (new) 3.68 kB 🔴 +3.68 kB 🔴 +1.38 kB 🔴 +1.24 kB
assets/cloudFeedbackTopbarButton-DIfMGaF3.js (removed) 1.6 kB 🟢 -1.6 kB 🟢 -857 B 🟢 -760 B
assets/cloudFeedbackTopbarButton-s47d-sJw.js (new) 1.6 kB 🔴 +1.6 kB 🔴 +853 B 🔴 +767 B
assets/CloudBadge-CuVvxtql.js (new) 1.2 kB 🔴 +1.2 kB 🔴 +591 B 🔴 +511 B
assets/CloudBadge-V9dvGAv0.js (removed) 1.2 kB 🟢 -1.2 kB 🟢 -591 B 🟢 -510 B
assets/ComfyQueueButton-BpVKE0pb.js (removed) 795 B 🟢 -795 B 🟢 -393 B 🟢 -354 B
assets/ComfyQueueButton-p_UM89vT.js (new) 795 B 🔴 +795 B 🔴 +390 B 🔴 +342 B
assets/Button-ChqYCdrL.js 3 kB 3 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/TopbarBadge-BsZTG314.js 7.52 kB 7.52 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/UserAvatar-Dtdiv1Hu.js 1.17 kB 1.17 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetButton-DVfWCi_V.js 1.84 kB 1.84 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 6 added / 6 removed

Data & Services — 2.1 MB (baseline 2.1 MB) • 🔴 +279 B

Stores, services, APIs, and repositories

File Before After Δ Raw Δ Gzip Δ Brotli
assets/dialogService-BX868mCh.js (new) 1.3 MB 🔴 +1.3 MB 🔴 +298 kB 🔴 +232 kB
assets/dialogService-DKSPPY1l.js (removed) 1.3 MB 🟢 -1.3 MB 🟢 -298 kB 🟢 -232 kB
assets/api-DLg33XIF.js (new) 641 kB 🔴 +641 kB 🔴 +144 kB 🔴 +116 kB
assets/api-CFaytb2I.js (removed) 640 kB 🟢 -640 kB 🟢 -144 kB 🟢 -116 kB
assets/load3dService-Dq6tdrPK.js (new) 91.1 kB 🔴 +91.1 kB 🔴 +19.1 kB 🔴 +16.4 kB
assets/load3dService-BAw_Fq0T.js (removed) 91.1 kB 🟢 -91.1 kB 🟢 -19.1 kB 🟢 -16.4 kB
assets/teamWorkspaceStore-B94rMaHF.js (new) 27.1 kB 🔴 +27.1 kB 🔴 +6.13 kB 🔴 +5.41 kB
assets/teamWorkspaceStore-BG3hzw_Z.js (removed) 27.1 kB 🟢 -27.1 kB 🟢 -6.12 kB 🟢 -5.41 kB
assets/systemStatsStore-CCtvdL0L.js (new) 12.3 kB 🔴 +12.3 kB 🔴 +4.29 kB 🔴 +3.77 kB
assets/systemStatsStore-Pxy3Tb3i.js (removed) 12.3 kB 🟢 -12.3 kB 🟢 -4.29 kB 🟢 -3.77 kB
assets/releaseStore-B4r4KKD9.js (removed) 8.14 kB 🟢 -8.14 kB 🟢 -2.24 kB 🟢 -1.97 kB
assets/releaseStore-DYEpwU61.js (new) 8.14 kB 🔴 +8.14 kB 🔴 +2.24 kB 🔴 +1.97 kB
assets/keybindingService-ClYHnSZ7.js (removed) 6.58 kB 🟢 -6.58 kB 🟢 -1.71 kB 🟢 -1.48 kB
assets/keybindingService-DqII4avZ.js (new) 6.58 kB 🔴 +6.58 kB 🔴 +1.71 kB 🔴 +1.48 kB
assets/bootstrapStore-CvNnJGA6.js (removed) 2.13 kB 🟢 -2.13 kB 🟢 -882 B 🟢 -814 B
assets/bootstrapStore-CVT9zW0S.js (new) 2.13 kB 🔴 +2.13 kB 🔴 +881 B 🔴 +810 B
assets/userStore-DAHozqm0.js (new) 1.85 kB 🔴 +1.85 kB 🔴 +721 B 🔴 +634 B
assets/userStore-DGRTB-u5.js (removed) 1.85 kB 🟢 -1.85 kB 🟢 -721 B 🟢 -675 B
assets/audioService-BuwAuU5m.js (new) 1.73 kB 🔴 +1.73 kB 🔴 +846 B 🔴 +728 B
assets/audioService-ChcEOCEx.js (removed) 1.73 kB 🟢 -1.73 kB 🟢 -843 B 🟢 -728 B
assets/releaseStore-BNCM_CRt.js (removed) 762 B 🟢 -762 B 🟢 -385 B 🟢 -338 B
assets/releaseStore-Cfsxuro-.js (new) 762 B 🔴 +762 B 🔴 +381 B 🔴 +326 B
assets/dialogStore-D2gUGUn6.js 4.1 kB 4.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/serverConfigStore-DB58Z5s2.js 2.32 kB 2.32 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 11 added / 11 removed

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

Helpers, composables, and utility bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/useConflictDetection-Cj_Eb9ik.js (removed) 177 kB 🟢 -177 kB 🟢 -38.9 kB 🟢 -32.4 kB
assets/useConflictDetection-ZpfHoArh.js (new) 177 kB 🔴 +177 kB 🔴 +38.9 kB 🔴 +32.4 kB
assets/useLoad3d-8GAQoiiA.js (removed) 14.4 kB 🟢 -14.4 kB 🟢 -3.56 kB 🟢 -3.15 kB
assets/useLoad3d-DKqO6CH4.js (new) 14.4 kB 🔴 +14.4 kB 🔴 +3.56 kB 🔴 +3.14 kB
assets/useLoad3dViewer-BlnZivZM.js (removed) 14.2 kB 🟢 -14.2 kB 🟢 -3.16 kB 🟢 -2.8 kB
assets/useLoad3dViewer-C__NDtli.js (new) 14.2 kB 🔴 +14.2 kB 🔴 +3.16 kB 🔴 +2.8 kB
assets/useErrorHandling-8CDz708C.js (new) 4.26 kB 🔴 +4.26 kB 🔴 +1.35 kB 🔴 +1.19 kB
assets/useErrorHandling-xYKy7a9u.js (removed) 4.26 kB 🟢 -4.26 kB 🟢 -1.34 kB 🟢 -1.18 kB
assets/useWorkspaceUI-BeX2_QHZ.js (new) 3.16 kB 🔴 +3.16 kB 🔴 +884 B 🔴 +766 B
assets/useWorkspaceUI-ByNLxcoj.js (removed) 3.16 kB 🟢 -3.16 kB 🟢 -883 B 🟢 -765 B
assets/useSubscriptionActions-DDT_M35K.js (removed) 1.76 kB 🟢 -1.76 kB 🟢 -759 B 🟢 -653 B
assets/useSubscriptionActions-knZLlPJJ.js (new) 1.76 kB 🔴 +1.76 kB 🔴 +756 B 🔴 +654 B
assets/subscriptionCheckoutUtil-BhtxaBle.js (removed) 1.75 kB 🟢 -1.75 kB 🟢 -782 B 🟢 -673 B
assets/subscriptionCheckoutUtil-BWl5mvZB.js (new) 1.75 kB 🔴 +1.75 kB 🔴 +786 B 🔴 +688 B
assets/useExternalLink-BGTvgS-9.js (removed) 1.63 kB 🟢 -1.63 kB 🟢 -757 B 🟢 -671 B
assets/useExternalLink-Dtd-tQ8v.js (new) 1.63 kB 🔴 +1.63 kB 🔴 +756 B 🔴 +668 B
assets/useCopyToClipboard-CB3EuFmd.js (new) 1.57 kB 🔴 +1.57 kB 🔴 +665 B 🔴 +566 B
assets/useCopyToClipboard-CTuQep2Q.js (removed) 1.57 kB 🟢 -1.57 kB 🟢 -666 B 🟢 -551 B
assets/useSubscriptionCredits-8XDWY-6z.js (new) 1.07 kB 🔴 +1.07 kB 🔴 +502 B 🔴 +458 B
assets/useSubscriptionCredits-CqRhI05b.js (removed) 1.07 kB 🟢 -1.07 kB 🟢 -503 B 🟢 -432 B
assets/useLoad3d-CM4kUbqP.js (removed) 861 B 🟢 -861 B 🟢 -426 B 🟢 -384 B
assets/useLoad3d-D1kDHvwH.js (new) 861 B 🔴 +861 B 🔴 +422 B 🔴 +374 B
assets/audioUtils-B69_6kT5.js (removed) 858 B 🟢 -858 B 🟢 -501 B 🟢 -420 B
assets/audioUtils-DxLmT0Dr.js (new) 858 B 🔴 +858 B 🔴 +499 B 🔴 +421 B
assets/useLoad3dViewer-BYbStJ0R.js (new) 840 B 🔴 +840 B 🔴 +406 B 🔴 +360 B
assets/useLoad3dViewer-Ces1KAc2.js (removed) 840 B 🟢 -840 B 🟢 -411 B 🟢 -374 B
assets/useCurrentUser-5GdQIsoK.js (removed) 724 B 🟢 -724 B 🟢 -372 B 🟢 -331 B
assets/useCurrentUser-lc620ULB.js (new) 724 B 🔴 +724 B 🔴 +369 B 🔴 +323 B
assets/_plugin-vue_export-helper-CAbbkOlw.js 315 B 315 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/colorUtil-FW_Ghng2.js 7 kB 7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/envUtil-Djb4sHrV.js 524 B 524 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/markdownRendererUtil-Cc2LFa5s.js 1.56 kB 1.56 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/networkUtil-Du2a_n7V.js 1.07 kB 1.07 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/SkeletonUtils-DwBAnKr-.js 133 B 133 B ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 14 added / 14 removed

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

External libraries and shared vendor chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/vendor-axios-D0w6WYH0.js 71.6 kB 71.6 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-chart-CIdI9Yl4.js 399 kB 399 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-firebase-CLEC0CcJ.js 842 kB 842 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-i18n-C6_f776o.js 132 kB 132 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-markdown-BkVHYrKV.js 102 kB 102 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-other-DPcKX1Hx.js 2.16 MB 2.16 MB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-primevue-Dw8RivU1.js 1.74 MB 1.74 MB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-reka-ui-CPrt7lw0.js 240 kB 240 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-sentry-BVA5kbUC.js 183 kB 183 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-three-CJhOuqDg.js 1.8 MB 1.8 MB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-tiptap-CvX7mojg.js 632 kB 632 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-vue-core-BBP9kkTE.js 312 kB 312 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-vueuse-CS5mlw4Q.js 111 kB 111 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-xterm-DOEEpxXk.js 398 kB 398 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-yjs-BtrvIr1x.js 143 kB 143 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-zod-gAWmQIF-.js 110 kB 110 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
Other — 7.08 MB (baseline 7.08 MB) • 🔴 +738 B

Bundles that do not match a named category

File Before After Δ Raw Δ Gzip Δ Brotli
assets/i18n-Clr-ST51.js (new) 479 kB 🔴 +479 kB 🔴 +91.5 kB 🔴 +71.3 kB
assets/i18n-CPvZppmN.js (removed) 479 kB 🟢 -479 kB 🟢 -91.5 kB 🟢 -71.3 kB
assets/nodeDefs-Bh0AabLz.js (new) 405 kB 🔴 +405 kB 🔴 +60.9 kB 🔴 +42.7 kB
assets/nodeDefs-BcADFj4z.js (removed) 404 kB 🟢 -404 kB 🟢 -60.9 kB 🟢 -42.7 kB
assets/nodeDefs-BaZgeHtM.js (new) 353 kB 🔴 +353 kB 🔴 +56.3 kB 🔴 +41.1 kB
assets/nodeDefs-DTPAo_v7.js (removed) 353 kB 🟢 -353 kB 🟢 -56.3 kB 🟢 -41.1 kB
assets/core-BrY0eipZ.js (new) 71.4 kB 🔴 +71.4 kB 🔴 +18.4 kB 🔴 +15.8 kB
assets/core-CravAKl5.js (removed) 71.4 kB 🟢 -71.4 kB 🟢 -18.4 kB 🟢 -15.8 kB
assets/groupNode-B1FajR-l.js (removed) 70.9 kB 🟢 -70.9 kB 🟢 -17.5 kB 🟢 -15.4 kB
assets/groupNode-CXlMiKTx.js (new) 70.9 kB 🔴 +70.9 kB 🔴 +17.5 kB 🔴 +15.4 kB
assets/WidgetSelect-DmrrU6ot.js (new) 56.6 kB 🔴 +56.6 kB 🔴 +12 kB 🔴 +10.4 kB
assets/WidgetSelect-C9zyEiXz.js (removed) 56.6 kB 🟢 -56.6 kB 🟢 -12 kB 🟢 -10.4 kB
assets/SettingDialogContent-BF2plNRj.js (new) 30.8 kB 🔴 +30.8 kB 🔴 +8.01 kB 🔴 +7.04 kB
assets/SettingDialogContent-CuGAUU5i.js (removed) 30.8 kB 🟢 -30.8 kB 🟢 -8 kB 🟢 -7.05 kB
assets/Load3DControls-BRPPxe3f.js (new) 30.8 kB 🔴 +30.8 kB 🔴 +5.33 kB 🔴 +4.64 kB
assets/Load3DControls-DLe3CqNR.js (removed) 30.8 kB 🟢 -30.8 kB 🟢 -5.33 kB 🟢 -4.63 kB
assets/SubscriptionRequiredDialogContent-BIZSAM2E.js (removed) 25.4 kB 🟢 -25.4 kB 🟢 -6.36 kB 🟢 -5.58 kB
assets/SubscriptionRequiredDialogContent-CiQET3vL.js (new) 25.4 kB 🔴 +25.4 kB 🔴 +6.36 kB 🔴 +5.58 kB
assets/Load3dViewerContent-BnQxBujo.js (new) 23.2 kB 🔴 +23.2 kB 🔴 +5.24 kB 🔴 +4.54 kB
assets/Load3dViewerContent-Ntns7T2d.js (removed) 23.2 kB 🟢 -23.2 kB 🟢 -5.24 kB 🟢 -4.54 kB
assets/WidgetImageCrop-Daa1PfN9.js (removed) 22.3 kB 🟢 -22.3 kB 🟢 -5.51 kB 🟢 -4.84 kB
assets/WidgetImageCrop-DaSnXUeV.js (new) 22.3 kB 🔴 +22.3 kB 🔴 +5.51 kB 🔴 +4.85 kB
assets/FormItem-BzZt8WoK.js (new) 20.2 kB 🔴 +20.2 kB 🔴 +4.87 kB 🔴 +4.26 kB
assets/FormItem-D9KRSnWc.js (removed) 20.2 kB 🟢 -20.2 kB 🟢 -4.87 kB 🟢 -4.25 kB
assets/CurrentUserPopoverWorkspace-BICAEI95.js (removed) 19.7 kB 🟢 -19.7 kB 🟢 -4.74 kB 🟢 -4.24 kB
assets/CurrentUserPopoverWorkspace-C382Vdm4.js (new) 19.7 kB 🔴 +19.7 kB 🔴 +4.74 kB 🔴 +4.22 kB
assets/SignInContent-C9pFliht.js (new) 19 kB 🔴 +19 kB 🔴 +4.8 kB 🔴 +4.2 kB
assets/SignInContent-gVQmfkYa.js (removed) 19 kB 🟢 -19 kB 🟢 -4.8 kB 🟢 -4.2 kB
assets/WidgetRecordAudio-BQvLHGiR.js (removed) 17.2 kB 🟢 -17.2 kB 🟢 -4.93 kB 🟢 -4.41 kB
assets/WidgetRecordAudio-QdUz2s17.js (new) 17.2 kB 🔴 +17.2 kB 🔴 +4.92 kB 🔴 +4.4 kB
assets/TopUpCreditsDialogContent--zU91uEP.js (removed) 16.9 kB 🟢 -16.9 kB 🟢 -4.8 kB 🟢 -4.25 kB
assets/TopUpCreditsDialogContent-CKLQsvaH.js (new) 16.9 kB 🔴 +16.9 kB 🔴 +4.79 kB 🔴 +4.25 kB
assets/Load3D-C4QZt1DZ.js (removed) 16.2 kB 🟢 -16.2 kB 🟢 -4.03 kB 🟢 -3.51 kB
assets/Load3D-D2cdFICN.js (new) 16.2 kB 🔴 +16.2 kB 🔴 +4.04 kB 🔴 +3.5 kB
assets/MissingModelsWarning-BS2J8zpJ.js (new) 16.1 kB 🔴 +16.1 kB 🔴 +4.4 kB 🔴 +3.91 kB
assets/MissingModelsWarning-g5a553b3.js (removed) 16.1 kB 🟢 -16.1 kB 🟢 -4.4 kB 🟢 -3.9 kB
assets/SubscriptionPanelContentWorkspace-CTaYyGNM.js (new) 15.8 kB 🔴 +15.8 kB 🔴 +4.04 kB 🔴 +3.54 kB
assets/SubscriptionPanelContentWorkspace-CywNBIdI.js (removed) 15.8 kB 🟢 -15.8 kB 🟢 -4.03 kB 🟢 -3.55 kB
assets/WidgetInputNumber-BUxre_p9.js (new) 15.8 kB 🔴 +15.8 kB 🔴 +4.26 kB 🔴 +3.8 kB
assets/WidgetInputNumber-CkoKmr5O.js (removed) 15.4 kB 🟢 -15.4 kB 🟢 -4.2 kB 🟢 -3.75 kB
assets/load3d-BaU0vy13.js (new) 14.8 kB 🔴 +14.8 kB 🔴 +4.17 kB 🔴 +3.64 kB
assets/load3d-DukagXnf.js (removed) 14.8 kB 🟢 -14.8 kB 🟢 -4.18 kB 🟢 -3.63 kB
assets/LazyImage-Bir4uhOp.js (new) 12.3 kB 🔴 +12.3 kB 🔴 +3.8 kB 🔴 +3.34 kB
assets/LazyImage-CVvKb-rW.js (removed) 12.3 kB 🟢 -12.3 kB 🟢 -3.78 kB 🟢 -3.32 kB
assets/NodeConflictDialogContent-Bw6YhZyE.js (new) 10.5 kB 🔴 +10.5 kB 🔴 +2.36 kB 🔴 +2.08 kB
assets/NodeConflictDialogContent-D3HvN8uk.js (removed) 10.5 kB 🟢 -10.5 kB 🟢 -2.36 kB 🟢 -2.06 kB
assets/AudioPreviewPlayer-CjMfWQo5.js (new) 10.1 kB 🔴 +10.1 kB 🔴 +2.99 kB 🔴 +2.68 kB
assets/AudioPreviewPlayer-F6R9cg0k.js (removed) 10.1 kB 🟢 -10.1 kB 🟢 -2.99 kB 🟢 -2.68 kB
assets/nodeTemplates-BsDi-b2E.js (removed) 9.33 kB 🟢 -9.33 kB 🟢 -3.27 kB 🟢 -2.88 kB
assets/nodeTemplates-CUjmBRDG.js (new) 9.33 kB 🔴 +9.33 kB 🔴 +3.27 kB 🔴 +2.87 kB
assets/InviteMemberDialogContent-D930FFMJ.js (new) 7.95 kB 🔴 +7.95 kB 🔴 +2.56 kB 🔴 +2.22 kB
assets/InviteMemberDialogContent-DwsAzeo9.js (removed) 7.95 kB 🟢 -7.95 kB 🟢 -2.56 kB 🟢 -2.23 kB
assets/WidgetWithControl-CqlGvB8N.js (removed) 6.97 kB 🟢 -6.97 kB 🟢 -2.59 kB 🟢 -2.31 kB
assets/WidgetWithControl-HH-7uWi-.js (new) 6.97 kB 🔴 +6.97 kB 🔴 +2.59 kB 🔴 +2.31 kB
assets/Load3DConfiguration-C4gpcS4X.js (new) 6.36 kB 🔴 +6.36 kB 🔴 +1.93 kB 🔴 +1.69 kB
assets/Load3DConfiguration-DSi3v-Ef.js (removed) 6.36 kB 🟢 -6.36 kB 🟢 -1.92 kB 🟢 -1.69 kB
assets/MissingNodesContent-Duy0hqak.js (new) 6.14 kB 🔴 +6.14 kB 🔴 +2.08 kB 🔴 +1.84 kB
assets/MissingNodesContent-DY1mKPJv.js (removed) 6.14 kB 🟢 -6.14 kB 🟢 -2.08 kB 🟢 -1.85 kB
assets/CreateWorkspaceDialogContent-D3riZOpf.js (new) 5.58 kB 🔴 +5.58 kB 🔴 +2 kB 🔴 +1.74 kB
assets/CreateWorkspaceDialogContent-DsDTIujZ.js (removed) 5.58 kB 🟢 -5.58 kB 🟢 -2 kB 🟢 -1.75 kB
assets/EditWorkspaceDialogContent-BdageNrh.js (new) 5.38 kB 🔴 +5.38 kB 🔴 +1.95 kB 🔴 +1.7 kB
assets/EditWorkspaceDialogContent-D-4Ym1_s.js (removed) 5.38 kB 🟢 -5.38 kB 🟢 -1.96 kB 🟢 -1.71 kB
assets/ValueControlPopover--gPQG0Vb.js (new) 4.92 kB 🔴 +4.92 kB 🔴 +1.77 kB 🔴 +1.58 kB
assets/ValueControlPopover-l696M1lA.js (removed) 4.92 kB 🟢 -4.92 kB 🟢 -1.77 kB 🟢 -1.58 kB
assets/Preview3d-CiNGcNnH.js (removed) 4.82 kB 🟢 -4.82 kB 🟢 -1.57 kB 🟢 -1.37 kB
assets/Preview3d-DPTiHGD0.js (new) 4.82 kB 🔴 +4.82 kB 🔴 +1.57 kB 🔴 +1.36 kB
assets/MissingNodesFooter-C1sNgPa8.js (removed) 4.8 kB 🟢 -4.8 kB 🟢 -1.78 kB 🟢 -1.57 kB
assets/MissingNodesFooter-Dp3OM3hm.js (new) 4.8 kB 🔴 +4.8 kB 🔴 +1.78 kB 🔴 +1.58 kB
assets/DeleteWorkspaceDialogContent-CMuYnau5.js (new) 4.28 kB 🔴 +4.28 kB 🔴 +1.64 kB 🔴 +1.42 kB
assets/DeleteWorkspaceDialogContent-lCMeatVK.js (removed) 4.28 kB 🟢 -4.28 kB 🟢 -1.64 kB 🟢 -1.43 kB
assets/LeaveWorkspaceDialogContent-Bw3Y5qqE.js (new) 4.11 kB 🔴 +4.11 kB 🔴 +1.59 kB 🔴 +1.37 kB
assets/LeaveWorkspaceDialogContent-weg_b6Er.js (removed) 4.11 kB 🟢 -4.11 kB 🟢 -1.59 kB 🟢 -1.38 kB
assets/RemoveMemberDialogContent-Cl4UD9C5.js (removed) 4.09 kB 🟢 -4.09 kB 🟢 -1.54 kB 🟢 -1.34 kB
assets/RemoveMemberDialogContent-DW0fJeBZ.js (new) 4.09 kB 🔴 +4.09 kB 🔴 +1.54 kB 🔴 +1.33 kB
assets/RevokeInviteDialogContent-B6LQp6YX.js (removed) 4 kB 🟢 -4 kB 🟢 -1.55 kB 🟢 -1.36 kB
assets/RevokeInviteDialogContent-BAv-iX1Z.js (new) 4 kB 🔴 +4 kB 🔴 +1.55 kB 🔴 +1.36 kB
assets/saveMesh-BhGKyecf.js (removed) 3.38 kB 🟢 -3.38 kB 🟢 -1.45 kB 🟢 -1.29 kB
assets/saveMesh-Bzdvevqt.js (new) 3.38 kB 🔴 +3.38 kB 🔴 +1.45 kB 🔴 +1.29 kB
assets/WidgetTextarea-D07MktMK.js (new) 3.14 kB 🔴 +3.14 kB 🔴 +1.3 kB 🔴 +1.14 kB
assets/WidgetTextarea-COgaptkR.js (removed) 3.09 kB 🟢 -3.09 kB 🟢 -1.28 kB 🟢 -1.12 kB
assets/cloudSessionCookie-C7MGXxmB.js (removed) 3.07 kB 🟢 -3.07 kB 🟢 -1.09 kB 🟢 -978 B
assets/cloudSessionCookie-CpaOV_hv.js (new) 3.07 kB 🔴 +3.07 kB 🔴 +1.08 kB 🔴 +934 B
assets/ApiNodesSignInContent-BCOxIIgf.js (new) 2.69 kB 🔴 +2.69 kB 🔴 +1.05 kB 🔴 +918 B
assets/ApiNodesSignInContent-CWyRM9Uw.js (removed) 2.69 kB 🟢 -2.69 kB 🟢 -1.05 kB 🟢 -919 B
assets/NodeConflictFooter-BOtQMVYa.js (removed) 2.37 kB 🟢 -2.37 kB 🟢 -1.03 kB 🟢 -908 B
assets/NodeConflictFooter-khQBsT2v.js (new) 2.37 kB 🔴 +2.37 kB 🔴 +1.03 kB 🔴 +897 B
assets/GlobalToast-B-ZX5LJL.js (new) 2.34 kB 🔴 +2.34 kB 🔴 +967 B 🔴 +811 B
assets/GlobalToast-Dlqa77Dp.js (removed) 2.34 kB 🟢 -2.34 kB 🟢 -964 B 🟢 -802 B
assets/SubscribeToRun-BM1F_Lww.js (new) 2.16 kB 🔴 +2.16 kB 🔴 +990 B 🔴 +854 B
assets/SubscribeToRun-CWqp3-Y3.js (removed) 2.16 kB 🟢 -2.16 kB 🟢 -991 B 🟢 -868 B
assets/ImportFailedNodeFooter-Bsmaq7bl.js (new) 1.88 kB 🔴 +1.88 kB 🔴 +864 B 🔴 +755 B
assets/ImportFailedNodeFooter-DR052jYb.js (removed) 1.88 kB 🟢 -1.88 kB 🟢 -866 B 🟢 -750 B
assets/CloudRunButtonWrapper-DcPY2-FX.js (removed) 1.67 kB 🟢 -1.67 kB 🟢 -780 B 🟢 -709 B
assets/CloudRunButtonWrapper-UCspcvr6.js (new) 1.67 kB 🔴 +1.67 kB 🔴 +778 B 🔴 +705 B
assets/signInSchema-B-o1OXNS.js (new) 1.53 kB 🔴 +1.53 kB 🔴 +563 B 🔴 +518 B
assets/signInSchema-Dx5pd6PK.js (removed) 1.53 kB 🟢 -1.53 kB 🟢 -562 B 🟢 -510 B
assets/cloudBadges-D24p6wSQ.js (new) 1.37 kB 🔴 +1.37 kB 🔴 +700 B 🔴 +607 B
assets/cloudBadges-DRGw0Rrh.js (removed) 1.37 kB 🟢 -1.37 kB 🟢 -703 B 🟢 -614 B
assets/cloudSubscription-CCZk_xit.js (removed) 1.32 kB 🟢 -1.32 kB 🟢 -652 B 🟢 -563 B
assets/cloudSubscription-DIAdH3b2.js (new) 1.32 kB 🔴 +1.32 kB 🔴 +651 B 🔴 +563 B
assets/SubscriptionPanelContentWorkspace-BPSQ22FD.js (new) 1.07 kB 🔴 +1.07 kB 🔴 +483 B 🔴 +419 B
assets/SubscriptionPanelContentWorkspace-VXqb5LKb.js (removed) 1.07 kB 🟢 -1.07 kB 🟢 -481 B 🟢 -422 B
assets/Load3D-CAzHTQPo.js (removed) 1.04 kB 🟢 -1.04 kB 🟢 -483 B 🟢 -438 B
assets/Load3D-ClFX_6n6.js (new) 1.04 kB 🔴 +1.04 kB 🔴 +481 B 🔴 +426 B
assets/nightlyBadges-BTs2gd2d.js (new) 1 kB 🔴 +1 kB 🔴 +532 B 🔴 +467 B
assets/nightlyBadges-C6lXKAGi.js (removed) 1 kB 🟢 -1 kB 🟢 -536 B 🟢 -478 B
assets/Load3dViewerContent-BNdLOwdg.js (removed) 961 B 🟢 -961 B 🟢 -456 B 🟢 -408 B
assets/Load3dViewerContent-D_9np9aT.js (new) 961 B 🔴 +961 B 🔴 +453 B 🔴 +401 B
assets/SettingDialogContent-CguQDx7x.js (new) 917 B 🔴 +917 B 🔴 +441 B 🔴 +385 B
assets/SettingDialogContent-mG46Yhm0.js (removed) 917 B 🟢 -917 B 🟢 -441 B 🟢 -392 B
assets/graphHasMissingNodes-Be9AxQjS.js (removed) 761 B 🟢 -761 B 🟢 -373 B 🟢 -327 B
assets/graphHasMissingNodes-BeJ8zrCu.js (new) 761 B 🔴 +761 B 🔴 +375 B 🔴 +327 B
assets/WidgetLegacy-CXvbQMOv.js (removed) 747 B 🟢 -747 B 🟢 -386 B 🟢 -336 B
assets/WidgetLegacy-D8O4xMfx.js (new) 747 B 🔴 +747 B 🔴 +383 B 🔴 +332 B
assets/WidgetInputNumber-avSFuTzY.js (new) 392 B 🔴 +392 B 🔴 +228 B 🔴 +196 B
assets/WidgetInputNumber-C1wm12U2.js (removed) 392 B 🟢 -392 B 🟢 -230 B 🟢 -189 B
assets/i18n-CEuPC6JE.js (removed) 199 B 🟢 -199 B 🟢 -160 B 🟢 -160 B
assets/i18n-D1H7iD0E.js (new) 199 B 🔴 +199 B 🔴 +160 B 🔴 +138 B
assets/AnimationControls-bPyINTJI.js 4.61 kB 4.61 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/auto-DjoqfnTX.js 1.7 kB 1.7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/BaseViewTemplate-BnXUotno.js 1.75 kB 1.75 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/comfy-logo-single-DCVL1uOL.js 198 B 198 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/ComfyOrgHeader-32ZIoIYN.js 909 B 909 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-BTIhwSf_.js 15.9 kB 15.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-BxiMWv9a.js 14.6 kB 14.6 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-BYGUQRX1.js 15.3 kB 15.3 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-CtxsvHdf.js 15.2 kB 15.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-D4xkLWYG.js 14.4 kB 14.4 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-D7Ez6YeH.js 17.9 kB 17.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-DFfk2Km5.js 15.4 kB 15.4 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-Ds7u8tBA.js 16.7 kB 16.7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-DuYqNMWX.js 16.7 kB 16.7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-ovF76AYH.js 16.2 kB 16.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-tMQq9SrH.js 15.4 kB 15.4 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/ImportFailedNodeContent-VPjQzi79.js 2.48 kB 2.48 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/ImportFailedNodeHeader-DUns4_x2.js 1.08 kB 1.08 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-2HxSpwOp.js 133 kB 133 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-5vUvgJMx.js 155 kB 155 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-B_En4SpT.js 148 kB 148 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-BpnmNj1n.js 113 kB 113 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-BuWOig7p.js 129 kB 129 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-BYoy9XSQ.js 136 kB 136 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-CKN_4E4Z.js 114 kB 114 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-CN7pSufO.js 180 kB 180 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-dc7AuxCr.js 128 kB 128 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-Dn8ME7jP.js 131 kB 131 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-Dt6bQoC3.js 161 kB 161 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/Media3DTop-DTYkrVtB.js 1.82 kB 1.82 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/MediaAudioTop-AFmsiWi3.js 1.43 kB 1.43 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/MediaImageTop-ATOoJCQr.js 1.75 kB 1.75 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/MediaVideoTop-CQw3f2T6.js 2.23 kB 2.23 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/MissingNodesHeader-BOlbqJ0O.js 1.09 kB 1.09 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/mixpanel.module-Dq6XmUX_.js 92 B 92 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/NodeConflictHeader-DRxQs5TH.js 1.09 kB 1.09 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-aApbAbNI.js 360 kB 360 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-B2JRfCRl.js 332 kB 332 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-BbVIS5BG.js 357 kB 357 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-BddTsShn.js 374 kB 374 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-BrQNg87y.js 329 kB 329 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-CEMSHoZg.js 360 kB 360 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-Cfjv7JEn.js 364 kB 364 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-PGdfR_x_.js 441 kB 441 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-SDKvs0-9.js 404 kB 404 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/OBJLoader2WorkerModule-DTMpvldF.js 109 kB 109 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/PanelTemplate-C1h0RxBM.js 1.2 kB 1.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/previousFullPath-DsBk66MD.js 665 B 665 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/rolldown-runtime-Ca2S-reV.js 1.87 kB 1.87 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/SelectValue-1KJOqzqF.js 8.94 kB 8.94 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/SettingDialogHeader-BHt-6Ao_.js 1.62 kB 1.62 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/SettingDialogHeader-D5wathvf.js 244 B 244 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/Slider-Bh_ZdHn9.js 3.52 kB 3.52 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/src-DAMctjF_.js 251 B 251 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/types-VDank0gz.js 318 B 318 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/widget-RLUqfB5N.js 445 B 445 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetBoundingBox-2w5BjjHm.js 3.94 kB 3.94 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetBoundingBox-Djm16aYN.js 131 B 131 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetChart-Dsp6bf_j.js 2.21 kB 2.21 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetColorPicker-jDbRm4n6.js 2.9 kB 2.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetGalleria-C8ikSQqn.js 3.61 kB 3.61 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetImageCompare-B1RSu0_k.js 3.1 kB 3.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetInputText-MXN3EUoN.js 1.85 kB 1.85 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetLayoutField-BcUSnWUK.js 1.95 kB 1.95 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetMarkdown-wePHc2fh.js 2.88 kB 2.88 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/widgetPropFilter-DyQHILEf.js 1.1 kB 1.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetToggleSwitch-CoKD027B.js 2.5 kB 2.5 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/widgetTypes-BCsKJASV.js 393 B 393 B ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 59 added / 59 removed

@Myestery Myestery marked this pull request as ready for review February 3, 2026 02:21
@dosubot dosubot bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Feb 3, 2026
@Myestery Myestery changed the title fix: resolve TypeScript errors in widgets and services Road to No Explicit Any Part 11 Feb 3, 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: 9

Caution

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

⚠️ Outside diff range comments (6)
src/platform/workflow/management/stores/workflowStore.ts (1)

720-742: 🧹 Nitpick | 🔵 Trivial

LGTM! The explicit return type annotation is correct.

All return paths align with string | undefined:

  • Line 726: returns id (string) or undefined
  • Line 728: implicit undefined
  • Line 740: subgraphNodeIds.at(-1) returns string | undefined
  • End of function: implicit undefined

Note: There's a pre-existing FIXME comment at Line 720. Would you like assistance refactoring this to use an existing utility function, or should I open an issue to track this?

src/renderer/extensions/vueNodes/widgets/components/WidgetSelectDropdown.vue (2)

76-83: 🧹 Nitpick | 🔵 Trivial

Type-check nodeType before invoking useAssetWidgetData.

The assertion can hide non-string values and push invalid data into the composable. A simple typeof guard keeps the runtime safe.

Proposed fix
-  const nodeType = (props.widget.options?.nodeType ?? props.nodeType) as
-    | string
-    | undefined
-  if (props.isAssetMode && nodeType) {
-    return useAssetWidgetData(toRef(nodeType))
-  }
+  const nodeType = props.widget.options?.nodeType ?? props.nodeType
+  if (props.isAssetMode && typeof nodeType === 'string') {
+    return useAssetWidgetData(toRef(() => nodeType))
+  }

285-290: 🧹 Nitpick | 🔵 Trivial

Only return placeholder when it’s a string.

The assertion can let non-string values flow into the UI. Guarding keeps the placeholder stable.

Proposed fix
-  if (options?.placeholder) {
-    return options.placeholder as string
-  }
+  if (typeof options?.placeholder === 'string') {
+    return options.placeholder
+  }
src/platform/settings/settingStore.ts (1)

99-107: ⚠️ Potential issue | 🟠 Major

Use deep equality comparison to detect unchanged object/array settings.

The get() function returns a deep clone (line 123), so the reference equality check on line 107 will always fail for objects and arrays, even when values are unchanged. This triggers unnecessary onChange callbacks and API calls.

Use _.isEqual() to compare the migrated value against the original stored/default value instead:

🔧 Suggested fix
-    const oldValue = get(key)
-    if (newValue === oldValue) return
+    const storedValue = settingValues.value[key] as Settings[K] | undefined
+    const oldValueForCompare = storedValue ?? getDefaultValue(key)
+    if (_.isEqual(newValue, oldValueForCompare)) return
+    const oldValue = get(key)

_.isEqual is available in es-toolkit/compat (already imported on line 2).

src/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberInput.vue (2)

185-188: ⚠️ Potential issue | 🟠 Major

Localize the tooltip string with vue-i18n.

The tooltip is user-facing and must be added to src/locales/en/main.json under the widgets namespace, then referenced via t() in the component. Add t to the useI18n() destructuring and update the return statement to use t('widgets.inputNumber.precisionLimitTooltip').

Suggested i18n update
-const { n } = useI18n()
+const { n, t } = useI18n()

  if (buttonsDisabled.value) {
-    return 'Increment/decrement disabled: value exceeds JavaScript precision limit (±2^53)'
+    return t('widgets.inputNumber.precisionLimitTooltip')
  }

Per coding guidelines: Use vue-i18n for ALL user-facing strings, configured in src/locales/en/main.json.


104-126: ⚠️ Potential issue | 🔴 Critical

Replace return 0 with safe fallback to match canonical getWidgetStep() logic.

Returning 0 when precision is undefined and step is ≤ 10 causes silent no-op stepping while buttons remain enabled. This contradicts the established pattern in src/lib/litegraph/src/utils/widget.ts which always returns a minimum step of 1. Widgets that set step without precision will be broken.

Recommended fix
  if (precision.value !== undefined) {
    if (precision.value === 0) {
      return 1
    }
    return Number((1 / Math.pow(10, precision.value)).toFixed(precision.value))
  }
-  return 0
+  if (step !== undefined) return Number(step)
+  return 1
🤖 Fix all issues with AI agents
In `@scripts/i18n-types.ts`:
- Line 5: The LocaleData type is too narrow (string | LocaleData) and conflicts
with the codebase's use of Record<string, unknown>; update the LocaleData alias
in scripts/i18n-types.ts so it uses the broader recursive shape (Record<string,
unknown>) to match src/i18n.ts and other loader patterns and avoid rejecting
non-string leaves—locate the LocaleData type definition and replace its current
union with Record<string, unknown>.

In `@src/lib/litegraph/src/widgets/ComboWidget.ts`:
- Around line 38-43: Remove the redundant type assertions on getOptionLabel:
instead of casting this.options.getOptionLabel to ((value?: string | null) =>
string) | undefined, assign it directly (const getOptionLabel =
this.options.getOptionLabel) and let the declared IWidgetOptions type provide
the signature; keep the existing null/undefined check and try/catch logic. Do
the same for the other occurrence around the later block (the code handling
option labels at the other location) so both uses rely on the IWidgetOptions
typing rather than explicit casts.

In
`@src/platform/workflow/persistence/composables/useWorkflowPersistence.test.ts`:
- Around line 192-195: Replace the unsafe cast to Record<string, unknown> for
the test variable drafts with the canonical draft type exported from the
persistence store: import the exported type (e.g., DraftRecord, DraftsMap, or
the appropriate name) from the module that defines the persistence shapes and
use that type in the JSON.parse cast for drafts; update the top-of-file imports
to include that type and change the cast on the const drafts declaration so
assertions in useWorkflowPersistence.test.ts are strongly typed and match
production shapes.

In `@src/renderer/extensions/vueNodes/widgets/components/WidgetSelectDefault.vue`:
- Around line 48-52: The default function for the defineModel called modelValue
blindly casts props.widget.options?.values to string[] and indexes it; change it
to first check Array.isArray(props.widget.options?.values) before accessing [0],
remove the unsafe cast, and return the first element if it's an array or
undefined otherwise (respecting the string | undefined type); update the
default(props: Props) implementation to use a guarded lookup on
widget.options.values.

In
`@src/renderer/extensions/vueNodes/widgets/components/WidgetSelectDropdown.vue`:
- Around line 58-62: The default() for defineModel's modelValue reads
props.widget.options?.values and indexes it directly, which can return a
character if values is a string; change the guard to check
Array.isArray(props.widget.options?.values) before indexing (use the array only
when true), otherwise return undefined or '' to match the model type; update the
default function and references to props.widget.options?.values to rely on the
Array.isArray check to ensure runtime safety.
- Around line 121-125: The code in getDisplayLabel casts
props.widget.options?.getOptionLabel to a function but doesn't verify it's
actually callable; replace the cast with a runtime check using typeof to ensure
props.widget.options?.getOptionLabel is a function before invoking it (e.g.,
check typeof props.widget.options?.getOptionLabel === 'function'), and fallback
to returning the raw value if not callable; update getDisplayLabel to call the
validated function reference (from props.widget.options?.getOptionLabel) only
when the typeof guard passes.

In `@src/renderer/extensions/vueNodes/widgets/composables/useRemoteWidget.ts`:
- Around line 131-134: The onFirstLoad handler currently sets widget.value to
data[0] when data is an array, which yields undefined for an empty array; update
onFirstLoad to treat empty arrays as a fallback by checking Array.isArray(data)
&& data.length > 0 and otherwise assigning a safe default (e.g., a provided
defaultValue or a new instance) before calling widget.callback; adjust
references in onFirstLoad, widget.value, isLoaded and widget.callback to ensure
widget.value is never set to undefined on first load.

In `@src/services/load3dService.ts`:
- Around line 188-190: The guard "if (!viewer) return" in handleViewerClose is
dead code because getOrCreateViewer always returns an instance; remove the
unreachable check or, if you want defensive behavior, call a new getViewer
method (which returns undefined) instead of getOrCreateViewer and keep the
guard; update handleViewerClose to use either getOrCreateViewer without the
if-statement or replace getOrCreateViewer with getViewer and retain the guard
accordingly.

In
`@src/workbench/extensions/manager/components/manager/skeleton/PackCardGridSkeleton.test.ts`:
- Around line 16-21: Replace the mountComponent arrow-function expression with a
named function declaration to follow repo guidance: change the const
mountComponent = ({ props = {} }: { props?: Partial<ComponentProps<typeof
GridSkeleton>> } = {}): VueWrapper => { ... } into a function mountComponent({
props = {} }: { props?: Partial<ComponentProps<typeof GridSkeleton>> } = {}):
VueWrapper { ... } and keep the same body (including i18n creation),
exports/usages, and types intact so all existing references to mountComponent
continue to work.

Copy link
Collaborator

@AustinMroz AustinMroz left a comment

Choose a reason for hiding this comment

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

Going to need to invest more time in this one later.
The simplifiedWidget typing needs some more love. I'd rather we didn't have to rewrite the widgets because strongly typed options get lost in translation. At a minimum, I'd like the generic typing to be updated to
O extends IWidgetOptions = IWidgetOptions
But ideally, there'd be a way to transfer the already strongly typed litegraph options 🤔

… components

Replace toRaw() prop mutations with proper Vue emit events pattern:
- TabSubgraphInputs now emits update:proxyWidgets event
- WidgetItem now emits update:widgetValue event
- Parent components handle events and perform mutations
- Follows Vue's one-way data flow principle

This change removes the vue/no-mutating-props lint violations without
using toRaw() to bypass Vue's reactivity system. While this improves
code maintainability and follows Vue best practices, it does not
address the underlying unified state management issues with widget
values across the application.
- settingStore: change settingValues to Partial<Settings>, simplify get() with non-null assertion
- litegraph: remove vestigial GraphOrSubgraph export, use LGraph directly in tests
- widgets: replace type assertions with runtime guards (typeof, Array.isArray)
- useRemoteWidget: handle empty arrays with fallback to defaultValue
- load3dService: remove unreachable null check
- tests: use real types (WorkflowDraftSnapshot) instead of Record<string, unknown>
- tests: convert arrow function to function declaration per guidelines
- Change SimplifiedWidget generic from Record<string, unknown> to IWidgetOptions
- Remove index signature from IWidgetOptions (was causing all props to become unknown)
- Add missing Vue widget properties to IWidgetOptions (disabled, useGrouping, placeholder, etc.)
- Update filterWidgetProps to accept object instead of Record<string, unknown>

This provides proper type safety for widget options without needing runtime guards or type assertions.
- WidgetSelectDefault: remove Array.isArray check, use optional chaining
- WidgetSelectDropdown: remove typeof check for getOptionLabel
- ComboWidget: simplify getOptionLabel usage

TypeScript now properly infers types from IWidgetOptions, eliminating the need for runtime type guards.
- WidgetChart: extend chart options with IWidgetOptions
- WidgetColorPicker: change from Record<string, unknown> to IWidgetOptions
- NodeWidgets: add type assertion for widgetOptions to satisfy SimplifiedWidget

Ensures all widget components properly extend IWidgetOptions for type safety.
- WidgetInputText.test: cast options to IWidgetOptions
- WidgetSelectDropdown.test: update getOptionLabel signature to match IWidgetOptions

Aligns test mocks with updated SimplifiedWidget type signature.
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

Caution

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

⚠️ Outside diff range comments (3)
src/platform/workflow/persistence/composables/useWorkflowPersistence.test.ts (1)

166-168: 🧹 Nitpick | 🔵 Trivial

Inconsistent typing: Use WorkflowDraftSnapshot here as well.

This test parses the same Comfy.Workflow.Drafts localStorage key as the test on line 193-195, but uses an inline type instead of WorkflowDraftSnapshot. For consistency and to prevent type drift, use the same canonical type.

♻️ Suggested fix
     const drafts = JSON.parse(
       localStorage.getItem('Comfy.Workflow.Drafts') ?? '{}'
-    ) as Record<string, { data: string; isTemporary: boolean }>
+    ) as Record<string, WorkflowDraftSnapshot>

Based on learnings: "In TypeScript test files (e.g., any test under src), avoid duplicating interface/type definitions. Import real type definitions from the component modules under test and reference them directly, so there is a single source of truth and to prevent type drift."

src/components/rightSidePanel/parameters/TabSubgraphInputs.vue (1)

188-190: 🧹 Nitpick | 🔵 Trivial

Minor: Redundant setDirty call.

The parent handler (handleProxyWidgetsUpdate in RightSidePanel.vue) already calls setDirty(true, true) after handling the emitted event. This call on line 189 results in double-marking the canvas dirty. While harmless, consider removing it for consistency with the event-driven pattern where the parent owns all side effects.

♻️ Optional: Remove redundant setDirty call
     proxyWidgets.value = pw
-    canvasStore.canvas?.setDirty(true, true)
     triggerRef(proxyWidgets)
src/renderer/extensions/vueNodes/widgets/components/WidgetInputText.test.ts (1)

14-24: 🧹 Nitpick | 🔵 Trivial

Align parameter type with IWidgetOptions for consistency.

The helper accepts Partial<InputTextProps> but casts to IWidgetOptions. For better type safety and to prevent type drift, consider updating the parameter type to Partial<IWidgetOptions>.

Proposed fix
 const createMockWidget = (
   value: string = 'default',
-  options: Partial<InputTextProps> = {},
+  options: Partial<IWidgetOptions> = {},
   callback?: (value: string) => void
 ): SimplifiedWidget<string> => ({
   name: 'test_input',
   type: 'string',
   value,
   options: options as IWidgetOptions,
   callback
 })

Based on learnings: In test files, import real type definitions from the component modules under test instead of using unrelated types to prevent type drift.

🤖 Fix all issues with AI agents
In `@src/platform/settings/settingStore.ts`:
- Around line 119-121: The get function uses a non-null assertion on
getDefaultValue(key) which can be undefined; update get to return Settings[K] |
undefined (change signature function get<K extends keyof Settings>(key: K):
Settings[K] | undefined) and return _.cloneDeep(settingValues.value[key] ??
getDefaultValue(key)); alternatively, if you want to guarantee a value, call
getDefaultValue and throw a descriptive error when it returns undefined
(referencing get and getDefaultValue to locate the code) so you avoid the `!`
operator and ensure type safety.

In `@src/renderer/extensions/vueNodes/components/NodeWidgets.vue`:
- Around line 175-177: The current inline cast of widgetOptions masks typing —
instead of asserting to IWidgetOptions | undefined, declare widgetOptions with
an explicit type and construct it accordingly: use the existing symbols
(widgetOptions, slotMetadata, options, IWidgetOptions) and build widgetOptions
as either undefined or an IWidgetOptions object (e.g., when slotMetadata?.linked
return a new object merging options with disabled: true, otherwise return
options) so the compiler infers correct types without the `as` assertion.

In `@src/renderer/extensions/vueNodes/widgets/composables/useRemoteWidget.ts`:
- Around line 143-153: The initialization check treats falsy cached values as
uninitialized because isInitialized uses a truthiness test on entry?.data;
update isInitialized to explicitly check entry?.data !== undefined (not
Boolean(entry?.data)) so valid falsy values like 0, false, or '' are considered
initialized, and then leave useRemoteWidget's logic (the checks around
isInitialized(entry), isFailed(entry), isBackingOff(entry), isFetching(entry),
and the CacheEntry/dataCache handling) unchanged so onFirstLoad and fetch gating
work correctly.

Comment on lines 119 to +121
function get<K extends keyof Settings>(key: K): Settings[K] {
// Clone the value when returning to prevent external mutations
return _.cloneDeep(settingValues.value[key] ?? getDefaultValue(key))
return _.cloneDeep(settingValues.value[key] ?? getDefaultValue(key)!)
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cd /tmp && find . -name "settingStore.ts" -type f 2>/dev/null | head -5

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 52


🏁 Script executed:

git ls-files | grep -i settingstore

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 150


🏁 Script executed:

fd "settingStore" --type f

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 150


🏁 Script executed:

fd "settingStore.ts"

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 107


🏁 Script executed:

wc -l src/platform/settings/settingStore.ts

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 111


🏁 Script executed:

cat -n src/platform/settings/settingStore.ts

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 10462


🏁 Script executed:

cat -n src/platform/settings/settingStore.test.ts

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 21597


🏁 Script executed:

rg "\.get\(" src --type ts --type tsx -B 2 -A 2 | head -100

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 97


🏁 Script executed:

rg "\.get\(" src --type ts --type js -B 2 -A 2 | head -150

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 10471


Avoid the non-null assertion on default lookup.

The signature promises Settings[K], but getDefaultValue() explicitly returns Settings[K] | undefined (see line 137–139). If a setting lacks a registered default, getDefaultValue(key) returns undefined, and the ! hides this type violation. Either widen the return type to Settings[K] | undefined or ensure all settings have registered defaults enforced at the type level.

✅ Suggested fix (type-safe fallback)
-  function get<K extends keyof Settings>(key: K): Settings[K] {
-    // Clone the value when returning to prevent external mutations
-    return _.cloneDeep(settingValues.value[key] ?? getDefaultValue(key)!)
-  }
+  function get<K extends keyof Settings>(key: K): Settings[K] | undefined {
+    // Clone the value when returning to prevent external mutations
+    const value = settingValues.value[key]
+    if (value !== undefined) return _.cloneDeep(value)
+    const defaultValue = getDefaultValue(key)
+    return defaultValue === undefined ? undefined : _.cloneDeep(defaultValue)
+  }
🤖 Prompt for AI Agents
In `@src/platform/settings/settingStore.ts` around lines 119 - 121, The get
function uses a non-null assertion on getDefaultValue(key) which can be
undefined; update get to return Settings[K] | undefined (change signature
function get<K extends keyof Settings>(key: K): Settings[K] | undefined) and
return _.cloneDeep(settingValues.value[key] ?? getDefaultValue(key));
alternatively, if you want to guarantee a value, call getDefaultValue and throw
a descriptive error when it returns undefined (referencing get and
getDefaultValue to locate the code) so you avoid the `!` operator and ensure
type safety.

…iles

# Conflicts:
#	browser_tests/fixtures/ComfyPage.ts
#	browser_tests/fixtures/ws.ts
#	browser_tests/tests/actionbar.spec.ts
#	src/services/load3dService.ts
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 `@browser_tests/fixtures/ws.ts`:
- Around line 3-5: Replace the unsafe non-null assertion when pulling a captured
WebSocket from the registry (the use of window.__ws__![url]) with explicit
null/undefined checks: first cast to TestWindow and read the registry into a
local variable (e.g., const registry = (window as TestWindow).__ws__), throw a
clear error if registry is undefined, then lookup the socket by URL (e.g., const
ws = registry[url]) and throw another clear error if ws is undefined before
returning/using it; this uses optional chaining/explicit validation rather than
! to prevent flaky failures.

In `@src/services/load3dService.ts`:
- Line 84: The Map typing uses typeof useLoad3dViewer which fails because
useLoad3dViewer is dynamically imported; change the Map value type to the
existing alias UseLoad3dViewerFn instead. Update the declaration of
viewerInstances (currently const viewerInstances = new Map<NodeId,
ReturnType<typeof useLoad3dViewer>>()) to use ReturnType<UseLoad3dViewerFn> or
directly UseLoad3dViewerFn as appropriate so the type no longer references the
out-of-scope useLoad3dViewer symbol.
🧹 Nitpick comments (1)
browser_tests/fixtures/ws.ts (1)

8-8: Validate unknown payloads before JSON.stringify.

With unknown, non-serializable values (e.g., BigInt or circular objects) will throw inside JSON.stringify, producing a cryptic failure. Consider guarding serialization and surfacing a clearer error.

♻️ Suggested hardening
         async trigger(data, url) {
+          let payload = ''
+          try {
+            payload = JSON.stringify(data)
+          } catch (error) {
+            throw new Error(
+              'webSocketFixture.trigger expects JSON-serializable data',
+              { cause: error }
+            )
+          }
           // Trigger a websocket event on the page
           await page.evaluate(
             function ([data, url]) {
               if (!url) {
                 // If no URL specified, use page URL
                 const u = new URL(window.location.toString())
                 u.protocol = 'ws:'
                 u.pathname = '/'
                 url = u.toString() + 'ws'
               }
               const ws: WebSocket = window.__ws__![url]
               ws.dispatchEvent(
                 new MessageEvent('message', {
                   data
                 })
               )
             },
-            [JSON.stringify(data), url]
+            [payload, url]
           )
         }

Also applies to: 30-49

- Fix LGraphCanvas to use _visibleReroutes instead of #visibleReroutes
- Fix load3dService viewer type to use ReturnType<UseLoad3dViewerFn>
- Make getOrCreateViewerSync generic to preserve actual return type
- Remove index signature from UseLoad3dViewerFn type
const widgetOptions = slotMetadata?.linked
? { ...options, disabled: true }
: options
const widgetOptions = (
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'd remove the cast here, remove the generic in useGraphNodeManager, and fix LGraphNodePreview instead

diff
diff --git a/src/composables/graph/useGraphNodeManager.ts b/src/composables/graph/useGraphNodeManager.ts
index 33822d1c5..7fec92440 100644
--- a/src/composables/graph/useGraphNodeManager.ts
+++ b/src/composables/graph/useGraphNodeManager.ts
@@ -52,7 +52,7 @@ export interface SafeWidgetData {
   isDOMWidget?: boolean
   label?: string
   nodeType?: string
-  options?: IWidgetOptions<unknown>
+  options?: IWidgetOptions
   spec?: InputSpec
   slotMetadata?: WidgetSlotMetadata
 }
diff --git a/src/renderer/extensions/vueNodes/components/LGraphNodePreview.vue b/src/renderer/extensions/vueNodes/components/LGraphNodePreview.vue
index da7423850..34ee83543 100644
--- a/src/renderer/extensions/vueNodes/components/LGraphNodePreview.vue
+++ b/src/renderer/extensions/vueNodes/components/LGraphNodePreview.vue
@@ -37,6 +37,7 @@ import type {
   INodeOutputSlot
 } from '@/lib/litegraph/src/interfaces'
 import { RenderShape } from '@/lib/litegraph/src/litegraph'
+import type { IWidgetOptions } from '@/lib/litegraph/src/types/widgets'
 import NodeHeader from '@/renderer/extensions/vueNodes/components/NodeHeader.vue'
 import NodeSlots from '@/renderer/extensions/vueNodes/components/NodeSlots.vue'
 import NodeWidgets from '@/renderer/extensions/vueNodes/components/NodeWidgets.vue'
@@ -69,8 +70,11 @@ const nodeData = computed<VueNodeData>(() => {
       options: {
         hidden: input.hidden,
         advanced: input.advanced,
-        values: input.type === 'COMBO' ? input.options : undefined // For combo widgets
-      }
+        values:
+          input.type === 'COMBO' && Array.isArray(input.options)
+            ? input.options
+            : undefined
+      } satisfies IWidgetOptions
     }))
 
   const inputs: INodeInputSlot[] = Object.entries(nodeDef.inputs || {})
diff --git a/src/renderer/extensions/vueNodes/components/NodeWidgets.vue b/src/renderer/extensions/vueNodes/components/NodeWidgets.vue
index c44419b71..37da74490 100644
--- a/src/renderer/extensions/vueNodes/components/NodeWidgets.vue
+++ b/src/renderer/extensions/vueNodes/components/NodeWidgets.vue
@@ -79,7 +79,6 @@ import type {
   VueNodeData,
   WidgetSlotMetadata
 } from '@/composables/graph/useGraphNodeManager'
-import type { IWidgetOptions } from '@/lib/litegraph/src/types/widgets'
 import { useSettingStore } from '@/platform/settings/settingStore'
 import { useErrorHandling } from '@/composables/useErrorHandling'
 import { st } from '@/i18n'
@@ -172,9 +171,9 @@ const processedWidgets = computed((): ProcessedWidget[] => {
     // Core feature: Disable Vue widgets when their input slots are connected
     // This prevents conflicting input sources - when a slot is linked to another
     // node's output, the widget should be read-only to avoid data conflicts
-    const widgetOptions = (
-      slotMetadata?.linked ? { ...options, disabled: true } : options
-    ) as IWidgetOptions | undefined
+    const widgetOptions = slotMetadata?.linked
+      ? { ...options, disabled: true }
+      : options
 
     const simplified: SimplifiedWidget = {
       name: widget.name,

Comment on lines 76 to 78
const nodeType = (props.widget.options?.nodeType ?? props.nodeType) as
| string
| undefined
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
const nodeType = (props.widget.options?.nodeType ?? props.nodeType) as
| string
| undefined
const nodeType: string | undefined =
props.widget.options?.nodeType ?? props.nodeType

}

return values.map((value: string, index: number) => ({
return (values as string[]).map((value, index) => ({
Copy link
Collaborator

Choose a reason for hiding this comment

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

  return values.map((value, index) => ({
    id: `input-${index}`,
    preview_url: getMediaUrl(String(value), 'input'),
    name: String(value),
    label: getDisplayLabel(String(value))
  }))


if (options?.placeholder) {
return options.placeholder
return options.placeholder as string
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
return options.placeholder as string
return options.placeholder

Comment on lines 62 to 64
const isReadOnly = computed(() => {
return (widget.options?.read_only as boolean | undefined) ?? false
})
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
const isReadOnly = computed(() => {
return (widget.options?.read_only as boolean | undefined) ?? false
})
const isReadOnly = computed(() => widget.options?.read_only ?? false)

function addNodeOnGraph(
nodeDef: ComfyNodeDefV1 | ComfyNodeDefV2,
options: Record<string, any> = {}
options?: { pos?: Point }
Copy link
Collaborator

@AustinMroz AustinMroz Feb 5, 2026

Choose a reason for hiding this comment

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

Options can be used to pass arbitrary values to the createNode call, so filtering options other than pos is a regression

  function addNodeOnGraph(
    nodeDef: ComfyNodeDefV1 | ComfyNodeDefV2,
    options: Record<string, unknown> & { pos?: Point } = {}
  ): LGraphNode {
    options.pos ??= getCanvasCenter()

    if (nodeDef.name.startsWith(useSubgraphStore().typePrefix)) {
      const canvas = canvasStore.getCanvas()
      const bp = useSubgraphStore().getBlueprint(nodeDef.name)
      const items: object = {
        nodes: bp.nodes,
        subgraphs: bp.definitions?.subgraphs
      }
      const results = canvas._deserializeItems(items, {
        position: options.pos
      })
      if (!results) throw new Error('Failed to add subgraph blueprint')
      const node = results.nodes.values().next().value
      if (!node)
        throw new Error(
          'Subgraph blueprint was added, but failed to resolve a subgraph Node'
        )
      return node
    }

    const node = LiteGraph.createNode(
      nodeDef.name,
      nodeDef.display_name,
      options
    )

EDIT: Or maybe IWidgetOptions? forgot to test this.

readonly inputs: Record<string, InputSpecV2>
readonly outputs: OutputSpecV2[]
readonly hidden?: Record<string, any>
readonly hidden?: Record<string, unknown>
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
readonly hidden?: Record<string, unknown>
readonly hidden?: Record<string, boolean>

Comment on lines 83 to 85
const isDisabled = computed(() => {
return (props.widget.options?.disabled as boolean | undefined) ?? false
})
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
const isDisabled = computed(() => {
return (props.widget.options?.disabled as boolean | undefined) ?? false
})
const isDisabled = computed(() => props.widget.options?.disabled ?? false)

@AustinMroz AustinMroz assigned Myestery and unassigned AustinMroz Feb 5, 2026
comfy-pr-bot and others added 3 commits February 5, 2026 22:18
Patch version increment to 1.39.6

**Base branch:** `main`

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Chores**
  * Version bumped to 1.39.6.

* **New Features**
* Added multilingual UI strings for secrets management, asset import
errors, app-mode prompts, and HitPaw tools.
* New node types for image/video/audio workflows and expanded export
formats (GLB/FBX/OBJ) for 3D/model outputs.

* **Bug Fixes / Removals**
* Removed the "Open 3D Viewer (Beta) for Selected Node" menu entry and
related 3D viewer settings.
* Added setting to enable automatic node replacement when mappings
exist.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8595-1-39-6-2fd6d73d3650818cba9cffca313909e8)
by [Unito](https://www.unito.io)

---------

Co-authored-by: christian-byrne <72887196+christian-byrne@users.noreply.github.com>
Co-authored-by: github-actions <github-actions@github.com>
…arison

Switch from reference-based to content-based duplicate detection in contextMenuCompat.
This properly identifies and filters out duplicate menu items even when they are
different objects with the same content, which commonly occurs with extension patches.

- Compare menu items by their 'content' property instead of object reference
- Create Sets of content strings for efficient duplicate detection
- Improve removal detection to accurately count removed items

Fixes issues where context menu items were duplicated by some extensions.
- Remove unnecessary type casts in widget components
- Use IWidgetOptions consistently instead of Record<string, any>
- Add Array.isArray guard and satisfies in LGraphNodePreview
- Restore extension pass-through in addNodeOnGraph options
- Narrow nodeDefStore.hidden to Record<string, boolean>
- Fix falsy check in useRemoteWidget isInitialized
@Myestery Myestery requested a review from a team as a code owner February 5, 2026 21:46
@dosubot dosubot bot added size:XXL This PR changes 1000+ lines, ignoring generated files. and removed size:L This PR changes 100-499 lines, ignoring generated files. labels Feb 5, 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: 8

Caution

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

⚠️ Outside diff range comments (9)
src/composables/graph/useGraphNodeManager.ts (1)

162-174: ⚠️ Potential issue | 🟡 Minor

Guard widget.options before asserting to IWidgetOptions.

widget.options as IWidgetOptions can pass through null/primitive values from extensions, which then get treated as an object downstream and can throw. Safer to only assign when it’s an object and otherwise leave options undefined.

🛡️ Suggested guard
   return {
     value: useReactiveWidgetValue(widget),
     controlWidget: getControlWidget(widget),
     spec: nodeDefStore.getInputSpecForWidget(node, widget.name),
     nodeType: getNodeType(node, widget),
     borderStyle: widget.promoted
       ? 'ring ring-component-node-widget-promoted'
       : widget.advanced
         ? 'ring ring-component-node-widget-advanced'
         : undefined,
     label: widget.label,
-    options: widget.options as IWidgetOptions
+    options:
+      widget.options && typeof widget.options === 'object'
+        ? (widget.options as IWidgetOptions)
+        : undefined
   }
src/renderer/extensions/vueNodes/components/LGraphNodePreview.vue (1)

59-77: ⚠️ Potential issue | 🟡 Minor

Use the resolved widget type when populating combo values.

type is derived from input.widgetType || input.type, but values (and the combo default) check only input.type. If a widget overrides widgetType (common for COMBO), the preview will omit options.

✅ Align with resolved widget type
-  const widgets = Object.entries(nodeDef.inputs || {})
+  const widgets = Object.entries(nodeDef.inputs || {})
     .filter(([_, input]) => widgetStore.inputIsWidget(input))
-    .map(([name, input]) => ({
-      name,
-      type: input.widgetType || input.type,
-      value:
-        input.default !== undefined
-          ? input.default
-          : input.type === 'COMBO' &&
-              Array.isArray(input.options) &&
-              input.options.length > 0
-            ? input.options[0]
-            : '',
-      options: {
-        hidden: input.hidden,
-        advanced: input.advanced,
-        values:
-          input.type === 'COMBO' && Array.isArray(input.options)
-            ? input.options
-            : undefined
-      } satisfies IWidgetOptions
-    }))
+    .map(([name, input]) => {
+      const widgetType = input.widgetType || input.type
+      const comboValues =
+        widgetType === 'COMBO' && Array.isArray(input.options)
+          ? input.options
+          : undefined
+
+      return {
+        name,
+        type: widgetType,
+        value:
+          input.default !== undefined
+            ? input.default
+            : comboValues && comboValues.length > 0
+              ? comboValues[0]
+              : '',
+        options: {
+          hidden: input.hidden,
+          advanced: input.advanced,
+          values: comboValues
+        } satisfies IWidgetOptions
+      }
+    })
src/locales/fa/nodeDefs.json (1)

6430-6447: ⚠️ Potential issue | 🟡 Minor

Fix missing name keys for Load3D button labels.

Line 6431, Line 6443, and Line 6447 use an empty-string key, which won’t match the name schema used elsewhere in this file.

🛠️ Proposed fix
@@
       "clear": {
-        "": "پاک‌سازی"
+        "name": "پاک‌سازی"
       },
@@
       "upload 3d model": {
-        "": "بارگذاری مدل سه‌بعدی"
+        "name": "بارگذاری مدل سه‌بعدی"
       },
       "upload extra resources": {
-        "": "بارگذاری منابع اضافی"
+        "name": "بارگذاری منابع اضافی"
       },
src/locales/pt-BR/main.json (1)

16-2051: ⚠️ Potential issue | 🟡 Minor

Avoid manual edits to generated locale files (pt-BR).

These non‑English locale files are auto‑generated in this repo and manual edits will be overwritten and create churn. Please revert the pt‑BR changes and update only src/locales/en/main.json, then regenerate locales.
Based on learnings: “locale files other than src/locales/en/main.json are generated automatically on every release… manual updates to other locale files … are not required.”

src/locales/tr/main.json (1)

16-2051: ⚠️ Potential issue | 🟡 Minor

Avoid manual edits to generated locale files (tr).

These non‑English locale files are auto‑generated in this repo and manual edits will be overwritten and create churn. Please revert the tr changes and update only src/locales/en/main.json, then regenerate locales.
Based on learnings: “locale files other than src/locales/en/main.json are generated automatically on every release… manual updates to other locale files … are not required.”

src/locales/fr/nodeDefs.json (1)

6421-6438: ⚠️ Potential issue | 🟡 Minor

Fix missing name keys for new Load3D inputs.

These entries use an empty-string key, so the label lookup will likely fail.

🛠️ Proposed fix
       "clear": {
-        "": "effacer"
+        "name": "effacer"
       },
@@
       "upload 3d model": {
-        "": "téléverser un modèle 3D"
+        "name": "téléverser un modèle 3D"
       },
       "upload extra resources": {
-        "": "téléverser des ressources supplémentaires"
+        "name": "téléverser des ressources supplémentaires"
       },
src/locales/ja/nodeDefs.json (1)

6421-6438: ⚠️ Potential issue | 🟡 Minor

Fix missing label keys for Load3D inputs.

Using an empty-string key will likely drop the label in the UI; these should be "name" like the other inputs.

🛠️ Suggested fix
      "clear": {
-        "": "クリア"
+        "name": "クリア"
      },
      ...
      "upload 3d model": {
-        "": "3Dモデルをアップロード"
+        "name": "3Dモデルをアップロード"
      },
      "upload extra resources": {
-        "": "追加リソースをアップロード"
+        "name": "追加リソースをアップロード"
      },
src/locales/es/nodeDefs.json (1)

6421-6438: ⚠️ Potential issue | 🟡 Minor

Fix missing name keys for Load3D labels.

These entries use an empty-string key, so the UI label likely won’t render. Replace with "name" for consistency.

✅ Suggested fix
       "clear": {
-        "": "limpiar"
+        "name": "limpiar"
       },
@@
       "upload 3d model": {
-        "": "subir modelo 3D"
+        "name": "subir modelo 3D"
       },
       "upload extra resources": {
-        "": "subir recursos adicionales"
+        "name": "subir recursos adicionales"
       },
src/locales/pt-BR/nodeDefs.json (1)

6428-6447: ⚠️ Potential issue | 🟡 Minor

Fix missing name keys for new Load3D inputs.
The clear, upload 3d model, and upload extra resources entries use an empty-string key, so the UI label won’t resolve. Use name like the other inputs.

🔧 Proposed fix
       "clear": {
-        "": "limpar"
+        "name": "limpar"
       },
@@
       "upload 3d model": {
-        "": "enviar modelo 3D"
+        "name": "enviar modelo 3D"
       },
       "upload extra resources": {
-        "": "enviar recursos extras"
+        "name": "enviar recursos extras"
       },
🤖 Fix all issues with AI agents
In `@src/lib/litegraph/src/contextMenuCompat.ts`:
- Around line 160-185: The set-diff logic for context menu items incorrectly
treats undefined content as a single key, so update the filters used when
building originalContents and patchedContents and when computing addedItems to
only include entries whose item.content is a stable key (e.g., typeof
item.content === 'string') rather than any undefined; specifically change the
predicates around originalItems, patchedItems, originalContents,
patchedContents, and addedItems (and ensure removedCount calculation uses the
filtered patchedContents) so separators or items with undefined content are not
collapsed into one set entry.

In `@src/locales/en/nodeDefs.json`:
- Around line 2212-2227: The batch_size tooltip for the node
"EmptyAceStep1_5LatentAudio" is incorrect (mentions latent images); update the
"inputs"."batch_size"."tooltip" text to reference audio instead — e.g., change
it to "The number of latent audio items in the batch." so the UI correctly
describes latent audio batching for the EmptyAceStep1_5LatentAudio node.

In `@src/locales/ko/nodeDefs.json`:
- Around line 7320-7331: Several multi-format export nodes (e.g.,
MeshyAnimateModelNode, MeshyImageToModelNode and other listed nodes) in the
Korean locale have array-based "outputs" where index entries were replaced with
nulls; restore those entries to match the English locale by replacing nulls with
the original object labels (use object keys "0","1","2", etc. as in the English
version) so that index 0 becomes "model_file", index 1 becomes "meshy_task_id"
(and index 2 "GLB"/"FBX" tooltips where applicable); update each affected node's
"outputs" array to mirror the English keys and values for the nodes named in the
comment to ensure UI labels attach to the correct outputs.

In `@src/locales/ru/nodeDefs.json`:
- Around line 11433-11449: Translate the English labels in the
ReferenceTimbreAudio node for the RU locale: update "display_name":
"ReferenceTimbreAudio" to a Russian display name (e.g., "ЭталонныйТембрАудио"),
translate input names for "conditioning" and "latent" to Russian equivalents,
and provide a Russian tooltip for the output "0". Locate the JSON object named
ReferenceTimbreAudio and replace the values of "display_name", inputs.*.name,
and outputs."0".tooltip with appropriate Russian strings while preserving the
JSON structure and keys.
- Around line 7316-7326: The RU locale's nodeDefs.json "outputs" entries are
using an array form and are missing many keys that the EN canonical uses; update
each 3D node (e.g., Meshy, Rodin3D, Tripo and the other affected nodes) so their
"outputs" match the EN structure exactly: convert the array to an
object/dictionary mapping output keys to objects (e.g., include "model_file",
"meshy_task_id", "3d_model_path"/"3D Model Path", "<node>_task_id", etc. as
present in EN), ensure each output object has the same "name" and "tooltip"
fields as EN, and mirror the exact key names and values used in the EN canonical
to avoid mislabeling.

In `@src/locales/zh-TW/nodeDefs.json`:
- Around line 6431-6436: The locale entries for the Load3D upload labels
("upload 3d model" and "upload extra resources") use a "zh-TW" key instead of
the schema's expected "name" field, so update those objects to replace the
"zh-TW" property with "name" (keeping the same Chinese strings) so the labels
conform to the locale schema and will be rendered; locate the entries by the
keys "upload 3d model" and "upload extra resources" in nodeDefs.json and change
their inner property from "zh-TW" to "name".

In `@src/locales/zh/main.json`:
- Around line 607-613: Remove unvalidated 3D formats from the code and
localization: delete .gltf, .glb, and .fbx entries from the SUPPORTED_EXTENSIONS
constant (symbol: SUPPORTED_EXTENSIONS in load3d/constants.ts), and remove the
localization keys FILE_3D_FBX, FILE_3D_GLB, FILE_3D_GLTF and FILE_3D_USDZ from
the locale JSON (symbol keys in main.json); then update the unsupportedFileType
message (symbol: unsupportedFileType) to list only the validated formats (.obj,
.stl, .ply, .spz) so UI/error text matches the actual supported set.

In `@src/locales/zh/nodeDefs.json`:
- Around line 2210-2226: The display_name for the node key
"EmptyAceStep1_5LatentAudio" is mixed English/Chinese; update its display_name
to a fully localized Chinese string (e.g., "空 Ace 步骤 1.5 潜在音频" or whatever
matches your existing AceStep naming convention) and apply the same consistent
localization to the other AceStep node display_name entries referenced (the
other AceStep entries in the diff ranges), ensuring only the display_name fields
are changed and input/output keys remain intact.
🧹 Nitpick comments (3)
src/locales/en/nodeDefs.json (1)

7335-7345: Optional: add format-specific tooltips for new 3D outputs.

The newly added GLB/FBX/OBJ sockets all have null tooltips. Adding a short tooltip (e.g., “GLB model file”) would make the UI more self-describing.

✍️ Example update (apply similarly to other GLB/FBX/OBJ outputs)
       "1": {
         "name": "GLB",
-        "tooltip": null
+        "tooltip": "GLB model file"
       },
       "2": {
         "name": "FBX",
-        "tooltip": null
+        "tooltip": "FBX model file"
       }

Also applies to: 7394-7409, 7457-7472, 7499-7514, 7533-7548, 7590-7605, 7634-7649, 11836-11843, 11867-11873, 11895-11902, 11917-11923, 11945-11951, 13947-13957, 13990-14000, 14622-14633, 14687-14698, 14711-14722, 14736-14747, 14758-14769, 14816-14827, 14853-14864

src/locales/ru/main.json (1)

19-83: Avoid manual edits to generated locale files.
These RU entries live in a non‑EN locale file that is regenerated on release; please drop these changes from the PR and keep only the EN additions in src/locales/en/main.json.

Based on learnings In the Comfy-Org/ComfyUI_frontend repository, locale files other than src/locales/en/main.json are generated automatically on every release. Developers only need to add English (en) key/values in src/locales/en/main.json when making PRs; manual updates to other locale files (fr, ja, ko, ru, zh, zh-TW, es, ar, tr, etc.) are not required and should not be suggested in reviews.

src/locales/fr/main.json (1)

19-83: Avoid manual edits to generated locale files.
These FR entries live in a non‑EN locale file that is regenerated on release; please drop these changes from the PR and keep only the EN additions in src/locales/en/main.json.

Based on learnings In the Comfy-Org/ComfyUI_frontend repository, locale files other than src/locales/en/main.json are generated automatically on every release. Developers only need to add English (en) key/values in src/locales/en/main.json when making PRs; manual updates to other locale files (fr, ja, ko, ru, zh, zh-TW, es, ar, tr, etc.) are not required and should not be suggested in reviews.

Comment on lines 2212 to 2227
"EmptyAceStep1_5LatentAudio": {
"display_name": "Empty Ace Step 1.5 Latent Audio",
"inputs": {
"seconds": {
"name": "seconds"
},
"batch_size": {
"name": "batch_size",
"tooltip": "The number of latent images in the batch."
}
},
"outputs": {
"0": {
"tooltip": null
}
}
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

Fix audio batch_size tooltip wording.

This node is for latent audio, but the tooltip still says “latent images,” which is confusing in the UI.

✏️ Proposed text fix
       "batch_size": {
         "name": "batch_size",
-        "tooltip": "The number of latent images in the batch."
+        "tooltip": "The number of latent audio samples in the batch."
       }
📝 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
"EmptyAceStep1_5LatentAudio": {
"display_name": "Empty Ace Step 1.5 Latent Audio",
"inputs": {
"seconds": {
"name": "seconds"
},
"batch_size": {
"name": "batch_size",
"tooltip": "The number of latent images in the batch."
}
},
"outputs": {
"0": {
"tooltip": null
}
}
"EmptyAceStep1_5LatentAudio": {
"display_name": "Empty Ace Step 1.5 Latent Audio",
"inputs": {
"seconds": {
"name": "seconds"
},
"batch_size": {
"name": "batch_size",
"tooltip": "The number of latent audio samples in the batch."
}
},
"outputs": {
"0": {
"tooltip": null
}
}
🤖 Prompt for AI Agents
In `@src/locales/en/nodeDefs.json` around lines 2212 - 2227, The batch_size
tooltip for the node "EmptyAceStep1_5LatentAudio" is incorrect (mentions latent
images); update the "inputs"."batch_size"."tooltip" text to reference audio
instead — e.g., change it to "The number of latent audio items in the batch." so
the UI correctly describes latent audio batching for the
EmptyAceStep1_5LatentAudio node.

Comment on lines 7316 to 7326
"outputs": [
null,
{
"name": "GLB",
"tooltip": null
},
{
"name": "FBX",
"tooltip": null
}
}
]
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:

#!/bin/bash
set -euo pipefail

ru_file="src/locales/ru/nodeDefs.json"
en_file="$(fd -t f 'nodeDefs.json' src/locales | rg '/en/' | head -n1)"

if [[ -z "$en_file" ]]; then
  echo "English nodeDefs.json not found under src/locales"; exit 1
fi

EN_PATH="$en_file" python - <<'PY'
import json, os, sys

ru_path = "src/locales/ru/nodeDefs.json"
en_path = os.environ["EN_PATH"]

nodes = [
  "MeshyAnimateModelNode","MeshyImageToModelNode","MeshyMultiImageToModelNode",
  "MeshyRefineNode","MeshyRigModelNode","MeshyTextToModelNode","MeshyTextureNode",
  "Rodin3D_Detail","Rodin3D_Gen2","Rodin3D_Regular","Rodin3D_Sketch","Rodin3D_Smooth",
  "TencentImageToModelNode","TencentTextToModelNode",
  "TripoImageToModelNode","TripoMultiviewToModelNode","TripoRefineNode",
  "TripoRetargetNode","TripoRigNode","TripoTextToModelNode","TripoTextureNode",
]

def normalize(outputs):
  if isinstance(outputs, list):
    return [o.get("name") if isinstance(o, dict) else None for o in outputs]
  if isinstance(outputs, dict):
    return [(k, (v.get("name") if isinstance(v, dict) else None)) for k, v in sorted(outputs.items(), key=lambda kv: kv[0])]
  return outputs

with open(ru_path, "r", encoding="utf-8") as f:
  ru = json.load(f)
with open(en_path, "r", encoding="utf-8") as f:
  en = json.load(f)

mismatches = []
for n in nodes:
  ru_out = ru.get(n, {}).get("outputs")
  en_out = en.get(n, {}).get("outputs")
  if ru_out is None or en_out is None:
    mismatches.append((n, "missing outputs", ru_out is None, en_out is None))
    continue
  if normalize(ru_out) != normalize(en_out):
    mismatches.append((n, normalize(ru_out), normalize(en_out)))

if mismatches:
  print("Output mismatches:")
  for m in mismatches:
    print("-", m)
  sys.exit(1)
else:
  print("All outputs match for listed nodes.")
PY

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 2296


Align RU output definitions with EN canonical format—critical mismatches detected across all 3D nodes.

Verification confirms significant discrepancies: the RU locale is missing essential outputs present in EN. For example, Meshy nodes in RU lack model_file and meshy_task_id outputs; Rodin3D nodes lack 3D Model Path; Tripo nodes lack model_file and task ID outputs. Additionally, RU uses array structure while EN uses object/dict structure, compounding the mislabeling risk. All 21 tested nodes show mismatches. The RU definitions must be completed to match EN's full output set and structure.

🤖 Prompt for AI Agents
In `@src/locales/ru/nodeDefs.json` around lines 7316 - 7326, The RU locale's
nodeDefs.json "outputs" entries are using an array form and are missing many
keys that the EN canonical uses; update each 3D node (e.g., Meshy, Rodin3D,
Tripo and the other affected nodes) so their "outputs" match the EN structure
exactly: convert the array to an object/dictionary mapping output keys to
objects (e.g., include "model_file", "meshy_task_id", "3d_model_path"/"3D Model
Path", "<node>_task_id", etc. as present in EN), ensure each output object has
the same "name" and "tooltip" fields as EN, and mirror the exact key names and
values used in the EN canonical to avoid mislabeling.

@dosubot dosubot bot added size:L This PR changes 100-499 lines, ignoring generated files. and removed size:XXL This PR changes 1000+ lines, ignoring generated files. labels Feb 5, 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/locales/pt-BR/nodeDefs.json (1)

6430-6463: ⚠️ Potential issue | 🔴 Critical

Fix Load3D input and output schema to match base locale format.

The pt-BR Load3D localization has two schema mismatches with the English base locale:

  1. Button/action inputs use {"": "..."} instead of {} for "clear", "upload 3d model", and "upload extra resources"
  2. Outputs use array format instead of object format with indexed string keys ("0"–"6")
💡 Correct schema (matching English base)
-      "clear": {
-        "": "limpar"
-      },
+      "clear": {},
...
-      "upload 3d model": {
-        "": "enviar modelo 3D"
-      },
+      "upload 3d model": {},
...
-      "upload extra resources": {
-        "": "enviar recursos extras"
-      },
+      "upload extra resources": {},
...
-    "outputs": [
-      null,
-      null,
-      null,
-      null,
-      null,
-      null,
-      {
-        "name": "model_3d",
-        "tooltip": null
-      }
-    ]
+    "outputs": {
+      "0": { "name": "image", "tooltip": null },
+      "1": { "name": "mask", "tooltip": null },
+      "2": { "name": "mesh_path", "tooltip": null },
+      "3": { "name": "normal", "tooltip": null },
+      "4": { "name": "camera_info", "tooltip": null },
+      "5": { "name": "recording_video", "tooltip": null },
+      "6": { "name": "model_3d", "tooltip": null }
+    }

@AustinMroz AustinMroz removed their assignment Feb 5, 2026
@AustinMroz AustinMroz merged commit 90a701d into main Feb 6, 2026
33 checks passed
@AustinMroz AustinMroz deleted the fix/penultimate-any-files branch February 6, 2026 00:29
snomiao pushed a commit that referenced this pull request Feb 6, 2026
## Summary

This PR removes `any` types from widgets, services, stores, and test
files, replacing them with proper TypeScript types.

### Key Changes

#### Type Safety Improvements
- Replaced `any` with `unknown`, explicit types, or proper interfaces
across widgets and services
- Added proper type imports (TgpuRoot, Point, StyleValue, etc.)
- Created typed interfaces (NumericWidgetOptions, TestWindow,
ImportFailureDetail, etc.)
- Fixed function return types to be non-nullable where appropriate
- Added type guards and null checks instead of non-null assertions
- Used `ComponentProps` from vue-component-type-helpers for component
testing

#### Widget System
- Added index signature to IWidgetOptions for Record compatibility
- Centralized disabled logic in WidgetInputNumberInput
- Moved template type assertions to computed properties
- Fixed ComboWidget getOptionLabel type assertions
- Improved remote widget type handling with runtime checks

#### Services & Stores
- Fixed getOrCreateViewer to return non-nullable values
- Updated addNodeOnGraph to use specific options type `{ pos?: Point }`
- Added proper type assertions for settings store retrieval
- Fixed executionIdToCurrentId return type (string | undefined)

#### Test Infrastructure
- Exported GraphOrSubgraph from litegraph barrel to avoid circular
dependencies
- Updated test fixtures with proper TypeScript types (TestInfo,
LGraphNode)
- Replaced loose Record types with ComponentProps in tests
- Added proper error handling in WebSocket fixture

#### Code Organization
- Created shared i18n-types module for locale data types
- Made ImportFailureDetail non-exported (internal use only)
- Added @public JSDoc tag to ElectronWindow type
- Fixed console.log usage in scripts to use allowed methods

### Files Changed

**Widgets & Components:**
-
src/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberInput.vue
-
src/renderer/extensions/vueNodes/widgets/components/WidgetSelectDefault.vue
-
src/renderer/extensions/vueNodes/widgets/components/WidgetSelectDropdown.vue
- src/renderer/extensions/vueNodes/widgets/components/WidgetTextarea.vue
-
src/renderer/extensions/vueNodes/widgets/composables/useRemoteWidget.ts
- src/lib/litegraph/src/widgets/ComboWidget.ts
- src/lib/litegraph/src/types/widgets.ts
- src/components/common/LazyImage.vue
- src/components/load3d/Load3dViewerContent.vue

**Services & Stores:**
- src/services/litegraphService.ts
- src/services/load3dService.ts
- src/services/colorPaletteService.ts
- src/stores/maskEditorStore.ts
- src/stores/nodeDefStore.ts
- src/platform/settings/settingStore.ts
- src/platform/workflow/management/stores/workflowStore.ts

**Composables & Utils:**
- src/composables/node/useWatchWidget.ts
- src/composables/useCanvasDrop.ts
- src/utils/widgetPropFilter.ts
- src/utils/queueDisplay.ts
- src/utils/envUtil.ts

**Test Files:**
- browser_tests/fixtures/ComfyPage.ts
- browser_tests/fixtures/ws.ts
- browser_tests/tests/actionbar.spec.ts
-
src/workbench/extensions/manager/components/manager/skeleton/PackCardGridSkeleton.test.ts
- src/lib/litegraph/src/subgraph/subgraphUtils.test.ts
- src/components/rightSidePanel/shared.test.ts
- src/platform/cloud/subscription/composables/useSubscription.test.ts
-
src/platform/workflow/persistence/composables/useWorkflowPersistence.test.ts

**Scripts & Types:**
- scripts/i18n-types.ts (new shared module)
- scripts/diff-i18n.ts
- scripts/check-unused-i18n-keys.ts
- src/workbench/extensions/manager/types/conflictDetectionTypes.ts
- src/types/algoliaTypes.ts
- src/types/simplifiedWidget.ts

**Infrastructure:**
- src/lib/litegraph/src/litegraph.ts (added GraphOrSubgraph export)
- src/lib/litegraph/src/infrastructure/CustomEventTarget.ts
- src/platform/assets/services/assetService.ts

**Stories:**
- apps/desktop-ui/src/views/InstallView.stories.ts
- src/components/queue/job/JobDetailsPopover.stories.ts

**Extension Manager:**
- src/workbench/extensions/manager/composables/useConflictDetection.ts
- src/workbench/extensions/manager/composables/useManagerQueue.ts
- src/workbench/extensions/manager/services/comfyManagerService.ts
- src/workbench/extensions/manager/utils/conflictMessageUtil.ts

### Testing

- [x] All TypeScript type checking passes (`pnpm typecheck`)
- [x] ESLint passes without errors (`pnpm lint`)
- [x] Format checks pass (`pnpm format:check`)
- [x] Knip (unused exports) passes (`pnpm knip`)
- [x] Pre-commit and pre-push hooks pass

Part of the "Road to No Explicit Any" initiative.

### Previous PRs in this series:
- Part 2: #7401
- Part 3: #7935
- Part 4: #7970
- Part 5: #8064
- Part 6: #8083
- Part 7: #8092
- Part 8 Group 1: #8253
- Part 8 Group 2: #8258
- Part 8 Group 3: #8304
- Part 8 Group 4: #8314
- Part 8 Group 5: #8329
- Part 8 Group 6: #8344
- Part 8 Group 7: #8459
- Part 8 Group 8: #8496
- Part 9: #8498
- Part 10: #8499

---------

Co-authored-by: Comfy Org PR Bot <snomiao+comfy-pr@gmail.com>
Co-authored-by: christian-byrne <72887196+christian-byrne@users.noreply.github.com>
Co-authored-by: github-actions <github-actions@github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants