feat: drive IndexedDB cache layer from a single registry

Introduces cacheableModels.js as the source of truth for which models the
client caches in IDB and how to dispatch their revalidate actions. DataManager
derives modelsToSync from the registry and creates object stores
idempotently, so adding new cached models needs only one place to change
plus a one-time DATA_VERSION bump.

Also fixes two latent bugs that the upcoming boot-hydration relies on:
setCacheKeys now awaits all per-key writes (was async-forEach with no await),
and replace awaits clear before push (avoids ConstraintError on rapid
refetches).
This commit is contained in:
Shivam Mishra
2026-05-21 17:21:33 +05:30
parent 991bc5a265
commit 0ae3a82339
3 changed files with 67 additions and 13 deletions
@@ -1,9 +1,10 @@
import { openDB } from 'idb';
import { DATA_VERSION } from './version';
import { cacheableModels, cacheableModelNames } from './cacheableModels';
export class DataManager {
constructor(accountId) {
this.modelsToSync = ['inbox', 'label', 'team'];
this.modelsToSync = cacheableModelNames;
this.accountId = accountId;
this.db = null;
}
@@ -11,12 +12,16 @@ export class DataManager {
async initDb() {
if (this.db) return this.db;
const dbName = `cw-store-${this.accountId}`;
this.db = await openDB(`cw-store-${this.accountId}`, DATA_VERSION, {
this.db = await openDB(dbName, DATA_VERSION, {
upgrade(db) {
db.createObjectStore('cache-keys');
db.createObjectStore('inbox', { keyPath: 'id' });
db.createObjectStore('label', { keyPath: 'id' });
db.createObjectStore('team', { keyPath: 'id' });
if (!db.objectStoreNames.contains('cache-keys')) {
db.createObjectStore('cache-keys');
}
cacheableModels.forEach(model => {
if (!db.objectStoreNames.contains(model.name)) {
db.createObjectStore(model.name, { keyPath: 'id' });
}
});
},
});
@@ -41,7 +46,7 @@ export class DataManager {
async replace({ modelName, data }) {
this.validateModel(modelName);
this.db.clear(modelName);
await this.db.clear(modelName);
return this.push({ modelName, data });
}
@@ -65,9 +70,11 @@ export class DataManager {
}
async setCacheKeys(cacheKeys) {
Object.keys(cacheKeys).forEach(async modelName => {
this.db.put('cache-keys', cacheKeys[modelName], modelName);
});
await Promise.all(
Object.entries(cacheKeys).map(([modelName, value]) =>
this.db.put('cache-keys', value, modelName)
)
);
}
async getCacheKey(modelName) {