Skip to content

feat(billing): method-aware payment-method collection UX#13354

Closed
wei-hai wants to merge 4 commits into
mainfrom
feat/payment-method-collection-ux
Closed

feat(billing): method-aware payment-method collection UX#13354
wei-hai wants to merge 4 commits into
mainfrom
feat/payment-method-collection-ux

Conversation

@wei-hai

@wei-hai wei-hai commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

What

Adds three UI surfaces for off-session payment collection, driven by a new payment_method_capability billing-status field (none / one_time_only / reusable):

  1. Spend-limit dialog (SpendLimitDialogContent.vue, dispatched via dialogService.showSpendLimitDialog) — method-aware variants: no method → add a method; a non-reusable method (e.g. Alipay) → prompt for a card/bank/Link (never implies the user has none); a failed automatic charge → update the method via the billing portal. Workspace-scoped; no-op for legacy accounts.
  2. Consent disclosure — a context prop on SubscriptionTermsNote renders an authorization disclosure for automatic off-session charges on the card-save screen.
  3. Owed-balance notice in CreditsTile — capability-aware CTA; a pay_owed billing operation with its own success handler (no dialog-close / no navigation); a settle-endpoint feature flag (default off → read-only fallback).

Notes

  • Reuses existing components (dialog service, Button, CreditsTile notice pattern, billingOperationStore, toasts); one new component.
  • New billing-status fields are added to the FE types now and will be confirmed when the backend contract lands.
  • The "Pay now" settle action is gated behind a feature flag (off by default) until the backend settle endpoint ships.
  • a11y: role="alert" on the owed notice, focus management after settle, method-aware labels.

Tests

New unit coverage for the pay_owed operation type (success does not close a dialog or navigate; failure/timeout messaging; lifecycle); billing-context + feature-flag + dialog tests pass; typecheck clean.

🤖 Generated with Claude Code

Add three surfaces for off-session payment collection:
- Spend-limit dialog (SpendLimitDialogContent) with method-aware variants
  driven by payment_method_capability; add-method routes to the setup flow,
  a failed auto-charge routes to the billing portal.
- Consent disclosure via a context prop on SubscriptionTermsNote.
- Owed-balance notice in CreditsTile with a capability-aware CTA, a
  settle-endpoint feature flag (default off -> read-only fallback), and a
  dedicated pay_owed billing operation type.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@wei-hai wei-hai requested a review from a team July 1, 2026 05:41
@dosubot dosubot Bot added the size:XL This PR changes 500-999 lines, ignoring generated files. label Jul 1, 2026
@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown

🎨 Storybook: ✅ Built — View Storybook

Details

⏰ Completed at: 07/01/2026, 07:36:25 AM UTC

Links

🎭 Playwright: ✅ 1691 passed, 0 failed · 2 flaky

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

📦 Bundle: 7.77 MB gzip 🔴 +5.45 kB

Details

Summary

  • Raw size: 32.8 MB baseline 32.8 MB — 🔴 +19.2 kB
  • Gzip: 7.77 MB baseline 7.77 MB — 🔴 +5.45 kB
  • Brotli: 5.35 MB baseline 5.34 MB — 🔴 +4.52 kB
  • Bundles: 301 current • 299 baseline • 239 added / 237 removed

Category Glance
Other 🔴 +16.2 kB (11.7 MB) · Utilities & Hooks 🔴 +2.94 kB (3.37 MB) · Panels & Settings 🔴 +41 B (546 kB) · Vendor & Third-Party ⚪ 0 B (15.3 MB) · Graph Workspace ⚪ 0 B (1.25 MB) · Data & Services ⚪ 0 B (270 kB) · + 5 more

App Entry Points — 47.4 kB (baseline 47.4 kB) • ⚪ 0 B

Main entry bundles and manifests

File Before After Δ Raw Δ Gzip Δ Brotli
assets/index-CG0nQK3O.js (removed) 47.4 kB 🟢 -47.4 kB 🟢 -13.9 kB 🟢 -12.1 kB
assets/index-DuYrIhkb.js (new) 47.4 kB 🔴 +47.4 kB 🔴 +13.9 kB 🔴 +12 kB

Status: 1 added / 1 removed

Graph Workspace — 1.25 MB (baseline 1.25 MB) • ⚪ 0 B

Graph editor runtime, canvas, workflow orchestration

File Before After Δ Raw Δ Gzip Δ Brotli
assets/GraphView-BJX79F7x.js (new) 1.25 MB 🔴 +1.25 MB 🔴 +267 kB 🔴 +201 kB
assets/GraphView-DEwYf5jo.js (removed) 1.25 MB 🟢 -1.25 MB 🟢 -267 kB 🟢 -201 kB

Status: 1 added / 1 removed

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

Top-level views, pages, and routed surfaces

File Before After Δ Raw Δ Gzip Δ Brotli
assets/CloudSurveyView-CmX-jWY2.js (new) 19.4 kB 🔴 +19.4 kB 🔴 +5.03 kB 🔴 +4.47 kB
assets/CloudSurveyView-q8keZBsA.js (removed) 19.4 kB 🟢 -19.4 kB 🟢 -5.04 kB 🟢 -4.47 kB
assets/OAuthConsentView-BBba47GO.js (new) 15 kB 🔴 +15 kB 🔴 +4.1 kB 🔴 +3.57 kB
assets/OAuthConsentView-D2kypZUX.js (removed) 15 kB 🟢 -15 kB 🟢 -4.1 kB 🟢 -3.57 kB
assets/CloudLoginView-B4mbVgKY.js (removed) 11.4 kB 🟢 -11.4 kB 🟢 -3.07 kB 🟢 -2.69 kB
assets/CloudLoginView-C6OhXcN4.js (new) 11.4 kB 🔴 +11.4 kB 🔴 +3.07 kB 🔴 +2.69 kB
assets/CloudSignupView-B2WouxuY.js (removed) 9.79 kB 🟢 -9.79 kB 🟢 -2.74 kB 🟢 -2.41 kB
assets/CloudSignupView-DAvkLMB7.js (new) 9.79 kB 🔴 +9.79 kB 🔴 +2.74 kB 🔴 +2.4 kB
assets/CloudLayoutView-C0bgcJME.js (new) 9.36 kB 🔴 +9.36 kB 🔴 +2.34 kB 🔴 +2.02 kB
assets/CloudLayoutView-DfhPDcs9.js (removed) 9.36 kB 🟢 -9.36 kB 🟢 -2.34 kB 🟢 -2.03 kB
assets/UserCheckView-CH9cG5tm.js (removed) 8.8 kB 🟢 -8.8 kB 🟢 -2.22 kB 🟢 -1.93 kB
assets/UserCheckView-DjS3bU4D.js (new) 8.8 kB 🔴 +8.8 kB 🔴 +2.22 kB 🔴 +1.93 kB
assets/CloudSubscriptionRedirectView-BXtgUxfY.js (new) 6.63 kB 🔴 +6.63 kB 🔴 +2.46 kB 🔴 +2.15 kB
assets/CloudSubscriptionRedirectView-tQaqdhMo.js (removed) 6.63 kB 🟢 -6.63 kB 🟢 -2.45 kB 🟢 -2.14 kB
assets/UserSelectView-BLhNzj6I.js (new) 6 kB 🔴 +6 kB 🔴 +2.15 kB 🔴 +1.89 kB
assets/UserSelectView-ByaI0XG4.js (removed) 6 kB 🟢 -6 kB 🟢 -2.15 kB 🟢 -1.89 kB
assets/CloudForgotPasswordView-BMkLnOVa.js (new) 5.15 kB 🔴 +5.15 kB 🔴 +1.76 kB 🔴 +1.53 kB
assets/CloudForgotPasswordView-DhwiKguX.js (removed) 5.15 kB 🟢 -5.15 kB 🟢 -1.76 kB 🟢 -1.54 kB
assets/CloudAuthTimeoutView-BgTMNtgM.js (new) 4.49 kB 🔴 +4.49 kB 🔴 +1.57 kB 🔴 +1.37 kB
assets/CloudAuthTimeoutView-DGDodGFX.js (removed) 4.49 kB 🟢 -4.49 kB 🟢 -1.58 kB 🟢 -1.37 kB
assets/CloudSorryContactSupportView-J37Xjc9t.js (removed) 1.21 kB 🟢 -1.21 kB 🟢 -607 B 🟢 -528 B
assets/CloudSorryContactSupportView-YEWjXvP4.js (new) 1.21 kB 🔴 +1.21 kB 🔴 +608 B 🔴 +527 B
assets/layout-C2s1oU-T.js (removed) 447 B 🟢 -447 B 🟢 -284 B 🟢 -235 B
assets/layout-D6yQcF35.js (new) 447 B 🔴 +447 B 🔴 +286 B 🔴 +236 B

Status: 12 added / 12 removed

Panels & Settings — 546 kB (baseline 546 kB) • 🔴 +41 B

Configuration panels, inspectors, and settings screens

File Before After Δ Raw Δ Gzip Δ Brotli
assets/KeybindingPanel-B-GyuIFp.js (removed) 49.4 kB 🟢 -49.4 kB 🟢 -9.96 kB 🟢 -8.82 kB
assets/KeybindingPanel-Dt14d8Go.js (new) 49.4 kB 🔴 +49.4 kB 🔴 +9.97 kB 🔴 +8.82 kB
assets/settings-C9Tmk3bJ.js (removed) 39.8 kB 🟢 -39.8 kB 🟢 -9.73 kB 🟢 -7.99 kB
assets/settings-iCA_svS6.js (new) 39.8 kB 🔴 +39.8 kB 🔴 +9.73 kB 🔴 +7.98 kB
assets/settings-C2wKwgxO.js (removed) 35.4 kB 🟢 -35.4 kB 🟢 -8.66 kB 🟢 -7.29 kB
assets/settings-o5pPExCR.js (new) 35.4 kB 🔴 +35.4 kB 🔴 +8.66 kB 🔴 +7.32 kB
assets/settings-Br4yRO0X.js (new) 33.5 kB 🔴 +33.5 kB 🔴 +8.48 kB 🔴 +6.91 kB
assets/settings-zmAzXhGy.js (removed) 33.5 kB 🟢 -33.5 kB 🟢 -8.48 kB 🟢 -6.9 kB
assets/settings-C4BF2z9s.js (removed) 33.1 kB 🟢 -33.1 kB 🟢 -8.51 kB 🟢 -7.1 kB
assets/settings-DrwVN8Ew.js (new) 33.1 kB 🔴 +33.1 kB 🔴 +8.51 kB 🔴 +7.09 kB
assets/settings-BYApwqx_.js (new) 31.5 kB 🔴 +31.5 kB 🔴 +8.78 kB 🔴 +7.31 kB
assets/settings-DMXOgQVA.js (removed) 31.5 kB 🟢 -31.5 kB 🟢 -8.78 kB 🟢 -7.31 kB
assets/settings-Bg4QnQI8.js (new) 30.9 kB 🔴 +30.9 kB 🔴 +8.41 kB 🔴 +7.38 kB
assets/settings-BwQRFbgb.js (removed) 30.9 kB 🟢 -30.9 kB 🟢 -8.41 kB 🟢 -7.37 kB
assets/settings-C2gc9HUt.js (removed) 29.7 kB 🟢 -29.7 kB 🟢 -8.07 kB 🟢 -6.88 kB
assets/settings-DvAV062j.js (new) 29.7 kB 🔴 +29.7 kB 🔴 +8.07 kB 🔴 +6.88 kB
assets/settings-CG5yZo1m.js (new) 29.6 kB 🔴 +29.6 kB 🔴 +8.31 kB 🔴 +7.26 kB
assets/settings-DbaQC_wv.js (removed) 29.6 kB 🟢 -29.6 kB 🟢 -8.31 kB 🟢 -7.25 kB
assets/settings-BNqisXpi.js (new) 28.8 kB 🔴 +28.8 kB 🔴 +7.99 kB 🔴 +6.95 kB
assets/settings-DPFn4SDi.js (removed) 28.8 kB 🟢 -28.8 kB 🟢 -7.99 kB 🟢 -6.95 kB
assets/settings-C0b1G-4Q.js (removed) 28.7 kB 🟢 -28.7 kB 🟢 -8.44 kB 🟢 -7.03 kB
assets/settings-D315AuoN.js (new) 28.7 kB 🔴 +28.7 kB 🔴 +8.44 kB 🔴 +7.03 kB
assets/settings-C3lEMXTa.js (new) 25.2 kB 🔴 +25.2 kB 🔴 +8.2 kB 🔴 +6.6 kB
assets/settings-Dd_PQ-qm.js (removed) 25.2 kB 🟢 -25.2 kB 🟢 -8.2 kB 🟢 -6.6 kB
assets/settings-BH_B17Kh.js (new) 24.6 kB 🔴 +24.6 kB 🔴 +8.02 kB 🔴 +6.27 kB
assets/settings-hVo59da3.js (removed) 24.6 kB 🟢 -24.6 kB 🟢 -8.01 kB 🟢 -6.28 kB
assets/SecretsPanel-B3C9hGMn.js (new) 24.2 kB 🔴 +24.2 kB 🔴 +5.77 kB 🔴 +5.07 kB
assets/SecretsPanel-C-wINKHN.js (removed) 24.2 kB 🟢 -24.2 kB 🟢 -5.77 kB 🟢 -5.07 kB
assets/CreditsPanel-CTRIkT8L.js (new) 15.6 kB 🔴 +15.6 kB 🔴 +4.61 kB 🔴 +4.05 kB
assets/CreditsPanel-DI8JgVV_.js (removed) 15.6 kB 🟢 -15.6 kB 🟢 -4.61 kB 🟢 -4.04 kB
assets/AboutPanel-BllBJ3cE.js (removed) 12 kB 🟢 -12 kB 🟢 -3.29 kB 🟢 -2.94 kB
assets/AboutPanel-DPjR74pK.js (new) 12 kB 🔴 +12 kB 🔴 +3.29 kB 🔴 +2.94 kB
assets/SubscriptionPanel-DQZSCcXY.js (new) 11.2 kB 🔴 +11.2 kB 🔴 +3.54 kB 🔴 +3.1 kB
assets/SubscriptionPanel-CF5Uk1XT.js (removed) 11.2 kB 🟢 -11.2 kB 🟢 -3.51 kB 🟢 -3.09 kB
assets/ExtensionPanel-DbAy6ich.js (removed) 9.03 kB 🟢 -9.03 kB 🟢 -2.49 kB 🟢 -2.19 kB
assets/ExtensionPanel-Os2V87IZ.js (new) 9.03 kB 🔴 +9.03 kB 🔴 +2.49 kB 🔴 +2.2 kB
assets/ServerConfigPanel-BgSpU8L4.js (new) 6.15 kB 🔴 +6.15 kB 🔴 +1.97 kB 🔴 +1.75 kB
assets/ServerConfigPanel-DwnUJsyq.js (removed) 6.15 kB 🟢 -6.15 kB 🟢 -1.97 kB 🟢 -1.76 kB
assets/UserPanel-AxVxegBp.js (new) 5.78 kB 🔴 +5.78 kB 🔴 +1.82 kB 🔴 +1.57 kB
assets/UserPanel-Jgcp_vq3.js (removed) 5.78 kB 🟢 -5.78 kB 🟢 -1.82 kB 🟢 -1.57 kB
assets/refreshRemoteConfig-CWcUn1xm.js (new) 2.73 kB 🔴 +2.73 kB 🔴 +1.22 kB 🔴 +1.07 kB
assets/refreshRemoteConfig-DAb1t1KW.js (removed) 2.73 kB 🟢 -2.73 kB 🟢 -1.22 kB 🟢 -1.07 kB
assets/config-B2VX_hK9.js (new) 2.14 kB 🔴 +2.14 kB 🔴 +1.04 kB 🔴 +846 B
assets/config-sCFY6THA.js (removed) 2.14 kB 🟢 -2.14 kB 🟢 -1.04 kB 🟢 -842 B
assets/cloudRemoteConfig-6aCJMYc5.js (removed) 990 B 🟢 -990 B 🟢 -542 B 🟢 -475 B
assets/cloudRemoteConfig-dwJgC0z0.js (new) 990 B 🔴 +990 B 🔴 +541 B 🔴 +467 B
assets/refreshRemoteConfig-BaIxPY-Z.js (new) 110 B 🔴 +110 B 🔴 +89 B 🔴 +88 B
assets/refreshRemoteConfig-VkZKN4_T.js (removed) 110 B 🟢 -110 B 🟢 -89 B 🟢 -89 B

