@buoy-gg/storage 1.7.2
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 +607 -0
- package/lib/commonjs/index.js +34 -0
- package/lib/commonjs/package.json +1 -0
- package/lib/commonjs/preset.js +94 -0
- package/lib/commonjs/storage/components/DiffViewer/DiffOptionsPanel.js +356 -0
- package/lib/commonjs/storage/components/DiffViewer/TreeDiffViewer.js +29 -0
- package/lib/commonjs/storage/components/DiffViewer/components/DiffSummary.js +121 -0
- package/lib/commonjs/storage/components/DiffViewer/modes/ThemedSplitView.js +419 -0
- package/lib/commonjs/storage/components/DiffViewer/themes/diffThemes.js +122 -0
- package/lib/commonjs/storage/components/GameUIStorageBrowser.js +924 -0
- package/lib/commonjs/storage/components/GameUIStorageStats.js +746 -0
- package/lib/commonjs/storage/components/MMKVInstanceInfoPanel.js +257 -0
- package/lib/commonjs/storage/components/MMKVInstanceSelector.js +418 -0
- package/lib/commonjs/storage/components/SelectionActionBar.js +224 -0
- package/lib/commonjs/storage/components/StorageActionButtons.js +239 -0
- package/lib/commonjs/storage/components/StorageActions.js +192 -0
- package/lib/commonjs/storage/components/StorageBrowserMode.js +31 -0
- package/lib/commonjs/storage/components/StorageEventDetailContent.js +1025 -0
- package/lib/commonjs/storage/components/StorageEventFilterView.js +141 -0
- package/lib/commonjs/storage/components/StorageEventListener.js +357 -0
- package/lib/commonjs/storage/components/StorageEventsSection.js +24 -0
- package/lib/commonjs/storage/components/StorageFilterCards.js +345 -0
- package/lib/commonjs/storage/components/StorageFilterViewV2.js +42 -0
- package/lib/commonjs/storage/components/StorageKeyCard.js +516 -0
- package/lib/commonjs/storage/components/StorageKeyRow.js +356 -0
- package/lib/commonjs/storage/components/StorageKeySection.js +105 -0
- package/lib/commonjs/storage/components/StorageKeyStats.js +344 -0
- package/lib/commonjs/storage/components/StorageModalWithTabs.js +871 -0
- package/lib/commonjs/storage/components/StorageSection.js +43 -0
- package/lib/commonjs/storage/hooks/useAsyncStorageKeys.js +126 -0
- package/lib/commonjs/storage/hooks/useMMKVInstances.js +221 -0
- package/lib/commonjs/storage/hooks/useMMKVKeys.js +362 -0
- package/lib/commonjs/storage/hooks/useTickEverySecond.js +21 -0
- package/lib/commonjs/storage/index.js +148 -0
- package/lib/commonjs/storage/types.js +5 -0
- package/lib/commonjs/storage/utils/AsyncStorageListener.js +510 -0
- package/lib/commonjs/storage/utils/MMKVInstanceRegistry.js +202 -0
- package/lib/commonjs/storage/utils/MMKVListener.js +380 -0
- package/lib/commonjs/storage/utils/clearAllStorage.js +47 -0
- package/lib/commonjs/storage/utils/index.js +180 -0
- package/lib/commonjs/storage/utils/lineDiff.js +363 -0
- package/lib/commonjs/storage/utils/mmkvAvailability.js +62 -0
- package/lib/commonjs/storage/utils/mmkvTypeDetection.js +139 -0
- package/lib/commonjs/storage/utils/objectDiff.js +157 -0
- package/lib/commonjs/storage/utils/safeAsyncStorage.js +140 -0
- package/lib/commonjs/storage/utils/storageActionHelpers.js +46 -0
- package/lib/commonjs/storage/utils/storageQueryUtils.js +35 -0
- package/lib/commonjs/storage/utils/valueType.js +18 -0
- package/lib/module/index.js +7 -0
- package/lib/module/preset.js +89 -0
- package/lib/module/storage/components/DiffViewer/DiffOptionsPanel.js +352 -0
- package/lib/module/storage/components/DiffViewer/TreeDiffViewer.js +25 -0
- package/lib/module/storage/components/DiffViewer/components/DiffSummary.js +117 -0
- package/lib/module/storage/components/DiffViewer/modes/ThemedSplitView.js +415 -0
- package/lib/module/storage/components/DiffViewer/themes/diffThemes.js +118 -0
- package/lib/module/storage/components/GameUIStorageBrowser.js +922 -0
- package/lib/module/storage/components/GameUIStorageStats.js +742 -0
- package/lib/module/storage/components/MMKVInstanceInfoPanel.js +253 -0
- package/lib/module/storage/components/MMKVInstanceSelector.js +414 -0
- package/lib/module/storage/components/SelectionActionBar.js +221 -0
- package/lib/module/storage/components/StorageActionButtons.js +236 -0
- package/lib/module/storage/components/StorageActions.js +189 -0
- package/lib/module/storage/components/StorageBrowserMode.js +27 -0
- package/lib/module/storage/components/StorageEventDetailContent.js +1020 -0
- package/lib/module/storage/components/StorageEventFilterView.js +137 -0
- package/lib/module/storage/components/StorageEventListener.js +354 -0
- package/lib/module/storage/components/StorageEventsSection.js +20 -0
- package/lib/module/storage/components/StorageFilterCards.js +341 -0
- package/lib/module/storage/components/StorageFilterViewV2.js +38 -0
- package/lib/module/storage/components/StorageKeyCard.js +513 -0
- package/lib/module/storage/components/StorageKeyRow.js +353 -0
- package/lib/module/storage/components/StorageKeySection.js +101 -0
- package/lib/module/storage/components/StorageKeyStats.js +340 -0
- package/lib/module/storage/components/StorageModalWithTabs.js +867 -0
- package/lib/module/storage/components/StorageSection.js +40 -0
- package/lib/module/storage/hooks/useAsyncStorageKeys.js +121 -0
- package/lib/module/storage/hooks/useMMKVInstances.js +216 -0
- package/lib/module/storage/hooks/useMMKVKeys.js +359 -0
- package/lib/module/storage/hooks/useTickEverySecond.js +18 -0
- package/lib/module/storage/index.js +25 -0
- package/lib/module/storage/types.js +3 -0
- package/lib/module/storage/utils/AsyncStorageListener.js +500 -0
- package/lib/module/storage/utils/MMKVInstanceRegistry.js +196 -0
- package/lib/module/storage/utils/MMKVListener.js +367 -0
- package/lib/module/storage/utils/clearAllStorage.js +42 -0
- package/lib/module/storage/utils/index.js +22 -0
- package/lib/module/storage/utils/lineDiff.js +359 -0
- package/lib/module/storage/utils/mmkvAvailability.js +56 -0
- package/lib/module/storage/utils/mmkvTypeDetection.js +133 -0
- package/lib/module/storage/utils/objectDiff.js +153 -0
- package/lib/module/storage/utils/safeAsyncStorage.js +134 -0
- package/lib/module/storage/utils/storageActionHelpers.js +42 -0
- package/lib/module/storage/utils/storageQueryUtils.js +30 -0
- package/lib/module/storage/utils/valueType.js +14 -0
- package/lib/typescript/index.d.ts +3 -0
- package/lib/typescript/index.d.ts.map +1 -0
- package/lib/typescript/preset.d.ts +90 -0
- package/lib/typescript/preset.d.ts.map +1 -0
- package/lib/typescript/storage/components/DiffViewer/DiffOptionsPanel.d.ts +18 -0
- package/lib/typescript/storage/components/DiffViewer/DiffOptionsPanel.d.ts.map +1 -0
- package/lib/typescript/storage/components/DiffViewer/TreeDiffViewer.d.ts +7 -0
- package/lib/typescript/storage/components/DiffViewer/TreeDiffViewer.d.ts.map +1 -0
- package/lib/typescript/storage/components/DiffViewer/components/DiffSummary.d.ts +12 -0
- package/lib/typescript/storage/components/DiffViewer/components/DiffSummary.d.ts.map +1 -0
- package/lib/typescript/storage/components/DiffViewer/modes/ThemedSplitView.d.ts +13 -0
- package/lib/typescript/storage/components/DiffViewer/modes/ThemedSplitView.d.ts.map +1 -0
- package/lib/typescript/storage/components/DiffViewer/themes/diffThemes.d.ts +64 -0
- package/lib/typescript/storage/components/DiffViewer/themes/diffThemes.d.ts.map +1 -0
- package/lib/typescript/storage/components/GameUIStorageBrowser.d.ts +16 -0
- package/lib/typescript/storage/components/GameUIStorageBrowser.d.ts.map +1 -0
- package/lib/typescript/storage/components/GameUIStorageStats.d.ts +7 -0
- package/lib/typescript/storage/components/GameUIStorageStats.d.ts.map +1 -0
- package/lib/typescript/storage/components/MMKVInstanceInfoPanel.d.ts +42 -0
- package/lib/typescript/storage/components/MMKVInstanceInfoPanel.d.ts.map +1 -0
- package/lib/typescript/storage/components/MMKVInstanceSelector.d.ts +35 -0
- package/lib/typescript/storage/components/MMKVInstanceSelector.d.ts.map +1 -0
- package/lib/typescript/storage/components/SelectionActionBar.d.ts +21 -0
- package/lib/typescript/storage/components/SelectionActionBar.d.ts.map +1 -0
- package/lib/typescript/storage/components/StorageActionButtons.d.ts +21 -0
- package/lib/typescript/storage/components/StorageActionButtons.d.ts.map +1 -0
- package/lib/typescript/storage/components/StorageActions.d.ts +10 -0
- package/lib/typescript/storage/components/StorageActions.d.ts.map +1 -0
- package/lib/typescript/storage/components/StorageBrowserMode.d.ts +18 -0
- package/lib/typescript/storage/components/StorageBrowserMode.d.ts.map +1 -0
- package/lib/typescript/storage/components/StorageEventDetailContent.d.ts +40 -0
- package/lib/typescript/storage/components/StorageEventDetailContent.d.ts.map +1 -0
- package/lib/typescript/storage/components/StorageEventFilterView.d.ts +11 -0
- package/lib/typescript/storage/components/StorageEventFilterView.d.ts.map +1 -0
- package/lib/typescript/storage/components/StorageEventListener.d.ts +6 -0
- package/lib/typescript/storage/components/StorageEventListener.d.ts.map +1 -0
- package/lib/typescript/storage/components/StorageEventsSection.d.ts +7 -0
- package/lib/typescript/storage/components/StorageEventsSection.d.ts.map +1 -0
- package/lib/typescript/storage/components/StorageFilterCards.d.ts +36 -0
- package/lib/typescript/storage/components/StorageFilterCards.d.ts.map +1 -0
- package/lib/typescript/storage/components/StorageFilterViewV2.d.ts +9 -0
- package/lib/typescript/storage/components/StorageFilterViewV2.d.ts.map +1 -0
- package/lib/typescript/storage/components/StorageKeyCard.d.ts +17 -0
- package/lib/typescript/storage/components/StorageKeyCard.d.ts.map +1 -0
- package/lib/typescript/storage/components/StorageKeyRow.d.ts +15 -0
- package/lib/typescript/storage/components/StorageKeyRow.d.ts.map +1 -0
- package/lib/typescript/storage/components/StorageKeySection.d.ts +25 -0
- package/lib/typescript/storage/components/StorageKeySection.d.ts.map +1 -0
- package/lib/typescript/storage/components/StorageKeyStats.d.ts +15 -0
- package/lib/typescript/storage/components/StorageKeyStats.d.ts.map +1 -0
- package/lib/typescript/storage/components/StorageModalWithTabs.d.ts +13 -0
- package/lib/typescript/storage/components/StorageModalWithTabs.d.ts.map +1 -0
- package/lib/typescript/storage/components/StorageSection.d.ts +10 -0
- package/lib/typescript/storage/components/StorageSection.d.ts.map +1 -0
- package/lib/typescript/storage/hooks/useAsyncStorageKeys.d.ts +10 -0
- package/lib/typescript/storage/hooks/useAsyncStorageKeys.d.ts.map +1 -0
- package/lib/typescript/storage/hooks/useMMKVInstances.d.ts +114 -0
- package/lib/typescript/storage/hooks/useMMKVInstances.d.ts.map +1 -0
- package/lib/typescript/storage/hooks/useMMKVKeys.d.ts +94 -0
- package/lib/typescript/storage/hooks/useMMKVKeys.d.ts.map +1 -0
- package/lib/typescript/storage/hooks/useTickEverySecond.d.ts +6 -0
- package/lib/typescript/storage/hooks/useTickEverySecond.d.ts.map +1 -0
- package/lib/typescript/storage/index.d.ts +15 -0
- package/lib/typescript/storage/index.d.ts.map +1 -0
- package/lib/typescript/storage/types.d.ts +41 -0
- package/lib/typescript/storage/types.d.ts.map +1 -0
- package/lib/typescript/storage/utils/AsyncStorageListener.d.ts +195 -0
- package/lib/typescript/storage/utils/AsyncStorageListener.d.ts.map +1 -0
- package/lib/typescript/storage/utils/MMKVInstanceRegistry.d.ts +224 -0
- package/lib/typescript/storage/utils/MMKVInstanceRegistry.d.ts.map +1 -0
- package/lib/typescript/storage/utils/MMKVListener.d.ts +218 -0
- package/lib/typescript/storage/utils/MMKVListener.d.ts.map +1 -0
- package/lib/typescript/storage/utils/clearAllStorage.d.ts +11 -0
- package/lib/typescript/storage/utils/clearAllStorage.d.ts.map +1 -0
- package/lib/typescript/storage/utils/index.d.ts +8 -0
- package/lib/typescript/storage/utils/index.d.ts.map +1 -0
- package/lib/typescript/storage/utils/lineDiff.d.ts +34 -0
- package/lib/typescript/storage/utils/lineDiff.d.ts.map +1 -0
- package/lib/typescript/storage/utils/mmkvAvailability.d.ts +23 -0
- package/lib/typescript/storage/utils/mmkvAvailability.d.ts.map +1 -0
- package/lib/typescript/storage/utils/mmkvTypeDetection.d.ts +71 -0
- package/lib/typescript/storage/utils/mmkvTypeDetection.d.ts.map +1 -0
- package/lib/typescript/storage/utils/objectDiff.d.ts +35 -0
- package/lib/typescript/storage/utils/objectDiff.d.ts.map +1 -0
- package/lib/typescript/storage/utils/safeAsyncStorage.d.ts +56 -0
- package/lib/typescript/storage/utils/safeAsyncStorage.d.ts.map +1 -0
- package/lib/typescript/storage/utils/storageActionHelpers.d.ts +5 -0
- package/lib/typescript/storage/utils/storageActionHelpers.d.ts.map +1 -0
- package/lib/typescript/storage/utils/storageQueryUtils.d.ts +6 -0
- package/lib/typescript/storage/utils/storageQueryUtils.d.ts.map +1 -0
- package/lib/typescript/storage/utils/valueType.d.ts +3 -0
- package/lib/typescript/storage/utils/valueType.d.ts.map +1 -0
- package/package.json +68 -0
|
@@ -0,0 +1,924 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.FREE_TIER_KEY_LIMIT = void 0;
|
|
7
|
+
exports.GameUIStorageBrowser = GameUIStorageBrowser;
|
|
8
|
+
var _react = require("react");
|
|
9
|
+
var _reactNative = require("react-native");
|
|
10
|
+
var _sharedUi = require("@buoy-gg/shared-ui");
|
|
11
|
+
var _StorageKeySection = require("./StorageKeySection");
|
|
12
|
+
var _StorageFilterCards = require("./StorageFilterCards");
|
|
13
|
+
var _useAsyncStorageKeys = require("../hooks/useAsyncStorageKeys");
|
|
14
|
+
var _AsyncStorageListener = require("../utils/AsyncStorageListener");
|
|
15
|
+
var _useMMKVKeys = require("../hooks/useMMKVKeys");
|
|
16
|
+
var _useMMKVInstances = require("../hooks/useMMKVInstances");
|
|
17
|
+
var _mmkvAvailability = require("../utils/mmkvAvailability");
|
|
18
|
+
var _StorageActionButtons = require("./StorageActionButtons");
|
|
19
|
+
var _SelectionActionBar = require("./SelectionActionBar");
|
|
20
|
+
var _jsxRuntime = require("react/jsx-runtime");
|
|
21
|
+
// Conditionally import MMKV listener
|
|
22
|
+
let addMMKVListener;
|
|
23
|
+
if ((0, _mmkvAvailability.isMMKVAvailable)()) {
|
|
24
|
+
const listener = require("../utils/MMKVListener");
|
|
25
|
+
addMMKVListener = listener.addMMKVListener;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Import shared Game UI components
|
|
29
|
+
|
|
30
|
+
// Lazy load the license hooks to avoid circular dependencies
|
|
31
|
+
let _useIsPro = null;
|
|
32
|
+
let _licenseLoadAttempted = false;
|
|
33
|
+
function loadLicenseModule() {
|
|
34
|
+
if (_licenseLoadAttempted) return;
|
|
35
|
+
_licenseLoadAttempted = true;
|
|
36
|
+
try {
|
|
37
|
+
const mod = require("@buoy-gg/license");
|
|
38
|
+
if (mod) {
|
|
39
|
+
_useIsPro = mod.useIsPro ?? null;
|
|
40
|
+
}
|
|
41
|
+
} catch {
|
|
42
|
+
// License package not available
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function getUseIsPro() {
|
|
46
|
+
loadLicenseModule();
|
|
47
|
+
return _useIsPro ?? (() => false);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// MMKV Instance color palette - consistent colors per instance
|
|
51
|
+
const INSTANCE_COLORS = [_sharedUi.macOSColors.semantic.info,
|
|
52
|
+
// Blue
|
|
53
|
+
_sharedUi.macOSColors.semantic.success,
|
|
54
|
+
// Green
|
|
55
|
+
_sharedUi.macOSColors.semantic.warning,
|
|
56
|
+
// Orange
|
|
57
|
+
_sharedUi.macOSColors.semantic.debug,
|
|
58
|
+
// Purple
|
|
59
|
+
'#FF6B9D',
|
|
60
|
+
// Pink
|
|
61
|
+
'#00D9FF' // Cyan
|
|
62
|
+
];
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Get consistent color for an MMKV instance based on its ID
|
|
66
|
+
* Uses simple hash to ensure same instance always gets same color
|
|
67
|
+
*/
|
|
68
|
+
function getInstanceColor(instanceId) {
|
|
69
|
+
const hash = instanceId.split('').reduce((acc, char) => acc + char.charCodeAt(0), 0);
|
|
70
|
+
return INSTANCE_COLORS[hash % INSTANCE_COLORS.length];
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** Free tier limit for storage keys */
|
|
74
|
+
const FREE_TIER_KEY_LIMIT = exports.FREE_TIER_KEY_LIMIT = 25;
|
|
75
|
+
function GameUIStorageBrowser({
|
|
76
|
+
requiredStorageKeys = [],
|
|
77
|
+
showFilters = false,
|
|
78
|
+
ignoredPatterns = new Set(["@react_buoy"]),
|
|
79
|
+
onTogglePattern,
|
|
80
|
+
onAddPattern,
|
|
81
|
+
searchQuery = "",
|
|
82
|
+
storageDataRef
|
|
83
|
+
}) {
|
|
84
|
+
// Check Pro status internally
|
|
85
|
+
const useIsPro = getUseIsPro();
|
|
86
|
+
const isPro = useIsPro();
|
|
87
|
+
const [showUpgradeModal, setShowUpgradeModal] = (0, _react.useState)(false);
|
|
88
|
+
const [activeFilter, setActiveFilter] = (0, _react.useState)("all");
|
|
89
|
+
const [activeStorageType, setActiveStorageType] = (0, _react.useState)("all");
|
|
90
|
+
const [selectedMMKVInstance, setSelectedMMKVInstance] = (0, _react.useState)(null);
|
|
91
|
+
|
|
92
|
+
// Selection mode state
|
|
93
|
+
const [isSelectMode, setIsSelectMode] = (0, _react.useState)(false);
|
|
94
|
+
const [selectedKeyIds, setSelectedKeyIds] = (0, _react.useState)(new Set());
|
|
95
|
+
|
|
96
|
+
// Get all MMKV instances
|
|
97
|
+
const {
|
|
98
|
+
instances: mmkvInstances
|
|
99
|
+
} = (0, _useMMKVInstances.useMMKVInstances)(false);
|
|
100
|
+
|
|
101
|
+
// REMOVED: Auto-selection is now handled by the instance navbar
|
|
102
|
+
// Users can manually select an instance from the navbar if they want to filter by instance
|
|
103
|
+
// By default, selectedMMKVInstance is null, which shows ALL MMKV keys
|
|
104
|
+
|
|
105
|
+
// Use AsyncStorage hook
|
|
106
|
+
const {
|
|
107
|
+
storageKeys: asyncStorageKeys,
|
|
108
|
+
isLoading: isLoadingAsync,
|
|
109
|
+
error: asyncError,
|
|
110
|
+
refresh: refreshAsync
|
|
111
|
+
} = (0, _useAsyncStorageKeys.useAsyncStorageKeys)(requiredStorageKeys);
|
|
112
|
+
|
|
113
|
+
// Memoize the instances array to prevent infinite re-renders
|
|
114
|
+
const mmkvInstancesForHook = (0, _react.useMemo)(() => mmkvInstances.map(inst => ({
|
|
115
|
+
instance: inst.instance,
|
|
116
|
+
id: inst.id
|
|
117
|
+
})), [mmkvInstances]);
|
|
118
|
+
|
|
119
|
+
// Use MMKV hook - always fetch from ALL instances, then filter by selected instance
|
|
120
|
+
const {
|
|
121
|
+
storageKeys: allMMKVKeys,
|
|
122
|
+
isLoading: isLoadingMMKV,
|
|
123
|
+
error: mmkvError,
|
|
124
|
+
refresh: refreshMMKV
|
|
125
|
+
} = (0, _useMMKVKeys.useMultiMMKVKeys)(mmkvInstancesForHook, requiredStorageKeys);
|
|
126
|
+
|
|
127
|
+
// Filter MMKV keys by selected instance (if one is selected)
|
|
128
|
+
const mmkvStorageKeys = (0, _react.useMemo)(() => {
|
|
129
|
+
if (!selectedMMKVInstance) {
|
|
130
|
+
return allMMKVKeys; // Show all MMKV keys
|
|
131
|
+
}
|
|
132
|
+
return allMMKVKeys.filter(k => k.instanceId === selectedMMKVInstance);
|
|
133
|
+
}, [allMMKVKeys, selectedMMKVInstance]);
|
|
134
|
+
|
|
135
|
+
// Merge storage keys from AsyncStorage and MMKV
|
|
136
|
+
const allStorageKeys = (0, _react.useMemo)(() => {
|
|
137
|
+
return [...asyncStorageKeys, ...mmkvStorageKeys];
|
|
138
|
+
}, [asyncStorageKeys, mmkvStorageKeys]);
|
|
139
|
+
|
|
140
|
+
// Determine loading and error states
|
|
141
|
+
const isLoading = isLoadingAsync || isLoadingMMKV;
|
|
142
|
+
const error = asyncError || mmkvError;
|
|
143
|
+
|
|
144
|
+
// Combined refresh function
|
|
145
|
+
const refresh = (0, _react.useCallback)(() => {
|
|
146
|
+
refreshAsync();
|
|
147
|
+
refreshMMKV();
|
|
148
|
+
}, [refreshAsync, refreshMMKV]);
|
|
149
|
+
|
|
150
|
+
// Generate unique identifier for a storage key
|
|
151
|
+
const getKeyIdentifier = (0, _react.useCallback)(storageKey => {
|
|
152
|
+
return storageKey.instanceId ? `${storageKey.storageType}-${storageKey.instanceId}-${storageKey.key}` : `${storageKey.storageType}-${storageKey.key}`;
|
|
153
|
+
}, []);
|
|
154
|
+
|
|
155
|
+
// Toggle select mode
|
|
156
|
+
const handleToggleSelectMode = (0, _react.useCallback)(() => {
|
|
157
|
+
setIsSelectMode(prev => {
|
|
158
|
+
if (prev) {
|
|
159
|
+
// When exiting select mode, clear selection
|
|
160
|
+
setSelectedKeyIds(new Set());
|
|
161
|
+
}
|
|
162
|
+
return !prev;
|
|
163
|
+
});
|
|
164
|
+
}, []);
|
|
165
|
+
|
|
166
|
+
// Handle selection change for a single key
|
|
167
|
+
const handleSelectionChange = (0, _react.useCallback)((storageKey, selected) => {
|
|
168
|
+
const keyId = getKeyIdentifier(storageKey);
|
|
169
|
+
setSelectedKeyIds(prev => {
|
|
170
|
+
const newSet = new Set(prev);
|
|
171
|
+
if (selected) {
|
|
172
|
+
newSet.add(keyId);
|
|
173
|
+
} else {
|
|
174
|
+
newSet.delete(keyId);
|
|
175
|
+
}
|
|
176
|
+
return newSet;
|
|
177
|
+
});
|
|
178
|
+
}, [getKeyIdentifier]);
|
|
179
|
+
|
|
180
|
+
// Clear selection and exit select mode after deletion
|
|
181
|
+
const handleDeleteComplete = (0, _react.useCallback)(() => {
|
|
182
|
+
setSelectedKeyIds(new Set());
|
|
183
|
+
setIsSelectMode(false);
|
|
184
|
+
refresh();
|
|
185
|
+
}, [refresh]);
|
|
186
|
+
|
|
187
|
+
// Memoized export data for copy functionality
|
|
188
|
+
const copyExportData = (0, _react.useMemo)(() => {
|
|
189
|
+
const allKeys = allStorageKeys;
|
|
190
|
+
|
|
191
|
+
// Calculate stats
|
|
192
|
+
const stats = {
|
|
193
|
+
valid: allKeys.filter(k => k.status === 'required_present' || k.status === 'optional_present').length,
|
|
194
|
+
missing: allKeys.filter(k => k.status === 'required_missing').length,
|
|
195
|
+
issues: allKeys.filter(k => k.status === 'required_wrong_value' || k.status === 'required_wrong_type').length,
|
|
196
|
+
total: allKeys.length
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
// Group by storage type
|
|
200
|
+
const asyncKeys = allKeys.filter(k => k.storageType === 'async');
|
|
201
|
+
const mmkvKeys = allKeys.filter(k => k.storageType === 'mmkv');
|
|
202
|
+
const secureKeys = allKeys.filter(k => k.storageType === 'secure');
|
|
203
|
+
|
|
204
|
+
// Build structured export
|
|
205
|
+
return {
|
|
206
|
+
summary: {
|
|
207
|
+
valid: stats.valid,
|
|
208
|
+
missing: stats.missing,
|
|
209
|
+
issues: stats.issues,
|
|
210
|
+
total: stats.total,
|
|
211
|
+
timestamp: new Date().toISOString()
|
|
212
|
+
},
|
|
213
|
+
asyncStorage: asyncKeys.reduce((acc, k) => {
|
|
214
|
+
acc[k.key] = k.value;
|
|
215
|
+
return acc;
|
|
216
|
+
}, {}),
|
|
217
|
+
mmkv: mmkvKeys.reduce((acc, k) => {
|
|
218
|
+
const instanceId = k.instanceId || 'default';
|
|
219
|
+
if (!acc[instanceId]) acc[instanceId] = {};
|
|
220
|
+
acc[instanceId][k.key] = k.value;
|
|
221
|
+
return acc;
|
|
222
|
+
}, {}),
|
|
223
|
+
secure: secureKeys.reduce((acc, k) => {
|
|
224
|
+
acc[k.key] = k.value;
|
|
225
|
+
return acc;
|
|
226
|
+
}, {})
|
|
227
|
+
};
|
|
228
|
+
}, [allStorageKeys]);
|
|
229
|
+
|
|
230
|
+
// Update storage data ref for copy functionality
|
|
231
|
+
(0, _react.useEffect)(() => {
|
|
232
|
+
if (storageDataRef) {
|
|
233
|
+
storageDataRef.current = allStorageKeys;
|
|
234
|
+
}
|
|
235
|
+
}, [allStorageKeys, storageDataRef]);
|
|
236
|
+
|
|
237
|
+
// Auto-refresh on storage events (AsyncStorage)
|
|
238
|
+
(0, _react.useEffect)(() => {
|
|
239
|
+
let timeoutId;
|
|
240
|
+
const unsubscribe = (0, _AsyncStorageListener.addListener)(event => {
|
|
241
|
+
clearTimeout(timeoutId);
|
|
242
|
+
timeoutId = setTimeout(() => {
|
|
243
|
+
refreshAsync(); // Auto-refresh AsyncStorage when it changes
|
|
244
|
+
}, 100); // 100ms debounce
|
|
245
|
+
});
|
|
246
|
+
return () => {
|
|
247
|
+
clearTimeout(timeoutId);
|
|
248
|
+
unsubscribe();
|
|
249
|
+
};
|
|
250
|
+
}, [refreshAsync]);
|
|
251
|
+
|
|
252
|
+
// Auto-refresh on MMKV storage events (only if MMKV is available)
|
|
253
|
+
(0, _react.useEffect)(() => {
|
|
254
|
+
if (!(0, _mmkvAvailability.isMMKVAvailable)() || !addMMKVListener) {
|
|
255
|
+
return; // Skip if MMKV not available
|
|
256
|
+
}
|
|
257
|
+
let timeoutId;
|
|
258
|
+
const unsubscribe = addMMKVListener(event => {
|
|
259
|
+
// Only refresh if event is for the selected instance
|
|
260
|
+
if (event.instanceId === selectedMMKVInstance) {
|
|
261
|
+
clearTimeout(timeoutId);
|
|
262
|
+
timeoutId = setTimeout(() => {
|
|
263
|
+
refreshMMKV(); // Auto-refresh MMKV when it changes
|
|
264
|
+
}, 100); // 100ms debounce
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
return () => {
|
|
268
|
+
clearTimeout(timeoutId);
|
|
269
|
+
unsubscribe();
|
|
270
|
+
};
|
|
271
|
+
}, [refreshMMKV, selectedMMKVInstance]);
|
|
272
|
+
|
|
273
|
+
// Calculate stats from ALL keys (not filtered) - base stats for display
|
|
274
|
+
const stats = (0, _react.useMemo)(() => {
|
|
275
|
+
const allKeys = allStorageKeys;
|
|
276
|
+
const appKeys = allKeys.filter(k => !(0, _sharedUi.isDevToolsStorageKey)(k.key));
|
|
277
|
+
const devKeys = allKeys.filter(k => (0, _sharedUi.isDevToolsStorageKey)(k.key));
|
|
278
|
+
const storageStats = {
|
|
279
|
+
totalCount: allKeys.length,
|
|
280
|
+
requiredCount: appKeys.filter(k => k.category === "required").length,
|
|
281
|
+
missingCount: appKeys.filter(k => k.status === "required_missing").length,
|
|
282
|
+
wrongValueCount: appKeys.filter(k => k.status === "required_wrong_value").length,
|
|
283
|
+
wrongTypeCount: appKeys.filter(k => k.status === "required_wrong_type").length,
|
|
284
|
+
presentRequiredCount: appKeys.filter(k => k.status === "required_present").length,
|
|
285
|
+
optionalCount: appKeys.filter(k => k.category === "optional").length,
|
|
286
|
+
// Count keys by their actual storageType property
|
|
287
|
+
mmkvCount: allKeys.filter(k => k.storageType === "mmkv").length,
|
|
288
|
+
asyncCount: allKeys.filter(k => k.storageType === "async").length,
|
|
289
|
+
secureCount: allKeys.filter(k => k.storageType === "secure").length,
|
|
290
|
+
devToolsCount: devKeys.length
|
|
291
|
+
};
|
|
292
|
+
return storageStats;
|
|
293
|
+
}, [allStorageKeys]);
|
|
294
|
+
|
|
295
|
+
// Calculate stats for tab badges based on current filters
|
|
296
|
+
const tabStats = (0, _react.useMemo)(() => {
|
|
297
|
+
// Start with all keys, excluding devtools keys
|
|
298
|
+
let keysForStats = allStorageKeys.filter(k => !(0, _sharedUi.isDevToolsStorageKey)(k.key));
|
|
299
|
+
|
|
300
|
+
// If a specific storage type is selected, filter by that type first
|
|
301
|
+
if (activeStorageType !== "all") {
|
|
302
|
+
keysForStats = keysForStats.filter(k => k.storageType === activeStorageType);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// Calculate status counts from filtered keys
|
|
306
|
+
const validCount = keysForStats.filter(k => k.status === "required_present" || k.status === "optional_present").length;
|
|
307
|
+
const missingCount = keysForStats.filter(k => k.status === "required_missing").length;
|
|
308
|
+
const issuesCount = keysForStats.filter(k => k.status === "required_wrong_type" || k.status === "required_wrong_value").length;
|
|
309
|
+
|
|
310
|
+
// Calculate storage type counts based on active status filter
|
|
311
|
+
let asyncCount = 0;
|
|
312
|
+
let mmkvCount = 0;
|
|
313
|
+
let secureCount = 0;
|
|
314
|
+
let totalCount = 0;
|
|
315
|
+
if (activeFilter === "all") {
|
|
316
|
+
// Valid: only keys with valid status
|
|
317
|
+
asyncCount = allStorageKeys.filter(k => !(0, _sharedUi.isDevToolsStorageKey)(k.key) && k.storageType === "async" && (k.status === "required_present" || k.status === "optional_present")).length;
|
|
318
|
+
mmkvCount = allStorageKeys.filter(k => !(0, _sharedUi.isDevToolsStorageKey)(k.key) && k.storageType === "mmkv" && (k.status === "required_present" || k.status === "optional_present")).length;
|
|
319
|
+
secureCount = allStorageKeys.filter(k => !(0, _sharedUi.isDevToolsStorageKey)(k.key) && k.storageType === "secure" && (k.status === "required_present" || k.status === "optional_present")).length;
|
|
320
|
+
totalCount = asyncCount + mmkvCount + secureCount;
|
|
321
|
+
} else if (activeFilter === "missing") {
|
|
322
|
+
// Missing: only keys with missing status
|
|
323
|
+
asyncCount = allStorageKeys.filter(k => !(0, _sharedUi.isDevToolsStorageKey)(k.key) && k.storageType === "async" && k.status === "required_missing").length;
|
|
324
|
+
mmkvCount = allStorageKeys.filter(k => !(0, _sharedUi.isDevToolsStorageKey)(k.key) && k.storageType === "mmkv" && k.status === "required_missing").length;
|
|
325
|
+
secureCount = allStorageKeys.filter(k => !(0, _sharedUi.isDevToolsStorageKey)(k.key) && k.storageType === "secure" && k.status === "required_missing").length;
|
|
326
|
+
totalCount = asyncCount + mmkvCount + secureCount;
|
|
327
|
+
} else if (activeFilter === "issues") {
|
|
328
|
+
// Issues: only keys with issue status
|
|
329
|
+
asyncCount = allStorageKeys.filter(k => !(0, _sharedUi.isDevToolsStorageKey)(k.key) && k.storageType === "async" && (k.status === "required_wrong_type" || k.status === "required_wrong_value")).length;
|
|
330
|
+
mmkvCount = allStorageKeys.filter(k => !(0, _sharedUi.isDevToolsStorageKey)(k.key) && k.storageType === "mmkv" && (k.status === "required_wrong_type" || k.status === "required_wrong_value")).length;
|
|
331
|
+
secureCount = allStorageKeys.filter(k => !(0, _sharedUi.isDevToolsStorageKey)(k.key) && k.storageType === "secure" && (k.status === "required_wrong_type" || k.status === "required_wrong_value")).length;
|
|
332
|
+
totalCount = asyncCount + mmkvCount + secureCount;
|
|
333
|
+
}
|
|
334
|
+
return {
|
|
335
|
+
validCount,
|
|
336
|
+
missingCount,
|
|
337
|
+
issuesCount,
|
|
338
|
+
asyncCount,
|
|
339
|
+
mmkvCount,
|
|
340
|
+
secureCount,
|
|
341
|
+
totalCount
|
|
342
|
+
};
|
|
343
|
+
}, [allStorageKeys, activeFilter, activeStorageType]);
|
|
344
|
+
|
|
345
|
+
// Sort all keys by priority (issues first)
|
|
346
|
+
const sortedKeys = (0, _react.useMemo)(() => {
|
|
347
|
+
// Sort by status priority: errors first, then warnings, then valid
|
|
348
|
+
return [...allStorageKeys].sort((a, b) => {
|
|
349
|
+
const priorityMap = {
|
|
350
|
+
required_missing: 1,
|
|
351
|
+
required_wrong_type: 2,
|
|
352
|
+
required_wrong_value: 3,
|
|
353
|
+
required_present: 4,
|
|
354
|
+
optional_present: 5
|
|
355
|
+
};
|
|
356
|
+
return (priorityMap[a.status] || 999) - (priorityMap[b.status] || 999);
|
|
357
|
+
});
|
|
358
|
+
}, [allStorageKeys]);
|
|
359
|
+
|
|
360
|
+
// Get all unique keys for filter suggestions
|
|
361
|
+
const allUniqueKeys = (0, _react.useMemo)(() => {
|
|
362
|
+
return Array.from(new Set(allStorageKeys.map(k => k.key))).sort();
|
|
363
|
+
}, [allStorageKeys]);
|
|
364
|
+
|
|
365
|
+
// Filter keys based on active filter, storage type, ignored patterns, and search
|
|
366
|
+
const filteredKeys = (0, _react.useMemo)(() => {
|
|
367
|
+
let keys = sortedKeys;
|
|
368
|
+
|
|
369
|
+
// Apply ignored pattern filter first
|
|
370
|
+
keys = keys.filter(k => {
|
|
371
|
+
// Check if key matches any ignored pattern
|
|
372
|
+
const shouldIgnore = Array.from(ignoredPatterns).some(pattern => k.key.includes(pattern));
|
|
373
|
+
return !shouldIgnore;
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
// Apply search filter
|
|
377
|
+
if (searchQuery) {
|
|
378
|
+
const query = searchQuery.toLowerCase();
|
|
379
|
+
keys = keys.filter(k => k.key.toLowerCase().includes(query));
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// Apply status filter
|
|
383
|
+
switch (activeFilter) {
|
|
384
|
+
case "all":
|
|
385
|
+
// "All" (Valid) shows only keys without issues
|
|
386
|
+
keys = keys.filter(k => k.status === "required_present" || k.status === "optional_present");
|
|
387
|
+
break;
|
|
388
|
+
case "missing":
|
|
389
|
+
keys = keys.filter(k => k.status === "required_missing");
|
|
390
|
+
break;
|
|
391
|
+
case "issues":
|
|
392
|
+
keys = keys.filter(k => k.status === "required_wrong_type" || k.status === "required_wrong_value");
|
|
393
|
+
break;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// Apply storage type filter
|
|
397
|
+
if (activeStorageType !== "all") {
|
|
398
|
+
keys = keys.filter(k => k.storageType === activeStorageType);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
// NOTE: MMKV instance filtering is now handled in mmkvStorageKeys memo (line 128)
|
|
402
|
+
// No need to filter again here
|
|
403
|
+
|
|
404
|
+
return keys;
|
|
405
|
+
}, [sortedKeys, activeFilter, activeStorageType, ignoredPatterns, searchQuery, selectedMMKVInstance]);
|
|
406
|
+
|
|
407
|
+
// For free users, limit visible keys to FREE_TIER_KEY_LIMIT
|
|
408
|
+
const visibleKeys = (0, _react.useMemo)(() => {
|
|
409
|
+
if (isPro) return filteredKeys;
|
|
410
|
+
return filteredKeys.slice(0, FREE_TIER_KEY_LIMIT);
|
|
411
|
+
}, [filteredKeys, isPro]);
|
|
412
|
+
|
|
413
|
+
// Calculate how many keys are locked (only those matching current filter)
|
|
414
|
+
const lockedKeyCount = (0, _react.useMemo)(() => {
|
|
415
|
+
if (isPro) return 0;
|
|
416
|
+
return Math.max(0, filteredKeys.length - FREE_TIER_KEY_LIMIT);
|
|
417
|
+
}, [filteredKeys.length, isPro]);
|
|
418
|
+
const hasLockedKeys = lockedKeyCount > 0;
|
|
419
|
+
|
|
420
|
+
// Calculate stats from FILTERED keys to show actual visible counts
|
|
421
|
+
const filteredStats = (0, _react.useMemo)(() => {
|
|
422
|
+
const appKeys = filteredKeys.filter(k => !(0, _sharedUi.isDevToolsStorageKey)(k.key));
|
|
423
|
+
const storageStats = {
|
|
424
|
+
totalCount: filteredKeys.length,
|
|
425
|
+
requiredCount: appKeys.filter(k => k.category === "required").length,
|
|
426
|
+
missingCount: appKeys.filter(k => k.status === "required_missing").length,
|
|
427
|
+
wrongValueCount: appKeys.filter(k => k.status === "required_wrong_value").length,
|
|
428
|
+
wrongTypeCount: appKeys.filter(k => k.status === "required_wrong_type").length,
|
|
429
|
+
presentRequiredCount: appKeys.filter(k => k.status === "required_present").length,
|
|
430
|
+
optionalCount: appKeys.filter(k => k.category === "optional").length,
|
|
431
|
+
mmkvCount: filteredKeys.filter(k => k.storageType === "mmkv").length,
|
|
432
|
+
asyncCount: filteredKeys.filter(k => k.storageType === "async").length,
|
|
433
|
+
secureCount: filteredKeys.filter(k => k.storageType === "secure").length,
|
|
434
|
+
devToolsCount: filteredKeys.filter(k => (0, _sharedUi.isDevToolsStorageKey)(k.key)).length
|
|
435
|
+
};
|
|
436
|
+
return storageStats;
|
|
437
|
+
}, [filteredKeys]);
|
|
438
|
+
|
|
439
|
+
// Get selected keys as StorageKeyInfo objects (from visible keys only)
|
|
440
|
+
const selectedKeysInfo = (0, _react.useMemo)(() => {
|
|
441
|
+
return visibleKeys.filter(key => selectedKeyIds.has(getKeyIdentifier(key)));
|
|
442
|
+
}, [visibleKeys, selectedKeyIds, getKeyIdentifier]);
|
|
443
|
+
|
|
444
|
+
// Select all visible keys (only unlocked keys can be selected)
|
|
445
|
+
const handleSelectAll = (0, _react.useCallback)(() => {
|
|
446
|
+
const allIds = new Set(visibleKeys.map(getKeyIdentifier));
|
|
447
|
+
setSelectedKeyIds(allIds);
|
|
448
|
+
}, [visibleKeys, getKeyIdentifier]);
|
|
449
|
+
|
|
450
|
+
// Clear all selections
|
|
451
|
+
const handleClearSelection = (0, _react.useCallback)(() => {
|
|
452
|
+
setSelectedKeyIds(new Set());
|
|
453
|
+
}, []);
|
|
454
|
+
|
|
455
|
+
// Calculate health percentage
|
|
456
|
+
const healthPercentage = stats.requiredCount > 0 ? Math.round(stats.presentRequiredCount / stats.requiredCount * 100) : stats.totalCount > 0 ? 100 : 0;
|
|
457
|
+
const healthStatus = healthPercentage >= 90 ? "OPTIMAL" : healthPercentage >= 70 ? "WARNING" : "CRITICAL";
|
|
458
|
+
const healthColor = healthPercentage >= 90 ? _sharedUi.gameUIColors.success : healthPercentage >= 70 ? _sharedUi.gameUIColors.warning : _sharedUi.gameUIColors.error;
|
|
459
|
+
|
|
460
|
+
// Loading state
|
|
461
|
+
if (isLoading && allStorageKeys.length === 0) {
|
|
462
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
463
|
+
style: styles.emptyState,
|
|
464
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Database, {
|
|
465
|
+
size: 48,
|
|
466
|
+
color: _sharedUi.macOSColors.text.muted
|
|
467
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
468
|
+
style: styles.emptyTitle,
|
|
469
|
+
children: "Loading storage keys..."
|
|
470
|
+
})]
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
// Error state
|
|
475
|
+
if (error) {
|
|
476
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
477
|
+
style: styles.emptyState,
|
|
478
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Database, {
|
|
479
|
+
size: 48,
|
|
480
|
+
color: _sharedUi.gameUIColors.error
|
|
481
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
482
|
+
style: [styles.emptyTitle, {
|
|
483
|
+
color: _sharedUi.gameUIColors.error
|
|
484
|
+
}],
|
|
485
|
+
children: "Error loading storage"
|
|
486
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
487
|
+
style: styles.emptySubtitle,
|
|
488
|
+
children: error.message
|
|
489
|
+
})]
|
|
490
|
+
});
|
|
491
|
+
}
|
|
492
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.ScrollView, {
|
|
493
|
+
style: styles.scrollContainer,
|
|
494
|
+
contentContainerStyle: styles.container,
|
|
495
|
+
showsVerticalScrollIndicator: false,
|
|
496
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
497
|
+
style: styles.backgroundGrid
|
|
498
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_StorageFilterCards.StorageFilterCards, {
|
|
499
|
+
stats: stats,
|
|
500
|
+
tabStats: tabStats,
|
|
501
|
+
healthPercentage: healthPercentage,
|
|
502
|
+
healthStatus: healthStatus,
|
|
503
|
+
healthColor: healthColor,
|
|
504
|
+
activeFilter: activeFilter,
|
|
505
|
+
onFilterChange: setActiveFilter,
|
|
506
|
+
activeStorageType: activeStorageType,
|
|
507
|
+
onStorageTypeChange: setActiveStorageType
|
|
508
|
+
}), activeStorageType === "mmkv" && mmkvInstances.length === 0 && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
509
|
+
style: styles.emptyMMKVState,
|
|
510
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
511
|
+
style: styles.emptyMMKVTitle,
|
|
512
|
+
children: "No MMKV Instances Detected"
|
|
513
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
514
|
+
style: styles.emptyMMKVSubtitle,
|
|
515
|
+
children: "MMKV instances must be registered with registerMMKVInstance()"
|
|
516
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
517
|
+
style: styles.emptyMMKVCode,
|
|
518
|
+
children: `import { registerMMKVInstance } from '@buoy-gg/storage';\n\nconst storage = createMMKV();\nregisterMMKVInstance('mmkv.default', storage);`
|
|
519
|
+
})]
|
|
520
|
+
}), activeStorageType === "mmkv" && mmkvInstances.length > 0 && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
521
|
+
style: styles.instanceNavbar,
|
|
522
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
523
|
+
style: styles.instanceNavbarHeader,
|
|
524
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
525
|
+
style: styles.instanceNavbarLabel,
|
|
526
|
+
children: "INSTANCES"
|
|
527
|
+
}), !isPro && mmkvInstances.length > 1 && /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ProBadge, {
|
|
528
|
+
style: {
|
|
529
|
+
transform: [{
|
|
530
|
+
scale: 0.85
|
|
531
|
+
}]
|
|
532
|
+
}
|
|
533
|
+
})]
|
|
534
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.ScrollView, {
|
|
535
|
+
horizontal: true,
|
|
536
|
+
showsHorizontalScrollIndicator: false,
|
|
537
|
+
contentContainerStyle: styles.instanceNavbarScroll,
|
|
538
|
+
children: [(isPro || mmkvInstances.length === 1) && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
|
|
539
|
+
onPress: () => setSelectedMMKVInstance(null),
|
|
540
|
+
style: [styles.instanceNavbarButton, selectedMMKVInstance === null && styles.instanceNavbarButtonActive],
|
|
541
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.HardDrive, {
|
|
542
|
+
size: 12,
|
|
543
|
+
color: selectedMMKVInstance === null ? _sharedUi.macOSColors.text.primary : _sharedUi.macOSColors.text.secondary
|
|
544
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
545
|
+
style: [styles.instanceNavbarButtonText, selectedMMKVInstance === null && styles.instanceNavbarButtonTextActive],
|
|
546
|
+
children: "All"
|
|
547
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
548
|
+
style: styles.instanceNavbarBadge,
|
|
549
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
550
|
+
style: styles.instanceNavbarBadgeText,
|
|
551
|
+
children: mmkvInstances.reduce((sum, inst) => sum + inst.keyCount, 0)
|
|
552
|
+
})
|
|
553
|
+
})]
|
|
554
|
+
}), mmkvInstances.map((inst, index) => {
|
|
555
|
+
const isLocked = !isPro && index > 0;
|
|
556
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
|
|
557
|
+
onPress: () => {
|
|
558
|
+
if (isLocked) {
|
|
559
|
+
setShowUpgradeModal(true);
|
|
560
|
+
} else {
|
|
561
|
+
setSelectedMMKVInstance(inst.id);
|
|
562
|
+
}
|
|
563
|
+
},
|
|
564
|
+
style: [styles.instanceNavbarButton, inst.id === selectedMMKVInstance && styles.instanceNavbarButtonActive, {
|
|
565
|
+
borderColor: isLocked ? _sharedUi.macOSColors.border.default : getInstanceColor(inst.id) + '40',
|
|
566
|
+
backgroundColor: inst.id === selectedMMKVInstance ? getInstanceColor(inst.id) + '20' : _sharedUi.macOSColors.background.card,
|
|
567
|
+
opacity: isLocked ? 0.5 : 1
|
|
568
|
+
}],
|
|
569
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.HardDrive, {
|
|
570
|
+
size: 12,
|
|
571
|
+
color: inst.id === selectedMMKVInstance ? getInstanceColor(inst.id) : _sharedUi.macOSColors.text.secondary
|
|
572
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
573
|
+
style: [styles.instanceNavbarButtonText, inst.id === selectedMMKVInstance && {
|
|
574
|
+
color: getInstanceColor(inst.id),
|
|
575
|
+
fontWeight: '700'
|
|
576
|
+
}],
|
|
577
|
+
children: inst.id
|
|
578
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
579
|
+
style: [styles.instanceNavbarBadge, inst.id === selectedMMKVInstance && {
|
|
580
|
+
backgroundColor: getInstanceColor(inst.id) + '30'
|
|
581
|
+
}],
|
|
582
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
583
|
+
style: [styles.instanceNavbarBadgeText, inst.id === selectedMMKVInstance && {
|
|
584
|
+
color: getInstanceColor(inst.id)
|
|
585
|
+
}],
|
|
586
|
+
children: inst.keyCount
|
|
587
|
+
})
|
|
588
|
+
})]
|
|
589
|
+
}, inst.id);
|
|
590
|
+
})]
|
|
591
|
+
})]
|
|
592
|
+
}), filteredKeys.length > 0 ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
593
|
+
style: styles.keysSection,
|
|
594
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
595
|
+
style: styles.sectionHeader,
|
|
596
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
597
|
+
style: styles.sectionHeaderLeft,
|
|
598
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
|
|
599
|
+
style: styles.sectionTitle,
|
|
600
|
+
children: [activeFilter === "all" ? "KEYS" : activeFilter === "missing" ? "MISSING KEYS" : "ISSUES TO FIX", activeStorageType !== "all" && ` (${activeStorageType.toUpperCase()})`]
|
|
601
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
602
|
+
style: styles.countBadge,
|
|
603
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
604
|
+
style: styles.countText,
|
|
605
|
+
children: visibleKeys.length
|
|
606
|
+
})
|
|
607
|
+
})]
|
|
608
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_StorageActionButtons.StorageActionButtons, {
|
|
609
|
+
copyValue: copyExportData,
|
|
610
|
+
mmkvInstances: mmkvInstances.map(inst => ({
|
|
611
|
+
id: inst.id,
|
|
612
|
+
instance: inst.instance
|
|
613
|
+
})),
|
|
614
|
+
activeStorageType: activeStorageType,
|
|
615
|
+
onClearComplete: refresh,
|
|
616
|
+
isSelectMode: isSelectMode,
|
|
617
|
+
onToggleSelectMode: handleToggleSelectMode,
|
|
618
|
+
selectedCount: selectedKeyIds.size
|
|
619
|
+
})]
|
|
620
|
+
}), isSelectMode && /*#__PURE__*/(0, _jsxRuntime.jsx)(_SelectionActionBar.SelectionActionBar, {
|
|
621
|
+
selectedKeys: selectedKeysInfo,
|
|
622
|
+
mmkvInstances: mmkvInstances.map(inst => ({
|
|
623
|
+
id: inst.id,
|
|
624
|
+
instance: inst.instance
|
|
625
|
+
})),
|
|
626
|
+
onDeleteComplete: handleDeleteComplete,
|
|
627
|
+
onSelectAll: handleSelectAll,
|
|
628
|
+
onClearSelection: handleClearSelection,
|
|
629
|
+
totalVisibleKeys: visibleKeys.length
|
|
630
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_StorageKeySection.StorageKeySection, {
|
|
631
|
+
title: "",
|
|
632
|
+
count: -1,
|
|
633
|
+
keys: visibleKeys,
|
|
634
|
+
emptyMessage: "",
|
|
635
|
+
isSelectMode: isSelectMode,
|
|
636
|
+
selectedKeys: selectedKeyIds,
|
|
637
|
+
onSelectionChange: handleSelectionChange
|
|
638
|
+
}), hasLockedKeys && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
|
|
639
|
+
style: styles.limitBanner,
|
|
640
|
+
onPress: () => setShowUpgradeModal(true),
|
|
641
|
+
activeOpacity: 0.8,
|
|
642
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
643
|
+
style: styles.limitBannerContent,
|
|
644
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
645
|
+
style: styles.limitBannerLeft,
|
|
646
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Zap, {
|
|
647
|
+
size: 16,
|
|
648
|
+
color: "#20C997"
|
|
649
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
650
|
+
style: styles.limitBannerText,
|
|
651
|
+
children: searchQuery ? `${lockedKeyCount} matching ${lockedKeyCount === 1 ? 'key' : 'keys'} in locked storage` : `${lockedKeyCount} keys locked`
|
|
652
|
+
})]
|
|
653
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ProBadge, {})]
|
|
654
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
655
|
+
style: styles.limitBannerSubtext,
|
|
656
|
+
children: searchQuery ? "Upgrade to Pro to search your full storage" : "Upgrade to Pro to unlock full storage access"
|
|
657
|
+
})]
|
|
658
|
+
})]
|
|
659
|
+
}) : /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
660
|
+
style: styles.emptyState,
|
|
661
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Database, {
|
|
662
|
+
size: 32,
|
|
663
|
+
color: _sharedUi.macOSColors.text.muted
|
|
664
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
665
|
+
style: styles.emptyTitle,
|
|
666
|
+
children: searchQuery ? "No results found" : activeFilter === "all" ? "No valid keys found" : activeFilter === "missing" ? "No missing keys" : "No issues found"
|
|
667
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
668
|
+
style: styles.emptySubtitle,
|
|
669
|
+
children: searchQuery ? `No keys matching "${searchQuery}"` : activeFilter === "all" ? "All keys have issues or are missing" : activeFilter === "missing" ? "All required keys are present" : "All storage keys are correctly configured"
|
|
670
|
+
})]
|
|
671
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
672
|
+
style: styles.techFooter,
|
|
673
|
+
children: "ASYNC STORAGE | MMKV | SECURE STORAGE BACKENDS"
|
|
674
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ProUpgradeModal, {
|
|
675
|
+
visible: showUpgradeModal,
|
|
676
|
+
onClose: () => setShowUpgradeModal(false),
|
|
677
|
+
featureName: "Storage Keys"
|
|
678
|
+
})]
|
|
679
|
+
});
|
|
680
|
+
}
|
|
681
|
+
const styles = _reactNative.StyleSheet.create({
|
|
682
|
+
scrollContainer: {
|
|
683
|
+
flex: 1,
|
|
684
|
+
backgroundColor: _sharedUi.gameUIColors.background
|
|
685
|
+
},
|
|
686
|
+
container: {
|
|
687
|
+
padding: 12,
|
|
688
|
+
paddingBottom: 32
|
|
689
|
+
},
|
|
690
|
+
backgroundGrid: {
|
|
691
|
+
..._reactNative.StyleSheet.absoluteFillObject,
|
|
692
|
+
opacity: 0.006,
|
|
693
|
+
backgroundColor: _sharedUi.gameUIColors.info
|
|
694
|
+
},
|
|
695
|
+
techFooter: {
|
|
696
|
+
fontSize: 8,
|
|
697
|
+
color: _sharedUi.gameUIColors.muted,
|
|
698
|
+
fontFamily: "monospace",
|
|
699
|
+
textAlign: "center",
|
|
700
|
+
marginTop: 20,
|
|
701
|
+
letterSpacing: 1,
|
|
702
|
+
opacity: 0.5
|
|
703
|
+
},
|
|
704
|
+
// Keys section
|
|
705
|
+
keysSection: {
|
|
706
|
+
marginTop: 8,
|
|
707
|
+
backgroundColor: _sharedUi.macOSColors.background.base,
|
|
708
|
+
borderRadius: 12,
|
|
709
|
+
padding: 12,
|
|
710
|
+
borderWidth: 1,
|
|
711
|
+
borderColor: _sharedUi.macOSColors.border.default
|
|
712
|
+
},
|
|
713
|
+
sectionHeader: {
|
|
714
|
+
flexDirection: "row",
|
|
715
|
+
justifyContent: "space-between",
|
|
716
|
+
alignItems: "center",
|
|
717
|
+
marginBottom: 10,
|
|
718
|
+
paddingBottom: 6,
|
|
719
|
+
borderBottomWidth: 1,
|
|
720
|
+
borderBottomColor: _sharedUi.macOSColors.border.default
|
|
721
|
+
},
|
|
722
|
+
sectionHeaderLeft: {
|
|
723
|
+
flexDirection: "row",
|
|
724
|
+
alignItems: "center",
|
|
725
|
+
gap: 8
|
|
726
|
+
},
|
|
727
|
+
sectionTitle: {
|
|
728
|
+
fontSize: 12,
|
|
729
|
+
fontWeight: "600",
|
|
730
|
+
color: _sharedUi.macOSColors.text.secondary,
|
|
731
|
+
letterSpacing: 0.4,
|
|
732
|
+
textTransform: "uppercase"
|
|
733
|
+
},
|
|
734
|
+
countBadge: {
|
|
735
|
+
backgroundColor: _sharedUi.macOSColors.background.card,
|
|
736
|
+
paddingHorizontal: 8,
|
|
737
|
+
paddingVertical: 3,
|
|
738
|
+
borderRadius: 6,
|
|
739
|
+
borderWidth: 1,
|
|
740
|
+
borderColor: _sharedUi.macOSColors.border.default
|
|
741
|
+
},
|
|
742
|
+
countText: {
|
|
743
|
+
fontSize: 11,
|
|
744
|
+
fontWeight: "600",
|
|
745
|
+
color: _sharedUi.macOSColors.text.primary,
|
|
746
|
+
fontFamily: "monospace"
|
|
747
|
+
},
|
|
748
|
+
// Empty state
|
|
749
|
+
emptyState: {
|
|
750
|
+
alignItems: "center",
|
|
751
|
+
justifyContent: "center",
|
|
752
|
+
paddingVertical: 48
|
|
753
|
+
},
|
|
754
|
+
emptyTitle: {
|
|
755
|
+
fontSize: 16,
|
|
756
|
+
fontWeight: "600",
|
|
757
|
+
color: _sharedUi.macOSColors.text.primary,
|
|
758
|
+
marginTop: 12,
|
|
759
|
+
marginBottom: 8
|
|
760
|
+
},
|
|
761
|
+
emptySubtitle: {
|
|
762
|
+
fontSize: 13,
|
|
763
|
+
color: _sharedUi.macOSColors.text.secondary,
|
|
764
|
+
textAlign: "center"
|
|
765
|
+
},
|
|
766
|
+
// Empty MMKV state
|
|
767
|
+
emptyMMKVState: {
|
|
768
|
+
backgroundColor: _sharedUi.macOSColors.background.card,
|
|
769
|
+
borderRadius: 12,
|
|
770
|
+
padding: 20,
|
|
771
|
+
borderWidth: 1,
|
|
772
|
+
borderColor: _sharedUi.macOSColors.border.default,
|
|
773
|
+
marginTop: 8,
|
|
774
|
+
alignItems: "center"
|
|
775
|
+
},
|
|
776
|
+
emptyMMKVTitle: {
|
|
777
|
+
fontSize: 14,
|
|
778
|
+
fontWeight: "600",
|
|
779
|
+
color: _sharedUi.macOSColors.text.primary,
|
|
780
|
+
marginBottom: 6
|
|
781
|
+
},
|
|
782
|
+
emptyMMKVSubtitle: {
|
|
783
|
+
fontSize: 12,
|
|
784
|
+
color: _sharedUi.macOSColors.text.secondary,
|
|
785
|
+
textAlign: "center",
|
|
786
|
+
marginBottom: 12
|
|
787
|
+
},
|
|
788
|
+
emptyMMKVCode: {
|
|
789
|
+
fontSize: 10,
|
|
790
|
+
fontFamily: "monospace",
|
|
791
|
+
color: _sharedUi.macOSColors.semantic.info,
|
|
792
|
+
backgroundColor: _sharedUi.macOSColors.background.input,
|
|
793
|
+
padding: 12,
|
|
794
|
+
borderRadius: 8,
|
|
795
|
+
borderWidth: 1,
|
|
796
|
+
borderColor: _sharedUi.macOSColors.border.default,
|
|
797
|
+
alignSelf: "stretch"
|
|
798
|
+
},
|
|
799
|
+
// Instance Navbar styles
|
|
800
|
+
instanceNavbar: {
|
|
801
|
+
marginTop: 12,
|
|
802
|
+
marginBottom: 8,
|
|
803
|
+
backgroundColor: _sharedUi.macOSColors.background.card,
|
|
804
|
+
borderRadius: 10,
|
|
805
|
+
borderWidth: 1,
|
|
806
|
+
borderColor: _sharedUi.macOSColors.border.default,
|
|
807
|
+
padding: 10,
|
|
808
|
+
shadowColor: '#000',
|
|
809
|
+
shadowOpacity: 0.08,
|
|
810
|
+
shadowRadius: 6,
|
|
811
|
+
shadowOffset: {
|
|
812
|
+
width: 0,
|
|
813
|
+
height: 2
|
|
814
|
+
}
|
|
815
|
+
},
|
|
816
|
+
instanceNavbarHeader: {
|
|
817
|
+
flexDirection: 'row',
|
|
818
|
+
alignItems: 'center',
|
|
819
|
+
justifyContent: 'space-between',
|
|
820
|
+
marginBottom: 8,
|
|
821
|
+
paddingLeft: 2
|
|
822
|
+
},
|
|
823
|
+
instanceNavbarLabel: {
|
|
824
|
+
fontSize: 9,
|
|
825
|
+
fontWeight: '700',
|
|
826
|
+
color: _sharedUi.macOSColors.text.muted,
|
|
827
|
+
textTransform: 'uppercase',
|
|
828
|
+
letterSpacing: 1
|
|
829
|
+
},
|
|
830
|
+
instanceNavbarScroll: {
|
|
831
|
+
gap: 8,
|
|
832
|
+
paddingRight: 8
|
|
833
|
+
},
|
|
834
|
+
instanceNavbarButton: {
|
|
835
|
+
flexDirection: 'row',
|
|
836
|
+
alignItems: 'center',
|
|
837
|
+
gap: 6,
|
|
838
|
+
paddingHorizontal: 12,
|
|
839
|
+
paddingVertical: 8,
|
|
840
|
+
backgroundColor: _sharedUi.macOSColors.background.card,
|
|
841
|
+
borderRadius: 8,
|
|
842
|
+
borderWidth: 1,
|
|
843
|
+
borderColor: _sharedUi.macOSColors.border.default,
|
|
844
|
+
minWidth: 90
|
|
845
|
+
},
|
|
846
|
+
instanceNavbarButtonActive: {
|
|
847
|
+
borderWidth: 1.5,
|
|
848
|
+
shadowColor: '#000',
|
|
849
|
+
shadowOpacity: 0.1,
|
|
850
|
+
shadowRadius: 4,
|
|
851
|
+
shadowOffset: {
|
|
852
|
+
width: 0,
|
|
853
|
+
height: 1
|
|
854
|
+
}
|
|
855
|
+
},
|
|
856
|
+
instanceNavbarButtonText: {
|
|
857
|
+
fontSize: 11,
|
|
858
|
+
fontWeight: '600',
|
|
859
|
+
color: _sharedUi.macOSColors.text.secondary,
|
|
860
|
+
fontFamily: 'monospace',
|
|
861
|
+
flex: 1
|
|
862
|
+
},
|
|
863
|
+
instanceNavbarButtonTextActive: {
|
|
864
|
+
fontWeight: '700',
|
|
865
|
+
color: _sharedUi.macOSColors.text.primary
|
|
866
|
+
},
|
|
867
|
+
instanceNavbarBadge: {
|
|
868
|
+
backgroundColor: _sharedUi.macOSColors.background.input,
|
|
869
|
+
paddingHorizontal: 6,
|
|
870
|
+
paddingVertical: 2,
|
|
871
|
+
borderRadius: 6,
|
|
872
|
+
minWidth: 24,
|
|
873
|
+
alignItems: 'center'
|
|
874
|
+
},
|
|
875
|
+
instanceNavbarBadgeText: {
|
|
876
|
+
fontSize: 10,
|
|
877
|
+
fontWeight: '700',
|
|
878
|
+
color: _sharedUi.macOSColors.text.secondary,
|
|
879
|
+
fontFamily: 'monospace'
|
|
880
|
+
},
|
|
881
|
+
clearSearchButton: {
|
|
882
|
+
marginTop: 16,
|
|
883
|
+
paddingHorizontal: 16,
|
|
884
|
+
paddingVertical: 8,
|
|
885
|
+
backgroundColor: _sharedUi.macOSColors.background.hover,
|
|
886
|
+
borderRadius: 6,
|
|
887
|
+
borderWidth: 1,
|
|
888
|
+
borderColor: _sharedUi.macOSColors.border.default
|
|
889
|
+
},
|
|
890
|
+
clearSearchText: {
|
|
891
|
+
fontSize: 13,
|
|
892
|
+
color: _sharedUi.macOSColors.text.primary,
|
|
893
|
+
fontWeight: "500"
|
|
894
|
+
},
|
|
895
|
+
// Free tier limit banner
|
|
896
|
+
limitBanner: {
|
|
897
|
+
backgroundColor: "#1A1A1A",
|
|
898
|
+
borderRadius: 10,
|
|
899
|
+
borderWidth: 1,
|
|
900
|
+
borderColor: "#20C997" + "40",
|
|
901
|
+
padding: 12,
|
|
902
|
+
marginTop: 12
|
|
903
|
+
},
|
|
904
|
+
limitBannerContent: {
|
|
905
|
+
flexDirection: "row",
|
|
906
|
+
alignItems: "center",
|
|
907
|
+
justifyContent: "space-between",
|
|
908
|
+
marginBottom: 4
|
|
909
|
+
},
|
|
910
|
+
limitBannerLeft: {
|
|
911
|
+
flexDirection: "row",
|
|
912
|
+
alignItems: "center",
|
|
913
|
+
gap: 8
|
|
914
|
+
},
|
|
915
|
+
limitBannerText: {
|
|
916
|
+
color: "#E0E0E0",
|
|
917
|
+
fontSize: 13,
|
|
918
|
+
fontWeight: "600"
|
|
919
|
+
},
|
|
920
|
+
limitBannerSubtext: {
|
|
921
|
+
color: "#888888",
|
|
922
|
+
fontSize: 11
|
|
923
|
+
}
|
|
924
|
+
});
|