@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,243 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.subscribeToStorageEvents = exports.storageEventStore = exports.stopStorageCapture = exports.startStorageCapture = exports.resumeStorageCapture = exports.pauseStorageCapture = exports.onStorageEvent = exports.isStorageCapturing = exports.getStorageEvents = exports.clearStorageEvents = void 0;
|
|
7
|
+
var _AsyncStorageListener = require("../utils/AsyncStorageListener");
|
|
8
|
+
var _MMKVListener = require("../utils/MMKVListener");
|
|
9
|
+
/**
|
|
10
|
+
* Storage Event Store
|
|
11
|
+
*
|
|
12
|
+
* Centralized store that aggregates storage events from AsyncStorage and MMKV
|
|
13
|
+
* into a single event stream. This provides a single source of truth for all
|
|
14
|
+
* storage operations, eliminating duplicate subscriptions across components.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* import { storageEventStore } from '@buoy-gg/storage';
|
|
19
|
+
*
|
|
20
|
+
* // Subscribe to storage events
|
|
21
|
+
* const unsubscribe = storageEventStore.subscribe((events) => {
|
|
22
|
+
* console.log('Storage events:', events);
|
|
23
|
+
* });
|
|
24
|
+
*
|
|
25
|
+
* // Start capturing (must be called once)
|
|
26
|
+
* await storageEventStore.startCapturing();
|
|
27
|
+
*
|
|
28
|
+
* // Later, clean up
|
|
29
|
+
* unsubscribe();
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Unified storage event type combining AsyncStorage and MMKV events
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Listener callback type for storage events
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Listener callback for individual new events
|
|
43
|
+
*/
|
|
44
|
+
|
|
45
|
+
const MAX_EVENTS = 500;
|
|
46
|
+
class StorageEventStore {
|
|
47
|
+
events = [];
|
|
48
|
+
listeners = new Set();
|
|
49
|
+
eventCallbacks = new Set();
|
|
50
|
+
isCapturing = false;
|
|
51
|
+
|
|
52
|
+
// Unsubscribe functions
|
|
53
|
+
asyncStorageUnsubscribe = null;
|
|
54
|
+
mmkvUnsubscribe = null;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Start capturing storage events from both AsyncStorage and MMKV
|
|
58
|
+
*/
|
|
59
|
+
async startCapturing() {
|
|
60
|
+
if (this.isCapturing) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Start AsyncStorage listening if not already active
|
|
65
|
+
if (!(0, _AsyncStorageListener.isListening)()) {
|
|
66
|
+
await (0, _AsyncStorageListener.startListening)();
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Subscribe to AsyncStorage events
|
|
70
|
+
this.asyncStorageUnsubscribe = (0, _AsyncStorageListener.addListener)(event => {
|
|
71
|
+
const storageEvent = {
|
|
72
|
+
...event,
|
|
73
|
+
storageType: "async"
|
|
74
|
+
};
|
|
75
|
+
this.addEvent(storageEvent);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// Subscribe to MMKV events
|
|
79
|
+
this.mmkvUnsubscribe = (0, _MMKVListener.addMMKVListener)(event => {
|
|
80
|
+
const storageEvent = {
|
|
81
|
+
...event,
|
|
82
|
+
storageType: "mmkv"
|
|
83
|
+
};
|
|
84
|
+
this.addEvent(storageEvent);
|
|
85
|
+
});
|
|
86
|
+
this.isCapturing = true;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Stop capturing storage events
|
|
91
|
+
*/
|
|
92
|
+
stopCapturing() {
|
|
93
|
+
if (!this.isCapturing) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Unsubscribe from AsyncStorage
|
|
98
|
+
if (this.asyncStorageUnsubscribe) {
|
|
99
|
+
this.asyncStorageUnsubscribe();
|
|
100
|
+
this.asyncStorageUnsubscribe = null;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Unsubscribe from MMKV
|
|
104
|
+
if (this.mmkvUnsubscribe) {
|
|
105
|
+
this.mmkvUnsubscribe();
|
|
106
|
+
this.mmkvUnsubscribe = null;
|
|
107
|
+
}
|
|
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
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Subscribe to all storage events (receives full event array on each change)
|
|
148
|
+
*/
|
|
149
|
+
subscribe(listener) {
|
|
150
|
+
this.listeners.add(listener);
|
|
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;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Get events filtered by storage type
|
|
194
|
+
*/
|
|
195
|
+
getEventsByType(storageType) {
|
|
196
|
+
return this.events.filter(event => event.storageType === storageType);
|
|
197
|
+
}
|
|
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
|
+
}
|
|
221
|
+
|
|
222
|
+
// Singleton instance
|
|
223
|
+
const storageEventStore = exports.storageEventStore = new StorageEventStore();
|
|
224
|
+
|
|
225
|
+
// Convenience exports
|
|
226
|
+
const startStorageCapture = () => storageEventStore.startCapturing();
|
|
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);
|
|
235
|
+
exports.subscribeToStorageEvents = subscribeToStorageEvents;
|
|
236
|
+
const onStorageEvent = callback => storageEventStore.onEvent(callback);
|
|
237
|
+
exports.onStorageEvent = onStorageEvent;
|
|
238
|
+
const getStorageEvents = () => storageEventStore.getEvents();
|
|
239
|
+
exports.getStorageEvents = getStorageEvents;
|
|
240
|
+
const clearStorageEvents = () => storageEventStore.clearEvents();
|
|
241
|
+
exports.clearStorageEvents = clearStorageEvents;
|
|
242
|
+
const isStorageCapturing = () => storageEventStore.capturing;
|
|
243
|
+
exports.isStorageCapturing = isStorageCapturing;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.stopListening = exports.startListening = exports.removeAllListeners = exports.isListening = exports.getListenerCount = exports.default = exports.addListener = void 0;
|
|
6
|
+
exports.stopListening = exports.startListening = exports.resumeCapture = exports.removeAllListeners = exports.pauseCapture = exports.isPaused = exports.isListening = exports.getListenerCount = exports.default = exports.addListener = void 0;
|
|
7
7
|
var _asyncStorage = _interopRequireDefault(require("@react-native-async-storage/async-storage"));
|
|
8
8
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
9
9
|
// AsyncStorage method signatures - matching the actual AsyncStorage API
|
|
@@ -40,6 +40,7 @@ class AsyncStorageListener {
|
|
|
40
40
|
listeners = [];
|
|
41
41
|
isListening = false;
|
|
42
42
|
isInitialized = false;
|
|
43
|
+
isPaused = false;
|
|
43
44
|
|
|
44
45
|
// Keys to ignore for dev tools to prevent self-triggering
|
|
45
46
|
// Only ignore specific keys that would cause infinite loops in the storage browser
|
|
@@ -153,9 +154,14 @@ class AsyncStorageListener {
|
|
|
153
154
|
*
|
|
154
155
|
* @param event - The AsyncStorage event to emit
|
|
155
156
|
*
|
|
156
|
-
* @performance Skips processing when no listeners are registered
|
|
157
|
+
* @performance Skips processing when no listeners are registered or when paused
|
|
157
158
|
*/
|
|
158
159
|
emit(event) {
|
|
160
|
+
// Skip emitting if paused (used during time-travel operations)
|
|
161
|
+
if (this.isPaused) {
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
|
|
159
165
|
// Skip emitting if there are no listeners
|
|
160
166
|
if (this.listeners.length === 0) {
|
|
161
167
|
return;
|
|
@@ -198,16 +204,25 @@ class AsyncStorageListener {
|
|
|
198
204
|
|
|
199
205
|
// Swizzle setItem
|
|
200
206
|
const swizzled_setItem = async (key, value) => {
|
|
201
|
-
// Only emit
|
|
207
|
+
// Only capture and emit if key is not ignored
|
|
202
208
|
if (!this.shouldIgnoreKey(key)) {
|
|
209
|
+
// Capture previous value before the operation
|
|
210
|
+
const prevValue = this.originalSetItem ? await _asyncStorage.default.getItem(key) : null;
|
|
211
|
+
|
|
212
|
+
// Execute the operation
|
|
213
|
+
const result = this.originalSetItem ? await this.originalSetItem(key, value) : undefined;
|
|
214
|
+
|
|
215
|
+
// Emit event with previous value
|
|
203
216
|
this.emit({
|
|
204
217
|
action: "setItem",
|
|
205
218
|
timestamp: new Date(),
|
|
206
219
|
data: {
|
|
207
220
|
key,
|
|
208
|
-
value
|
|
221
|
+
value,
|
|
222
|
+
prevValue
|
|
209
223
|
}
|
|
210
224
|
});
|
|
225
|
+
return result;
|
|
211
226
|
}
|
|
212
227
|
return this.originalSetItem ? this.originalSetItem(key, value) : Promise.resolve();
|
|
213
228
|
};
|
|
@@ -221,19 +236,24 @@ class AsyncStorageListener {
|
|
|
221
236
|
// Swizzle removeItem
|
|
222
237
|
if (_asyncStorage.default) {
|
|
223
238
|
_asyncStorage.default.removeItem = async key => {
|
|
224
|
-
//
|
|
225
|
-
|
|
226
|
-
// Only emit event if key is not ignored
|
|
239
|
+
// Only capture and emit if key is not ignored
|
|
227
240
|
if (!this.shouldIgnoreKey(key)) {
|
|
241
|
+
// Capture previous value before the operation
|
|
242
|
+
const prevValue = this.originalRemoveItem ? await _asyncStorage.default.getItem(key) : null;
|
|
243
|
+
|
|
244
|
+
// Execute the operation
|
|
245
|
+
const result = this.originalRemoveItem ? await this.originalRemoveItem(key) : undefined;
|
|
246
|
+
|
|
247
|
+
// Emit event with previous value
|
|
228
248
|
this.emit({
|
|
229
249
|
action: "removeItem",
|
|
230
250
|
timestamp: new Date(),
|
|
231
251
|
data: {
|
|
232
|
-
key
|
|
252
|
+
key,
|
|
253
|
+
prevValue
|
|
233
254
|
}
|
|
234
255
|
});
|
|
235
|
-
|
|
236
|
-
// Ignoring removeItem for ignored key
|
|
256
|
+
return result;
|
|
237
257
|
}
|
|
238
258
|
return this.originalRemoveItem ? this.originalRemoveItem(key) : Promise.resolve();
|
|
239
259
|
};
|
|
@@ -242,20 +262,25 @@ class AsyncStorageListener {
|
|
|
242
262
|
// Swizzle mergeItem
|
|
243
263
|
if (_asyncStorage.default) {
|
|
244
264
|
_asyncStorage.default.mergeItem = async (key, value) => {
|
|
245
|
-
//
|
|
246
|
-
|
|
247
|
-
// Only emit event if key is not ignored
|
|
265
|
+
// Only capture and emit if key is not ignored
|
|
248
266
|
if (!this.shouldIgnoreKey(key)) {
|
|
267
|
+
// Capture previous value before the operation
|
|
268
|
+
const prevValue = this.originalMergeItem ? await _asyncStorage.default.getItem(key) : null;
|
|
269
|
+
|
|
270
|
+
// Execute the operation
|
|
271
|
+
const result = this.originalMergeItem ? await this.originalMergeItem(key, value) : undefined;
|
|
272
|
+
|
|
273
|
+
// Emit event with previous value
|
|
249
274
|
this.emit({
|
|
250
275
|
action: "mergeItem",
|
|
251
276
|
timestamp: new Date(),
|
|
252
277
|
data: {
|
|
253
278
|
key,
|
|
254
|
-
value
|
|
279
|
+
value,
|
|
280
|
+
prevValue
|
|
255
281
|
}
|
|
256
282
|
});
|
|
257
|
-
|
|
258
|
-
// Ignoring mergeItem for ignored key
|
|
283
|
+
return result;
|
|
259
284
|
}
|
|
260
285
|
return this.originalMergeItem ? this.originalMergeItem(key, value) : Promise.resolve();
|
|
261
286
|
};
|
|
@@ -264,32 +289,64 @@ class AsyncStorageListener {
|
|
|
264
289
|
// Swizzle clear
|
|
265
290
|
if (_asyncStorage.default) {
|
|
266
291
|
_asyncStorage.default.clear = async () => {
|
|
267
|
-
//
|
|
292
|
+
// Capture all key-value pairs before clearing
|
|
293
|
+
let prevPairs = [];
|
|
294
|
+
try {
|
|
295
|
+
const allKeys = await _asyncStorage.default.getAllKeys();
|
|
296
|
+
// Filter out ignored keys
|
|
297
|
+
const keysToCapture = allKeys.filter(key => !this.shouldIgnoreKey(key));
|
|
298
|
+
if (keysToCapture.length > 0) {
|
|
299
|
+
const keyValuePairs = await _asyncStorage.default.multiGet(keysToCapture);
|
|
300
|
+
prevPairs = keyValuePairs;
|
|
301
|
+
}
|
|
302
|
+
} catch {
|
|
303
|
+
// Failed to capture previous state
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// Execute the operation
|
|
307
|
+
const result = this.originalClear ? await this.originalClear() : undefined;
|
|
308
|
+
|
|
309
|
+
// Emit event with previous pairs
|
|
268
310
|
this.emit({
|
|
269
311
|
action: "clear",
|
|
270
|
-
timestamp: new Date()
|
|
312
|
+
timestamp: new Date(),
|
|
313
|
+
data: {
|
|
314
|
+
prevPairs
|
|
315
|
+
}
|
|
271
316
|
});
|
|
272
|
-
return
|
|
317
|
+
return result;
|
|
273
318
|
};
|
|
274
319
|
}
|
|
275
320
|
|
|
276
321
|
// Swizzle multiSet
|
|
277
322
|
if (_asyncStorage.default) {
|
|
278
323
|
_asyncStorage.default.multiSet = async keyValuePairs => {
|
|
279
|
-
// Intercepted multiSet operation with multiple pairs
|
|
280
|
-
|
|
281
324
|
// Filter out ignored keys
|
|
282
325
|
const filteredPairs = keyValuePairs.filter(([key]) => !this.shouldIgnoreKey(key));
|
|
283
326
|
if (filteredPairs.length > 0) {
|
|
327
|
+
// Capture previous values for all keys being set
|
|
328
|
+
const keysToSet = filteredPairs.map(([key]) => key);
|
|
329
|
+
let prevPairs = [];
|
|
330
|
+
try {
|
|
331
|
+
const existingValues = await _asyncStorage.default.multiGet(keysToSet);
|
|
332
|
+
prevPairs = existingValues;
|
|
333
|
+
} catch {
|
|
334
|
+
// Failed to capture previous values
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// Execute the operation
|
|
338
|
+
const result = this.originalMultiSet ? await this.originalMultiSet(keyValuePairs) : undefined;
|
|
339
|
+
|
|
340
|
+
// Emit event with previous values
|
|
284
341
|
this.emit({
|
|
285
342
|
action: "multiSet",
|
|
286
343
|
timestamp: new Date(),
|
|
287
344
|
data: {
|
|
288
|
-
pairs: filteredPairs
|
|
345
|
+
pairs: filteredPairs,
|
|
346
|
+
prevPairs
|
|
289
347
|
}
|
|
290
348
|
});
|
|
291
|
-
|
|
292
|
-
// All keys in multiSet are ignored
|
|
349
|
+
return result;
|
|
293
350
|
}
|
|
294
351
|
return this.originalMultiSet ? this.originalMultiSet(keyValuePairs) : Promise.resolve();
|
|
295
352
|
};
|
|
@@ -298,20 +355,31 @@ class AsyncStorageListener {
|
|
|
298
355
|
// Swizzle multiRemove
|
|
299
356
|
if (_asyncStorage.default) {
|
|
300
357
|
_asyncStorage.default.multiRemove = async keys => {
|
|
301
|
-
// Intercepted multiRemove operation with multiple keys
|
|
302
|
-
|
|
303
358
|
// Filter out ignored keys
|
|
304
359
|
const filteredKeys = keys.filter(key => !this.shouldIgnoreKey(key));
|
|
305
360
|
if (filteredKeys.length > 0) {
|
|
361
|
+
// Capture previous values for all keys being removed
|
|
362
|
+
let prevPairs = [];
|
|
363
|
+
try {
|
|
364
|
+
const existingValues = await _asyncStorage.default.multiGet(filteredKeys);
|
|
365
|
+
prevPairs = existingValues;
|
|
366
|
+
} catch {
|
|
367
|
+
// Failed to capture previous values
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// Execute the operation
|
|
371
|
+
const result = this.originalMultiRemove ? await this.originalMultiRemove(keys) : undefined;
|
|
372
|
+
|
|
373
|
+
// Emit event with previous values
|
|
306
374
|
this.emit({
|
|
307
375
|
action: "multiRemove",
|
|
308
376
|
timestamp: new Date(),
|
|
309
377
|
data: {
|
|
310
|
-
keys: filteredKeys
|
|
378
|
+
keys: filteredKeys,
|
|
379
|
+
prevPairs
|
|
311
380
|
}
|
|
312
381
|
});
|
|
313
|
-
|
|
314
|
-
// All keys in multiRemove are ignored
|
|
382
|
+
return result;
|
|
315
383
|
}
|
|
316
384
|
return this.originalMultiRemove ? this.originalMultiRemove(keys) : Promise.resolve();
|
|
317
385
|
};
|
|
@@ -320,20 +388,32 @@ class AsyncStorageListener {
|
|
|
320
388
|
// Swizzle multiMerge if available
|
|
321
389
|
if (this.originalMultiMerge && _asyncStorage.default) {
|
|
322
390
|
_asyncStorage.default.multiMerge = async keyValuePairs => {
|
|
323
|
-
// Intercepted multiMerge operation with multiple pairs
|
|
324
|
-
|
|
325
391
|
// Filter out ignored keys
|
|
326
392
|
const filteredPairs = keyValuePairs.filter(([key]) => !this.shouldIgnoreKey(key));
|
|
327
393
|
if (filteredPairs.length > 0) {
|
|
394
|
+
// Capture previous values for all keys being merged
|
|
395
|
+
const keysToMerge = filteredPairs.map(([key]) => key);
|
|
396
|
+
let prevPairs = [];
|
|
397
|
+
try {
|
|
398
|
+
const existingValues = await _asyncStorage.default.multiGet(keysToMerge);
|
|
399
|
+
prevPairs = existingValues;
|
|
400
|
+
} catch {
|
|
401
|
+
// Failed to capture previous values
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// Execute the operation
|
|
405
|
+
const result = this.originalMultiMerge ? await this.originalMultiMerge(keyValuePairs) : undefined;
|
|
406
|
+
|
|
407
|
+
// Emit event with previous values
|
|
328
408
|
this.emit({
|
|
329
409
|
action: "multiMerge",
|
|
330
410
|
timestamp: new Date(),
|
|
331
411
|
data: {
|
|
332
|
-
pairs: filteredPairs
|
|
412
|
+
pairs: filteredPairs,
|
|
413
|
+
prevPairs
|
|
333
414
|
}
|
|
334
415
|
});
|
|
335
|
-
|
|
336
|
-
// All keys in multiMerge are ignored
|
|
416
|
+
return result;
|
|
337
417
|
}
|
|
338
418
|
return this.originalMultiMerge ? this.originalMultiMerge(keyValuePairs) : Promise.resolve();
|
|
339
419
|
};
|
|
@@ -439,6 +519,32 @@ class AsyncStorageListener {
|
|
|
439
519
|
get listenerCount() {
|
|
440
520
|
return this.listeners.length;
|
|
441
521
|
}
|
|
522
|
+
|
|
523
|
+
/**
|
|
524
|
+
* Pause event emission (used during time-travel operations)
|
|
525
|
+
*
|
|
526
|
+
* When paused, storage operations still execute but events are not emitted.
|
|
527
|
+
* This prevents circular event triggering during replay/jump operations.
|
|
528
|
+
*/
|
|
529
|
+
pause() {
|
|
530
|
+
this.isPaused = true;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
/**
|
|
534
|
+
* Resume event emission after pausing
|
|
535
|
+
*/
|
|
536
|
+
resume() {
|
|
537
|
+
this.isPaused = false;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
/**
|
|
541
|
+
* Check if event emission is currently paused
|
|
542
|
+
*
|
|
543
|
+
* @returns True if paused, false otherwise
|
|
544
|
+
*/
|
|
545
|
+
get paused() {
|
|
546
|
+
return this.isPaused;
|
|
547
|
+
}
|
|
442
548
|
}
|
|
443
549
|
|
|
444
550
|
/**
|
|
@@ -493,6 +599,29 @@ const isListening = () => asyncStorageListener.isActive;
|
|
|
493
599
|
exports.isListening = isListening;
|
|
494
600
|
const getListenerCount = () => asyncStorageListener.listenerCount;
|
|
495
601
|
|
|
602
|
+
/**
|
|
603
|
+
* Pause event emission (used during time-travel operations)
|
|
604
|
+
*
|
|
605
|
+
* When paused, storage operations still execute but events are not emitted.
|
|
606
|
+
* This prevents circular event triggering during replay/jump operations.
|
|
607
|
+
*/
|
|
608
|
+
exports.getListenerCount = getListenerCount;
|
|
609
|
+
const pauseCapture = () => asyncStorageListener.pause();
|
|
610
|
+
|
|
611
|
+
/**
|
|
612
|
+
* Resume event emission after pausing
|
|
613
|
+
*/
|
|
614
|
+
exports.pauseCapture = pauseCapture;
|
|
615
|
+
const resumeCapture = () => asyncStorageListener.resume();
|
|
616
|
+
|
|
617
|
+
/**
|
|
618
|
+
* Check if event emission is currently paused
|
|
619
|
+
*
|
|
620
|
+
* @returns True if paused, false otherwise
|
|
621
|
+
*/
|
|
622
|
+
exports.resumeCapture = resumeCapture;
|
|
623
|
+
const isPaused = () => asyncStorageListener.paused;
|
|
624
|
+
|
|
496
625
|
/**
|
|
497
626
|
* Export the singleton instance for advanced usage
|
|
498
627
|
*
|
|
@@ -506,5 +635,5 @@ const getListenerCount = () => asyncStorageListener.listenerCount;
|
|
|
506
635
|
* }
|
|
507
636
|
* ```
|
|
508
637
|
*/
|
|
509
|
-
exports.
|
|
638
|
+
exports.isPaused = isPaused;
|
|
510
639
|
var _default = exports.default = asyncStorageListener;
|
|
@@ -27,6 +27,12 @@ Object.defineProperty(exports, "asyncStorageListener", {
|
|
|
27
27
|
return _AsyncStorageListener.default;
|
|
28
28
|
}
|
|
29
29
|
});
|
|
30
|
+
Object.defineProperty(exports, "canUndo", {
|
|
31
|
+
enumerable: true,
|
|
32
|
+
get: function () {
|
|
33
|
+
return _storageTimeTravelUtils.canUndo;
|
|
34
|
+
}
|
|
35
|
+
});
|
|
30
36
|
Object.defineProperty(exports, "clearAllAppStorage", {
|
|
31
37
|
enumerable: true,
|
|
32
38
|
get: function () {
|
|
@@ -105,12 +111,24 @@ Object.defineProperty(exports, "isMMKVListening", {
|
|
|
105
111
|
return _MMKVListener.isMMKVListening;
|
|
106
112
|
}
|
|
107
113
|
});
|
|
114
|
+
Object.defineProperty(exports, "isPaused", {
|
|
115
|
+
enumerable: true,
|
|
116
|
+
get: function () {
|
|
117
|
+
return _AsyncStorageListener.isPaused;
|
|
118
|
+
}
|
|
119
|
+
});
|
|
108
120
|
Object.defineProperty(exports, "isTypeMatch", {
|
|
109
121
|
enumerable: true,
|
|
110
122
|
get: function () {
|
|
111
123
|
return _mmkvTypeDetection.isTypeMatch;
|
|
112
124
|
}
|
|
113
125
|
});
|
|
126
|
+
Object.defineProperty(exports, "jumpToState", {
|
|
127
|
+
enumerable: true,
|
|
128
|
+
get: function () {
|
|
129
|
+
return _storageTimeTravelUtils.jumpToState;
|
|
130
|
+
}
|
|
131
|
+
});
|
|
114
132
|
Object.defineProperty(exports, "mmkvInstanceRegistry", {
|
|
115
133
|
enumerable: true,
|
|
116
134
|
get: function () {
|
|
@@ -123,6 +141,12 @@ Object.defineProperty(exports, "mmkvListener", {
|
|
|
123
141
|
return _MMKVListener.mmkvListener;
|
|
124
142
|
}
|
|
125
143
|
});
|
|
144
|
+
Object.defineProperty(exports, "pauseCapture", {
|
|
145
|
+
enumerable: true,
|
|
146
|
+
get: function () {
|
|
147
|
+
return _AsyncStorageListener.pauseCapture;
|
|
148
|
+
}
|
|
149
|
+
});
|
|
126
150
|
Object.defineProperty(exports, "registerMMKVInstance", {
|
|
127
151
|
enumerable: true,
|
|
128
152
|
get: function () {
|
|
@@ -153,6 +177,12 @@ Object.defineProperty(exports, "removeMMKVInstance", {
|
|
|
153
177
|
return _MMKVListener.removeMMKVInstance;
|
|
154
178
|
}
|
|
155
179
|
});
|
|
180
|
+
Object.defineProperty(exports, "resumeCapture", {
|
|
181
|
+
enumerable: true,
|
|
182
|
+
get: function () {
|
|
183
|
+
return _AsyncStorageListener.resumeCapture;
|
|
184
|
+
}
|
|
185
|
+
});
|
|
156
186
|
Object.defineProperty(exports, "startListening", {
|
|
157
187
|
enumerable: true,
|
|
158
188
|
get: function () {
|
|
@@ -165,6 +195,12 @@ Object.defineProperty(exports, "stopListening", {
|
|
|
165
195
|
return _AsyncStorageListener.stopListening;
|
|
166
196
|
}
|
|
167
197
|
});
|
|
198
|
+
Object.defineProperty(exports, "undoOperation", {
|
|
199
|
+
enumerable: true,
|
|
200
|
+
get: function () {
|
|
201
|
+
return _storageTimeTravelUtils.undoOperation;
|
|
202
|
+
}
|
|
203
|
+
});
|
|
168
204
|
Object.defineProperty(exports, "unregisterMMKVInstance", {
|
|
169
205
|
enumerable: true,
|
|
170
206
|
get: function () {
|
|
@@ -174,6 +210,7 @@ Object.defineProperty(exports, "unregisterMMKVInstance", {
|
|
|
174
210
|
var _clearAllStorage = require("./clearAllStorage");
|
|
175
211
|
var _mmkvAvailability = require("./mmkvAvailability");
|
|
176
212
|
var _AsyncStorageListener = _interopRequireWildcard(require("./AsyncStorageListener"));
|
|
213
|
+
var _storageTimeTravelUtils = require("./storageTimeTravelUtils");
|
|
177
214
|
var _MMKVInstanceRegistry = require("./MMKVInstanceRegistry");
|
|
178
215
|
var _MMKVListener = require("./MMKVListener");
|
|
179
216
|
var _mmkvTypeDetection = require("./mmkvTypeDetection");
|