UNPKG

@tdb/util

Version:
94 lines (84 loc) 2.38 kB
import * as Cookie from 'js-cookie'; import { isJson } from '../value/value'; import { ICookieOptions, CookieValue, CookieProperty, ICookieChangedEvent, } from './types'; import { subject$ } from './events.rx'; /** * Creates a wrapper for a cookie property at a specific key. */ export function prop<T extends CookieValue>( key: string, defaultOptions: ICookieOptions = {}, ): CookieProperty<T> { const func = <T extends CookieValue>( value?: T | null, options: ICookieOptions = {}, ) => { const args = { ...defaultOptions, ...options }; return value === undefined ? getValue<T>(key, args) : setValue<T>(key, value, args); }; const result = func as CookieProperty<T>; result.key = key; result.isProp = true; result.options = defaultOptions; return result; } /** * INTERNAL */ function getValue<T extends CookieValue>(key: string, options: ICookieOptions) { // Retrieve the value from the client-side object, // or the given server-side cookies. const { ctx } = options; const cookies = (ctx && ctx.req && ctx.req.cookies) || Cookie.getJSON() || {}; let value = cookies[key]; // TODO:BUG // If the key contains a `/` characther this will fail because the paths is encoded. // Account for URL encoding in the cookie keys. if (key.includes('/')) { throw new Error( `Cookie keys cannot contain "/" character. Given key: "${key}".`, ); } // Optionally parse as JSON. if (isJson(value)) { try { value = JSON.parse(value as string); } catch (error) { // Ignore parse error - just return the raw value. } } // Update with default value if no value was found. if (value === undefined && options.default !== undefined) { value = options.default; } // Finish up. return value as T; } function setValue<T extends CookieValue>( key: string, value: T | null, options: ICookieOptions, ) { const fireEvent = ( action: ICookieChangedEvent['action'], value?: CookieValue, ) => { subject$.next({ key, value, action }); return value; }; if (value === null) { Cookie.remove(key); return fireEvent('DELETE'); } else { const { expires, path, domain, isSecure: secure } = options; Cookie.set(key, value, { expires, path, domain, secure }); return fireEvent('UPDATE', getValue<T>(key, options)); } }