@buoy-gg/events 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.
Files changed (84) hide show
  1. package/LICENSE +58 -0
  2. package/README.md +55 -0
  3. package/lib/commonjs/components/EventsCopySettingsView.js +645 -0
  4. package/lib/commonjs/components/EventsModal.js +263 -0
  5. package/lib/commonjs/components/ReactQueryEventDetail.js +428 -0
  6. package/lib/commonjs/components/UnifiedEventDetail.js +370 -0
  7. package/lib/commonjs/components/UnifiedEventFilters.js +113 -0
  8. package/lib/commonjs/components/UnifiedEventItem.js +349 -0
  9. package/lib/commonjs/components/UnifiedEventList.js +154 -0
  10. package/lib/commonjs/components/UnifiedEventViewer.js +126 -0
  11. package/lib/commonjs/hooks/useUnifiedEvents.js +237 -0
  12. package/lib/commonjs/index.js +205 -0
  13. package/lib/commonjs/package.json +1 -0
  14. package/lib/commonjs/preset.js +66 -0
  15. package/lib/commonjs/stores/unifiedEventStore.js +413 -0
  16. package/lib/commonjs/types/copySettings.js +220 -0
  17. package/lib/commonjs/types/index.js +17 -0
  18. package/lib/commonjs/utils/autoDiscoverEventSources.js +640 -0
  19. package/lib/commonjs/utils/badgeSelectionStorage.js +58 -0
  20. package/lib/commonjs/utils/copySettingsStorage.js +66 -0
  21. package/lib/commonjs/utils/correlationUtils.js +130 -0
  22. package/lib/commonjs/utils/eventExportFormatter.js +1095 -0
  23. package/lib/commonjs/utils/eventTransformers.js +496 -0
  24. package/lib/module/components/EventsCopySettingsView.js +641 -0
  25. package/lib/module/components/EventsModal.js +259 -0
  26. package/lib/module/components/ReactQueryEventDetail.js +424 -0
  27. package/lib/module/components/UnifiedEventDetail.js +366 -0
  28. package/lib/module/components/UnifiedEventFilters.js +109 -0
  29. package/lib/module/components/UnifiedEventItem.js +345 -0
  30. package/lib/module/components/UnifiedEventList.js +150 -0
  31. package/lib/module/components/UnifiedEventViewer.js +122 -0
  32. package/lib/module/hooks/useUnifiedEvents.js +234 -0
  33. package/lib/module/index.js +77 -0
  34. package/lib/module/preset.js +62 -0
  35. package/lib/module/stores/unifiedEventStore.js +387 -0
  36. package/lib/module/types/copySettings.js +215 -0
  37. package/lib/module/types/index.js +37 -0
  38. package/lib/module/utils/autoDiscoverEventSources.js +633 -0
  39. package/lib/module/utils/badgeSelectionStorage.js +52 -0
  40. package/lib/module/utils/copySettingsStorage.js +61 -0
  41. package/lib/module/utils/correlationUtils.js +120 -0
  42. package/lib/module/utils/eventExportFormatter.js +1085 -0
  43. package/lib/module/utils/eventTransformers.js +487 -0
  44. package/lib/typescript/components/EventsCopySettingsView.d.ts +16 -0
  45. package/lib/typescript/components/EventsModal.d.ts +16 -0
  46. package/lib/typescript/components/ReactQueryEventDetail.d.ts +15 -0
  47. package/lib/typescript/components/UnifiedEventDetail.d.ts +15 -0
  48. package/lib/typescript/components/UnifiedEventFilters.d.ts +21 -0
  49. package/lib/typescript/components/UnifiedEventItem.d.ts +26 -0
  50. package/lib/typescript/components/UnifiedEventList.d.ts +27 -0
  51. package/lib/typescript/components/UnifiedEventViewer.d.ts +8 -0
  52. package/lib/typescript/hooks/useUnifiedEvents.d.ts +30 -0
  53. package/lib/typescript/index.d.ts +28 -0
  54. package/lib/typescript/preset.d.ts +62 -0
  55. package/lib/typescript/stores/unifiedEventStore.d.ts +146 -0
  56. package/lib/typescript/types/copySettings.d.ts +179 -0
  57. package/lib/typescript/types/index.d.ts +73 -0
  58. package/lib/typescript/utils/autoDiscoverEventSources.d.ts +74 -0
  59. package/lib/typescript/utils/badgeSelectionStorage.d.ts +21 -0
  60. package/lib/typescript/utils/copySettingsStorage.d.ts +21 -0
  61. package/lib/typescript/utils/correlationUtils.d.ts +36 -0
  62. package/lib/typescript/utils/eventExportFormatter.d.ts +49 -0
  63. package/lib/typescript/utils/eventTransformers.d.ts +119 -0
  64. package/package.json +91 -0
  65. package/src/components/EventsCopySettingsView.tsx +742 -0
  66. package/src/components/EventsModal.tsx +328 -0
  67. package/src/components/ReactQueryEventDetail.tsx +413 -0
  68. package/src/components/UnifiedEventDetail.tsx +371 -0
  69. package/src/components/UnifiedEventFilters.tsx +156 -0
  70. package/src/components/UnifiedEventItem.tsx +396 -0
  71. package/src/components/UnifiedEventList.tsx +197 -0
  72. package/src/components/UnifiedEventViewer.tsx +132 -0
  73. package/src/hooks/useUnifiedEvents.ts +288 -0
  74. package/src/index.tsx +112 -0
  75. package/src/preset.tsx +57 -0
  76. package/src/stores/unifiedEventStore.ts +405 -0
  77. package/src/types/copySettings.ts +269 -0
  78. package/src/types/index.ts +96 -0
  79. package/src/utils/autoDiscoverEventSources.ts +690 -0
  80. package/src/utils/badgeSelectionStorage.ts +51 -0
  81. package/src/utils/copySettingsStorage.ts +61 -0
  82. package/src/utils/correlationUtils.ts +146 -0
  83. package/src/utils/eventExportFormatter.ts +1233 -0
  84. package/src/utils/eventTransformers.ts +567 -0
