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