@buoy-gg/events 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.
Files changed (47) hide show
  1. package/lib/commonjs/components/EventsCopySettingsView.js +39 -8
  2. package/lib/commonjs/components/EventsModal.js +4 -7
  3. package/lib/commonjs/components/UnifiedEventDetail.js +32 -1
  4. package/lib/commonjs/components/UnifiedEventFilters.js +50 -21
  5. package/lib/commonjs/components/UnifiedEventItem.js +6 -1
  6. package/lib/commonjs/hooks/useUnifiedEvents.js +137 -28
  7. package/lib/commonjs/index.js +6 -0
  8. package/lib/commonjs/stores/unifiedEventStore.js +61 -16
  9. package/lib/commonjs/types/copySettings.js +29 -0
  10. package/lib/commonjs/utils/autoDiscoverEventSources.js +261 -39
  11. package/lib/commonjs/utils/badgeSelectionStorage.js +32 -0
  12. package/lib/commonjs/utils/eventExportFormatter.js +778 -1
  13. package/lib/module/components/EventsCopySettingsView.js +40 -9
  14. package/lib/module/components/EventsModal.js +5 -8
  15. package/lib/module/components/UnifiedEventDetail.js +32 -1
  16. package/lib/module/components/UnifiedEventFilters.js +50 -21
  17. package/lib/module/components/UnifiedEventItem.js +6 -1
  18. package/lib/module/hooks/useUnifiedEvents.js +140 -31
  19. package/lib/module/index.js +4 -1
  20. package/lib/module/stores/unifiedEventStore.js +58 -16
  21. package/lib/module/types/copySettings.js +29 -0
  22. package/lib/module/utils/autoDiscoverEventSources.js +260 -39
  23. package/lib/module/utils/badgeSelectionStorage.js +30 -0
  24. package/lib/module/utils/eventExportFormatter.js +777 -1
  25. package/lib/typescript/components/UnifiedEventFilters.d.ts +3 -0
  26. package/lib/typescript/hooks/useUnifiedEvents.d.ts +2 -0
  27. package/lib/typescript/index.d.ts +1 -1
  28. package/lib/typescript/stores/unifiedEventStore.d.ts +18 -2
  29. package/lib/typescript/types/copySettings.d.ts +25 -1
  30. package/lib/typescript/types/index.d.ts +3 -1
  31. package/lib/typescript/utils/autoDiscoverEventSources.d.ts +17 -0
  32. package/lib/typescript/utils/badgeSelectionStorage.d.ts +9 -0
  33. package/lib/typescript/utils/eventExportFormatter.d.ts +4 -0
  34. package/package.json +3 -3
  35. package/src/components/EventsCopySettingsView.tsx +41 -5
  36. package/src/components/EventsModal.tsx +6 -17
  37. package/src/components/UnifiedEventDetail.tsx +28 -0
  38. package/src/components/UnifiedEventFilters.tsx +88 -21
  39. package/src/components/UnifiedEventItem.tsx +5 -0
  40. package/src/hooks/useUnifiedEvents.ts +153 -25
  41. package/src/index.tsx +4 -0
  42. package/src/stores/unifiedEventStore.ts +58 -12
  43. package/src/types/copySettings.ts +31 -1
  44. package/src/types/index.ts +4 -1
  45. package/src/utils/autoDiscoverEventSources.ts +268 -44
  46. package/src/utils/badgeSelectionStorage.ts +30 -0
  47. package/src/utils/eventExportFormatter.ts +797 -0
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.unsubscribeFromStorage = exports.unsubscribeFromRoutes = exports.unsubscribeFromRedux = exports.unsubscribeFromReactQuery = exports.unsubscribeFromNetwork = exports.unsubscribeAll = exports.unifiedEventStore = exports.subscribeToStorage = exports.subscribeToRoutes = exports.subscribeToRedux = exports.subscribeToReactQuery = exports.subscribeToNetwork = exports.subscribeToAll = exports.subscribe = exports.isSourceSubscribed = exports.getSubscriptionStatus = exports.getSourceCounts = exports.getEvents = exports.getEventCount = exports.getDiscoveredSources = exports.getAvailableEventSources = exports.getActiveSources = exports.clearEvents = void 0;
6
+ exports.unsubscribeFromStorage = exports.unsubscribeFromRoutes = exports.unsubscribeFromRender = exports.unsubscribeFromRedux = exports.unsubscribeFromReactQuery = exports.unsubscribeFromNetwork = exports.unsubscribeAll = exports.unifiedEventStore = exports.subscribeToStorage = exports.subscribeToRoutes = exports.subscribeToRender = exports.subscribeToRedux = exports.subscribeToReactQuery = exports.subscribeToNetwork = exports.subscribeToAll = exports.subscribe = exports.isSourceSubscribed = exports.getSubscriptionStatus = exports.getSubscriberCounts = exports.getSourceCounts = exports.getEvents = exports.getEventCount = exports.getDiscoveredSources = exports.getAvailableEventSources = exports.getActiveSources = exports.clearEvents = void 0;
7
7
  var _autoDiscoverEventSources = require("../utils/autoDiscoverEventSources");
