@buoy-gg/storage 1.7.7 → 2.1.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/lib/commonjs/index.js +219 -16
- package/lib/commonjs/storage/components/DiffViewer/themes/diffThemes.js +35 -44
- package/lib/commonjs/storage/components/GameUIStorageBrowser.js +9 -23
- package/lib/commonjs/storage/components/SelectionActionBar.js +8 -22
- package/lib/commonjs/storage/components/StorageActionButtons.js +8 -22
- package/lib/commonjs/storage/components/StorageActions.js +8 -22
- package/lib/commonjs/storage/components/StorageEventActionButton.js +120 -0
- package/lib/commonjs/storage/components/StorageEventCard.js +112 -0
- package/lib/commonjs/storage/components/StorageEventDetailContent.js +331 -822
- package/lib/commonjs/storage/components/StorageModalWithTabs.js +43 -200
- package/lib/commonjs/storage/hooks/useStorageEvents.js +98 -0
- package/lib/commonjs/storage/index.js +111 -2
- package/lib/commonjs/storage/stores/storageEventStore.js +243 -0
- package/lib/commonjs/storage/utils/AsyncStorageListener.js +164 -35
- package/lib/commonjs/storage/utils/index.js +37 -0
- package/lib/commonjs/storage/utils/storageTimeTravelUtils.js +251 -0
- package/lib/module/index.js +74 -3
- package/lib/module/storage/components/DiffViewer/themes/diffThemes.js +35 -44
- package/lib/module/storage/components/GameUIStorageBrowser.js +9 -23
- package/lib/module/storage/components/SelectionActionBar.js +9 -24
- package/lib/module/storage/components/StorageActionButtons.js +9 -24
- package/lib/module/storage/components/StorageActions.js +9 -24
- package/lib/module/storage/components/StorageEventActionButton.js +117 -0
- package/lib/module/storage/components/StorageEventCard.js +107 -0
- package/lib/module/storage/components/StorageEventDetailContent.js +332 -824
- package/lib/module/storage/components/StorageModalWithTabs.js +45 -202
- package/lib/module/storage/hooks/useStorageEvents.js +95 -0
- package/lib/module/storage/index.js +7 -1
- package/lib/module/storage/stores/storageEventStore.js +231 -0
- package/lib/module/storage/utils/AsyncStorageListener.js +159 -33
- package/lib/module/storage/utils/index.js +4 -1
- package/lib/module/storage/utils/storageTimeTravelUtils.js +245 -0
- package/lib/typescript/index.d.ts +36 -1
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/storage/components/DiffViewer/themes/diffThemes.d.ts +1 -1
- package/lib/typescript/storage/components/DiffViewer/themes/diffThemes.d.ts.map +1 -1
- package/lib/typescript/storage/components/GameUIStorageBrowser.d.ts.map +1 -1
- package/lib/typescript/storage/components/SelectionActionBar.d.ts.map +1 -1
- package/lib/typescript/storage/components/StorageActionButtons.d.ts +0 -2
- package/lib/typescript/storage/components/StorageActionButtons.d.ts.map +1 -1
- package/lib/typescript/storage/components/StorageActions.d.ts.map +1 -1
- package/lib/typescript/storage/components/StorageEventActionButton.d.ts +37 -0
- package/lib/typescript/storage/components/StorageEventActionButton.d.ts.map +1 -0
- package/lib/typescript/storage/components/StorageEventCard.d.ts +40 -0
- package/lib/typescript/storage/components/StorageEventCard.d.ts.map +1 -0
- package/lib/typescript/storage/components/StorageEventDetailContent.d.ts +11 -3
- package/lib/typescript/storage/components/StorageEventDetailContent.d.ts.map +1 -1
- package/lib/typescript/storage/components/StorageModalWithTabs.d.ts.map +1 -1
- package/lib/typescript/storage/hooks/useStorageEvents.d.ts +51 -0
- package/lib/typescript/storage/hooks/useStorageEvents.d.ts.map +1 -0
- package/lib/typescript/storage/index.d.ts +4 -0
- package/lib/typescript/storage/index.d.ts.map +1 -1
- package/lib/typescript/storage/stores/storageEventStore.d.ts +113 -0
- package/lib/typescript/storage/stores/storageEventStore.d.ts.map +1 -0
- package/lib/typescript/storage/utils/AsyncStorageListener.d.ts +38 -1
- package/lib/typescript/storage/utils/AsyncStorageListener.d.ts.map +1 -1
- package/lib/typescript/storage/utils/index.d.ts +2 -1
- package/lib/typescript/storage/utils/index.d.ts.map +1 -1
- package/lib/typescript/storage/utils/storageTimeTravelUtils.d.ts +35 -0
- package/lib/typescript/storage/utils/storageTimeTravelUtils.d.ts.map +1 -0
- package/package.json +20 -4
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.canUndo = canUndo;
|
|
7
|
+
exports.jumpToState = jumpToState;
|
|
8
|
+
exports.undoOperation = undoOperation;
|
|
9
|
+
var _asyncStorage = _interopRequireDefault(require("@react-native-async-storage/async-storage"));
|
|
10
|
+
var _AsyncStorageListener = require("./AsyncStorageListener");
|
|
11
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
12
|
+
/**
|
|
13
|
+
* Storage Time-Travel Utilities
|
|
14
|
+
*
|
|
15
|
+
* Provides jump and undo functionality for AsyncStorage operations.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Undo a single storage operation
|
|
20
|
+
*
|
|
21
|
+
* Restores the previous value(s) before the operation occurred.
|
|
22
|
+
* This pauses event capture to avoid creating new events during restoration.
|
|
23
|
+
*
|
|
24
|
+
* @param event - The storage event to undo
|
|
25
|
+
*/
|
|
26
|
+
async function undoOperation(event) {
|
|
27
|
+
const {
|
|
28
|
+
action,
|
|
29
|
+
data
|
|
30
|
+
} = event;
|
|
31
|
+
|
|
32
|
+
// Pause capture to avoid creating events during restoration
|
|
33
|
+
(0, _AsyncStorageListener.pauseCapture)();
|
|
34
|
+
try {
|
|
35
|
+
switch (action) {
|
|
36
|
+
case "setItem":
|
|
37
|
+
case "mergeItem":
|
|
38
|
+
if (data?.key) {
|
|
39
|
+
if (data.prevValue === null || data.prevValue === undefined) {
|
|
40
|
+
// Key didn't exist before, remove it
|
|
41
|
+
await _asyncStorage.default.removeItem(data.key);
|
|
42
|
+
} else {
|
|
43
|
+
// Restore previous value
|
|
44
|
+
await _asyncStorage.default.setItem(data.key, data.prevValue);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
break;
|
|
48
|
+
case "removeItem":
|
|
49
|
+
if (data?.key && data.prevValue !== null && data.prevValue !== undefined) {
|
|
50
|
+
// Restore the removed value
|
|
51
|
+
await _asyncStorage.default.setItem(data.key, data.prevValue);
|
|
52
|
+
}
|
|
53
|
+
break;
|
|
54
|
+
case "multiSet":
|
|
55
|
+
case "multiMerge":
|
|
56
|
+
if (data?.prevPairs && data.prevPairs.length > 0) {
|
|
57
|
+
// Restore all previous values
|
|
58
|
+
for (const [key, value] of data.prevPairs) {
|
|
59
|
+
if (value === null) {
|
|
60
|
+
await _asyncStorage.default.removeItem(key);
|
|
61
|
+
} else {
|
|
62
|
+
await _asyncStorage.default.setItem(key, value);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
break;
|
|
67
|
+
case "multiRemove":
|
|
68
|
+
if (data?.prevPairs && data.prevPairs.length > 0) {
|
|
69
|
+
// Restore all removed values
|
|
70
|
+
for (const [key, value] of data.prevPairs) {
|
|
71
|
+
if (value !== null) {
|
|
72
|
+
await _asyncStorage.default.setItem(key, value);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
break;
|
|
77
|
+
case "clear":
|
|
78
|
+
if (data?.prevPairs && data.prevPairs.length > 0) {
|
|
79
|
+
// Restore all cleared key-value pairs
|
|
80
|
+
const pairsToRestore = data.prevPairs.filter(([, value]) => value !== null);
|
|
81
|
+
if (pairsToRestore.length > 0) {
|
|
82
|
+
await _asyncStorage.default.multiSet(pairsToRestore);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
break;
|
|
86
|
+
default:
|
|
87
|
+
throw new Error(`Cannot undo unknown action type: ${action}`);
|
|
88
|
+
}
|
|
89
|
+
} finally {
|
|
90
|
+
// Always resume capture, even if an error occurred
|
|
91
|
+
(0, _AsyncStorageListener.resumeCapture)();
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Jump to a specific point in storage history
|
|
97
|
+
*
|
|
98
|
+
* This reconstructs the storage state as it was after a specific event
|
|
99
|
+
* by clearing storage and replaying all events up to that point.
|
|
100
|
+
*
|
|
101
|
+
* Note: This is a destructive operation - it will clear current storage
|
|
102
|
+
* and replay events to reach the target state.
|
|
103
|
+
*
|
|
104
|
+
* @param events - All events in chronological order (oldest first)
|
|
105
|
+
* @param targetEventIndex - The index of the event to jump to (0-based)
|
|
106
|
+
*/
|
|
107
|
+
async function jumpToState(events, targetEventIndex) {
|
|
108
|
+
if (targetEventIndex < 0 || targetEventIndex >= events.length) {
|
|
109
|
+
throw new Error(`Invalid event index: ${targetEventIndex}`);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Pause capture to avoid creating events during replay
|
|
113
|
+
(0, _AsyncStorageListener.pauseCapture)();
|
|
114
|
+
try {
|
|
115
|
+
// Clear all storage first
|
|
116
|
+
await _asyncStorage.default.clear();
|
|
117
|
+
|
|
118
|
+
// Build up the state by applying each event up to and including the target
|
|
119
|
+
// We use the final values from each event, not the operations themselves
|
|
120
|
+
const stateMap = new Map();
|
|
121
|
+
for (let i = 0; i <= targetEventIndex; i++) {
|
|
122
|
+
const event = events[i];
|
|
123
|
+
applyEventToStateMap(event, stateMap);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Apply the final state
|
|
127
|
+
const pairsToSet = [];
|
|
128
|
+
for (const [key, value] of stateMap) {
|
|
129
|
+
if (value !== null) {
|
|
130
|
+
pairsToSet.push([key, value]);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
if (pairsToSet.length > 0) {
|
|
134
|
+
await _asyncStorage.default.multiSet(pairsToSet);
|
|
135
|
+
}
|
|
136
|
+
} finally {
|
|
137
|
+
// Always resume capture
|
|
138
|
+
(0, _AsyncStorageListener.resumeCapture)();
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Helper to apply an event's effects to a state map
|
|
144
|
+
*/
|
|
145
|
+
function applyEventToStateMap(event, stateMap) {
|
|
146
|
+
const {
|
|
147
|
+
action,
|
|
148
|
+
data
|
|
149
|
+
} = event;
|
|
150
|
+
switch (action) {
|
|
151
|
+
case "setItem":
|
|
152
|
+
if (data?.key && data?.value !== undefined) {
|
|
153
|
+
stateMap.set(data.key, data.value);
|
|
154
|
+
}
|
|
155
|
+
break;
|
|
156
|
+
case "removeItem":
|
|
157
|
+
if (data?.key) {
|
|
158
|
+
stateMap.set(data.key, null);
|
|
159
|
+
}
|
|
160
|
+
break;
|
|
161
|
+
case "mergeItem":
|
|
162
|
+
if (data?.key && data?.value !== undefined) {
|
|
163
|
+
const existing = stateMap.get(data.key);
|
|
164
|
+
if (existing) {
|
|
165
|
+
try {
|
|
166
|
+
// Merge JSON objects
|
|
167
|
+
const existingObj = JSON.parse(existing);
|
|
168
|
+
const newObj = JSON.parse(data.value);
|
|
169
|
+
const merged = {
|
|
170
|
+
...existingObj,
|
|
171
|
+
...newObj
|
|
172
|
+
};
|
|
173
|
+
stateMap.set(data.key, JSON.stringify(merged));
|
|
174
|
+
} catch {
|
|
175
|
+
// If not valid JSON, just overwrite
|
|
176
|
+
stateMap.set(data.key, data.value);
|
|
177
|
+
}
|
|
178
|
+
} else {
|
|
179
|
+
stateMap.set(data.key, data.value);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
break;
|
|
183
|
+
case "multiSet":
|
|
184
|
+
if (data?.pairs) {
|
|
185
|
+
for (const [key, value] of data.pairs) {
|
|
186
|
+
stateMap.set(key, value);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
break;
|
|
190
|
+
case "multiRemove":
|
|
191
|
+
if (data?.keys) {
|
|
192
|
+
for (const key of data.keys) {
|
|
193
|
+
stateMap.set(key, null);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
break;
|
|
197
|
+
case "multiMerge":
|
|
198
|
+
if (data?.pairs) {
|
|
199
|
+
for (const [key, value] of data.pairs) {
|
|
200
|
+
const existing = stateMap.get(key);
|
|
201
|
+
if (existing) {
|
|
202
|
+
try {
|
|
203
|
+
const existingObj = JSON.parse(existing);
|
|
204
|
+
const newObj = JSON.parse(value);
|
|
205
|
+
const merged = {
|
|
206
|
+
...existingObj,
|
|
207
|
+
...newObj
|
|
208
|
+
};
|
|
209
|
+
stateMap.set(key, JSON.stringify(merged));
|
|
210
|
+
} catch {
|
|
211
|
+
stateMap.set(key, value);
|
|
212
|
+
}
|
|
213
|
+
} else {
|
|
214
|
+
stateMap.set(key, value);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
break;
|
|
219
|
+
case "clear":
|
|
220
|
+
// Clear the entire state map
|
|
221
|
+
stateMap.clear();
|
|
222
|
+
break;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Check if an operation can be undone
|
|
228
|
+
*
|
|
229
|
+
* Some operations may not have the previous value captured.
|
|
230
|
+
*/
|
|
231
|
+
function canUndo(event) {
|
|
232
|
+
const {
|
|
233
|
+
action,
|
|
234
|
+
data
|
|
235
|
+
} = event;
|
|
236
|
+
switch (action) {
|
|
237
|
+
case "setItem":
|
|
238
|
+
case "mergeItem":
|
|
239
|
+
case "removeItem":
|
|
240
|
+
// Can undo if we have the key
|
|
241
|
+
return !!data?.key;
|
|
242
|
+
case "multiSet":
|
|
243
|
+
case "multiRemove":
|
|
244
|
+
case "multiMerge":
|
|
245
|
+
case "clear":
|
|
246
|
+
// Can undo if we have previous pairs
|
|
247
|
+
return !!data?.prevPairs && data.prevPairs.length > 0;
|
|
248
|
+
default:
|
|
249
|
+
return false;
|
|
250
|
+
}
|
|
251
|
+
}
|
package/lib/module/index.js
CHANGED
|
@@ -1,7 +1,78 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
/**
|
|
4
|
+
* @buoy-gg/storage
|
|
5
|
+
*
|
|
6
|
+
* Storage monitoring tool for React Native DevTools.
|
|
7
|
+
* Supports AsyncStorage and MMKV.
|
|
8
|
+
*
|
|
9
|
+
* PUBLIC API - Only these exports are supported for external use.
|
|
10
|
+
* Internal listeners and capture controls are not exported to prevent
|
|
11
|
+
* bypassing the tool's intended usage patterns.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
// =============================================================================
|
|
15
|
+
// PRESET (Primary entry point for users)
|
|
16
|
+
// =============================================================================
|
|
4
17
|
export { storageToolPreset, createStorageTool } from "./preset";
|
|
5
18
|
|
|
6
|
-
//
|
|
7
|
-
|
|
19
|
+
// =============================================================================
|
|
20
|
+
// COMPONENTS (For custom UI implementations)
|
|
21
|
+
// =============================================================================
|
|
22
|
+
export { StorageSection } from "./storage/components/StorageSection";
|
|
23
|
+
export { StorageModalWithTabs } from "./storage/components/StorageModalWithTabs";
|
|
24
|
+
export { StorageKeyCard } from "./storage/components/StorageKeyCard";
|
|
25
|
+
export { StorageKeyStatsSection } from "./storage/components/StorageKeyStats";
|
|
26
|
+
export { StorageKeySection } from "./storage/components/StorageKeySection";
|
|
27
|
+
export { StorageBrowserMode } from "./storage/components/StorageBrowserMode";
|
|
28
|
+
export { StorageEventsSection } from "./storage/components/StorageEventsSection";
|
|
29
|
+
export { StorageEventCard, getValueType } from "./storage/components/StorageEventCard";
|
|
30
|
+
export { StorageEventDetailContent, StorageEventDetailFooter } from "./storage/components/StorageEventDetailContent";
|
|
31
|
+
export { MMKVInstanceSelector } from "./storage/components/MMKVInstanceSelector";
|
|
32
|
+
export { MMKVInstanceInfoPanel } from "./storage/components/MMKVInstanceInfoPanel";
|
|
33
|
+
|
|
34
|
+
// =============================================================================
|
|
35
|
+
// HOOKS (For consuming storage data in custom components)
|
|
36
|
+
// =============================================================================
|
|
37
|
+
export { useAsyncStorageKeys } from "./storage/hooks/useAsyncStorageKeys";
|
|
38
|
+
export { useMMKVKeys, useMultiMMKVKeys } from "./storage/hooks/useMMKVKeys";
|
|
39
|
+
export { useMMKVInstances, useMMKVInstance, useMMKVInstanceExists } from "./storage/hooks/useMMKVInstances";
|
|
40
|
+
export { useStorageEvents } from "./storage/hooks/useStorageEvents";
|
|
41
|
+
|
|
42
|
+
// =============================================================================
|
|
43
|
+
// TYPES
|
|
44
|
+
// =============================================================================
|
|
45
|
+
|
|
46
|
+
// =============================================================================
|
|
47
|
+
// UTILITIES (Public helpers only)
|
|
48
|
+
// =============================================================================
|
|
49
|
+
export { clearAllAppStorage } from "./storage/utils/clearAllStorage";
|
|
50
|
+
export { isMMKVAvailable, getMMKVClass, getMMKVUnavailableMessage } from "./storage/utils/mmkvAvailability";
|
|
51
|
+
export { detectMMKVType, formatMMKVValue, isTypeMatch } from "./storage/utils/mmkvTypeDetection";
|
|
52
|
+
export { undoOperation, jumpToState, canUndo } from "./storage/utils/storageTimeTravelUtils";
|
|
53
|
+
// =============================================================================
|
|
54
|
+
// MMKV INSTANCE REGISTRATION (For users to register their MMKV instances)
|
|
55
|
+
// =============================================================================
|
|
56
|
+
export { registerMMKVInstance, unregisterMMKVInstance } from "./storage/utils/MMKVInstanceRegistry";
|
|
57
|
+
|
|
58
|
+
// =============================================================================
|
|
59
|
+
// INTERNAL EXPORTS (For @buoy-gg/* packages only - not part of public API)
|
|
60
|
+
// =============================================================================
|
|
61
|
+
/** @internal */
|
|
62
|
+
export { storageEventStore } from "./storage/stores/storageEventStore";
|
|
63
|
+
|
|
64
|
+
// =============================================================================
|
|
65
|
+
// NOT EXPORTED (Internal capture controls)
|
|
66
|
+
// =============================================================================
|
|
67
|
+
// The following are intentionally NOT exported to prevent bypassing:
|
|
68
|
+
// - startStorageCapture, stopStorageCapture, pauseStorageCapture, resumeStorageCapture
|
|
69
|
+
// - subscribeToStorageEvents, onStorageEvent, getStorageEvents, clearStorageEvents
|
|
70
|
+
// - isStorageCapturing
|
|
71
|
+
// - startListening, stopListening, addListener, removeAllListeners (AsyncStorage)
|
|
72
|
+
// - pauseCapture, resumeCapture, isPaused, isListening, getListenerCount
|
|
73
|
+
// - asyncStorageListener instance
|
|
74
|
+
// - addMMKVInstance, removeMMKVInstance, removeAllMMKVInstances (MMKV listener controls)
|
|
75
|
+
// - addMMKVListener, removeAllMMKVListeners, isMMKVInstanceMonitored
|
|
76
|
+
// - getMonitoredMMKVInstances, getMMKVInstanceCount, getMMKVListenerCount, isMMKVListening
|
|
77
|
+
// - mmkvListener instance
|
|
78
|
+
// - mmkvInstanceRegistry instance
|
|
@@ -50,63 +50,54 @@ export const gitClassicTheme = {
|
|
|
50
50
|
|
|
51
51
|
/**
|
|
52
52
|
* Dev Tools Default Theme
|
|
53
|
-
* Clean dark theme
|
|
53
|
+
* Clean dark theme matching Buoy website brand colors
|
|
54
54
|
*/
|
|
55
55
|
export const devToolsDefaultTheme = {
|
|
56
56
|
name: "Dev Tools Default",
|
|
57
|
-
description: "Clean dark theme with
|
|
58
|
-
//
|
|
59
|
-
background: "#
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
//
|
|
63
|
-
|
|
64
|
-
//
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
removedBackground: "rgba(255, 82, 82, 0.1)",
|
|
70
|
-
// Red for removals
|
|
71
|
-
modifiedBackground: "rgba(0, 184, 230, 0.1)",
|
|
72
|
-
// Cyan for modifications
|
|
57
|
+
description: "Clean dark theme with Buoy brand colors",
|
|
58
|
+
// Surface colors (matching website dark theme)
|
|
59
|
+
background: "#121212",
|
|
60
|
+
panelBackground: "#1A1A1A",
|
|
61
|
+
headerBackground: "#1A1A1A",
|
|
62
|
+
// Diff colors using website's semantic colors
|
|
63
|
+
// Added: Primary teal (#20C997)
|
|
64
|
+
// Removed: Error red (#EF4444)
|
|
65
|
+
// Modified: Secondary purple (#9B70E0)
|
|
66
|
+
addedBackground: "rgba(32, 201, 151, 0.12)",
|
|
67
|
+
removedBackground: "rgba(239, 68, 68, 0.12)",
|
|
68
|
+
modifiedBackground: "rgba(155, 112, 224, 0.12)",
|
|
73
69
|
unchangedBackground: "transparent",
|
|
74
70
|
contextBackground: "rgba(255, 255, 255, 0.02)",
|
|
75
71
|
// Text colors
|
|
76
|
-
addedText: "#
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
modifiedText: "#00B8E6",
|
|
81
|
-
// Bright cyan
|
|
82
|
-
unchangedText: "#B8BFC9",
|
|
83
|
-
// Muted text
|
|
84
|
-
|
|
72
|
+
addedText: "#20C997",
|
|
73
|
+
removedText: "#EF4444",
|
|
74
|
+
modifiedText: "#9B70E0",
|
|
75
|
+
unchangedText: "#E0E0E0",
|
|
85
76
|
// Word-level highlights
|
|
86
|
-
addedWordHighlight: "rgba(
|
|
87
|
-
removedWordHighlight: "rgba(
|
|
77
|
+
addedWordHighlight: "rgba(32, 201, 151, 0.3)",
|
|
78
|
+
removedWordHighlight: "rgba(239, 68, 68, 0.3)",
|
|
88
79
|
// UI elements
|
|
89
|
-
lineNumberBackground: "#
|
|
90
|
-
lineNumberText: "#
|
|
91
|
-
lineNumberBorder: "#
|
|
80
|
+
lineNumberBackground: "#121212",
|
|
81
|
+
lineNumberText: "#A0A0A0",
|
|
82
|
+
lineNumberBorder: "#333333",
|
|
92
83
|
// Markers
|
|
93
|
-
markerAddedBackground: "rgba(
|
|
94
|
-
markerRemovedBackground: "rgba(
|
|
95
|
-
markerModifiedBackground: "rgba(
|
|
96
|
-
markerText: "#
|
|
84
|
+
markerAddedBackground: "rgba(32, 201, 151, 0.2)",
|
|
85
|
+
markerRemovedBackground: "rgba(239, 68, 68, 0.2)",
|
|
86
|
+
markerModifiedBackground: "rgba(155, 112, 224, 0.2)",
|
|
87
|
+
markerText: "#A0A0A0",
|
|
97
88
|
// Borders and dividers
|
|
98
|
-
borderColor: "#
|
|
99
|
-
dividerColor: "#
|
|
89
|
+
borderColor: "#333333",
|
|
90
|
+
dividerColor: "#333333",
|
|
100
91
|
// Summary bar
|
|
101
|
-
summaryBackground: "#
|
|
102
|
-
summaryAddedText: "#
|
|
103
|
-
summaryRemovedText: "#
|
|
104
|
-
summaryModifiedText: "#
|
|
92
|
+
summaryBackground: "#1A1A1A",
|
|
93
|
+
summaryAddedText: "#20C997",
|
|
94
|
+
summaryRemovedText: "#EF4444",
|
|
95
|
+
summaryModifiedText: "#9B70E0",
|
|
105
96
|
// Empty state
|
|
106
|
-
emptyStateText: "#
|
|
97
|
+
emptyStateText: "#888888",
|
|
107
98
|
// Separator
|
|
108
|
-
separatorBackground: "#
|
|
109
|
-
separatorText: "#
|
|
99
|
+
separatorBackground: "#1A1A1A",
|
|
100
|
+
separatorText: "#A0A0A0"
|
|
110
101
|
};
|
|
111
102
|
|
|
112
103
|
/**
|
|
@@ -23,29 +23,10 @@ if (isMMKVAvailable()) {
|
|
|
23
23
|
|
|
24
24
|
// Import shared Game UI components
|
|
25
25
|
import { gameUIColors, macOSColors, HardDrive } from "@buoy-gg/shared-ui";
|
|
26
|
-
|
|
27
|
-
// Lazy load the license hooks to avoid circular dependencies
|
|
28
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
29
|
-
let _useIsPro = null;
|
|
30
|
-
let _licenseLoadAttempted = false;
|
|
31
|
-
function loadLicenseModule() {
|
|
32
|
-
if (_licenseLoadAttempted) return;
|
|
33
|
-
_licenseLoadAttempted = true;
|
|
34
|
-
try {
|
|
35
|
-
const mod = require("@buoy-gg/license");
|
|
36
|
-
if (mod) {
|
|
37
|
-
_useIsPro = mod.useIsPro ?? null;
|
|
38
|
-
}
|
|
39
|
-
} catch {
|
|
40
|
-
// License package not available
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
function getUseIsPro() {
|
|
44
|
-
loadLicenseModule();
|
|
45
|
-
return _useIsPro ?? (() => false);
|
|
46
|
-
}
|
|
26
|
+
import { useIsPro } from "@buoy-gg/license";
|
|
47
27
|
|
|
48
28
|
// MMKV Instance color palette - consistent colors per instance
|
|
29
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
49
30
|
const INSTANCE_COLORS = [macOSColors.semantic.info,
|
|
50
31
|
// Blue
|
|
51
32
|
macOSColors.semantic.success,
|
|
@@ -79,10 +60,15 @@ export function GameUIStorageBrowser({
|
|
|
79
60
|
searchQuery = "",
|
|
80
61
|
storageDataRef
|
|
81
62
|
}) {
|
|
82
|
-
// Check Pro status internally
|
|
83
|
-
const useIsPro = getUseIsPro();
|
|
84
63
|
const isPro = useIsPro();
|
|
85
64
|
const [showUpgradeModal, setShowUpgradeModal] = useState(false);
|
|
65
|
+
|
|
66
|
+
// Auto-close upgrade modal when user becomes Pro
|
|
67
|
+
useEffect(() => {
|
|
68
|
+
if (showUpgradeModal && isPro) {
|
|
69
|
+
setShowUpgradeModal(false);
|
|
70
|
+
}
|
|
71
|
+
}, [showUpgradeModal, isPro]);
|
|
86
72
|
const [activeFilter, setActiveFilter] = useState("all");
|
|
87
73
|
const [activeStorageType, setActiveStorageType] = useState("all");
|
|
88
74
|
const [selectedMMKVInstance, setSelectedMMKVInstance] = useState(null);
|
|
@@ -1,31 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
import { useState } from "react";
|
|
3
|
+
import { useState, useEffect } from "react";
|
|
4
4
|
import { View, Text, StyleSheet, TouchableOpacity, Alert } from "react-native";
|
|
5
5
|
import { Trash2, CopyButton, CheckSquare, ProUpgradeModal } from "@buoy-gg/shared-ui";
|
|
6
6
|
import { macOSColors } from "@buoy-gg/shared-ui";
|
|
7
|
+
import { useIsPro } from "@buoy-gg/license";
|
|
7
8
|
import AsyncStorage from "@react-native-async-storage/async-storage";
|
|
8
|
-
|
|
9
|
-
// Lazy load the license hooks to avoid circular dependencies
|
|
10
9
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
11
|
-
let _useIsPro = null;
|
|
12
|
-
let _licenseLoadAttempted = false;
|
|
13
|
-
function loadLicenseModule() {
|
|
14
|
-
if (_licenseLoadAttempted) return;
|
|
15
|
-
_licenseLoadAttempted = true;
|
|
16
|
-
try {
|
|
17
|
-
const mod = require("@buoy-gg/license");
|
|
18
|
-
if (mod) {
|
|
19
|
-
_useIsPro = mod.useIsPro ?? null;
|
|
20
|
-
}
|
|
21
|
-
} catch {
|
|
22
|
-
// License package not available
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
function getUseIsPro() {
|
|
26
|
-
loadLicenseModule();
|
|
27
|
-
return _useIsPro ?? (() => false);
|
|
28
|
-
}
|
|
29
10
|
export function SelectionActionBar({
|
|
30
11
|
selectedKeys,
|
|
31
12
|
mmkvInstances,
|
|
@@ -35,10 +16,14 @@ export function SelectionActionBar({
|
|
|
35
16
|
totalVisibleKeys
|
|
36
17
|
}) {
|
|
37
18
|
const [showUpgradeModal, setShowUpgradeModal] = useState(false);
|
|
38
|
-
|
|
39
|
-
// Check Pro status internally
|
|
40
|
-
const useIsPro = getUseIsPro();
|
|
41
19
|
const isPro = useIsPro();
|
|
20
|
+
|
|
21
|
+
// Auto-close upgrade modal when user becomes Pro
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
if (showUpgradeModal && isPro) {
|
|
24
|
+
setShowUpgradeModal(false);
|
|
25
|
+
}
|
|
26
|
+
}, [showUpgradeModal, isPro]);
|
|
42
27
|
const selectedCount = selectedKeys.length;
|
|
43
28
|
const allSelected = selectedCount === totalVisibleKeys && totalVisibleKeys > 0;
|
|
44
29
|
|
|
@@ -1,31 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
import { useState } from "react";
|
|
3
|
+
import { useState, useEffect } from "react";
|
|
4
4
|
import { View, Text, StyleSheet, TouchableOpacity, Alert } from "react-native";
|
|
5
5
|
import { Trash2, CopyButton, SquareDashed, X, ProUpgradeModal } from "@buoy-gg/shared-ui";
|
|
6
6
|
import { macOSColors } from "@buoy-gg/shared-ui";
|
|
7
|
+
import { useIsPro } from "@buoy-gg/license";
|
|
7
8
|
import AsyncStorage from "@react-native-async-storage/async-storage";
|
|
8
|
-
|
|
9
|
-
// Lazy load the license hooks to avoid circular dependencies
|
|
10
9
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
11
|
-
let _useIsPro = null;
|
|
12
|
-
let _licenseLoadAttempted = false;
|
|
13
|
-
function loadLicenseModule() {
|
|
14
|
-
if (_licenseLoadAttempted) return;
|
|
15
|
-
_licenseLoadAttempted = true;
|
|
16
|
-
try {
|
|
17
|
-
const mod = require("@buoy-gg/license");
|
|
18
|
-
if (mod) {
|
|
19
|
-
_useIsPro = mod.useIsPro ?? null;
|
|
20
|
-
}
|
|
21
|
-
} catch {
|
|
22
|
-
// License package not available
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
function getUseIsPro() {
|
|
26
|
-
loadLicenseModule();
|
|
27
|
-
return _useIsPro ?? (() => false);
|
|
28
|
-
}
|
|
29
10
|
export function StorageActionButtons({
|
|
30
11
|
copyValue,
|
|
31
12
|
mmkvInstances = [],
|
|
@@ -36,10 +17,14 @@ export function StorageActionButtons({
|
|
|
36
17
|
selectedCount = 0
|
|
37
18
|
}) {
|
|
38
19
|
const [showUpgradeModal, setShowUpgradeModal] = useState(false);
|
|
39
|
-
|
|
40
|
-
// Check Pro status internally
|
|
41
|
-
const useIsPro = getUseIsPro();
|
|
42
20
|
const isPro = useIsPro();
|
|
21
|
+
|
|
22
|
+
// Auto-close upgrade modal when user becomes Pro
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
if (showUpgradeModal && isPro) {
|
|
25
|
+
setShowUpgradeModal(false);
|
|
26
|
+
}
|
|
27
|
+
}, [showUpgradeModal, isPro]);
|
|
43
28
|
const handleClearAsyncStorage = () => {
|
|
44
29
|
// Gate clear behind Pro
|
|
45
30
|
if (!isPro) {
|
|
@@ -1,30 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
import { View, Text, TouchableOpacity, StyleSheet, Alert } from "react-native";
|
|
4
|
-
import { useState, useCallback } from "react";
|
|
4
|
+
import { useState, useCallback, useEffect } from "react";
|
|
5
5
|
import { clearAllStorageIncludingDevTools } from "../utils/clearAllStorage";
|
|
6
6
|
import { RefreshCw, Trash2, CopyButton, ProUpgradeModal } from "@buoy-gg/shared-ui";
|
|
7
|
-
|
|
8
|
-
// Lazy load the license hooks to avoid circular dependencies
|
|
7
|
+
import { useIsPro } from "@buoy-gg/license";
|
|
9
8
|
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
10
|
-
let _useIsPro = null;
|
|
11
|
-
let _licenseLoadAttempted = false;
|
|
12
|
-
function loadLicenseModule() {
|
|
13
|
-
if (_licenseLoadAttempted) return;
|
|
14
|
-
_licenseLoadAttempted = true;
|
|
15
|
-
try {
|
|
16
|
-
const mod = require("@buoy-gg/license");
|
|
17
|
-
if (mod) {
|
|
18
|
-
_useIsPro = mod.useIsPro ?? null;
|
|
19
|
-
}
|
|
20
|
-
} catch {
|
|
21
|
-
// License package not available
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
function getUseIsPro() {
|
|
25
|
-
loadLicenseModule();
|
|
26
|
-
return _useIsPro ?? (() => false);
|
|
27
|
-
}
|
|
28
9
|
export function StorageActions({
|
|
29
10
|
storageKeys,
|
|
30
11
|
onClearAll,
|
|
@@ -33,10 +14,14 @@ export function StorageActions({
|
|
|
33
14
|
}) {
|
|
34
15
|
const [isRefreshing, setIsRefreshing] = useState(false);
|
|
35
16
|
const [showUpgradeModal, setShowUpgradeModal] = useState(false);
|
|
36
|
-
|
|
37
|
-
// Check Pro status internally
|
|
38
|
-
const useIsPro = getUseIsPro();
|
|
39
17
|
const isPro = useIsPro();
|
|
18
|
+
|
|
19
|
+
// Auto-close upgrade modal when user becomes Pro
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
if (showUpgradeModal && isPro) {
|
|
22
|
+
setShowUpgradeModal(false);
|
|
23
|
+
}
|
|
24
|
+
}, [showUpgradeModal, isPro]);
|
|
40
25
|
const handleRefresh = useCallback(async () => {
|
|
41
26
|
setIsRefreshing(true);
|
|
42
27
|
try {
|