Status: 24 added / 24 removed / 3 unchanged

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

Authentication, profile, and account management bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/SignUpForm-d-CIzLRw.js (removed) 10 kB 🟢 -10 kB 🟢 -3.46 kB 🟢 -3.03 kB
assets/SignUpForm-DbUsX3Pz.js (new) 10 kB 🔴 +10 kB 🔴 +3.46 kB 🔴 +3.03 kB
assets/auth-BTN8uF-D.js (removed) 3.69 kB 🟢 -3.69 kB 🟢 -1.3 kB 🟢 -1.13 kB
assets/auth-DfC44gzp.js (new) 3.69 kB 🔴 +3.69 kB 🔴 +1.3 kB 🔴 +1.12 kB
assets/usePostAuthRedirect-DTYnwmNp.js (new) 3.33 kB 🔴 +3.33 kB 🔴 +1.27 kB 🔴 +1.11 kB
assets/usePostAuthRedirect-DYNZa1AG.js (removed) 3.33 kB 🟢 -3.33 kB 🟢 -1.27 kB 🟢 -1.11 kB
assets/UpdatePasswordContent-C0sSBsu3.js (removed) 1.92 kB 🟢 -1.92 kB 🟢 -875 B 🟢 -765 B
assets/UpdatePasswordContent-PPiXg9AJ.js (new) 1.92 kB 🔴 +1.92 kB 🔴 +876 B 🔴 +762 B
assets/WorkspaceProfilePic-1GR-yxtZ.js (removed) 1.66 kB 🟢 -1.66 kB 🟢 -862 B 🟢 -777 B
assets/WorkspaceProfilePic-DA3oYgmE.js (new) 1.66 kB 🔴 +1.66 kB 🔴 +860 B 🔴 +777 B
assets/authStore-16Mri6kI.js (new) 130 B 🔴 +130 B 🔴 +112 B 🔴 +111 B
assets/authStore-BvxwkC9W.js (removed) 130 B 🟢 -130 B 🟢 -112 B 🟢 -117 B
assets/workspaceAuthStore-C_CY5sTp.js (removed) 110 B 🟢 -110 B 🟢 -104 B 🟢 -114 B
assets/workspaceAuthStore-C2YnEoc8.js (new) 110 B 🔴 +110 B 🔴 +104 B 🔴 +107 B
assets/auth-D7QzG7G_.js (removed) 105 B 🟢 -105 B 🟢 -96 B 🟢 -88 B
assets/auth-O6vb-xwv.js (new) 105 B 🔴 +105 B 🔴 +96 B 🔴 +79 B

Status: 8 added / 8 removed / 2 unchanged

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

Modals, dialogs, drawers, and in-app editors

File Before After Δ Raw Δ Gzip Δ Brotli
assets/ComfyHubPublishDialog-C3N4nRwO.js (new) 90.5 kB 🔴 +90.5 kB 🔴 +19.3 kB 🔴 +16.5 kB
assets/ComfyHubPublishDialog-CXbfVcDi.js (removed) 90.5 kB 🟢 -90.5 kB 🟢 -19.3 kB 🟢 -16.5 kB
assets/useShareDialog-3nRirsZz.js (removed) 23.7 kB 🟢 -23.7 kB 🟢 -5.59 kB 🟢 -4.97 kB
assets/useShareDialog-Ca82E80I.js (new) 23.7 kB 🔴 +23.7 kB 🔴 +5.59 kB 🔴 +4.96 kB
assets/SubscriptionInactiveMemberDialog-B82spW03.js (removed) 2.55 kB 🟢 -2.55 kB 🟢 -1.03 kB 🟢 -895 B
assets/SubscriptionInactiveMemberDialog-Od1oFk3F.js (new) 2.55 kB 🔴 +2.55 kB 🔴 +1.03 kB 🔴 +903 B
assets/ComfyHubPublishDialog-Ca0J6mS1.js (removed) 143 B 🟢 -143 B 🟢 -105 B 🟢 -91 B
assets/ComfyHubPublishDialog-SNNtrkJc.js (new) 143 B 🔴 +143 B 🔴 +105 B 🔴 +89 B
assets/useSubscriptionDialog-Bggld6eR.js (removed) 110 B 🟢 -110 B 🟢 -102 B 🟢 -88 B
assets/useSubscriptionDialog-RxgovcDB.js (new) 110 B 🔴 +110 B 🔴 +102 B 🔴 +89 B

Status: 5 added / 5 removed

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

Reusable component library chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/ComfyQueueButton-CKgEFCbS.js (removed) 13.6 kB 🟢 -13.6 kB 🟢 -3.82 kB 🟢 -3.41 kB
assets/ComfyQueueButton-CPKqWuvk.js (new) 13.6 kB 🔴 +13.6 kB 🔴 +3.82 kB 🔴 +3.41 kB
assets/useTerminalTabs-DbZNrmcu.js (removed) 12.1 kB 🟢 -12.1 kB 🟢 -3.83 kB 🟢 -3.38 kB
assets/useTerminalTabs-DXgXOkLd.js (new) 12.1 kB 🔴 +12.1 kB 🔴 +3.84 kB 🔴 +3.38 kB
assets/TopbarBadge-4XMVBkLC.js (removed) 7.7 kB 🟢 -7.7 kB 🟢 -1.87 kB 🟢 -1.65 kB
assets/TopbarBadge-CRc0YaAb.js (new) 7.7 kB 🔴 +7.7 kB 🔴 +1.87 kB 🔴 +1.64 kB
assets/toggle-group-Ng4HwkLv.js (new) 4.16 kB 🔴 +4.16 kB 🔴 +1.45 kB 🔴 +1.27 kB
assets/toggle-group-TzH8HFvr.js (removed) 4.16 kB 🟢 -4.16 kB 🟢 -1.45 kB 🟢 -1.28 kB
assets/SubscribeButton-aC_zPZAl.js (removed) 2.35 kB 🟢 -2.35 kB 🟢 -1.04 kB 🟢 -901 B
assets/SubscribeButton-DwIv4RGx.js (new) 2.35 kB 🔴 +2.35 kB 🔴 +1.04 kB 🔴 +906 B
assets/WidgetButton-b1XpxoyF.js (removed) 1.98 kB 🟢 -1.98 kB 🟢 -920 B 🟢 -809 B
assets/WidgetButton-BSmanv-X.js (new) 1.98 kB 🔴 +1.98 kB 🔴 +919 B 🔴 +821 B
assets/UserAvatar-Bc6vTz_1.js (removed) 1.29 kB 🟢 -1.29 kB 🟢 -673 B 🟢 -576 B
assets/UserAvatar-Cg1jEPvz.js (new) 1.29 kB 🔴 +1.29 kB 🔴 +673 B 🔴 +574 B
assets/CloudBadge-CM0lQyYo.js (removed) 1.18 kB 🟢 -1.18 kB 🟢 -595 B 🟢 -521 B
assets/CloudBadge-CZNisnYb.js (new) 1.18 kB 🔴 +1.18 kB 🔴 +592 B 🔴 +518 B
assets/cloudFeedbackTopbarButton-CHtfACOl.js (removed) 829 B 🟢 -829 B 🟢 -496 B 🟢 -450 B
assets/cloudFeedbackTopbarButton-i5EmkI_0.js (new) 829 B 🔴 +829 B 🔴 +499 B 🔴 +450 B
assets/ComfyQueueButton-CoWYvSxZ.js (removed) 128 B 🟢 -128 B 🟢 -99 B 🟢 -89 B
assets/ComfyQueueButton-DRJ3QL6p.js (new) 128 B 🔴 +128 B 🔴 +99 B 🔴 +92 B

Status: 10 added / 10 removed / 3 unchanged

Data & Services — 270 kB (baseline 270 kB) • ⚪ 0 B

Stores, services, APIs, and repositories

File Before After Δ Raw Δ Gzip Δ Brotli
assets/load3dService-BZa27F1P.js (new) 126 kB 🔴 +126 kB 🔴 +27.8 kB 🔴 +23.5 kB
assets/load3dService-CQftcJ8o.js (removed) 126 kB 🟢 -126 kB 🟢 -27.8 kB 🟢 -23.5 kB
assets/api-CJjcVd_w.js (removed) 91.9 kB 🟢 -91.9 kB 🟢 -25.3 kB 🟢 -21.7 kB
assets/api-D4_wM8AF.js (new) 91.9 kB 🔴 +91.9 kB 🔴 +25.3 kB 🔴 +21.7 kB
assets/workflowShareService-B3nJPdRX.js (new) 17 kB 🔴 +17 kB 🔴 +5.01 kB 🔴 +4.44 kB
assets/workflowShareService-CNX97SkD.js (removed) 17 kB 🟢 -17 kB 🟢 -5.01 kB 🟢 -4.44 kB
assets/releaseStore-BMMT8nvp.js (removed) 8.29 kB 🟢 -8.29 kB 🟢 -2.34 kB 🟢 -2.04 kB
assets/releaseStore-C0c7u2T-.js (new) 8.29 kB 🔴 +8.29 kB 🔴 +2.34 kB 🔴 +2.04 kB
assets/keybindingService-CzyAXzlP.js (removed) 7.46 kB 🟢 -7.46 kB 🟢 -1.92 kB 🟢 -1.64 kB
assets/keybindingService-NEH6KUdK.js (new) 7.46 kB 🔴 +7.46 kB 🔴 +1.92 kB 🔴 +1.64 kB
assets/extensionStore-CSL-U41j.js (removed) 5.29 kB 🟢 -5.29 kB 🟢 -1.86 kB 🟢 -1.57 kB
assets/extensionStore-CTsxUOCZ.js (new) 5.29 kB 🔴 +5.29 kB 🔴 +1.86 kB 🔴 +1.57 kB
assets/userStore-CeRWzLOO.js (new) 2.42 kB 🔴 +2.42 kB 🔴 +933 B 🔴 +822 B
assets/userStore-DLmJ2x2g.js (removed) 2.42 kB 🟢 -2.42 kB 🟢 -932 B 🟢 -816 B
assets/serverConfigStore-CN4Xkrt5.js (new) 2.35 kB 🔴 +2.35 kB 🔴 +811 B 🔴 +707 B
assets/serverConfigStore-m5ZP9rkQ.js (removed) 2.35 kB 🟢 -2.35 kB 🟢 -811 B 🟢 -707 B
assets/audioService-G3HoBZLs.js (removed) 1.76 kB 🟢 -1.76 kB 🟢 -862 B 🟢 -747 B
assets/audioService-shV4DSjk.js (new) 1.76 kB 🔴 +1.76 kB 🔴 +862 B 🔴 +748 B
assets/dialogService-Bx3djGWJ.js (new) 100 B 🔴 +100 B 🔴 +99 B 🔴 +91 B
assets/dialogService-hqjucAVl.js (removed) 100 B 🟢 -100 B 🟢 -99 B 🟢 -94 B
assets/settingStore-BHSgmrwB.js (removed) 98 B 🟢 -98 B 🟢 -98 B 🟢 -93 B
assets/settingStore-IRl2xYe-.js (new) 98 B 🔴 +98 B 🔴 +98 B 🔴 +101 B
assets/assetsStore-BBgPs8oE.js (new) 96 B 🔴 +96 B 🔴 +97 B 🔴 +96 B
assets/assetsStore-cjSnZZK6.js (removed) 96 B 🟢 -96 B 🟢 -97 B 🟢 -87 B
assets/releaseStore-CkAVnhLn.js (new) 95 B 🔴 +95 B 🔴 +86 B 🔴 +79 B
assets/releaseStore-Df8A-5gJ.js (removed) 95 B 🟢 -95 B 🟢 -86 B 🟢 -91 B
assets/api-CBY1Uh79.js (removed) 62 B 🟢 -62 B 🟢 -74 B 🟢 -66 B
assets/api-CkXHLMw8.js (new) 62 B 🔴 +62 B 🔴 +74 B 🔴 +66 B

