fix(smartupdate): improve update check caching, validation, and error handling

This commit is contained in:
2026-05-10 15:05:00 +00:00
parent d049d1a1e9
commit 3d1a73cf9e
12 changed files with 376 additions and 114 deletions
+47 -12
View File
@@ -1,18 +1,21 @@
import * as plugins from './smartupdate.plugins.js';
import type { ICacheStatus, ICacheOptions } from './smartupdate.interfaces.js';
import type { ICacheStatus, ICacheOptions, TCacheStrategy, TCachedUpdateStatus } from './smartupdate.interfaces.js';
type TCacheStoreData = Record<string, ICacheStatus>;
/**
* Manages caching of update check results
*/
export class UpdateCacheManager {
public readonly kvStore: plugins.npmextra.KeyValueStore;
public readonly kvStore: plugins.npmextra.KeyValueStore<TCacheStoreData>;
private cacheDurationMs: number;
constructor(options: ICacheOptions) {
this.cacheDurationMs = options.durationMs;
this.kvStore = new plugins.npmextra.KeyValueStore({
typeArg: 'userHomeDir',
this.kvStore = new plugins.npmextra.KeyValueStore<TCacheStoreData>({
typeArg: options.storeType || 'userHomeDir',
identityArg: options.storeIdentifier || 'global_smartupdate',
customPath: options.customPath,
});
}
@@ -27,7 +30,7 @@ export class UpdateCacheManager {
* Get cached status for a package
*/
public async getCached(packageName: string): Promise<ICacheStatus | null> {
return await this.kvStore.readKey(packageName);
return (await this.kvStore.readKey(packageName)) || null;
}
/**
@@ -42,11 +45,12 @@ export class UpdateCacheManager {
*/
public async clearCache(packageName?: string): Promise<void> {
if (packageName) {
await this.kvStore.deleteKey(packageName);
const cacheData = await this.kvStore.readAll();
delete cacheData[packageName];
await this.kvStore.wipe();
await this.kvStore.writeAll(cacheData);
} else {
// Clear all keys - this requires reading all keys first
// For now, we'll skip implementing full cache clear as it requires more kvStore API
throw new Error('Clearing all cache entries is not yet implemented');
await this.kvStore.wipe();
}
}
@@ -56,7 +60,11 @@ export class UpdateCacheManager {
*/
public async shouldCheckRegistry(
packageName: string,
strategy: 'always' | 'never' | 'time-based' = 'time-based'
strategy: TCacheStrategy = 'time-based',
cacheContext: {
currentVersion?: string;
registryUrl?: string;
} = {}
): Promise<{
shouldCheck: boolean;
cacheStatus?: ICacheStatus;
@@ -72,7 +80,7 @@ export class UpdateCacheManager {
const cacheStatus = await this.getCached(packageName);
// No cache exists
if (!cacheStatus) {
if (!cacheStatus || !this.cacheMatchesContext(cacheStatus, cacheContext)) {
return { shouldCheck: true };
}
@@ -106,11 +114,38 @@ export class UpdateCacheManager {
/**
* Create a new cache status object
*/
public createCacheStatus(latestVersion: string, performedUpgrade: boolean = false): ICacheStatus {
public createCacheStatus(
latestVersion: string,
performedUpgrade: boolean = false,
metadata: {
currentVersion?: string;
registryUrl?: string;
status?: TCachedUpdateStatus;
} = {}
): ICacheStatus {
return {
lastCheck: Date.now(),
latestVersion,
currentVersion: metadata.currentVersion,
registryUrl: metadata.registryUrl,
status: metadata.status,
performedUpgrade,
};
}
private cacheMatchesContext(
cacheStatus: ICacheStatus,
cacheContext: {
currentVersion?: string;
registryUrl?: string;
}
): boolean {
if (cacheContext.currentVersion && cacheStatus.currentVersion !== cacheContext.currentVersion) {
return false;
}
if (cacheContext.registryUrl && cacheStatus.registryUrl !== cacheContext.registryUrl) {
return false;
}
return true;
}
}