[backport cloud/1.50] fix: bound auth wait in startStoreBootstrap + catch-all for unknown routes (IR-105) - #15180
Conversation
…outes (IR-105) (#15063) ## Summary Two durable fixes for the IR-105 splash-screen hang incident. ### Fix 1 — Bootstrap auth wait timeout (`bootstrapStore.ts`) **Root cause:** `until(isInitialized).toBe(true)` and `until(isAuthenticated).toBe(true)` in `startStoreBootstrap` have no timeout. A stale Firebase session or broken auth response hangs bootstrap silently and indefinitely — no error, no log, just a forever splash screen. **Fix:** Extract `waitForCloudAuth()` with: - 16 s timeout (matching `router.ts:176` and `WorkspaceAuthGate.vue:78` — existing convention) - One retry after 3 s backoff - On second timeout: `captureException` to Sentry + **continue bootstrap** rather than blocking This means the worst case is now 35 s to a usable (logged-out) state instead of infinity. ### Fix 2 — Catch-all route for unknown paths (`router.ts`) **Root cause:** A request to e.g. `cloud.comfy.org/woiadawd` gets a 200 + app shell from the static host, Vue boots, finds **no matching route**, and the global auth guard's `until(isInitialized)` then hangs (see Fix 1). Even with Fix 1, a no-match route leaves the app on the splash screen. **Fix:** Add `{ path: '/:pathMatch(.*)*', redirect: '/' }` at the end of the route list. Unknown paths redirect to root; the global auth guard then sends unauthenticated users to `/cloud/login` as normal. ## Red-Green Verification | Commit | Purpose | |--------|---------| | `test: add failing tests for unbounded auth wait in startStoreBootstrap` | 🔴 Proves test catches the bug — the "gives up" test times out in 5 s against the unpatched code | | `fix: bound auth wait in startStoreBootstrap and add catch-all route` | 🟢 Both new tests pass, all 18 tests in the two affected files pass | ## Relation to open PRs - Supersedes / closes the scope of #15032 (`fix/bootstrap-auth-wait-timeout`) — same fix, same tests. If reviewers prefer to land #15032 first this PR can drop Fix 1. - Companion to #15022 (marketing-site redirect) and #15026 (`/login` → `cloud-login` route, already on main). ## Test Plan - [x] `pnpm vitest run src/stores/bootstrapStore.test.ts` — 7/7 pass (including 2 new timeout tests) - [x] `pnpm vitest run src/platform/cloud/onboarding/onboardingCloudRoutes.test.ts` — 11/11 pass - [x] `pnpm typecheck` — clean - [x] `pnpm exec eslint src/stores/bootstrapStore.ts src/router.ts` — clean - [ ] CI green (Playwright, Storybook, Codecov) 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: GitHub Action <action@github.com>
🎨 Storybook: ✅ Built — View Storybook🎭 Playwright: ✅ 1795 passed, 0 failed · 4 flaky📊 Browser Reports
📦 Bundle Size
⚡ Performance Report
Absolute values
Raw data{
"timestamp": "2026-08-13T05:03:50.203Z",
"gitSha": "834036eec330c85271afc24a7e8adcfb173af11b",
"branch": "backport-15063-to-cloud-1.50",
"measurements": [
{
"name": "canvas-idle",
"durationMs": 2029.4880000000148,
"styleRecalcs": 7,
"styleRecalcDurationMs": 6.744,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 545.9200000000001,
"heapDeltaBytes": 5850012,
"heapUsedBytes": 70638948,
"domNodes": 14,
"jsHeapTotalBytes": 24641536,
"scriptDurationMs": 19.311000000000003,
"eventListeners": 6,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "canvas-idle",
"durationMs": 2038.1150000000616,
"styleRecalcs": 10,
"styleRecalcDurationMs": 9.5,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 491.6070000000001,
"heapDeltaBytes": 5967688,
"heapUsedBytes": 70608312,
"domNodes": 20,
"jsHeapTotalBytes": 24641536,
"scriptDurationMs": 21.080000000000002,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333335,
"p95FrameDurationMs": 16.699999999999818
},
{
"name": "canvas-mouse-sweep",
"durationMs": 1940.5669999999873,
"styleRecalcs": 75,
"styleRecalcDurationMs": 40.739,
"layouts": 12,
"layoutDurationMs": 3.6109999999999998,
"taskDurationMs": 962.828,
"heapDeltaBytes": -15216648,
"heapUsedBytes": 49431740,
"domNodes": -282,
"jsHeapTotalBytes": 22519808,
"scriptDurationMs": 133.192,
"eventListeners": -151,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "canvas-mouse-sweep",
"durationMs": 1857.0079999999507,
"styleRecalcs": 76,
"styleRecalcDurationMs": 38.663999999999994,
"layouts": 12,
"layoutDurationMs": 3.488,
"taskDurationMs": 860.251,
"heapDeltaBytes": 475888,
"heapUsedBytes": 65276952,
"domNodes": 59,
"jsHeapTotalBytes": 25165824,
"scriptDurationMs": 125.774,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "canvas-zoom-sweep",
"durationMs": 1739.2970000000219,
"styleRecalcs": 32,
"styleRecalcDurationMs": 18.700000000000003,
"layouts": 6,
"layoutDurationMs": 0.7210000000000001,
"taskDurationMs": 398.199,
"heapDeltaBytes": 8925344,
"heapUsedBytes": 73482792,
"domNodes": 77,
"jsHeapTotalBytes": 25165824,
"scriptDurationMs": 22.765,
"eventListeners": 19,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "canvas-zoom-sweep",
"durationMs": 1742.9179999999178,
"styleRecalcs": 32,
"styleRecalcDurationMs": 18.358000000000004,
"layouts": 6,
"layoutDurationMs": 0.696,
"taskDurationMs": 428.951,
"heapDeltaBytes": 8634668,
"heapUsedBytes": 73206856,
"domNodes": 78,
"jsHeapTotalBytes": 24903680,
"scriptDurationMs": 27.031,
"eventListeners": 19,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "dom-widget-clipping",
"durationMs": 603.2999999999902,
"styleRecalcs": 10,
"styleRecalcDurationMs": 6.7269999999999985,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 385.974,
"heapDeltaBytes": -11015888,
"heapUsedBytes": 53572516,
"domNodes": 16,
"jsHeapTotalBytes": 25427968,
"scriptDurationMs": 60.899,
"eventListeners": 2,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.699999999999818
},
{
"name": "dom-widget-clipping",
"durationMs": 574.9160000000302,
"styleRecalcs": 11,
"styleRecalcDurationMs": 7.447999999999998,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 378.347,
"heapDeltaBytes": -11273336,
"heapUsedBytes": 53538316,
"domNodes": 18,
"jsHeapTotalBytes": 25427968,
"scriptDurationMs": 59.23699999999999,
"eventListeners": 2,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "large-graph-idle",
"durationMs": 2031.5259999999853,
"styleRecalcs": 8,
"styleRecalcDurationMs": 8.614999999999998,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 700.2570000000002,
"heapDeltaBytes": 6859052,
"heapUsedBytes": 66953784,
"domNodes": -284,
"jsHeapTotalBytes": 4034560,
"scriptDurationMs": 113.10100000000001,
"eventListeners": -149,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "large-graph-idle",
"durationMs": 2056.940999999938,
"styleRecalcs": 8,
"styleRecalcDurationMs": 11.269000000000002,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 694.207,
"heapDeltaBytes": 7686084,
"heapUsedBytes": 67772372,
"domNodes": -284,
"jsHeapTotalBytes": 3510272,
"scriptDurationMs": 116.056,
"eventListeners": -149,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "large-graph-pan",
"durationMs": 2199.1649999999936,
"styleRecalcs": 69,
"styleRecalcDurationMs": 14.188999999999997,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 1321.862,
"heapDeltaBytes": 4749108,
"heapUsedBytes": 65674656,
"domNodes": -284,
"jsHeapTotalBytes": 4751360,
"scriptDurationMs": 442.05899999999997,
"eventListeners": -149,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333335,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "large-graph-pan",
"durationMs": 2170.5950000000485,
"styleRecalcs": 68,
"styleRecalcDurationMs": 13.710000000000003,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 1346.976,
"heapDeltaBytes": 1553364,
"heapUsedBytes": 62471504,
"domNodes": -287,
"jsHeapTotalBytes": 4227072,
"scriptDurationMs": 451.878,
"eventListeners": -149,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.670000000000012,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "large-graph-zoom",
"durationMs": 3229.4780000000287,
"styleRecalcs": 64,
"styleRecalcDurationMs": 14.604000000000003,
"layouts": 60,
"layoutDurationMs": 7.244,
"taskDurationMs": 1510.6739999999998,
"heapDeltaBytes": 24754908,
"heapUsedBytes": 87227244,
"domNodes": 10,
"jsHeapTotalBytes": 7340032,
"scriptDurationMs": 544.8960000000001,
"eventListeners": 8,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "large-graph-zoom",
"durationMs": 3310.9379999999646,
"styleRecalcs": 65,
"styleRecalcDurationMs": 15.099000000000002,
"layouts": 60,
"layoutDurationMs": 7.413,
"taskDurationMs": 1630.2839999999999,
"heapDeltaBytes": 4021068,
"heapUsedBytes": 66653372,
"domNodes": -287,
"jsHeapTotalBytes": 6131712,
"scriptDurationMs": 581.155,
"eventListeners": -153,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "minimap-idle",
"durationMs": 2011.8820000000142,
"styleRecalcs": 9,
"styleRecalcDurationMs": 8.973000000000003,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 705.5089999999999,
"heapDeltaBytes": 5944580,
"heapUsedBytes": 66878532,
"domNodes": -284,
"jsHeapTotalBytes": 4034560,
"scriptDurationMs": 115.15400000000001,
"eventListeners": -151,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "minimap-idle",
"durationMs": 2067.9139999999734,
"styleRecalcs": 7,
"styleRecalcDurationMs": 6.814000000000001,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 747.9490000000001,
"heapDeltaBytes": 5002656,
"heapUsedBytes": 65886052,
"domNodes": -283,
"jsHeapTotalBytes": 2723840,
"scriptDurationMs": 126.58900000000001,
"eventListeners": -179,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-dom-widget-clipping",
"durationMs": 590.8230000000003,
"styleRecalcs": 47,
"styleRecalcDurationMs": 10.738000000000001,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 406.18199999999996,
"heapDeltaBytes": -10729684,
"heapUsedBytes": 54244580,
"domNodes": 20,
"jsHeapTotalBytes": 26476544,
"scriptDurationMs": 118.60699999999999,
"eventListeners": 8,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-dom-widget-clipping",
"durationMs": 595.8669999999984,
"styleRecalcs": 46,
"styleRecalcDurationMs": 9.531,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 411.69000000000005,
"heapDeltaBytes": -10620612,
"heapUsedBytes": 54091304,
"domNodes": 18,
"jsHeapTotalBytes": 26214400,
"scriptDurationMs": 126.11,
"eventListeners": 6,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.699999999999818
},
{
"name": "subgraph-idle",
"durationMs": 2004.0919999999574,
"styleRecalcs": 9,
"styleRecalcDurationMs": 8.946000000000002,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 473.908,
"heapDeltaBytes": 6023316,
"heapUsedBytes": 70672500,
"domNodes": 18,
"jsHeapTotalBytes": 24117248,
"scriptDurationMs": 16.421,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-idle",
"durationMs": 2007.4010000000726,
"styleRecalcs": 11,
"styleRecalcDurationMs": 9.82,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 471.93600000000004,
"heapDeltaBytes": 5906396,
"heapUsedBytes": 70774860,
"domNodes": 22,
"jsHeapTotalBytes": 24641536,
"scriptDurationMs": 14.55,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "subgraph-mouse-sweep",
"durationMs": 1725.375999999983,
"styleRecalcs": 76,
"styleRecalcDurationMs": 38.884,
"layouts": 16,
"layoutDurationMs": 4.746,
"taskDurationMs": 804.091,
"heapDeltaBytes": -3189776,
"heapUsedBytes": 61628532,
"domNodes": 62,
"jsHeapTotalBytes": 24641536,
"scriptDurationMs": 98.92200000000001,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.699999999999818
},
{
"name": "subgraph-mouse-sweep",
"durationMs": 1694.2450000000235,
"styleRecalcs": 77,
"styleRecalcDurationMs": 36.658,
"layouts": 16,
"layoutDurationMs": 4.194,
"taskDurationMs": 764.9469999999999,
"heapDeltaBytes": -3211536,
"heapUsedBytes": 61357144,
"domNodes": 65,
"jsHeapTotalBytes": 24641536,
"scriptDurationMs": 93.45200000000001,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-transition-enter",
"durationMs": 1417.3039999999446,
"styleRecalcs": 18,
"styleRecalcDurationMs": 30.872999999999998,
"layouts": 14,
"layoutDurationMs": 12.849000000000002,
"taskDurationMs": 1020.0180000000001,
"heapDeltaBytes": 8593592,
"heapUsedBytes": 101124920,
"domNodes": 13673,
"jsHeapTotalBytes": 11534336,
"scriptDurationMs": 40.39299999999999,
"eventListeners": 2375,
"totalBlockingTimeMs": 142,
"frameDurationMs": 16.666666666666636,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "viewport-pan-sweep",
"durationMs": 8409.800000000017,
"styleRecalcs": 250,
"styleRecalcDurationMs": 38.193999999999996,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 4680.695,
"heapDeltaBytes": 71540,
"heapUsedBytes": 59223020,
"domNodes": -282,
"jsHeapTotalBytes": 4296704,
"scriptDurationMs": 1430.433,
"eventListeners": -163,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "viewport-pan-sweep",
"durationMs": 8446.217000000048,
"styleRecalcs": 250,
"styleRecalcDurationMs": 39.044999999999995,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 4760.259,
"heapDeltaBytes": 10620856,
"heapUsedBytes": 71102720,
"domNodes": -285,
"jsHeapTotalBytes": 4751360,
"scriptDurationMs": 1458.901,
"eventListeners": -133,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "vue-large-graph-idle",
"durationMs": 17164.556000000004,
"styleRecalcs": 0,
"styleRecalcDurationMs": 0,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 17145.865,
"heapDeltaBytes": -60365824,
"heapUsedBytes": 165993292,
"domNodes": -8312,
"jsHeapTotalBytes": -9641984,
"scriptDurationMs": 538.516,
"eventListeners": -16385,
"totalBlockingTimeMs": 0,
"frameDurationMs": 18.329999999999927,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "vue-large-graph-idle",
"durationMs": 17188.600000000064,
"styleRecalcs": 0,
"styleRecalcDurationMs": 0,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 17169.115999999998,
"heapDeltaBytes": -35680232,
"heapUsedBytes": 167865696,
"domNodes": -8312,
"jsHeapTotalBytes": -8327168,
"scriptDurationMs": 581.171,
"eventListeners": -16389,
"totalBlockingTimeMs": 0,
"frameDurationMs": 18.333333333333332,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "vue-large-graph-pan",
"durationMs": 20758.488,
"styleRecalcs": 144,
"styleRecalcDurationMs": 18.093999999999998,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 20723.051,
"heapDeltaBytes": -74875700,
"heapUsedBytes": 154545728,
"domNodes": -8312,
"jsHeapTotalBytes": -8069120,
"scriptDurationMs": 928.177,
"eventListeners": -16387,
"totalBlockingTimeMs": 195,
"frameDurationMs": 17.776666666666642,
"p95FrameDurationMs": 16.80000000000291
},
{
"name": "vue-large-graph-pan",
"durationMs": 20667.12599999994,
"styleRecalcs": 141,
"styleRecalcDurationMs": 17.342000000000024,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 20630.866,
"heapDeltaBytes": -48335688,
"heapUsedBytes": 157904080,
"domNodes": -8312,
"jsHeapTotalBytes": -9375744,
"scriptDurationMs": 898.174,
"eventListeners": -16387,
"totalBlockingTimeMs": 127,
"frameDurationMs": 17.780000000000047,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "workflow-execution",
"durationMs": 480.8219999999892,
"styleRecalcs": 16,
"styleRecalcDurationMs": 22.944,
"layouts": 4,
"layoutDurationMs": 1.595,
"taskDurationMs": 128,
"heapDeltaBytes": 5191820,
"heapUsedBytes": 68871916,
"domNodes": 148,
"jsHeapTotalBytes": 5242880,
"scriptDurationMs": 10.853000000000002,
"eventListeners": 99,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "workflow-execution",
"durationMs": 488.9290000000983,
"styleRecalcs": 17,
"styleRecalcDurationMs": 22.295999999999996,
"layouts": 3,
"layoutDurationMs": 1.2069999999999999,
"taskDurationMs": 123.94300000000001,
"heapDeltaBytes": 5287440,
"heapUsedBytes": 69116564,
"domNodes": 145,
"jsHeapTotalBytes": 4980736,
"scriptDurationMs": 12.443000000000001,
"eventListeners": 97,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.700000000000728
}
]
} |
Codecov Report✅ All modified and coverable lines are covered by tests. @@ Coverage Diff @@
## cloud/1.50 #15180 +/- ##
=============================================
Coverage ? 81.33%
=============================================
Files ? 1872
Lines ? 106229
Branches ? 32727
=============================================
Hits ? 86398
Misses ? 19475
Partials ? 356
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
Backport of #15063 to
cloud/1.50Automatically created by backport workflow.