@buoy-gg/storage 3.0.1 → 4.0.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/README.md +1 -1
- package/lib/commonjs/index.js +7 -0
- package/lib/commonjs/storage/components/GameUIStorageBrowser.js +25 -4
- package/lib/commonjs/storage/components/GameUIStorageStats.js +2 -2
- package/lib/commonjs/storage/components/SelectionActionBar.js +16 -3
- package/lib/commonjs/storage/components/StorageBrowserMode.js +6 -2
- package/lib/commonjs/storage/components/StorageEventDetailContent.js +2 -2
- package/lib/commonjs/storage/components/StorageKeyCard.js +5 -5
- package/lib/commonjs/storage/components/StorageKeyRow.js +97 -8
- package/lib/commonjs/storage/components/StorageKeySection.js +10 -4
- package/lib/commonjs/storage/components/StorageModalWithTabs.js +47 -1
- package/lib/commonjs/storage/hooks/useAsyncStorageKeys.js +15 -3
- package/lib/commonjs/storage/hooks/useMMKVKeys.js +20 -2
- package/lib/commonjs/storage/stores/storageEventStore.js +84 -0
- package/lib/commonjs/storage/sync/storageSyncAdapter.js +53 -0
- package/lib/commonjs/storage/utils/AsyncStorageListener.js +148 -160
- package/lib/commonjs/storage/utils/asyncStorageCompat.js +89 -0
- package/lib/commonjs/storage/utils/clearAllStorage.js +2 -1
- package/lib/commonjs/storage/utils/mmkvTypeDetection.js +20 -5
- package/lib/commonjs/storage/utils/storageTimeTravelUtils.js +3 -2
- package/lib/commonjs/storage/utils/valueType.js +41 -0
- package/lib/module/index.js +5 -0
- package/lib/module/storage/components/GameUIStorageBrowser.js +26 -4
- package/lib/module/storage/components/GameUIStorageStats.js +3 -2
- package/lib/module/storage/components/SelectionActionBar.js +17 -3
- package/lib/module/storage/components/StorageBrowserMode.js +6 -2
- package/lib/module/storage/components/StorageEventDetailContent.js +2 -2
- package/lib/module/storage/components/StorageKeyCard.js +5 -5
- package/lib/module/storage/components/StorageKeyRow.js +99 -10
- package/lib/module/storage/components/StorageKeySection.js +10 -4
- package/lib/module/storage/components/StorageModalWithTabs.js +47 -1
- package/lib/module/storage/hooks/useAsyncStorageKeys.js +16 -4
- package/lib/module/storage/hooks/useMMKVKeys.js +21 -3
- package/lib/module/storage/stores/storageEventStore.js +84 -0
- package/lib/module/storage/sync/storageSyncAdapter.js +48 -0
- package/lib/module/storage/utils/AsyncStorageListener.js +124 -135
- package/lib/module/storage/utils/asyncStorageCompat.js +81 -0
- package/lib/module/storage/utils/clearAllStorage.js +2 -1
- package/lib/module/storage/utils/mmkvTypeDetection.js +20 -5
- package/lib/module/storage/utils/storageTimeTravelUtils.js +3 -2
- package/lib/module/storage/utils/valueType.js +39 -0
- package/lib/typescript/index.d.ts +1 -0
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/storage/components/GameUIStorageBrowser.d.ts +5 -1
- package/lib/typescript/storage/components/GameUIStorageBrowser.d.ts.map +1 -1
- package/lib/typescript/storage/components/GameUIStorageStats.d.ts.map +1 -1
- package/lib/typescript/storage/components/SelectionActionBar.d.ts +3 -1
- package/lib/typescript/storage/components/SelectionActionBar.d.ts.map +1 -1
- package/lib/typescript/storage/components/StorageBrowserMode.d.ts +3 -1
- package/lib/typescript/storage/components/StorageBrowserMode.d.ts.map +1 -1
- package/lib/typescript/storage/components/StorageKeyRow.d.ts +7 -1
- package/lib/typescript/storage/components/StorageKeyRow.d.ts.map +1 -1
- package/lib/typescript/storage/components/StorageKeySection.d.ts +7 -1
- package/lib/typescript/storage/components/StorageKeySection.d.ts.map +1 -1
- package/lib/typescript/storage/components/StorageModalWithTabs.d.ts.map +1 -1
- package/lib/typescript/storage/hooks/useAsyncStorageKeys.d.ts.map +1 -1
- package/lib/typescript/storage/hooks/useMMKVKeys.d.ts.map +1 -1
- package/lib/typescript/storage/stores/storageEventStore.d.ts +8 -0
- package/lib/typescript/storage/stores/storageEventStore.d.ts.map +1 -1
- package/lib/typescript/storage/sync/storageSyncAdapter.d.ts +31 -0
- package/lib/typescript/storage/sync/storageSyncAdapter.d.ts.map +1 -0
- package/lib/typescript/storage/utils/AsyncStorageListener.d.ts +20 -0
- package/lib/typescript/storage/utils/AsyncStorageListener.d.ts.map +1 -1
- package/lib/typescript/storage/utils/asyncStorageCompat.d.ts +30 -0
- package/lib/typescript/storage/utils/asyncStorageCompat.d.ts.map +1 -0
- package/lib/typescript/storage/utils/clearAllStorage.d.ts.map +1 -1
- package/lib/typescript/storage/utils/mmkvTypeDetection.d.ts.map +1 -1
- package/lib/typescript/storage/utils/storageTimeTravelUtils.d.ts.map +1 -1
- package/lib/typescript/storage/utils/valueType.d.ts +13 -0
- package/lib/typescript/storage/utils/valueType.d.ts.map +1 -1
- package/package.json +6 -6
|
@@ -23,7 +23,10 @@ export function StorageKeySection({
|
|
|
23
23
|
selectedKeys = new Set(),
|
|
24
24
|
onSelectionChange,
|
|
25
25
|
eventCountByKey,
|
|
26
|
-
onViewHistory
|
|
26
|
+
onViewHistory,
|
|
27
|
+
onHideKey,
|
|
28
|
+
pinnedKeys,
|
|
29
|
+
onTogglePin
|
|
27
30
|
}) {
|
|
28
31
|
const [expandedKey, setExpandedKey] = useState(null);
|
|
29
32
|
const handleKeyPress = useCallback(storageKey => {
|
|
@@ -56,14 +59,14 @@ export function StorageKeySection({
|
|
|
56
59
|
if (keys.length === 0) return null;
|
|
57
60
|
return /*#__PURE__*/_jsxs(View, {
|
|
58
61
|
style: styles.sectionContainer,
|
|
59
|
-
children: [title
|
|
62
|
+
children: [title ? /*#__PURE__*/_jsxs(SectionHeader, {
|
|
60
63
|
children: [/*#__PURE__*/_jsx(SectionHeader.Title, {
|
|
61
64
|
children: title
|
|
62
65
|
}), count >= 0 && /*#__PURE__*/_jsx(SectionHeader.Badge, {
|
|
63
66
|
count: count,
|
|
64
67
|
color: headerColor
|
|
65
68
|
})]
|
|
66
|
-
}), /*#__PURE__*/_jsx(View, {
|
|
69
|
+
}) : null, /*#__PURE__*/_jsx(View, {
|
|
67
70
|
style: styles.sectionContent,
|
|
68
71
|
children: keys.map(storageKey => {
|
|
69
72
|
// Create unique key by combining storage type, instance ID (if present), and key name
|
|
@@ -76,7 +79,10 @@ export function StorageKeySection({
|
|
|
76
79
|
isSelected: selectedKeys.has(uniqueKey),
|
|
77
80
|
onSelectionChange: onSelectionChange,
|
|
78
81
|
eventCount: eventCountByKey?.[storageKey.key],
|
|
79
|
-
onViewHistory: onViewHistory ? () => onViewHistory(storageKey.key) : undefined
|
|
82
|
+
onViewHistory: onViewHistory ? () => onViewHistory(storageKey.key) : undefined,
|
|
83
|
+
onHideKey: onHideKey,
|
|
84
|
+
isPinned: pinnedKeys?.has(storageKey.key),
|
|
85
|
+
onTogglePin: onTogglePin
|
|
80
86
|
}, uniqueKey);
|
|
81
87
|
})
|
|
82
88
|
})]
|
|
@@ -56,8 +56,10 @@ export function StorageModalWithTabs({
|
|
|
56
56
|
);
|
|
57
57
|
const [enabledStorageTypes, setEnabledStorageTypes] = useState(new Set(['async', 'mmkv', 'secure']) // All enabled by default
|
|
58
58
|
);
|
|
59
|
+
const [pinnedKeys, setPinnedKeys] = useState(new Set());
|
|
59
60
|
const lastEventRef = useRef(null);
|
|
60
61
|
const hasLoadedFilters = useRef(false);
|
|
62
|
+
const hasLoadedPins = useRef(false);
|
|
61
63
|
const hasLoadedTabState = useRef(false);
|
|
62
64
|
const hasLoadedMonitoringState = useRef(false);
|
|
63
65
|
|
|
@@ -172,6 +174,37 @@ export function StorageModalWithTabs({
|
|
|
172
174
|
saveFilters();
|
|
173
175
|
}, [ignoredPatterns]);
|
|
174
176
|
|
|
177
|
+
// Load persisted pinned keys on mount
|
|
178
|
+
useEffect(() => {
|
|
179
|
+
if (!visible || hasLoadedPins.current) return;
|
|
180
|
+
const loadPins = async () => {
|
|
181
|
+
try {
|
|
182
|
+
const stored = await AsyncStorage.getItem(devToolsStorageKeys.storage.pinnedKeys());
|
|
183
|
+
if (stored) {
|
|
184
|
+
setPinnedKeys(new Set(JSON.parse(stored)));
|
|
185
|
+
}
|
|
186
|
+
hasLoadedPins.current = true;
|
|
187
|
+
} catch (error) {
|
|
188
|
+
// Failed to load pinned keys
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
loadPins();
|
|
192
|
+
}, [visible]);
|
|
193
|
+
|
|
194
|
+
// Save pinned keys when they change
|
|
195
|
+
useEffect(() => {
|
|
196
|
+
if (!hasLoadedPins.current) return; // Don't save on initial load
|
|
197
|
+
|
|
198
|
+
const savePins = async () => {
|
|
199
|
+
try {
|
|
200
|
+
await AsyncStorage.setItem(devToolsStorageKeys.storage.pinnedKeys(), JSON.stringify(Array.from(pinnedKeys)));
|
|
201
|
+
} catch (error) {
|
|
202
|
+
// Failed to save pinned keys
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
savePins();
|
|
206
|
+
}, [pinnedKeys]);
|
|
207
|
+
|
|
175
208
|
// Event listener setup - now handled by useStorageEvents hook
|
|
176
209
|
// The hook subscribes to the centralized storageEventStore
|
|
177
210
|
|
|
@@ -206,6 +239,17 @@ export function StorageModalWithTabs({
|
|
|
206
239
|
const handleAddPattern = useCallback(pattern => {
|
|
207
240
|
setIgnoredPatterns(prev => new Set([...prev, pattern]));
|
|
208
241
|
}, []);
|
|
242
|
+
const handleTogglePin = useCallback(key => {
|
|
243
|
+
setPinnedKeys(prev => {
|
|
244
|
+
const next = new Set(prev);
|
|
245
|
+
if (next.has(key)) {
|
|
246
|
+
next.delete(key);
|
|
247
|
+
} else {
|
|
248
|
+
next.add(key);
|
|
249
|
+
}
|
|
250
|
+
return next;
|
|
251
|
+
});
|
|
252
|
+
}, []);
|
|
209
253
|
const handleToggleFilters = useCallback(() => {
|
|
210
254
|
setShowFilters(!showFilters);
|
|
211
255
|
}, [showFilters]);
|
|
@@ -504,7 +548,9 @@ export function StorageModalWithTabs({
|
|
|
504
548
|
storageDataRef: storageDataRef,
|
|
505
549
|
eventCountByKey: eventCountByKey,
|
|
506
550
|
onViewHistory: handleViewHistoryFromBrowser,
|
|
507
|
-
enabledStorageTypes: enabledStorageTypes
|
|
551
|
+
enabledStorageTypes: enabledStorageTypes,
|
|
552
|
+
pinnedKeys: pinnedKeys,
|
|
553
|
+
onTogglePin: handleTogglePin
|
|
508
554
|
});
|
|
509
555
|
}
|
|
510
556
|
|
|
@@ -1,15 +1,26 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
import { useState, useEffect, useCallback } from 'react';
|
|
3
|
+
import { useState, useEffect, useCallback, useRef } from 'react';
|
|
4
4
|
import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
5
|
+
import { readMany } from '../utils/asyncStorageCompat';
|
|
5
6
|
export function useAsyncStorageKeys(requiredStorageKeys = []) {
|
|
6
7
|
// State management
|
|
7
8
|
const [storageKeys, setStorageKeys] = useState([]);
|
|
8
9
|
const [isLoading, setIsLoading] = useState(true);
|
|
9
10
|
const [error, setError] = useState(null);
|
|
10
11
|
|
|
12
|
+
// Callers routinely pass a fresh array literal (or rely on the `= []`
|
|
13
|
+
// default, which is a new array every render). Depending on its identity
|
|
14
|
+
// would recreate `fetchStorageData` each render, re-fire the effect, and
|
|
15
|
+
// loop AsyncStorage.getAllKeys/multiGet forever. Depend on a stable content
|
|
16
|
+
// signature instead, and read the latest array via a ref inside the fetch.
|
|
17
|
+
const requiredSignature = JSON.stringify(requiredStorageKeys);
|
|
18
|
+
const requiredRef = useRef(requiredStorageKeys);
|
|
19
|
+
requiredRef.current = requiredStorageKeys;
|
|
20
|
+
|
|
11
21
|
// Fetch all keys and values from AsyncStorage
|
|
12
22
|
const fetchStorageData = useCallback(async () => {
|
|
23
|
+
const requiredStorageKeys = requiredRef.current;
|
|
13
24
|
setIsLoading(true);
|
|
14
25
|
setError(null);
|
|
15
26
|
try {
|
|
@@ -21,8 +32,8 @@ export function useAsyncStorageKeys(requiredStorageKeys = []) {
|
|
|
21
32
|
return;
|
|
22
33
|
}
|
|
23
34
|
|
|
24
|
-
// 2. Get all values
|
|
25
|
-
const allKeyValuePairs = await
|
|
35
|
+
// 2. Get all values (compat helper normalizes v2 multiGet / v3 getMany)
|
|
36
|
+
const allKeyValuePairs = await readMany(allKeys);
|
|
26
37
|
|
|
27
38
|
// 3. Process keys into StorageKeyInfo format
|
|
28
39
|
const allStorageKeys = [];
|
|
@@ -106,7 +117,8 @@ export function useAsyncStorageKeys(requiredStorageKeys = []) {
|
|
|
106
117
|
} finally {
|
|
107
118
|
setIsLoading(false);
|
|
108
119
|
}
|
|
109
|
-
|
|
120
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
121
|
+
}, [requiredSignature]);
|
|
110
122
|
|
|
111
123
|
// Initial fetch
|
|
112
124
|
useEffect(() => {
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* - No multiGet - must fetch keys individually
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
-
import { useState, useEffect, useCallback } from 'react';
|
|
16
|
+
import { useState, useEffect, useCallback, useRef } from 'react';
|
|
17
17
|
import { isMMKVAvailable } from '../utils/mmkvAvailability';
|
|
18
18
|
|
|
19
19
|
// Conditionally import MMKV types
|
|
@@ -73,8 +73,16 @@ export function useMMKVKeys(instance, instanceId, requiredStorageKeys = []) {
|
|
|
73
73
|
const [isLoading, setIsLoading] = useState(true);
|
|
74
74
|
const [error, setError] = useState(null);
|
|
75
75
|
|
|
76
|
+
// Depend on a stable content signature rather than the array identity — a
|
|
77
|
+
// fresh `requiredStorageKeys` literal each render would otherwise loop the
|
|
78
|
+
// fetch effect. Read the latest array via ref inside the fetch.
|
|
79
|
+
const requiredSignature = JSON.stringify(requiredStorageKeys);
|
|
80
|
+
const requiredRef = useRef(requiredStorageKeys);
|
|
81
|
+
requiredRef.current = requiredStorageKeys;
|
|
82
|
+
|
|
76
83
|
// Fetch all keys and values from MMKV instance
|
|
77
84
|
const fetchStorageData = useCallback(() => {
|
|
85
|
+
const requiredStorageKeys = requiredRef.current;
|
|
78
86
|
setIsLoading(true);
|
|
79
87
|
setError(null);
|
|
80
88
|
try {
|
|
@@ -206,7 +214,8 @@ export function useMMKVKeys(instance, instanceId, requiredStorageKeys = []) {
|
|
|
206
214
|
} finally {
|
|
207
215
|
setIsLoading(false);
|
|
208
216
|
}
|
|
209
|
-
|
|
217
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
218
|
+
}, [instance, instanceId, requiredSignature]);
|
|
210
219
|
|
|
211
220
|
// Initial fetch
|
|
212
221
|
useEffect(() => {
|
|
@@ -252,7 +261,15 @@ export function useMultiMMKVKeys(instances, requiredStorageKeys = []) {
|
|
|
252
261
|
const [storageKeys, setStorageKeys] = useState([]);
|
|
253
262
|
const [isLoading, setIsLoading] = useState(true);
|
|
254
263
|
const [error, setError] = useState(null);
|
|
264
|
+
|
|
265
|
+
// Depend on a stable content signature rather than the array identity — a
|
|
266
|
+
// fresh `requiredStorageKeys` literal each render would otherwise loop the
|
|
267
|
+
// fetch effect. Read the latest array via ref inside the fetch.
|
|
268
|
+
const requiredSignature = JSON.stringify(requiredStorageKeys);
|
|
269
|
+
const requiredRef = useRef(requiredStorageKeys);
|
|
270
|
+
requiredRef.current = requiredStorageKeys;
|
|
255
271
|
const fetchStorageData = useCallback(() => {
|
|
272
|
+
const requiredStorageKeys = requiredRef.current;
|
|
256
273
|
setIsLoading(true);
|
|
257
274
|
setError(null);
|
|
258
275
|
try {
|
|
@@ -346,7 +363,8 @@ export function useMultiMMKVKeys(instances, requiredStorageKeys = []) {
|
|
|
346
363
|
} finally {
|
|
347
364
|
setIsLoading(false);
|
|
348
365
|
}
|
|
349
|
-
|
|
366
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
367
|
+
}, [instances, requiredSignature]);
|
|
350
368
|
useEffect(() => {
|
|
351
369
|
fetchStorageData();
|
|
352
370
|
}, [fetchStorageData]);
|
|
@@ -25,6 +25,8 @@
|
|
|
25
25
|
import { BaseEventStore } from "@buoy-gg/shared-ui";
|
|
26
26
|
import { startListening as startAsyncStorageListening, addListener as addAsyncStorageListener, isListening as isAsyncStorageListening } from "../utils/AsyncStorageListener";
|
|
27
27
|
import { addMMKVListener } from "../utils/MMKVListener";
|
|
28
|
+
import { mmkvInstanceRegistry } from "../utils/MMKVInstanceRegistry";
|
|
29
|
+
import { detectMMKVType } from "../utils/mmkvTypeDetection";
|
|
28
30
|
|
|
29
31
|
/**
|
|
30
32
|
* Unified storage event type combining AsyncStorage and MMKV events.
|
|
@@ -50,6 +52,7 @@ class StorageEventStore extends BaseEventStore {
|
|
|
50
52
|
// Unsubscribe functions for raw listeners
|
|
51
53
|
asyncStorageUnsubscribe = null;
|
|
52
54
|
mmkvUnsubscribe = null;
|
|
55
|
+
hasScannedInitialState = false;
|
|
53
56
|
constructor() {
|
|
54
57
|
super({
|
|
55
58
|
storeName: "storage",
|
|
@@ -57,6 +60,84 @@ class StorageEventStore extends BaseEventStore {
|
|
|
57
60
|
});
|
|
58
61
|
}
|
|
59
62
|
|
|
63
|
+
/**
|
|
64
|
+
* Scan all registered MMKV instances and AsyncStorage for existing keys,
|
|
65
|
+
* creating synthetic events so that getEvents() includes the current state
|
|
66
|
+
* (not just changes made after capture started). Only runs once per store
|
|
67
|
+
* lifetime to avoid duplicates.
|
|
68
|
+
*/
|
|
69
|
+
async scanExistingState() {
|
|
70
|
+
if (this.hasScannedInitialState) return;
|
|
71
|
+
this.hasScannedInitialState = true;
|
|
72
|
+
const now = new Date();
|
|
73
|
+
|
|
74
|
+
// ── MMKV: synchronous scan ──
|
|
75
|
+
const instances = mmkvInstanceRegistry.getAll();
|
|
76
|
+
for (const {
|
|
77
|
+
id: instanceId,
|
|
78
|
+
instance
|
|
79
|
+
} of instances) {
|
|
80
|
+
try {
|
|
81
|
+
const keys = instance.getAllKeys();
|
|
82
|
+
for (const key of keys) {
|
|
83
|
+
const {
|
|
84
|
+
value,
|
|
85
|
+
type: valueType
|
|
86
|
+
} = detectMMKVType(instance, key);
|
|
87
|
+
const actionMap = {
|
|
88
|
+
string: "set.string",
|
|
89
|
+
number: "set.number",
|
|
90
|
+
boolean: "set.boolean",
|
|
91
|
+
buffer: "set.buffer"
|
|
92
|
+
};
|
|
93
|
+
const action = actionMap[valueType] ?? "set.string";
|
|
94
|
+
this.addEvent({
|
|
95
|
+
action,
|
|
96
|
+
timestamp: now,
|
|
97
|
+
instanceId,
|
|
98
|
+
data: {
|
|
99
|
+
key,
|
|
100
|
+
value,
|
|
101
|
+
valueType
|
|
102
|
+
},
|
|
103
|
+
storageType: "mmkv",
|
|
104
|
+
id: nextStorageEventId()
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
} catch {
|
|
108
|
+
// Instance may not be accessible — skip silently
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// ── AsyncStorage: async scan ──
|
|
113
|
+
try {
|
|
114
|
+
const {
|
|
115
|
+
asyncStorage,
|
|
116
|
+
readMany
|
|
117
|
+
} = require("../utils/asyncStorageCompat");
|
|
118
|
+
if (asyncStorage) {
|
|
119
|
+
const allKeys = await asyncStorage.getAllKeys();
|
|
120
|
+
if (allKeys.length > 0) {
|
|
121
|
+
const pairs = await readMany(allKeys);
|
|
122
|
+
for (const [key, rawValue] of pairs) {
|
|
123
|
+
this.addEvent({
|
|
124
|
+
action: "setItem",
|
|
125
|
+
timestamp: now,
|
|
126
|
+
data: {
|
|
127
|
+
key,
|
|
128
|
+
value: rawValue ?? undefined
|
|
129
|
+
},
|
|
130
|
+
storageType: "async",
|
|
131
|
+
id: nextStorageEventId()
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
} catch {
|
|
137
|
+
// AsyncStorage not available — skip silently
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
60
141
|
/**
|
|
61
142
|
* Start capturing storage events from both AsyncStorage and MMKV
|
|
62
143
|
*/
|
|
@@ -89,6 +170,9 @@ class StorageEventStore extends BaseEventStore {
|
|
|
89
170
|
this.addEvent(storageEvent);
|
|
90
171
|
});
|
|
91
172
|
}
|
|
173
|
+
|
|
174
|
+
// Scan existing keys so getEvents() includes pre-existing state
|
|
175
|
+
await this.scanExistingState();
|
|
92
176
|
}
|
|
93
177
|
|
|
94
178
|
/**
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import AsyncStorage from "@react-native-async-storage/async-storage";
|
|
4
|
+
import { readMany, writeMany, removeMany } from "../utils/asyncStorageCompat";
|
|
5
|
+
import { storageEventStore } from "../stores/storageEventStore";
|
|
6
|
+
import { clearAllAppStorage } from "../utils/clearAllStorage";
|
|
7
|
+
/**
|
|
8
|
+
* Sync adapter for the storage tool, consumed by @buoy-gg/external-sync's
|
|
9
|
+
* `useExternalSync` (structurally matches its ToolSyncAdapter interface so
|
|
10
|
+
* this package doesn't need a dependency on it).
|
|
11
|
+
*
|
|
12
|
+
* Subscribing starts the underlying capture lifecycle (including the initial
|
|
13
|
+
* key scan), so storage events are only recorded while a dashboard is
|
|
14
|
+
* watching.
|
|
15
|
+
*
|
|
16
|
+
* The `async.*` actions mirror the AsyncStorage API so the desktop dashboard
|
|
17
|
+
* can proxy its browse/edit mode against the device's real storage.
|
|
18
|
+
*/
|
|
19
|
+
export const storageSyncAdapter = {
|
|
20
|
+
version: 1,
|
|
21
|
+
getSnapshot: () => storageEventStore.getEvents(),
|
|
22
|
+
subscribe: onChange => storageEventStore.subscribeToEvents(onChange),
|
|
23
|
+
actions: {
|
|
24
|
+
clearEvents: () => {
|
|
25
|
+
storageEventStore.clearEvents();
|
|
26
|
+
},
|
|
27
|
+
/** Clears all app storage keys, preserving dev tools settings. */
|
|
28
|
+
clearAppStorage: () => clearAllAppStorage(),
|
|
29
|
+
// ── Remote AsyncStorage proxy (desktop browse/edit mode) ──
|
|
30
|
+
// Single-item methods share the same signature across async-storage v2/v3;
|
|
31
|
+
// batch methods go through the compat helpers (which translate to v3's
|
|
32
|
+
// getMany/setMany/removeMany) and keep the v2 tuple/pairs shape on the wire.
|
|
33
|
+
"async.getAllKeys": () => AsyncStorage.getAllKeys(),
|
|
34
|
+
"async.multiGet": params => readMany(params.keys),
|
|
35
|
+
"async.getItem": params => AsyncStorage.getItem(params.key),
|
|
36
|
+
"async.setItem": params => {
|
|
37
|
+
const {
|
|
38
|
+
key,
|
|
39
|
+
value
|
|
40
|
+
} = params;
|
|
41
|
+
return AsyncStorage.setItem(key, value);
|
|
42
|
+
},
|
|
43
|
+
"async.removeItem": params => AsyncStorage.removeItem(params.key),
|
|
44
|
+
"async.multiRemove": params => removeMany(params.keys),
|
|
45
|
+
"async.multiSet": params => writeMany(params.pairs),
|
|
46
|
+
"async.clear": () => AsyncStorage.clear()
|
|
47
|
+
}
|
|
48
|
+
};
|