Skip to content

Commit 363b8d9

Browse files
committed
feat: auto refresh indexedDB cache every day
1 parent dd8a5c0 commit 363b8d9

File tree

1 file changed

+50
-5
lines changed

1 file changed

+50
-5
lines changed

src/lib/indexeddb.ts

Lines changed: 50 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ export class IndexedDB {
88
private dbName = 'McpRegistryDB';
99
private settingsStore = 'user-settings';
1010
private serversStore = 'mcp-servers';
11+
private lastFetchKey = 'servers-last-fetch';
12+
private cacheMaxAge = 24 * 60 * 60 * 1000; // 24 hours
1113

1214
async init() {
1315
if (typeof window === 'undefined') return null;
@@ -104,11 +106,26 @@ export class IndexedDB {
104106
await this.set('mcp-servers-stack', stack);
105107
}
106108

109+
/** Get timestamp of last server fetch */
110+
async getLastFetchTime(): Promise<number> {
111+
return (await this.get<number>(this.lastFetchKey)) || 0;
112+
}
113+
114+
/** Set timestamp of last server fetch */
115+
async setLastFetchTime(timestamp: number): Promise<void> {
116+
await this.set(this.lastFetchKey, timestamp);
117+
}
118+
119+
/** Check if cached server data is stale */
120+
async isDataStale(): Promise<boolean> {
121+
return Date.now() - (await this.getLastFetchTime()) > this.cacheMaxAge;
122+
}
123+
107124
// NOTE: can use IndexedDB as a basic search store for MCP servers
108125

109126
/**
110127
* Initialize servers in IndexedDB.
111-
* By default this will not re-fetch if the DB already contains servers.
128+
* By default this will not re-fetch if the DB already contains fresh servers.
112129
* Set `forceRefresh` to true to always re-fetch and replace stored servers.
113130
*/
114131
async initServers(registryUrl: string, forceRefresh = false) {
@@ -117,11 +134,15 @@ export class IndexedDB {
117134
try {
118135
const db = await this.init();
119136
if (!db) return null;
120-
// If we already have servers stored and no forced refresh requested, skip fetching
121-
if (!forceRefresh) {
122-
const has = await this.hasServers();
123-
if (has) return this.db;
137+
138+
const hasServers = await this.hasServers();
139+
const isStale = await this.isDataStale();
140+
141+
// Skip fetching if: not forced, has servers, and data is fresh
142+
if (!forceRefresh && hasServers && !isStale) {
143+
return this.db;
124144
}
145+
125146
// Attempt to fetch servers. On failure, preserve existing DB contents instead of clearing them.
126147
const docs = await fetchAllServers(registryUrl).catch((err) => {
127148
console.warn('Failed to fetch servers for initServers:', err);
@@ -131,13 +152,37 @@ export class IndexedDB {
131152
if (!docs) return this.db;
132153
// Save using the existing saveServers method which handles clearing and writing
133154
await this.saveServers(docs || []);
155+
await this.setLastFetchTime(Date.now());
134156
return this.db;
135157
} catch (err) {
136158
console.warn('initServers failed:', err);
137159
return null;
138160
}
139161
}
140162

163+
/**
164+
* Refresh servers in the background without blocking.
165+
* Dispatches 'servers-updated' event when complete.
166+
*/
167+
async refreshInBackground(registryUrl: string): Promise<void> {
168+
setTimeout(async () => {
169+
try {
170+
console.log('Starting background server refresh...');
171+
const docs = await fetchAllServers(registryUrl);
172+
await this.saveServers(docs);
173+
await this.setLastFetchTime(Date.now());
174+
console.log('IndexedDB refresh completed');
175+
176+
// Dispatch custom event to notify UI
177+
if (typeof window !== 'undefined') {
178+
window.dispatchEvent(new CustomEvent('servers-updated', { detail: { count: docs.length } }));
179+
}
180+
} catch (err) {
181+
console.warn('IndexedDB refresh failed:', err);
182+
}
183+
}, 0);
184+
}
185+
141186
async search(term: string): Promise<McpServerItem[]> {
142187
if (!this.db) return [];
143188
try {

0 commit comments

Comments
 (0)