@buoy-gg/storage 2.1.1 → 2.1.3
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/storage/components/StorageModalWithTabs.js +20 -36
- package/lib/commonjs/storage/hooks/useStorageEvents.js +20 -34
- package/lib/commonjs/storage/index.js +0 -28
- package/lib/commonjs/storage/stores/storageEventStore.js +40 -151
- package/lib/module/index.js +0 -1
- package/lib/module/storage/components/StorageModalWithTabs.js +21 -37
- package/lib/module/storage/hooks/useStorageEvents.js +20 -34
- package/lib/module/storage/index.js +1 -1
- package/lib/module/storage/stores/storageEventStore.js +40 -147
- package/lib/typescript/storage/components/StorageModalWithTabs.d.ts.map +1 -1
- package/lib/typescript/storage/hooks/useStorageEvents.d.ts +5 -12
- package/lib/typescript/storage/hooks/useStorageEvents.d.ts.map +1 -1
- package/lib/typescript/storage/index.d.ts +1 -1
- package/lib/typescript/storage/index.d.ts.map +1 -1
- package/lib/typescript/storage/stores/storageEventStore.d.ts +14 -58
- package/lib/typescript/storage/stores/storageEventStore.d.ts.map +1 -1
- package/package.json +4 -4
|
@@ -11,7 +11,6 @@ var _asyncStorage = _interopRequireDefault(require("@react-native-async-storage/
|
|
|
11
11
|
var _sharedUi = require("@buoy-gg/shared-ui");
|
|
12
12
|
var _StorageBrowserMode = require("./StorageBrowserMode");
|
|
13
13
|
var _clearAllStorage = require("../utils/clearAllStorage");
|
|
14
|
-
var _AsyncStorageListener = require("../utils/AsyncStorageListener");
|
|
15
14
|
var _useStorageEvents = require("../hooks/useStorageEvents");
|
|
16
15
|
var _StorageEventDetailContent = require("./StorageEventDetailContent");
|
|
17
16
|
var _StorageFilterViewV = require("./StorageFilterViewV2");
|
|
@@ -44,17 +43,19 @@ function StorageModalWithTabs({
|
|
|
44
43
|
const [isSearchActive, setIsSearchActive] = (0, _react.useState)(false);
|
|
45
44
|
const hasLoadedStorageFilters = (0, _react.useRef)(false);
|
|
46
45
|
|
|
46
|
+
// Local state to control subscription (true = subscribed, false = unsubscribed)
|
|
47
|
+
const [isListeningEnabled, setIsListeningEnabled] = (0, _react.useState)(true);
|
|
48
|
+
|
|
47
49
|
// Event Listener state - using centralized store via hook
|
|
50
|
+
// Pass enabled option to control subscription - this allows events tool to
|
|
51
|
+
// continue receiving events while storage UI has toggled off
|
|
48
52
|
const {
|
|
49
53
|
events,
|
|
50
54
|
clearEvents: clearStorageEvents,
|
|
51
|
-
isCapturing
|
|
52
|
-
startCapturing,
|
|
53
|
-
stopCapturing
|
|
55
|
+
isCapturing
|
|
54
56
|
} = (0, _useStorageEvents.useStorageEvents)({
|
|
55
|
-
|
|
56
|
-
});
|
|
57
|
-
const [isListening, setIsListening] = (0, _react.useState)(false);
|
|
57
|
+
enabled: isListeningEnabled
|
|
58
|
+
});
|
|
58
59
|
const [selectedConversationKey, setSelectedConversationKey] = (0, _react.useState)(null);
|
|
59
60
|
const [selectedEventIndex, setSelectedEventIndex] = (0, _react.useState)(0);
|
|
60
61
|
const [showFilters, setShowFilters] = (0, _react.useState)(false);
|
|
@@ -67,10 +68,8 @@ function StorageModalWithTabs({
|
|
|
67
68
|
const hasLoadedTabState = (0, _react.useRef)(false);
|
|
68
69
|
const hasLoadedMonitoringState = (0, _react.useRef)(false);
|
|
69
70
|
|
|
70
|
-
//
|
|
71
|
-
|
|
72
|
-
setIsListening(isCapturing);
|
|
73
|
-
}, [isCapturing]);
|
|
71
|
+
// isListening = enabled and capturing (has subscribers)
|
|
72
|
+
const isListening = isListeningEnabled && isCapturing;
|
|
74
73
|
const handleModeChange = (0, _react.useCallback)(_mode => {
|
|
75
74
|
// Mode changes handled by JsModal
|
|
76
75
|
}, []);
|
|
@@ -102,9 +101,7 @@ function StorageModalWithTabs({
|
|
|
102
101
|
const storedMonitoring = await _asyncStorage.default.getItem(_sharedUi.devToolsStorageKeys.storage.isMonitoring());
|
|
103
102
|
if (storedMonitoring !== null) {
|
|
104
103
|
const shouldMonitor = storedMonitoring === "true";
|
|
105
|
-
|
|
106
|
-
await startCapturing();
|
|
107
|
-
}
|
|
104
|
+
setIsListeningEnabled(shouldMonitor);
|
|
108
105
|
}
|
|
109
106
|
hasLoadedMonitoringState.current = true;
|
|
110
107
|
} catch (error) {
|
|
@@ -112,7 +109,7 @@ function StorageModalWithTabs({
|
|
|
112
109
|
}
|
|
113
110
|
};
|
|
114
111
|
loadMonitoringState();
|
|
115
|
-
}, [visible
|
|
112
|
+
}, [visible]);
|
|
116
113
|
|
|
117
114
|
// Note: Conversations will appear when storage events are triggered
|
|
118
115
|
// Click on any conversation to see the unified view with toggle cards
|
|
@@ -181,14 +178,10 @@ function StorageModalWithTabs({
|
|
|
181
178
|
// Event listener setup - now handled by useStorageEvents hook
|
|
182
179
|
// The hook subscribes to the centralized storageEventStore
|
|
183
180
|
|
|
184
|
-
const handleToggleListening = (0, _react.useCallback)(
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
} else {
|
|
189
|
-
await startCapturing();
|
|
190
|
-
}
|
|
191
|
-
}, [isListening, startCapturing, stopCapturing]);
|
|
181
|
+
const handleToggleListening = (0, _react.useCallback)(() => {
|
|
182
|
+
// Toggle subscription - this actually subscribes/unsubscribes from the store
|
|
183
|
+
setIsListeningEnabled(prev => !prev);
|
|
184
|
+
}, []);
|
|
192
185
|
const handleClearEvents = (0, _react.useCallback)(() => {
|
|
193
186
|
clearStorageEvents();
|
|
194
187
|
setSelectedConversationKey(null);
|
|
@@ -577,16 +570,10 @@ function StorageModalWithTabs({
|
|
|
577
570
|
size: 14,
|
|
578
571
|
color: ignoredPatterns.size > 0 ? _sharedUi.macOSColors.semantic.debug : _sharedUi.macOSColors.text.secondary
|
|
579
572
|
})
|
|
580
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
size: 14,
|
|
585
|
-
color: _sharedUi.macOSColors.semantic.success
|
|
586
|
-
}) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Play, {
|
|
587
|
-
size: 14,
|
|
588
|
-
color: _sharedUi.macOSColors.semantic.success
|
|
589
|
-
})
|
|
573
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.PowerToggleButton, {
|
|
574
|
+
isEnabled: isListening,
|
|
575
|
+
onToggle: handleToggleListening,
|
|
576
|
+
accessibilityLabel: "Toggle storage event monitoring"
|
|
590
577
|
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
|
|
591
578
|
onPress: handleClearEvents,
|
|
592
579
|
style: styles.iconButton,
|
|
@@ -623,9 +610,6 @@ const styles = _reactNative.StyleSheet.create({
|
|
|
623
610
|
alignItems: "center",
|
|
624
611
|
justifyContent: "center"
|
|
625
612
|
},
|
|
626
|
-
activeButton: {
|
|
627
|
-
backgroundColor: _sharedUi.macOSColors.semantic.successBackground
|
|
628
|
-
},
|
|
629
613
|
activeFilterButton: {
|
|
630
614
|
backgroundColor: _sharedUi.macOSColors.semantic.infoBackground
|
|
631
615
|
},
|
|
@@ -10,7 +10,8 @@ var _storageEventStore = require("../stores/storageEventStore");
|
|
|
10
10
|
* useStorageEvents Hook
|
|
11
11
|
*
|
|
12
12
|
* React hook for subscribing to storage events from the centralized store.
|
|
13
|
-
*
|
|
13
|
+
* Uses self-managing Subscribable pattern - the storage listener automatically
|
|
14
|
+
* starts when this hook mounts and stops when all subscribers unmount.
|
|
14
15
|
*
|
|
15
16
|
* @example
|
|
16
17
|
* ```typescript
|
|
@@ -36,14 +37,21 @@ function useStorageEvents(options = {}) {
|
|
|
36
37
|
const {
|
|
37
38
|
storageType = "all",
|
|
38
39
|
maxEvents = 500,
|
|
39
|
-
|
|
40
|
+
enabled = true
|
|
40
41
|
} = options;
|
|
41
42
|
const [events, setEvents] = (0, _react.useState)([]);
|
|
42
|
-
|
|
43
|
+
// Track capturing state locally so it updates reactively with the subscription
|
|
44
|
+
const [isCapturing, setIsCapturing] = (0, _react.useState)(enabled);
|
|
43
45
|
|
|
44
|
-
// Subscribe to store
|
|
46
|
+
// Subscribe to store - this automatically starts/stops the storage listener
|
|
47
|
+
// based on subscriber count (Subscribable pattern from TanStack Query)
|
|
48
|
+
// Only subscribe when enabled is true
|
|
45
49
|
(0, _react.useEffect)(() => {
|
|
46
|
-
|
|
50
|
+
if (!enabled) {
|
|
51
|
+
setIsCapturing(false);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
const unsubscribe = _storageEventStore.storageEventStore.subscribeToEvents(allEvents => {
|
|
47
55
|
// Filter by storage type if specified
|
|
48
56
|
let filtered = allEvents;
|
|
49
57
|
if (storageType !== "all") {
|
|
@@ -55,44 +63,22 @@ function useStorageEvents(options = {}) {
|
|
|
55
63
|
filtered = filtered.slice(0, maxEvents);
|
|
56
64
|
}
|
|
57
65
|
setEvents(filtered);
|
|
58
|
-
setIsCapturing(_storageEventStore.storageEventStore.capturing);
|
|
59
66
|
});
|
|
67
|
+
|
|
68
|
+
// Mark as capturing after successful subscription
|
|
69
|
+
setIsCapturing(true);
|
|
60
70
|
return () => {
|
|
61
71
|
unsubscribe();
|
|
72
|
+
// Note: Don't set isCapturing=false here because we might be
|
|
73
|
+
// re-subscribing due to dependency change, not actually stopping
|
|
62
74
|
};
|
|
63
|
-
}, [storageType, maxEvents]);
|
|
64
|
-
|
|
65
|
-
// Auto-start capturing on mount
|
|
66
|
-
(0, _react.useEffect)(() => {
|
|
67
|
-
if (autoStart && !_storageEventStore.storageEventStore.capturing) {
|
|
68
|
-
_storageEventStore.storageEventStore.startCapturing();
|
|
69
|
-
setIsCapturing(true);
|
|
70
|
-
}
|
|
71
|
-
}, [autoStart]);
|
|
75
|
+
}, [storageType, maxEvents, enabled]);
|
|
72
76
|
const clearEvents = (0, _react.useCallback)(() => {
|
|
73
77
|
_storageEventStore.storageEventStore.clearEvents();
|
|
74
78
|
}, []);
|
|
75
|
-
const startCapturing = (0, _react.useCallback)(async () => {
|
|
76
|
-
await _storageEventStore.storageEventStore.startCapturing();
|
|
77
|
-
setIsCapturing(true);
|
|
78
|
-
}, []);
|
|
79
|
-
const stopCapturing = (0, _react.useCallback)(() => {
|
|
80
|
-
_storageEventStore.storageEventStore.stopCapturing();
|
|
81
|
-
setIsCapturing(false);
|
|
82
|
-
}, []);
|
|
83
|
-
const pauseCapturing = (0, _react.useCallback)(() => {
|
|
84
|
-
_storageEventStore.storageEventStore.pauseCapture();
|
|
85
|
-
}, []);
|
|
86
|
-
const resumeCapturing = (0, _react.useCallback)(() => {
|
|
87
|
-
_storageEventStore.storageEventStore.resumeCapture();
|
|
88
|
-
}, []);
|
|
89
79
|
return {
|
|
90
80
|
events,
|
|
91
81
|
clearEvents,
|
|
92
|
-
isCapturing
|
|
93
|
-
startCapturing,
|
|
94
|
-
stopCapturing,
|
|
95
|
-
pauseCapturing,
|
|
96
|
-
resumeCapturing
|
|
82
|
+
isCapturing
|
|
97
83
|
};
|
|
98
84
|
}
|
|
@@ -25,10 +25,6 @@ var _exportNames = {
|
|
|
25
25
|
MMKVInstanceSelector: true,
|
|
26
26
|
MMKVInstanceInfoPanel: true,
|
|
27
27
|
storageEventStore: true,
|
|
28
|
-
startStorageCapture: true,
|
|
29
|
-
stopStorageCapture: true,
|
|
30
|
-
pauseStorageCapture: true,
|
|
31
|
-
resumeStorageCapture: true,
|
|
32
28
|
subscribeToStorageEvents: true,
|
|
33
29
|
onStorageEvent: true,
|
|
34
30
|
getStorageEvents: true,
|
|
@@ -137,30 +133,6 @@ Object.defineProperty(exports, "onStorageEvent", {
|
|
|
137
133
|
return _storageEventStore.onStorageEvent;
|
|
138
134
|
}
|
|
139
135
|
});
|
|
140
|
-
Object.defineProperty(exports, "pauseStorageCapture", {
|
|
141
|
-
enumerable: true,
|
|
142
|
-
get: function () {
|
|
143
|
-
return _storageEventStore.pauseStorageCapture;
|
|
144
|
-
}
|
|
145
|
-
});
|
|
146
|
-
Object.defineProperty(exports, "resumeStorageCapture", {
|
|
147
|
-
enumerable: true,
|
|
148
|
-
get: function () {
|
|
149
|
-
return _storageEventStore.resumeStorageCapture;
|
|
150
|
-
}
|
|
151
|
-
});
|
|
152
|
-
Object.defineProperty(exports, "startStorageCapture", {
|
|
153
|
-
enumerable: true,
|
|
154
|
-
get: function () {
|
|
155
|
-
return _storageEventStore.startStorageCapture;
|
|
156
|
-
}
|
|
157
|
-
});
|
|
158
|
-
Object.defineProperty(exports, "stopStorageCapture", {
|
|
159
|
-
enumerable: true,
|
|
160
|
-
get: function () {
|
|
161
|
-
return _storageEventStore.stopStorageCapture;
|
|
162
|
-
}
|
|
163
|
-
});
|
|
164
136
|
Object.defineProperty(exports, "storageEventStore", {
|
|
165
137
|
enumerable: true,
|
|
166
138
|
get: function () {
|
|
@@ -3,29 +3,28 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.subscribeToStorageEvents = exports.storageEventStore = exports.
|
|
6
|
+
exports.subscribeToStorageEvents = exports.storageEventStore = exports.onStorageEvent = exports.isStorageCapturing = exports.getStorageEvents = exports.clearStorageEvents = void 0;
|
|
7
|
+
var _sharedUi = require("@buoy-gg/shared-ui");
|
|
7
8
|
var _AsyncStorageListener = require("../utils/AsyncStorageListener");
|
|
8
9
|
var _MMKVListener = require("../utils/MMKVListener");
|
|
9
10
|
/**
|
|
10
11
|
* Storage Event Store
|
|
11
12
|
*
|
|
12
13
|
* Centralized store that aggregates storage events from AsyncStorage and MMKV
|
|
13
|
-
* into a single event stream.
|
|
14
|
-
*
|
|
14
|
+
* into a single event stream. Uses BaseEventStore pattern - the storage listener
|
|
15
|
+
* automatically starts when the first subscriber joins and stops when the last
|
|
16
|
+
* subscriber leaves.
|
|
15
17
|
*
|
|
16
18
|
* @example
|
|
17
19
|
* ```typescript
|
|
18
20
|
* import { storageEventStore } from '@buoy-gg/storage';
|
|
19
21
|
*
|
|
20
|
-
* // Subscribe to storage events
|
|
21
|
-
* const unsubscribe = storageEventStore.
|
|
22
|
+
* // Subscribe to storage events - automatically starts capturing!
|
|
23
|
+
* const unsubscribe = storageEventStore.subscribeToEvents((events) => {
|
|
22
24
|
* console.log('Storage events:', events);
|
|
23
25
|
* });
|
|
24
26
|
*
|
|
25
|
-
* //
|
|
26
|
-
* await storageEventStore.startCapturing();
|
|
27
|
-
*
|
|
28
|
-
* // Later, clean up
|
|
27
|
+
* // Later, clean up - automatically stops if no other subscribers
|
|
29
28
|
* unsubscribe();
|
|
30
29
|
* ```
|
|
31
30
|
*/
|
|
@@ -35,65 +34,60 @@ var _MMKVListener = require("../utils/MMKVListener");
|
|
|
35
34
|
*/
|
|
36
35
|
|
|
37
36
|
/**
|
|
38
|
-
* Listener callback type for storage events
|
|
37
|
+
* Listener callback type for storage events array
|
|
39
38
|
*/
|
|
40
39
|
|
|
41
40
|
/**
|
|
42
41
|
* Listener callback for individual new events
|
|
43
42
|
*/
|
|
44
43
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
events = [];
|
|
48
|
-
listeners = new Set();
|
|
49
|
-
eventCallbacks = new Set();
|
|
50
|
-
isCapturing = false;
|
|
51
|
-
|
|
52
|
-
// Unsubscribe functions
|
|
44
|
+
class StorageEventStore extends _sharedUi.BaseEventStore {
|
|
45
|
+
// Unsubscribe functions for raw listeners
|
|
53
46
|
asyncStorageUnsubscribe = null;
|
|
54
47
|
mmkvUnsubscribe = null;
|
|
48
|
+
constructor() {
|
|
49
|
+
super({
|
|
50
|
+
storeName: "storage",
|
|
51
|
+
maxEvents: 500
|
|
52
|
+
});
|
|
53
|
+
}
|
|
55
54
|
|
|
56
55
|
/**
|
|
57
56
|
* Start capturing storage events from both AsyncStorage and MMKV
|
|
58
57
|
*/
|
|
59
58
|
async startCapturing() {
|
|
60
|
-
if (this.isCapturing) {
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
59
|
// Start AsyncStorage listening if not already active
|
|
65
60
|
if (!(0, _AsyncStorageListener.isListening)()) {
|
|
66
61
|
await (0, _AsyncStorageListener.startListening)();
|
|
67
62
|
}
|
|
68
63
|
|
|
69
64
|
// Subscribe to AsyncStorage events
|
|
70
|
-
this.asyncStorageUnsubscribe
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
65
|
+
if (!this.asyncStorageUnsubscribe) {
|
|
66
|
+
this.asyncStorageUnsubscribe = (0, _AsyncStorageListener.addListener)(event => {
|
|
67
|
+
const storageEvent = {
|
|
68
|
+
...event,
|
|
69
|
+
storageType: "async"
|
|
70
|
+
};
|
|
71
|
+
this.addEvent(storageEvent);
|
|
72
|
+
});
|
|
73
|
+
}
|
|
77
74
|
|
|
78
75
|
// Subscribe to MMKV events
|
|
79
|
-
this.mmkvUnsubscribe
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
76
|
+
if (!this.mmkvUnsubscribe) {
|
|
77
|
+
this.mmkvUnsubscribe = (0, _MMKVListener.addMMKVListener)(event => {
|
|
78
|
+
const storageEvent = {
|
|
79
|
+
...event,
|
|
80
|
+
storageType: "mmkv"
|
|
81
|
+
};
|
|
82
|
+
this.addEvent(storageEvent);
|
|
83
|
+
});
|
|
84
|
+
}
|
|
87
85
|
}
|
|
88
86
|
|
|
89
87
|
/**
|
|
90
88
|
* Stop capturing storage events
|
|
91
89
|
*/
|
|
92
90
|
stopCapturing() {
|
|
93
|
-
if (!this.isCapturing) {
|
|
94
|
-
return;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
91
|
// Unsubscribe from AsyncStorage
|
|
98
92
|
if (this.asyncStorageUnsubscribe) {
|
|
99
93
|
this.asyncStorageUnsubscribe();
|
|
@@ -105,88 +99,13 @@ class StorageEventStore {
|
|
|
105
99
|
this.mmkvUnsubscribe();
|
|
106
100
|
this.mmkvUnsubscribe = null;
|
|
107
101
|
}
|
|
108
|
-
this.isCapturing = false;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Pause event capture (used during time-travel operations)
|
|
113
|
-
*/
|
|
114
|
-
pauseCapture() {
|
|
115
|
-
(0, _AsyncStorageListener.pauseCapture)();
|
|
116
|
-
// MMKV listener doesn't have pause, but it's less common for time-travel
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* Resume event capture after pausing
|
|
121
|
-
*/
|
|
122
|
-
resumeCapture() {
|
|
123
|
-
(0, _AsyncStorageListener.resumeCapture)();
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* Add an event to the store
|
|
128
|
-
*/
|
|
129
|
-
addEvent(event) {
|
|
130
|
-
// Add to beginning (newest first)
|
|
131
|
-
this.events = [event, ...this.events].slice(0, MAX_EVENTS);
|
|
132
|
-
|
|
133
|
-
// Notify event callbacks (for individual events)
|
|
134
|
-
this.eventCallbacks.forEach(callback => {
|
|
135
|
-
try {
|
|
136
|
-
callback(event);
|
|
137
|
-
} catch {
|
|
138
|
-
// Ignore callback errors
|
|
139
|
-
}
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
// Notify listeners (for full event list)
|
|
143
|
-
this.notifyListeners();
|
|
144
102
|
}
|
|
145
103
|
|
|
146
104
|
/**
|
|
147
|
-
*
|
|
105
|
+
* Check if currently capturing events (has subscribers)
|
|
148
106
|
*/
|
|
149
|
-
|
|
150
|
-
this.
|
|
151
|
-
|
|
152
|
-
// Immediately call with current events
|
|
153
|
-
listener(this.events);
|
|
154
|
-
|
|
155
|
-
// Return unsubscribe function
|
|
156
|
-
return () => {
|
|
157
|
-
this.listeners.delete(listener);
|
|
158
|
-
};
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* Subscribe to new events only (receives individual events as they occur)
|
|
163
|
-
*/
|
|
164
|
-
onEvent(callback) {
|
|
165
|
-
this.eventCallbacks.add(callback);
|
|
166
|
-
return () => {
|
|
167
|
-
this.eventCallbacks.delete(callback);
|
|
168
|
-
};
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
/**
|
|
172
|
-
* Notify all listeners of changes
|
|
173
|
-
*/
|
|
174
|
-
notifyListeners() {
|
|
175
|
-
const events = this.events;
|
|
176
|
-
this.listeners.forEach(listener => {
|
|
177
|
-
try {
|
|
178
|
-
listener(events);
|
|
179
|
-
} catch {
|
|
180
|
-
// Ignore listener errors
|
|
181
|
-
}
|
|
182
|
-
});
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* Get all events
|
|
187
|
-
*/
|
|
188
|
-
getEvents() {
|
|
189
|
-
return this.events;
|
|
107
|
+
isCapturing() {
|
|
108
|
+
return this.asyncStorageUnsubscribe !== null || this.mmkvUnsubscribe !== null;
|
|
190
109
|
}
|
|
191
110
|
|
|
192
111
|
/**
|
|
@@ -195,43 +114,13 @@ class StorageEventStore {
|
|
|
195
114
|
getEventsByType(storageType) {
|
|
196
115
|
return this.events.filter(event => event.storageType === storageType);
|
|
197
116
|
}
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
* Get event count
|
|
201
|
-
*/
|
|
202
|
-
getEventCount() {
|
|
203
|
-
return this.events.length;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
/**
|
|
207
|
-
* Clear all events
|
|
208
|
-
*/
|
|
209
|
-
clearEvents() {
|
|
210
|
-
this.events = [];
|
|
211
|
-
this.notifyListeners();
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
/**
|
|
215
|
-
* Check if currently capturing events
|
|
216
|
-
*/
|
|
217
|
-
get capturing() {
|
|
218
|
-
return this.isCapturing;
|
|
219
|
-
}
|
|
220
117
|
}
|
|
221
118
|
|
|
222
119
|
// Singleton instance
|
|
223
120
|
const storageEventStore = exports.storageEventStore = new StorageEventStore();
|
|
224
121
|
|
|
225
122
|
// Convenience exports
|
|
226
|
-
const
|
|
227
|
-
exports.startStorageCapture = startStorageCapture;
|
|
228
|
-
const stopStorageCapture = () => storageEventStore.stopCapturing();
|
|
229
|
-
exports.stopStorageCapture = stopStorageCapture;
|
|
230
|
-
const pauseStorageCapture = () => storageEventStore.pauseCapture();
|
|
231
|
-
exports.pauseStorageCapture = pauseStorageCapture;
|
|
232
|
-
const resumeStorageCapture = () => storageEventStore.resumeCapture();
|
|
233
|
-
exports.resumeStorageCapture = resumeStorageCapture;
|
|
234
|
-
const subscribeToStorageEvents = listener => storageEventStore.subscribe(listener);
|
|
123
|
+
const subscribeToStorageEvents = listener => storageEventStore.subscribeToEvents(listener);
|
|
235
124
|
exports.subscribeToStorageEvents = subscribeToStorageEvents;
|
|
236
125
|
const onStorageEvent = callback => storageEventStore.onEvent(callback);
|
|
237
126
|
exports.onStorageEvent = onStorageEvent;
|
|
@@ -239,5 +128,5 @@ const getStorageEvents = () => storageEventStore.getEvents();
|
|
|
239
128
|
exports.getStorageEvents = getStorageEvents;
|
|
240
129
|
const clearStorageEvents = () => storageEventStore.clearEvents();
|
|
241
130
|
exports.clearStorageEvents = clearStorageEvents;
|
|
242
|
-
const isStorageCapturing = () => storageEventStore.
|
|
131
|
+
const isStorageCapturing = () => storageEventStore.isCapturing();
|
|
243
132
|
exports.isStorageCapturing = isStorageCapturing;
|
package/lib/module/index.js
CHANGED
|
@@ -65,7 +65,6 @@ export { storageEventStore } from "./storage/stores/storageEventStore";
|
|
|
65
65
|
// NOT EXPORTED (Internal capture controls)
|
|
66
66
|
// =============================================================================
|
|
67
67
|
// The following are intentionally NOT exported to prevent bypassing:
|
|
68
|
-
// - startStorageCapture, stopStorageCapture, pauseStorageCapture, resumeStorageCapture
|
|
69
68
|
// - subscribeToStorageEvents, onStorageEvent, getStorageEvents, clearStorageEvents
|
|
70
69
|
// - isStorageCapturing
|
|
71
70
|
// - startListening, stopListening, addListener, removeAllListeners (AsyncStorage)
|
|
@@ -3,11 +3,10 @@
|
|
|
3
3
|
import { useState, useCallback, useEffect, useRef, useMemo } from "react";
|
|
4
4
|
import { Text, View, TouchableOpacity, StyleSheet, FlatList, Alert } from "react-native";
|
|
5
5
|
import AsyncStorage from "@react-native-async-storage/async-storage";
|
|
6
|
-
import { JsModal, ModalHeader, TabSelector, parseValue, devToolsStorageKeys, macOSColors, Database,
|
|
6
|
+
import { JsModal, ModalHeader, TabSelector, parseValue, devToolsStorageKeys, macOSColors, Database, Trash2, Filter, Search, SearchBar, PowerToggleButton } from "@buoy-gg/shared-ui";
|
|
7
7
|
import { StorageBrowserMode } from "./StorageBrowserMode";
|
|
8
8
|
import { clearAllAppStorage, clearAllStorageIncludingDevTools } from "../utils/clearAllStorage";
|
|
9
9
|
import { ProFeatureBanner } from "@buoy-gg/shared-ui";
|
|
10
|
-
import { stopListening } from "../utils/AsyncStorageListener";
|
|
11
10
|
import { useStorageEvents } from "../hooks/useStorageEvents";
|
|
12
11
|
import { StorageEventDetailContent, StorageEventDetailFooter } from "./StorageEventDetailContent";
|
|
13
12
|
import { StorageFilterViewV2 } from "./StorageFilterViewV2";
|
|
@@ -40,17 +39,19 @@ export function StorageModalWithTabs({
|
|
|
40
39
|
const [isSearchActive, setIsSearchActive] = useState(false);
|
|
41
40
|
const hasLoadedStorageFilters = useRef(false);
|
|
42
41
|
|
|
42
|
+
// Local state to control subscription (true = subscribed, false = unsubscribed)
|
|
43
|
+
const [isListeningEnabled, setIsListeningEnabled] = useState(true);
|
|
44
|
+
|
|
43
45
|
// Event Listener state - using centralized store via hook
|
|
46
|
+
// Pass enabled option to control subscription - this allows events tool to
|
|
47
|
+
// continue receiving events while storage UI has toggled off
|
|
44
48
|
const {
|
|
45
49
|
events,
|
|
46
50
|
clearEvents: clearStorageEvents,
|
|
47
|
-
isCapturing
|
|
48
|
-
startCapturing,
|
|
49
|
-
stopCapturing
|
|
51
|
+
isCapturing
|
|
50
52
|
} = useStorageEvents({
|
|
51
|
-
|
|
52
|
-
});
|
|
53
|
-
const [isListening, setIsListening] = useState(false);
|
|
53
|
+
enabled: isListeningEnabled
|
|
54
|
+
});
|
|
54
55
|
const [selectedConversationKey, setSelectedConversationKey] = useState(null);
|
|
55
56
|
const [selectedEventIndex, setSelectedEventIndex] = useState(0);
|
|
56
57
|
const [showFilters, setShowFilters] = useState(false);
|
|
@@ -63,10 +64,8 @@ export function StorageModalWithTabs({
|
|
|
63
64
|
const hasLoadedTabState = useRef(false);
|
|
64
65
|
const hasLoadedMonitoringState = useRef(false);
|
|
65
66
|
|
|
66
|
-
//
|
|
67
|
-
|
|
68
|
-
setIsListening(isCapturing);
|
|
69
|
-
}, [isCapturing]);
|
|
67
|
+
// isListening = enabled and capturing (has subscribers)
|
|
68
|
+
const isListening = isListeningEnabled && isCapturing;
|
|
70
69
|
const handleModeChange = useCallback(_mode => {
|
|
71
70
|
// Mode changes handled by JsModal
|
|
72
71
|
}, []);
|
|
@@ -98,9 +97,7 @@ export function StorageModalWithTabs({
|
|
|
98
97
|
const storedMonitoring = await AsyncStorage.getItem(devToolsStorageKeys.storage.isMonitoring());
|
|
99
98
|
if (storedMonitoring !== null) {
|
|
100
99
|
const shouldMonitor = storedMonitoring === "true";
|
|
101
|
-
|
|
102
|
-
await startCapturing();
|
|
103
|
-
}
|
|
100
|
+
setIsListeningEnabled(shouldMonitor);
|
|
104
101
|
}
|
|
105
102
|
hasLoadedMonitoringState.current = true;
|
|
106
103
|
} catch (error) {
|
|
@@ -108,7 +105,7 @@ export function StorageModalWithTabs({
|
|
|
108
105
|
}
|
|
109
106
|
};
|
|
110
107
|
loadMonitoringState();
|
|
111
|
-
}, [visible
|
|
108
|
+
}, [visible]);
|
|
112
109
|
|
|
113
110
|
// Note: Conversations will appear when storage events are triggered
|
|
114
111
|
// Click on any conversation to see the unified view with toggle cards
|
|
@@ -177,14 +174,10 @@ export function StorageModalWithTabs({
|
|
|
177
174
|
// Event listener setup - now handled by useStorageEvents hook
|
|
178
175
|
// The hook subscribes to the centralized storageEventStore
|
|
179
176
|
|
|
180
|
-
const handleToggleListening = useCallback(
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
} else {
|
|
185
|
-
await startCapturing();
|
|
186
|
-
}
|
|
187
|
-
}, [isListening, startCapturing, stopCapturing]);
|
|
177
|
+
const handleToggleListening = useCallback(() => {
|
|
178
|
+
// Toggle subscription - this actually subscribes/unsubscribes from the store
|
|
179
|
+
setIsListeningEnabled(prev => !prev);
|
|
180
|
+
}, []);
|
|
188
181
|
const handleClearEvents = useCallback(() => {
|
|
189
182
|
clearStorageEvents();
|
|
190
183
|
setSelectedConversationKey(null);
|
|
@@ -573,16 +566,10 @@ export function StorageModalWithTabs({
|
|
|
573
566
|
size: 14,
|
|
574
567
|
color: ignoredPatterns.size > 0 ? macOSColors.semantic.debug : macOSColors.text.secondary
|
|
575
568
|
})
|
|
576
|
-
}), /*#__PURE__*/_jsx(
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
size: 14,
|
|
581
|
-
color: macOSColors.semantic.success
|
|
582
|
-
}) : /*#__PURE__*/_jsx(Play, {
|
|
583
|
-
size: 14,
|
|
584
|
-
color: macOSColors.semantic.success
|
|
585
|
-
})
|
|
569
|
+
}), /*#__PURE__*/_jsx(PowerToggleButton, {
|
|
570
|
+
isEnabled: isListening,
|
|
571
|
+
onToggle: handleToggleListening,
|
|
572
|
+
accessibilityLabel: "Toggle storage event monitoring"
|
|
586
573
|
}), /*#__PURE__*/_jsx(TouchableOpacity, {
|
|
587
574
|
onPress: handleClearEvents,
|
|
588
575
|
style: styles.iconButton,
|
|
@@ -619,9 +606,6 @@ const styles = StyleSheet.create({
|
|
|
619
606
|
alignItems: "center",
|
|
620
607
|
justifyContent: "center"
|
|
621
608
|
},
|
|
622
|
-
activeButton: {
|
|
623
|
-
backgroundColor: macOSColors.semantic.successBackground
|
|
624
|
-
},
|
|
625
609
|
activeFilterButton: {
|
|
626
610
|
backgroundColor: macOSColors.semantic.infoBackground
|
|
627
611
|
},
|
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
* useStorageEvents Hook
|
|
5
5
|
*
|
|
6
6
|
* React hook for subscribing to storage events from the centralized store.
|
|
7
|
-
*
|
|
7
|
+
* Uses self-managing Subscribable pattern - the storage listener automatically
|
|
8
|
+
* starts when this hook mounts and stops when all subscribers unmount.
|
|
8
9
|
*
|
|
9
10
|
* @example
|
|
10
11
|
* ```typescript
|
|
@@ -33,14 +34,21 @@ export function useStorageEvents(options = {}) {
|
|
|
33
34
|
const {
|
|
34
35
|
storageType = "all",
|
|
35
36
|
maxEvents = 500,
|
|
36
|
-
|
|
37
|
+
enabled = true
|
|
37
38
|
} = options;
|
|
38
39
|
const [events, setEvents] = useState([]);
|
|
39
|
-
|
|
40
|
+
// Track capturing state locally so it updates reactively with the subscription
|
|
41
|
+
const [isCapturing, setIsCapturing] = useState(enabled);
|
|
40
42
|
|
|
41
|
-
// Subscribe to store
|
|
43
|
+
// Subscribe to store - this automatically starts/stops the storage listener
|
|
44
|
+
// based on subscriber count (Subscribable pattern from TanStack Query)
|
|
45
|
+
// Only subscribe when enabled is true
|
|
42
46
|
useEffect(() => {
|
|
43
|
-
|
|
47
|
+
if (!enabled) {
|
|
48
|
+
setIsCapturing(false);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
const unsubscribe = storageEventStore.subscribeToEvents(allEvents => {
|
|
44
52
|
// Filter by storage type if specified
|
|
45
53
|
let filtered = allEvents;
|
|
46
54
|
if (storageType !== "all") {
|
|
@@ -52,44 +60,22 @@ export function useStorageEvents(options = {}) {
|
|
|
52
60
|
filtered = filtered.slice(0, maxEvents);
|
|
53
61
|
}
|
|
54
62
|
setEvents(filtered);
|
|
55
|
-
setIsCapturing(storageEventStore.capturing);
|
|
56
63
|
});
|
|
64
|
+
|
|
65
|
+
// Mark as capturing after successful subscription
|
|
66
|
+
setIsCapturing(true);
|
|
57
67
|
return () => {
|
|
58
68
|
unsubscribe();
|
|
69
|
+
// Note: Don't set isCapturing=false here because we might be
|
|
70
|
+
// re-subscribing due to dependency change, not actually stopping
|
|
59
71
|
};
|
|
60
|
-
}, [storageType, maxEvents]);
|
|
61
|
-
|
|
62
|
-
// Auto-start capturing on mount
|
|
63
|
-
useEffect(() => {
|
|
64
|
-
if (autoStart && !storageEventStore.capturing) {
|
|
65
|
-
storageEventStore.startCapturing();
|
|
66
|
-
setIsCapturing(true);
|
|
67
|
-
}
|
|
68
|
-
}, [autoStart]);
|
|
72
|
+
}, [storageType, maxEvents, enabled]);
|
|
69
73
|
const clearEvents = useCallback(() => {
|
|
70
74
|
storageEventStore.clearEvents();
|
|
71
75
|
}, []);
|
|
72
|
-
const startCapturing = useCallback(async () => {
|
|
73
|
-
await storageEventStore.startCapturing();
|
|
74
|
-
setIsCapturing(true);
|
|
75
|
-
}, []);
|
|
76
|
-
const stopCapturing = useCallback(() => {
|
|
77
|
-
storageEventStore.stopCapturing();
|
|
78
|
-
setIsCapturing(false);
|
|
79
|
-
}, []);
|
|
80
|
-
const pauseCapturing = useCallback(() => {
|
|
81
|
-
storageEventStore.pauseCapture();
|
|
82
|
-
}, []);
|
|
83
|
-
const resumeCapturing = useCallback(() => {
|
|
84
|
-
storageEventStore.resumeCapture();
|
|
85
|
-
}, []);
|
|
86
76
|
return {
|
|
87
77
|
events,
|
|
88
78
|
clearEvents,
|
|
89
|
-
isCapturing
|
|
90
|
-
startCapturing,
|
|
91
|
-
stopCapturing,
|
|
92
|
-
pauseCapturing,
|
|
93
|
-
resumeCapturing
|
|
79
|
+
isCapturing
|
|
94
80
|
};
|
|
95
81
|
}
|
|
@@ -28,4 +28,4 @@ export * from "./types";
|
|
|
28
28
|
export * from "./utils";
|
|
29
29
|
|
|
30
30
|
// Storage Event Store
|
|
31
|
-
export { storageEventStore,
|
|
31
|
+
export { storageEventStore, subscribeToStorageEvents, onStorageEvent, getStorageEvents, clearStorageEvents, isStorageCapturing } from "./stores/storageEventStore";
|
|
@@ -4,27 +4,26 @@
|
|
|
4
4
|
* Storage Event Store
|
|
5
5
|
*
|
|
6
6
|
* Centralized store that aggregates storage events from AsyncStorage and MMKV
|
|
7
|
-
* into a single event stream.
|
|
8
|
-
*
|
|
7
|
+
* into a single event stream. Uses BaseEventStore pattern - the storage listener
|
|
8
|
+
* automatically starts when the first subscriber joins and stops when the last
|
|
9
|
+
* subscriber leaves.
|
|
9
10
|
*
|
|
10
11
|
* @example
|
|
11
12
|
* ```typescript
|
|
12
13
|
* import { storageEventStore } from '@buoy-gg/storage';
|
|
13
14
|
*
|
|
14
|
-
* // Subscribe to storage events
|
|
15
|
-
* const unsubscribe = storageEventStore.
|
|
15
|
+
* // Subscribe to storage events - automatically starts capturing!
|
|
16
|
+
* const unsubscribe = storageEventStore.subscribeToEvents((events) => {
|
|
16
17
|
* console.log('Storage events:', events);
|
|
17
18
|
* });
|
|
18
19
|
*
|
|
19
|
-
* //
|
|
20
|
-
* await storageEventStore.startCapturing();
|
|
21
|
-
*
|
|
22
|
-
* // Later, clean up
|
|
20
|
+
* // Later, clean up - automatically stops if no other subscribers
|
|
23
21
|
* unsubscribe();
|
|
24
22
|
* ```
|
|
25
23
|
*/
|
|
26
24
|
|
|
27
|
-
import {
|
|
25
|
+
import { BaseEventStore } from "@buoy-gg/shared-ui";
|
|
26
|
+
import { startListening as startAsyncStorageListening, addListener as addAsyncStorageListener, isListening as isAsyncStorageListening } from "../utils/AsyncStorageListener";
|
|
28
27
|
import { addMMKVListener } from "../utils/MMKVListener";
|
|
29
28
|
|
|
30
29
|
/**
|
|
@@ -32,65 +31,60 @@ import { addMMKVListener } from "../utils/MMKVListener";
|
|
|
32
31
|
*/
|
|
33
32
|
|
|
34
33
|
/**
|
|
35
|
-
* Listener callback type for storage events
|
|
34
|
+
* Listener callback type for storage events array
|
|
36
35
|
*/
|
|
37
36
|
|
|
38
37
|
/**
|
|
39
38
|
* Listener callback for individual new events
|
|
40
39
|
*/
|
|
41
40
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
events = [];
|
|
45
|
-
listeners = new Set();
|
|
46
|
-
eventCallbacks = new Set();
|
|
47
|
-
isCapturing = false;
|
|
48
|
-
|
|
49
|
-
// Unsubscribe functions
|
|
41
|
+
class StorageEventStore extends BaseEventStore {
|
|
42
|
+
// Unsubscribe functions for raw listeners
|
|
50
43
|
asyncStorageUnsubscribe = null;
|
|
51
44
|
mmkvUnsubscribe = null;
|
|
45
|
+
constructor() {
|
|
46
|
+
super({
|
|
47
|
+
storeName: "storage",
|
|
48
|
+
maxEvents: 500
|
|
49
|
+
});
|
|
50
|
+
}
|
|
52
51
|
|
|
53
52
|
/**
|
|
54
53
|
* Start capturing storage events from both AsyncStorage and MMKV
|
|
55
54
|
*/
|
|
56
55
|
async startCapturing() {
|
|
57
|
-
if (this.isCapturing) {
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
56
|
// Start AsyncStorage listening if not already active
|
|
62
57
|
if (!isAsyncStorageListening()) {
|
|
63
58
|
await startAsyncStorageListening();
|
|
64
59
|
}
|
|
65
60
|
|
|
66
61
|
// Subscribe to AsyncStorage events
|
|
67
|
-
this.asyncStorageUnsubscribe
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
62
|
+
if (!this.asyncStorageUnsubscribe) {
|
|
63
|
+
this.asyncStorageUnsubscribe = addAsyncStorageListener(event => {
|
|
64
|
+
const storageEvent = {
|
|
65
|
+
...event,
|
|
66
|
+
storageType: "async"
|
|
67
|
+
};
|
|
68
|
+
this.addEvent(storageEvent);
|
|
69
|
+
});
|
|
70
|
+
}
|
|
74
71
|
|
|
75
72
|
// Subscribe to MMKV events
|
|
76
|
-
this.mmkvUnsubscribe
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
73
|
+
if (!this.mmkvUnsubscribe) {
|
|
74
|
+
this.mmkvUnsubscribe = addMMKVListener(event => {
|
|
75
|
+
const storageEvent = {
|
|
76
|
+
...event,
|
|
77
|
+
storageType: "mmkv"
|
|
78
|
+
};
|
|
79
|
+
this.addEvent(storageEvent);
|
|
80
|
+
});
|
|
81
|
+
}
|
|
84
82
|
}
|
|
85
83
|
|
|
86
84
|
/**
|
|
87
85
|
* Stop capturing storage events
|
|
88
86
|
*/
|
|
89
87
|
stopCapturing() {
|
|
90
|
-
if (!this.isCapturing) {
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
88
|
// Unsubscribe from AsyncStorage
|
|
95
89
|
if (this.asyncStorageUnsubscribe) {
|
|
96
90
|
this.asyncStorageUnsubscribe();
|
|
@@ -102,88 +96,13 @@ class StorageEventStore {
|
|
|
102
96
|
this.mmkvUnsubscribe();
|
|
103
97
|
this.mmkvUnsubscribe = null;
|
|
104
98
|
}
|
|
105
|
-
this.isCapturing = false;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Pause event capture (used during time-travel operations)
|
|
110
|
-
*/
|
|
111
|
-
pauseCapture() {
|
|
112
|
-
pauseAsyncStorageCapture();
|
|
113
|
-
// MMKV listener doesn't have pause, but it's less common for time-travel
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* Resume event capture after pausing
|
|
118
|
-
*/
|
|
119
|
-
resumeCapture() {
|
|
120
|
-
resumeAsyncStorageCapture();
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Add an event to the store
|
|
125
|
-
*/
|
|
126
|
-
addEvent(event) {
|
|
127
|
-
// Add to beginning (newest first)
|
|
128
|
-
this.events = [event, ...this.events].slice(0, MAX_EVENTS);
|
|
129
|
-
|
|
130
|
-
// Notify event callbacks (for individual events)
|
|
131
|
-
this.eventCallbacks.forEach(callback => {
|
|
132
|
-
try {
|
|
133
|
-
callback(event);
|
|
134
|
-
} catch {
|
|
135
|
-
// Ignore callback errors
|
|
136
|
-
}
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
// Notify listeners (for full event list)
|
|
140
|
-
this.notifyListeners();
|
|
141
99
|
}
|
|
142
100
|
|
|
143
101
|
/**
|
|
144
|
-
*
|
|
102
|
+
* Check if currently capturing events (has subscribers)
|
|
145
103
|
*/
|
|
146
|
-
|
|
147
|
-
this.
|
|
148
|
-
|
|
149
|
-
// Immediately call with current events
|
|
150
|
-
listener(this.events);
|
|
151
|
-
|
|
152
|
-
// Return unsubscribe function
|
|
153
|
-
return () => {
|
|
154
|
-
this.listeners.delete(listener);
|
|
155
|
-
};
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
/**
|
|
159
|
-
* Subscribe to new events only (receives individual events as they occur)
|
|
160
|
-
*/
|
|
161
|
-
onEvent(callback) {
|
|
162
|
-
this.eventCallbacks.add(callback);
|
|
163
|
-
return () => {
|
|
164
|
-
this.eventCallbacks.delete(callback);
|
|
165
|
-
};
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* Notify all listeners of changes
|
|
170
|
-
*/
|
|
171
|
-
notifyListeners() {
|
|
172
|
-
const events = this.events;
|
|
173
|
-
this.listeners.forEach(listener => {
|
|
174
|
-
try {
|
|
175
|
-
listener(events);
|
|
176
|
-
} catch {
|
|
177
|
-
// Ignore listener errors
|
|
178
|
-
}
|
|
179
|
-
});
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
/**
|
|
183
|
-
* Get all events
|
|
184
|
-
*/
|
|
185
|
-
getEvents() {
|
|
186
|
-
return this.events;
|
|
104
|
+
isCapturing() {
|
|
105
|
+
return this.asyncStorageUnsubscribe !== null || this.mmkvUnsubscribe !== null;
|
|
187
106
|
}
|
|
188
107
|
|
|
189
108
|
/**
|
|
@@ -192,40 +111,14 @@ class StorageEventStore {
|
|
|
192
111
|
getEventsByType(storageType) {
|
|
193
112
|
return this.events.filter(event => event.storageType === storageType);
|
|
194
113
|
}
|
|
195
|
-
|
|
196
|
-
/**
|
|
197
|
-
* Get event count
|
|
198
|
-
*/
|
|
199
|
-
getEventCount() {
|
|
200
|
-
return this.events.length;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* Clear all events
|
|
205
|
-
*/
|
|
206
|
-
clearEvents() {
|
|
207
|
-
this.events = [];
|
|
208
|
-
this.notifyListeners();
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
/**
|
|
212
|
-
* Check if currently capturing events
|
|
213
|
-
*/
|
|
214
|
-
get capturing() {
|
|
215
|
-
return this.isCapturing;
|
|
216
|
-
}
|
|
217
114
|
}
|
|
218
115
|
|
|
219
116
|
// Singleton instance
|
|
220
117
|
export const storageEventStore = new StorageEventStore();
|
|
221
118
|
|
|
222
119
|
// Convenience exports
|
|
223
|
-
export const
|
|
224
|
-
export const stopStorageCapture = () => storageEventStore.stopCapturing();
|
|
225
|
-
export const pauseStorageCapture = () => storageEventStore.pauseCapture();
|
|
226
|
-
export const resumeStorageCapture = () => storageEventStore.resumeCapture();
|
|
227
|
-
export const subscribeToStorageEvents = listener => storageEventStore.subscribe(listener);
|
|
120
|
+
export const subscribeToStorageEvents = listener => storageEventStore.subscribeToEvents(listener);
|
|
228
121
|
export const onStorageEvent = callback => storageEventStore.onEvent(callback);
|
|
229
122
|
export const getStorageEvents = () => storageEventStore.getEvents();
|
|
230
123
|
export const clearStorageEvents = () => storageEventStore.clearEvents();
|
|
231
|
-
export const isStorageCapturing = () => storageEventStore.
|
|
124
|
+
export const isStorageCapturing = () => storageEventStore.isCapturing();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StorageModalWithTabs.d.ts","sourceRoot":"","sources":["../../../../src/storage/components/StorageModalWithTabs.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"StorageModalWithTabs.d.ts","sourceRoot":"","sources":["../../../../src/storage/components/StorageModalWithTabs.tsx"],"names":[],"mappings":"AAyBA,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAuB9C,eAAO,MAAM,qBAAqB,KAAK,CAAC;AAExC,UAAU,yBAAyB;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,UAAU,CAAC,EAAE,CAAC,UAAU,EAAE,GAAG,KAAK,IAAI,CAAC;IACvC,2BAA2B,CAAC,EAAE,OAAO,CAAC;IACtC,mBAAmB,CAAC,EAAE,kBAAkB,EAAE,CAAC;CAC5C;AAqBD,wBAAgB,oBAAoB,CAAC,EACnC,OAAO,EACP,OAAO,EACP,MAAM,EACN,UAAU,EACV,2BAAmC,EACnC,mBAAwB,GACzB,EAAE,yBAAyB,sCA+rB3B"}
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
* useStorageEvents Hook
|
|
3
3
|
*
|
|
4
4
|
* React hook for subscribing to storage events from the centralized store.
|
|
5
|
-
*
|
|
5
|
+
* Uses self-managing Subscribable pattern - the storage listener automatically
|
|
6
|
+
* starts when this hook mounts and stops when all subscribers unmount.
|
|
6
7
|
*
|
|
7
8
|
* @example
|
|
8
9
|
* ```typescript
|
|
@@ -28,24 +29,16 @@ export interface UseStorageEventsOptions {
|
|
|
28
29
|
storageType?: "async" | "mmkv" | "all";
|
|
29
30
|
/** Maximum number of events to keep in state */
|
|
30
31
|
maxEvents?: number;
|
|
31
|
-
/**
|
|
32
|
-
|
|
32
|
+
/** Whether to subscribe to events (default: true). Set to false to unsubscribe. */
|
|
33
|
+
enabled?: boolean;
|
|
33
34
|
}
|
|
34
35
|
export interface UseStorageEventsResult {
|
|
35
36
|
/** All storage events (newest first) */
|
|
36
37
|
events: StorageEvent[];
|
|
37
38
|
/** Clear all events */
|
|
38
39
|
clearEvents: () => void;
|
|
39
|
-
/** Whether events are being captured */
|
|
40
|
+
/** Whether events are being captured (has subscribers) */
|
|
40
41
|
isCapturing: boolean;
|
|
41
|
-
/** Start capturing events */
|
|
42
|
-
startCapturing: () => Promise<void>;
|
|
43
|
-
/** Stop capturing events */
|
|
44
|
-
stopCapturing: () => void;
|
|
45
|
-
/** Pause capturing (for time-travel) */
|
|
46
|
-
pauseCapturing: () => void;
|
|
47
|
-
/** Resume capturing after pause */
|
|
48
|
-
resumeCapturing: () => void;
|
|
49
42
|
}
|
|
50
43
|
export declare function useStorageEvents(options?: UseStorageEventsOptions): UseStorageEventsResult;
|
|
51
44
|
//# sourceMappingURL=useStorageEvents.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useStorageEvents.d.ts","sourceRoot":"","sources":["../../../../src/storage/hooks/useStorageEvents.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"useStorageEvents.d.ts","sourceRoot":"","sources":["../../../../src/storage/hooks/useStorageEvents.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAGH,OAAO,EAEL,KAAK,YAAY,EAClB,MAAM,6BAA6B,CAAC;AAGrC,YAAY,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAEhE,MAAM,WAAW,uBAAuB;IACtC,6BAA6B;IAC7B,WAAW,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,KAAK,CAAC;IACvC,gDAAgD;IAChD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mFAAmF;IACnF,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,sBAAsB;IACrC,wCAAwC;IACxC,MAAM,EAAE,YAAY,EAAE,CAAC;IACvB,uBAAuB;IACvB,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,0DAA0D;IAC1D,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,wBAAgB,gBAAgB,CAC9B,OAAO,GAAE,uBAA4B,GACpC,sBAAsB,CAkDxB"}
|
|
@@ -15,5 +15,5 @@ export { MMKVInstanceSelector } from "./components/MMKVInstanceSelector";
|
|
|
15
15
|
export { MMKVInstanceInfoPanel } from "./components/MMKVInstanceInfoPanel";
|
|
16
16
|
export * from "./types";
|
|
17
17
|
export * from "./utils";
|
|
18
|
-
export { storageEventStore,
|
|
18
|
+
export { storageEventStore, subscribeToStorageEvents, onStorageEvent, getStorageEvents, clearStorageEvents, isStorageCapturing, type StorageEvent, type StorageEventListener, type StorageEventCallback, } from "./stores/storageEventStore";
|
|
19
19
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/storage/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AACzE,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AACtE,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AACrE,OAAO,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AACzE,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,KAAK,oBAAoB,EAAE,KAAK,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjI,OAAO,EAAE,yBAAyB,EAAE,wBAAwB,EAAE,MAAM,wCAAwC,CAAC;AAG7G,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACpG,OAAO,EAAE,gBAAgB,EAAE,KAAK,uBAAuB,EAAE,KAAK,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAGvH,OAAO,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AACzE,OAAO,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAC;AAG3E,cAAc,SAAS,CAAC;AAGxB,cAAc,SAAS,CAAC;AAGxB,OAAO,EACL,iBAAiB,EACjB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/storage/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AACzE,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AACtE,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AACrE,OAAO,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AACzE,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,KAAK,oBAAoB,EAAE,KAAK,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjI,OAAO,EAAE,yBAAyB,EAAE,wBAAwB,EAAE,MAAM,wCAAwC,CAAC;AAG7G,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACpG,OAAO,EAAE,gBAAgB,EAAE,KAAK,uBAAuB,EAAE,KAAK,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAGvH,OAAO,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AACzE,OAAO,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAC;AAG3E,cAAc,SAAS,CAAC;AAGxB,cAAc,SAAS,CAAC;AAGxB,OAAO,EACL,iBAAiB,EACjB,wBAAwB,EACxB,cAAc,EACd,gBAAgB,EAChB,kBAAkB,EAClB,kBAAkB,EAClB,KAAK,YAAY,EACjB,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,GAC1B,MAAM,4BAA4B,CAAC"}
|
|
@@ -2,25 +2,24 @@
|
|
|
2
2
|
* Storage Event Store
|
|
3
3
|
*
|
|
4
4
|
* Centralized store that aggregates storage events from AsyncStorage and MMKV
|
|
5
|
-
* into a single event stream.
|
|
6
|
-
*
|
|
5
|
+
* into a single event stream. Uses BaseEventStore pattern - the storage listener
|
|
6
|
+
* automatically starts when the first subscriber joins and stops when the last
|
|
7
|
+
* subscriber leaves.
|
|
7
8
|
*
|
|
8
9
|
* @example
|
|
9
10
|
* ```typescript
|
|
10
11
|
* import { storageEventStore } from '@buoy-gg/storage';
|
|
11
12
|
*
|
|
12
|
-
* // Subscribe to storage events
|
|
13
|
-
* const unsubscribe = storageEventStore.
|
|
13
|
+
* // Subscribe to storage events - automatically starts capturing!
|
|
14
|
+
* const unsubscribe = storageEventStore.subscribeToEvents((events) => {
|
|
14
15
|
* console.log('Storage events:', events);
|
|
15
16
|
* });
|
|
16
17
|
*
|
|
17
|
-
* //
|
|
18
|
-
* await storageEventStore.startCapturing();
|
|
19
|
-
*
|
|
20
|
-
* // Later, clean up
|
|
18
|
+
* // Later, clean up - automatically stops if no other subscribers
|
|
21
19
|
* unsubscribe();
|
|
22
20
|
* ```
|
|
23
21
|
*/
|
|
22
|
+
import { BaseEventStore } from "@buoy-gg/shared-ui";
|
|
24
23
|
import { type AsyncStorageEvent } from "../utils/AsyncStorageListener";
|
|
25
24
|
import { type MMKVEvent } from "../utils/MMKVListener";
|
|
26
25
|
/**
|
|
@@ -32,78 +31,35 @@ export type StorageEvent = (AsyncStorageEvent & {
|
|
|
32
31
|
storageType: "mmkv";
|
|
33
32
|
});
|
|
34
33
|
/**
|
|
35
|
-
* Listener callback type for storage events
|
|
34
|
+
* Listener callback type for storage events array
|
|
36
35
|
*/
|
|
37
36
|
export type StorageEventListener = (events: StorageEvent[]) => void;
|
|
38
37
|
/**
|
|
39
38
|
* Listener callback for individual new events
|
|
40
39
|
*/
|
|
41
40
|
export type StorageEventCallback = (event: StorageEvent) => void;
|
|
42
|
-
declare class StorageEventStore {
|
|
43
|
-
private events;
|
|
44
|
-
private listeners;
|
|
45
|
-
private eventCallbacks;
|
|
46
|
-
private isCapturing;
|
|
41
|
+
declare class StorageEventStore extends BaseEventStore<StorageEvent> {
|
|
47
42
|
private asyncStorageUnsubscribe;
|
|
48
43
|
private mmkvUnsubscribe;
|
|
44
|
+
constructor();
|
|
49
45
|
/**
|
|
50
46
|
* Start capturing storage events from both AsyncStorage and MMKV
|
|
51
47
|
*/
|
|
52
|
-
startCapturing(): Promise<void>;
|
|
48
|
+
protected startCapturing(): Promise<void>;
|
|
53
49
|
/**
|
|
54
50
|
* Stop capturing storage events
|
|
55
51
|
*/
|
|
56
|
-
stopCapturing(): void;
|
|
57
|
-
/**
|
|
58
|
-
* Pause event capture (used during time-travel operations)
|
|
59
|
-
*/
|
|
60
|
-
pauseCapture(): void;
|
|
61
|
-
/**
|
|
62
|
-
* Resume event capture after pausing
|
|
63
|
-
*/
|
|
64
|
-
resumeCapture(): void;
|
|
52
|
+
protected stopCapturing(): void;
|
|
65
53
|
/**
|
|
66
|
-
*
|
|
54
|
+
* Check if currently capturing events (has subscribers)
|
|
67
55
|
*/
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Subscribe to all storage events (receives full event array on each change)
|
|
71
|
-
*/
|
|
72
|
-
subscribe(listener: StorageEventListener): () => void;
|
|
73
|
-
/**
|
|
74
|
-
* Subscribe to new events only (receives individual events as they occur)
|
|
75
|
-
*/
|
|
76
|
-
onEvent(callback: StorageEventCallback): () => void;
|
|
77
|
-
/**
|
|
78
|
-
* Notify all listeners of changes
|
|
79
|
-
*/
|
|
80
|
-
private notifyListeners;
|
|
81
|
-
/**
|
|
82
|
-
* Get all events
|
|
83
|
-
*/
|
|
84
|
-
getEvents(): StorageEvent[];
|
|
56
|
+
isCapturing(): boolean;
|
|
85
57
|
/**
|
|
86
58
|
* Get events filtered by storage type
|
|
87
59
|
*/
|
|
88
60
|
getEventsByType(storageType: "async" | "mmkv"): StorageEvent[];
|
|
89
|
-
/**
|
|
90
|
-
* Get event count
|
|
91
|
-
*/
|
|
92
|
-
getEventCount(): number;
|
|
93
|
-
/**
|
|
94
|
-
* Clear all events
|
|
95
|
-
*/
|
|
96
|
-
clearEvents(): void;
|
|
97
|
-
/**
|
|
98
|
-
* Check if currently capturing events
|
|
99
|
-
*/
|
|
100
|
-
get capturing(): boolean;
|
|
101
61
|
}
|
|
102
62
|
export declare const storageEventStore: StorageEventStore;
|
|
103
|
-
export declare const startStorageCapture: () => Promise<void>;
|
|
104
|
-
export declare const stopStorageCapture: () => void;
|
|
105
|
-
export declare const pauseStorageCapture: () => void;
|
|
106
|
-
export declare const resumeStorageCapture: () => void;
|
|
107
63
|
export declare const subscribeToStorageEvents: (listener: StorageEventListener) => () => void;
|
|
108
64
|
export declare const onStorageEvent: (callback: StorageEventCallback) => () => void;
|
|
109
65
|
export declare const getStorageEvents: () => StorageEvent[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storageEventStore.d.ts","sourceRoot":"","sources":["../../../../src/storage/stores/storageEventStore.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"storageEventStore.d.ts","sourceRoot":"","sources":["../../../../src/storage/stores/storageEventStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAIL,KAAK,iBAAiB,EACvB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAEL,KAAK,SAAS,EACf,MAAM,uBAAuB,CAAC;AAE/B;;GAEG;AACH,MAAM,MAAM,YAAY,GACpB,CAAC,iBAAiB,GAAG;IAAE,WAAW,EAAE,OAAO,CAAA;CAAE,CAAC,GAC9C,CAAC,SAAS,GAAG;IAAE,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAE1C;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,MAAM,EAAE,YAAY,EAAE,KAAK,IAAI,CAAC;AAEpE;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;AAEjE,cAAM,iBAAkB,SAAQ,cAAc,CAAC,YAAY,CAAC;IAE1D,OAAO,CAAC,uBAAuB,CAA6B;IAC5D,OAAO,CAAC,eAAe,CAA6B;;IASpD;;OAEG;cACa,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAyB/C;;OAEG;IACH,SAAS,CAAC,aAAa,IAAI,IAAI;IAc/B;;OAEG;IACH,WAAW,IAAI,OAAO;IAItB;;OAEG;IACH,eAAe,CAAC,WAAW,EAAE,OAAO,GAAG,MAAM,GAAG,YAAY,EAAE;CAG/D;AAGD,eAAO,MAAM,iBAAiB,mBAA0B,CAAC;AAGzD,eAAO,MAAM,wBAAwB,GAAI,UAAU,oBAAoB,eACxB,CAAC;AAChD,eAAO,MAAM,cAAc,GAAI,UAAU,oBAAoB,eACxB,CAAC;AACtC,eAAO,MAAM,gBAAgB,sBAAsC,CAAC;AACpE,eAAO,MAAM,kBAAkB,YAAwC,CAAC;AACxE,eAAO,MAAM,kBAAkB,eAAwC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@buoy-gg/storage",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.3",
|
|
4
4
|
"description": "storage package",
|
|
5
5
|
"main": "lib/commonjs/index.js",
|
|
6
6
|
"module": "lib/module/index.js",
|
|
@@ -26,8 +26,8 @@
|
|
|
26
26
|
],
|
|
27
27
|
"sideEffects": false,
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@buoy-gg/
|
|
30
|
-
"@buoy-gg/
|
|
29
|
+
"@buoy-gg/shared-ui": "2.1.3",
|
|
30
|
+
"@buoy-gg/floating-tools-core": "2.1.3"
|
|
31
31
|
},
|
|
32
32
|
"peerDependencies": {
|
|
33
33
|
"@buoy-gg/license": "*",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"@types/react": "^19.1.0",
|
|
41
41
|
"@types/react-native": "^0.73.0",
|
|
42
42
|
"typescript": "~5.8.3",
|
|
43
|
-
"@buoy-gg/license": "2.1.
|
|
43
|
+
"@buoy-gg/license": "2.1.3"
|
|
44
44
|
},
|
|
45
45
|
"react-native-builder-bob": {
|
|
46
46
|
"source": "src",
|