Status: 14 added / 14 removed / 2 unchanged

Utilities & Hooks — 3.37 MB (baseline 3.37 MB) • 🔴 +2.94 kB

Helpers, composables, and utility bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/promotionUtils-DymM6y-1.js (new) 3.01 MB 🔴 +3.01 MB 🔴 +696 kB 🔴 +524 kB
assets/promotionUtils-CcCU8qfq.js (removed) 3.01 MB 🟢 -3.01 MB 🟢 -695 kB 🟢 -524 kB
assets/useConflictDetection-BY0_m9UN.js (new) 234 kB 🔴 +234 kB 🔴 +52.3 kB 🔴 +42.6 kB
assets/useConflictDetection-CUxooSfp.js (removed) 234 kB 🟢 -234 kB 🟢 -52.3 kB 🟢 -42.6 kB
assets/useLoad3d-DhSpqnO7.js (new) 25.5 kB 🔴 +25.5 kB 🔴 +5.76 kB 🔴 +5.1 kB
assets/useLoad3d-nMRA5Ugr.js (removed) 25.5 kB 🟢 -25.5 kB 🟢 -5.76 kB 🟢 -5.09 kB
assets/useLoad3dViewer-DVE74sCO.js (new) 21.1 kB 🔴 +21.1 kB 🔴 +4.98 kB 🔴 +4.37 kB
assets/useLoad3dViewer-pZlHrkq9.js (removed) 21.1 kB 🟢 -21.1 kB 🟢 -4.98 kB 🟢 -4.35 kB
assets/useFeatureFlags-B6n3h3go.js (new) 5.73 kB 🔴 +5.73 kB 🔴 +1.75 kB 🔴 +1.49 kB
assets/useFeatureFlags-BQYKh4WT.js (removed) 5.55 kB 🟢 -5.55 kB 🟢 -1.71 kB 🟢 -1.46 kB
assets/useTypeformEmbed-BPpLqbsy.js (new) 4.92 kB 🔴 +4.92 kB 🔴 +1.96 kB 🔴 +1.63 kB
assets/useTypeformEmbed-jq1pPuGB.js (removed) 4.92 kB 🟢 -4.92 kB 🟢 -1.96 kB 🟢 -1.64 kB
assets/downloadUtil-D3YA8L70.js (new) 4.68 kB 🔴 +4.68 kB 🔴 +1.85 kB 🔴 +1.54 kB
assets/downloadUtil-DmruXCTb.js (removed) 4.68 kB 🟢 -4.68 kB 🟢 -1.85 kB 🟢 -1.54 kB
assets/useTransformState-DTBFWJgd.js (new) 3.58 kB 🔴 +3.58 kB 🔴 +1.58 kB 🔴 +1.31 kB
assets/useTransformState-VmwWA6Xs.js (removed) 3.58 kB 🟢 -3.58 kB 🟢 -1.58 kB 🟢 -1.31 kB
assets/subscriptionCheckoutUtil-7PIw32Qz.js (new) 3.52 kB 🔴 +3.52 kB 🔴 +1.45 kB 🔴 +1.25 kB
assets/subscriptionCheckoutUtil-CAtpo6eL.js (removed) 3.52 kB 🟢 -3.52 kB 🟢 -1.45 kB 🟢 -1.25 kB
assets/useSessionCookie-Dg7TcyyR.js (new) 3.33 kB 🔴 +3.33 kB 🔴 +1.15 kB 🔴 +988 B
assets/useSessionCookie-Dgab2NJq.js (removed) 3.33 kB 🟢 -3.33 kB 🟢 -1.15 kB 🟢 -980 B
assets/useExternalLink-CueHldkX.js (new) 3.03 kB 🔴 +3.03 kB 🔴 +1.16 kB 🔴 +1.02 kB
assets/useExternalLink-XnC3MruT.js (removed) 3.03 kB 🟢 -3.03 kB 🟢 -1.16 kB 🟢 -1.02 kB
assets/useDowngradeToPersonal-BKzEeYCn.js (new) 3 kB 🔴 +3 kB 🔴 +1.19 kB 🔴 +1.05 kB
assets/useDowngradeToPersonal-nzGMEaDu.js (removed) 3 kB 🟢 -3 kB 🟢 -1.18 kB 🟢 -1.02 kB
assets/assetPreviewUtil-CHkiRRrj.js (new) 2.41 kB 🔴 +2.41 kB 🔴 +1 kB 🔴 +876 B
assets/assetPreviewUtil-i0rvmfNP.js (removed) 2.41 kB 🟢 -2.41 kB 🟢 -1 kB 🟢 -877 B
assets/useUpstreamValue-B7tMtThJ.js (new) 2.04 kB 🔴 +2.04 kB 🔴 +794 B 🔴 +703 B
assets/useUpstreamValue-DFH-xfqy.js (removed) 2.04 kB 🟢 -2.04 kB 🟢 -793 B 🟢 -703 B
assets/useWorkspaceTierLabel-BQcclyiZ.js (new) 1.99 kB 🔴 +1.99 kB 🔴 +853 B 🔴 +737 B
assets/useWorkspaceTierLabel-CRUJKi3i.js (removed) 1.99 kB 🟢 -1.99 kB 🟢 -852 B 🟢 -734 B
assets/useErrorHandling-B27hywWR.js (new) 1.54 kB 🔴 +1.54 kB 🔴 +646 B 🔴 +556 B
assets/useErrorHandling-B5ZyNvgs.js (removed) 1.54 kB 🟢 -1.54 kB 🟢 -647 B 🟢 -558 B
assets/hdrFormatUtil-Bp_FtymG.js (removed) 1.08 kB 🟢 -1.08 kB 🟢 -516 B 🟢 -436 B
assets/hdrFormatUtil-D-Y86x4W.js (new) 1.08 kB 🔴 +1.08 kB 🔴 +518 B 🔴 +438 B
assets/useClickDragGuard-B3h3Ov-P.js (new) 828 B 🔴 +828 B 🔴 +412 B 🔴 +359 B
assets/useClickDragGuard-B7vIq_1f.js (removed) 828 B 🟢 -828 B 🟢 -412 B 🟢 -360 B
assets/useLoad3d-B0oxgFeY.js (new) 311 B 🔴 +311 B 🔴 +163 B 🔴 +150 B
assets/useLoad3d-mJAM8xbQ.js (removed) 311 B 🟢 -311 B 🟢 -164 B 🟢 -147 B
assets/useSessionCookie-BlM1V4B5.js (new) 101 B 🔴 +101 B 🔴 +86 B 🔴 +80 B
assets/useSessionCookie-gUD_Ddk3.js (removed) 101 B 🟢 -101 B 🟢 -86 B 🟢 -83 B
assets/useFeatureFlags-JuRL8Jdk.js (removed) 98 B 🟢 -98 B 🟢 -85 B 🟢 -82 B
assets/useFeatureFlags-rePnoT5L.js (new) 98 B 🔴 +98 B 🔴 +85 B 🔴 +80 B
assets/useLoad3dViewer-3KLJu3NC.js (new) 98 B 🔴 +98 B 🔴 +85 B 🔴 +88 B
assets/useLoad3dViewer-BOfMwKEB.js (removed) 98 B 🟢 -98 B 🟢 -85 B 🟢 -83 B
assets/useCurrentUser-J4KhPtYE.js (new) 96 B 🔴 +96 B 🔴 +97 B 🔴 +83 B
assets/useCurrentUser-qp2ZO4QP.js (removed) 96 B 🟢 -96 B 🟢 -97 B 🟢 -93 B

Status: 23 added / 23 removed / 10 unchanged

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

External libraries and shared vendor chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/vendor-xterm-CxZK3uIy.js (new) 374 kB 🔴 +374 kB 🔴 +75.6 kB 🔴 +61.1 kB
assets/vendor-xterm-Dw-c804Z.js (removed) 374 kB 🟢 -374 kB 🟢 -75.6 kB 🟢 -61 kB

Status: 1 added / 1 removed / 15 unchanged

Other — 11.7 MB (baseline 11.7 MB) • 🔴 +16.2 kB

Bundles that do not match a named category

