refactor: simplify form draft key generation

This commit is contained in:
Firman Ramdhani
2026-07-27 21:58:18 +07:00
parent a01b0c1339
commit b55606817c
4 changed files with 139 additions and 53 deletions
@@ -4,6 +4,8 @@ import type { IStorageService } from '../types/storage.interface';
export interface StorageOptions<TKey extends string> {
encryptedKeys?: Set<TKey>;
plainTextKeys?: Set<TKey>;
personalizedKeys?: Set<TKey>;
getUserId?: () => string | null | undefined;
}
/**
@@ -13,11 +15,15 @@ export class LocalStorageService<TKey extends string> implements IStorageService
private readonly encryption: EncryptionUtils;
private readonly encryptedKeys: Set<TKey>;
private readonly plainTextKeys: Set<TKey>;
private readonly personalizedKeys?: Set<TKey>;
private readonly getUserId?: () => string | null | undefined;
constructor(options?: StorageOptions<TKey>, encryptionUtils?: EncryptionUtils) {
this.encryption = encryptionUtils ?? EncryptionUtils.getInstance();
this.encryptedKeys = options?.encryptedKeys ?? new Set();
this.plainTextKeys = options?.plainTextKeys ?? new Set();
this.personalizedKeys = options?.personalizedKeys;
this.getUserId = options?.getUserId;
}
private validateKey(key: TKey): void {
@@ -26,25 +32,35 @@ export class LocalStorageService<TKey extends string> implements IStorageService
}
}
private resolveKey(key: TKey): string {
if (this.personalizedKeys?.has(key)) {
const userId = this.getUserId?.() || 'guest';
return `${String(key)}_${userId}`;
}
return String(key);
}
private shouldEncrypt(key: TKey): boolean {
return this.encryptedKeys.has(key);
}
async setItem<T>(key: TKey, value: T): Promise<void> {
this.validateKey(key);
const resolvedKey = this.resolveKey(key);
const serialized = JSON.stringify(value);
if (this.shouldEncrypt(key)) {
const encrypted = this.encryption.encrypt(serialized);
localStorage.setItem(key as string, encrypted);
localStorage.setItem(resolvedKey, encrypted);
} else {
localStorage.setItem(key as string, serialized);
localStorage.setItem(resolvedKey, serialized);
}
}
async getItem<T>(key: TKey): Promise<T | null> {
this.validateKey(key);
const raw = localStorage.getItem(key as string);
const resolvedKey = this.resolveKey(key);
const raw = localStorage.getItem(resolvedKey);
if (raw === null) return null;
try {
@@ -55,15 +71,16 @@ export class LocalStorageService<TKey extends string> implements IStorageService
}
return JSON.parse(raw) as T;
} catch {
console.warn(`[core-storage] Failed to parse key "${key}". Removing corrupt entry.`);
localStorage.removeItem(key as string);
console.warn(`[core-storage] Failed to parse key "${String(key)}". Removing corrupt entry.`);
localStorage.removeItem(resolvedKey);
return null;
}
}
async removeItem(key: TKey): Promise<void> {
this.validateKey(key);
localStorage.removeItem(key as string);
const resolvedKey = this.resolveKey(key);
localStorage.removeItem(resolvedKey);
}
async clear(): Promise<void> {
@@ -71,7 +88,8 @@ export class LocalStorageService<TKey extends string> implements IStorageService
}
async hasItem(key: TKey): Promise<boolean> {
return localStorage.getItem(key as string) !== null;
const resolvedKey = this.resolveKey(key);
return localStorage.getItem(resolvedKey) !== null;
}
async keys(): Promise<TKey[]> {