@buoy-gg/events 2.1.10 → 2.1.13
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/components/EventsCopySettingsView.js +3 -1
- package/lib/commonjs/components/ReactQueryEventDetail.js +7 -3
- package/lib/commonjs/components/UnifiedEventDetail.js +68 -2
- package/lib/commonjs/components/UnifiedEventItem.js +59 -1
- package/lib/commonjs/hooks/useUnifiedEvents.js +23 -1
- package/lib/commonjs/stores/unifiedEventStore.js +59 -1
- package/lib/commonjs/utils/autoDiscoverEventSources.js +146 -1
- package/lib/commonjs/utils/eventExportFormatter.js +2 -0
- package/lib/module/components/EventsCopySettingsView.js +3 -1
- package/lib/module/components/ReactQueryEventDetail.js +7 -3
- package/lib/module/components/UnifiedEventDetail.js +68 -2
- package/lib/module/components/UnifiedEventItem.js +59 -1
- package/lib/module/hooks/useUnifiedEvents.js +24 -2
- package/lib/module/stores/unifiedEventStore.js +54 -0
- package/lib/module/utils/autoDiscoverEventSources.js +146 -1
- package/lib/module/utils/eventExportFormatter.js +2 -0
- package/lib/typescript/stores/unifiedEventStore.d.ts +20 -0
- package/lib/typescript/types/index.d.ts +1 -1
- package/package.json +3 -3
- package/src/components/EventsCopySettingsView.tsx +3 -1
- package/src/components/ReactQueryEventDetail.tsx +7 -3
- package/src/components/UnifiedEventDetail.tsx +79 -1
- package/src/components/UnifiedEventItem.tsx +66 -0
- package/src/hooks/useUnifiedEvents.ts +28 -0
- package/src/stores/unifiedEventStore.ts +54 -0
- package/src/types/index.ts +3 -1
- package/src/utils/autoDiscoverEventSources.ts +165 -0
- package/src/utils/eventExportFormatter.ts +2 -0
|
@@ -23,7 +23,9 @@ function tryLoadOptionalDetailComponents() {
|
|
|
23
23
|
StorageEventDetailContent: null,
|
|
24
24
|
ReduxActionDetailContent: null,
|
|
25
25
|
NetworkEventDetailView: null,
|
|
26
|
-
RenderDetailView: null
|
|
26
|
+
RenderDetailView: null,
|
|
27
|
+
ZustandStateDetailContent: null,
|
|
28
|
+
JotaiAtomDetailContent: null
|
|
27
29
|
};
|
|
28
30
|
|
|
29
31
|
// Try to load storage detail component
|
|
@@ -61,6 +63,24 @@ function tryLoadOptionalDetailComponents() {
|
|
|
61
63
|
} catch {
|
|
62
64
|
// Optional dependency not installed
|
|
63
65
|
}
|
|
66
|
+
|
|
67
|
+
// Try to load zustand detail component
|
|
68
|
+
try {
|
|
69
|
+
// @ts-ignore - Dynamic import that may not exist
|
|
70
|
+
const zustand = require("@buoy-gg/zustand");
|
|
71
|
+
components.ZustandStateDetailContent = zustand.ZustandStateDetailContent;
|
|
72
|
+
} catch {
|
|
73
|
+
// Optional dependency not installed
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Try to load jotai detail component
|
|
77
|
+
try {
|
|
78
|
+
// @ts-ignore - Dynamic import that may not exist
|
|
79
|
+
const jotai = require("@buoy-gg/jotai");
|
|
80
|
+
components.JotaiAtomDetailContent = jotai.JotaiAtomDetailContent;
|
|
81
|
+
} catch {
|
|
82
|
+
// Optional dependency not installed
|
|
83
|
+
}
|
|
64
84
|
return components;
|
|
65
85
|
}
|
|
66
86
|
|
|
@@ -107,6 +127,14 @@ const SOURCE_CONFIG = {
|
|
|
107
127
|
label: "Route",
|
|
108
128
|
color: "#06B6D4"
|
|
109
129
|
},
|
|
130
|
+
zustand: {
|
|
131
|
+
label: "Zustand",
|
|
132
|
+
color: "#764ABC"
|
|
133
|
+
},
|
|
134
|
+
jotai: {
|
|
135
|
+
label: "Jotai",
|
|
136
|
+
color: "#14B8A6"
|
|
137
|
+
},
|
|
110
138
|
render: {
|
|
111
139
|
label: "Render",
|
|
112
140
|
color: "#F472B6"
|
|
@@ -225,6 +253,42 @@ export const UnifiedEventDetail = /*#__PURE__*/memo(function UnifiedEventDetail(
|
|
|
225
253
|
});
|
|
226
254
|
}
|
|
227
255
|
|
|
256
|
+
// For Zustand events, use the shared ZustandStateDetailContent if available
|
|
257
|
+
if (event.source === "zustand" && optionalComponents.ZustandStateDetailContent) {
|
|
258
|
+
const {
|
|
259
|
+
ZustandStateDetailContent
|
|
260
|
+
} = optionalComponents;
|
|
261
|
+
const zustandChange = event.originalEvent;
|
|
262
|
+
return /*#__PURE__*/_jsx(View, {
|
|
263
|
+
style: styles.container,
|
|
264
|
+
children: /*#__PURE__*/_jsx(ZustandStateDetailContent, {
|
|
265
|
+
change: zustandChange,
|
|
266
|
+
changes: [zustandChange],
|
|
267
|
+
selectedIndex: 0,
|
|
268
|
+
onIndexChange: () => {},
|
|
269
|
+
disableInternalFooter: true
|
|
270
|
+
})
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// For Jotai events, use the shared JotaiAtomDetailContent if available
|
|
275
|
+
if (event.source === "jotai" && optionalComponents.JotaiAtomDetailContent) {
|
|
276
|
+
const {
|
|
277
|
+
JotaiAtomDetailContent
|
|
278
|
+
} = optionalComponents;
|
|
279
|
+
const jotaiChange = event.originalEvent;
|
|
280
|
+
return /*#__PURE__*/_jsx(View, {
|
|
281
|
+
style: styles.container,
|
|
282
|
+
children: /*#__PURE__*/_jsx(JotaiAtomDetailContent, {
|
|
283
|
+
change: jotaiChange,
|
|
284
|
+
changes: [jotaiChange],
|
|
285
|
+
selectedIndex: 0,
|
|
286
|
+
onIndexChange: () => {},
|
|
287
|
+
disableInternalFooter: true
|
|
288
|
+
})
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
|
|
228
292
|
// For render events, use the RenderDetailView if available
|
|
229
293
|
if (event.source === "render" && optionalComponents.RenderDetailView) {
|
|
230
294
|
const {
|
|
@@ -305,7 +369,9 @@ export const UnifiedEventDetail = /*#__PURE__*/memo(function UnifiedEventDetail(
|
|
|
305
369
|
children: /*#__PURE__*/_jsx(DataViewer, {
|
|
306
370
|
data: getEventData(),
|
|
307
371
|
title: "",
|
|
308
|
-
showTypeFilter:
|
|
372
|
+
showTypeFilter: true,
|
|
373
|
+
rawMode: true,
|
|
374
|
+
initialExpanded: true
|
|
309
375
|
})
|
|
310
376
|
})]
|
|
311
377
|
})]
|
|
@@ -22,7 +22,9 @@ function tryLoadOptionalComponents() {
|
|
|
22
22
|
getValueType: null,
|
|
23
23
|
ReduxActionItem: null,
|
|
24
24
|
NetworkEventItemCompact: null,
|
|
25
|
-
RouteEventItemCompact: null
|
|
25
|
+
RouteEventItemCompact: null,
|
|
26
|
+
ZustandStateChangeItem: null,
|
|
27
|
+
JotaiAtomChangeItem: null
|
|
26
28
|
};
|
|
27
29
|
|
|
28
30
|
// Try to load storage components
|
|
@@ -61,6 +63,24 @@ function tryLoadOptionalComponents() {
|
|
|
61
63
|
} catch {
|
|
62
64
|
// Optional dependency not installed
|
|
63
65
|
}
|
|
66
|
+
|
|
67
|
+
// Try to load zustand components
|
|
68
|
+
try {
|
|
69
|
+
// @ts-ignore - Dynamic import that may not exist
|
|
70
|
+
const zustand = require("@buoy-gg/zustand");
|
|
71
|
+
components.ZustandStateChangeItem = zustand.ZustandStateChangeItem;
|
|
72
|
+
} catch {
|
|
73
|
+
// Optional dependency not installed
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Try to load jotai components
|
|
77
|
+
try {
|
|
78
|
+
// @ts-ignore - Dynamic import that may not exist
|
|
79
|
+
const jotai = require("@buoy-gg/jotai");
|
|
80
|
+
components.JotaiAtomChangeItem = jotai.JotaiAtomChangeItem;
|
|
81
|
+
} catch {
|
|
82
|
+
// Optional dependency not installed
|
|
83
|
+
}
|
|
64
84
|
return components;
|
|
65
85
|
}
|
|
66
86
|
|
|
@@ -107,6 +127,14 @@ const SOURCE_CONFIG = {
|
|
|
107
127
|
label: "Route",
|
|
108
128
|
color: "#06B6D4" // Cyan
|
|
109
129
|
},
|
|
130
|
+
zustand: {
|
|
131
|
+
label: "Zustand",
|
|
132
|
+
color: "#764ABC" // Purple
|
|
133
|
+
},
|
|
134
|
+
jotai: {
|
|
135
|
+
label: "Jotai",
|
|
136
|
+
color: "#14B8A6" // Teal
|
|
137
|
+
},
|
|
110
138
|
render: {
|
|
111
139
|
label: "Render",
|
|
112
140
|
color: "#F472B6" // Pink
|
|
@@ -178,6 +206,8 @@ const SOURCE_BADGE_LABELS = {
|
|
|
178
206
|
"react-query-query": "QUERY",
|
|
179
207
|
"react-query-mutation": "MUTATION",
|
|
180
208
|
route: "ROUTE",
|
|
209
|
+
zustand: "ZUSTAND",
|
|
210
|
+
jotai: "JOTAI",
|
|
181
211
|
render: "RENDER"
|
|
182
212
|
};
|
|
183
213
|
|
|
@@ -289,6 +319,34 @@ export const UnifiedEventItem = /*#__PURE__*/memo(function UnifiedEventItem({
|
|
|
289
319
|
});
|
|
290
320
|
}
|
|
291
321
|
|
|
322
|
+
// For Zustand events, try to use the shared ZustandStateChangeItem component
|
|
323
|
+
if (event.source === "zustand" && optionalComponents.ZustandStateChangeItem) {
|
|
324
|
+
const {
|
|
325
|
+
ZustandStateChangeItem
|
|
326
|
+
} = optionalComponents;
|
|
327
|
+
return /*#__PURE__*/_jsx(SourceBadgeWrapper, {
|
|
328
|
+
source: event.source,
|
|
329
|
+
children: /*#__PURE__*/_jsx(ZustandStateChangeItem, {
|
|
330
|
+
change: event.originalEvent,
|
|
331
|
+
onPress: () => onPress()
|
|
332
|
+
})
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// For Jotai events, try to use the shared JotaiAtomChangeItem component
|
|
337
|
+
if (event.source === "jotai" && optionalComponents.JotaiAtomChangeItem) {
|
|
338
|
+
const {
|
|
339
|
+
JotaiAtomChangeItem
|
|
340
|
+
} = optionalComponents;
|
|
341
|
+
return /*#__PURE__*/_jsx(SourceBadgeWrapper, {
|
|
342
|
+
source: event.source,
|
|
343
|
+
children: /*#__PURE__*/_jsx(JotaiAtomChangeItem, {
|
|
344
|
+
change: event.originalEvent,
|
|
345
|
+
onPress: () => onPress()
|
|
346
|
+
})
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
|
|
292
350
|
// Fallback: Use CompactRow for all events when specific components aren't available
|
|
293
351
|
const customBadge = correlationLabel && correlationColor ? /*#__PURE__*/_jsx(CorrelationBadge, {
|
|
294
352
|
label: correlationLabel,
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
import { useState, useEffect, useCallback, useMemo, useRef } from "react";
|
|
11
11
|
import { useFeatureGate, subscribeToSubscriberCountChanges, isDevToolsStorageKey } from "@buoy-gg/shared-ui";
|
|
12
|
-
import { subscribe, subscribeToStorage, subscribeToRedux, subscribeToNetwork, subscribeToReactQuery, subscribeToRoutes, subscribeToRender, unsubscribeFromStorage, unsubscribeFromRedux, unsubscribeFromNetwork, unsubscribeFromReactQuery, unsubscribeFromRoutes, unsubscribeFromRender, unsubscribeAll, getSourceCounts, clearEvents as clearStoreEvents, getAvailableEventSources, getSubscriberCounts } from "../stores/unifiedEventStore";
|
|
12
|
+
import { subscribe, subscribeToStorage, subscribeToRedux, subscribeToNetwork, subscribeToReactQuery, subscribeToRoutes, subscribeToZustand, subscribeToJotai, subscribeToRender, unsubscribeFromStorage, unsubscribeFromRedux, unsubscribeFromNetwork, unsubscribeFromReactQuery, unsubscribeFromRoutes, unsubscribeFromZustand, unsubscribeFromJotai, unsubscribeFromRender, unsubscribeAll, getSourceCounts, clearEvents as clearStoreEvents, getAvailableEventSources, getSubscriberCounts } from "../stores/unifiedEventStore";
|
|
13
13
|
import { saveEnabledSources, loadEnabledSources, saveCapturingState, loadCapturingState } from "../utils/badgeSelectionStorage";
|
|
14
14
|
import { getSourceDisplayConfig } from "../utils/autoDiscoverEventSources";
|
|
15
15
|
|
|
@@ -51,7 +51,7 @@ function isBuoyInternalEvent(event) {
|
|
|
51
51
|
/**
|
|
52
52
|
* All possible sources for display
|
|
53
53
|
*/
|
|
54
|
-
const ALL_DISPLAY_SOURCES = ["storage-async", "redux", "network", "react-query-query", "react-query-mutation", "route", "render"];
|
|
54
|
+
const ALL_DISPLAY_SOURCES = ["storage-async", "redux", "network", "react-query-query", "react-query-mutation", "route", "zustand", "jotai", "render"];
|
|
55
55
|
|
|
56
56
|
/**
|
|
57
57
|
* Sources enabled by default on first load.
|
|
@@ -72,6 +72,8 @@ const SOURCE_TO_EVENT_SOURCES = {
|
|
|
72
72
|
"react-query-query": ["react-query", "react-query-query"],
|
|
73
73
|
"react-query-mutation": ["react-query-mutation"],
|
|
74
74
|
route: ["route"],
|
|
75
|
+
zustand: ["zustand"],
|
|
76
|
+
jotai: ["jotai"],
|
|
75
77
|
render: ["render"]
|
|
76
78
|
};
|
|
77
79
|
|
|
@@ -87,6 +89,8 @@ const EVENT_SOURCE_TO_DISCOVERY_ID = {
|
|
|
87
89
|
"react-query-query": "react-query",
|
|
88
90
|
"react-query-mutation": "react-query",
|
|
89
91
|
route: "route-events",
|
|
92
|
+
zustand: "zustand",
|
|
93
|
+
jotai: "jotai",
|
|
90
94
|
render: "render"
|
|
91
95
|
};
|
|
92
96
|
export function useUnifiedEvents() {
|
|
@@ -166,6 +170,8 @@ export function useUnifiedEvents() {
|
|
|
166
170
|
subscribeToReactQuery();
|
|
167
171
|
}
|
|
168
172
|
if (sourcesToEnable.has("route")) subscribeToRoutes();
|
|
173
|
+
if (sourcesToEnable.has("zustand")) subscribeToZustand();
|
|
174
|
+
if (sourcesToEnable.has("jotai")) subscribeToJotai();
|
|
169
175
|
if (sourcesToEnable.has("render")) subscribeToRender();
|
|
170
176
|
}
|
|
171
177
|
isStateRestoredRef.current = true;
|
|
@@ -246,6 +252,8 @@ export function useUnifiedEvents() {
|
|
|
246
252
|
"react-query-query": "react-query",
|
|
247
253
|
"react-query-mutation": "react-query",
|
|
248
254
|
route: "route-events",
|
|
255
|
+
zustand: "zustand",
|
|
256
|
+
jotai: "jotai",
|
|
249
257
|
render: "render"
|
|
250
258
|
};
|
|
251
259
|
const sources = availableDisplaySources.map(source => {
|
|
@@ -296,6 +304,12 @@ export function useUnifiedEvents() {
|
|
|
296
304
|
case "route":
|
|
297
305
|
unsubscribeFromRoutes();
|
|
298
306
|
break;
|
|
307
|
+
case "zustand":
|
|
308
|
+
unsubscribeFromZustand();
|
|
309
|
+
break;
|
|
310
|
+
case "jotai":
|
|
311
|
+
unsubscribeFromJotai();
|
|
312
|
+
break;
|
|
299
313
|
case "render":
|
|
300
314
|
unsubscribeFromRender();
|
|
301
315
|
break;
|
|
@@ -321,6 +335,12 @@ export function useUnifiedEvents() {
|
|
|
321
335
|
case "route":
|
|
322
336
|
subscribeToRoutes();
|
|
323
337
|
break;
|
|
338
|
+
case "zustand":
|
|
339
|
+
subscribeToZustand();
|
|
340
|
+
break;
|
|
341
|
+
case "jotai":
|
|
342
|
+
subscribeToJotai();
|
|
343
|
+
break;
|
|
324
344
|
case "render":
|
|
325
345
|
subscribeToRender();
|
|
326
346
|
break;
|
|
@@ -345,6 +365,8 @@ export function useUnifiedEvents() {
|
|
|
345
365
|
subscribeToReactQuery();
|
|
346
366
|
}
|
|
347
367
|
if (enabledSources.has("route")) subscribeToRoutes();
|
|
368
|
+
if (enabledSources.has("zustand")) subscribeToZustand();
|
|
369
|
+
if (enabledSources.has("jotai")) subscribeToJotai();
|
|
348
370
|
if (enabledSources.has("render")) subscribeToRender();
|
|
349
371
|
setIsCapturing(true);
|
|
350
372
|
}, [enabledSources]);
|
|
@@ -194,6 +194,48 @@ class UnifiedEventStore {
|
|
|
194
194
|
this.activeSources.delete("route");
|
|
195
195
|
}
|
|
196
196
|
|
|
197
|
+
/**
|
|
198
|
+
* Subscribe to Zustand state changes (if @buoy-gg/zustand is installed)
|
|
199
|
+
*/
|
|
200
|
+
subscribeToZustand() {
|
|
201
|
+
const {
|
|
202
|
+
sources
|
|
203
|
+
} = getCachedDiscovery();
|
|
204
|
+
const zustandSource = sources.find(s => s.id === "zustand");
|
|
205
|
+
if (zustandSource) {
|
|
206
|
+
this.subscribeToSource(zustandSource);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Unsubscribe from Zustand state changes
|
|
212
|
+
*/
|
|
213
|
+
unsubscribeFromZustand() {
|
|
214
|
+
this.unsubscribeFromSource("zustand");
|
|
215
|
+
this.activeSources.delete("zustand");
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Subscribe to Jotai atom changes (if @buoy-gg/jotai is installed)
|
|
220
|
+
*/
|
|
221
|
+
subscribeToJotai() {
|
|
222
|
+
const {
|
|
223
|
+
sources
|
|
224
|
+
} = getCachedDiscovery();
|
|
225
|
+
const jotaiSource = sources.find(s => s.id === "jotai");
|
|
226
|
+
if (jotaiSource) {
|
|
227
|
+
this.subscribeToSource(jotaiSource);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Unsubscribe from Jotai atom changes
|
|
233
|
+
*/
|
|
234
|
+
unsubscribeFromJotai() {
|
|
235
|
+
this.unsubscribeFromSource("jotai");
|
|
236
|
+
this.activeSources.delete("jotai");
|
|
237
|
+
}
|
|
238
|
+
|
|
197
239
|
/**
|
|
198
240
|
* Subscribe to render events (if @buoy-gg/highlight-updates is installed)
|
|
199
241
|
*/
|
|
@@ -279,6 +321,8 @@ class UnifiedEventStore {
|
|
|
279
321
|
"react-query-query": 0,
|
|
280
322
|
"react-query-mutation": 0,
|
|
281
323
|
route: 0,
|
|
324
|
+
zustand: 0,
|
|
325
|
+
jotai: 0,
|
|
282
326
|
render: 0
|
|
283
327
|
};
|
|
284
328
|
for (const event of this.events) {
|
|
@@ -360,6 +404,10 @@ class UnifiedEventStore {
|
|
|
360
404
|
return this.sourceUnsubscribers.has("react-query");
|
|
361
405
|
case "route":
|
|
362
406
|
return this.sourceUnsubscribers.has("route-events");
|
|
407
|
+
case "zustand":
|
|
408
|
+
return this.sourceUnsubscribers.has("zustand");
|
|
409
|
+
case "jotai":
|
|
410
|
+
return this.sourceUnsubscribers.has("jotai");
|
|
363
411
|
case "render":
|
|
364
412
|
return this.sourceUnsubscribers.has("render");
|
|
365
413
|
default:
|
|
@@ -380,6 +428,8 @@ class UnifiedEventStore {
|
|
|
380
428
|
"react-query-query": this.sourceUnsubscribers.has("react-query"),
|
|
381
429
|
"react-query-mutation": this.sourceUnsubscribers.has("react-query"),
|
|
382
430
|
route: this.sourceUnsubscribers.has("route-events"),
|
|
431
|
+
zustand: this.sourceUnsubscribers.has("zustand"),
|
|
432
|
+
jotai: this.sourceUnsubscribers.has("jotai"),
|
|
383
433
|
render: this.sourceUnsubscribers.has("render")
|
|
384
434
|
};
|
|
385
435
|
}
|
|
@@ -407,6 +457,10 @@ export const subscribeToReactQuery = () => unifiedEventStore.subscribeToReactQue
|
|
|
407
457
|
export const unsubscribeFromReactQuery = () => unifiedEventStore.unsubscribeFromReactQuery();
|
|
408
458
|
export const subscribeToRoutes = () => unifiedEventStore.subscribeToRoutes();
|
|
409
459
|
export const unsubscribeFromRoutes = () => unifiedEventStore.unsubscribeFromRoutes();
|
|
460
|
+
export const subscribeToZustand = () => unifiedEventStore.subscribeToZustand();
|
|
461
|
+
export const unsubscribeFromZustand = () => unifiedEventStore.unsubscribeFromZustand();
|
|
462
|
+
export const subscribeToJotai = () => unifiedEventStore.subscribeToJotai();
|
|
463
|
+
export const unsubscribeFromJotai = () => unifiedEventStore.unsubscribeFromJotai();
|
|
410
464
|
export const subscribeToRender = () => unifiedEventStore.subscribeToRender();
|
|
411
465
|
export const unsubscribeFromRender = () => unifiedEventStore.unsubscribeFromRender();
|
|
412
466
|
export const getEvents = enabledSources => unifiedEventStore.getEvents(enabledSources);
|
|
@@ -517,6 +517,141 @@ function transformRouteEvent(event) {
|
|
|
517
517
|
};
|
|
518
518
|
}
|
|
519
519
|
|
|
520
|
+
// ============================================================================
|
|
521
|
+
// Zustand Event Source Discovery
|
|
522
|
+
// ============================================================================
|
|
523
|
+
|
|
524
|
+
function tryLoadZustandSource() {
|
|
525
|
+
try {
|
|
526
|
+
// @ts-ignore - Dynamic import that may not exist
|
|
527
|
+
const {
|
|
528
|
+
zustandStateStore
|
|
529
|
+
} = require("@buoy-gg/zustand");
|
|
530
|
+
let lastChangeId = null;
|
|
531
|
+
return {
|
|
532
|
+
id: "zustand",
|
|
533
|
+
name: "Zustand",
|
|
534
|
+
eventSources: ["zustand"],
|
|
535
|
+
available: true,
|
|
536
|
+
subscribe: onEvent => {
|
|
537
|
+
return zustandStateStore.subscribe(changes => {
|
|
538
|
+
if (changes.length > 0) {
|
|
539
|
+
const latestChange = changes[0];
|
|
540
|
+
if (latestChange.id !== lastChangeId) {
|
|
541
|
+
lastChangeId = latestChange.id;
|
|
542
|
+
const unifiedEvent = transformZustandChange(latestChange);
|
|
543
|
+
onEvent(unifiedEvent);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
});
|
|
547
|
+
}
|
|
548
|
+
};
|
|
549
|
+
} catch {
|
|
550
|
+
return null;
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
function transformZustandChange(change) {
|
|
554
|
+
const c = change;
|
|
555
|
+
|
|
556
|
+
// Get status
|
|
557
|
+
let status = "neutral";
|
|
558
|
+
if (c.isSlowUpdate) {
|
|
559
|
+
status = "pending"; // Yellow for slow updates
|
|
560
|
+
} else if (c.hasStateChange) {
|
|
561
|
+
status = "success";
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
// Get subtitle
|
|
565
|
+
const parts = [];
|
|
566
|
+
if (c.changedKeys && c.changedKeys.length > 0) {
|
|
567
|
+
const keys = c.changedKeys.slice(0, 3).join(", ");
|
|
568
|
+
const more = c.changedKeys.length > 3 ? ` +${c.changedKeys.length - 3}` : "";
|
|
569
|
+
parts.push(`${keys}${more}`);
|
|
570
|
+
} else if (c.diffSummary) {
|
|
571
|
+
parts.push(c.diffSummary);
|
|
572
|
+
}
|
|
573
|
+
if (c.duration !== undefined) {
|
|
574
|
+
parts.push(`${c.duration.toFixed(1)}ms`);
|
|
575
|
+
}
|
|
576
|
+
if (c.category === "replace") {
|
|
577
|
+
parts.push("replace");
|
|
578
|
+
}
|
|
579
|
+
return {
|
|
580
|
+
id: generateEventId("zustand"),
|
|
581
|
+
source: "zustand",
|
|
582
|
+
timestamp: c.timestamp,
|
|
583
|
+
title: c.storeName,
|
|
584
|
+
subtitle: parts.join(" · ") || (c.hasStateChange ? "state changed" : "no change"),
|
|
585
|
+
status,
|
|
586
|
+
originalEvent: change
|
|
587
|
+
};
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
// ============================================================================
|
|
591
|
+
// Jotai Event Source Discovery
|
|
592
|
+
// ============================================================================
|
|
593
|
+
|
|
594
|
+
function tryLoadJotaiSource() {
|
|
595
|
+
try {
|
|
596
|
+
// @ts-ignore - Dynamic import that may not exist
|
|
597
|
+
const {
|
|
598
|
+
jotaiStateStore
|
|
599
|
+
} = require("@buoy-gg/jotai");
|
|
600
|
+
let lastChangeId = null;
|
|
601
|
+
return {
|
|
602
|
+
id: "jotai",
|
|
603
|
+
name: "Jotai",
|
|
604
|
+
eventSources: ["jotai"],
|
|
605
|
+
available: true,
|
|
606
|
+
subscribe: onEvent => {
|
|
607
|
+
return jotaiStateStore.subscribe(changes => {
|
|
608
|
+
if (changes.length > 0) {
|
|
609
|
+
const latestChange = changes[0];
|
|
610
|
+
if (latestChange.id !== lastChangeId) {
|
|
611
|
+
lastChangeId = latestChange.id;
|
|
612
|
+
const unifiedEvent = transformJotaiChange(latestChange);
|
|
613
|
+
onEvent(unifiedEvent);
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
});
|
|
617
|
+
}
|
|
618
|
+
};
|
|
619
|
+
} catch {
|
|
620
|
+
return null;
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
function transformJotaiChange(change) {
|
|
624
|
+
const c = change;
|
|
625
|
+
|
|
626
|
+
// Get status
|
|
627
|
+
let status = "neutral";
|
|
628
|
+
if (c.category === "write" && c.hasValueChange) {
|
|
629
|
+
status = "success";
|
|
630
|
+
} else if (c.category === "read") {
|
|
631
|
+
status = "neutral";
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
// Get subtitle
|
|
635
|
+
const parts = [];
|
|
636
|
+
if (c.valuePreview) {
|
|
637
|
+
parts.push(c.valuePreview);
|
|
638
|
+
} else if (c.diffSummary) {
|
|
639
|
+
parts.push(c.diffSummary);
|
|
640
|
+
}
|
|
641
|
+
if (c.category) {
|
|
642
|
+
parts.push(c.category);
|
|
643
|
+
}
|
|
644
|
+
return {
|
|
645
|
+
id: generateEventId("jotai"),
|
|
646
|
+
source: "jotai",
|
|
647
|
+
timestamp: c.timestamp,
|
|
648
|
+
title: c.atomLabel,
|
|
649
|
+
subtitle: parts.join(" · ") || (c.hasValueChange ? "value changed" : "no change"),
|
|
650
|
+
status,
|
|
651
|
+
originalEvent: change
|
|
652
|
+
};
|
|
653
|
+
}
|
|
654
|
+
|
|
520
655
|
// ============================================================================
|
|
521
656
|
// Render Events Source Discovery (Highlight Updates)
|
|
522
657
|
// ============================================================================
|
|
@@ -671,7 +806,7 @@ export function autoDiscoverEventSources() {
|
|
|
671
806
|
const availableEventSources = new Set();
|
|
672
807
|
|
|
673
808
|
// Try to load each source
|
|
674
|
-
const loaders = [tryLoadStorageSource, tryLoadReduxSource, tryLoadNetworkSource, tryLoadReactQuerySource, tryLoadRouteEventsSource, tryLoadHighlightUpdatesSource];
|
|
809
|
+
const loaders = [tryLoadStorageSource, tryLoadReduxSource, tryLoadNetworkSource, tryLoadReactQuerySource, tryLoadRouteEventsSource, tryLoadZustandSource, tryLoadJotaiSource, tryLoadHighlightUpdatesSource];
|
|
675
810
|
for (const loader of loaders) {
|
|
676
811
|
const source = loader();
|
|
677
812
|
if (source && source.available) {
|
|
@@ -731,6 +866,16 @@ export function getSourceDisplayConfig(source) {
|
|
|
731
866
|
color: "#06B6D4",
|
|
732
867
|
icon: "navigate-outline"
|
|
733
868
|
},
|
|
869
|
+
zustand: {
|
|
870
|
+
label: "Zustand",
|
|
871
|
+
color: "#764ABC",
|
|
872
|
+
icon: "cube-outline"
|
|
873
|
+
},
|
|
874
|
+
jotai: {
|
|
875
|
+
label: "Jotai",
|
|
876
|
+
color: "#14B8A6",
|
|
877
|
+
icon: "ellipse-outline"
|
|
878
|
+
},
|
|
734
879
|
render: {
|
|
735
880
|
label: "Render",
|
|
736
881
|
color: "#F472B6",
|
|
@@ -74,6 +74,22 @@ declare class UnifiedEventStore {
|
|
|
74
74
|
* Unsubscribe from route events
|
|
75
75
|
*/
|
|
76
76
|
unsubscribeFromRoutes(): void;
|
|
77
|
+
/**
|
|
78
|
+
* Subscribe to Zustand state changes (if @buoy-gg/zustand is installed)
|
|
79
|
+
*/
|
|
80
|
+
subscribeToZustand(): void;
|
|
81
|
+
/**
|
|
82
|
+
* Unsubscribe from Zustand state changes
|
|
83
|
+
*/
|
|
84
|
+
unsubscribeFromZustand(): void;
|
|
85
|
+
/**
|
|
86
|
+
* Subscribe to Jotai atom changes (if @buoy-gg/jotai is installed)
|
|
87
|
+
*/
|
|
88
|
+
subscribeToJotai(): void;
|
|
89
|
+
/**
|
|
90
|
+
* Unsubscribe from Jotai atom changes
|
|
91
|
+
*/
|
|
92
|
+
unsubscribeFromJotai(): void;
|
|
77
93
|
/**
|
|
78
94
|
* Subscribe to render events (if @buoy-gg/highlight-updates is installed)
|
|
79
95
|
*/
|
|
@@ -143,6 +159,10 @@ export declare const subscribeToReactQuery: () => void;
|
|
|
143
159
|
export declare const unsubscribeFromReactQuery: () => void;
|
|
144
160
|
export declare const subscribeToRoutes: () => void;
|
|
145
161
|
export declare const unsubscribeFromRoutes: () => void;
|
|
162
|
+
export declare const subscribeToZustand: () => void;
|
|
163
|
+
export declare const unsubscribeFromZustand: () => void;
|
|
164
|
+
export declare const subscribeToJotai: () => void;
|
|
165
|
+
export declare const unsubscribeFromJotai: () => void;
|
|
146
166
|
export declare const subscribeToRender: () => void;
|
|
147
167
|
export declare const unsubscribeFromRender: () => void;
|
|
148
168
|
export declare const getEvents: (enabledSources?: Set<EventSource>) => UnifiedEvent[];
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
/**
|
|
7
7
|
* Event source identifiers
|
|
8
8
|
*/
|
|
9
|
-
export type EventSource = "storage-async" | "storage-mmkv" | "redux" | "network" | "react-query" | "react-query-query" | "react-query-mutation" | "route" | "render";
|
|
9
|
+
export type EventSource = "storage-async" | "storage-mmkv" | "redux" | "network" | "react-query" | "react-query-query" | "react-query-mutation" | "route" | "render" | "zustand" | "jotai";
|
|
10
10
|
/**
|
|
11
11
|
* Event status for visual indicators
|
|
12
12
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@buoy-gg/events",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.13",
|
|
4
4
|
"description": "events package",
|
|
5
5
|
"main": "lib/commonjs/index",
|
|
6
6
|
"module": "lib/module/index",
|
|
@@ -27,8 +27,8 @@
|
|
|
27
27
|
],
|
|
28
28
|
"sideEffects": false,
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@buoy-gg/floating-tools-core": "2.1.
|
|
31
|
-
"@buoy-gg/shared-ui": "2.1.
|
|
30
|
+
"@buoy-gg/floating-tools-core": "2.1.13",
|
|
31
|
+
"@buoy-gg/shared-ui": "2.1.13"
|
|
32
32
|
},
|
|
33
33
|
"peerDependencies": {
|
|
34
34
|
"react": "*",
|
|
@@ -184,7 +184,8 @@ export const ReactQueryEventDetail = memo(function ReactQueryEventDetail({
|
|
|
184
184
|
<DataViewer
|
|
185
185
|
title=""
|
|
186
186
|
data={reactQueryEvent.mutationVariables}
|
|
187
|
-
showTypeFilter={
|
|
187
|
+
showTypeFilter={true}
|
|
188
|
+
rawMode={true}
|
|
188
189
|
initialExpanded={true}
|
|
189
190
|
/>
|
|
190
191
|
</View>
|
|
@@ -203,7 +204,8 @@ export const ReactQueryEventDetail = memo(function ReactQueryEventDetail({
|
|
|
203
204
|
<DataViewer
|
|
204
205
|
title=""
|
|
205
206
|
data={isQuery ? reactQueryEvent.queryData : reactQueryEvent.mutationData}
|
|
206
|
-
showTypeFilter={
|
|
207
|
+
showTypeFilter={true}
|
|
208
|
+
rawMode={true}
|
|
207
209
|
initialExpanded={true}
|
|
208
210
|
/>
|
|
209
211
|
</View>
|
|
@@ -220,7 +222,8 @@ export const ReactQueryEventDetail = memo(function ReactQueryEventDetail({
|
|
|
220
222
|
<DataViewer
|
|
221
223
|
title=""
|
|
222
224
|
data={isQuery ? reactQueryEvent.queryError : reactQueryEvent.mutationError}
|
|
223
|
-
showTypeFilter={
|
|
225
|
+
showTypeFilter={true}
|
|
226
|
+
rawMode={true}
|
|
224
227
|
initialExpanded={true}
|
|
225
228
|
/>
|
|
226
229
|
</View>
|
|
@@ -237,6 +240,7 @@ export const ReactQueryEventDetail = memo(function ReactQueryEventDetail({
|
|
|
237
240
|
title=""
|
|
238
241
|
data={reactQueryEvent}
|
|
239
242
|
showTypeFilter={true}
|
|
243
|
+
rawMode={true}
|
|
240
244
|
initialExpanded={false}
|
|
241
245
|
/>
|
|
242
246
|
</View>
|