forked from facebook/docusaurus
/
storageUtils.ts
121 lines (109 loc) · 3.37 KB
/
storageUtils.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const StorageTypes = ['localStorage', 'sessionStorage', 'none'] as const;
export type StorageType = typeof StorageTypes[number];
const DefaultStorageType: StorageType = 'localStorage';
// Will return null browser storage is unavailable (like running Docusaurus in iframe)
// See https://github.com/facebook/docusaurus/pull/4501
function getBrowserStorage(
storageType: StorageType = DefaultStorageType,
): Storage | null {
if (typeof window === 'undefined') {
throw new Error(
'Browser storage is not available on Node.js/Docusaurus SSR process.',
);
}
if (storageType === 'none') {
return null;
} else {
try {
return window[storageType];
} catch (e) {
logOnceBrowserStorageNotAvailableWarning(e as Error);
return null;
}
}
}
/**
* Poor man's memoization to avoid logging multiple times the same warning
* Sometimes, localStorage/sessionStorage is unavailable due to browser policies
*/
let hasLoggedBrowserStorageNotAvailableWarning = false;
function logOnceBrowserStorageNotAvailableWarning(error: Error) {
if (!hasLoggedBrowserStorageNotAvailableWarning) {
console.warn(
`Docusaurus browser storage is not available.
Possible reasons: running Docusaurus in an iframe, in an incognito browser session, or using too strict browser privacy settings.`,
error,
);
hasLoggedBrowserStorageNotAvailableWarning = true;
}
}
// Convenient storage interface for a single storage key
export interface StorageSlot {
get: () => string | null;
set: (value: string) => void;
del: () => void;
}
const NoopStorageSlot: StorageSlot = {
get: () => null,
set: () => {},
del: () => {},
};
// Fail-fast, as storage APIs should not be used during the SSR process
function createServerStorageSlot(key: string): StorageSlot {
function throwError(): never {
throw new Error(`Illegal storage API usage for storage key "${key}".
Docusaurus storage APIs are not supposed to be called on the server-rendering process.
Please only call storage APIs in effects and event handlers.`);
}
return {
get: throwError,
set: throwError,
del: throwError,
};
}
/**
* Creates an object for accessing a particular key in localStorage.
*/
export const createStorageSlot = (
key: string,
options?: {persistence?: StorageType},
): StorageSlot => {
if (typeof window === 'undefined') {
return createServerStorageSlot(key);
}
const browserStorage = getBrowserStorage(options?.persistence);
if (browserStorage === null) {
return NoopStorageSlot;
}
return {
get: () => browserStorage.getItem(key),
set: (value) => browserStorage.setItem(key, value),
del: () => browserStorage.removeItem(key),
};
};
/**
* Returns a list of all the keys currently stored in browser storage
* or an empty list if browser storage can't be accessed.
*/
export function listStorageKeys(
storageType: StorageType = DefaultStorageType,
): string[] {
const browserStorage = getBrowserStorage(storageType);
if (!browserStorage) {
return [];
}
const keys: string[] = [];
for (let i = 0; i < browserStorage.length; i += 1) {
const key = browserStorage.key(i);
if (key !== null) {
keys.push(key);
}
}
return keys;
}