@@ -0,0 +1,633 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * Auto-Discover Event Sources
5
+ *
6
+ * Automatically discovers and loads event stores from installed packages.
7
+ * Uses try-catch pattern to safely handle missing packages - if a tool
8
+ * isn't installed, it's silently skipped.
9
+ *
10
+ * This enables zero-config setup - just install the dev tool packages you
11
+ * want and they'll automatically appear in the unified events timeline!
12
+ */
13
+
14
+ // ============================================================================
15
+ // Types for discovered event sources
16
+ // ============================================================================
17
+
18
+ /**
19
+ * Configuration for a discovered event source
20
+ */
21
+
22
+ /**
23
+ * Result of auto-discovery
24
+ */
25
+
26
+ // ============================================================================
27
+ // Event transformers (inline to avoid import dependencies)
28
+ // ============================================================================
29
+
30
+ let eventIdCounter = 0;
31
+ function generateEventId(source) {
32
+ return `${source}-${Date.now()}-${++eventIdCounter}`;
33
+ }
34
+
35
+ // ============================================================================
36
+ // Storage Event Source Discovery
37
+ // ============================================================================
38
+
39
+ function tryLoadStorageSource() {
40
+ try {
41
+ // @ts-ignore - Dynamic import that may not exist
42
+ const {
43
+ storageEventStore
44
+ } = require("@buoy-gg/storage");
45
+ return {
46
+ id: "storage",
47
+ name: "Storage",
48
+ eventSources: ["storage-async", "storage-mmkv"],
49
+ available: true,
50
+ setup: async () => {
51
+ await storageEventStore.startCapturing();
52
+ },
53
+ subscribe: onEvent => {
54
+ return storageEventStore.onEvent(event => {
55
+ const unifiedEvent = transformStorageEvent(event);
56
+ onEvent(unifiedEvent);
57
+ });
58
+ }
59
+ };
60
+ } catch {
61
+ return null;
62
+ }
63
+ }
64
+ function transformStorageEvent(event) {
65
+ const e = event;
66
+ const source = e.storageType === "async" ? "storage-async" : "storage-mmkv";
67
+
68
+ // Get action label
69
+ let title = e.action;
70
+ if (e.storageType === "async") {
71
+ const labelMap = {
72
+ setItem: "Set Item",
73
+ removeItem: "Remove Item",
74
+ mergeItem: "Merge Item",
75
+ clear: "Clear All",
76
+ multiSet: "Multi Set",
77
+ multiRemove: "Multi Remove",
78
+ multiMerge: "Multi Merge"
79
+ };
80
+ title = labelMap[e.action] || e.action;
81
+ }
82
+
83
+ // Get subtitle
84
+ let subtitle = "";
85
+ if (e.storageType === "async") {
86
+ switch (e.action) {
87
+ case "setItem":
88
+ case "removeItem":
89
+ case "mergeItem":
90
+ subtitle = e.data?.key || "unknown key";
91
+ break;
92
+ case "multiSet":
93
+ case "multiMerge":
94
+ {
95
+ const pairCount = e.data?.pairs?.length || 0;
96
+ subtitle = `${pairCount} key${pairCount !== 1 ? "s" : ""}`;
97
+ break;
98
+ }
99
+ case "multiRemove":
100
+ {
101
+ const keyCount = e.data?.keys?.length || 0;
102
+ subtitle = `${keyCount} key${keyCount !== 1 ? "s" : ""}`;
103
+ break;
104
+ }
105
+ case "clear":
106
+ subtitle = "all keys";
107
+ break;
108
+ }
109
+ } else {
110
+ subtitle = e.data?.key || e.data?.instanceId || "unknown";
111
+ }
112
+
113
+ // Get status
114
+ let status = "neutral";
115
+ if (e.action.includes("set") || e.action.includes("Set") || e.action.includes("merge") || e.action.includes("Merge")) {
116
+ status = "success";
117
+ }
118
+ return {
119
+ id: generateEventId(source),
120
+ source,
121
+ timestamp: e.timestamp.getTime(),
122
+ title,
123
+ subtitle,
124
+ status,
125
+ originalEvent: event
126
+ };
127
+ }
128
+
129
+ // ============================================================================
130
+ // Redux Event Source Discovery
131
+ // ============================================================================
132
+
133
+ function tryLoadReduxSource() {
134
+ try {
135
+ // @ts-ignore - Dynamic import that may not exist
136
+ const {
137
+ reduxActionStore
138
+ } = require("@buoy-gg/redux");
139
+ let lastActionId = null;
140
+ return {
141
+ id: "redux",
142
+ name: "Redux",
143
+ eventSources: ["redux"],
144
+ available: true,
145
+ subscribe: onEvent => {
146
+ return reduxActionStore.subscribe(actions => {
147
+ if (actions.length > 0) {
148
+ const latestAction = actions[0];
149
+ if (latestAction.id !== lastActionId) {
150
+ lastActionId = latestAction.id;
151
+ const unifiedEvent = transformReduxAction(latestAction);
152
+ onEvent(unifiedEvent);
153
+ }
154
+ }
155
+ });
156
+ }
157
+ };
158
+ } catch {
159
+ return null;
160
+ }
161
+ }
162
+ function transformReduxAction(action) {
163
+ const a = action;
164
+
165
+ // Get status
166
+ let status = "neutral";
167
+ switch (a.category) {
168
+ case "fulfilled":
169
+ status = "success";
170
+ break;
171
+ case "rejected":
172
+ status = "error";
173
+ break;
174
+ case "pending":
175
+ status = "pending";
176
+ break;
177
+ default:
178
+ status = a.hasStateChange ? "success" : "neutral";
179
+ }
180
+
181
+ // Get subtitle
182
+ let subtitle = "";
183
+ if (a.payloadPreview) {
184
+ subtitle = a.payloadPreview;
185
+ } else if (a.hasStateChange && a.diffSummary) {
186
+ subtitle = a.diffSummary;
187
+ } else if (a.duration !== undefined) {
188
+ subtitle = `${a.duration.toFixed(1)}ms`;
189
+ } else {
190
+ subtitle = a.sliceName || "";
191
+ }
192
+ return {
193
+ id: generateEventId("redux"),
194
+ source: "redux",
195
+ timestamp: a.timestamp,
196
+ title: a.type,
197
+ subtitle,
198
+ status,
199
+ originalEvent: action
200
+ };
201
+ }
202
+
203
+ // ============================================================================
204
+ // Network Event Source Discovery
205
+ // ============================================================================
206
+
207
+ function tryLoadNetworkSource() {
208
+ try {
209
+ // @ts-ignore - Dynamic import that may not exist
210
+ const {
211
+ networkEventStore,
212
+ startNetworkListener,
213
+ addNetworkListener
214
+ } = require("@buoy-gg/network");
215
+
216
+ // Map network event IDs to unified event IDs for updates
217
+ const networkEventIdMap = new Map();
218
+ let storeUnsubscribe = null;
219
+ let listenerUnsubscribe = null;
220
+ return {
221
+ id: "network",
222
+ name: "Network",
223
+ eventSources: ["network"],
224
+ available: true,
225
+ setup: () => {
226
+ startNetworkListener();
227
+ },
228
+ subscribe: onEvent => {
229
+ // Add listener to process network events into the store
230
+ listenerUnsubscribe = addNetworkListener(event => {
231
+ networkEventStore.processNetworkEvent(event);
232
+ });
233
+
234
+ // Subscribe to network event store
235
+ storeUnsubscribe = networkEventStore.subscribe(events => {
236
+ for (const networkEvent of events) {
237
+ const ne = networkEvent;
238
+ const existingUnifiedId = networkEventIdMap.get(ne.id);
239
+ if (!existingUnifiedId) {
240
+ // New event
241
+ const unifiedEvent = transformNetworkEvent(networkEvent);
242
+ networkEventIdMap.set(ne.id, unifiedEvent.id);
243
+ onEvent(unifiedEvent);
244
+ } else {
245
+ // Existing event updated (e.g., pending -> success/error)
246
+ // Create updated unified event with same ID so store can update it
247
+ const unifiedEvent = transformNetworkEvent(networkEvent);
248
+ unifiedEvent.id = existingUnifiedId; // Keep the same unified ID
249
+ onEvent(unifiedEvent);
250
+ }
251
+ }
252
+ });
253
+ return () => {
254
+ listenerUnsubscribe?.();
255
+ storeUnsubscribe?.();
256
+ listenerUnsubscribe = null;
257
+ storeUnsubscribe = null;
258
+ };
259
+ }
260
+ };
261
+ } catch {
262
+ return null;
263
+ }
264
+ }
265
+ function transformNetworkEvent(event) {
266
+ const e = event;
267
+
268
+ // Get status
269
+ let status = "neutral";
270
+ if (e.status === undefined) {
271
+ status = "pending";
272
+ } else if (e.error || e.status >= 400) {
273
+ status = "error";
274
+ } else if (e.status >= 200 && e.status < 400) {
275
+ status = "success";
276
+ }
277
+
278
+ // Get title
279
+ const title = e.operationName || `${e.method} ${e.path || e.url}`;
280
+
281
+ // Get subtitle
282
+ const parts = [];
283
+ if (e.status !== undefined) {
284
+ parts.push(`${e.status}`);
285
+ } else if (e.error) {
286
+ parts.push("Error");
287
+ } else {
288
+ parts.push("Pending");
289
+ }
290
+ if (e.duration !== undefined) {
291
+ parts.push(`${e.duration.toFixed(0)}ms`);
292
+ }
293
+ if (e.host) {
294
+ parts.push(e.host);
295
+ }
296
+ return {
297
+ id: generateEventId("network"),
298
+ source: "network",
299
+ timestamp: e.timestamp,
300
+ title,
301
+ subtitle: parts.join(" · "),
302
+ status,
303
+ originalEvent: event
304
+ };
305
+ }
306
+
307
+ // ============================================================================
308
+ // React Query Event Source Discovery
309
+ // ============================================================================
310
+
311
+ function tryLoadReactQuerySource() {
312
+ try {
313
+ // @ts-ignore - Dynamic import that may not exist
314
+ const {
315
+ reactQueryEventStore
316
+ } = require("@buoy-gg/react-query");
317
+ let lastEventId = null;
318
+ return {
319
+ id: "react-query",
320
+ name: "React Query",
321
+ eventSources: ["react-query", "react-query-query", "react-query-mutation"],
322
+ available: true,
323
+ subscribe: onEvent => {
324
+ return reactQueryEventStore.subscribe(events => {
325
+ if (events.length > 0) {
326
+ const latestEvent = events[0];
327
+ if (latestEvent.id !== lastEventId) {
328
+ lastEventId = latestEvent.id;
329
+ const unifiedEvent = transformReactQueryEvent(latestEvent);
330
+ onEvent(unifiedEvent);
331
+ }
332
+ }
333
+ });
334
+ }
335
+ };
336
+ } catch {
337
+ return null;
338
+ }
339
+ }
340
+ function formatQueryKey(queryKey) {
341
+ if (!queryKey || queryKey.length === 0) return "unknown";
342
+ return queryKey.map(part => {
343
+ if (typeof part === "string") return part;
344
+ if (typeof part === "number") return String(part);
345
+ if (typeof part === "object" && part !== null) {
346
+ const obj = part;
347
+ const firstValue = Object.values(obj)[0];
348
+ if (typeof firstValue === "string" || typeof firstValue === "number") {
349
+ return String(firstValue);
350
+ }
351
+ return JSON.stringify(part).slice(0, 20);
352
+ }
353
+ return String(part);
354
+ }).join(" › ");
355
+ }
356
+ function transformReactQueryEvent(event) {
357
+ const e = event;
358
+ const isMutation = e.type.startsWith("mutation-");
359
+ const source = isMutation ? "react-query-mutation" : "react-query-query";
360
+
361
+ // Get status
362
+ let status = "neutral";
363
+ switch (e.type) {
364
+ case "query-fetch-start":
365
+ case "mutation-start":
366
+ status = "pending";
367
+ break;
368
+ case "query-fetch-success":
369
+ case "mutation-success":
370
+ status = "success";
371
+ break;
372
+ case "query-fetch-error":
373
+ case "mutation-error":
374
+ status = "error";
375
+ break;
376
+ }
377
+
378
+ // Get title
379
+ let title = "";
380
+ if (e.queryKey) {
381
+ title = formatQueryKey(e.queryKey);
382
+ } else if (e.mutationKey) {
383
+ title = formatQueryKey(e.mutationKey);
384
+ } else if (e.mutationId !== undefined) {
385
+ title = `Mutation #${e.mutationId}`;
386
+ } else {
387
+ title = e.type.replace(/-/g, " ");
388
+ }
389
+
390
+ // Get subtitle
391
+ const parts = [];
392
+ switch (e.type) {
393
+ case "query-fetch-start":
394
+ parts.push("Fetching");
395
+ break;
396
+ case "query-fetch-success":
397
+ parts.push("Success");
398
+ break;
399
+ case "query-fetch-error":
400
+ parts.push("Error");
401
+ break;
402
+ case "query-invalidated":
403
+ parts.push("Invalidated");
404
+ break;
405
+ case "mutation-start":
406
+ parts.push("Mutating");
407
+ break;
408
+ case "mutation-success":
409
+ parts.push("Success");
410
+ break;
411
+ case "mutation-error":
412
+ parts.push("Error");
413
+ break;
414
+ }
415
+ if (e.duration !== undefined) {
416
+ parts.push(`${e.duration.toFixed(0)}ms`);
417
+ }
418
+
419
+ // Get correlation info
420
+ let correlationId;
421
+ if (e.queryHash) {
422
+ correlationId = `rq-query-${e.queryHash}`;
423
+ } else if (e.mutationId !== undefined) {
424
+ correlationId = `rq-mutation-${e.mutationId}`;
425
+ }
426
+ let sequenceInGroup = 1;
427
+ switch (e.type) {
428
+ case "query-fetch-start":
429
+ case "mutation-start":
430
+ sequenceInGroup = 1;
431
+ break;
432
+ case "query-fetch-success":
433
+ case "query-fetch-error":
434
+ case "mutation-success":
435
+ case "mutation-error":
436
+ sequenceInGroup = 2;
437
+ break;
438
+ case "query-invalidated":
439
+ sequenceInGroup = 3;
440
+ break;
441
+ }
442
+ return {
443
+ id: generateEventId(source),
444
+ source,
445
+ timestamp: e.timestamp,
446
+ title,
447
+ subtitle: parts.join(" · "),
448
+ status,
449
+ originalEvent: event,
450
+ correlationId,
451
+ sequenceInGroup
452
+ };
453
+ }
454
+
455
+ // ============================================================================
456
+ // Route Events Source Discovery
457
+ // ============================================================================
458
+
459
+ function tryLoadRouteEventsSource() {
460
+ try {
461
+ // @ts-ignore - Dynamic import that may not exist
462
+ const {
463
+ routeObserver
464
+ } = require("@buoy-gg/route-events");
465
+ return {
466
+ id: "route-events",
467
+ name: "Routes",
468
+ eventSources: ["route"],
469
+ available: true,
470
+ subscribe: onEvent => {
471
+ return routeObserver.addListener(event => {
472
+ const unifiedEvent = transformRouteEvent(event);
473
+ onEvent(unifiedEvent);
474
+ });
475
+ }
476
+ };
477
+ } catch {
478
+ return null;
479
+ }
480
+ }
481
+ function transformRouteEvent(event) {
482
+ const e = event;
483
+
484
+ // Get status
485
+ let status = "neutral";
486
+ if (e.pathname === "/") {
487
+ status = "success";
488
+ } else if (Object.keys(e.params).length > 0) {
489
+ status = "success";
490
+ }
491
+
492
+ // Get subtitle
493
+ const parts = [];
494
+ const paramCount = Object.keys(e.params).length;
495
+ if (paramCount > 0) {
496
+ parts.push(`${paramCount} param${paramCount !== 1 ? "s" : ""}`);
497
+ }
498
+ if (e.timeSincePrevious !== undefined && e.timeSincePrevious > 0) {
499
+ if (e.timeSincePrevious < 1000) {
500
+ parts.push(`${e.timeSincePrevious}ms`);
501
+ } else {
502
+ parts.push(`${(e.timeSincePrevious / 1000).toFixed(1)}s`);
503
+ }
504
+ }
505
+ if (e.previousPathname && e.previousPathname !== e.pathname) {
506
+ parts.push(`from ${e.previousPathname}`);
507
+ }
508
+ return {
509
+ id: generateEventId("route"),
510
+ source: "route",
511
+ timestamp: e.timestamp,
512
+ title: e.pathname || "/",
513
+ subtitle: parts.join(" · ") || "navigation",
514
+ status,
515
+ originalEvent: event
516
+ };
517
+ }
518
+
519
+ // ============================================================================
520
+ // Main Auto-Discovery Function
521
+ // ============================================================================
522
+
523
+ /**
524
+ * Automatically discovers which event source packages are installed.
525
+ *
526
+ * This function attempts to load event stores from known dev tool packages.
527
+ * If a package is installed, its event source will be available.
528
+ * If a package is not installed, it will be silently skipped.
529
+ *
530
+ * @returns Discovery result with all available sources
531
+ *
532
+ * @example
533
+ * ```tsx
534
+ * const { sources, availableEventSources } = autoDiscoverEventSources();
535
+ *
536
+ * // sources contains all available event source configs
537
+ * // availableEventSources contains the Set of EventSource types available
538
+ * ```
539
+ */
540
+ export function autoDiscoverEventSources() {
541
+ const sources = [];
542
+ const availableEventSources = new Set();
543
+
544
+ // Try to load each source
545
+ const loaders = [tryLoadStorageSource, tryLoadReduxSource, tryLoadNetworkSource, tryLoadReactQuerySource, tryLoadRouteEventsSource];
546
+ for (const loader of loaders) {
547
+ const source = loader();
548
+ if (source && source.available) {
549
+ sources.push(source);
550
+ source.eventSources.forEach(es => availableEventSources.add(es));
551
+ }
552
+ }
553
+ return {
554
+ sources,
555
+ availableEventSources
556
+ };
557
+ }
558
+
559
+ /**
560
+ * Get display configuration for an event source.
561
+ * Returns config even for unavailable sources (for consistent UI).
562
+ */
563
+ export function getSourceDisplayConfig(source) {
564
+ const configs = {
565
+ "storage-async": {
566
+ label: "Storage",
567
+ color: "#8B5CF6",
568
+ icon: "server-outline"
569
+ },
570
+ "storage-mmkv": {
571
+ label: "MMKV",
572
+ color: "#F59E0B",
573
+ icon: "flash-outline"
574
+ },
575
+ redux: {
576
+ label: "Redux",
577
+ color: "#3B82F6",
578
+ icon: "git-branch-outline"
579
+ },
580
+ network: {
581
+ label: "Network",
582
+ color: "#10B981",
583
+ icon: "globe-outline"
584
+ },
585
+ "react-query": {
586
+ label: "Query",
587
+ color: "#EC4899",
588
+ icon: "sync-outline"
589
+ },
590
+ "react-query-query": {
591
+ label: "Query",
592
+ color: "#EC4899",
593
+ icon: "sync-outline"
594
+ },
595
+ "react-query-mutation": {
596
+ label: "Mutation",
597
+ color: "#F97316",
598
+ icon: "flash-outline"
599
+ },
600
+ route: {
601
+ label: "Route",
602
+ color: "#06B6D4",
603
+ icon: "navigate-outline"
604
+ }
605
+ };
606
+ return configs[source] || {
607
+ label: source,
608
+ color: "#6B7280",
609
+ icon: "help-outline"
610
+ };
611
+ }
612
+
613
+ // Cache for discovered sources (singleton)
614
+ let cachedDiscovery = null;
615
+
616
+ /**
617
+ * Get cached discovery result, or run discovery if not cached.
618
+ * Use this for performance - avoids repeated require() calls.
619
+ */
620
+ export function getCachedDiscovery() {
621
+ if (!cachedDiscovery) {
622
+ cachedDiscovery = autoDiscoverEventSources();
623
+ }
624
+ return cachedDiscovery;
625
+ }
626
+
627
+ /**
628
+ * Clear the discovery cache (useful for testing or hot reload).
629
+ */
630
+ export function clearDiscoveryCache() {
631
+ cachedDiscovery = null;
632
+ }
633
+ //# sourceMappingURL=autoDiscoverEventSources.js.map
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * Badge Selection Storage
5
+ *
6
+ * Utilities for persisting and restoring the enabled event source badges.
7
+ * Uses the same storage patterns as other packages (React Query, Network, etc.)
8
+ */
9
+
10
+ import { persistentStorage, devToolsStorageKeys } from "@buoy-gg/shared-ui";
11
+ /**
12
+ * Save the enabled sources to persistent storage
13
+ */
14
+ export async function saveEnabledSources(sources) {
15
+ try {
16
+ const key = devToolsStorageKeys.events.enabledSources();
17
+ await persistentStorage.setItem(key, JSON.stringify(sources));
18
+ } catch {
19
+ // Silently fail - persistence is optional
20
+ }
21
+ }
22
+
23
+ /**
24
+ * Load the enabled sources from persistent storage
25
+ * Returns null if no saved state exists
26
+ */
27
+ export async function loadEnabledSources() {
28
+ try {
29
+ const key = devToolsStorageKeys.events.enabledSources();
30
+ const value = await persistentStorage.getItem(key);
31
+ if (value && value !== "") {
32
+ return JSON.parse(value);
33
+ }
34
+ return null;
35
+ } catch {
36
+ // Silently fail - return null to use defaults
37
+ return null;
38
+ }
39
+ }
40
+
41
+ /**
42
+ * Clear the saved enabled sources
43
+ */
44
+ export async function clearEnabledSources() {
45
+ try {
46
+ const key = devToolsStorageKeys.events.enabledSources();
47
+ await persistentStorage.removeItem(key);
48
+ } catch {
49
+ // Silently fail
50
+ }
51
+ }
52
+ //# sourceMappingURL=badgeSelectionStorage.js.map