From 335347a56f4f5606fd0f2ff25951483a4f0788f7 Mon Sep 17 00:00:00 2001 From: lucamzanon Date: Thu, 10 Sep 2026 10:11:37 +0200 Subject: [PATCH] fix: detect HTTP/2 from the initial navigation timing so accounts aren't capped at five isHttp2Available() only inspected "resource" timing entries, which can be empty right after a fresh login or session restore, before any subresource finishes loading. On an HTTP/2 page this made getMaxAccounts() fall back to the HTTP/1.1 cap of five accounts. Include the "navigation" timing entry, whose nextHopProtocol is known immediately, so h2/h3 is recognized on first load. Environments without timing data still return false (no h2 assumed). --- lib/__tests__/account-utils-http2.test.ts | 13 +++++++++++++ lib/account-utils.ts | 8 +++++++- 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 lib/__tests__/account-utils-http2.test.ts diff --git a/lib/__tests__/account-utils-http2.test.ts b/lib/__tests__/account-utils-http2.test.ts new file mode 100644 index 000000000..9a10c5f7b --- /dev/null +++ b/lib/__tests__/account-utils-http2.test.ts @@ -0,0 +1,13 @@ +import { afterEach, describe, expect, it, vi } from 'vitest'; +import { getMaxAccounts, MAX_ACCOUNT_SLOTS } from '../account-utils'; +afterEach(() => vi.restoreAllMocks()); +describe('account limit protocol detection', () => { + it('recognizes HTTP/2 from document navigation before resources load', () => { + vi.spyOn(performance, 'getEntriesByType').mockImplementation(type => type === 'navigation' ? [{ nextHopProtocol: 'h2' } as PerformanceResourceTiming] : []); + expect(getMaxAccounts()).toBe(MAX_ACCOUNT_SLOTS); + }); + it('retains the conservative cap when no multiplexed protocol was observed', () => { + vi.spyOn(performance, 'getEntriesByType').mockReturnValue([{ nextHopProtocol: 'http/1.1' } as PerformanceResourceTiming]); + expect(getMaxAccounts()).toBe(5); + }); +}); diff --git a/lib/account-utils.ts b/lib/account-utils.ts index 41204e37b..1f08671c0 100644 --- a/lib/account-utils.ts +++ b/lib/account-utils.ts @@ -87,7 +87,13 @@ export const MAX_ACCOUNTS_HTTP1 = 5; */ export function isHttp2Available(): boolean { if (typeof performance === 'undefined') return false; - const entries = performance.getEntriesByType('resource') as PerformanceResourceTiming[]; + // The document connection is already known before any subresources finish + // loading. Include it so a fresh login/restore doesn't incorrectly cap an + // HTTP/2 page at five accounts. Do not assume h2 when timing is unavailable. + const entries = [ + ...performance.getEntriesByType('navigation'), + ...performance.getEntriesByType('resource'), + ] as PerformanceResourceTiming[]; for (let i = entries.length - 1; i >= 0; i--) { const proto = entries[i].nextHopProtocol; if (proto === 'h2' || proto === 'h3') return true;