4f1d4821c5
* persist startup queries * Use IDB for query storage (#9687) * Add storage abstraction for persisted query data Introduce a platform-specific storage abstraction layer for react-query persistence: - Native: Uses MMKV for high-performance synchronous storage - Web: Uses IndexedDB via the `idb` library for efficient async storage This replaces the previous AsyncStorage implementation with more performant platform-native solutions. The abstraction maintains API compatibility with @tanstack/query-async-storage-persister. * Refactor storage abstraction to use factory pattern Change createPersistedQueryStorage to a factory function that accepts a storage ID, allowing multiple isolated storage instances: - Native: Each instance gets its own MMKV store - Web: Each instance gets its own IndexedDB database Adopt the factory pattern in: - react-query.tsx: Uses 'persisted_queries' storage - ageAssurance/data.tsx: Uses 'age_assurance' storage This provides better separation between different query client caches and allows each to be managed independently. --------- Co-authored-by: Claude <noreply@anthropic.com> * Refactor to use archival storage (cherry picked from commit a773b40e41c96f821cd32260919ce1437c0fc3ab) * Improve archive db types (cherry picked from commit 80e4959ba2aa00c984c26aed2f7dfae1095720b0) * rm idb * clear on logout, bust on app version * create abstraction for persisting queries, make gcTime infinite * Rm abstraction --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Eric Bailey <git@esb.lol>
#/storage
Usage
Import the correctly scoped store from #/storage. Each instance of Storage
(the base class, not to be used directly), has the following interface:
set([...scope, key], value)get([...scope, key])remove([...scope, key])removeMany([...scope], [...keys])
For example, using our device store looks like this, since it's scoped to the
device (the most base level scope):
import { device } from '#/storage';
device.set(['foobar'], true);
device.get(['foobar']);
device.remove(['foobar']);
device.removeMany([], ['foobar']);
TypeScript
Stores are strongly typed, and when setting a given value, it will need to
conform to the schemas defined in #/storage/schema. When getting a value, it
will be returned to you as the type defined in its schema.
Scoped Stores
Some stores are (or might be) scoped to an account or other identifier. In this case, storage instances are created with type-guards, like this:
type AccountSchema = {
language: `${string}-${string}`;
};
type DID = `did:${string}`;
const account = new Storage<
[DID],
AccountSchema
>({
id: 'account',
});
account.set(
['did:plc:abc', 'language'],
'en-US',
);
const language = account.get([
'did:plc:abc',
'language',
]);
Here, if ['did:plc:abc'] is not supplied along with the key of
language, the get will return undefined (and TS will yell at you).