Initial commit

This commit is contained in:
Igor Martyniuk
2026-06-25 15:53:49 +03:00
commit 1bb0b7e68a
1517 changed files with 218469 additions and 0 deletions
@@ -0,0 +1 @@
export * from './main';
+125
View File
@@ -0,0 +1,125 @@
interface StorageEnvelope<T> {
value: T;
expiresAt?: number;
}
interface LocalStorageServiceConfig {
prefix?: string;
logger?: Console;
}
interface SetOptions {
ttlMs?: number;
}
export class LocalStorageService {
private _prefix?: string;
private _logger?: Console;
constructor(config?: LocalStorageServiceConfig) {
this._prefix = config?.prefix;
this._logger = config?.logger;
}
private _buildKey(key: string): string {
return this._prefix ? `${this._prefix}:${key}` : key;
}
private _stripPrefix(rawKey: string): string {
return this._prefix ? rawKey.slice(this._prefix.length + 1) : rawKey;
}
public get<T>(key: string): T | undefined {
try {
const raw = localStorage.getItem(this._buildKey(key));
if (raw == null) return undefined;
const envelope = JSON.parse(raw) as StorageEnvelope<T>;
if (envelope.expiresAt != null && Date.now() > envelope.expiresAt) {
this.remove(key);
return undefined;
}
return envelope.value;
} catch (error) {
this._logger?.error(`[LocalStorageService] get "${key}":`, error);
return undefined;
}
}
public set<T>(key: string, value: T, options?: SetOptions): void {
try {
const envelope: StorageEnvelope<T> = {
value,
expiresAt: options?.ttlMs != null ? Date.now() + options.ttlMs : undefined,
};
localStorage.setItem(this._buildKey(key), JSON.stringify(envelope));
} catch (error) {
this._logger?.error(`[LocalStorageService] set "${key}":`, error);
}
}
public getOrSet<T>(key: string, fallback: T, options?: SetOptions): T {
const existing = this.get<T>(key);
if (existing != null) return existing;
this.set(key, fallback, options);
return fallback;
}
public has(key: string): boolean {
return localStorage.getItem(this._buildKey(key)) != null;
}
public remove(key: string): void {
try {
localStorage.removeItem(this._buildKey(key));
} catch (error) {
this._logger?.error(`[LocalStorageService] remove "${key}":`, error);
}
}
public clear(): void {
try {
if (this._prefix) {
this.keys().forEach((key) => this.remove(key));
} else {
localStorage.clear();
}
} catch (error) {
this._logger?.error('[LocalStorageService] clear:', error);
}
}
public getAll<T extends object>(): Partial<T> {
return this.keys().reduce<T>((acc, key) => {
const value = this.get(key);
if (value != null) {
acc[key as keyof T] = value as T[keyof T];
}
return acc;
}, {} as T);
}
public keys(): string[] {
const result: string[] = [];
for (let i = 0; i < localStorage.length; i++) {
const rawKey = localStorage.key(i);
if (rawKey == null) continue;
if (this._prefix && !rawKey.startsWith(`${this._prefix}:`)) continue;
result.push(this._stripPrefix(rawKey));
}
return result;
}
}