File Before After Δ Raw Δ Gzip Δ Brotli
assets/nodeDefs-BVReO2Ir.js (removed) 692 kB 🟢 -692 kB 🟢 -112 kB 🟢 -76.7 kB
assets/nodeDefs-CvenK_Dx.js (new) 692 kB 🔴 +692 kB 🔴 +112 kB 🔴 +76.7 kB
assets/nodeDefs-CECu2fPz.js (new) 634 kB 🔴 +634 kB 🔴 +102 kB 🔴 +71.1 kB
assets/nodeDefs-DEt_ujgC.js (removed) 634 kB 🟢 -634 kB 🟢 -102 kB 🟢 -71.1 kB
assets/nodeDefs-Boy1CVTf.js (new) 631 kB 🔴 +631 kB 🔴 +105 kB 🔴 +73.1 kB
assets/nodeDefs-BOZkNaBV.js (removed) 631 kB 🟢 -631 kB 🟢 -105 kB 🟢 -73.1 kB
assets/nodeDefs-DvtYNaPO.js (removed) 580 kB 🟢 -580 kB 🟢 -102 kB 🟢 -70.7 kB
assets/nodeDefs-pswsxUmn.js (new) 580 kB 🔴 +580 kB 🔴 +102 kB 🔴 +70.7 kB
assets/nodeDefs-BbkaGvv_.js (new) 577 kB 🔴 +577 kB 🔴 +96.2 kB 🔴 +68.5 kB
assets/nodeDefs-BHolcFG0.js (removed) 577 kB 🟢 -577 kB 🟢 -96.2 kB 🟢 -68.5 kB
assets/nodeDefs-daSYebel.js (removed) 559 kB 🟢 -559 kB 🟢 -99.4 kB 🟢 -70 kB
assets/nodeDefs-DOaxTBJc.js (new) 559 kB 🔴 +559 kB 🔴 +99.4 kB 🔴 +70 kB
assets/nodeDefs-C7QsZoqL.js (removed) 556 kB 🟢 -556 kB 🟢 -97.8 kB 🟢 -71 kB
assets/nodeDefs-CPCJb_xt.js (new) 556 kB 🔴 +556 kB 🔴 +97.8 kB 🔴 +71 kB
assets/nodeDefs-CIgpFbzl.js (new) 551 kB 🔴 +551 kB 🔴 +98.5 kB 🔴 +71.5 kB
assets/nodeDefs-DlE0SJ96.js (removed) 551 kB 🟢 -551 kB 🟢 -98.5 kB 🟢 -71.5 kB
assets/nodeDefs-BHxUV7Wu.js (removed) 548 kB 🟢 -548 kB 🟢 -95.3 kB 🟢 -69.2 kB
assets/nodeDefs-rLKHWRy3.js (new) 548 kB 🔴 +548 kB 🔴 +95.3 kB 🔴 +69.2 kB
assets/nodeDefs-CRNmGaHv.js (removed) 541 kB 🟢 -541 kB 🟢 -94.2 kB 🟢 -68.5 kB
assets/nodeDefs-DrCuGidp.js (new) 541 kB 🔴 +541 kB 🔴 +94.2 kB 🔴 +68.5 kB
assets/nodeDefs-BBEK8jGs.js (removed) 504 kB 🟢 -504 kB 🟢 -97.6 kB 🟢 -68.3 kB
assets/nodeDefs-C76U1zck.js (new) 504 kB 🔴 +504 kB 🔴 +97.6 kB 🔴 +68.3 kB
assets/nodeDefs-CWSr3nGp.js (removed) 499 kB 🟢 -499 kB 🟢 -96.2 kB 🟢 -66.8 kB
assets/nodeDefs-IC4I27i_.js (new) 499 kB 🔴 +499 kB 🔴 +96.2 kB 🔴 +66.9 kB
assets/main-9MvXihMA.js (new) 286 kB 🔴 +286 kB 🔴 +71.3 kB 🔴 +55.8 kB
assets/main-9WVPdED5.js (removed) 286 kB 🟢 -286 kB 🟢 -71.4 kB 🟢 -55.8 kB
assets/main-CjhSaP28.js (new) 256 kB 🔴 +256 kB 🔴 +64.6 kB 🔴 +51.7 kB
assets/main-ZsakGBGn.js (removed) 256 kB 🟢 -256 kB 🟢 -64.6 kB 🟢 -51.7 kB
assets/main-BkgeqeNK.js (new) 244 kB 🔴 +244 kB 🔴 +64.1 kB 🔴 +50.9 kB
assets/main-CyKvEzda.js (removed) 244 kB 🟢 -244 kB 🟢 -64.1 kB 🟢 -50.9 kB
assets/main-C1cqicH2.js (new) 235 kB 🔴 +235 kB 🔴 +63.7 kB 🔴 +50.3 kB
assets/main-DxtZVO1O.js (removed) 235 kB 🟢 -235 kB 🟢 -63.7 kB 🟢 -50.3 kB
assets/main-BAB5Pyne.js (removed) 227 kB 🟢 -227 kB 🟢 -61.5 kB 🟢 -49.3 kB
assets/main-CXn-gBN9.js (new) 227 kB 🔴 +227 kB 🔴 +61.5 kB 🔴 +49.3 kB
assets/main-CyaE1Ypn.js (new) 214 kB 🔴 +214 kB 🔴 +62.4 kB 🔴 +51.7 kB
assets/main-DAb8ArUg.js (removed) 214 kB 🟢 -214 kB 🟢 -62.4 kB 🟢 -51.7 kB
assets/main--1gWbj6r.js (new) 212 kB 🔴 +212 kB 🔴 +61.6 kB 🔴 +49.4 kB
assets/main-x8Swm7YW.js (removed) 212 kB 🟢 -212 kB 🟢 -61.7 kB 🟢 -49.4 kB
assets/main-Ca3MK5T7.js (removed) 207 kB 🟢 -207 kB 🟢 -60.7 kB 🟢 -50.2 kB
assets/main-Gi7YXtJj.js (new) 207 kB 🔴 +207 kB 🔴 +60.7 kB 🔴 +50.2 kB
assets/main-BQEkNxa_.js (new) 204 kB 🔴 +204 kB 🔴 +61 kB 🔴 +50.8 kB
assets/main-uG0Jrrrl.js (removed) 204 kB 🟢 -204 kB 🟢 -61 kB 🟢 -50.8 kB
assets/main-CxOf62yR.js (new) 203 kB 🔴 +203 kB 🔴 +60.1 kB 🔴 +50.2 kB
assets/main-zAY2e_61.js (removed) 203 kB 🟢 -203 kB 🟢 -60.1 kB 🟢 -50.2 kB
assets/main-BS3JnXju.js (new) 186 kB 🔴 +186 kB 🔴 +54.7 kB 🔴 +45.9 kB
assets/main-CIXdNL0Z.js (removed) 184 kB 🟢 -184 kB 🟢 -54.1 kB 🟢 -45.4 kB
assets/main-_Ahcbdkk.js (new) 180 kB 🔴 +180 kB 🔴 +59.8 kB 🔴 +47.6 kB
assets/main-BT8KtYQg.js (removed) 180 kB 🟢 -180 kB 🟢 -59.8 kB 🟢 -47.6 kB
assets/main-CBKTaxLV.js (removed) 179 kB 🟢 -179 kB 🟢 -59.7 kB 🟢 -47.3 kB
assets/main-kg-N4bL2.js (new) 179 kB 🔴 +179 kB 🔴 +59.7 kB 🔴 +47.3 kB
assets/core-Bj6_4VoE.js (removed) 119 kB 🟢 -119 kB 🟢 -30.7 kB 🟢 -25.9 kB
assets/core-NVWgHehB.js (new) 119 kB 🔴 +119 kB 🔴 +30.7 kB 🔴 +25.9 kB
assets/WidgetSelect-4qa9CfF8.js (new) 89 kB 🔴 +89 kB 🔴 +20 kB 🔴 +17.2 kB
assets/WidgetSelect-DQdx_RvA.js (removed) 89 kB 🟢 -89 kB 🟢 -20 kB 🟢 -17.2 kB
assets/Load3DControls-BQF4mOl2.js (new) 46.8 kB 🔴 +46.8 kB 🔴 +7.56 kB 🔴 +6.62 kB
assets/Load3DControls-DSVCPb7n.js (removed) 46.8 kB 🟢 -46.8 kB 🟢 -7.56 kB 🟢 -6.62 kB
assets/SubscriptionTransitionPreviewWorkspace-LrlcqSlb.js (removed) 45.7 kB 🟢 -45.7 kB 🟢 -9.48 kB 🟢 -8.37 kB
assets/SubscriptionTransitionPreviewWorkspace-eabmxGko.js (new) 44.6 kB 🔴 +44.6 kB 🔴 +9.19 kB 🔴 +8.13 kB
assets/SubscriptionRequiredDialogContentUnified-DPS5kdng.js (new) 41.2 kB 🔴 +41.2 kB 🔴 +9.15 kB 🔴 +7.96 kB
assets/SubscriptionRequiredDialogContentUnified-pSivMEZ2.js (removed) 41.2 kB 🟢 -41.2 kB 🟢 -9.15 kB 🟢 -7.99 kB
assets/WorkspacePanelContent-CUw_T1Xf.js (new) 34.5 kB 🔴 +34.5 kB 🔴 +7.48 kB 🔴 +6.59 kB
assets/WorkspacePanelContent-DqWE6X-0.js (removed) 34.5 kB 🟢 -34.5 kB 🟢 -7.48 kB 🟢 -6.59 kB
assets/WidgetPainter-CluPVt8R.js (removed) 32.7 kB 🟢 -32.7 kB 🟢 -7.9 kB 🟢 -6.99 kB
assets/WidgetPainter-CS2Q8Wf8.js (new) 32.7 kB 🔴 +32.7 kB 🔴 +7.9 kB 🔴 +7.01 kB
assets/Load3dViewerContent-DZMrKeGi.js (new) 30.9 kB 🔴 +30.9 kB 🔴 +6.3 kB 🔴 +5.46 kB
assets/Load3dViewerContent-sY_LcI_p.js (removed) 30.9 kB 🟢 -30.9 kB 🟢 -6.3 kB 🟢 -5.46 kB
assets/HdrViewerContent-CNzbuRXX.js (removed) 29.2 kB 🟢 -29.2 kB 🟢 -8.09 kB 🟢 -7.14 kB
assets/HdrViewerContent-DOeTwN39.js (new) 29.2 kB 🔴 +29.2 kB 🔴 +8.09 kB 🔴 +7.14 kB
assets/WidgetBoundingBoxes-C0pHs1Vx.js (removed) 28.6 kB 🟢 -28.6 kB 🟢 -7.9 kB 🟢 -7 kB
assets/WidgetBoundingBoxes-Ul7xXh-7.js (new) 28.6 kB 🔴 +28.6 kB 🔴 +7.9 kB 🔴 +7.01 kB
assets/SubscriptionRequiredDialogContent-Caouw-sZ.js (removed) 26.8 kB 🟢 -26.8 kB 🟢 -6.63 kB 🟢 -5.84 kB
assets/SubscriptionRequiredDialogContent-DBKQ3QDY.js (new) 26.8 kB 🔴 +26.8 kB 🔴 +6.63 kB 🔴 +5.84 kB
assets/initHostTelemetry-B873_SZr.js (removed) 25.2 kB 🟢 -25.2 kB 🟢 -6.22 kB 🟢 -5.19 kB
assets/initHostTelemetry-D6zuPZfD.js (new) 25.2 kB 🔴 +25.2 kB 🔴 +6.22 kB 🔴 +5.18 kB
assets/SubscriptionPanelContentWorkspace-Ce80Ln4n.js (removed) 24.8 kB 🟢 -24.8 kB 🟢 -5.77 kB 🟢 -5.07 kB
assets/SubscriptionPanelContentWorkspace-CmxRHdjH.js (new) 24.8 kB 🔴 +24.8 kB 🔴 +5.78 kB 🔴 +5.06 kB
assets/SubscriptionRequiredDialogContentWorkspace-Cs8m57vJ.js (new) 24.6 kB 🔴 +24.6 kB 🔴 +5.65 kB 🔴 +4.97 kB
assets/SubscriptionRequiredDialogContentWorkspace-CXd0aOmB.js (removed) 24.6 kB 🟢 -24.6 kB 🟢 -5.65 kB 🟢 -4.97 kB
assets/WidgetImageCrop-BJmsj7jy.js (removed) 23.3 kB 🟢 -23.3 kB 🟢 -5.75 kB 🟢 -5.04 kB
assets/WidgetImageCrop-XCVb_eQ3.js (new) 23.3 kB 🔴 +23.3 kB 🔴 +5.75 kB 🔴 +5.05 kB
assets/CreditsTile-BjT-KVcF.js (new) 23.1 kB 🔴 +23.1 kB 🔴 +5.83 kB 🔴 +5.16 kB
assets/load3d-BhKOyj7b.js (removed) 21.3 kB 🟢 -21.3 kB 🟢 -5.19 kB 🟢 -4.5 kB
assets/load3d-m66VRj1R.js (new) 21.3 kB 🔴 +21.3 kB 🔴 +5.19 kB 🔴 +4.5 kB
assets/CurrentUserPopoverWorkspace-DsdDzA4u.js (removed) 20.5 kB 🟢 -20.5 kB 🟢 -4.7 kB 🟢 -4.19 kB
assets/CurrentUserPopoverWorkspace-S9dNhiiU.js (new) 20.5 kB 🔴 +20.5 kB 🔴 +4.7 kB 🔴 +4.19 kB
assets/SignInContent-CAAhqGrg.js (new) 20.1 kB 🔴 +20.1 kB 🔴 +5.07 kB 🔴 +4.43 kB
assets/SignInContent-DnD6N2PA.js (removed) 20.1 kB 🟢 -20.1 kB 🟢 -5.07 kB 🟢 -4.42 kB
assets/Load3D-BwttAz7g.js (new) 19.1 kB 🔴 +19.1 kB 🔴 +4.51 kB 🔴 +3.93 kB
assets/Load3D-D-ERiwPl.js (removed) 19.1 kB 🟢 -19.1 kB 🟢 -4.51 kB 🟢 -3.93 kB
assets/WidgetInputNumber-BGTOpc-G.js (new) 19 kB 🔴 +19 kB 🔴 +4.79 kB 🔴 +4.25 kB
assets/WidgetInputNumber-Fu6ZSrrS.js (removed) 19 kB 🟢 -19 kB 🟢 -4.79 kB 🟢 -4.25 kB
assets/commands-8BJa1tUH.js (new) 18.4 kB 🔴 +18.4 kB 🔴 +4 kB 🔴 +3.12 kB
assets/commands-BCR5v4jO.js (removed) 18.4 kB 🟢 -18.4 kB 🟢 -4 kB 🟢 -3.12 kB
assets/commands-DLhPZ1b6.js (removed) 17.5 kB 🟢 -17.5 kB 🟢 -3.65 kB 🟢 -2.88 kB
assets/commands-KWp2QHjJ.js (new) 17.5 kB 🔴 +17.5 kB 🔴 +3.65 kB 🔴 +2.88 kB
assets/commands-DBoEDfRg.js (new) 17.2 kB 🔴 +17.2 kB 🔴 +3.69 kB 🔴 +2.83 kB
assets/commands-ZL67hGVC.js (removed) 17.2 kB 🟢 -17.2 kB 🟢 -3.69 kB 🟢 -2.84 kB
assets/commands-ADMnfph0.js (new) 17.1 kB 🔴 +17.1 kB 🔴 +3.76 kB 🔴 +2.96 kB
assets/commands-DNq7V1Bd.js (removed) 17.1 kB 🟢 -17.1 kB 🟢 -3.77 kB 🟢 -2.96 kB
assets/CreditsTile-BFDsT5Ts.js (removed) 17 kB 🟢 -17 kB 🟢 -4.53 kB 🟢 -3.99 kB
assets/WidgetRecordAudio-8vLdZ6ja.js (removed) 16.6 kB 🟢 -16.6 kB 🟢 -4.63 kB 🟢 -4.13 kB
assets/WidgetRecordAudio-DEdezxgL.js (new) 16.6 kB 🔴 +16.6 kB 🔴 +4.63 kB 🔴 +4.14 kB
assets/commands-BozNMrPH.js (new) 16.6 kB 🔴 +16.6 kB 🔴 +3.79 kB 🔴 +2.99 kB
assets/commands-q6-PsLUZ.js (removed) 16.6 kB 🟢 -16.6 kB 🟢 -3.8 kB 🟢 -2.99 kB
assets/commands-DqZHjSEb.js (new) 16.3 kB 🔴 +16.3 kB 🔴 +3.53 kB 🔴 +2.95 kB
assets/commands-EZNoZhIQ.js (removed) 16.3 kB 🟢 -16.3 kB 🟢 -3.53 kB 🟢 -2.95 kB
assets/WidgetRange-B0c-2jTx.js (removed) 16.2 kB 🟢 -16.2 kB 🟢 -4.17 kB 🟢 -3.73 kB
assets/WidgetRange-CMBhpRjT.js (new) 16.2 kB 🔴 +16.2 kB 🔴 +4.17 kB 🔴 +3.73 kB
assets/commands-Cq6ZsgGb.js (removed) 15.8 kB 🟢 -15.8 kB 🟢 -3.5 kB 🟢 -2.91 kB
assets/commands-DX1BN-nq.js (new) 15.8 kB 🔴 +15.8 kB 🔴 +3.5 kB 🔴 +2.91 kB
assets/commands-aQkHTdTB.js (removed) 15.8 kB 🟢 -15.8 kB 🟢 -3.42 kB 🟢 -2.8 kB
assets/commands-BmFuKeTZ.js (new) 15.8 kB 🔴 +15.8 kB 🔴 +3.42 kB 🔴 +2.8 kB
assets/commands-Dqb6GUHE.js (new) 15.7 kB 🔴 +15.7 kB 🔴 +3.39 kB 🔴 +2.81 kB
assets/commands-Dxp06ttF.js (removed) 15.7 kB 🟢 -15.7 kB 🟢 -3.39 kB 🟢 -2.81 kB
assets/commands-B8qT9HDX.js (new) 15.6 kB 🔴 +15.6 kB 🔴 +3.66 kB 🔴 +2.85 kB
assets/commands-BQu3xLRE.js (removed) 15.6 kB 🟢 -15.6 kB 🟢 -3.65 kB 🟢 -2.85 kB
assets/commands-CNOXwlmE.js (new) 14.9 kB 🔴 +14.9 kB 🔴 +3.59 kB 🔴 +2.74 kB
assets/commands-DeppHLGy.js (removed) 14.9 kB 🟢 -14.9 kB 🟢 -3.59 kB 🟢 -2.72 kB
assets/commands-cQYjl6qv.js (removed) 14.7 kB 🟢 -14.7 kB 🟢 -3.54 kB 🟢 -2.64 kB
assets/commands-J67MQZm-.js (new) 14.7 kB 🔴 +14.7 kB 🔴 +3.54 kB 🔴 +2.64 kB
assets/WaveAudioPlayer-BKaXkLXa.js (new) 12.8 kB 🔴 +12.8 kB 🔴 +3.48 kB 🔴 +3.06 kB
assets/WaveAudioPlayer-Df5Sqmng.js (removed) 12.8 kB 🟢 -12.8 kB 🟢 -3.48 kB 🟢 -3.06 kB
assets/i18n-BwUCL_jj.js (removed) 12.2 kB 🟢 -12.2 kB 🟢 -3.24 kB 🟢 -2.72 kB
assets/i18n-CHTr_V_D.js (new) 12.2 kB 🔴 +12.2 kB 🔴 +3.24 kB 🔴 +2.72 kB
assets/WidgetCurve-D2DUuV4g.js (removed) 11.3 kB 🟢 -11.3 kB 🟢 -3.5 kB 🟢 -3.16 kB
assets/WidgetCurve-D56FSd_7.js (new) 11.3 kB 🔴 +11.3 kB 🔴 +3.5 kB 🔴 +3.16 kB
assets/AudioPreviewPlayer-B_8HKSiq.js (new) 10.6 kB 🔴 +10.6 kB 🔴 +3.06 kB 🔴 +2.73 kB
assets/AudioPreviewPlayer-B4eeGCmh.js (removed) 10.6 kB 🟢 -10.6 kB 🟢 -3.06 kB 🟢 -2.73 kB
assets/TeamWorkspacesDialogContent-Bvu8oOF0.js (removed) 10.3 kB 🟢 -10.3 kB 🟢 -3 kB 🟢 -2.66 kB
assets/TeamWorkspacesDialogContent-CsBRwYIb.js (new) 10.3 kB 🔴 +10.3 kB 🔴 +3 kB 🔴 +2.66 kB
assets/Load3DConfiguration-Cuy6GYWq.js (new) 9.02 kB 🔴 +9.02 kB 🔴 +2.67 kB 🔴 +2.35 kB
assets/Load3DConfiguration-QkafQ3hm.js (removed) 9.02 kB 🟢 -9.02 kB 🟢 -2.66 kB 🟢 -2.35 kB
assets/nodeTemplates-C5CAz__P.js (removed) 8.33 kB 🟢 -8.33 kB 🟢 -2.88 kB 🟢 -2.54 kB
assets/nodeTemplates-PY3erycQ.js (new) 8.33 kB 🔴 +8.33 kB 🔴 +2.88 kB 🔴 +2.54 kB
assets/onboardingCloudRoutes-8vMVRutl.js (new) 8.28 kB 🔴 +8.28 kB 🔴 +2.59 kB 🔴 +2.21 kB
assets/onboardingCloudRoutes-DkJ0yV0w.js (removed) 8.28 kB 🟢 -8.28 kB 🟢 -2.59 kB 🟢 -2.22 kB
assets/WidgetImageCompare-B5EmIv6u.js (removed) 8.19 kB 🟢 -8.19 kB 🟢 -2.33 kB 🟢 -2.04 kB
assets/WidgetImageCompare-C8gBi4zX.js (new) 8.19 kB 🔴 +8.19 kB 🔴 +2.33 kB 🔴 +2.04 kB
assets/NightlySurveyController-BdHoVDVI.js (new) 7.95 kB 🔴 +7.95 kB 🔴 +2.7 kB 🔴 +2.39 kB
assets/NightlySurveyController-DNNU9z8c.js (removed) 7.95 kB 🟢 -7.95 kB 🟢 -2.7 kB 🟢 -2.39 kB
assets/SpendLimitDialogContent-CdEcBshD.js (new) 7.09 kB 🔴 +7.09 kB 🔴 +2.33 kB 🔴 +2.03 kB
assets/InviteMemberDialogContent-IjSoa-xF.js (new) 6.76 kB 🔴 +6.76 kB 🔴 +2.22 kB 🔴 +1.96 kB
assets/InviteMemberDialogContent-VBH0rP4-.js (removed) 6.76 kB 🟢 -6.76 kB 🟢 -2.22 kB 🟢 -1.96 kB
assets/WidgetWithControl-72z5v6av.js (removed) 6.3 kB 🟢 -6.3 kB 🟢 -2.54 kB 🟢 -2.26 kB
assets/WidgetWithControl-BH8KU5n-.js (new) 6.3 kB 🔴 +6.3 kB 🔴 +2.54 kB 🔴 +2.24 kB
assets/AnimationControls-CVxzimKA.js (removed) 6.16 kB 🟢 -6.16 kB 🟢 -1.88 kB 🟢 -1.67 kB
assets/AnimationControls-DgO2ne2n.js (new) 6.16 kB 🔴 +6.16 kB 🔴 +1.88 kB 🔴 +1.67 kB
assets/tierBenefits-Bor1nl1e.js (removed) 5.94 kB 🟢 -5.94 kB 🟢 -1.9 kB 🟢 -1.65 kB
assets/tierBenefits-IxjwvbaO.js (new) 5.94 kB 🔴 +5.94 kB 🔴 +1.9 kB 🔴 +1.65 kB
assets/main-Cc7vEiFz.js (new) 5.7 kB 🔴 +5.7 kB 🔴 +1.83 kB 🔴 +1.56 kB
assets/main-CTItiKsh.js (removed) 5.68 kB 🟢 -5.68 kB 🟢 -1.83 kB 🟢 -1.54 kB
assets/load3dPreviewExtensions-B0R31TDe.js (new) 5.38 kB 🔴 +5.38 kB 🔴 +1.75 kB 🔴 +1.55 kB
assets/load3dPreviewExtensions-DdK8JnB9.js (removed) 5.38 kB 🟢 -5.38 kB 🟢 -1.75 kB 🟢 -1.55 kB
assets/FreeTierDialogContent-Dddu7hGx.js (removed) 5.23 kB 🟢 -5.23 kB 🟢 -1.77 kB 🟢 -1.55 kB
assets/FreeTierDialogContent-DF8wtcO9.js (new) 5.23 kB 🔴 +5.23 kB 🔴 +1.77 kB 🔴 +1.55 kB
assets/CreateWorkspaceDialogContent-Bkud-Y8A.js (new) 5.19 kB 🔴 +5.19 kB 🔴 +1.83 kB 🔴 +1.58 kB
assets/CreateWorkspaceDialogContent-CJAMuXEN.js (removed) 5.19 kB 🟢 -5.19 kB 🟢 -1.83 kB 🟢 -1.58 kB
assets/CloudNotificationContent-nbxgIVrb.js (new) 5.11 kB 🔴 +5.11 kB 🔴 +1.79 kB 🔴 +1.54 kB
assets/CloudNotificationContent-TqZKLgYV.js (removed) 5.11 kB 🟢 -5.11 kB 🟢 -1.79 kB 🟢 -1.54 kB
assets/missingModelDownload-CHrJOta3.js (new) 5.07 kB 🔴 +5.07 kB 🔴 +1.98 kB 🔴 +1.72 kB
assets/missingModelDownload-P9-oWy_E.js (removed) 5.07 kB 🟢 -5.07 kB 🟢 -1.98 kB 🟢 -1.72 kB
assets/ChangeMemberRoleDialogContent-B1Kmb8Vi.js (new) 5.04 kB 🔴 +5.04 kB 🔴 +1.67 kB 🔴 +1.46 kB
assets/ChangeMemberRoleDialogContent-DKVO-ka2.js (removed) 5.04 kB 🟢 -5.04 kB 🟢 -1.67 kB 🟢 -1.46 kB
assets/EditWorkspaceDialogContent-Ccp1ORGG.js (removed) 5 kB 🟢 -5 kB 🟢 -1.79 kB 🟢 -1.56 kB
assets/EditWorkspaceDialogContent-DEolePSw.js (new) 5 kB 🔴 +5 kB 🔴 +1.79 kB 🔴 +1.55 kB
assets/WidgetTextarea-B0zbyXQK.js (new) 4.86 kB 🔴 +4.86 kB 🔴 +1.9 kB 🔴 +1.66 kB
assets/WidgetTextarea-CddxaNe5.js (removed) 4.86 kB 🟢 -4.86 kB 🟢 -1.9 kB 🟢 -1.66 kB
assets/DowngradeRemoveMembersDialogContent-BUAk41fK.js (new) 4.83 kB 🔴 +4.83 kB 🔴 +1.71 kB 🔴 +1.47 kB
assets/DowngradeRemoveMembersDialogContent-C7xCczBY.js (removed) 4.83 kB 🟢 -4.83 kB 🟢 -1.71 kB 🟢 -1.47 kB
assets/saveMesh-BurFpl-Z.js (removed) 4.81 kB 🟢 -4.81 kB 🟢 -1.55 kB 🟢 -1.37 kB
assets/saveMesh-DZp5rlI5.js (new) 4.81 kB 🔴 +4.81 kB 🔴 +1.55 kB 🔴 +1.37 kB
assets/Preview3d-B1yvQ5b1.js (removed) 4.59 kB 🟢 -4.59 kB 🟢 -1.43 kB 🟢 -1.23 kB
assets/Preview3d-BnaV1tFy.js (new) 4.59 kB 🔴 +4.59 kB 🔴 +1.43 kB 🔴 +1.23 kB
assets/ValueControlPopover-COG00dRC.js (removed) 4.55 kB 🟢 -4.55 kB 🟢 -1.59 kB 🟢 -1.42 kB
assets/ValueControlPopover-L_wNzRAq.js (new) 4.55 kB 🔴 +4.55 kB 🔴 +1.59 kB 🔴 +1.42 kB
assets/CancelSubscriptionDialogContent-BoDLotad.js (new) 4.54 kB 🔴 +4.54 kB 🔴 +1.65 kB 🔴 +1.44 kB
assets/CancelSubscriptionDialogContent-C_P1mCWQ.js (removed) 4.54 kB 🟢 -4.54 kB 🟢 -1.65 kB 🟢 -1.44 kB
assets/ApiNodesSignInContent-D54Rnpp9.js (new) 4.14 kB 🔴 +4.14 kB 🔴 +1.34 kB 🔴 +1.2 kB
assets/ApiNodesSignInContent-DmO1amAK.js (removed) 4.14 kB 🟢 -4.14 kB 🟢 -1.34 kB 🟢 -1.18 kB
assets/DeleteWorkspaceDialogContent-BJgRuo6V.js (removed) 3.91 kB 🟢 -3.91 kB 🟢 -1.47 kB 🟢 -1.27 kB
assets/DeleteWorkspaceDialogContent-D3Nmoiov.js (new) 3.91 kB 🔴 +3.91 kB 🔴 +1.47 kB 🔴 +1.27 kB
assets/WidgetGalleria-B7MwER-x.js (removed) 3.8 kB 🟢 -3.8 kB 🟢 -1.48 kB 🟢 -1.32 kB
assets/WidgetGalleria-BROoAR3J.js (new) 3.8 kB 🔴 +3.8 kB 🔴 +1.48 kB 🔴 +1.32 kB
assets/LeaveWorkspaceDialogContent-CO4segP4.js (removed) 3.73 kB 🟢 -3.73 kB 🟢 -1.41 kB 🟢 -1.23 kB
assets/LeaveWorkspaceDialogContent-Z8WUMNDQ.js (new) 3.73 kB 🔴 +3.73 kB 🔴 +1.42 kB 🔴 +1.22 kB
assets/RemoveMemberDialogContent-BgjHdd7y.js (removed) 3.71 kB 🟢 -3.71 kB 🟢 -1.37 kB 🟢 -1.19 kB
assets/RemoveMemberDialogContent-rlbA5g-9.js (new) 3.71 kB 🔴 +3.71 kB 🔴 +1.37 kB 🔴 +1.19 kB
assets/WidgetToggleSwitch-BoNq-Ghy.js (removed) 3.67 kB 🟢 -3.67 kB 🟢 -1.4 kB 🟢 -1.23 kB
assets/WidgetToggleSwitch-ChFSeoQ2.js (new) 3.67 kB 🔴 +3.67 kB 🔴 +1.4 kB 🔴 +1.23 kB
assets/RevokeInviteDialogContent-DdslSyxM.js (new) 3.63 kB 🔴 +3.63 kB 🔴 +1.38 kB 🔴 +1.2 kB
assets/RevokeInviteDialogContent-Dj8QaqJU.js (removed) 3.63 kB 🟢 -3.63 kB 🟢 -1.38 kB 🟢 -1.21 kB
assets/InviteMemberUpsellDialogContent-CCu8tqgY.js (removed) 3.47 kB 🟢 -3.47 kB 🟢 -1.25 kB 🟢 -1.09 kB
assets/InviteMemberUpsellDialogContent-DOZbQE8Y.js (new) 3.47 kB 🔴 +3.47 kB 🔴 +1.25 kB 🔴 +1.09 kB
assets/Media3DTop-ClZUvUn1.js (new) 3.26 kB 🔴 +3.26 kB 🔴 +1.3 kB 🔴 +1.13 kB
assets/Media3DTop-CNvJJqym.js (removed) 3.26 kB 🟢 -3.26 kB 🟢 -1.3 kB 🟢 -1.13 kB
assets/WidgetMarkdown-ClcE_sge.js (new) 3.1 kB 🔴 +3.1 kB 🔴 +1.27 kB 🔴 +1.1 kB
assets/WidgetMarkdown-CnNX4txX.js (removed) 3.1 kB 🟢 -3.1 kB 🟢 -1.27 kB 🟢 -1.1 kB
assets/WidgetInputText-BdfCrD6U.js (new) 3.07 kB 🔴 +3.07 kB 🔴 +1.29 kB 🔴 +1.15 kB
assets/WidgetInputText-DHCFrZsy.js (removed) 3.07 kB 🟢 -3.07 kB 🟢 -1.29 kB 🟢 -1.16 kB
assets/GlobalToast-CXy__emj.js (new) 3.05 kB 🔴 +3.05 kB 🔴 +1.26 kB 🔴 +1.08 kB
assets/GlobalToast-D7m6dGmv.js (removed) 3.05 kB 🟢 -3.05 kB 🟢 -1.26 kB 🟢 -1.08 kB
assets/MediaVideoTop-8jxjx8mO.js (removed) 2.91 kB 🟢 -2.91 kB 🟢 -1.18 kB 🟢 -1.03 kB
assets/MediaVideoTop-DTzoL8dg.js (new) 2.91 kB 🔴 +2.91 kB 🔴 +1.18 kB 🔴 +1.03 kB
assets/load3dAdvanced-07kLnghm.js (new) 2.87 kB 🔴 +2.87 kB 🔴 +1.13 kB 🔴 +979 B
assets/load3dAdvanced-B8hM6HAl.js (removed) 2.87 kB 🟢 -2.87 kB 🟢 -1.13 kB 🟢 -986 B
assets/teamPlanCreditStops-BK6OKGCe.js (removed) 2.83 kB 🟢 -2.83 kB 🟢 -1.3 kB 🟢 -1.11 kB
assets/teamPlanCreditStops-Dlh_rZn8.js (new) 2.83 kB 🔴 +2.83 kB 🔴 +1.3 kB 🔴 +1.11 kB
assets/ErrorPanelSurveyCta-Bwjig1m9.js (new) 2.64 kB 🔴 +2.64 kB 🔴 +1.16 kB 🔴 +1.03 kB
assets/ErrorPanelSurveyCta-C-a7HFki.js (removed) 2.64 kB 🟢 -2.64 kB 🟢 -1.16 kB 🟢 -1.03 kB
assets/SubscribeToRun-BV7RcG8H.js (removed) 2.53 kB 🟢 -2.53 kB 🟢 -1.1 kB 🟢 -968 B
assets/SubscribeToRun-tCxZgLc-.js (new) 2.53 kB 🔴 +2.53 kB 🔴 +1.1 kB 🔴 +966 B
assets/WidgetLayoutField-D2qGWQwb.js (removed) 2.43 kB 🟢 -2.43 kB 🟢 -1.06 kB 🟢 -937 B
assets/WidgetLayoutField-KOMFHYUq.js (new) 2.43 kB 🔴 +2.43 kB 🔴 +1.06 kB 🔴 +936 B
assets/WidgetChart-CUcivpiS.js (removed) 2.41 kB 🟢 -2.41 kB 🟢 -1.03 kB 🟢 -887 B
assets/WidgetChart-GYNALMHB.js (new) 2.41 kB 🔴 +2.41 kB 🔴 +1.03 kB 🔴 +888 B
assets/SubscriptionTermsNote-BS7pfNy2.js (new) 2.37 kB 🔴 +2.37 kB 🔴 +959 B 🔴 +800 B
assets/SubscriptionBenefits-B-DXLZh1.js (removed) 2.07 kB 🟢 -2.07 kB 🟢 -710 B 🟢 -609 B
assets/SubscriptionBenefits-Bk0EbzpD.js (new) 2.07 kB 🔴 +2.07 kB 🔴 +710 B 🔴 +606 B
assets/MediaImageTop-CKOVNt74.js (new) 2.06 kB 🔴 +2.06 kB 🔴 +995 B 🔴 +890 B
assets/MediaImageTop-Cygn2y79.js (removed) 2.06 kB 🟢 -2.06 kB 🟢 -994 B 🟢 -878 B
assets/constants-CbJlHDPr.js (new) 2.04 kB 🔴 +2.04 kB 🔴 +724 B 🔴 +612 B
assets/constants-DY0idKVf.js (removed) 2.04 kB 🟢 -2.04 kB 🟢 -724 B 🟢 -613 B
assets/graphHasMissingNodes-BprXCdbY.js (removed) 1.93 kB 🟢 -1.93 kB 🟢 -907 B 🟢 -803 B
assets/graphHasMissingNodes-ChIwxedH.js (new) 1.93 kB 🔴 +1.93 kB 🔴 +906 B 🔴 +800 B
assets/WidgetColorPicker-BI8fjYbK.js (removed) 1.74 kB 🟢 -1.74 kB 🟢 -786 B 🟢 -693 B
assets/WidgetColorPicker-DBlYQtKM.js (new) 1.74 kB 🔴 +1.74 kB 🔴 +784 B 🔴 +697 B
assets/WidgetColors-B6lGm2oV.js (removed) 1.68 kB 🟢 -1.68 kB 🟢 -832 B 🟢 -738 B
assets/WidgetColors-D56upAer.js (new) 1.68 kB 🔴 +1.68 kB 🔴 +832 B 🔴 +739 B
assets/MediaAudioTop-BZvxa0Ni.js (new) 1.67 kB 🔴 +1.67 kB 🔴 +837 B 🔴 +696 B
assets/MediaAudioTop-Ct8LAsDD.js (removed) 1.67 kB 🟢 -1.67 kB 🟢 -837 B 🟢 -702 B
assets/signInSchema-BNOfvodS.js (removed) 1.6 kB 🟢 -1.6 kB 🟢 -586 B 🟢 -511 B
assets/signInSchema-DQyUOqke.js (new) 1.6 kB 🔴 +1.6 kB 🔴 +587 B 🔴 +509 B
assets/widgetPropFilter-DAGctpLT.js (new) 1.52 kB 🔴 +1.52 kB 🔴 +701 B 🔴 +598 B
assets/widgetPropFilter-Dpa84SyG.js (removed) 1.52 kB 🟢 -1.52 kB 🟢 -704 B 🟢 -604 B
assets/CloudRunButtonWrapper-DCCncbbp.js (removed) 1.13 kB 🟢 -1.13 kB 🟢 -548 B 🟢 -522 B
assets/CloudRunButtonWrapper-GKqaDWKR.js (new) 1.13 kB 🔴 +1.13 kB 🔴 +550 B 🔴 +489 B
assets/MediaOtherTop-ejrLHe36.js (new) 1.08 kB 🔴 +1.08 kB 🔴 +607 B 🔴 +504 B
assets/MediaOtherTop-wWt5rXzg.js (removed) 1.08 kB 🟢 -1.08 kB 🟢 -606 B 🟢 -502 B
assets/MediaTextTop-BmYmtyBm.js (new) 1.06 kB 🔴 +1.06 kB 🔴 +600 B 🔴 +501 B
assets/MediaTextTop-BsXZPdug.js (removed) 1.06 kB 🟢 -1.06 kB 🟢 -600 B 🟢 -503 B
assets/cloudSessionCookie-DBJxw6uC.js (new) 991 B 🔴 +991 B 🔴 +466 B 🔴 +425 B
assets/cloudSessionCookie-QSfrCLyF.js (removed) 991 B 🟢 -991 B 🟢 -466 B 🟢 -418 B
assets/cloudBadges-BTZklu3P.js (removed) 973 B 🟢 -973 B 🟢 -548 B 🟢 -505 B
assets/cloudBadges-DHBtBMw-.js (new) 973 B 🔴 +973 B 🔴 +548 B 🔴 +497 B
assets/ComfyOrgHeader-CB9bZtIQ.js (removed) 960 B 🟢 -960 B 🟢 -530 B 🟢 -464 B
assets/ComfyOrgHeader-D6DG7qLs.js (new) 960 B 🔴 +960 B 🔴 +530 B 🔴 +453 B
assets/nodeTypes-DgIyNkY-.js (removed) 932 B 🟢 -932 B 🟢 -446 B 🟢 -369 B
assets/nodeTypes-PFpwDDmN.js (new) 932 B 🔴 +932 B 🔴 +446 B 🔴 +369 B
assets/load3dSerialize-BEarJvnG.js (new) 885 B 🔴 +885 B 🔴 +424 B 🔴 +359 B
assets/load3dSerialize-BGyX73HL.js (removed) 885 B 🟢 -885 B 🟢 -426 B 🟢 -363 B
assets/WebGLViewport-CiJtIVHv.js (new) 842 B 🔴 +842 B 🔴 +414 B 🔴 +336 B
assets/WebGLViewport-CV29bZH4.js (removed) 842 B 🟢 -842 B 🟢 -418 B 🟢 -339 B
assets/Load3DAdvanced-_kHPUd1Y.js (new) 813 B 🔴 +813 B 🔴 +454 B 🔴 +409 B
assets/Load3DAdvanced-B6D0sH2p.js (removed) 813 B 🟢 -813 B 🟢 -453 B 🟢 -411 B
assets/nightlyBadges-B5Vtci6C.js (new) 464 B 🔴 +464 B 🔴 +306 B 🔴 +254 B
assets/nightlyBadges-DTAd2f5Y.js (removed) 464 B 🟢 -464 B 🟢 -306 B 🟢 -254 B
assets/cloud-subscription-Bc9NQDoO.js (new) 279 B 🔴 +279 B 🔴 +184 B 🔴 +146 B
assets/cloud-subscription-CMkhwSUG.js (removed) 279 B 🟢 -279 B 🟢 -184 B 🟢 -147 B
assets/comfy-logo-single-DiwGj85E.js (removed) 272 B 🟢 -272 B 🟢 -186 B 🟢 -150 B
assets/comfy-logo-single-Dq11FC4M.js (new) 272 B 🔴 +272 B 🔴 +186 B 🔴 +150 B
assets/missingModelDownload--QZXzekX.js (new) 228 B 🔴 +228 B 🔴 +150 B 🔴 +130 B
assets/missingModelDownload-zVOa2vJ3.js (removed) 228 B 🟢 -228 B 🟢 -150 B 🟢 -129 B
assets/SubscriptionPanelContentWorkspace-Df-RroWj.js (new) 179 B 🔴 +179 B 🔴 +117 B 🔴 +93 B
assets/SubscriptionPanelContentWorkspace-n6s0B28p.js (removed) 179 B 🟢 -179 B 🟢 -117 B 🟢 -105 B
assets/Load3dViewerContent-BpF1r1wI.js (new) 137 B 🔴 +137 B 🔴 +103 B 🔴 +92 B
assets/Load3dViewerContent-BsMj5ov3.js (removed) 137 B 🟢 -137 B 🟢 -103 B 🟢 -92 B
assets/Load3DAdvanced-CZN8G2nz.js (new) 122 B 🔴 +122 B 🔴 +97 B 🔴 +102 B
assets/Load3DAdvanced-DBOeg-zE.js (removed) 122 B 🟢 -122 B 🟢 -97 B 🟢 -88 B
assets/WidgetLegacy-D_fjcoGD.js (new) 119 B 🔴 +119 B 🔴 +108 B 🔴 +93 B
assets/WidgetLegacy-DooyWyPW.js (removed) 119 B 🟢 -119 B 🟢 -108 B 🟢 -106 B
assets/workflowDraftStoreV2-CBlGKU9h.js (removed) 113 B 🟢 -113 B 🟢 -105 B 🟢 -115 B
assets/workflowDraftStoreV2-Dpu7fRP9.js (new) 113 B 🔴 +113 B 🔴 +105 B 🔴 +116 B
assets/Load3D-Bx0sod4P.js (removed) 98 B 🟢 -98 B 🟢 -89 B 🟢 -87 B
assets/Load3D-DLgoPO2r.js (new) 98 B 🔴 +98 B 🔴 +89 B 🔴 +81 B
assets/i18n-C0vZK8Al.js (new) 97 B 🔴 +97 B 🔴 +92 B 🔴 +101 B
assets/i18n-DOVcIhor.js (removed) 97 B 🟢 -97 B 🟢 -92 B 🟢 -92 B
assets/changeTracker-BRAxc9cX.js (new) 93 B 🔴 +93 B 🔴 +95 B 🔴 +80 B
assets/changeTracker-Caqe03sO.js (removed) 93 B 🟢 -93 B 🟢 -95 B 🟢 -85 B

