@buoy-gg/storage 3.0.2 → 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/storage/components/GameUIStorageBrowser.js +24 -3
- package/lib/commonjs/storage/components/SelectionActionBar.js +16 -3
- package/lib/commonjs/storage/components/StorageBrowserMode.js +6 -2
- package/lib/commonjs/storage/components/StorageKeyRow.js +95 -6
- package/lib/commonjs/storage/components/StorageKeySection.js +8 -2
- package/lib/commonjs/storage/components/StorageModalWithTabs.js +47 -1
- package/lib/commonjs/storage/hooks/useAsyncStorageKeys.js +3 -2
- package/lib/commonjs/storage/stores/storageEventStore.js +7 -4
- package/lib/commonjs/storage/sync/storageSyncAdapter.js +7 -3
- 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/storage/components/GameUIStorageBrowser.js +24 -3
- package/lib/module/storage/components/SelectionActionBar.js +17 -3
- package/lib/module/storage/components/StorageBrowserMode.js +6 -2
- package/lib/module/storage/components/StorageKeyRow.js +97 -8
- package/lib/module/storage/components/StorageKeySection.js +8 -2
- package/lib/module/storage/components/StorageModalWithTabs.js +47 -1
- package/lib/module/storage/hooks/useAsyncStorageKeys.js +3 -2
- package/lib/module/storage/stores/storageEventStore.js +7 -4
- package/lib/module/storage/sync/storageSyncAdapter.js +7 -3
- 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/storage/components/GameUIStorageBrowser.d.ts +5 -1
- package/lib/typescript/storage/components/GameUIStorageBrowser.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/stores/storageEventStore.d.ts.map +1 -1
- package/lib/typescript/storage/sync/storageSyncAdapter.d.ts +1 -1
- package/lib/typescript/storage/sync/storageSyncAdapter.d.ts.map +1 -1
- 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
package/README.md
CHANGED
|
@@ -570,7 +570,7 @@ Required storage keys can be validated for:
|
|
|
570
570
|
## Dependencies
|
|
571
571
|
|
|
572
572
|
- `@buoy/shared-ui` - Common UI components and utilities
|
|
573
|
-
- `@react-native-async-storage/async-storage` - AsyncStorage implementation (peer dependency)
|
|
573
|
+
- `@react-native-async-storage/async-storage` - AsyncStorage implementation (peer dependency; supports v2 and v3 — `^2.0.0 || ^3.1.0`. Avoid 3.0.x, which has an Android build issue fixed upstream in 3.1.0.)
|
|
574
574
|
- `react-native-mmkv` - MMKV storage implementation (optional peer dependency)
|
|
575
575
|
- React and React Native (peer dependencies)
|
|
576
576
|
|
|
@@ -63,7 +63,9 @@ function GameUIStorageBrowser({
|
|
|
63
63
|
storageDataRef,
|
|
64
64
|
eventCountByKey,
|
|
65
65
|
onViewHistory,
|
|
66
|
-
enabledStorageTypes
|
|
66
|
+
enabledStorageTypes,
|
|
67
|
+
pinnedKeys,
|
|
68
|
+
onTogglePin
|
|
67
69
|
}) {
|
|
68
70
|
const isPro = (0, _license.useIsPro)();
|
|
69
71
|
const [showUpgradeModal, setShowUpgradeModal] = (0, _react.useState)(false);
|
|
@@ -173,6 +175,15 @@ function GameUIStorageBrowser({
|
|
|
173
175
|
refresh();
|
|
174
176
|
}, [refresh]);
|
|
175
177
|
|
|
178
|
+
// Hide the selected keys by adding each to the ignored-pattern filter store,
|
|
179
|
+
// then exit selection mode. Non-destructive — keys can be unhidden from the
|
|
180
|
+
// filters UI.
|
|
181
|
+
const handleHideKeys = (0, _react.useCallback)(keys => {
|
|
182
|
+
keys.forEach(k => onAddPattern?.(k.key));
|
|
183
|
+
setSelectedKeyIds(new Set());
|
|
184
|
+
setIsSelectMode(false);
|
|
185
|
+
}, [onAddPattern]);
|
|
186
|
+
|
|
176
187
|
// Memoized export data for copy functionality
|
|
177
188
|
const copyExportData = (0, _react.useMemo)(() => {
|
|
178
189
|
const allKeys = allStorageKeys;
|
|
@@ -395,8 +406,14 @@ function GameUIStorageBrowser({
|
|
|
395
406
|
// NOTE: MMKV instance filtering is now handled in mmkvStorageKeys memo (line 128)
|
|
396
407
|
// No need to filter again here
|
|
397
408
|
|
|
409
|
+
// Float pinned keys to the top (stable — preserves existing order otherwise)
|
|
410
|
+
if (pinnedKeys && pinnedKeys.size > 0) {
|
|
411
|
+
const pinned = keys.filter(k => pinnedKeys.has(k.key));
|
|
412
|
+
const rest = keys.filter(k => !pinnedKeys.has(k.key));
|
|
413
|
+
keys = [...pinned, ...rest];
|
|
414
|
+
}
|
|
398
415
|
return keys;
|
|
399
|
-
}, [sortedKeys, activeFilter, activeStorageType, ignoredPatterns, searchQuery, selectedMMKVInstance, enabledStorageTypes]);
|
|
416
|
+
}, [sortedKeys, activeFilter, activeStorageType, ignoredPatterns, searchQuery, selectedMMKVInstance, enabledStorageTypes, pinnedKeys]);
|
|
400
417
|
|
|
401
418
|
// For free users, limit visible keys to FREE_TIER_KEY_LIMIT
|
|
402
419
|
const visibleKeys = (0, _react.useMemo)(() => {
|
|
@@ -618,6 +635,7 @@ function GameUIStorageBrowser({
|
|
|
618
635
|
instance: inst.instance
|
|
619
636
|
})),
|
|
620
637
|
onDeleteComplete: handleDeleteComplete,
|
|
638
|
+
onHideKeys: handleHideKeys,
|
|
621
639
|
onSelectAll: handleSelectAll,
|
|
622
640
|
onClearSelection: handleClearSelection,
|
|
623
641
|
totalVisibleKeys: visibleKeys.length
|
|
@@ -630,7 +648,10 @@ function GameUIStorageBrowser({
|
|
|
630
648
|
selectedKeys: selectedKeyIds,
|
|
631
649
|
onSelectionChange: handleSelectionChange,
|
|
632
650
|
eventCountByKey: eventCountByKey,
|
|
633
|
-
onViewHistory: onViewHistory
|
|
651
|
+
onViewHistory: onViewHistory,
|
|
652
|
+
onHideKey: key => handleHideKeys([key]),
|
|
653
|
+
pinnedKeys: pinnedKeys,
|
|
654
|
+
onTogglePin: onTogglePin
|
|
634
655
|
}), hasLockedKeys && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
|
|
635
656
|
style: styles.limitBanner,
|
|
636
657
|
onPress: () => setShowUpgradeModal(true),
|
|
@@ -8,13 +8,13 @@ var _react = require("react");
|
|
|
8
8
|
var _reactNative = require("react-native");
|
|
9
9
|
var _sharedUi = require("@buoy-gg/shared-ui");
|
|
10
10
|
var _license = require("@buoy-gg/license");
|
|
11
|
-
var
|
|
11
|
+
var _asyncStorageCompat = require("../utils/asyncStorageCompat");
|
|
12
12
|
var _jsxRuntime = require("react/jsx-runtime");
|
|
13
|
-
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
14
13
|
function SelectionActionBar({
|
|
15
14
|
selectedKeys,
|
|
16
15
|
mmkvInstances,
|
|
17
16
|
onDeleteComplete,
|
|
17
|
+
onHideKeys,
|
|
18
18
|
onSelectAll,
|
|
19
19
|
onClearSelection,
|
|
20
20
|
totalVisibleKeys
|
|
@@ -45,6 +45,12 @@ function SelectionActionBar({
|
|
|
45
45
|
};
|
|
46
46
|
};
|
|
47
47
|
|
|
48
|
+
// Hide selected keys (adds them to the filter store; non-destructive)
|
|
49
|
+
const handleHideSelected = () => {
|
|
50
|
+
if (selectedCount === 0) return;
|
|
51
|
+
onHideKeys?.(selectedKeys);
|
|
52
|
+
};
|
|
53
|
+
|
|
48
54
|
// Handle delete selected keys
|
|
49
55
|
const handleDeleteSelected = () => {
|
|
50
56
|
if (selectedCount === 0) return;
|
|
@@ -68,7 +74,7 @@ function SelectionActionBar({
|
|
|
68
74
|
|
|
69
75
|
// Delete AsyncStorage keys
|
|
70
76
|
if (asyncKeys.length > 0) {
|
|
71
|
-
await
|
|
77
|
+
await (0, _asyncStorageCompat.removeMany)(asyncKeys.map(k => k.key));
|
|
72
78
|
}
|
|
73
79
|
|
|
74
80
|
// Delete MMKV keys
|
|
@@ -131,6 +137,13 @@ function SelectionActionBar({
|
|
|
131
137
|
success: _sharedUi.macOSColors.semantic.success,
|
|
132
138
|
error: _sharedUi.macOSColors.semantic.error
|
|
133
139
|
}
|
|
140
|
+
}), onHideKeys && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
|
|
141
|
+
style: styles.actionButton,
|
|
142
|
+
onPress: handleHideSelected,
|
|
143
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.EyeOff, {
|
|
144
|
+
size: 14,
|
|
145
|
+
color: _sharedUi.macOSColors.semantic.warning
|
|
146
|
+
})
|
|
134
147
|
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
|
|
135
148
|
style: styles.actionButton,
|
|
136
149
|
onPress: handleDeleteSelected,
|
|
@@ -20,7 +20,9 @@ function StorageBrowserMode({
|
|
|
20
20
|
storageDataRef,
|
|
21
21
|
eventCountByKey,
|
|
22
22
|
onViewHistory,
|
|
23
|
-
enabledStorageTypes
|
|
23
|
+
enabledStorageTypes,
|
|
24
|
+
pinnedKeys,
|
|
25
|
+
onTogglePin
|
|
24
26
|
}) {
|
|
25
27
|
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_GameUIStorageBrowser.GameUIStorageBrowser, {
|
|
26
28
|
requiredStorageKeys: requiredStorageKeys,
|
|
@@ -32,6 +34,8 @@ function StorageBrowserMode({
|
|
|
32
34
|
storageDataRef: storageDataRef,
|
|
33
35
|
eventCountByKey: eventCountByKey,
|
|
34
36
|
onViewHistory: onViewHistory,
|
|
35
|
-
enabledStorageTypes: enabledStorageTypes
|
|
37
|
+
enabledStorageTypes: enabledStorageTypes,
|
|
38
|
+
pinnedKeys: pinnedKeys,
|
|
39
|
+
onTogglePin: onTogglePin
|
|
36
40
|
});
|
|
37
41
|
}
|
|
@@ -81,11 +81,18 @@ function StorageKeyRow({
|
|
|
81
81
|
isSelected = false,
|
|
82
82
|
onSelectionChange,
|
|
83
83
|
eventCount,
|
|
84
|
-
onViewHistory
|
|
84
|
+
onViewHistory,
|
|
85
|
+
onHideKey,
|
|
86
|
+
isPinned = false,
|
|
87
|
+
onTogglePin
|
|
85
88
|
}) {
|
|
86
89
|
const config = getStatusConfig(storageKey.status);
|
|
87
90
|
const hasValue = storageKey.value !== undefined && storageKey.value !== null;
|
|
88
91
|
|
|
92
|
+
// Booleans get a dedicated colored badge instead of an inline text preview so
|
|
93
|
+
// their value is scannable at a glance.
|
|
94
|
+
const isBoolean = hasValue && typeof storageKey.value === "boolean";
|
|
95
|
+
|
|
89
96
|
// Format primary text - show the key
|
|
90
97
|
const primaryText = storageKey.key;
|
|
91
98
|
|
|
@@ -198,6 +205,45 @@ function StorageKeyRow({
|
|
|
198
205
|
style: styles.expandedDescription,
|
|
199
206
|
children: storageKey.description
|
|
200
207
|
})]
|
|
208
|
+
}) : null, onTogglePin || onHideKey ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
209
|
+
style: styles.actionRow,
|
|
210
|
+
children: [onTogglePin ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
|
|
211
|
+
style: [styles.actionChip, isPinned && styles.actionChipActive],
|
|
212
|
+
onPress: () => onTogglePin(storageKey.key),
|
|
213
|
+
hitSlop: {
|
|
214
|
+
top: 6,
|
|
215
|
+
bottom: 6,
|
|
216
|
+
left: 6,
|
|
217
|
+
right: 6
|
|
218
|
+
},
|
|
219
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Pin, {
|
|
220
|
+
size: 12,
|
|
221
|
+
color: _sharedUi.macOSColors.semantic.info
|
|
222
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
223
|
+
style: [styles.actionChipText, {
|
|
224
|
+
color: _sharedUi.macOSColors.semantic.info
|
|
225
|
+
}],
|
|
226
|
+
children: isPinned ? "Unpin" : "Pin to top"
|
|
227
|
+
})]
|
|
228
|
+
}) : null, onHideKey ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
|
|
229
|
+
style: styles.actionChip,
|
|
230
|
+
onPress: () => onHideKey(storageKey),
|
|
231
|
+
hitSlop: {
|
|
232
|
+
top: 6,
|
|
233
|
+
bottom: 6,
|
|
234
|
+
left: 6,
|
|
235
|
+
right: 6
|
|
236
|
+
},
|
|
237
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.EyeOff, {
|
|
238
|
+
size: 12,
|
|
239
|
+
color: _sharedUi.macOSColors.semantic.warning
|
|
240
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
241
|
+
style: [styles.actionChipText, {
|
|
242
|
+
color: _sharedUi.macOSColors.semantic.warning
|
|
243
|
+
}],
|
|
244
|
+
children: "Hide from list"
|
|
245
|
+
})]
|
|
246
|
+
}) : null]
|
|
201
247
|
}) : null]
|
|
202
248
|
});
|
|
203
249
|
|
|
@@ -233,17 +279,28 @@ function StorageKeyRow({
|
|
|
233
279
|
statusLabel: config.label,
|
|
234
280
|
statusSublabel: config.sublabel,
|
|
235
281
|
primaryText: primaryText,
|
|
236
|
-
secondaryText: hasValue ? (0, _valueType.getValueTypeLabel)(storageKey.value) : undefined,
|
|
282
|
+
secondaryText: hasValue ? isBoolean ? (0, _valueType.getValueTypeLabel)(storageKey.value) : (0, _valueType.getValueTypeWithPreview)(storageKey.value) : undefined,
|
|
283
|
+
secondaryAccessory: isBoolean ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.PillBadge, {
|
|
284
|
+
size: "sm",
|
|
285
|
+
color: storageKey.value ? _sharedUi.macOSColors.semantic.success : _sharedUi.macOSColors.semantic.error,
|
|
286
|
+
children: storageKey.value ? "true" : "false"
|
|
287
|
+
}) : undefined,
|
|
237
288
|
expandedContent: expandedContent,
|
|
238
289
|
isExpanded: isExpanded,
|
|
239
290
|
expandedGlowColor: config.color,
|
|
240
|
-
customBadge: /*#__PURE__*/(0, _jsxRuntime.
|
|
241
|
-
|
|
242
|
-
children:
|
|
291
|
+
customBadge: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
292
|
+
style: styles.badgeRow,
|
|
293
|
+
children: [isPinned && /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Pin, {
|
|
294
|
+
size: 12,
|
|
295
|
+
color: _sharedUi.macOSColors.semantic.info
|
|
296
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.PillBadge, {
|
|
297
|
+
color: getStorageTypeColor(storageKey.storageType),
|
|
298
|
+
children: storageTypeLabel
|
|
299
|
+
})]
|
|
243
300
|
}),
|
|
244
301
|
showChevron: !isSelectMode,
|
|
245
302
|
onPress: isSelectMode ? handleCheckboxPress : onPress ? () => onPress(storageKey) : undefined
|
|
246
|
-
}), eventCount != null && eventCount >
|
|
303
|
+
}), eventCount != null && eventCount > 1 && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
247
304
|
style: [styles.absCountBadge, {
|
|
248
305
|
backgroundColor: _sharedUi.macOSColors.semantic.warning + "22",
|
|
249
306
|
borderColor: _sharedUi.macOSColors.semantic.warning + "55"
|
|
@@ -272,6 +329,11 @@ const getStorageTypeColor = storageType => {
|
|
|
272
329
|
}
|
|
273
330
|
};
|
|
274
331
|
const styles = _reactNative.StyleSheet.create({
|
|
332
|
+
badgeRow: {
|
|
333
|
+
flexDirection: "row",
|
|
334
|
+
alignItems: "center",
|
|
335
|
+
gap: 6
|
|
336
|
+
},
|
|
275
337
|
expandedContainer: {
|
|
276
338
|
gap: 8
|
|
277
339
|
},
|
|
@@ -345,6 +407,33 @@ const styles = _reactNative.StyleSheet.create({
|
|
|
345
407
|
fontWeight: "700",
|
|
346
408
|
fontFamily: "monospace"
|
|
347
409
|
},
|
|
410
|
+
actionRow: {
|
|
411
|
+
flexDirection: "row",
|
|
412
|
+
alignItems: "center",
|
|
413
|
+
flexWrap: "wrap",
|
|
414
|
+
gap: 8,
|
|
415
|
+
marginTop: 4
|
|
416
|
+
},
|
|
417
|
+
actionChip: {
|
|
418
|
+
flexDirection: "row",
|
|
419
|
+
alignItems: "center",
|
|
420
|
+
gap: 6,
|
|
421
|
+
paddingVertical: 6,
|
|
422
|
+
paddingHorizontal: 10,
|
|
423
|
+
borderRadius: 6,
|
|
424
|
+
backgroundColor: _sharedUi.macOSColors.background.card,
|
|
425
|
+
borderWidth: 1,
|
|
426
|
+
borderColor: _sharedUi.macOSColors.border.default
|
|
427
|
+
},
|
|
428
|
+
actionChipActive: {
|
|
429
|
+
backgroundColor: _sharedUi.macOSColors.semantic.info + "15",
|
|
430
|
+
borderColor: _sharedUi.macOSColors.semantic.info + "44"
|
|
431
|
+
},
|
|
432
|
+
actionChipText: {
|
|
433
|
+
fontSize: 11,
|
|
434
|
+
fontWeight: "600",
|
|
435
|
+
fontFamily: "monospace"
|
|
436
|
+
},
|
|
348
437
|
viewHistoryButton: {
|
|
349
438
|
marginLeft: 4
|
|
350
439
|
},
|
|
@@ -27,7 +27,10 @@ function StorageKeySection({
|
|
|
27
27
|
selectedKeys = new Set(),
|
|
28
28
|
onSelectionChange,
|
|
29
29
|
eventCountByKey,
|
|
30
|
-
onViewHistory
|
|
30
|
+
onViewHistory,
|
|
31
|
+
onHideKey,
|
|
32
|
+
pinnedKeys,
|
|
33
|
+
onTogglePin
|
|
31
34
|
}) {
|
|
32
35
|
const [expandedKey, setExpandedKey] = (0, _react.useState)(null);
|
|
33
36
|
const handleKeyPress = (0, _react.useCallback)(storageKey => {
|
|
@@ -80,7 +83,10 @@ function StorageKeySection({
|
|
|
80
83
|
isSelected: selectedKeys.has(uniqueKey),
|
|
81
84
|
onSelectionChange: onSelectionChange,
|
|
82
85
|
eventCount: eventCountByKey?.[storageKey.key],
|
|
83
|
-
onViewHistory: onViewHistory ? () => onViewHistory(storageKey.key) : undefined
|
|
86
|
+
onViewHistory: onViewHistory ? () => onViewHistory(storageKey.key) : undefined,
|
|
87
|
+
onHideKey: onHideKey,
|
|
88
|
+
isPinned: pinnedKeys?.has(storageKey.key),
|
|
89
|
+
onTogglePin: onTogglePin
|
|
84
90
|
}, uniqueKey);
|
|
85
91
|
})
|
|
86
92
|
})]
|
|
@@ -60,8 +60,10 @@ function StorageModalWithTabs({
|
|
|
60
60
|
);
|
|
61
61
|
const [enabledStorageTypes, setEnabledStorageTypes] = (0, _react.useState)(new Set(['async', 'mmkv', 'secure']) // All enabled by default
|
|
62
62
|
);
|
|
63
|
+
const [pinnedKeys, setPinnedKeys] = (0, _react.useState)(new Set());
|
|
63
64
|
const lastEventRef = (0, _react.useRef)(null);
|
|
64
65
|
const hasLoadedFilters = (0, _react.useRef)(false);
|
|
66
|
+
const hasLoadedPins = (0, _react.useRef)(false);
|
|
65
67
|
const hasLoadedTabState = (0, _react.useRef)(false);
|
|
66
68
|
const hasLoadedMonitoringState = (0, _react.useRef)(false);
|
|
67
69
|
|
|
@@ -176,6 +178,37 @@ function StorageModalWithTabs({
|
|
|
176
178
|
saveFilters();
|
|
177
179
|
}, [ignoredPatterns]);
|
|
178
180
|
|
|
181
|
+
// Load persisted pinned keys on mount
|
|
182
|
+
(0, _react.useEffect)(() => {
|
|
183
|
+
if (!visible || hasLoadedPins.current) return;
|
|
184
|
+
const loadPins = async () => {
|
|
185
|
+
try {
|
|
186
|
+
const stored = await _asyncStorage.default.getItem(_sharedUi.devToolsStorageKeys.storage.pinnedKeys());
|
|
187
|
+
if (stored) {
|
|
188
|
+
setPinnedKeys(new Set(JSON.parse(stored)));
|
|
189
|
+
}
|
|
190
|
+
hasLoadedPins.current = true;
|
|
191
|
+
} catch (error) {
|
|
192
|
+
// Failed to load pinned keys
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
loadPins();
|
|
196
|
+
}, [visible]);
|
|
197
|
+
|
|
198
|
+
// Save pinned keys when they change
|
|
199
|
+
(0, _react.useEffect)(() => {
|
|
200
|
+
if (!hasLoadedPins.current) return; // Don't save on initial load
|
|
201
|
+
|
|
202
|
+
const savePins = async () => {
|
|
203
|
+
try {
|
|
204
|
+
await _asyncStorage.default.setItem(_sharedUi.devToolsStorageKeys.storage.pinnedKeys(), JSON.stringify(Array.from(pinnedKeys)));
|
|
205
|
+
} catch (error) {
|
|
206
|
+
// Failed to save pinned keys
|
|
207
|
+
}
|
|
208
|
+
};
|
|
209
|
+
savePins();
|
|
210
|
+
}, [pinnedKeys]);
|
|
211
|
+
|
|
179
212
|
// Event listener setup - now handled by useStorageEvents hook
|
|
180
213
|
// The hook subscribes to the centralized storageEventStore
|
|
181
214
|
|
|
@@ -210,6 +243,17 @@ function StorageModalWithTabs({
|
|
|
210
243
|
const handleAddPattern = (0, _react.useCallback)(pattern => {
|
|
211
244
|
setIgnoredPatterns(prev => new Set([...prev, pattern]));
|
|
212
245
|
}, []);
|
|
246
|
+
const handleTogglePin = (0, _react.useCallback)(key => {
|
|
247
|
+
setPinnedKeys(prev => {
|
|
248
|
+
const next = new Set(prev);
|
|
249
|
+
if (next.has(key)) {
|
|
250
|
+
next.delete(key);
|
|
251
|
+
} else {
|
|
252
|
+
next.add(key);
|
|
253
|
+
}
|
|
254
|
+
return next;
|
|
255
|
+
});
|
|
256
|
+
}, []);
|
|
213
257
|
const handleToggleFilters = (0, _react.useCallback)(() => {
|
|
214
258
|
setShowFilters(!showFilters);
|
|
215
259
|
}, [showFilters]);
|
|
@@ -508,7 +552,9 @@ function StorageModalWithTabs({
|
|
|
508
552
|
storageDataRef: storageDataRef,
|
|
509
553
|
eventCountByKey: eventCountByKey,
|
|
510
554
|
onViewHistory: handleViewHistoryFromBrowser,
|
|
511
|
-
enabledStorageTypes: enabledStorageTypes
|
|
555
|
+
enabledStorageTypes: enabledStorageTypes,
|
|
556
|
+
pinnedKeys: pinnedKeys,
|
|
557
|
+
onTogglePin: handleTogglePin
|
|
512
558
|
});
|
|
513
559
|
}
|
|
514
560
|
|
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
exports.useAsyncStorageKeys = useAsyncStorageKeys;
|
|
7
7
|
var _react = require("react");
|
|
8
8
|
var _asyncStorage = _interopRequireDefault(require("@react-native-async-storage/async-storage"));
|
|
9
|
+
var _asyncStorageCompat = require("../utils/asyncStorageCompat");
|
|
9
10
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
10
11
|
function useAsyncStorageKeys(requiredStorageKeys = []) {
|
|
11
12
|
// State management
|
|
@@ -36,8 +37,8 @@ function useAsyncStorageKeys(requiredStorageKeys = []) {
|
|
|
36
37
|
return;
|
|
37
38
|
}
|
|
38
39
|
|
|
39
|
-
// 2. Get all values
|
|
40
|
-
const allKeyValuePairs = await
|
|
40
|
+
// 2. Get all values (compat helper normalizes v2 multiGet / v3 getMany)
|
|
41
|
+
const allKeyValuePairs = await (0, _asyncStorageCompat.readMany)(allKeys);
|
|
41
42
|
|
|
42
43
|
// 3. Process keys into StorageKeyInfo format
|
|
43
44
|
const allStorageKeys = [];
|
|
@@ -114,11 +114,14 @@ class StorageEventStore extends _sharedUi.BaseEventStore {
|
|
|
114
114
|
|
|
115
115
|
// ── AsyncStorage: async scan ──
|
|
116
116
|
try {
|
|
117
|
-
const
|
|
118
|
-
|
|
119
|
-
|
|
117
|
+
const {
|
|
118
|
+
asyncStorage,
|
|
119
|
+
readMany
|
|
120
|
+
} = require("../utils/asyncStorageCompat");
|
|
121
|
+
if (asyncStorage) {
|
|
122
|
+
const allKeys = await asyncStorage.getAllKeys();
|
|
120
123
|
if (allKeys.length > 0) {
|
|
121
|
-
const pairs = await
|
|
124
|
+
const pairs = await readMany(allKeys);
|
|
122
125
|
for (const [key, rawValue] of pairs) {
|
|
123
126
|
this.addEvent({
|
|
124
127
|
action: "setItem",
|
|
@@ -5,6 +5,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.storageSyncAdapter = void 0;
|
|
7
7
|
var _asyncStorage = _interopRequireDefault(require("@react-native-async-storage/async-storage"));
|
|
8
|
+
var _asyncStorageCompat = require("../utils/asyncStorageCompat");
|
|
8
9
|
var _storageEventStore = require("../stores/storageEventStore");
|
|
9
10
|
var _clearAllStorage = require("../utils/clearAllStorage");
|
|
10
11
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
@@ -31,8 +32,11 @@ const storageSyncAdapter = exports.storageSyncAdapter = {
|
|
|
31
32
|
/** Clears all app storage keys, preserving dev tools settings. */
|
|
32
33
|
clearAppStorage: () => (0, _clearAllStorage.clearAllAppStorage)(),
|
|
33
34
|
// ── Remote AsyncStorage proxy (desktop browse/edit mode) ──
|
|
35
|
+
// Single-item methods share the same signature across async-storage v2/v3;
|
|
36
|
+
// batch methods go through the compat helpers (which translate to v3's
|
|
37
|
+
// getMany/setMany/removeMany) and keep the v2 tuple/pairs shape on the wire.
|
|
34
38
|
"async.getAllKeys": () => _asyncStorage.default.getAllKeys(),
|
|
35
|
-
"async.multiGet": params =>
|
|
39
|
+
"async.multiGet": params => (0, _asyncStorageCompat.readMany)(params.keys),
|
|
36
40
|
"async.getItem": params => _asyncStorage.default.getItem(params.key),
|
|
37
41
|
"async.setItem": params => {
|
|
38
42
|
const {
|
|
@@ -42,8 +46,8 @@ const storageSyncAdapter = exports.storageSyncAdapter = {
|
|
|
42
46
|
return _asyncStorage.default.setItem(key, value);
|
|
43
47
|
},
|
|
44
48
|
"async.removeItem": params => _asyncStorage.default.removeItem(params.key),
|
|
45
|
-
"async.multiRemove": params =>
|
|
46
|
-
"async.multiSet": params =>
|
|
49
|
+
"async.multiRemove": params => (0, _asyncStorageCompat.removeMany)(params.keys),
|
|
50
|
+
"async.multiSet": params => (0, _asyncStorageCompat.writeMany)(params.pairs),
|
|
47
51
|
"async.clear": () => _asyncStorage.default.clear()
|
|
48
52
|
}
|
|
49
53
|
};
|