mirror of
https://github.com/tompro/sattle.git
synced 2026-08-27 07:15:59 +00:00
fix: normalize storage lock failures
This commit is contained in:
@@ -0,0 +1,30 @@
|
|||||||
|
import {describe, expect, it, vi} from 'vitest'
|
||||||
|
|
||||||
|
import {withStorageLock} from './storageLock'
|
||||||
|
|
||||||
|
describe('withStorageLock fallback', () => {
|
||||||
|
it('runs unlocked when Web Locks are unavailable without promising serialization', async () => {
|
||||||
|
vi.stubGlobal('navigator', {})
|
||||||
|
const entered: string[] = []
|
||||||
|
let releaseFirst: (() => void) | undefined
|
||||||
|
|
||||||
|
try {
|
||||||
|
const first = withStorageLock('registry', async () => {
|
||||||
|
entered.push('first')
|
||||||
|
await new Promise<void>((resolve) => {
|
||||||
|
releaseFirst = resolve
|
||||||
|
})
|
||||||
|
})
|
||||||
|
const second = withStorageLock('registry', () => {
|
||||||
|
entered.push('second')
|
||||||
|
})
|
||||||
|
|
||||||
|
await second
|
||||||
|
expect(entered).toEqual(['first', 'second'])
|
||||||
|
releaseFirst?.()
|
||||||
|
await first
|
||||||
|
} finally {
|
||||||
|
vi.unstubAllGlobals()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -3,12 +3,13 @@
|
|||||||
// lose each other's records (worst case: a stale tab overwrites a freshly
|
// lose each other's records (worst case: a stale tab overwrites a freshly
|
||||||
// persisted rotated note after its old k1 was burned). Falls back to
|
// persisted rotated note after its old k1 was burned). Falls back to
|
||||||
// running unlocked where Web Locks is unavailable (plain-Node tests, very
|
// running unlocked where Web Locks is unavailable (plain-Node tests, very
|
||||||
// old browsers).
|
// old browsers). That fallback provides no cross-tab serialization
|
||||||
export const withStorageLock = <T>(
|
// guarantee; the promise hop only normalizes synchronous callback errors.
|
||||||
name: string,
|
export const withStorageLock = <T>(name: string, fn: () => T | Promise<T>): Promise<T> => {
|
||||||
fn: () => T | Promise<T>
|
|
||||||
): Promise<T> => {
|
|
||||||
const locks = typeof navigator !== 'undefined' ? navigator.locks : undefined
|
const locks = typeof navigator !== 'undefined' ? navigator.locks : undefined
|
||||||
if (locks) return locks.request(name, fn)
|
if (locks) return locks.request(name, () => Promise.resolve().then(fn))
|
||||||
return Promise.resolve(fn())
|
return Promise.resolve().then(fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const storageLocksAvailable = (): boolean =>
|
||||||
|
typeof navigator !== 'undefined' && navigator.locks !== undefined
|
||||||
|
|||||||
Reference in New Issue
Block a user