react-wire-persisted 2.0.1 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +121 -28
- package/client.js +1 -1
- package/client.mjs +6 -5
- package/dist/index.d.ts +197 -0
- package/dist/index.js +241 -305
- package/dist/react-wire-persisted.js +241 -305
- package/dist/react-wire-persisted.js.map +1 -0
- package/dist/react-wire-persisted.umd.cjs +2 -1
- package/dist/react-wire-persisted.umd.cjs.map +1 -0
- package/nextjs.js +4 -27
- package/package.json +91 -75
- package/src/components/{HydrationProvider.jsx → HydrationProvider.tsx} +13 -3
- package/src/components/index.tsx +1 -0
- package/src/global.d.ts +16 -0
- package/src/hooks/{useHydration.js → useHydration.ts} +19 -26
- package/src/index.ts +9 -0
- package/src/providers/LocalStorageProvider.ts +145 -0
- package/src/providers/MemoryStorageProvider.ts +14 -0
- package/src/providers/{StorageProvider.js → RWPStorageProvider.ts} +42 -39
- package/src/react-wire-persisted.ts +257 -0
- package/src/types.ts +19 -0
- package/src/utils/fakeLocalStorage.ts +17 -0
- package/src/utils/{index.js → index.ts} +5 -7
- package/src/utils/{isomorphic.js → isomorphic.ts} +24 -11
- package/src/utils/keys.ts +49 -0
- package/src/components/HydrationProvider.js +0 -45
- package/src/components/index.js +0 -1
- package/src/index.js +0 -6
- package/src/providers/LocalStorageProvider.js +0 -194
- package/src/providers/MemoryStorageProvider.js +0 -20
- package/src/react-wire-persisted.js +0 -136
- package/src/utils/fakeLocalStorage.js +0 -16
- package/src/utils/keys.js +0 -49
|
@@ -1,194 +0,0 @@
|
|
|
1
|
-
import StorageProvider from './StorageProvider'
|
|
2
|
-
import { fakeLocalStorage, isPrimitive, isLocalStorageAvailable } from '../utils'
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* A storage provider for `localStorage`
|
|
6
|
-
* @see `StorageProvider.js` for documentation
|
|
7
|
-
*/
|
|
8
|
-
class LocalStorageProvider extends StorageProvider {
|
|
9
|
-
|
|
10
|
-
constructor(namespace = null, registry = {}) {
|
|
11
|
-
|
|
12
|
-
super(namespace, registry)
|
|
13
|
-
|
|
14
|
-
this.storage = this.getStorage()
|
|
15
|
-
this._isUsingFakeStorage = !isLocalStorageAvailable()
|
|
16
|
-
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
getStorage() {
|
|
20
|
-
|
|
21
|
-
// Use the isomorphic utility to check localStorage availability
|
|
22
|
-
if (isLocalStorageAvailable()) {
|
|
23
|
-
return window.localStorage
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// Fallback to fake localStorage for SSR or when localStorage is disabled
|
|
27
|
-
return fakeLocalStorage
|
|
28
|
-
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
setNamespace(namespace) {
|
|
32
|
-
|
|
33
|
-
if (!this.namespace) {
|
|
34
|
-
this.namespace = namespace
|
|
35
|
-
return
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
if (this.namespace === namespace)
|
|
39
|
-
return
|
|
40
|
-
|
|
41
|
-
const items = JSON.parse(JSON.stringify(this.getAll()))
|
|
42
|
-
|
|
43
|
-
this.removeAll()
|
|
44
|
-
|
|
45
|
-
for (const [key, value] of Object.entries(items)) {
|
|
46
|
-
const newKey = key.replace(this.namespace, namespace)
|
|
47
|
-
this.setItem(newKey, value)
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
this.namespace = namespace
|
|
51
|
-
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
getItem(key) {
|
|
55
|
-
|
|
56
|
-
const val = this.storage.getItem(key)
|
|
57
|
-
|
|
58
|
-
if (val === undefined || val === null)
|
|
59
|
-
return null
|
|
60
|
-
|
|
61
|
-
try {
|
|
62
|
-
return JSON.parse(val)
|
|
63
|
-
} catch (e) {
|
|
64
|
-
return val
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
setItem(key, value) {
|
|
70
|
-
|
|
71
|
-
let val = value
|
|
72
|
-
|
|
73
|
-
// Don't allow "null" & similar values to be stringified
|
|
74
|
-
if (val !== undefined && val !== null)
|
|
75
|
-
val = isPrimitive(value) ? value : JSON.stringify(value)
|
|
76
|
-
|
|
77
|
-
return this.storage.setItem(key, val)
|
|
78
|
-
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
removeItem(key, fromRegistry = false) {
|
|
82
|
-
|
|
83
|
-
if (fromRegistry)
|
|
84
|
-
delete this.registry[key]
|
|
85
|
-
|
|
86
|
-
return this.storage.removeItem(key)
|
|
87
|
-
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
getAll() {
|
|
91
|
-
|
|
92
|
-
const prefixNs = `${this.namespace}.`
|
|
93
|
-
|
|
94
|
-
return Object.keys(this.storage).reduce((acc, it) => {
|
|
95
|
-
|
|
96
|
-
if (this.namespace ? it.startsWith(prefixNs) : true)
|
|
97
|
-
acc[it] = this.storage.getItem(it)
|
|
98
|
-
|
|
99
|
-
return acc
|
|
100
|
-
|
|
101
|
-
}, {})
|
|
102
|
-
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
_resetAll(
|
|
106
|
-
useInitialValues = true,
|
|
107
|
-
excludedKeys = [],
|
|
108
|
-
clearRegistry = false
|
|
109
|
-
) {
|
|
110
|
-
|
|
111
|
-
const prefixNs = `${this.namespace}.`
|
|
112
|
-
|
|
113
|
-
Object.keys(this.storage).forEach(it => {
|
|
114
|
-
|
|
115
|
-
const isAppKey = this.namespace ? it.startsWith(prefixNs) : true
|
|
116
|
-
const isExcluded = excludedKeys?.includes(it) || false
|
|
117
|
-
|
|
118
|
-
if (!isAppKey || isExcluded) return
|
|
119
|
-
|
|
120
|
-
if (useInitialValues) {
|
|
121
|
-
|
|
122
|
-
const isRegistered = Object.prototype.hasOwnProperty.call(this.registry, it)
|
|
123
|
-
|
|
124
|
-
if (isRegistered)
|
|
125
|
-
this.storage.setItem(it, this.registry[it])
|
|
126
|
-
else
|
|
127
|
-
this.storage.removeItem(it)
|
|
128
|
-
|
|
129
|
-
} else {
|
|
130
|
-
|
|
131
|
-
this.storage.removeItem(it)
|
|
132
|
-
|
|
133
|
-
if (clearRegistry)
|
|
134
|
-
delete this.registry[it]
|
|
135
|
-
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
})
|
|
139
|
-
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
resetAll(excludedKeys = [], clearRegistry = false) {
|
|
143
|
-
this._resetAll(true, excludedKeys || [], clearRegistry)
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
removeAll(excludedKeys = [], clearRegistry = false) {
|
|
147
|
-
this._resetAll(false, excludedKeys || [], clearRegistry)
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* Attempt to upgrade from fake storage to real localStorage
|
|
152
|
-
* This is useful for hydration scenarios
|
|
153
|
-
*/
|
|
154
|
-
upgradeToRealStorage() {
|
|
155
|
-
|
|
156
|
-
if (!this._isUsingFakeStorage) {
|
|
157
|
-
return false // Already using real storage
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
if (!isLocalStorageAvailable()) {
|
|
161
|
-
return false // Real storage still not available
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
const fakeData = { ...this.storage }
|
|
165
|
-
this.storage = window.localStorage
|
|
166
|
-
this._isUsingFakeStorage = false
|
|
167
|
-
|
|
168
|
-
// Migrate data from fake storage to real storage
|
|
169
|
-
Object.keys(fakeData).forEach(key => {
|
|
170
|
-
if (key !== '__IS_FAKE_LOCAL_STORAGE__' && fakeData[key] != null) {
|
|
171
|
-
try {
|
|
172
|
-
this.storage.setItem(key, fakeData[key])
|
|
173
|
-
} catch (e) {
|
|
174
|
-
// If we can't write to localStorage, revert to fake storage
|
|
175
|
-
this.storage = fakeLocalStorage
|
|
176
|
-
this._isUsingFakeStorage = true
|
|
177
|
-
return false
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
})
|
|
181
|
-
|
|
182
|
-
return true
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* Check if currently using fake storage
|
|
187
|
-
*/
|
|
188
|
-
isUsingFakeStorage() {
|
|
189
|
-
return this._isUsingFakeStorage
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
export default LocalStorageProvider
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import LocalStorageProvider from './LocalStorageProvider'
|
|
2
|
-
import { fakeLocalStorage } from '../utils'
|
|
3
|
-
|
|
4
|
-
class MemoryStorageProvider extends LocalStorageProvider {
|
|
5
|
-
|
|
6
|
-
constructor(namespace = null, registry = {}) {
|
|
7
|
-
|
|
8
|
-
super(namespace, registry)
|
|
9
|
-
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
getStorage() {
|
|
13
|
-
|
|
14
|
-
return fakeLocalStorage
|
|
15
|
-
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export default MemoryStorageProvider
|
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
import { createWire } from '@forminator/react-wire'
|
|
2
|
-
import LocalStorageProvider from './providers/LocalStorageProvider'
|
|
3
|
-
import { getIsClient, getHasHydrated } from './utils'
|
|
4
|
-
|
|
5
|
-
export const defaultOptions = {
|
|
6
|
-
logging: {
|
|
7
|
-
enabled: false,
|
|
8
|
-
},
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
let Provider = LocalStorageProvider
|
|
12
|
-
let storage = new Provider()
|
|
13
|
-
let options = { ...defaultOptions }
|
|
14
|
-
let pendingLogs = []
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Gets the namespace of the storage provider
|
|
18
|
-
*
|
|
19
|
-
* @returns {String}
|
|
20
|
-
*/
|
|
21
|
-
export const getNamespace = () => storage.namespace
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Gets the current storage provider class instance
|
|
25
|
-
*
|
|
26
|
-
* @returns {StorageProvider}
|
|
27
|
-
*/
|
|
28
|
-
export const getStorage = () => storage
|
|
29
|
-
|
|
30
|
-
export const getOptions = () => options
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Sets the namespace for the storage provider
|
|
34
|
-
*
|
|
35
|
-
* @param {String} namespace The namespace for the storage provider
|
|
36
|
-
*/
|
|
37
|
-
export const setNamespace = namespace => {
|
|
38
|
-
storage.setNamespace(namespace)
|
|
39
|
-
storage = new Provider(namespace || getNamespace())
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export const setOptions = value => {
|
|
43
|
-
options = {
|
|
44
|
-
...options,
|
|
45
|
-
...value,
|
|
46
|
-
}
|
|
47
|
-
/* istanbul ignore next */
|
|
48
|
-
if (options.logging.enabled) {
|
|
49
|
-
console.info('Flushing', pendingLogs.length, 'pending logs')
|
|
50
|
-
while (pendingLogs.length)
|
|
51
|
-
/* istanbul ignore next */
|
|
52
|
-
console.log(...pendingLogs.shift())
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Attempts to upgrade the storage provider from fake storage to real localStorage
|
|
58
|
-
* This should be called on the client side after hydration
|
|
59
|
-
*
|
|
60
|
-
* @returns {Boolean} True if upgrade was successful
|
|
61
|
-
*/
|
|
62
|
-
export const upgradeStorage = () => {
|
|
63
|
-
if (!getIsClient()) {
|
|
64
|
-
return false
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
const upgraded = storage.upgradeToRealStorage()
|
|
68
|
-
|
|
69
|
-
if (upgraded) {
|
|
70
|
-
log('react-wire-persisted: Upgraded to real localStorage after hydration')
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
return upgraded
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
const log = (...args) => {
|
|
77
|
-
/* istanbul ignore next */
|
|
78
|
-
if (options.logging.enabled)
|
|
79
|
-
/* istanbul ignore next */
|
|
80
|
-
console.log(...args)
|
|
81
|
-
else
|
|
82
|
-
pendingLogs.push(args)
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Creates a persisted Wire using the `StorageProvider` that is currently set
|
|
87
|
-
* Defaults to `localStorage` via `LocalStorageProvider`
|
|
88
|
-
*
|
|
89
|
-
* @param {String} key Unique key for storing this value
|
|
90
|
-
* @param {*} value Initial value of this Wire
|
|
91
|
-
* @returns A new Wire decorated with localStorage functionality
|
|
92
|
-
*/
|
|
93
|
-
export const createPersistedWire = (key, value = null) => {
|
|
94
|
-
|
|
95
|
-
// This check helps ensure no accidental key typos occur
|
|
96
|
-
if (!key && (typeof key) !== 'number') throw new Error(
|
|
97
|
-
`createPersistedWire: Key cannot be a falsey value (${key}}`
|
|
98
|
-
)
|
|
99
|
-
|
|
100
|
-
// Track this writable entry so we can easily clear all
|
|
101
|
-
storage.register(key, value)
|
|
102
|
-
|
|
103
|
-
// The actual Wire backing object
|
|
104
|
-
const wire = createWire(value)
|
|
105
|
-
|
|
106
|
-
const getValue = () => wire.getValue()
|
|
107
|
-
|
|
108
|
-
const setValue = newValue => {
|
|
109
|
-
storage.setItem(key, newValue)
|
|
110
|
-
return wire.setValue(newValue)
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
const subscribe = fn => {
|
|
114
|
-
wire.subscribe(fn)
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
const storedValue = storage.getItem(key)
|
|
118
|
-
const initialValue = storedValue === null ? value : storedValue
|
|
119
|
-
|
|
120
|
-
log('react-wire-persisted: create', key, {
|
|
121
|
-
value,
|
|
122
|
-
storedValue,
|
|
123
|
-
initialValue,
|
|
124
|
-
})
|
|
125
|
-
|
|
126
|
-
if (initialValue !== value)
|
|
127
|
-
setValue(initialValue)
|
|
128
|
-
|
|
129
|
-
return {
|
|
130
|
-
...wire,
|
|
131
|
-
getValue,
|
|
132
|
-
setValue,
|
|
133
|
-
subscribe,
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
const storage = {
|
|
3
|
-
__IS_FAKE_LOCAL_STORAGE__: true,
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
export const fakeLocalStorage = {
|
|
7
|
-
getItem: key => storage[key],
|
|
8
|
-
setItem: (key, value) => {
|
|
9
|
-
storage[key] = value
|
|
10
|
-
},
|
|
11
|
-
removeItem: key => {
|
|
12
|
-
delete storage[key]
|
|
13
|
-
},
|
|
14
|
-
// Make Object.keys() work properly for _resetAll method
|
|
15
|
-
...storage
|
|
16
|
-
}
|
package/src/utils/keys.js
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
/**
|
|
3
|
-
* Convenience map of keys
|
|
4
|
-
*/
|
|
5
|
-
const storageKeys = {}
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Adds a key to the keys map
|
|
9
|
-
*
|
|
10
|
-
* @param {String} value Key name
|
|
11
|
-
*/
|
|
12
|
-
export const addKey = value => {
|
|
13
|
-
storageKeys[value] = value
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Adds a key to the keys map
|
|
18
|
-
* (Alias for `addKey`)
|
|
19
|
-
*
|
|
20
|
-
* @param {String} value Key name
|
|
21
|
-
*/
|
|
22
|
-
export const key = value => addKey(value)
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Convenience method to get internally managed storage keys
|
|
26
|
-
*
|
|
27
|
-
* @returns {Object} Storage keys map
|
|
28
|
-
*/
|
|
29
|
-
export const getKeys = () => storageKeys
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Helper utility to prefix all keys in a map to use a namespace
|
|
33
|
-
*
|
|
34
|
-
* @param {String} namespace Storage namespace prefix
|
|
35
|
-
* @param {Object} keys (Optional) Storage key/values. Defaults to the internally managed keys map
|
|
36
|
-
*/
|
|
37
|
-
export const getPrefixedKeys = (namespace, keys = null) => {
|
|
38
|
-
|
|
39
|
-
const items = keys || storageKeys
|
|
40
|
-
|
|
41
|
-
if (!namespace)
|
|
42
|
-
return items
|
|
43
|
-
|
|
44
|
-
return Object.keys(items).reduce((acc, it) => ({
|
|
45
|
-
...acc,
|
|
46
|
-
[it]: `${namespace}.${items[it]}`,
|
|
47
|
-
}), {})
|
|
48
|
-
|
|
49
|
-
}
|