UNPKG

storage-manager-js

Version:

A little way to control Cookies, LocalStorage and SessionStorage without tears

92 lines (84 loc) 2.83 kB
import type { CookieStorage, SetCookies, SetCookiesParser } from "../types"; import { isNil, isPrimitive } from "../utils"; import { Subscribe } from "../types"; const fnDate = (str: number | string | Date) => str instanceof Date ? str : typeof str === "number" ? new Date((new Date() as any) * 1 + (str as number) * 864e5) : str; const zeroEpoch = "1969-12-31T23:59:59.000Z"; const json = <T>(): T => { const cookie = document.cookie; if (cookie === "") { return {} as T; } return document.cookie .split("; ") .map((v) => v.split("=")) .reduce((acc: any, v: any) => { acc[decodeURIComponent(v[0].trim())] = decodeURIComponent(v[1].trim()); return acc; }, {}); }; const listeners = new Set<Subscribe>(); const callListeners = () => { const store = json(); listeners.forEach((fn) => fn(store)); }; const parsers: SetCookiesParser = [ { name: "expires", parse: (opts) => `expires=${fnDate(opts.expires ?? zeroEpoch)}` }, { name: "maxAge", parse: (opts) => (opts.maxAge ? `max-age=${fnDate(opts.expires ?? zeroEpoch)}` : "") }, { name: "path", parse: (opts) => `path=${opts.path ?? "/"}` }, { name: "sameSite", parse: (opts) => `samesite=${opts.sameSite ?? "strict"}` }, { name: "useSecure", parse: (opts) => `${opts.useSecure ?? true ? "secure" : ""}` }, { name: "domain", parse: (opts) => { const domain = opts.domain ?? ""; if (domain === "") return ""; return `domain=${opts.multiDomain ? "." : ""}${domain}`; }, }, { name: "partitioned", parse: (opts) => (opts.partitioned ? `Partitioned` : "") }, ]; export const Cookie: CookieStorage = { json, listener: (fn) => { listeners.add(fn); return () => listeners.delete(fn); }, clearListeners: () => listeners.clear(), has: (key) => document.cookie.split(";").some((item) => item.trim().startsWith(`${key}=`)), deleteAll: () => { document.cookie.split(";").forEach((cookie) => { document.cookie = cookie.replace(/^ +/, "").replace(/=.*/, `=;expires=${new Date().toUTCString()};path=/`); }); callListeners(); }, get: <E>(key: string): E | null => { const value = (Cookie.json<E>() as any)[key]; if (isNil(value)) { return null; } try { return JSON.parse(decodeURIComponent(value)) as E; } catch (error) { return value; } }, delete: (key: string) => { document.cookie = `${encodeURIComponent(key)}=;expires=${new Date().toUTCString()}`; callListeners(); }, set: (key: string, object: unknown, opts: SetCookies = {}) => { const value = isPrimitive(object) ? object : encodeURIComponent(JSON.stringify(object)); const cookies = parsers .reduce<string[]>( (acc, el) => { const val = el.parse(opts); return val === "" ? acc : acc.concat(val); }, [`${encodeURIComponent(key)}=${value}`], ) .join(";"); document.cookie = cookies; callListeners(); }, };