Status: 140 added / 138 removed / 27 unchanged

⚡ Performance

⏳ Performance tests in progress…

@coderabbitai

coderabbitai Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 27c11976-c766-417c-aca2-70670ec560d6

📥 Commits

Reviewing files that changed from the base of the PR and between 8f2a24a and 744b105.

📒 Files selected for processing (3)
  • src/platform/workspace/components/SpendLimitDialogContent.vue
  • src/platform/workspace/components/SubscriptionAddPaymentPreviewWorkspace.test.ts
  • src/platform/workspace/components/SubscriptionTransitionPreviewWorkspace.test.ts

📝 Walkthrough

Walkthrough

This PR adds workspace billing support for pending charges and payment-method capabilities, including new workspace API endpoints, feature-flagged settlement flow, owed-balance UI, a pay_owed operation path, and updated consent and localization text.

Changes

Owed Balance Payment Settlement

Layer / File(s) Summary
Billing contracts and state mapping
src/composables/billing/types.ts, src/composables/billing/useBillingContext.ts, src/composables/billing/useLegacyBilling.ts, src/platform/workspace/composables/useWorkspaceBilling.ts, src/storybook/mocks/useBillingContext.ts
Adds payment-method capability fields and pending-charge balance data to billing types and billing-context implementations.
Workspace API and feature flag
src/platform/workspace/api/workspaceApi.ts, src/composables/useFeatureFlags.ts
Adds payment-method/owed-balance API shapes and endpoints, plus the settle-endpoint feature flag accessor.
pay_owed billing operation flow
src/platform/workspace/stores/billingOperationStore.ts, src/platform/workspace/stores/billingOperationStore.test.ts, src/locales/en/main.json
Extends billing operation handling for pay_owed with processing, success, failure, timeout, and derived-state coverage.
Owed balance tile UI
src/platform/cloud/subscription/components/CreditsTile.vue, src/platform/cloud/subscription/components/CreditsTile.test.ts
Adds owed-balance rendering and settlement actions in the credits tile, with supporting tests and localized copy.
Spend-limit dialog and service
src/platform/workspace/components/SpendLimitDialogContent.vue, src/services/dialogService.ts, src/locales/en/main.json
Creates the spend-limit dialog and wires the dialog-service entry point for workspace billing.
Consent note and billing strings
src/platform/workspace/components/SubscriptionTermsNote.vue, src/locales/en/main.json
Adds payment-method consent handling and the related billing consent copy.
Vue i18n test harness
src/platform/workspace/components/SubscriptionAddPaymentPreviewWorkspace.test.ts, src/platform/workspace/components/SubscriptionTransitionPreviewWorkspace.test.ts
Updates the preview tests to preserve original vue-i18n exports while overriding translation helpers.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

