@buoy-gg/storage 7.0.41 → 7.0.42
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 +11 -90
- package/lib/commonjs/index.js +1 -353
- package/lib/commonjs/preset.js +1 -85
- package/lib/commonjs/storage/components/DiffViewer/TreeDiffViewer.js +1 -36
- package/lib/commonjs/storage/components/DiffViewer/modes/ThemedSplitView.js +1 -12
- package/lib/commonjs/storage/components/DiffViewer/themes/diffThemes.js +1 -24
- package/lib/commonjs/storage/components/GameUIStorageBrowser.js +3 -1259
- package/lib/commonjs/storage/components/MMKVInstanceInfoPanel.js +1 -257
- package/lib/commonjs/storage/components/MMKVInstanceSelector.js +1 -419
- package/lib/commonjs/storage/components/SelectionActionBar.js +1 -207
- package/lib/commonjs/storage/components/StorageActionButtons.js +1 -242
- package/lib/commonjs/storage/components/StorageBrowserMode.js +1 -61
- package/lib/commonjs/storage/components/StorageEventActionButton.js +1 -121
- package/lib/commonjs/storage/components/StorageEventCard.js +1 -118
- package/lib/commonjs/storage/components/StorageEventDetailContent.js +1 -494
- package/lib/commonjs/storage/components/StorageEventFilterView.js +1 -160
- package/lib/commonjs/storage/components/StorageEventsSection.js +1 -24
- package/lib/commonjs/storage/components/StorageFilterCards.js +1 -231
- package/lib/commonjs/storage/components/StorageKeyCard.js +1 -520
- package/lib/commonjs/storage/components/StorageKeyDetailScreen.js +1 -579
- package/lib/commonjs/storage/components/StorageKeyRow.js +1 -559
- package/lib/commonjs/storage/components/StorageKeySection.js +1 -160
- package/lib/commonjs/storage/components/StorageKeyStats.js +1 -345
- package/lib/commonjs/storage/components/StorageModalWithTabs.js +1 -954
- package/lib/commonjs/storage/components/StorageSaveNotice.js +1 -171
- package/lib/commonjs/storage/components/StorageSection.js +1 -43
- package/lib/commonjs/storage/components/StorageTypeFilterBar.js +1 -144
- package/lib/commonjs/storage/hooks/useAsyncStorageKeys.js +1 -141
- package/lib/commonjs/storage/hooks/useMMKVInstances.js +1 -210
- package/lib/commonjs/storage/hooks/useMMKVKeys.js +1 -376
- package/lib/commonjs/storage/hooks/useSecureStoreKeys.js +1 -202
- package/lib/commonjs/storage/hooks/useStorageEvents.js +1 -61
- package/lib/commonjs/storage/stores/storageEventStore.js +1 -312
- package/lib/commonjs/storage/sync/storageSyncAdapter.js +1 -492
- package/lib/commonjs/storage/types.js +1 -5
- package/lib/commonjs/storage/utils/AsyncStorageListener.js +1 -691
- package/lib/commonjs/storage/utils/AsyncStorageListener.web.js +1 -89
- package/lib/commonjs/storage/utils/MMKVInstanceRegistry.js +1 -203
- package/lib/commonjs/storage/utils/MMKVListener.js +1 -416
- package/lib/commonjs/storage/utils/SecureStoreRegistry.js +1 -200
- package/lib/commonjs/storage/utils/asyncStorageCompat.js +1 -89
- package/lib/commonjs/storage/utils/browserStorageLifecycle.js +1 -10
- package/lib/commonjs/storage/utils/browserStorageLifecycle.web.js +1 -70
- package/lib/commonjs/storage/utils/clearAllStorage.js +1 -48
- package/lib/commonjs/storage/utils/deleteStorageKeys.js +1 -82
- package/lib/commonjs/storage/utils/lineDiff.js +1 -30
- package/lib/commonjs/storage/utils/mmkvAvailability.js +1 -62
- package/lib/commonjs/storage/utils/mmkvAvailability.web.js +1 -21
- package/lib/commonjs/storage/utils/mmkvTypeDetection.js +1 -154
- package/lib/commonjs/storage/utils/requiredStorageKeyScope.js +1 -17
- package/lib/commonjs/storage/utils/setStorageValue.js +1 -218
- package/lib/commonjs/storage/utils/snapshotProvider.js +1 -382
- package/lib/commonjs/storage/utils/storageActionHelpers.js +1 -46
- package/lib/commonjs/storage/utils/storageBrowserRefresh.js +1 -49
- package/lib/commonjs/storage/utils/storageLabels.js +1 -13
- package/lib/commonjs/storage/utils/storageLabels.web.js +1 -13
- package/lib/commonjs/storage/utils/storageOps.js +1 -53
- package/lib/commonjs/storage/utils/storageQueryUtils.js +1 -35
- package/lib/commonjs/storage/utils/storageTimeTravelUtils.js +1 -288
- package/lib/commonjs/storage/utils/valueType.js +1 -83
- package/lib/module/index.js +1 -114
- package/lib/module/preset.js +1 -82
- package/lib/module/storage/components/DiffViewer/TreeDiffViewer.js +1 -32
- package/lib/module/storage/components/DiffViewer/modes/ThemedSplitView.js +1 -9
- package/lib/module/storage/components/DiffViewer/themes/diffThemes.js +1 -10
- package/lib/module/storage/components/GameUIStorageBrowser.js +3 -1257
- package/lib/module/storage/components/MMKVInstanceInfoPanel.js +1 -253
- package/lib/module/storage/components/MMKVInstanceSelector.js +1 -415
- package/lib/module/storage/components/SelectionActionBar.js +1 -204
- package/lib/module/storage/components/StorageActionButtons.js +1 -238
- package/lib/module/storage/components/StorageBrowserMode.js +1 -57
- package/lib/module/storage/components/StorageEventActionButton.js +1 -118
- package/lib/module/storage/components/StorageEventCard.js +1 -113
- package/lib/module/storage/components/StorageEventDetailContent.js +1 -490
- package/lib/module/storage/components/StorageEventFilterView.js +1 -156
- package/lib/module/storage/components/StorageEventsSection.js +1 -20
- package/lib/module/storage/components/StorageFilterCards.js +1 -227
- package/lib/module/storage/components/StorageKeyCard.js +1 -517
- package/lib/module/storage/components/StorageKeyDetailScreen.js +1 -577
- package/lib/module/storage/components/StorageKeyRow.js +1 -554
- package/lib/module/storage/components/StorageKeySection.js +1 -155
- package/lib/module/storage/components/StorageKeyStats.js +1 -342
- package/lib/module/storage/components/StorageModalWithTabs.js +1 -949
- package/lib/module/storage/components/StorageSaveNotice.js +1 -168
- package/lib/module/storage/components/StorageSection.js +1 -40
- package/lib/module/storage/components/StorageTypeFilterBar.js +1 -139
- package/lib/module/storage/hooks/useAsyncStorageKeys.js +1 -136
- package/lib/module/storage/hooks/useMMKVInstances.js +1 -204
- package/lib/module/storage/hooks/useMMKVKeys.js +1 -371
- package/lib/module/storage/hooks/useSecureStoreKeys.js +1 -199
- package/lib/module/storage/hooks/useStorageEvents.js +1 -58
- package/lib/module/storage/stores/storageEventStore.js +1 -301
- package/lib/module/storage/sync/storageSyncAdapter.js +1 -486
- package/lib/module/storage/types.js +1 -3
- package/lib/module/storage/utils/AsyncStorageListener.js +1 -679
- package/lib/module/storage/utils/AsyncStorageListener.web.js +1 -76
- package/lib/module/storage/utils/MMKVInstanceRegistry.js +1 -197
- package/lib/module/storage/utils/MMKVListener.js +1 -403
- package/lib/module/storage/utils/SecureStoreRegistry.js +1 -194
- package/lib/module/storage/utils/asyncStorageCompat.js +1 -81
- package/lib/module/storage/utils/browserStorageLifecycle.js +1 -6
- package/lib/module/storage/utils/browserStorageLifecycle.web.js +1 -66
- package/lib/module/storage/utils/clearAllStorage.js +1 -43
- package/lib/module/storage/utils/deleteStorageKeys.js +1 -78
- package/lib/module/storage/utils/lineDiff.js +1 -12
- package/lib/module/storage/utils/mmkvAvailability.js +1 -56
- package/lib/module/storage/utils/mmkvAvailability.web.js +1 -15
- package/lib/module/storage/utils/mmkvTypeDetection.js +1 -148
- package/lib/module/storage/utils/requiredStorageKeyScope.js +1 -13
- package/lib/module/storage/utils/setStorageValue.js +1 -209
- package/lib/module/storage/utils/snapshotProvider.js +1 -380
- package/lib/module/storage/utils/storageActionHelpers.js +1 -42
- package/lib/module/storage/utils/storageBrowserRefresh.js +1 -44
- package/lib/module/storage/utils/storageLabels.js +1 -9
- package/lib/module/storage/utils/storageLabels.web.js +1 -9
- package/lib/module/storage/utils/storageOps.js +1 -46
- package/lib/module/storage/utils/storageQueryUtils.js +1 -30
- package/lib/module/storage/utils/storageTimeTravelUtils.js +1 -281
- package/lib/module/storage/utils/valueType.js +1 -76
- package/lib/web/index.mjs +2 -3
- package/package.json +5 -5
- package/lib/typescript/index.d.ts.map +0 -1
- package/lib/typescript/preset.d.ts.map +0 -1
- package/lib/typescript/storage/components/DiffViewer/TreeDiffViewer.d.ts.map +0 -1
- package/lib/typescript/storage/components/DiffViewer/modes/ThemedSplitView.d.ts.map +0 -1
- package/lib/typescript/storage/components/DiffViewer/themes/diffThemes.d.ts.map +0 -1
- package/lib/typescript/storage/components/GameUIStorageBrowser.d.ts.map +0 -1
- package/lib/typescript/storage/components/MMKVInstanceInfoPanel.d.ts.map +0 -1
- package/lib/typescript/storage/components/MMKVInstanceSelector.d.ts.map +0 -1
- package/lib/typescript/storage/components/SelectionActionBar.d.ts.map +0 -1
- package/lib/typescript/storage/components/StorageActionButtons.d.ts.map +0 -1
- package/lib/typescript/storage/components/StorageBrowserMode.d.ts.map +0 -1
- package/lib/typescript/storage/components/StorageEventActionButton.d.ts.map +0 -1
- package/lib/typescript/storage/components/StorageEventCard.d.ts.map +0 -1
- package/lib/typescript/storage/components/StorageEventDetailContent.d.ts.map +0 -1
- package/lib/typescript/storage/components/StorageEventFilterView.d.ts.map +0 -1
- package/lib/typescript/storage/components/StorageEventsSection.d.ts.map +0 -1
- package/lib/typescript/storage/components/StorageFilterCards.d.ts.map +0 -1
- package/lib/typescript/storage/components/StorageKeyCard.d.ts.map +0 -1
- package/lib/typescript/storage/components/StorageKeyDetailScreen.d.ts.map +0 -1
- package/lib/typescript/storage/components/StorageKeyRow.d.ts.map +0 -1
- package/lib/typescript/storage/components/StorageKeySection.d.ts.map +0 -1
- package/lib/typescript/storage/components/StorageKeyStats.d.ts.map +0 -1
- package/lib/typescript/storage/components/StorageModalWithTabs.d.ts.map +0 -1
- package/lib/typescript/storage/components/StorageSaveNotice.d.ts.map +0 -1
- package/lib/typescript/storage/components/StorageSection.d.ts.map +0 -1
- package/lib/typescript/storage/components/StorageTypeFilterBar.d.ts.map +0 -1
- package/lib/typescript/storage/hooks/useAsyncStorageKeys.d.ts.map +0 -1
- package/lib/typescript/storage/hooks/useMMKVInstances.d.ts.map +0 -1
- package/lib/typescript/storage/hooks/useMMKVKeys.d.ts.map +0 -1
- package/lib/typescript/storage/hooks/useSecureStoreKeys.d.ts.map +0 -1
- package/lib/typescript/storage/hooks/useStorageEvents.d.ts.map +0 -1
- package/lib/typescript/storage/stores/storageEventStore.d.ts.map +0 -1
- package/lib/typescript/storage/sync/storageSyncAdapter.d.ts.map +0 -1
- package/lib/typescript/storage/types.d.ts.map +0 -1
- package/lib/typescript/storage/utils/AsyncStorageListener.d.ts.map +0 -1
- package/lib/typescript/storage/utils/AsyncStorageListener.web.d.ts.map +0 -1
- package/lib/typescript/storage/utils/MMKVInstanceRegistry.d.ts.map +0 -1
- package/lib/typescript/storage/utils/MMKVListener.d.ts.map +0 -1
- package/lib/typescript/storage/utils/SecureStoreRegistry.d.ts.map +0 -1
- package/lib/typescript/storage/utils/asyncStorageCompat.d.ts.map +0 -1
- package/lib/typescript/storage/utils/browserStorageLifecycle.d.ts.map +0 -1
- package/lib/typescript/storage/utils/browserStorageLifecycle.web.d.ts.map +0 -1
- package/lib/typescript/storage/utils/clearAllStorage.d.ts.map +0 -1
- package/lib/typescript/storage/utils/deleteStorageKeys.d.ts.map +0 -1
- package/lib/typescript/storage/utils/lineDiff.d.ts.map +0 -1
- package/lib/typescript/storage/utils/mmkvAvailability.d.ts.map +0 -1
- package/lib/typescript/storage/utils/mmkvAvailability.web.d.ts.map +0 -1
- package/lib/typescript/storage/utils/mmkvTypeDetection.d.ts.map +0 -1
- package/lib/typescript/storage/utils/requiredStorageKeyScope.d.ts.map +0 -1
- package/lib/typescript/storage/utils/setStorageValue.d.ts.map +0 -1
- package/lib/typescript/storage/utils/snapshotProvider.d.ts.map +0 -1
- package/lib/typescript/storage/utils/storageActionHelpers.d.ts.map +0 -1
- package/lib/typescript/storage/utils/storageBrowserRefresh.d.ts.map +0 -1
- package/lib/typescript/storage/utils/storageLabels.d.ts.map +0 -1
- package/lib/typescript/storage/utils/storageLabels.web.d.ts.map +0 -1
- package/lib/typescript/storage/utils/storageOps.d.ts.map +0 -1
- package/lib/typescript/storage/utils/storageQueryUtils.d.ts.map +0 -1
- package/lib/typescript/storage/utils/storageTimeTravelUtils.d.ts.map +0 -1
- package/lib/typescript/storage/utils/valueType.d.ts.map +0 -1
|
@@ -1,202 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.useSecureStoreKeys = useSecureStoreKeys;
|
|
7
|
-
var _react = require("react");
|
|
8
|
-
var _requiredStorageKeyScope = require("../utils/requiredStorageKeyScope");
|
|
9
|
-
var _SecureStoreRegistry = require("../utils/SecureStoreRegistry");
|
|
10
|
-
/**
|
|
11
|
-
* Placeholder value shown for `requireAuthentication` keys. Reading those
|
|
12
|
-
* triggers a biometric (Face ID / fingerprint) prompt, so the tool never
|
|
13
|
-
* auto-reads them — it just shows they exist.
|
|
14
|
-
*/
|
|
15
|
-
const BIOMETRIC_PLACEHOLDER = "•••••• (biometric protected)";
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* How often to re-read registered SecureStore values.
|
|
19
|
-
*
|
|
20
|
-
* SecureStore is the one backend with no change feed at all: AsyncStorage and
|
|
21
|
-
* MMKV writes are intercepted (and MMKV has a native value-changed listener),
|
|
22
|
-
* but the keychain gives no notification, so a value written by the app while
|
|
23
|
-
* the tool is open would otherwise stay stale until the browser remounts.
|
|
24
|
-
* Polling is the only option — kept cheap by re-reading a handful of registered
|
|
25
|
-
* keys and only committing state when a value actually changed.
|
|
26
|
-
*/
|
|
27
|
-
const DEFAULT_POLL_MS = 3000;
|
|
28
|
-
/** Identity signature used to skip no-op state updates. */
|
|
29
|
-
function signature(keys) {
|
|
30
|
-
return JSON.stringify(keys);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Read all registered SecureStore keys into StorageKeyInfo[] for the browser.
|
|
35
|
-
*
|
|
36
|
-
* SecureStore has no enumeration API, so this only surfaces keys declared via
|
|
37
|
-
* `registerSecureStoreKeys()` (see SecureStoreRegistry). Values are read with
|
|
38
|
-
* the options each key was registered with (keychainService must match), and
|
|
39
|
-
* biometric-protected keys are listed without being read.
|
|
40
|
-
*
|
|
41
|
-
* Values are re-read on a poll and whenever the registry changes, so the
|
|
42
|
-
* browser tracks writes the app makes while the tool is open.
|
|
43
|
-
*/
|
|
44
|
-
function useSecureStoreKeys(requiredStorageKeys = [], options = {}) {
|
|
45
|
-
const {
|
|
46
|
-
pollMs = DEFAULT_POLL_MS
|
|
47
|
-
} = options;
|
|
48
|
-
// Read through a ref so a fresh array literal each render doesn't restart the poll.
|
|
49
|
-
const requiredRef = (0, _react.useRef)(requiredStorageKeys);
|
|
50
|
-
requiredRef.current = requiredStorageKeys;
|
|
51
|
-
const requiredSignature = JSON.stringify(requiredStorageKeys);
|
|
52
|
-
const [storageKeys, setStorageKeys] = (0, _react.useState)([]);
|
|
53
|
-
const [isLoading, setIsLoading] = (0, _react.useState)(true);
|
|
54
|
-
const [error, setError] = (0, _react.useState)(null);
|
|
55
|
-
|
|
56
|
-
// Last committed content, so a poll that finds nothing new costs zero
|
|
57
|
-
// renders (this hook feeds a non-virtualized list of every storage key).
|
|
58
|
-
const signatureRef = (0, _react.useRef)(signature([]));
|
|
59
|
-
const hasLoadedRef = (0, _react.useRef)(false);
|
|
60
|
-
const inFlightRef = (0, _react.useRef)(false);
|
|
61
|
-
const commit = (0, _react.useCallback)(keys => {
|
|
62
|
-
const next = signature(keys);
|
|
63
|
-
if (next === signatureRef.current) return;
|
|
64
|
-
signatureRef.current = next;
|
|
65
|
-
setStorageKeys(keys);
|
|
66
|
-
}, []);
|
|
67
|
-
const fetchSecureStoreData = (0, _react.useCallback)(async () => {
|
|
68
|
-
// Reads are async and the poll is unconditional — never stack them.
|
|
69
|
-
if (inFlightRef.current) return;
|
|
70
|
-
inFlightRef.current = true;
|
|
71
|
-
try {
|
|
72
|
-
const module = _SecureStoreRegistry.secureStoreRegistry.getModule();
|
|
73
|
-
const entries = _SecureStoreRegistry.secureStoreRegistry.getAll();
|
|
74
|
-
// Required keys scoped to SecureStore. Registration is what lets the tool
|
|
75
|
-
// read a key; `requiredStorageKeys` is what says the app needs it. A
|
|
76
|
-
// registered key with no value that nobody requires is simply absent.
|
|
77
|
-
const required = requiredRef.current.filter(req => (0, _requiredStorageKeyScope.requiredKeyAppliesTo)(req, "secure"));
|
|
78
|
-
const requiredFor = key => required.find(req => (typeof req === "string" ? req : req.key) === key);
|
|
79
|
-
if (!module || entries.length === 0 && required.length === 0) {
|
|
80
|
-
commit([]);
|
|
81
|
-
hasLoadedRef.current = true;
|
|
82
|
-
setIsLoading(false);
|
|
83
|
-
return;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// Only the first read is a "loading" state; polls refresh in place so the
|
|
87
|
-
// browser never flashes its spinner over data it already has.
|
|
88
|
-
if (!hasLoadedRef.current) setIsLoading(true);
|
|
89
|
-
setError(null);
|
|
90
|
-
const keys = [];
|
|
91
|
-
|
|
92
|
-
// Required keys that were never registered are still readable by name,
|
|
93
|
-
// with the default keychain options.
|
|
94
|
-
const toRead = [...entries, ...required.map(req => typeof req === "string" ? req : req.key).filter(key => !entries.some(e => e.key === key)).map(key => ({
|
|
95
|
-
key,
|
|
96
|
-
options: {},
|
|
97
|
-
description: undefined
|
|
98
|
-
}))];
|
|
99
|
-
for (const entry of toRead) {
|
|
100
|
-
const req = requiredFor(entry.key);
|
|
101
|
-
const reqObj = typeof req === "object" ? req : undefined;
|
|
102
|
-
const expectations = {
|
|
103
|
-
...(reqObj?.expectedValue !== undefined && {
|
|
104
|
-
expectedValue: reqObj.expectedValue
|
|
105
|
-
}),
|
|
106
|
-
...(reqObj?.expectedType !== undefined && {
|
|
107
|
-
expectedType: reqObj.expectedType
|
|
108
|
-
})
|
|
109
|
-
};
|
|
110
|
-
const description = reqObj?.description ?? entry.description;
|
|
111
|
-
if (entry.options.requireAuthentication) {
|
|
112
|
-
// Never auto-read: reading would fire a biometric prompt.
|
|
113
|
-
keys.push({
|
|
114
|
-
key: entry.key,
|
|
115
|
-
value: BIOMETRIC_PLACEHOLDER,
|
|
116
|
-
storageType: "secure",
|
|
117
|
-
status: req ? "required_present" : "optional_present",
|
|
118
|
-
category: req ? "required" : "optional",
|
|
119
|
-
description: description ?? "Protected by biometric authentication — value not read by DevTools",
|
|
120
|
-
...expectations,
|
|
121
|
-
...(entry.options.keychainService && {
|
|
122
|
-
instanceId: entry.options.keychainService
|
|
123
|
-
})
|
|
124
|
-
});
|
|
125
|
-
continue;
|
|
126
|
-
}
|
|
127
|
-
let rawValue = null;
|
|
128
|
-
try {
|
|
129
|
-
rawValue = await module.getItemAsync(entry.key, entry.options);
|
|
130
|
-
} catch {
|
|
131
|
-
// Key unreadable (e.g. keychain state changed) — treat as absent.
|
|
132
|
-
}
|
|
133
|
-
if (rawValue === null && !req) continue;
|
|
134
|
-
|
|
135
|
-
// Parse JSON values for the DataViewer, same as the AsyncStorage hook.
|
|
136
|
-
let parsedValue = rawValue;
|
|
137
|
-
if (rawValue) {
|
|
138
|
-
try {
|
|
139
|
-
parsedValue = JSON.parse(rawValue);
|
|
140
|
-
} catch {
|
|
141
|
-
parsedValue = rawValue;
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
let status = "optional_present";
|
|
145
|
-
if (req) {
|
|
146
|
-
if (rawValue === null) status = "required_missing";else if (reqObj?.expectedValue !== undefined) status = String(parsedValue) === String(reqObj.expectedValue) ? "required_present" : "required_wrong_value";else if (reqObj?.expectedType !== undefined) {
|
|
147
|
-
const actualType = parsedValue === null ? "null" : Array.isArray(parsedValue) ? "array" : typeof parsedValue;
|
|
148
|
-
// A keychain value is always stored as a string, so a string is
|
|
149
|
-
// acceptable wherever the parsed form would be.
|
|
150
|
-
const want = reqObj.expectedType.toLowerCase();
|
|
151
|
-
status = actualType === want || want === "string" && typeof rawValue === "string" ? "required_present" : "required_wrong_type";
|
|
152
|
-
} else status = "required_present";
|
|
153
|
-
}
|
|
154
|
-
keys.push({
|
|
155
|
-
key: entry.key,
|
|
156
|
-
value: rawValue === null ? undefined : parsedValue,
|
|
157
|
-
storageType: "secure",
|
|
158
|
-
status,
|
|
159
|
-
category: req ? "required" : "optional",
|
|
160
|
-
...(description && {
|
|
161
|
-
description
|
|
162
|
-
}),
|
|
163
|
-
...expectations,
|
|
164
|
-
...(entry.options.keychainService && {
|
|
165
|
-
instanceId: entry.options.keychainService
|
|
166
|
-
})
|
|
167
|
-
});
|
|
168
|
-
}
|
|
169
|
-
commit(keys);
|
|
170
|
-
} catch (err) {
|
|
171
|
-
setError(err instanceof Error ? err : new Error("Failed to read SecureStore"));
|
|
172
|
-
commit([]);
|
|
173
|
-
} finally {
|
|
174
|
-
hasLoadedRef.current = true;
|
|
175
|
-
inFlightRef.current = false;
|
|
176
|
-
setIsLoading(false);
|
|
177
|
-
}
|
|
178
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
179
|
-
}, [commit, requiredSignature]);
|
|
180
|
-
|
|
181
|
-
// Initial fetch + poll. Registration usually happens at app startup, but the
|
|
182
|
-
// registry is also refilled on the dashboard every time a device syncs, so
|
|
183
|
-
// subscribe as well rather than assuming the key list is final at mount.
|
|
184
|
-
(0, _react.useEffect)(() => {
|
|
185
|
-
fetchSecureStoreData();
|
|
186
|
-
const unsubscribe = _SecureStoreRegistry.secureStoreRegistry.subscribe(() => {
|
|
187
|
-
fetchSecureStoreData();
|
|
188
|
-
});
|
|
189
|
-
if (pollMs <= 0) return unsubscribe;
|
|
190
|
-
const interval = setInterval(fetchSecureStoreData, pollMs);
|
|
191
|
-
return () => {
|
|
192
|
-
unsubscribe();
|
|
193
|
-
clearInterval(interval);
|
|
194
|
-
};
|
|
195
|
-
}, [fetchSecureStoreData, pollMs]);
|
|
196
|
-
return {
|
|
197
|
-
storageKeys,
|
|
198
|
-
isLoading,
|
|
199
|
-
error,
|
|
200
|
-
refresh: fetchSecureStoreData
|
|
201
|
-
};
|
|
202
|
-
}
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.useSecureStoreKeys=useSecureStoreKeys;var _react=require("react");var _requiredStorageKeyScope=require("../utils/requiredStorageKeyScope");var _SecureStoreRegistry=require("../utils/SecureStoreRegistry");const BIOMETRIC_PLACEHOLDER="\u2022\u2022\u2022\u2022\u2022\u2022 (biometric protected)";const DEFAULT_POLL_MS=3e3;function signature(u){return JSON.stringify(u)}function useSecureStoreKeys(u=[],x={}){const{pollMs:p=DEFAULT_POLL_MS}=x;const h=(0,_react.useRef)(u);h.current=u;const b=JSON.stringify(u);const[T,m]=(0,_react.useState)([]);const[L,d]=(0,_react.useState)(true);const[A,q]=(0,_react.useState)(null);const v=(0,_react.useRef)(signature([]));const y=(0,_react.useRef)(false);const f=(0,_react.useRef)(false);const l=(0,_react.useCallback)(r=>{const i=signature(r);if(i===v.current)return;v.current=i;m(r)},[]);const c=(0,_react.useCallback)(async()=>{if(f.current)return;f.current=true;try{const r=_SecureStoreRegistry.secureStoreRegistry.getModule();const i=_SecureStoreRegistry.secureStoreRegistry.getAll();const g=h.current.filter(e=>(0,_requiredStorageKeyScope.requiredKeyAppliesTo)(e,"secure"));const E=e=>g.find(t=>(typeof t==="string"?t:t.key)===e);if(!r||i.length===0&&g.length===0){l([]);y.current=true;d(false);return}if(!y.current)d(true);q(null);const S=[];const I=[...i,...g.map(e=>typeof e==="string"?e:e.key).filter(e=>!i.some(t=>t.key===e)).map(e=>({key:e,options:{},description:void 0}))];for(const e of I){const t=E(e.key);const n=typeof t==="object"?t:void 0;const R={...n?.expectedValue!==void 0&&{expectedValue:n.expectedValue},...n?.expectedType!==void 0&&{expectedType:n.expectedType}};const _=n?.description??e.description;if(e.options.requireAuthentication){S.push({key:e.key,value:BIOMETRIC_PLACEHOLDER,storageType:"secure",status:t?"required_present":"optional_present",category:t?"required":"optional",description:_??"Protected by biometric authentication \u2014 value not read by DevTools",...R,...e.options.keychainService&&{instanceId:e.options.keychainService}});continue}let s=null;try{s=await r.getItemAsync(e.key,e.options)}catch{}if(s===null&&!t)continue;let o=s;if(s){try{o=JSON.parse(s)}catch{o=s}}let a="optional_present";if(t){if(s===null)a="required_missing";else if(n?.expectedValue!==void 0)a=String(o)===String(n.expectedValue)?"required_present":"required_wrong_value";else if(n?.expectedType!==void 0){const O=o===null?"null":Array.isArray(o)?"array":typeof o;const k=n.expectedType.toLowerCase();a=O===k||k==="string"&&typeof s==="string"?"required_present":"required_wrong_type"}else a="required_present"}S.push({key:e.key,value:s===null?void 0:o,storageType:"secure",status:a,category:t?"required":"optional",..._&&{description:_},...R,...e.options.keychainService&&{instanceId:e.options.keychainService}})}l(S)}catch(r){q(r instanceof Error?r:new Error("Failed to read SecureStore"));l([])}finally{y.current=true;f.current=false;d(false)}},[l,b]);(0,_react.useEffect)(()=>{c();const r=_SecureStoreRegistry.secureStoreRegistry.subscribe(()=>{c()});if(p<=0)return r;const i=setInterval(c,p);return()=>{r();clearInterval(i)}},[c,p]);return{storageKeys:T,isLoading:L,error:A,refresh:c}}
|
|
@@ -1,61 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.useStorageEvents = useStorageEvents;
|
|
7
|
-
var _react = require("react");
|
|
8
|
-
var _sharedUi = require("@buoy-gg/shared-ui");
|
|
9
|
-
var _storageEventStore = require("../stores/storageEventStore");
|
|
10
|
-
/**
|
|
11
|
-
* useStorageEvents Hook
|
|
12
|
-
*
|
|
13
|
-
* React hook for subscribing to storage events from the centralized store.
|
|
14
|
-
* Uses self-managing Subscribable pattern - the storage listener automatically
|
|
15
|
-
* starts when this hook mounts and stops when all subscribers unmount.
|
|
16
|
-
*
|
|
17
|
-
* @example
|
|
18
|
-
* ```typescript
|
|
19
|
-
* function MyComponent() {
|
|
20
|
-
* const { events, clearEvents, isCapturing } = useStorageEvents();
|
|
21
|
-
*
|
|
22
|
-
* return (
|
|
23
|
-
* <View>
|
|
24
|
-
* {events.map((event) => (
|
|
25
|
-
* <Text key={event.timestamp.toString()}>
|
|
26
|
-
* {event.action}: {event.data?.key}
|
|
27
|
-
* </Text>
|
|
28
|
-
* ))}
|
|
29
|
-
* </View>
|
|
30
|
-
* );
|
|
31
|
-
* }
|
|
32
|
-
* ```
|
|
33
|
-
*/
|
|
34
|
-
|
|
35
|
-
// Re-export StorageEvent for convenience
|
|
36
|
-
|
|
37
|
-
function useStorageEvents(options = {}) {
|
|
38
|
-
const {
|
|
39
|
-
storageType = "all",
|
|
40
|
-
maxEvents = 500,
|
|
41
|
-
enabled = true
|
|
42
|
-
} = options;
|
|
43
|
-
// Stable per storageType so the shared hook doesn't resubscribe every render.
|
|
44
|
-
const select = (0, _react.useMemo)(() => storageType === "all" ? undefined : events => events.filter(e => e.storageType === storageType), [storageType]);
|
|
45
|
-
// Subscribing auto-starts the storage listener (Subscribable pattern), and
|
|
46
|
-
// the shared hook frame-coalesces write bursts into one commit.
|
|
47
|
-
const {
|
|
48
|
-
events,
|
|
49
|
-
clearEvents,
|
|
50
|
-
isActive
|
|
51
|
-
} = (0, _sharedUi.useEventStoreEvents)(_storageEventStore.storageEventStore, {
|
|
52
|
-
maxEvents,
|
|
53
|
-
enabled,
|
|
54
|
-
select
|
|
55
|
-
});
|
|
56
|
-
return {
|
|
57
|
-
events,
|
|
58
|
-
clearEvents,
|
|
59
|
-
isCapturing: isActive
|
|
60
|
-
};
|
|
61
|
-
}
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.useStorageEvents=useStorageEvents;var _react=require("react");var _sharedUi=require("@buoy-gg/shared-ui");var _storageEventStore=require("../stores/storageEventStore");function useStorageEvents(t={}){const{storageType:e="all",maxEvents:r=500,enabled:s=true}=t;const o=(0,_react.useMemo)(()=>e==="all"?void 0:v=>v.filter(i=>i.storageType===e),[e]);const{events:a,clearEvents:n,isActive:u}=(0,_sharedUi.useEventStoreEvents)(_storageEventStore.storageEventStore,{maxEvents:r,enabled:s,select:o});return{events:a,clearEvents:n,isCapturing:u}}
|
|
@@ -1,312 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.batchPairsOf = batchPairsOf;
|
|
7
|
-
exports.isStorageCapturing = exports.getStorageEvents = exports.clearStorageEvents = void 0;
|
|
8
|
-
exports.isValueOnDevice = isValueOnDevice;
|
|
9
|
-
exports.subscribeToStorageEvents = exports.storageEventStore = exports.onStorageEvent = void 0;
|
|
10
|
-
var _sharedUi = require("@buoy-gg/shared-ui");
|
|
11
|
-
var _AsyncStorageListener = require("../utils/AsyncStorageListener");
|
|
12
|
-
var _MMKVListener = require("../utils/MMKVListener");
|
|
13
|
-
var _MMKVInstanceRegistry = require("../utils/MMKVInstanceRegistry");
|
|
14
|
-
var _mmkvTypeDetection = require("../utils/mmkvTypeDetection");
|
|
15
|
-
/**
|
|
16
|
-
* Storage Event Store
|
|
17
|
-
*
|
|
18
|
-
* Centralized store that aggregates storage events from AsyncStorage and MMKV
|
|
19
|
-
* into a single event stream. Uses BaseEventStore pattern - the storage listener
|
|
20
|
-
* automatically starts when the first subscriber joins and stops when the last
|
|
21
|
-
* subscriber leaves.
|
|
22
|
-
*
|
|
23
|
-
* @example
|
|
24
|
-
* ```typescript
|
|
25
|
-
* import { storageEventStore } from '@buoy-gg/storage';
|
|
26
|
-
*
|
|
27
|
-
* // Subscribe to storage events - automatically starts capturing!
|
|
28
|
-
* const unsubscribe = storageEventStore.subscribeToEvents((events) => {
|
|
29
|
-
* console.log('Storage events:', events);
|
|
30
|
-
* });
|
|
31
|
-
*
|
|
32
|
-
* // Later, clean up - automatically stops if no other subscribers
|
|
33
|
-
* unsubscribe();
|
|
34
|
-
* ```
|
|
35
|
-
*/
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Unified storage event type combining AsyncStorage and MMKV events.
|
|
39
|
-
* `id` is assigned by the store when the event enters — needed because raw
|
|
40
|
-
* events have no unique identifier (rapid same-key writes can share a
|
|
41
|
-
* millisecond timestamp), and React keys must be unique per render.
|
|
42
|
-
*/
|
|
43
|
-
|
|
44
|
-
/** True when a field is the wire-form VALUE_ON_DEVICE marker. */
|
|
45
|
-
function isValueOnDevice(value) {
|
|
46
|
-
return !!value && typeof value === "object" && value.__buoyValueOnDevice === true;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* `pairs` / `prevPairs` are AsyncStorage-only — they carry the batch
|
|
51
|
-
* operations (multiSet / multiRemove / multiMerge / clear), and MMKV has no
|
|
52
|
-
* batch API, so its `data` has no such fields. Reading them off the
|
|
53
|
-
* `StorageEvent` union needs narrowing, and this is the one place that does
|
|
54
|
-
* it; writing them unconditionally would also graft meaningless keys onto
|
|
55
|
-
* every MMKV event on the wire.
|
|
56
|
-
*/
|
|
57
|
-
function batchPairsOf(event) {
|
|
58
|
-
if (event.storageType !== "async" || !event.data) return {};
|
|
59
|
-
return {
|
|
60
|
-
pairs: event.data.pairs,
|
|
61
|
-
prevPairs: event.data.prevPairs
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
function eventHasOnDeviceValues(event) {
|
|
65
|
-
const data = event.data;
|
|
66
|
-
if (!data) return false;
|
|
67
|
-
const {
|
|
68
|
-
pairs,
|
|
69
|
-
prevPairs
|
|
70
|
-
} = batchPairsOf(event);
|
|
71
|
-
return isValueOnDevice(data.value) || isValueOnDevice(data.prevValue) || isValueOnDevice(pairs) || isValueOnDevice(prevPairs);
|
|
72
|
-
}
|
|
73
|
-
let storageEventIdCounter = 0;
|
|
74
|
-
function nextStorageEventId() {
|
|
75
|
-
return `se-${Date.now()}-${++storageEventIdCounter}`;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Listener callback type for storage events array
|
|
80
|
-
*/
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Listener callback for individual new events
|
|
84
|
-
*/
|
|
85
|
-
|
|
86
|
-
class StorageEventStore extends _sharedUi.BaseEventStore {
|
|
87
|
-
// Unsubscribe functions for raw listeners
|
|
88
|
-
asyncStorageUnsubscribe = null;
|
|
89
|
-
mmkvUnsubscribe = null;
|
|
90
|
-
hasScannedInitialState = false;
|
|
91
|
-
constructor() {
|
|
92
|
-
super({
|
|
93
|
-
storeName: "storage",
|
|
94
|
-
maxEvents: 500
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Scan all registered MMKV instances and AsyncStorage for existing keys,
|
|
100
|
-
* creating synthetic events so that getEvents() includes the current state
|
|
101
|
-
* (not just changes made after capture started). Only runs once per store
|
|
102
|
-
* lifetime to avoid duplicates.
|
|
103
|
-
*/
|
|
104
|
-
async scanExistingState() {
|
|
105
|
-
if (this.hasScannedInitialState) return;
|
|
106
|
-
this.hasScannedInitialState = true;
|
|
107
|
-
const now = new Date();
|
|
108
|
-
|
|
109
|
-
// ── MMKV: synchronous scan ──
|
|
110
|
-
const instances = _MMKVInstanceRegistry.mmkvInstanceRegistry.getAll();
|
|
111
|
-
for (const {
|
|
112
|
-
id: instanceId,
|
|
113
|
-
instance
|
|
114
|
-
} of instances) {
|
|
115
|
-
try {
|
|
116
|
-
const keys = instance.getAllKeys();
|
|
117
|
-
for (const key of keys) {
|
|
118
|
-
const {
|
|
119
|
-
value,
|
|
120
|
-
type: valueType
|
|
121
|
-
} = (0, _mmkvTypeDetection.detectMMKVType)(instance, key);
|
|
122
|
-
const actionMap = {
|
|
123
|
-
string: "set.string",
|
|
124
|
-
number: "set.number",
|
|
125
|
-
boolean: "set.boolean",
|
|
126
|
-
buffer: "set.buffer"
|
|
127
|
-
};
|
|
128
|
-
const action = actionMap[valueType] ?? "set.string";
|
|
129
|
-
this.addEvent({
|
|
130
|
-
action,
|
|
131
|
-
timestamp: now,
|
|
132
|
-
instanceId,
|
|
133
|
-
data: {
|
|
134
|
-
key,
|
|
135
|
-
value,
|
|
136
|
-
valueType,
|
|
137
|
-
initialScan: true
|
|
138
|
-
},
|
|
139
|
-
storageType: "mmkv",
|
|
140
|
-
id: nextStorageEventId()
|
|
141
|
-
});
|
|
142
|
-
}
|
|
143
|
-
} catch {
|
|
144
|
-
// Instance may not be accessible — skip silently
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
// ── AsyncStorage: async scan ──
|
|
149
|
-
try {
|
|
150
|
-
const {
|
|
151
|
-
asyncStorage,
|
|
152
|
-
readMany
|
|
153
|
-
} = require("../utils/asyncStorageCompat");
|
|
154
|
-
if (asyncStorage) {
|
|
155
|
-
const allKeys = await asyncStorage.getAllKeys();
|
|
156
|
-
if (allKeys.length > 0) {
|
|
157
|
-
const pairs = await readMany(allKeys);
|
|
158
|
-
for (const [key, rawValue] of pairs) {
|
|
159
|
-
this.addEvent({
|
|
160
|
-
action: "setItem",
|
|
161
|
-
timestamp: now,
|
|
162
|
-
data: {
|
|
163
|
-
key,
|
|
164
|
-
value: rawValue ?? undefined,
|
|
165
|
-
initialScan: true
|
|
166
|
-
},
|
|
167
|
-
storageType: "async",
|
|
168
|
-
id: nextStorageEventId()
|
|
169
|
-
});
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
} catch {
|
|
174
|
-
// AsyncStorage not available — skip silently
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
/**
|
|
179
|
-
* Start capturing storage events from both AsyncStorage and MMKV
|
|
180
|
-
*/
|
|
181
|
-
async startCapturing() {
|
|
182
|
-
// Start AsyncStorage listening if not already active
|
|
183
|
-
if (!(0, _AsyncStorageListener.isListening)()) {
|
|
184
|
-
await (0, _AsyncStorageListener.startListening)();
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
// Subscribe to AsyncStorage events
|
|
188
|
-
if (!this.asyncStorageUnsubscribe) {
|
|
189
|
-
this.asyncStorageUnsubscribe = (0, _AsyncStorageListener.addListener)(event => {
|
|
190
|
-
const storageEvent = {
|
|
191
|
-
...event,
|
|
192
|
-
storageType: "async",
|
|
193
|
-
id: nextStorageEventId()
|
|
194
|
-
};
|
|
195
|
-
this.addEvent(storageEvent);
|
|
196
|
-
});
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
// Subscribe to MMKV events
|
|
200
|
-
if (!this.mmkvUnsubscribe) {
|
|
201
|
-
this.mmkvUnsubscribe = (0, _MMKVListener.addMMKVListener)(event => {
|
|
202
|
-
const storageEvent = {
|
|
203
|
-
...event,
|
|
204
|
-
storageType: "mmkv",
|
|
205
|
-
id: nextStorageEventId()
|
|
206
|
-
};
|
|
207
|
-
this.addEvent(storageEvent);
|
|
208
|
-
});
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
// Scan existing keys so getEvents() includes pre-existing state
|
|
212
|
-
await this.scanExistingState();
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
/**
|
|
216
|
-
* Stop capturing storage events
|
|
217
|
-
*/
|
|
218
|
-
stopCapturing() {
|
|
219
|
-
// Unsubscribe from AsyncStorage
|
|
220
|
-
if (this.asyncStorageUnsubscribe) {
|
|
221
|
-
this.asyncStorageUnsubscribe();
|
|
222
|
-
this.asyncStorageUnsubscribe = null;
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
// Unsubscribe from MMKV
|
|
226
|
-
if (this.mmkvUnsubscribe) {
|
|
227
|
-
this.mmkvUnsubscribe();
|
|
228
|
-
this.mmkvUnsubscribe = null;
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
/**
|
|
233
|
-
* Check if currently capturing events (has subscribers)
|
|
234
|
-
*/
|
|
235
|
-
isCapturing() {
|
|
236
|
-
return this.asyncStorageUnsubscribe !== null || this.mmkvUnsubscribe !== null;
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
/**
|
|
240
|
-
* Get events filtered by storage type
|
|
241
|
-
*/
|
|
242
|
-
getEventsByType(storageType) {
|
|
243
|
-
return this.events.filter(event => event.storageType === storageType);
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
/**
|
|
247
|
-
* Replace the event list, keeping values a remote mirror already hydrated.
|
|
248
|
-
* Wire-form snapshots always carry VALUE_ON_DEVICE markers for oversized
|
|
249
|
-
* payloads; a later snapshot must not blank the detail pane (or wipe
|
|
250
|
-
* `prevValue` that time-travel undo needs).
|
|
251
|
-
*/
|
|
252
|
-
replaceEvents(events) {
|
|
253
|
-
const hydrated = new Map();
|
|
254
|
-
for (const existing of this.events) {
|
|
255
|
-
if (!eventHasOnDeviceValues(existing)) {
|
|
256
|
-
hydrated.set(existing.id, existing);
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
const merged = events.map(incoming => {
|
|
260
|
-
const kept = hydrated.get(incoming.id);
|
|
261
|
-
if (!kept || !eventHasOnDeviceValues(incoming)) return incoming;
|
|
262
|
-
// Restore only the fields this event's storage type actually has, so an
|
|
263
|
-
// MMKV event never grows `pairs`/`prevPairs` it has no meaning for.
|
|
264
|
-
return {
|
|
265
|
-
...incoming,
|
|
266
|
-
data: {
|
|
267
|
-
...incoming.data,
|
|
268
|
-
value: kept.data?.value,
|
|
269
|
-
prevValue: kept.data?.prevValue,
|
|
270
|
-
...batchPairsOf(kept)
|
|
271
|
-
}
|
|
272
|
-
};
|
|
273
|
-
});
|
|
274
|
-
super.replaceEvents(merged);
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
/**
|
|
278
|
-
* Hydrate one mirrored event with real values fetched on demand from the
|
|
279
|
-
* device via the adapter's `getEventDetail`. Remote-mirror (desktop) only.
|
|
280
|
-
*/
|
|
281
|
-
hydrateEvent(event) {
|
|
282
|
-
const index = this.events.findIndex(e => e.id === event.id);
|
|
283
|
-
if (index === -1) return;
|
|
284
|
-
const current = this.events[index];
|
|
285
|
-
const next = this.events.slice();
|
|
286
|
-
next[index] = {
|
|
287
|
-
...current,
|
|
288
|
-
...event,
|
|
289
|
-
timestamp: current.timestamp,
|
|
290
|
-
data: {
|
|
291
|
-
...current.data,
|
|
292
|
-
...event.data
|
|
293
|
-
}
|
|
294
|
-
};
|
|
295
|
-
super.replaceEvents(next);
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
// Singleton instance
|
|
300
|
-
const storageEventStore = exports.storageEventStore = new StorageEventStore();
|
|
301
|
-
|
|
302
|
-
// Convenience exports
|
|
303
|
-
const subscribeToStorageEvents = listener => storageEventStore.subscribeToEvents(listener);
|
|
304
|
-
exports.subscribeToStorageEvents = subscribeToStorageEvents;
|
|
305
|
-
const onStorageEvent = callback => storageEventStore.onEvent(callback);
|
|
306
|
-
exports.onStorageEvent = onStorageEvent;
|
|
307
|
-
const getStorageEvents = () => storageEventStore.getEvents();
|
|
308
|
-
exports.getStorageEvents = getStorageEvents;
|
|
309
|
-
const clearStorageEvents = () => storageEventStore.clearEvents();
|
|
310
|
-
exports.clearStorageEvents = clearStorageEvents;
|
|
311
|
-
const isStorageCapturing = () => storageEventStore.isCapturing();
|
|
312
|
-
exports.isStorageCapturing = isStorageCapturing;
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.batchPairsOf=batchPairsOf;exports.isStorageCapturing=exports.getStorageEvents=exports.clearStorageEvents=void 0;exports.isValueOnDevice=isValueOnDevice;exports.subscribeToStorageEvents=exports.storageEventStore=exports.onStorageEvent=void 0;var _sharedUi=require("@buoy-gg/shared-ui");var _AsyncStorageListener=require("../utils/AsyncStorageListener");var _MMKVListener=require("../utils/MMKVListener");var _MMKVInstanceRegistry=require("../utils/MMKVInstanceRegistry");var _mmkvTypeDetection=require("../utils/mmkvTypeDetection");function isValueOnDevice(s){return!!s&&typeof s==="object"&&s.__buoyValueOnDevice===true}function batchPairsOf(s){if(s.storageType!=="async"||!s.data)return{};return{pairs:s.data.pairs,prevPairs:s.data.prevPairs}}function eventHasOnDeviceValues(s){const e=s.data;if(!e)return false;const{pairs:a,prevPairs:n}=batchPairsOf(s);return isValueOnDevice(e.value)||isValueOnDevice(e.prevValue)||isValueOnDevice(a)||isValueOnDevice(n)}let storageEventIdCounter=0;function nextStorageEventId(){return`se-${Date.now()}-${++storageEventIdCounter}`}class StorageEventStore extends _sharedUi.BaseEventStore{asyncStorageUnsubscribe=null;mmkvUnsubscribe=null;hasScannedInitialState=false;constructor(){super({storeName:"storage",maxEvents:500})}async scanExistingState(){if(this.hasScannedInitialState)return;this.hasScannedInitialState=true;const e=new Date;const a=_MMKVInstanceRegistry.mmkvInstanceRegistry.getAll();for(const{id:n,instance:t}of a){try{const r=t.getAllKeys();for(const i of r){const{value:c,type:o}=(0,_mmkvTypeDetection.detectMMKVType)(t,i);const u={string:"set.string",number:"set.number",boolean:"set.boolean",buffer:"set.buffer"};const v=u[o]??"set.string";this.addEvent({action:v,timestamp:e,instanceId:n,data:{key:i,value:c,valueType:o,initialScan:true},storageType:"mmkv",id:nextStorageEventId()})}}catch{}}try{const{asyncStorage:n,readMany:t}=require("../utils/asyncStorageCompat");if(n){const r=await n.getAllKeys();if(r.length>0){const i=await t(r);for(const[c,o]of i){this.addEvent({action:"setItem",timestamp:e,data:{key:c,value:o??void 0,initialScan:true},storageType:"async",id:nextStorageEventId()})}}}}catch{}}async startCapturing(){if(!(0,_AsyncStorageListener.isListening)()){await(0,_AsyncStorageListener.startListening)()}if(!this.asyncStorageUnsubscribe){this.asyncStorageUnsubscribe=(0,_AsyncStorageListener.addListener)(e=>{const a={...e,storageType:"async",id:nextStorageEventId()};this.addEvent(a)})}if(!this.mmkvUnsubscribe){this.mmkvUnsubscribe=(0,_MMKVListener.addMMKVListener)(e=>{const a={...e,storageType:"mmkv",id:nextStorageEventId()};this.addEvent(a)})}await this.scanExistingState()}stopCapturing(){if(this.asyncStorageUnsubscribe){this.asyncStorageUnsubscribe();this.asyncStorageUnsubscribe=null}if(this.mmkvUnsubscribe){this.mmkvUnsubscribe();this.mmkvUnsubscribe=null}}isCapturing(){return this.asyncStorageUnsubscribe!==null||this.mmkvUnsubscribe!==null}getEventsByType(e){return this.events.filter(a=>a.storageType===e)}replaceEvents(e){const a=new Map;for(const t of this.events){if(!eventHasOnDeviceValues(t)){a.set(t.id,t)}}const n=e.map(t=>{const r=a.get(t.id);if(!r||!eventHasOnDeviceValues(t))return t;return{...t,data:{...t.data,value:r.data?.value,prevValue:r.data?.prevValue,...batchPairsOf(r)}}});super.replaceEvents(n)}hydrateEvent(e){const a=this.events.findIndex(r=>r.id===e.id);if(a===-1)return;const n=this.events[a];const t=this.events.slice();t[a]={...n,...e,timestamp:n.timestamp,data:{...n.data,...e.data}};super.replaceEvents(t)}}const storageEventStore=exports.storageEventStore=new StorageEventStore;const subscribeToStorageEvents=s=>storageEventStore.subscribeToEvents(s);exports.subscribeToStorageEvents=subscribeToStorageEvents;const onStorageEvent=s=>storageEventStore.onEvent(s);exports.onStorageEvent=onStorageEvent;const getStorageEvents=()=>storageEventStore.getEvents();exports.getStorageEvents=getStorageEvents;const clearStorageEvents=()=>storageEventStore.clearEvents();exports.clearStorageEvents=clearStorageEvents;const isStorageCapturing=()=>storageEventStore.isCapturing();exports.isStorageCapturing=isStorageCapturing;
|