8
8
  /**
9
9
  * Unified Event Store
@@ -59,18 +59,21 @@ class UnifiedEventStore {
59
59
  if (this.sourceUnsubscribers.has(source.id)) {
60
60
  return; // Already subscribed
61
61
  }
62
+ try {
63
+ // Run setup if needed
64
+ if (source.setup) {
65
+ await source.setup();
66
+ }
62
67
 
63
- // Run setup if needed
64
- if (source.setup) {
65
- await source.setup();
66
- }
67
-
68
- // Subscribe and track the unsubscriber
69
- const unsubscribe = await source.subscribe(event => {
70
- this.addEvent(event);
71
- });
72
- if (unsubscribe) {
73
- this.sourceUnsubscribers.set(source.id, unsubscribe);
68
+ // Subscribe and track the unsubscriber
69
+ const unsubscribe = await source.subscribe(event => {
70
+ this.addEvent(event);
71
+ });
72
+ if (unsubscribe) {
73
+ this.sourceUnsubscribers.set(source.id, unsubscribe);
74
+ }
75
+ } catch {
76
+ // Silently fail - source may not be available
74
77
  }
75
78
  }
76
79
 
@@ -147,7 +150,8 @@ class UnifiedEventStore {
147
150
  unsubscribeFromNetwork() {
148
151
  this.unsubscribeFromSource("network");
149
152
  this.activeSources.delete("network");
150
- this.networkEventIdMap.clear();
153
+ // Don't clear networkEventIdMap - it's needed to deduplicate events
154
+ // when resubscribing while requests are still in flight
151
155
  }
152
156
 
153
157
  /**
@@ -194,6 +198,27 @@ class UnifiedEventStore {
194
198
  this.activeSources.delete("route");
195
199
  }
196
200
 
201
+ /**
202
+ * Subscribe to render events (if @buoy-gg/highlight-updates is installed)
203
+ */
204
+ subscribeToRender() {
205
+ const {
206
+ sources
207
+ } = (0, _autoDiscoverEventSources.getCachedDiscovery)();
208
+ const renderSource = sources.find(s => s.id === "render");
209
+ if (renderSource) {
210
+ this.subscribeToSource(renderSource);
211
+ }
212
+ }
213
+
214
+ /**
215
+ * Unsubscribe from render events
216
+ */
217
+ unsubscribeFromRender() {
218
+ this.unsubscribeFromSource("render");
219
+ this.activeSources.delete("render");
220
+ }
221
+
197
222
  /**
198
223
  * Add an event to the store
199
224
  */
@@ -257,7 +282,8 @@ class UnifiedEventStore {
257
282
  "react-query": 0,
258
283
  "react-query-query": 0,
259
284
  "react-query-mutation": 0,
260
- route: 0
285
+ route: 0,
286
+ render: 0
261
287
  };