Suggested labels: released:cloud, cloud/1.45

Suggested reviewers: christian-byrne, pythongosssss, DrJKL


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
End-To-End Regression Coverage For Fixes ❓ Inconclusive PR title and commit subjects aren’t provided here, so I can’t verify the bug-fix signal required to judge this check. Provide the PR title or commit subjects, since the pass/fail rule depends on whether they use bug-fix language.
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately captures the main change: method-aware billing payment-method UX.
Description check ✅ Passed The description covers the main changes, tests, and rollout notes, though it doesn't follow the template headings exactly.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Adr Compliance For Entity/Litegraph Changes ✅ Passed No changed files touch src/lib/litegraph/, src/ecs/, or graph entity code, so ADR 0003/0008 checks are not applicable.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/payment-method-collection-ux

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.

@wei-hai wei-hai added the cursor-review Trigger multi-model Cursor agent review on this PR label Jul 1, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 10

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/locales/en/main.json`:
- Around line 4497-4506: Add the missing billing.spendLimit.defaultMethod
translation entry in the main locale JSON so SpendLimitDialogContent.vue can
resolve t('billing.spendLimit.defaultMethod') when methodType is falsy. Update
the spendLimit object in src/locales/en/main.json to include a suitable default
method label that matches the existing spend-limit copy and keeps the
methodLabel computed in SpendLimitDialogContent.vue from falling back to a
missing-translation string.

In `@src/platform/cloud/subscription/components/CreditsTile.vue`:
- Around line 326-337: The popup flow in handleOwedAddPaymentMethod does not
handle a blocked window.open result, so add a check on the return value before
proceeding. If window.open returns a falsy value, show a warning toast through
toastStore similar to SpendLimitDialogContent’s handleMainCta, and keep the
existing error handling for initiateAddPaymentMethod failures unchanged. Use
handleOwedAddPaymentMethod and the toastStore pattern as the main touchpoints to
mirror the sibling component’s behavior consistently.
- Around line 356-368: The refresh-button focus logic in CreditsTile.vue is
using a fragile document.querySelector with a localized aria-label, which can
throw and incorrectly fall into the error path after a successful operation.
Replace that lookup with a template ref like the existing payNowButtonRef, and
bind a new refreshButtonRef on the refresh Button in the template. Then update
the success branch in the payment flow to focus refreshButtonRef directly after
nextTick, avoiding any selector built from t('subscription.refreshCredits').
- Around line 339-376: `handlePayNow` in `CreditsTile.vue` is vulnerable to
duplicate submissions because `isPayingOwed` only becomes true after async work
starts. Add a synchronous local in-flight guard (for example a
`isSubmittingPayNow` ref) at the top of `handlePayNow` before calling
`workspaceApi.settleOwedBalance()`, and clear it in a `finally` block. Also
update the pay-now button’s disabled state to include this new guard alongside
`isPayingOwed`, so rapid clicks or repeated keyboard submits cannot re-enter the
flow.

In `@src/platform/workspace/api/workspaceApi.ts`:
- Around line 831-844: The settleOwedBalance flow is currently optional on
idempotency, which allows duplicate settlement on retry. Update
workspaceApi.settleOwedBalance to require an idempotency key (or generate one
before the first call) and propagate it from the CreditsTile.vue caller so every
settlement request is uniquely keyed. Make sure the method signature and the
workspaceApiClient.post payload in settleOwedBalance use the required key
consistently.
- Around line 261-262: Require an idempotency key on settleOwedBalance and
update its call site(s) to always pass one. The current workspaceApi payment
flow allows the endpoint to be invoked without idempotency protection, so adjust
the settleOwedBalance API signature and the caller that uses it to supply a
stable key for retries/double submits. Use the settleOwedBalance method and its
related payment request types in workspaceApi as the main symbols to update.

In `@src/platform/workspace/components/SpendLimitDialogContent.vue`:
- Around line 128-144: `ctaAriaLabel` is out of sync with `ctaLabel` in
`SpendLimitDialogContent.vue`, causing the accessible name to differ from the
visible button text. Update the CTA so it uses the same computed label for both
the displayed text and accessibility, or remove the separate aria-label entirely
since the button already has visible text. Keep the fix localized to the
`ctaLabel` / `ctaAriaLabel` computed values used by the CTA rendering.
- Around line 82-95: Replace the local duplicated capability union in
SpendLimitDialogContent.vue with the shared PaymentMethodCapability type
exported from workspaceApi.ts, and update any matching usage in dialogService.ts
to reference the same type. Keep Scenario defined locally in
SpendLimitDialogContent.vue, but ensure the props and related dialogService
logic use the shared Capability symbol so the union is defined in one place
only.
- Around line 105-115: The labels in SpendLimitDialogContent’s methodLabel logic
are using hardcoded English text instead of vue-i18n. Update METHOD_LABELS and
the fallback in the computed methodLabel to read from translation keys under
billing.spendLimit, and add the matching entries in src/locales/en/main.json so
all user-facing payment method names are localized.

In `@src/platform/workspace/stores/billingOperationStore.ts`:
- Around line 87-94: The messageKey selection in billingOperationStore is using
an implicit catch-all else that assumes every non-subscription and non-topup
type is pay_owed, which can silently mislabel future OperationType values.
Update the branching in the relevant store method to use an explicit pay_owed
check alongside the existing subscription and topup cases, and make the
remaining path fail clearly or be otherwise exhaustive so any new OperationType
must be handled intentionally.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 4506c47a-8a29-40d5-a94b-e0af05fe46cb

📥 Commits

Reviewing files that changed from the base of the PR and between 690e0e3 and 2fae5a2.

📒 Files selected for processing (14)
  • src/composables/billing/types.ts
  • src/composables/billing/useBillingContext.ts
  • src/composables/billing/useLegacyBilling.ts
  • src/composables/useFeatureFlags.ts
  • src/locales/en/main.json
  • src/platform/cloud/subscription/components/CreditsTile.vue
  • src/platform/workspace/api/workspaceApi.ts
  • src/platform/workspace/components/SpendLimitDialogContent.vue
  • src/platform/workspace/components/SubscriptionTermsNote.vue
  • src/platform/workspace/composables/useWorkspaceBilling.ts
  • src/platform/workspace/stores/billingOperationStore.test.ts
  • src/platform/workspace/stores/billingOperationStore.ts
  • src/services/dialogService.ts
  • src/storybook/mocks/useBillingContext.ts

Comment thread src/locales/en/main.json
Comment thread src/platform/cloud/subscription/components/CreditsTile.vue
Comment thread src/platform/cloud/subscription/components/CreditsTile.vue
Comment thread src/platform/cloud/subscription/components/CreditsTile.vue
Comment thread src/platform/workspace/api/workspaceApi.ts
Comment thread src/platform/workspace/api/workspaceApi.ts
Comment thread src/platform/workspace/components/SpendLimitDialogContent.vue
Comment thread src/platform/workspace/components/SpendLimitDialogContent.vue Outdated
Comment thread src/platform/workspace/components/SpendLimitDialogContent.vue
Comment thread src/platform/workspace/stores/billingOperationStore.ts Outdated

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔍 Cursor Review — Consolidated panel

Triggered by @wei-hai.

Found 10 finding(s).

Severity Count
🟠 High 1
🟡 Medium 6
🟢 Low 2
⚪ Nit 1

Panel: 8/8 reviewers contributed findings.

Comment thread src/platform/cloud/subscription/components/CreditsTile.vue Outdated
Comment thread src/platform/cloud/subscription/components/CreditsTile.vue Outdated
Comment thread src/platform/cloud/subscription/components/CreditsTile.vue Outdated
Comment thread src/platform/workspace/components/SpendLimitDialogContent.vue Outdated
Comment thread src/platform/workspace/components/SpendLimitDialogContent.vue
Comment thread src/platform/cloud/subscription/components/CreditsTile.vue Outdated
Comment thread src/platform/cloud/subscription/components/CreditsTile.vue
Comment thread src/platform/cloud/subscription/components/CreditsTile.vue Outdated
Comment thread src/platform/workspace/components/SpendLimitDialogContent.vue Outdated
Comment thread src/platform/cloud/subscription/components/CreditsTile.vue Outdated
…flow

- Add SubscriptionTermsNote (context="payment_method") above the
  add-payment-method CTA in SpendLimitDialogContent (Variants A and B)
  and above the CTA in CreditsTile for none/one_time_only capability

- Add Pay now button to CreditsTile owed-balance notice when
  paymentMethodCapability=reusable and the settle endpoint flag is on;
  passes a crypto.randomUUID() idempotency key to settleOwedBalance()

- Guard handlePayNow with a local ref to prevent double-submission
  before the billing-operation store updates; focus management moves to
  the refresh button on success or pay-now button on failure/cancel

- Validate Stripe redirect URL (hostname must end with .stripe.com)
  before window.open() in both CreditsTile and SpendLimitDialogContent;
  toast + abort on mismatch

- Null-check the window.open() return value and toast a "popup blocked"
  warning when the browser suppresses the popup

- Widen showSpendLimitDialog options with capabilityError?: boolean
  and fix ctaAriaLabel to be consistent with ctaLabel when capabilityError

- Add billing.spendLimit.defaultMethod i18n key used as the fallback
  method label in SpendLimitDialogContent

- Fix test suite: mock useBillingOperationStore with a plain getter for
  isPayingOwed (not a ComputedRef) to match Pinia's auto-unwrap
  behaviour; add mocks for useFeatureFlags, workspaceApi, and
  useToastStore; add 9 owed-balance notice test cases

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

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

⚠️ Outside diff range comments (1)
src/platform/cloud/subscription/components/CreditsTile.vue (1)

147-223: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Add a fallback and permission gate for owed-balance actions

  • Add a loading/disabled branch for paymentMethodCapability === null; otherwise this alert can render with no CTA while status is still loading.
  • Apply permissions.canTopUp here as well so the owed-balance actions match the main top-up button.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/platform/cloud/subscription/components/CreditsTile.vue` around lines 147
