UNPKG

3.48 kBPlain TextView Raw
1import * as Cookies from 'es-cookie';
2
3interface ClientStorageOptions {
4 daysUntilExpire?: number;
5 cookieDomain?: string;
6}
7
8/**
9 * Defines a type that handles storage to/from a storage location
10 */
11export type ClientStorage = {
12 get<T extends Object>(key: string): T | undefined;
13 save(key: string, value: any, options?: ClientStorageOptions): void;
14 remove(key: string, options?: ClientStorageOptions): void;
15};
16
17/**
18 * A storage protocol for marshalling data to/from cookies
19 */
20export const CookieStorage = {
21 get<T extends Object>(key: string) {
22 const value = Cookies.get(key);
23
24 if (typeof value === 'undefined') {
25 return;
26 }
27
28 return <T>JSON.parse(value);
29 },
30
31 save(key: string, value: any, options?: ClientStorageOptions): void {
32 let cookieAttributes: Cookies.CookieAttributes = {};
33
34 if ('https:' === window.location.protocol) {
35 cookieAttributes = {
36 secure: true,
37 sameSite: 'none'
38 };
39 }
40
41 if (options?.daysUntilExpire) {
42 cookieAttributes.expires = options.daysUntilExpire;
43 }
44
45 if (options?.cookieDomain) {
46 cookieAttributes.domain = options.cookieDomain;
47 }
48
49 Cookies.set(key, JSON.stringify(value), cookieAttributes);
50 },
51
52 remove(key: string, options?: ClientStorageOptions) {
53 let cookieAttributes: Cookies.CookieAttributes = {};
54
55 if (options?.cookieDomain) {
56 cookieAttributes.domain = options.cookieDomain;
57 }
58
59 Cookies.remove(key, cookieAttributes);
60 }
61} as ClientStorage;
62
63/**
64 * @ignore
65 */
66const LEGACY_PREFIX = '_legacy_';
67
68/**
69 * Cookie storage that creates a cookie for modern and legacy browsers.
70 * See: https://web.dev/samesite-cookie-recipes/#handling-incompatible-clients
71 */
72export const CookieStorageWithLegacySameSite = {
73 get<T extends Object>(key: string) {
74 const value = CookieStorage.get<T>(key);
75
76 if (value) {
77 return value;
78 }
79
80 return CookieStorage.get<T>(`${LEGACY_PREFIX}${key}`);
81 },
82
83 save(key: string, value: any, options?: ClientStorageOptions): void {
84 let cookieAttributes: Cookies.CookieAttributes = {};
85
86 if ('https:' === window.location.protocol) {
87 cookieAttributes = { secure: true };
88 }
89
90 if (options?.daysUntilExpire) {
91 cookieAttributes.expires = options.daysUntilExpire;
92 }
93
94 if (options?.cookieDomain) {
95 cookieAttributes.domain = options.cookieDomain;
96 }
97
98 Cookies.set(
99 `${LEGACY_PREFIX}${key}`,
100 JSON.stringify(value),
101 cookieAttributes
102 );
103 CookieStorage.save(key, value, options);
104 },
105
106 remove(key: string, options?: ClientStorageOptions) {
107 let cookieAttributes: Cookies.CookieAttributes = {};
108
109 if (options?.cookieDomain) {
110 cookieAttributes.domain = options.cookieDomain;
111 }
112
113 Cookies.remove(key, cookieAttributes);
114 CookieStorage.remove(key, options);
115 CookieStorage.remove(`${LEGACY_PREFIX}${key}`, options);
116 }
117} as ClientStorage;
118
119/**
120 * A storage protocol for marshalling data to/from session storage
121 */
122export const SessionStorage = {
123 get<T extends Object>(key: string) {
124 /* c8 ignore next 3 */
125 if (typeof sessionStorage === 'undefined') {
126 return;
127 }
128
129 const value = sessionStorage.getItem(key);
130
131 if (value == null) {
132 return;
133 }
134
135 return <T>JSON.parse(value);
136 },
137
138 save(key: string, value: any): void {
139 sessionStorage.setItem(key, JSON.stringify(value));
140 },
141
142 remove(key: string) {
143 sessionStorage.removeItem(key);
144 }
145} as ClientStorage;