UNPKG

@coveord/plasma-mantine

Version:

A Plasma flavoured Mantine theme

152 lines (138 loc) 4.67 kB
/** * Versioned localStorage utility for Plasma. * * All Plasma data is stored under a single `"plasma"` key with the shape: * ```json * { * "storage-version": 1, * "storage": { * "table": { * "my-table": { "columnVisibility": { ... } } * } * } * } * ``` */ export const STORAGE_KEY = 'plasma'; export const CURRENT_STORAGE_VERSION = 1; type JsonObject = Record<string, unknown>; const createStorageObject = (): JsonObject => Object.create(null) as JsonObject; const isUnsafeKey = (key: string): boolean => key === '__proto__' || key === 'constructor' || key === 'prototype'; const isSafePath = (path: string[]): boolean => path.every((key) => !isUnsafeKey(key)); interface PlasmaStorageSchema { 'storage-version': number; storage: JsonObject; } const readStorage = (): PlasmaStorageSchema | null => { try { const raw = localStorage.getItem(STORAGE_KEY); if (raw === null) { return null; } const parsed = JSON.parse(raw); if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { localStorage.removeItem(STORAGE_KEY); return null; } return parsed as PlasmaStorageSchema; } catch { try { localStorage.removeItem(STORAGE_KEY); } catch { console.warn(`Unable to clean up corrupted localStorage key "${STORAGE_KEY}".`); } return null; } }; const writeStorage = (data: PlasmaStorageSchema): void => { try { localStorage.setItem(STORAGE_KEY, JSON.stringify(data)); } catch { console.warn(`Unable to write to localStorage key "${STORAGE_KEY}".`); } }; const getNestedValue = (obj: JsonObject, path: string[]): unknown => { let current: unknown = obj; for (const key of path) { if (typeof current !== 'object' || current === null) { return undefined; } current = (current as JsonObject)[key]; } return current; }; const setNestedValue = (obj: JsonObject, path: string[], value: unknown): void => { let current = obj; for (let i = 0; i < path.length - 1; i++) { const key = path[i]; if (isUnsafeKey(key)) { return; } if (typeof current[key] !== 'object' || current[key] === null) { current[key] = createStorageObject(); } current = current[key] as JsonObject; } const lastKey = path[path.length - 1]; if (!isUnsafeKey(lastKey)) { current[lastKey] = value; } }; /** * Read a value from the versioned Plasma storage at the given path. * * @param path - Path segments within `storage`, e.g. `['table', 'my-table', 'columnVisibility']`. * @returns The stored value, or `null` if it doesn't exist or the storage is corrupted. */ export const getStorageItem = <T = unknown>(path: string[]): T | null => { if (!isSafePath(path)) { return null; } const data = readStorage(); if (!data || data['storage-version'] !== CURRENT_STORAGE_VERSION) { return null; } const value = getNestedValue(data.storage ?? createStorageObject(), path); return value !== undefined ? (value as T) : null; }; /** * Write a value to the versioned Plasma storage at the given path. * * @param path - Path segments within `storage`, e.g. `['table', 'my-table', 'columnVisibility']`. * @param value - The value to store (must be JSON-serializable). */ export const setStorageItem = <T = unknown>(path: string[], value: T): void => { if (!isSafePath(path)) { return; } let data = readStorage(); if (!data || data['storage-version'] !== CURRENT_STORAGE_VERSION) { data = {'storage-version': CURRENT_STORAGE_VERSION, storage: createStorageObject()}; } if (!data.storage) { data.storage = createStorageObject(); } setNestedValue(data.storage, path, value); writeStorage(data); }; /** * Remove a value from the versioned Plasma storage at the given path. * * @param path - Path segments within `storage`, e.g. `['table', 'my-table', 'columnVisibility']`. */ export const removeStorageItem = (path: string[]): void => { if (!isSafePath(path)) { return; } const data = readStorage(); if (!data || data['storage-version'] !== CURRENT_STORAGE_VERSION) { return; } const parentPath = path.slice(0, -1); const key = path[path.length - 1]; const parent = getNestedValue(data.storage ?? {}, parentPath); if (typeof parent === 'object' && parent !== null) { delete (parent as JsonObject)[key]; writeStorage(data); } };