1 import { AVERAGE_BYTES_PER_LOG_LINE, MAX_LOG_STORAGE_LINES, MAX_LOG_STORAGE_RATIO } from '@proton/pass/constants';
2 import type { AnyStorage } from '@proton/pass/types';
3 import { getLocalStorageQuota } from '@proton/pass/utils/dom/storage';
4 import debounce from '@proton/utils/debounce';
6 export type LogStorageData = { logs: string };
8 export const createLogStore = <T extends LogStorageData>(storage: AnyStorage<T>) => {
9 const buffer: string[] = [];
11 /** Reads the logs from storage. If parsing the
12 * logs fails, clears the log storage key */
13 const read = async (): Promise<string[]> => {
15 const logs = await storage.getItem('logs');
16 return typeof logs === 'string' ? [...buffer, ...JSON.parse(logs)] : buffer;
18 void storage.removeItem('logs');
23 /** Debounces the write operation to occur once every 5 seconds
24 * to prevent excessive concurrent writes to the storage */
25 const write = debounce(async () => {
26 const maxLogSize = MAX_LOG_STORAGE_RATIO * (await getLocalStorageQuota());
27 const maxLogLinesLength = maxLogSize / AVERAGE_BYTES_PER_LOG_LINE;
28 const max = Math.min(maxLogLinesLength, MAX_LOG_STORAGE_LINES);
30 const logs = (await read()).slice(0, max);
31 void storage.setItem('logs', JSON.stringify(logs));
35 const push = (...logs: string[]) => {
36 buffer.unshift(`${new Date().toLocaleString()} ${logs.join(' ')}`);
41 return { push, read, flush: write.flush };
44 export type LogStore = ReturnType<typeof createLogStore>;