262
288
  for (const event of this.events) {
263
289
  counts[event.source]++;
@@ -310,7 +336,7 @@ class UnifiedEventStore {
310
336
  */
311
337
  unsubscribeAll() {
312
338
  // Unsubscribe from all tracked sources
313
- for (const [sourceId, unsubscribe] of this.sourceUnsubscribers) {
339
+ for (const [, unsubscribe] of this.sourceUnsubscribers) {
314
340
  unsubscribe();
315
341
  }
316
342
  this.sourceUnsubscribers.clear();
@@ -338,6 +364,8 @@ class UnifiedEventStore {
338
364
  return this.sourceUnsubscribers.has("react-query");
339
365
  case "route":
340
366
  return this.sourceUnsubscribers.has("route-events");
367
+ case "render":
368
+ return this.sourceUnsubscribers.has("render");
341
369
  default:
342
370
  return false;
343
371
  }
@@ -355,9 +383,18 @@ class UnifiedEventStore {
355
383
  "react-query": this.sourceUnsubscribers.has("react-query"),
356
384
  "react-query-query": this.sourceUnsubscribers.has("react-query"),
357
385
  "react-query-mutation": this.sourceUnsubscribers.has("react-query"),
358
- route: this.sourceUnsubscribers.has("route-events")
386
+ route: this.sourceUnsubscribers.has("route-events"),
387
+ render: this.sourceUnsubscribers.has("render")
359
388
  };
360
389
  }
390
+
391
+ /**
392
+ * Get subscriber counts from all underlying event stores.
393
+ * Useful for debugging the event system.
394
+ */
395
+ getSubscriberCounts() {
396
+ return (0, _autoDiscoverEventSources.getAggregatedSubscriberCounts)();
397
+ }
361
398
  }
362
399
 
363
400
  // Singleton instance
@@ -384,6 +421,10 @@ const subscribeToRoutes = () => unifiedEventStore.subscribeToRoutes();
384
421
  exports.subscribeToRoutes = subscribeToRoutes;
385
422
  const unsubscribeFromRoutes = () => unifiedEventStore.unsubscribeFromRoutes();
386
423
  exports.unsubscribeFromRoutes = unsubscribeFromRoutes;
424
+ const subscribeToRender = () => unifiedEventStore.subscribeToRender();
425
+ exports.subscribeToRender = subscribeToRender;
426
+ const unsubscribeFromRender = () => unifiedEventStore.unsubscribeFromRender();
427
+ exports.unsubscribeFromRender = unsubscribeFromRender;
387
428
  const getEvents = enabledSources => unifiedEventStore.getEvents(enabledSources);
388
429
  exports.getEvents = getEvents;
389
430
  const getActiveSources = () => unifiedEventStore.getActiveSources();
@@ -410,4 +451,8 @@ const getAvailableEventSources = () => unifiedEventStore.getAvailableEventSource
410
451
  exports.getAvailableEventSources = getAvailableEventSources;
411
452
  const subscribeToAll = () => unifiedEventStore.subscribeToAll();
412
453
  exports.subscribeToAll = subscribeToAll;
454
+ const getSubscriberCounts = () => unifiedEventStore.getSubscriberCounts();
455
+
456
+ // Re-export type for convenience
457
+ exports.getSubscriberCounts = getSubscriberCounts;
413
458
  //# sourceMappingURL=unifiedEventStore.js.map
@@ -165,6 +165,30 @@ const COPY_PRESETS = exports.COPY_PRESETS = {
165
165
  reduxChangedOnly: true,
166
166
  showStorageDiff: false,
167
167
  stripVerboseFields: true
168
+ },
169
+ /**
170
+ * Mermaid Diagram - Visual sequence diagram for flow visualization
171
+ */
172
+ mermaid: {
173
+ timestampFormat: "relative",
174
+ includeSource: true,
175
+ includeStatus: true,
176
+ includeTitle: true,
177
+ includeSubtitle: false,
178
+ includeCorrelation: true,
179
+ includeDuration: true,
180
+ includeSummaryHeader: false,
181
+ includeTotalDuration: false,
182
+ includeEventData: false,
183
+ dataSizeThreshold: 1,
184
+ format: "mermaid",
185
+ filterMode: "all",
186
+ filterSources: [],
187
+ compactMode: false,
188
+ smartJsonParsing: true,
189
+ reduxChangedOnly: true,
190
+ showStorageDiff: true,
191
+ stripVerboseFields: true
168
192
  }
169
193
  };
170
194
  /**
@@ -215,6 +239,11 @@ const PRESET_METADATA = exports.PRESET_METADATA = {
215
239
  label: "Minimal",
216
240
  description: "Quick reference",
217
241
  color: "#6B7280" // Gray
242
+ },
243
+ mermaid: {
244
+ label: "Diagram",
245
+ description: "Visual flow",
246
+ color: "#A855F7" // Purple
218
247
  }
219
248
  };
220
249
  //# sourceMappingURL=copySettings.js.map
@@ -5,6 +5,7 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.autoDiscoverEventSources = autoDiscoverEventSources;
7
7
  exports.clearDiscoveryCache = clearDiscoveryCache;
8
+ exports.getAggregatedSubscriberCounts = getAggregatedSubscriberCounts;
8
9
  exports.getCachedDiscovery = getCachedDiscovery;
9
10
  exports.getSourceDisplayConfig = getSourceDisplayConfig;
10
11
  /**
@@ -54,9 +55,7 @@ function tryLoadStorageSource() {
54
55
  name: "Storage",
55
56
  eventSources: ["storage-async", "storage-mmkv"],
56
57
  available: true,
57
- setup: async () => {
58
- await storageEventStore.startCapturing();
59
- },
58
+ // No setup needed - onEvent() auto-starts capturing via Subscribable pattern
60
59
  subscribe: onEvent => {
61
60
  return storageEventStore.onEvent(event => {
62
61
  const unifiedEvent = transformStorageEvent(event);
@@ -214,55 +213,55 @@ function transformReduxAction(action) {
214
213
  function tryLoadNetworkSource() {
215
214
  try {
216
215
  // @ts-ignore - Dynamic import that may not exist
216
+ // Note: We use networkListener (the getter) instead of startNetworkListener
217
+ // because startNetworkListener is not exported from the main package
217
218
  const {
218
219
  networkEventStore,
219
- startNetworkListener,
220
+ networkListener,
220
221
  addNetworkListener
221
222
  } = require("@buoy-gg/network");
222
223
 
223
- // Map network event IDs to unified event IDs for updates
224
+ // Map network event IDs to unified event IDs for updates (request -> response)
224
225
  const networkEventIdMap = new Map();
225
- let storeUnsubscribe = null;
226
- let listenerUnsubscribe = null;
227
226
  return {
228
227
  id: "network",
229
228
  name: "Network",
230
229
  eventSources: ["network"],
231
230
  available: true,
232
231
  setup: () => {
233
- startNetworkListener();
232
+ // Get the network listener singleton and start it if not already active
233
+ const listener = networkListener();
234
+ if (!listener.isActive) {
235
+ listener.startListening();
236
+ }
237
+
238
+ // Ensure events flow into the store. The network panel does this via
239
+ // addNetworkListener, but if events package loads first, we need to
240
+ // set it up ourselves.
241
+ if (listener.listenerCount === 0) {
242
+ addNetworkListener(event => {
243
+ networkEventStore.processNetworkEvent(event);
244
+ });
245
+ }
234
246
  },
235
247
  subscribe: onEvent => {
236
- // Add listener to process network events into the store
237
- listenerUnsubscribe = addNetworkListener(event => {
238
- networkEventStore.processNetworkEvent(event);
239
- });
240
-
241
- // Subscribe to network event store
242
- storeUnsubscribe = networkEventStore.subscribe(events => {
243
- for (const networkEvent of events) {
244
- const ne = networkEvent;
245
- const existingUnifiedId = networkEventIdMap.get(ne.id);
246
- if (!existingUnifiedId) {
247
- // New event
248
- const unifiedEvent = transformNetworkEvent(networkEvent);
249
- networkEventIdMap.set(ne.id, unifiedEvent.id);
250
- onEvent(unifiedEvent);
251
- } else {
252
- // Existing event updated (e.g., pending -> success/error)
253
- // Create updated unified event with same ID so store can update it
254
- const unifiedEvent = transformNetworkEvent(networkEvent);
255
- unifiedEvent.id = existingUnifiedId; // Keep the same unified ID
256
- onEvent(unifiedEvent);
257
- }
248
+ // Use onEvent() pattern - same as storage
249
+ // This fires for each individual event (request or response/error update)
250
+ return networkEventStore.onEvent(event => {
251
+ const ne = event;
252
+ const existingUnifiedId = networkEventIdMap.get(ne.id);
253
+ if (!existingUnifiedId) {
254
+ // New event (request started)
255
+ const unifiedEvent = transformNetworkEvent(event);
256
+ networkEventIdMap.set(ne.id, unifiedEvent.id);
257
+ onEvent(unifiedEvent);
258
+ } else {
259
+ // Existing event updated (response received or error)
260
+ const unifiedEvent = transformNetworkEvent(event);
261
+ unifiedEvent.id = existingUnifiedId; // Keep the same unified ID
262
+ onEvent(unifiedEvent);
258
263
  }
259
264
  });
260
- return () => {
261
- listenerUnsubscribe?.();
262
- storeUnsubscribe?.();
263
- listenerUnsubscribe = null;
264
- storeUnsubscribe = null;
265
- };
266
265
  }
267
266
  };
268
267
  } catch {
@@ -467,15 +466,16 @@ function tryLoadRouteEventsSource() {
467
466
  try {
468
467
  // @ts-ignore - Dynamic import that may not exist
469
468
  const {
470
- routeObserver
469
+ routeEventStore
471
470
  } = require("@buoy-gg/route-events");
472
471
  return {
473
472
  id: "route-events",
474
473
  name: "Routes",
475
474
  eventSources: ["route"],
476
475
  available: true,
476
+ // No setup needed - onEvent() auto-starts listening via Subscribable pattern
477
477
  subscribe: onEvent => {
478
- return routeObserver.addListener(event => {
478
+ return routeEventStore.onEvent(event => {
479
479
  const unifiedEvent = transformRouteEvent(event);
480
480
  onEvent(unifiedEvent);
481
481
  });
@@ -523,6 +523,134 @@ function transformRouteEvent(event) {
523
523
  };
524
524
  }
525
525
 
526
+ // ============================================================================
527
+ // Render Events Source Discovery (Highlight Updates)
528
+ // ============================================================================
529
+
530
+ function tryLoadHighlightUpdatesSource() {
531
+ try {
532
+ // @ts-ignore - Dynamic import that may not exist
533
+ const highlightUpdates = require("@buoy-gg/highlight-updates");
534
+
535
+ // Verify the required exports exist
536
+ if (!highlightUpdates.RenderTracker || !highlightUpdates.HighlightUpdatesController) {
537
+ return null;
538
+ }
539
+ return {
540
+ id: "render",
541
+ name: "Render",
542
+ eventSources: ["render"],
543
+ available: true,
544
+ setup: () => {
545
+ // @ts-ignore
546
+ const {
547
+ HighlightUpdatesController
548
+ } = require("@buoy-gg/highlight-updates");
549
+ // Enable background tracking (NOT the visual toggle) - this sets up render
550
+ // interception without affecting the user's visual highlight toggle state
551
+ if (HighlightUpdatesController) {
552
+ HighlightUpdatesController.enableBackgroundTracking();
553
+ }
554
+ },
555
+ subscribe: onEvent => {
556
+ // @ts-ignore
557
+ const {
558
+ RenderTracker,
559
+ HighlightUpdatesController
560
+ } = require("@buoy-gg/highlight-updates");
561
+
562
+ // Ensure background tracking is enabled (separate from visual toggle)
563
+ if (HighlightUpdatesController && !HighlightUpdatesController.isBackgroundTrackingEnabled()) {
564
+ HighlightUpdatesController.enableBackgroundTracking();
565
+ }
566
+ const unsubscribeCallback = RenderTracker.onRenderEvent((event, render) => {
567
+ const unifiedEvent = transformRenderEvent(event, render);
568
+ onEvent(unifiedEvent);
569
+ });
570
+
571
+ // Return a wrapped unsubscribe that also disables background tracking
572
+ return () => {
573
+ unsubscribeCallback();
574
+ HighlightUpdatesController.disableBackgroundTracking();
575
+ };
576
+ }
577
+ };
578
+ } catch {
579
+ return null;
580
+ }
581
+ }
582
+ function transformRenderEvent(event, render) {
583
+ const e = event;
584
+ const r = render;
585
+
586
+ // Use component name if available, otherwise display name (View, Text, etc.)
587
+ const title = r.componentName || r.displayName || r.viewType;
588
+
589
+ // Build subtitle from cause info
590
+ const subtitleParts = [];
591
+
592
+ // Add cause type
593
+ const causeLabels = {
594
+ mount: "mounted",
595
+ props: "props changed",
596
+ state: "state changed",
597
+ hooks: "hooks changed",
598
+ context: "context changed",
599
+ parent: "parent re-rendered",
600
+ unknown: "re-rendered"
601
+ };
602
+ subtitleParts.push(causeLabels[e.cause.type] || e.cause.type);
603
+
604
+ // Add changed keys if props changed
605
+ if (e.cause.type === "props" && e.cause.changedKeys?.length) {
606
+ const keys = e.cause.changedKeys.slice(0, 3).join(", ");
607
+ const more = e.cause.changedKeys.length > 3 ? ` +${e.cause.changedKeys.length - 3}` : "";
608
+ subtitleParts.push(`[${keys}${more}]`);
609
+ }
610
+
611
+ // Add hook change description if available
612
+ if (e.cause.hookChanges?.length) {
613
+ const firstChange = e.cause.hookChanges[0];
614
+ if (firstChange.description) {
615
+ subtitleParts.push(firstChange.description);
616
+ }
617
+ }
618
+
619
+ // Add render number
620
+ subtitleParts.push(`#${e.renderNumber}`);
621
+
622
+ // Determine status based on cause type
623
+ let status = "neutral";
624
+ switch (e.cause.type) {
625
+ case "mount":
626
+ status = "neutral"; // First render is expected
627
+ break;
628
+ case "props":
629
+ case "state":
630
+ case "hooks":
631
+ case "context":
632
+ status = "success"; // Intentional re-renders
633
+ break;
634
+ case "parent":
635
+ status = "pending"; // Potentially wasteful (yellow highlight)
636
+ break;
637
+ default:
638
+ status = "neutral";
639
+ }
640
+ return {
641
+ id: generateEventId("render"),
642
+ source: "render",
643
+ timestamp: e.timestamp,
644
+ title,
645
+ subtitle: subtitleParts.join(" · "),
646
+ status,
647
+ originalEvent: {
648
+ event: e,
649
+ render: r
650
+ }
651
+ };
652
+ }
653
+
526
654
  // ============================================================================
527
655
  // Main Auto-Discovery Function
528
656
  // ============================================================================
@@ -549,7 +677,7 @@ function autoDiscoverEventSources() {
549
677
  const availableEventSources = new Set();
550
678
 
551
679
  // Try to load each source
552
- const loaders = [tryLoadStorageSource, tryLoadReduxSource, tryLoadNetworkSource, tryLoadReactQuerySource, tryLoadRouteEventsSource];
680
+ const loaders = [tryLoadStorageSource, tryLoadReduxSource, tryLoadNetworkSource, tryLoadReactQuerySource, tryLoadRouteEventsSource, tryLoadHighlightUpdatesSource];
553
681
  for (const loader of loaders) {
554
682
  const source = loader();
555
683
  if (source && source.available) {
@@ -608,6 +736,11 @@ function getSourceDisplayConfig(source) {
608
736
  label: "Route",
609
737
  color: "#06B6D4",
610
738
  icon: "navigate-outline"
739
+ },
740
+ render: {
741
+ label: "Render",
742
+ color: "#F472B6",
743
+ icon: "layers-outline"
611
744
  }
612
745
  };
613
746
  return configs[source] || {
@@ -637,4 +770,93 @@ function getCachedDiscovery() {
637
770
  function clearDiscoveryCache() {
638
771
  cachedDiscovery = null;
639
772
  }
773
+
774
+ // ============================================================================
775
+ // Subscriber Count Aggregation
776
+ // ============================================================================
777
+
778
+ /**
779
+ * Get subscriber counts from all discovered event stores.
780
+ * Useful for debugging and monitoring the event system.
781
+ */
782
+ function getAggregatedSubscriberCounts() {
783
+ const sources = [];
784
+ let totalSubscribers = 0;
785
+
786
+ // Try to get counts from storage store
787
+ try {
788
+ // @ts-ignore - Dynamic import that may not exist
789
+ const {
790
+ storageEventStore
791
+ } = require("@buoy-gg/storage");
792
+ const counts = storageEventStore.getSubscriberCounts();
793
+ sources.push({
794
+ sourceId: "storage",
795
+ counts
796
+ });
797
+ totalSubscribers += counts.total;
798
+ } catch {
799
+ // Package not installed
800
+ }
801
+
802
+ // Try to get counts from network store
803
+ try {
804
+ // @ts-ignore - Dynamic import that may not exist
805
+ const {
806
+ networkEventStore
807
+ } = require("@buoy-gg/network");
808
+ const counts = networkEventStore.getSubscriberCounts();
809
+ sources.push({
810
+ sourceId: "network",
811
+ counts
812
+ });
813
+ totalSubscribers += counts.total;
814
+ } catch {
815
+ // Package not installed
816
+ }
817
+
818
+ // Try to get counts from route events store
819
+ try {
820
+ // @ts-ignore - Dynamic import that may not exist
821
+ const {
822
+ routeEventStore
823
+ } = require("@buoy-gg/route-events");
824
+ const counts = routeEventStore.getSubscriberCounts();
825
+ sources.push({
826
+ sourceId: "route-events",
827
+ counts
828
+ });
829
+ totalSubscribers += counts.total;
830
+ } catch {
831
+ // Package not installed
832
+ }
833
+
834
+ // Try to get counts from render tracker (highlight-updates)
835
+ try {
836
+ // @ts-ignore - Dynamic import that may not exist
837
+ const {
838
+ RenderTracker,
839
+ HighlightUpdatesController
840
+ } = require("@buoy-gg/highlight-updates");
841
+ const callbackCount = RenderTracker.getRenderEventCallbackCount();
842
+ // Also count the visual highlight tool as a subscriber when enabled
843
+ const visualToolEnabled = HighlightUpdatesController?.isEnabled?.() ? 1 : 0;
844
+ const counts = {
845
+ eventCallbacks: callbackCount,
846
+ arrayListeners: visualToolEnabled,
847
+ total: callbackCount + visualToolEnabled
848
+ };
849
+ sources.push({
850
+ sourceId: "render",
851
+ counts
852
+ });
853
+ totalSubscribers += counts.total;
854
+ } catch {
855
+ // Package not installed
856
+ }
857
+ return {
858
+ sources,
859
+ totalSubscribers
860
+ };
861
+ }
640
862
  //# sourceMappingURL=autoDiscoverEventSources.js.map
@@ -4,7 +4,9 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.clearEnabledSources = clearEnabledSources;
7
+ exports.loadCapturingState = loadCapturingState;
7
8
  exports.loadEnabledSources = loadEnabledSources;
9
+ exports.saveCapturingState = saveCapturingState;
8
10
  exports.saveEnabledSources = saveEnabledSources;
9
11
  var _sharedUi = require("@buoy-gg/shared-ui");
10
12
  /**
@@ -55,4 +57,34 @@ async function clearEnabledSources() {
55
57
  // Silently fail
56
58
  }
57
59
  }
60
+
61
+ /**
62
+ * Save the capturing state to persistent storage
63
+ */
64
+ async function saveCapturingState(isCapturing) {
65
+ try {
66
+ const key = _sharedUi.devToolsStorageKeys.events.isCapturing();
67
+ await _sharedUi.persistentStorage.setItem(key, JSON.stringify(isCapturing));
68
+ } catch {
69
+ // Silently fail - persistence is optional
70
+ }
71
+ }
72
+
73
+ /**
74
+ * Load the capturing state from persistent storage
75
+ * Returns null if no saved state exists (defaults to true on first load)
76
+ */
77
+ async function loadCapturingState() {
78
+ try {
79
+ const key = _sharedUi.devToolsStorageKeys.events.isCapturing();
80
+ const value = await _sharedUi.persistentStorage.getItem(key);
81
+ if (value !== null && value !== "") {
82
+ return JSON.parse(value);
83
+ }
84
+ return null;
85
+ } catch {
86
+ // Silently fail - return null to use defaults
87
+ return null;
88
+ }
89
+ }
58
90
  //# sourceMappingURL=badgeSelectionStorage.js.map