add persisted.readLatest for cross-tab session reads
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -31,6 +31,18 @@ export function get<K extends keyof Schema>(key: K): Schema[K] {
|
||||
}
|
||||
get satisfies PersistedApi['get']
|
||||
|
||||
/**
|
||||
* Native is single-instance: there is no other tab that could have written
|
||||
* newer data behind our back, so the in-memory `_state` is already the truth
|
||||
* and a synchronous fresh read is impossible anyway (AsyncStorage is async).
|
||||
* This mirrors {@link get}; the web implementation is the one that actually
|
||||
* re-reads the store.
|
||||
*/
|
||||
export function readLatest<K extends keyof Schema>(key: K): Schema[K] {
|
||||
return _state[key]
|
||||
}
|
||||
readLatest satisfies PersistedApi['readLatest']
|
||||
|
||||
export async function write<K extends keyof Schema>(
|
||||
key: K,
|
||||
value: Schema[K],
|
||||
|
||||
@@ -39,6 +39,29 @@ export function get<K extends keyof Schema>(key: K): Schema[K] {
|
||||
}
|
||||
get satisfies PersistedApi['get']
|
||||
|
||||
/**
|
||||
* Force a fresh synchronous re-read of localStorage and return the requested
|
||||
* key from it, WITHOUT adopting it as `_state`.
|
||||
*
|
||||
* This exists for the cross-tab expiry-rescue path. A frozen tab may not have
|
||||
* processed a queued broadcast yet, so {@link get} (and persisted's in-memory
|
||||
* `_state`) can be stale even though another tab already wrote healthy tokens
|
||||
* to storage. Reading through storage directly here is the only way to see the
|
||||
* true cross-tab-latest tokens on web.
|
||||
*
|
||||
* Crucially we do NOT adopt into `_state`. {@link readFromStorage} memoizes by
|
||||
* raw string and returns the same object reference for unchanged data, so
|
||||
* adopting here would make the later queued broadcast/storage event for that
|
||||
* same write see `next === _state` and suppress its listener notification -
|
||||
* leaving non-current-account changes (removals, other tokens, metadata) stale
|
||||
* indefinitely. Leaving `_state` alone lets that queued event still fire.
|
||||
*/
|
||||
export function readLatest<K extends keyof Schema>(key: K): Schema[K] {
|
||||
const next = readFromStorage()
|
||||
return next?.[key] ?? _state[key]
|
||||
}
|
||||
readLatest satisfies PersistedApi['readLatest']
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/require-await
|
||||
export async function write<K extends keyof Schema>(
|
||||
key: K,
|
||||
|
||||
@@ -3,6 +3,15 @@ import {type Schema} from './schema'
|
||||
export type PersistedApi = {
|
||||
init(): Promise<void>
|
||||
get<K extends keyof Schema>(key: K): Schema[K]
|
||||
/**
|
||||
* Like {@link get}, but on web forces a fresh synchronous re-read of the
|
||||
* backing store before returning (without adopting it as the in-memory
|
||||
* state). This exists for the cross-tab expiry-rescue path: a frozen tab may
|
||||
* not have processed a queued broadcast yet, so {@link get} can be stale
|
||||
* while another tab has already written healthy tokens to storage. On native
|
||||
* it is identical to {@link get} (single-instance, no other writer).
|
||||
*/
|
||||
readLatest<K extends keyof Schema>(key: K): Schema[K]
|
||||
write<K extends keyof Schema>(key: K, value: Schema[K]): Promise<void>
|
||||
onUpdate<K extends keyof Schema>(
|
||||
key: K,
|
||||
|
||||
Reference in New Issue
Block a user