@plq/use-persisted-state 1.3.0 → 1.4.1
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/LICENSE +1 -1
- package/README.md +179 -50
- package/esm/index.d.mts +13 -0
- package/esm/index.mjs +10 -0
- package/esm/storages/browser-storage.d.mts +1 -0
- package/esm/storages/browser-storage.mjs +5 -0
- package/esm/storages/chrome-storage.d.mts +1 -0
- package/esm/storages/chrome-storage.mjs +5 -0
- package/esm/storages/local-storage.d.mts +1 -0
- package/esm/storages/local-storage.mjs +3 -0
- package/esm/storages/session-storage.d.mts +1 -0
- package/esm/storages/session-storage.mjs +3 -0
- package/lib/@types/storage.d.ts.map +1 -1
- package/lib/create-async-persisted-state.d.ts +2 -2
- package/lib/create-async-persisted-state.d.ts.map +1 -1
- package/lib/create-async-persisted-state.js +136 -17
- package/lib/create-async-persisted-state.js.map +1 -1
- package/lib/create-persisted-state.d.ts +2 -2
- package/lib/create-persisted-state.d.ts.map +1 -1
- package/lib/create-persisted-state.js +76 -15
- package/lib/create-persisted-state.js.map +1 -1
- package/lib/index.d.ts +6 -5
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +4 -2
- package/lib/index.js.map +1 -1
- package/lib/storages/browser-storage.d.ts +2 -2
- package/lib/storages/browser-storage.d.ts.map +1 -1
- package/lib/storages/browser-storage.js +6 -26
- package/lib/storages/browser-storage.js.map +1 -1
- package/lib/storages/chrome-storage.d.ts +2 -2
- package/lib/storages/chrome-storage.d.ts.map +1 -1
- package/lib/storages/chrome-storage.js +10 -27
- package/lib/storages/chrome-storage.js.map +1 -1
- package/lib/storages/local-storage.d.ts +1 -1
- package/lib/storages/local-storage.d.ts.map +1 -1
- package/lib/storages/local-storage.js +3 -1
- package/lib/storages/local-storage.js.map +1 -1
- package/lib/storages/session-storage.d.ts +1 -1
- package/lib/storages/session-storage.d.ts.map +1 -1
- package/lib/storages/session-storage.js +3 -1
- package/lib/storages/session-storage.js.map +1 -1
- package/lib/utils/change-notifier.d.ts +18 -0
- package/lib/utils/change-notifier.d.ts.map +1 -0
- package/lib/utils/change-notifier.js +38 -0
- package/lib/utils/change-notifier.js.map +1 -0
- package/lib/utils/create-web-storage.d.ts +10 -2
- package/lib/utils/create-web-storage.d.ts.map +1 -1
- package/lib/utils/create-web-storage.js +72 -75
- package/lib/utils/create-web-storage.js.map +1 -1
- package/lib/utils/extension-storage.d.ts +38 -0
- package/lib/utils/extension-storage.d.ts.map +1 -0
- package/lib/utils/extension-storage.js +66 -0
- package/lib/utils/extension-storage.js.map +1 -0
- package/lib/utils/get-new-item.d.ts +13 -1
- package/lib/utils/get-new-item.d.ts.map +1 -1
- package/lib/utils/get-new-item.js +27 -7
- package/lib/utils/get-new-item.js.map +1 -1
- package/lib/utils/get-new-value.d.ts +1 -1
- package/lib/utils/get-new-value.d.ts.map +1 -1
- package/lib/utils/get-persisted-value.d.ts +8 -1
- package/lib/utils/get-persisted-value.d.ts.map +1 -1
- package/lib/utils/get-persisted-value.js +19 -5
- package/lib/utils/get-persisted-value.js.map +1 -1
- package/lib/utils/is-async-storage.d.ts +7 -0
- package/lib/utils/is-async-storage.d.ts.map +1 -1
- package/lib/utils/is-async-storage.js +51 -20
- package/lib/utils/is-async-storage.js.map +1 -1
- package/lib/utils/storage-event-router.d.ts +17 -0
- package/lib/utils/storage-event-router.d.ts.map +1 -0
- package/lib/utils/storage-event-router.js +54 -0
- package/lib/utils/storage-event-router.js.map +1 -0
- package/lib/utils/use-storage-handler.d.ts +14 -3
- package/lib/utils/use-storage-handler.d.ts.map +1 -1
- package/lib/utils/use-storage-handler.js +109 -26
- package/lib/utils/use-storage-handler.js.map +1 -1
- package/package.json +97 -41
- package/src/@types/storage.ts +13 -13
- package/src/create-async-persisted-state.ts +125 -20
- package/src/create-persisted-state.ts +59 -23
- package/src/index.ts +12 -7
- package/src/storages/browser-storage.ts +8 -36
- package/src/storages/chrome-storage.ts +24 -46
- package/src/storages/local-storage.ts +3 -1
- package/src/storages/session-storage.ts +3 -1
- package/src/utils/change-notifier.ts +43 -0
- package/src/utils/create-web-storage.ts +74 -77
- package/src/utils/extension-storage.ts +79 -0
- package/src/utils/get-new-item.ts +32 -9
- package/src/utils/get-new-value.ts +1 -1
- package/src/utils/get-persisted-value.ts +22 -7
- package/src/utils/is-async-storage.ts +72 -27
- package/src/utils/storage-event-router.ts +67 -0
- package/src/utils/use-storage-handler.ts +144 -36
- package/storages/browser-storage.d.ts +1 -0
- package/storages/browser-storage.js +11 -0
- package/storages/chrome-storage.d.ts +1 -0
- package/storages/chrome-storage.js +11 -0
- package/storages/local-storage.d.ts +1 -0
- package/storages/local-storage.js +9 -0
- package/storages/session-storage.d.ts +1 -0
- package/storages/session-storage.js +9 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.addRoute = addRoute;
|
|
4
|
+
exports.removeRoute = removeRoute;
|
|
5
|
+
const routes = new Set();
|
|
6
|
+
let subscription = null;
|
|
7
|
+
function routeStorageEvent(event) {
|
|
8
|
+
if (!event.key)
|
|
9
|
+
return;
|
|
10
|
+
const changes = {
|
|
11
|
+
[event.key]: {
|
|
12
|
+
newValue: event.newValue,
|
|
13
|
+
oldValue: event.oldValue,
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
for (const route of routes) {
|
|
17
|
+
// A browser always names the area it changed, so real cross-tab events
|
|
18
|
+
// reach only the adapter of that area. An event a consumer synthesized —
|
|
19
|
+
// the sole way to test cross-tab sync under jsdom, and a common way to
|
|
20
|
+
// notify the writing tab in production — often cannot name one: the
|
|
21
|
+
// StorageEvent constructor rejects a mocked storage there. Those still go
|
|
22
|
+
// everywhere, exactly as they did before areas were told apart.
|
|
23
|
+
if (event.storageArea == null || event.storageArea === route.storage) {
|
|
24
|
+
route.fire(changes);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
// A runtime can provide storage without the DOM event API, and can provide half
|
|
29
|
+
// of that API: subscribing where nothing can unsubscribe strands a listener and
|
|
30
|
+
// makes releasing it throw, so both halves are required before taking one.
|
|
31
|
+
function canSubscribe() {
|
|
32
|
+
return typeof globalThis.addEventListener === 'function' && typeof globalThis.removeEventListener === 'function';
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Starts routing DOM storage events to `route`. Every adapter shares one
|
|
36
|
+
* subscription on the global object, so creating adapters nobody listens to
|
|
37
|
+
* costs nothing.
|
|
38
|
+
*/
|
|
39
|
+
function addRoute(route) {
|
|
40
|
+
routes.add(route);
|
|
41
|
+
if (!subscription && canSubscribe()) {
|
|
42
|
+
subscription = routeStorageEvent;
|
|
43
|
+
globalThis.addEventListener('storage', subscription);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/** Stops routing to `route`, releasing the shared subscription with the last one. */
|
|
47
|
+
function removeRoute(route) {
|
|
48
|
+
routes.delete(route);
|
|
49
|
+
if (routes.size === 0 && subscription) {
|
|
50
|
+
globalThis.removeEventListener('storage', subscription);
|
|
51
|
+
subscription = null;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=storage-event-router.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage-event-router.js","sourceRoot":"","sources":["../../src/utils/storage-event-router.ts"],"names":[],"mappings":";;AA+CA,4BAQC;AAGD,kCAQC;AA1DD,MAAM,MAAM,GAAG,IAAI,GAAG,EAAqB,CAAA;AAE3C,IAAI,YAAY,GAA2C,IAAI,CAAA;AAE/D,SAAS,iBAAiB,CAAC,KAAmB;IAC5C,IAAI,CAAC,KAAK,CAAC,GAAG;QAAE,OAAM;IAEtB,MAAM,OAAO,GAAG;QACd,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE;YACX,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,QAAQ,EAAE,KAAK,CAAC,QAAQ;SACzB;KACF,CAAA;IAED,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,uEAAuE;QACvE,yEAAyE;QACzE,uEAAuE;QACvE,oEAAoE;QACpE,0EAA0E;QAC1E,gEAAgE;QAChE,IAAI,KAAK,CAAC,WAAW,IAAI,IAAI,IAAI,KAAK,CAAC,WAAW,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC;YACrE,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;QACrB,CAAC;IACH,CAAC;AACH,CAAC;AAED,gFAAgF;AAChF,gFAAgF;AAChF,2EAA2E;AAC3E,SAAS,YAAY;IACnB,OAAO,OAAO,UAAU,CAAC,gBAAgB,KAAK,UAAU,IAAI,OAAO,UAAU,CAAC,mBAAmB,KAAK,UAAU,CAAA;AAClH,CAAC;AAED;;;;GAIG;AACH,SAAgB,QAAQ,CAAC,KAAwB;IAC/C,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;IAEjB,IAAI,CAAC,YAAY,IAAI,YAAY,EAAE,EAAE,CAAC;QACpC,YAAY,GAAG,iBAAiB,CAAA;QAEhC,UAAU,CAAC,gBAAgB,CAAC,SAAS,EAAE,YAAY,CAAC,CAAA;IACtD,CAAC;AACH,CAAC;AAED,qFAAqF;AACrF,SAAgB,WAAW,CAAC,KAAwB;IAClD,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IAEpB,IAAI,MAAM,CAAC,IAAI,KAAK,CAAC,IAAI,YAAY,EAAE,CAAC;QACtC,UAAU,CAAC,mBAAmB,CAAC,SAAS,EAAE,YAAY,CAAC,CAAA;QAEvD,YAAY,GAAG,IAAI,CAAA;IACrB,CAAC;AACH,CAAC"}
|
|
@@ -1,4 +1,15 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { AsyncStorage, Storage } from '../@types/storage';
|
|
3
|
-
|
|
1
|
+
import type React from 'react';
|
|
2
|
+
import type { AsyncStorage, Storage } from '../@types/storage';
|
|
3
|
+
/**
|
|
4
|
+
* Remembers an entry the hook is about to write, so the change the backend
|
|
5
|
+
* reports for it can be told apart from someone else's write.
|
|
6
|
+
*
|
|
7
|
+
* Recorded before the write, because a backend may report it before the call
|
|
8
|
+
* settles. One slot was not enough: a backend free to report after its write
|
|
9
|
+
* settles - chrome and browser storage both are - lets the next write overwrite
|
|
10
|
+
* the record of a write still waiting to be reported, and that unsuppressed echo
|
|
11
|
+
* then puts the earlier value back over the later one.
|
|
12
|
+
*/
|
|
13
|
+
export declare function recordOwnWrite(pendingOwnWrites: React.RefObject<string[]>, item: string): void;
|
|
14
|
+
export default function useStorageHandler<T>(key: string, storageKey: string, applyValue: (value: T) => void, storage: AsyncStorage | Storage, initialValue: T | (() => T), pendingOwnWrites: React.RefObject<string[]>): void;
|
|
4
15
|
//# sourceMappingURL=use-storage-handler.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-storage-handler.d.ts","sourceRoot":"","sources":["../../src/utils/use-storage-handler.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"use-storage-handler.d.ts","sourceRoot":"","sources":["../../src/utils/use-storage-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAiB,MAAM,mBAAmB,CAAA;AAkE7E;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,gBAAgB,EAAE,KAAK,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAM9F;AA+DD,MAAM,CAAC,OAAO,UAAU,iBAAiB,CAAC,CAAC,EACzC,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,EAC9B,OAAO,EAAE,YAAY,GAAG,OAAO,EAC/B,YAAY,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EAC3B,gBAAgB,EAAE,KAAK,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,GAC1C,IAAI,CAsBN"}
|
|
@@ -1,48 +1,131 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.recordOwnWrite = recordOwnWrite;
|
|
4
|
+
exports.default = useStorageHandler;
|
|
4
5
|
const react_1 = require("react");
|
|
5
6
|
const is_1 = require("@plq/is");
|
|
6
|
-
function
|
|
7
|
-
let
|
|
7
|
+
function readStoredValue(key, entry) {
|
|
8
|
+
let parsed;
|
|
8
9
|
try {
|
|
9
|
-
|
|
10
|
+
parsed = JSON.parse(entry);
|
|
10
11
|
}
|
|
11
12
|
catch (err) {
|
|
12
|
-
console.error(
|
|
13
|
+
console.error("use-persisted-state: Can't parse value from storage", err);
|
|
14
|
+
return { status: 'unavailable' };
|
|
13
15
|
}
|
|
14
|
-
|
|
16
|
+
// A foreign entry can be any JSON value, and `in` throws on a primitive. This
|
|
17
|
+
// runs inside the adapter's notify loop, where a throw also cuts off every
|
|
18
|
+
// listener queued behind this one.
|
|
19
|
+
if (!(0, is_1.isObject)(parsed) || !(key in parsed))
|
|
20
|
+
return { status: 'unavailable' };
|
|
21
|
+
return { status: 'stored', value: parsed[key] };
|
|
15
22
|
}
|
|
16
|
-
|
|
23
|
+
// Restores the initial value when the whole entry is removed from the storage.
|
|
24
|
+
function applyRemoval(change, itemKey, applyValue, latestInitialValue) {
|
|
25
|
+
if (change.oldValue === null || change.oldValue === undefined)
|
|
26
|
+
return;
|
|
27
|
+
const oldValue = readStoredValue(itemKey, change.oldValue);
|
|
28
|
+
const declaredInitialValue = latestInitialValue.current;
|
|
29
|
+
// Compared against the resolved value: a factory is never equal to what it
|
|
30
|
+
// produces, so comparing the declaration re-applies the initial value on every
|
|
31
|
+
// removal.
|
|
32
|
+
const initialValue = (0, is_1.isFunction)(declaredInitialValue) ? declaredInitialValue() : declaredInitialValue;
|
|
33
|
+
// An entry with no readable value for the key cannot be shown to have held the
|
|
34
|
+
// initial value, so the fallback is applied rather than skipped. The entry is
|
|
35
|
+
// gone either way, and stale state left in place is worse than a redundant
|
|
36
|
+
// restore.
|
|
37
|
+
if (oldValue.status === 'stored' && oldValue.value === initialValue)
|
|
38
|
+
return;
|
|
39
|
+
applyValue(initialValue);
|
|
40
|
+
}
|
|
41
|
+
// A backend that reports nothing back leaves every record unmatched, so the list
|
|
42
|
+
// needs a ceiling or it grows by one string per write for as long as the hook is
|
|
43
|
+
// mounted. A bound, not a tuning: a backend that does report drains the list on
|
|
44
|
+
// every echo, and one that reports late is what the list exists for.
|
|
45
|
+
const MAX_PENDING_OWN_WRITES = 8;
|
|
46
|
+
/**
|
|
47
|
+
* Remembers an entry the hook is about to write, so the change the backend
|
|
48
|
+
* reports for it can be told apart from someone else's write.
|
|
49
|
+
*
|
|
50
|
+
* Recorded before the write, because a backend may report it before the call
|
|
51
|
+
* settles. One slot was not enough: a backend free to report after its write
|
|
52
|
+
* settles - chrome and browser storage both are - lets the next write overwrite
|
|
53
|
+
* the record of a write still waiting to be reported, and that unsuppressed echo
|
|
54
|
+
* then puts the earlier value back over the later one.
|
|
55
|
+
*/
|
|
56
|
+
function recordOwnWrite(pendingOwnWrites, item) {
|
|
57
|
+
const pending = pendingOwnWrites.current;
|
|
58
|
+
if (pending.length >= MAX_PENDING_OWN_WRITES)
|
|
59
|
+
pending.shift();
|
|
60
|
+
pending.push(item);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Reports whether this change is a write the hook itself made, forgetting the
|
|
64
|
+
* record when it is. A backend reports a write to every listener, the one that
|
|
65
|
+
* made it included, and applying that echo is the storage-to-state re-sync this
|
|
66
|
+
* hook was rebuilt without, arriving by another road: it decodes the entry again
|
|
67
|
+
* and hands the caller an equal value with a new identity, plus a render for a
|
|
68
|
+
* value it already holds.
|
|
69
|
+
*
|
|
70
|
+
* The price, accepted knowingly: for a value JSON cannot carry, the writer keeps
|
|
71
|
+
* what it set - NaN - while every other component on the key decodes the null
|
|
72
|
+
* that reached storage, so the two disagree until one of them remounts. Applying
|
|
73
|
+
* the echo would settle that disagreement and bring back both the second
|
|
74
|
+
* storage-to-state path and the render per write, so it is not the repair it
|
|
75
|
+
* looks like.
|
|
76
|
+
*
|
|
77
|
+
* Forgetting on the first match keeps a later identical entry a change. Another
|
|
78
|
+
* hook writing the same bytes is suppressed along with it, and nothing is lost:
|
|
79
|
+
* it would have replaced a value with an equal one.
|
|
80
|
+
*/
|
|
81
|
+
function consumeOwnWriteEcho(entry, pendingOwnWrites) {
|
|
82
|
+
const matched = pendingOwnWrites.current.indexOf(entry);
|
|
83
|
+
if (matched === -1)
|
|
84
|
+
return false;
|
|
85
|
+
// Everything recorded before the reported entry goes with it: a backend applies
|
|
86
|
+
// writes in the order it took them and reports them in that order too, so a
|
|
87
|
+
// record still unmatched by now has no echo left to wait for.
|
|
88
|
+
pendingOwnWrites.current.splice(0, matched + 1);
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
// Builds the change handler. Not a hook, despite living next to one.
|
|
92
|
+
function createStorageHandler(itemKey, storageKey, applyValue, latestInitialValue, pendingOwnWrites) {
|
|
17
93
|
return (changes) => {
|
|
18
|
-
|
|
19
|
-
if (key
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
if (key === storageKey
|
|
28
|
-
&& change.newValue !== null
|
|
29
|
-
&& change.newValue !== undefined) {
|
|
30
|
-
const newValue = getValue(itemKey, change.newValue);
|
|
31
|
-
if (newValue !== null)
|
|
32
|
-
setState(newValue);
|
|
94
|
+
for (const [key, change] of Object.entries(changes)) {
|
|
95
|
+
if (key !== storageKey)
|
|
96
|
+
continue;
|
|
97
|
+
// Ahead of the echo check, which needs an entry to match and a removal has
|
|
98
|
+
// none. A removal is never one of this hook's own writes anyway: only the
|
|
99
|
+
// entries it stores are recorded.
|
|
100
|
+
if (change.newValue === null || change.newValue === undefined) {
|
|
101
|
+
applyRemoval(change, itemKey, applyValue, latestInitialValue);
|
|
102
|
+
continue;
|
|
33
103
|
}
|
|
34
|
-
|
|
104
|
+
if (consumeOwnWriteEcho(change.newValue, pendingOwnWrites))
|
|
105
|
+
continue;
|
|
106
|
+
const newValue = readStoredValue(itemKey, change.newValue);
|
|
107
|
+
if (newValue.status === 'stored')
|
|
108
|
+
applyValue(newValue.value);
|
|
109
|
+
}
|
|
35
110
|
};
|
|
36
111
|
}
|
|
37
|
-
function
|
|
112
|
+
function useStorageHandler(key, storageKey, applyValue, storage, initialValue, pendingOwnWrites) {
|
|
113
|
+
// A removal restores the initial value the hook holds now, the same one the
|
|
114
|
+
// key-change path reads, so a caller whose default travels with its data gets
|
|
115
|
+
// that record's default back rather than the mounted one. Tracked through a ref
|
|
116
|
+
// rather than a dependency because an inline object or factory has a new
|
|
117
|
+
// identity every render, which would tear the subscription down and rebuild it;
|
|
118
|
+
// written during render, as the key the hook is rendering for is.
|
|
119
|
+
const latestInitialValue = (0, react_1.useRef)(initialValue);
|
|
120
|
+
latestInitialValue.current = initialValue;
|
|
38
121
|
(0, react_1.useEffect)(() => {
|
|
39
|
-
const handleStorage =
|
|
122
|
+
const handleStorage = createStorageHandler(key, storageKey, applyValue, latestInitialValue, pendingOwnWrites);
|
|
40
123
|
storage.onChanged.addListener(handleStorage);
|
|
41
124
|
return () => {
|
|
42
125
|
if (storage.onChanged.hasListener(handleStorage)) {
|
|
43
126
|
storage.onChanged.removeListener(handleStorage);
|
|
44
127
|
}
|
|
45
128
|
};
|
|
46
|
-
}, [
|
|
129
|
+
}, [key, storage.onChanged, storageKey, applyValue, pendingOwnWrites]);
|
|
47
130
|
}
|
|
48
131
|
//# sourceMappingURL=use-storage-handler.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-storage-handler.js","sourceRoot":"","sources":["../../src/utils/use-storage-handler.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"use-storage-handler.js","sourceRoot":"","sources":["../../src/utils/use-storage-handler.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,49 +1,110 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plq/use-persisted-state",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.1",
|
|
4
4
|
"description": "useState hook with persistence in storage",
|
|
5
|
+
"type": "commonjs",
|
|
5
6
|
"main": "lib/index.js",
|
|
6
7
|
"types": "lib/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": {
|
|
11
|
+
"types": "./esm/index.d.mts",
|
|
12
|
+
"default": "./esm/index.mjs"
|
|
13
|
+
},
|
|
14
|
+
"require": {
|
|
15
|
+
"types": "./lib/index.d.ts",
|
|
16
|
+
"default": "./lib/index.js"
|
|
17
|
+
},
|
|
18
|
+
"default": "./lib/index.js"
|
|
19
|
+
},
|
|
20
|
+
"./storages/local-storage": {
|
|
21
|
+
"import": {
|
|
22
|
+
"types": "./esm/storages/local-storage.d.mts",
|
|
23
|
+
"default": "./esm/storages/local-storage.mjs"
|
|
24
|
+
},
|
|
25
|
+
"require": {
|
|
26
|
+
"types": "./lib/storages/local-storage.d.ts",
|
|
27
|
+
"default": "./lib/storages/local-storage.js"
|
|
28
|
+
},
|
|
29
|
+
"default": "./lib/storages/local-storage.js"
|
|
30
|
+
},
|
|
31
|
+
"./storages/session-storage": {
|
|
32
|
+
"import": {
|
|
33
|
+
"types": "./esm/storages/session-storage.d.mts",
|
|
34
|
+
"default": "./esm/storages/session-storage.mjs"
|
|
35
|
+
},
|
|
36
|
+
"require": {
|
|
37
|
+
"types": "./lib/storages/session-storage.d.ts",
|
|
38
|
+
"default": "./lib/storages/session-storage.js"
|
|
39
|
+
},
|
|
40
|
+
"default": "./lib/storages/session-storage.js"
|
|
41
|
+
},
|
|
42
|
+
"./storages/browser-storage": {
|
|
43
|
+
"import": {
|
|
44
|
+
"types": "./esm/storages/browser-storage.d.mts",
|
|
45
|
+
"default": "./esm/storages/browser-storage.mjs"
|
|
46
|
+
},
|
|
47
|
+
"require": {
|
|
48
|
+
"types": "./lib/storages/browser-storage.d.ts",
|
|
49
|
+
"default": "./lib/storages/browser-storage.js"
|
|
50
|
+
},
|
|
51
|
+
"default": "./lib/storages/browser-storage.js"
|
|
52
|
+
},
|
|
53
|
+
"./storages/chrome-storage": {
|
|
54
|
+
"import": {
|
|
55
|
+
"types": "./esm/storages/chrome-storage.d.mts",
|
|
56
|
+
"default": "./esm/storages/chrome-storage.mjs"
|
|
57
|
+
},
|
|
58
|
+
"require": {
|
|
59
|
+
"types": "./lib/storages/chrome-storage.d.ts",
|
|
60
|
+
"default": "./lib/storages/chrome-storage.js"
|
|
61
|
+
},
|
|
62
|
+
"default": "./lib/storages/chrome-storage.js"
|
|
63
|
+
},
|
|
64
|
+
"./lib": "./lib/index.js",
|
|
65
|
+
"./lib/*.js": "./lib/*.js",
|
|
66
|
+
"./lib/*": "./lib/*.js",
|
|
67
|
+
"./src": "./src/index.ts",
|
|
68
|
+
"./src/*.ts": "./src/*.ts",
|
|
69
|
+
"./src/*": "./src/*.ts",
|
|
70
|
+
"./package.json": "./package.json"
|
|
71
|
+
},
|
|
7
72
|
"engines": {
|
|
8
73
|
"node": ">=16.0.0"
|
|
9
74
|
},
|
|
10
75
|
"files": [
|
|
11
76
|
"/src",
|
|
12
77
|
"/lib",
|
|
78
|
+
"/esm",
|
|
79
|
+
"/storages",
|
|
13
80
|
"LICENSE"
|
|
14
81
|
],
|
|
15
82
|
"scripts": {
|
|
16
83
|
"build": "tsc",
|
|
17
84
|
"build:watch": "tsc --watch",
|
|
18
85
|
"build:types": "tsc --emitDeclarationOnly",
|
|
86
|
+
"typecheck": "tsc -p tsconfig.test.json --noEmit",
|
|
19
87
|
"test": "jest --verbose",
|
|
88
|
+
"test:random": "jest --randomize --showSeed",
|
|
20
89
|
"test:watch": "npm test -- --watchAll",
|
|
21
|
-
"lint": "
|
|
90
|
+
"lint": "biome check",
|
|
91
|
+
"lint:fix": "biome check --write",
|
|
92
|
+
"check:package": "node scripts/check-package.mjs",
|
|
93
|
+
"check:publint": "npx --yes publint",
|
|
94
|
+
"check:attw": "npx --yes @arethetypeswrong/cli --pack . --exclude-entrypoints lib",
|
|
95
|
+
"check:smoke": "node scripts/smoke.mjs",
|
|
96
|
+
"check:types": "tsc -p tsconfig.package.json --noEmit",
|
|
97
|
+
"prepublishOnly": "npm run build",
|
|
98
|
+
"format": "biome format --write",
|
|
22
99
|
"release": "dotenv release-it",
|
|
23
|
-
"demo": "vite
|
|
24
|
-
"demo:build": "vite build
|
|
25
|
-
"demo:preview": "vite preview
|
|
100
|
+
"demo": "vite",
|
|
101
|
+
"demo:build": "vite build",
|
|
102
|
+
"demo:preview": "vite preview"
|
|
26
103
|
},
|
|
27
104
|
"repository": {
|
|
28
105
|
"type": "git",
|
|
29
106
|
"url": "git+https://github.com/Akurganow/use-persisted-state.git"
|
|
30
107
|
},
|
|
31
|
-
"release-it": {
|
|
32
|
-
"hooks": {
|
|
33
|
-
"before:init": [
|
|
34
|
-
"npm run lint",
|
|
35
|
-
"npm test",
|
|
36
|
-
"npm run build"
|
|
37
|
-
],
|
|
38
|
-
"after:release": "echo Successfully released ${name} v${version} to ${repo.repository}."
|
|
39
|
-
},
|
|
40
|
-
"plugins": {
|
|
41
|
-
"@release-it/conventional-changelog": {
|
|
42
|
-
"preset": "conventionalcommits",
|
|
43
|
-
"infile": "CHANGELOG.md"
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
},
|
|
47
108
|
"keywords": [
|
|
48
109
|
"react",
|
|
49
110
|
"hook",
|
|
@@ -54,8 +115,9 @@
|
|
|
54
115
|
"persist",
|
|
55
116
|
"sync"
|
|
56
117
|
],
|
|
57
|
-
"author": "
|
|
118
|
+
"author": "Alexander Kurganov <a.kurganow@gmail.com>",
|
|
58
119
|
"license": "MIT",
|
|
120
|
+
"funding": "https://ko-fi.com/akurganow",
|
|
59
121
|
"publishConfig": {
|
|
60
122
|
"access": "public"
|
|
61
123
|
},
|
|
@@ -64,38 +126,32 @@
|
|
|
64
126
|
},
|
|
65
127
|
"homepage": "https://github.com/Akurganow/use-persisted-state#readme",
|
|
66
128
|
"devDependencies": {
|
|
67
|
-
"@
|
|
68
|
-
"@release-it/conventional-changelog": "^
|
|
69
|
-
"@testing-library/
|
|
129
|
+
"@biomejs/biome": "^2.5.6",
|
|
130
|
+
"@release-it/conventional-changelog": "^12.0.0",
|
|
131
|
+
"@testing-library/dom": "^10.4.1",
|
|
132
|
+
"@testing-library/jest-dom": "^7.0.0",
|
|
70
133
|
"@testing-library/react": "^16.3.0",
|
|
71
|
-
"@types/chrome": "0.
|
|
72
|
-
"@types/firefox-webext-browser": "^
|
|
134
|
+
"@types/chrome": "^0.2.2",
|
|
135
|
+
"@types/firefox-webext-browser": "^143.0.0",
|
|
73
136
|
"@types/jest": "^30.0.0",
|
|
74
137
|
"@types/react": "^19.0.0",
|
|
75
138
|
"@types/react-dom": "^19.0.0",
|
|
76
|
-
"@vitejs/plugin-react": "^
|
|
77
|
-
"
|
|
78
|
-
"dotenv-cli": "^10.0.0",
|
|
79
|
-
"eslint": "^9.32.0",
|
|
80
|
-
"eslint-plugin-jest": "^29.0.1",
|
|
81
|
-
"eslint-plugin-react": "^7.37.0",
|
|
82
|
-
"eslint-plugin-react-hooks": "^5.0.0",
|
|
139
|
+
"@vitejs/plugin-react": "^6.0.0",
|
|
140
|
+
"dotenv-cli": "^11.0.0",
|
|
83
141
|
"jest": "^30.0.5",
|
|
84
142
|
"jest-environment-jsdom": "^30.0.5",
|
|
85
143
|
"jest-localstorage-mock": "^2.4.6",
|
|
86
144
|
"jest-webextension-mock": "^4.0.0",
|
|
87
|
-
"process": "^0.11.10",
|
|
88
145
|
"react": "^19.1.1",
|
|
89
146
|
"react-dom": "^19.1.1",
|
|
90
|
-
"release-it": "^
|
|
147
|
+
"release-it": "^21.0.0",
|
|
91
148
|
"ts-jest": "^29.4.0",
|
|
92
|
-
"typescript": "^
|
|
93
|
-
"
|
|
94
|
-
"vite": "^7.0.6"
|
|
149
|
+
"typescript": "^6.0.3",
|
|
150
|
+
"vite": "^8.2.0"
|
|
95
151
|
},
|
|
96
152
|
"peerDependencies": {
|
|
97
|
-
"react": ">=16.8.0
|
|
98
|
-
"react-dom": ">=16.8.0
|
|
153
|
+
"react": ">=16.8.0",
|
|
154
|
+
"react-dom": ">=16.8.0"
|
|
99
155
|
},
|
|
100
156
|
"dependencies": {
|
|
101
157
|
"@plq/is": "^1.2.0"
|
package/src/@types/storage.ts
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
export interface StorageChange {
|
|
2
|
-
oldValue?: string | null
|
|
3
|
-
newValue?: string | null
|
|
2
|
+
oldValue?: string | null
|
|
3
|
+
newValue?: string | null
|
|
4
4
|
}
|
|
5
5
|
|
|
6
6
|
export type StorageChangeListener = (changes: { [key: string]: StorageChange }) => void
|
|
7
7
|
|
|
8
8
|
export interface StorageChangeEvent {
|
|
9
|
-
addListener(listener: StorageChangeListener): void
|
|
10
|
-
removeListener(listener: StorageChangeListener): void
|
|
11
|
-
hasListener(listener: StorageChangeListener): boolean
|
|
9
|
+
addListener(listener: StorageChangeListener): void
|
|
10
|
+
removeListener(listener: StorageChangeListener): void
|
|
11
|
+
hasListener(listener: StorageChangeListener): boolean
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
export interface Storage {
|
|
15
|
-
get: (keys: string | string[]) => { [key: string]: string }
|
|
16
|
-
set: (items: { [key: string]: string }) => void
|
|
17
|
-
remove: (keys: string | string[]) => void
|
|
18
|
-
onChanged: StorageChangeEvent
|
|
15
|
+
get: (keys: string | string[]) => { [key: string]: string }
|
|
16
|
+
set: (items: { [key: string]: string }) => void
|
|
17
|
+
remove: (keys: string | string[]) => void
|
|
18
|
+
onChanged: StorageChangeEvent
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
export interface AsyncStorage {
|
|
22
|
-
get: (keys: string | string[]) => Promise<{ [key: string]: string }
|
|
23
|
-
set: (items: { [key: string]: string }) => Promise<void
|
|
24
|
-
remove: (keys: string | string[]) => Promise<void
|
|
25
|
-
onChanged: StorageChangeEvent
|
|
22
|
+
get: (keys: string | string[]) => Promise<{ [key: string]: string }>
|
|
23
|
+
set: (items: { [key: string]: string }) => Promise<void>
|
|
24
|
+
remove: (keys: string | string[]) => Promise<void>
|
|
25
|
+
onChanged: StorageChangeEvent
|
|
26
26
|
}
|