- 223, The owed-balance alert in CreditsTile.vue needs a loading fallback and
the same permission gate as the main top-up flow. Update the v-if/v-else-if
branches around the owed balance CTA so paymentMethodCapability === null renders
a disabled or loading state instead of an empty alert, and ensure
handleOwedAddPaymentMethod and handlePayNow are only shown when
permissions.canTopUp is true. Use the existing owedBalanceAmount,
paymentMethodCapability, settleEndpointEnabled, and permissions.canTopUp
conditions to keep the logic consistent.
♻️ Duplicate comments (5)
src/platform/workspace/components/SpendLimitDialogContent.vue (3)

134-154: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

ctaAriaLabel still diverges from ctaLabel for reusable + limit_reached.

For capability === 'reusable' and scenario === 'limit_reached', ctaLabel resolves to updatePaymentMethodCta, but ctaAriaLabel's condition requires scenario === 'payment_failed', so it falls back to addPaymentMethodCta — the accessible name still contradicts the visible button text in this branch. Since the button already renders visible text, the cleanest fix remains removing the separate aria-label.

🛠️ Proposed fix
-const ctaAriaLabel = computed(() => {
-  if (
-    !capabilityError &&
-    capability === 'reusable' &&
-    scenario === 'payment_failed'
-  ) {
-    return t('billing.spendLimit.updatePaymentMethodCta')
-  }
-  return t('billing.spendLimit.addPaymentMethodCta')
-})

Remove the corresponding :aria-label="ctaAriaLabel" binding on the CTA button in the template.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/platform/workspace/components/SpendLimitDialogContent.vue` around lines
134 - 154, The CTA accessible name still diverges from the visible label in
SpendLimitDialogContent.vue because ctaAriaLabel only matches ctaLabel for one
scenario. Remove the separate ctaAriaLabel computed logic and delete the
corresponding :aria-label binding on the CTA button in the template so the
button relies on its visible text for all capability/scenario branches.

Source: Learnings


160-195: 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

window.open missing noopener/noreferrer.

Same gap as CreditsTile.vue's handleOwedAddPaymentMethod: the opened Stripe tab retains window.opener access.

🔒 Proposed fix
-      const paymentWindow = window.open(url, '_blank')
+      const paymentWindow = window.open(url, '_blank', 'noopener,noreferrer')
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/platform/workspace/components/SpendLimitDialogContent.vue` around lines
160 - 195, The `handleMainCta` flow opens the Stripe payment URL with
`window.open` but does not prevent the new tab from accessing `window.opener`.
Update the `window.open` call in `SpendLimitDialogContent.vue` to include the
appropriate `noopener`/`noreferrer` protection, matching the fix used in
`CreditsTile.vue`’s `handleOwedAddPaymentMethod`, and keep the existing
blocked-popup warning behavior unchanged.

111-121: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

METHOD_LABELS values are still hardcoded, unlocalized strings.

The fallback in methodLabel now correctly uses t('billing.spendLimit.defaultMethod'), but the METHOD_LABELS map itself ('Alipay', 'Your card', 'Your bank account', 'Link') still bypasses vue-i18n. As per coding guidelines, src/**/*.{js,ts,vue} must "Use vue-i18n for ALL user-facing strings, configured in src/locales/en/main.json."

🌐 Proposed fix
-const METHOD_LABELS: Record<string, string> = {
-  alipay: 'Alipay',
-  card: 'Your card',
-  us_bank_account: 'Your bank account',
-  link: 'Link'
-}
-
 const methodLabel = computed(() => {
   if (!methodType) return t('billing.spendLimit.defaultMethod')
-  return METHOD_LABELS[methodType] ?? t('billing.spendLimit.defaultMethod')
+  return t(`billing.spendLimit.methodLabels.${methodType}`, {
+    defaultValue: t('billing.spendLimit.defaultMethod')
+  })
 })
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/platform/workspace/components/SpendLimitDialogContent.vue` around lines
111 - 121, The user-facing payment method labels in METHOD_LABELS are still
hardcoded and need to be localized through vue-i18n. Update the methodLabel
computed flow in SpendLimitDialogContent so each method key (alipay, card,
us_bank_account, link) resolves via t(...) keys from the locale files instead of
static English strings, while keeping the existing fallback to
billing.spendLimit.defaultMethod for unknown or missing methods. Use the
existing methodLabel and METHOD_LABELS symbols to locate the mapping and replace
the literal labels with translation-based lookups.

Source: Coding guidelines

src/platform/cloud/subscription/components/CreditsTile.vue (2)

318-326: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Invalid currency can still throw RangeError and crash the tile render.

currency ?? 'USD' only catches null/undefined; an empty string or non-ISO code from the API reaches toLocaleString({ style: 'currency', currency }) uncaught, since this computed has no try/catch and runs inline in the template. This was raised previously and is still unresolved — the diff only added .toUpperCase().

🛡️ Proposed fix
 const owedBalanceAmount = computed(() => {
   const pendingMicros = balance.value?.pendingChargesMicros
   if (pendingMicros == null || pendingMicros <= 0) return null
-  const currency = balance.value?.currency ?? 'USD'
-  return (pendingMicros / 1_000_000).toLocaleString(locale.value, {
-    style: 'currency',
-    currency: currency.toUpperCase()
-  })
+  const currency = balance.value?.currency?.toUpperCase() || 'USD'
+  try {
+    return (pendingMicros / 1_000_000).toLocaleString(locale.value, {
+      style: 'currency',
+      currency
+    })
+  } catch {
+    return (pendingMicros / 1_000_000).toLocaleString(locale.value, {
+      style: 'currency',
+      currency: 'USD'
+    })
+  }
 })
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/platform/cloud/subscription/components/CreditsTile.vue` around lines 318
- 326, The owed balance formatter in the CreditsTile component can still throw a
RangeError when balance.value.currency is empty or invalid, since
owedBalanceAmount uses toLocaleString with currency directly. Update
owedBalanceAmount to defensively validate or sanitize the currency value before
formatting, and fall back to a safe default or null when the API returns a
non-ISO code; keep the fix localized to the computed in CreditsTile.vue so the
template render cannot crash.

