@@ -14,14 +14,7 @@ import {
1414 createCookieStoreAccess ,
1515 createDocumentCookieAccess ,
1616} from '../../../browser/cookieAccess'
17- import { timeStampNow , dateNow } from '../../../tools/utils/timeUtils'
18- import { addTelemetryError } from '../../telemetry'
19-
20- const LOCK_QUERY_TIMEOUT = 1000
2117import type { CookieStoreWindow } from '../../../browser/browser.types'
22- import { getLifecycleContext } from '../../../browser/lifecycleTracker'
23- import { clearTimeout , setTimeout } from '../../../tools/timer'
24- import type { Context } from '../../../tools/serialisation/context'
2518import { CookieApi , LEGACY_SESSION_STORE_KEY , SESSION_STORE_KEY } from './sessionStoreStrategy'
2619import type {
2720 SessionStoreStrategy ,
@@ -68,7 +61,6 @@ export function initCookieStrategy(
6861 const opts = encodeCookieOptions ( cookieOptions )
6962 const cookieAccess = mockable ( createCookieAccess ) ( cookieApi , configuration , cookieOptions )
7063 let isFirstCall = true
71- const initTimestamp = timeStampNow ( )
7264
7365 cookieAccess . observable . subscribe ( ( ) => {
7466 cookieAccess
@@ -99,15 +91,15 @@ export function initCookieStrategy(
9991 return {
10092 async setSessionState (
10193 fn : ( sessionState : SessionState ) => SessionState ,
102- operation : SessionStateOperation
94+ _operation : SessionStateOperation
10395 ) : Promise < void > {
10496 if ( typeof navigator !== 'undefined' && navigator . locks ) {
105- const lockRequestedAt = dateNow ( )
10697 await navigator . locks
10798 . request ( SESSION_STORE_KEY , ( ) => applyAndWrite ( fn ) )
108- . catch ( async ( error ) => {
109- const context = await buildLockErrorContext ( operation , initTimestamp , lockRequestedAt )
110- addTelemetryError ( error , context )
99+ . catch ( ( error : unknown ) => {
100+ if ( isContextGoingAwayError ( error ) ) {
101+ return
102+ }
111103 throw error
112104 } )
113105 } else {
@@ -119,76 +111,14 @@ export function initCookieStrategy(
119111 }
120112}
121113
122- interface LockQuerySnapshot {
123- heldByOthers : number
124- pendingCount : number
125- isPending : boolean
126- }
127-
128- async function queryLockSnapshot ( ) : Promise < LockQuerySnapshot | 'timeout' | 'unavailable' | 'error' > {
129- if ( typeof navigator === 'undefined' || ! navigator . locks ?. query ) {
130- return 'unavailable'
131- }
132- let timeoutId : ReturnType < typeof setTimeout > | undefined
133- const timeout = new Promise < 'timeout' > ( ( resolve ) => {
134- timeoutId = setTimeout ( ( ) => resolve ( 'timeout' ) , LOCK_QUERY_TIMEOUT )
135- } )
136- try {
137- const snapshot = await Promise . race ( [ navigator . locks . query ( ) , timeout ] )
138- if ( snapshot === 'timeout' ) {
139- return 'timeout'
140- }
141- const held = snapshot . held ?? [ ]
142- const pending = snapshot . pending ?? [ ]
143- return {
144- heldByOthers : held . filter ( ( lock ) => lock . name === SESSION_STORE_KEY ) . length ,
145- pendingCount : pending . filter ( ( lock ) => lock . name === SESSION_STORE_KEY ) . length ,
146- isPending : pending . some ( ( lock ) => lock . name === SESSION_STORE_KEY ) ,
147- }
148- } catch {
149- return 'error'
150- } finally {
151- clearTimeout ( timeoutId )
152- }
153- }
154-
155- function getNavigationType ( ) : string | undefined {
156- if ( typeof performance === 'undefined' || typeof performance . getEntriesByType !== 'function' ) {
157- return undefined
158- }
159- // The document-load entry is what we want here ('back_forward' signals bfcache restore).
160- // Some Chromium builds expose extra entries for experimental soft navigations β index 0 is
161- // still the original document-load entry per the Performance Timeline ordering.
162- const entry = performance . getEntriesByType ( 'navigation' ) [ 0 ] as PerformanceNavigationTiming | undefined
163- return entry ?. type
164- }
165-
166- function isInIframe ( ) : boolean | undefined {
167- try {
168- return window !== window . top
169- } catch {
170- // Cross-origin access β definitely in an iframe
171- return true
172- }
173- }
174-
175- async function buildLockErrorContext (
176- operation : SessionStateOperation ,
177- initTimestamp : number ,
178- lockRequestedAt : number
179- ) : Promise < Context > {
180- return {
181- operation,
182- timeSinceInit : dateNow ( ) - initTimestamp ,
183- lockRequestDuration : dateNow ( ) - lockRequestedAt ,
184- visibilityState : document . visibilityState ,
185- readyState : document . readyState ,
186- inIframe : isInIframe ( ) ,
187- navigationType : getNavigationType ( ) ,
188- sessionCookies : getCookies ( SESSION_STORE_KEY ) ,
189- lockQuery : ( await queryLockSnapshot ( ) ) as Context [ string ] ,
190- ...getLifecycleContext ( ) ,
114+ // Thrown when the browsing context tears down mid-lock-request.
115+ // - "AbortError: Promise was rejected because the browsing context is going away" (Webkit)
116+ // - "Error: Failed to execute 'request' on 'LockManager': The provided callback is no longer runnable." (Chromium)
117+ function isContextGoingAwayError ( error : unknown ) : boolean {
118+ if ( ! ( error instanceof Error ) ) {
119+ return false
191120 }
121+ return error . name === 'AbortError' || error . message . includes ( 'no longer runnable' )
192122}
193123
194124export function createCookieAccess (
0 commit comments