336-363: 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Double-submit guard and popup-blocked handling are fixed; window.open still missing noopener.

The synchronous isPayingNow guard and popup-blocked toast address prior critical/major findings. One remaining gap: window.open(url, '_blank') at line 348 doesn't pass noopener,noreferrer, so the opened tab retains window.opener access (reverse-tabnabbing), even though the URL is hostname-validated. Same pattern exists in SpendLimitDialogContent.vue.

🔒 Proposed fix
-    const win = window.open(url, '_blank')
+    const win = window.open(url, '_blank', 'noopener,noreferrer')

Also applies to: 365-405

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/platform/cloud/subscription/components/CreditsTile.vue` around lines 336
- 363, The popup-open flow still uses a plain window.open call without security
flags, leaving the new tab with access to window.opener. Update
handleOwedAddPaymentMethod to open the Stripe URL with noopener,noreferrer in
the target features, and apply the same fix to the matching window.open usage in
SpendLimitDialogContent so both payment-method flows are protected against
reverse-tabnabbing.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/platform/cloud/subscription/components/CreditsTile.test.ts`:
- Around line 450-544: Add test coverage in the `owed balance notice` suite for
the unresolved `paymentMethodCapability === null` state. Use `renderTile()` with
a positive `pendingChargesMicros` and `state.paymentMethodCapability = null`,
then assert the notice renders without an actionable CTA (matching the expected
loading/unresolved behavior). Place the new case alongside the existing
capability-specific tests in `CreditsTile.test.ts` so the behavior is locked in
for `CreditsTile.vue`.

---

Outside diff comments:
In `@src/platform/cloud/subscription/components/CreditsTile.vue`:
- Around line 147-223: The owed-balance alert in CreditsTile.vue needs a loading
fallback and the same permission gate as the main top-up flow. Update the
v-if/v-else-if branches around the owed balance CTA so paymentMethodCapability
=== null renders a disabled or loading state instead of an empty alert, and
ensure handleOwedAddPaymentMethod and handlePayNow are only shown when
permissions.canTopUp is true. Use the existing owedBalanceAmount,
paymentMethodCapability, settleEndpointEnabled, and permissions.canTopUp
conditions to keep the logic consistent.

---

Duplicate comments:
In `@src/platform/cloud/subscription/components/CreditsTile.vue`:
- Around line 318-326: The owed balance formatter in the CreditsTile component
can still throw a RangeError when balance.value.currency is empty or invalid,
since owedBalanceAmount uses toLocaleString with currency directly. Update
owedBalanceAmount to defensively validate or sanitize the currency value before
formatting, and fall back to a safe default or null when the API returns a
non-ISO code; keep the fix localized to the computed in CreditsTile.vue so the
template render cannot crash.
- Around line 336-363: The popup-open flow still uses a plain window.open call
without security flags, leaving the new tab with access to window.opener. Update
handleOwedAddPaymentMethod to open the Stripe URL with noopener,noreferrer in
the target features, and apply the same fix to the matching window.open usage in
SpendLimitDialogContent so both payment-method flows are protected against
reverse-tabnabbing.

In `@src/platform/workspace/components/SpendLimitDialogContent.vue`:
- Around line 134-154: The CTA accessible name still diverges from the visible
label in SpendLimitDialogContent.vue because ctaAriaLabel only matches ctaLabel
for one scenario. Remove the separate ctaAriaLabel computed logic and delete the
corresponding :aria-label binding on the CTA button in the template so the
button relies on its visible text for all capability/scenario branches.
- Around line 160-195: The `handleMainCta` flow opens the Stripe payment URL
with `window.open` but does not prevent the new tab from accessing
`window.opener`. Update the `window.open` call in `SpendLimitDialogContent.vue`
to include the appropriate `noopener`/`noreferrer` protection, matching the fix
used in `CreditsTile.vue`’s `handleOwedAddPaymentMethod`, and keep the existing
blocked-popup warning behavior unchanged.
- Around line 111-121: The user-facing payment method labels in METHOD_LABELS
are still hardcoded and need to be localized through vue-i18n. Update the
methodLabel computed flow in SpendLimitDialogContent so each method key (alipay,
card, us_bank_account, link) resolves via t(...) keys from the locale files
instead of static English strings, while keeping the existing fallback to
billing.spendLimit.defaultMethod for unknown or missing methods. Use the
existing methodLabel and METHOD_LABELS symbols to locate the mapping and replace
the literal labels with translation-based lookups.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: b980ab16-1e59-45b1-8dc2-0945bb2fc589

📥 Commits

Reviewing files that changed from the base of the PR and between 2fae5a2 and a222ad0.

📒 Files selected for processing (5)
  • src/locales/en/main.json
  • src/platform/cloud/subscription/components/CreditsTile.test.ts
  • src/platform/cloud/subscription/components/CreditsTile.vue
  • src/platform/workspace/components/SpendLimitDialogContent.vue
  • src/services/dialogService.ts

Comment thread src/platform/cloud/subscription/components/CreditsTile.test.ts
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jul 1, 2026
- Validate currency code with /^[A-Z]{3}$/ before passing to
  toLocaleString, falling back to USD for empty/invalid values
- Gate owed-balance notice CTAs (terms note + action buttons) behind
  permissions.canTopUp so non-owner members see the balance text but
  not owner-only billing actions
- Add neutral message branch for null paymentMethodCapability (status
  still loading or unavailable) so users are never stuck with no
  feedback
- Add noopener,noreferrer to window.open calls in CreditsTile and
  SpendLimitDialogContent to prevent reverse-tabnabbing
- Fix SpendLimitDialogContent title/ctaLabel to branch on scenario as
  well as capability, making visible label, aria-label, and action
  self-consistent for reusable+limit_reached
- Replace hardcoded English METHOD_LABELS with vue-i18n keys under
  billing.spendLimit.methodLabels
- Import PaymentMethodCapability from workspaceApi instead of
  duplicating the union in SpendLimitDialogContent and dialogService
- Make the pay_owed processing-toast branch explicit in
  billingOperationStore to avoid a silent implicit else
- Add tests: currency fallback, canTopUp gate, null-capability branch

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

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

⚠️ Outside diff range comments (1)
src/services/dialogService.ts (1)

630-634: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Misplaced JSDoc: describes showDowngradeToPersonalDialog, not showSpendLimitDialog.

This docstring ("Downgrade a team plan to a personal plan (FE-977)...") clearly documents showDowngradeToPersonalDialog (defined at line 654), but sits above the newly-inserted showSpendLimitDialog. showDowngradeToPersonalDialog is now left without its own docstring, and readers of showSpendLimitDialog get an unrelated/misleading description.

📝 Proposed fix
-  /**
-   * Downgrade a team plan to a personal plan (FE-977). Skips the type-"I
-   * understand" confirm dialog when the workspace has no other members;
-   * failures on that path surface as an error toast.
-   */
   async function showSpendLimitDialog(options: {
     scenario: 'limit_reached' | 'payment_failed'
     capability: PaymentMethodCapability
     methodType?: string
     capabilityError?: boolean
   }) {
+  /**
+   * Downgrade a team plan to a personal plan (FE-977). Skips the type-"I
+   * understand" confirm dialog when the workspace has no other members;
+   * failures on that path surface as an error toast.
+   */
   async function showDowngradeToPersonalDialog(options: {
     planName: string
     planSlug: string
   }) {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/services/dialogService.ts` around lines 630 - 634, The JSDoc currently
attached to showSpendLimitDialog is actually documenting
showDowngradeToPersonalDialog, so move that comment down to the
showDowngradeToPersonalDialog declaration and add or keep a spend-limit-specific
docstring above showSpendLimitDialog. Use the function names
showSpendLimitDialog and showDowngradeToPersonalDialog to place the comments
correctly so each method has the right description.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/platform/workspace/components/SpendLimitDialogContent.vue`:
- Around line 111-120: The methodLabel computed in SpendLimitDialogContent.vue
eagerly calls t() for all payment methods on every run; refactor it to resolve
only the active methodType key directly and fall back to
billing.spendLimit.defaultMethod when needed. Use the methodLabel computed and
the existing translation keys for alipay, card, us_bank_account, and link to
keep the logic simple and avoid building the labels map.

---

Outside diff comments:
In `@src/services/dialogService.ts`:
- Around line 630-634: The JSDoc currently attached to showSpendLimitDialog is
actually documenting showDowngradeToPersonalDialog, so move that comment down to
the showDowngradeToPersonalDialog declaration and add or keep a
spend-limit-specific docstring above showSpendLimitDialog. Use the function
names showSpendLimitDialog and showDowngradeToPersonalDialog to place the
comments correctly so each method has the right description.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: dd20115f-8d27-43b9-9bc6-2b61d767887a

📥 Commits

Reviewing files that changed from the base of the PR and between a222ad0 and 8f2a24a.

📒 Files selected for processing (6)
  • src/locales/en/main.json
  • src/platform/cloud/subscription/components/CreditsTile.test.ts
  • src/platform/cloud/subscription/components/CreditsTile.vue
  • src/platform/workspace/components/SpendLimitDialogContent.vue
  • src/platform/workspace/stores/billingOperationStore.ts
  • src/services/dialogService.ts

Comment thread src/platform/workspace/components/SpendLimitDialogContent.vue
…rmsNote refactor

SubscriptionTermsNote gained a <script setup> that imports useSettingsDialog,
pulling in dialogService -> @/i18n -> createI18n from vue-i18n. Two existing
tests mocked vue-i18n with only useI18n, so createI18n was undefined at module
load time, collapsing both test suites.

Use importOriginal in both test mocks so all real vue-i18n exports (including
createI18n) are preserved while only useI18n is overridden. Also stub
SubscriptionTermsNote in SubscriptionAddPaymentPreviewWorkspace.test.ts to
prevent the component's setup() from calling useSettingsDialog (which requires
an active Pinia instance not set up in that test).

Also simplify methodLabel computed in SpendLimitDialogContent.vue to look up
the single needed i18n key instead of eagerly translating all four method
labels on every recompute.
@codecov

codecov Bot commented Jul 1, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 28.49741% with 138 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...m/workspace/components/SpendLimitDialogContent.vue 0.00% 67 Missing and 2 partials ⚠️
...form/cloud/subscription/components/CreditsTile.vue 47.88% 37 Missing ⚠️
src/platform/workspace/api/workspaceApi.ts 0.00% 13 Missing ⚠️
...orm/workspace/components/SubscriptionTermsNote.vue 0.00% 8 Missing ⚠️
src/services/dialogService.ts 0.00% 5 Missing ⚠️
src/composables/useFeatureFlags.ts 50.00% 2 Missing ⚠️
...tform/workspace/composables/useWorkspaceBilling.ts 60.00% 2 Missing ⚠️
src/storybook/mocks/useBillingContext.ts 0.00% 2 Missing ⚠️
@@            Coverage Diff             @@
##             main   #13354      +/-   ##
==========================================
- Coverage   76.89%   76.83%   -0.07%     
==========================================
  Files        1636     1640       +4     
  Lines       98625    98836     +211     
  Branches    33194    33262      +68     
==========================================
+ Hits        75842    75943     +101     
- Misses      22067    22177     +110     
  Partials      716      716              
Flag Coverage Δ
unit 65.37% <28.49%> (-0.02%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
src/composables/billing/useBillingContext.ts 73.50% <100.00%> (+0.35%) ⬆️
src/composables/billing/useLegacyBilling.ts 66.66% <100.00%> (+0.56%) ⬆️
...platform/workspace/stores/billingOperationStore.ts 65.53% <100.00%> (+1.69%) ⬆️
src/composables/useFeatureFlags.ts 75.23% <50.00%> (-1.24%) ⬇️
...tform/workspace/composables/useWorkspaceBilling.ts 71.49% <60.00%> (-0.41%) ⬇️
src/storybook/mocks/useBillingContext.ts 0.00% <0.00%> (ø)
src/services/dialogService.ts 51.11% <0.00%> (-1.17%) ⬇️
...orm/workspace/components/SubscriptionTermsNote.vue 11.11% <0.00%> (-22.23%) ⬇️
src/platform/workspace/api/workspaceApi.ts 40.96% <0.00%> (-1.67%) ⬇️
...form/cloud/subscription/components/CreditsTile.vue 79.71% <47.88%> (-16.62%) ⬇️
... and 1 more

... and 15 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@wei-hai

wei-hai commented Jul 1, 2026

Copy link
Copy Markdown
Contributor Author

Closing for now: payment-method capture is handled server-side (hosted checkout + webhook); the method-aware prompt UX is deferred. Branch retained.

@wei-hai wei-hai closed this Jul 1, 2026
@github-actions github-actions Bot locked and limited conversation to collaborators Jul 1, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

cursor-review Trigger multi-model Cursor agent review on this PR size:XL This PR changes 500-999 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant