@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,366 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * UnifiedEventDetail
5
+ *
6
+ * Detail view for a single unified event.
7
+ * Uses shared detail components from other packages when available,
8
+ * falls back to generic DataViewer when packages aren't installed.
9
+ */
10
+
11
+ import { View, Text, StyleSheet, ScrollView } from "react-native";
12
+ import { memo, useMemo } from "react";
13
+ import { buoyColors, formatRelativeTime, copyToClipboard, parseValue } from "@buoy-gg/shared-ui";
14
+ import { DataViewer } from "@buoy-gg/shared-ui/dataViewer";
15
+ import { ReactQueryEventDetail } from "./ReactQueryEventDetail";
16
+
17
+ // ============================================================================
18
+ // Optional Component Loading
19
+ // ============================================================================
20
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
21
+ function tryLoadOptionalDetailComponents() {
22
+ const components = {
23
+ StorageEventDetailContent: null,
24
+ ReduxActionDetailContent: null,
25
+ NetworkEventDetailView: null
26
+ };
27
+
28
+ // Try to load storage detail component
29
+ try {
30
+ // @ts-ignore - Dynamic import that may not exist
31
+ const storage = require("@buoy-gg/storage");
32
+ components.StorageEventDetailContent = storage.StorageEventDetailContent;
33
+ } catch {
34
+ // Optional dependency not installed
35
+ }
36
+
37
+ // Try to load redux detail component
38
+ try {
39
+ // @ts-ignore - Dynamic import that may not exist
40
+ const redux = require("@buoy-gg/redux");
41
+ components.ReduxActionDetailContent = redux.ReduxActionDetailContent;
42
+ } catch {
43
+ // Optional dependency not installed
44
+ }
45
+
46
+ // Try to load network detail component
47
+ try {
48
+ // @ts-ignore - Dynamic import that may not exist
49
+ const network = require("@buoy-gg/network");
50
+ components.NetworkEventDetailView = network.NetworkEventDetailView;
51
+ } catch {
52
+ // Optional dependency not installed
53
+ }
54
+ return components;
55
+ }
56
+
57
+ // Cache loaded components
58
+ const optionalComponents = tryLoadOptionalDetailComponents();
59
+
60
+ // ============================================================================
61
+ // Configuration
62
+ // ============================================================================
63
+
64
+ /**
65
+ * Source configuration for display
66
+ */
67
+ const SOURCE_CONFIG = {
68
+ "storage-async": {
69
+ label: "AsyncStorage",
70
+ color: "#8B5CF6"
71
+ },
72
+ "storage-mmkv": {
73
+ label: "MMKV",
74
+ color: "#F59E0B"
75
+ },
76
+ redux: {
77
+ label: "Redux",
78
+ color: "#3B82F6"
79
+ },
80
+ network: {
81
+ label: "Network",
82
+ color: "#10B981"
83
+ },
84
+ "react-query": {
85
+ label: "React Query",
86
+ color: "#EC4899"
87
+ },
88
+ "react-query-query": {
89
+ label: "Query",
90
+ color: "#EC4899"
91
+ },
92
+ "react-query-mutation": {
93
+ label: "Mutation",
94
+ color: "#F97316"
95
+ },
96
+ route: {
97
+ label: "Route",
98
+ color: "#06B6D4"
99
+ }
100
+ };
101
+
102
+ /**
103
+ * Check if an event is a storage event
104
+ */
105
+ function isStorageEvent(source) {
106
+ return source === "storage-async" || source === "storage-mmkv";
107
+ }
108
+
109
+ /**
110
+ * Get value type from a value
111
+ */
112
+ function getValueType(value) {
113
+ const parsed = parseValue(value);
114
+ if (parsed === null) return "null";
115
+ if (parsed === undefined) return "undefined";
116
+ if (Array.isArray(parsed)) return "array";
117
+ if (typeof parsed === "boolean") return "boolean";
118
+ if (typeof parsed === "number") return "number";
119
+ if (typeof parsed === "string") return "string";
120
+ if (typeof parsed === "object") return "object";
121
+ return "undefined";
122
+ }
123
+
124
+ // ============================================================================
125
+ // Component
126
+ // ============================================================================
127
+
128
+ export const UnifiedEventDetail = /*#__PURE__*/memo(function UnifiedEventDetail({
129
+ event,
130
+ onBack
131
+ }) {
132
+ const sourceConfig = SOURCE_CONFIG[event.source];
133
+ const timestamp = new Date(event.timestamp);
134
+
135
+ // For storage events, create a conversation object to use with StorageEventDetailContent
136
+ const storageConversation = useMemo(() => {
137
+ if (!isStorageEvent(event.source)) return null;
138
+ if (!optionalComponents.StorageEventDetailContent) return null;
139
+ const originalEvent = event.originalEvent;
140
+
141
+ // Create a conversation with a single event for the detail view
142
+ return {
143
+ key: originalEvent.data?.key || "unknown",
144
+ lastEvent: originalEvent,
145
+ events: [originalEvent],
146
+ totalOperations: 1,
147
+ currentValue: originalEvent.data?.value,
148
+ valueType: getValueType(originalEvent.data?.value),
149
+ storageTypes: new Set([originalEvent.storageType || "async"])
150
+ };
151
+ }, [event]);
152
+
153
+ // For storage events, use the shared StorageEventDetailContent if available
154
+ if (storageConversation && optionalComponents.StorageEventDetailContent) {
155
+ const {
156
+ StorageEventDetailContent
157
+ } = optionalComponents;
158
+ return /*#__PURE__*/_jsx(View, {
159
+ style: styles.container,
160
+ children: /*#__PURE__*/_jsx(StorageEventDetailContent, {
161
+ conversation: storageConversation,
162
+ selectedEventIndex: 0,
163
+ onEventIndexChange: () => {},
164
+ disableInternalFooter: true
165
+ })
166
+ });
167
+ }
168
+
169
+ // For Redux events, use the shared ReduxActionDetailContent if available
170
+ if (event.source === "redux" && optionalComponents.ReduxActionDetailContent) {
171
+ const {
172
+ ReduxActionDetailContent
173
+ } = optionalComponents;
174
+ const reduxAction = event.originalEvent;
175
+ return /*#__PURE__*/_jsx(View, {
176
+ style: styles.container,
177
+ children: /*#__PURE__*/_jsx(ReduxActionDetailContent, {
178
+ action: reduxAction,
179
+ actions: [reduxAction],
180
+ selectedIndex: 0,
181
+ onIndexChange: () => {},
182
+ disableInternalFooter: true
183
+ })
184
+ });
185
+ }
186
+
187
+ // For network events, use the shared NetworkEventDetailView if available
188
+ if (event.source === "network" && optionalComponents.NetworkEventDetailView) {
189
+ const {
190
+ NetworkEventDetailView
191
+ } = optionalComponents;
192
+ const networkEvent = event.originalEvent;
193
+ return /*#__PURE__*/_jsx(View, {
194
+ style: styles.container,
195
+ children: /*#__PURE__*/_jsx(ScrollView, {
196
+ style: styles.content,
197
+ children: /*#__PURE__*/_jsx(NetworkEventDetailView, {
198
+ event: networkEvent
199
+ })
200
+ })
201
+ });
202
+ }
203
+
204
+ // For React Query events, use the specialized ReactQueryEventDetail
205
+ if (event.source === "react-query" || event.source === "react-query-query" || event.source === "react-query-mutation") {
206
+ return /*#__PURE__*/_jsx(View, {
207
+ style: styles.container,
208
+ children: /*#__PURE__*/_jsx(ReactQueryEventDetail, {
209
+ event: event
210
+ })
211
+ });
212
+ }
213
+
214
+ // Route events expand in-place in the list, so they shouldn't reach this detail view
215
+ // If they do somehow, fall through to the generic view
216
+
217
+ // For all other events (or when specific components aren't available), show the generic detail view
218
+ const getEventData = () => {
219
+ return event.originalEvent;
220
+ };
221
+ const handleCopy = async () => {
222
+ await copyToClipboard({
223
+ source: event.source,
224
+ timestamp: timestamp.toISOString(),
225
+ title: event.title,
226
+ subtitle: event.subtitle,
227
+ data: getEventData()
228
+ });
229
+ };
230
+ return /*#__PURE__*/_jsx(View, {
231
+ style: styles.container,
232
+ children: /*#__PURE__*/_jsxs(ScrollView, {
233
+ style: styles.content,
234
+ contentContainerStyle: styles.contentContainer,
235
+ children: [/*#__PURE__*/_jsx(View, {
236
+ style: styles.sourceBadgeRow,
237
+ children: /*#__PURE__*/_jsxs(View, {
238
+ style: [styles.sourceBadge, {
239
+ backgroundColor: sourceConfig.color + "20"
240
+ }],
241
+ children: [/*#__PURE__*/_jsx(View, {
242
+ style: [styles.sourceDot, {
243
+ backgroundColor: sourceConfig.color
244
+ }]
245
+ }), /*#__PURE__*/_jsx(Text, {
246
+ style: [styles.sourceLabel, {
247
+ color: sourceConfig.color
248
+ }],
249
+ children: sourceConfig.label
250
+ })]
251
+ })
252
+ }), /*#__PURE__*/_jsx(Text, {
253
+ style: styles.title,
254
+ children: event.title
255
+ }), /*#__PURE__*/_jsx(Text, {
256
+ style: styles.subtitle,
257
+ children: event.subtitle
258
+ }), /*#__PURE__*/_jsxs(View, {
259
+ style: styles.timestampRow,
260
+ children: [/*#__PURE__*/_jsx(Text, {
261
+ style: styles.timestampLabel,
262
+ children: "Timestamp"
263
+ }), /*#__PURE__*/_jsxs(Text, {
264
+ style: styles.timestampValue,
265
+ children: [timestamp.toLocaleTimeString(), " (", formatRelativeTime(timestamp), ")"]
266
+ })]
267
+ }), /*#__PURE__*/_jsxs(View, {
268
+ style: styles.dataSection,
269
+ children: [/*#__PURE__*/_jsx(Text, {
270
+ style: styles.sectionLabel,
271
+ children: "Event Data"
272
+ }), /*#__PURE__*/_jsx(View, {
273
+ style: styles.dataContainer,
274
+ children: /*#__PURE__*/_jsx(DataViewer, {
275
+ data: getEventData(),
276
+ title: "",
277
+ showTypeFilter: false
278
+ })
279
+ })]
280
+ })]
281
+ })
282
+ });
283
+ });
284
+ const styles = StyleSheet.create({
285
+ container: {
286
+ flex: 1,
287
+ backgroundColor: buoyColors.base
288
+ },
289
+ content: {
290
+ flex: 1
291
+ },
292
+ contentContainer: {
293
+ padding: 16
294
+ },
295
+ sourceBadgeRow: {
296
+ flexDirection: "row",
297
+ marginBottom: 12
298
+ },
299
+ sourceBadge: {
300
+ flexDirection: "row",
301
+ alignItems: "center",
302
+ paddingHorizontal: 10,
303
+ paddingVertical: 6,
304
+ borderRadius: 12,
305
+ gap: 6
306
+ },
307
+ sourceDot: {
308
+ width: 6,
309
+ height: 6,
310
+ borderRadius: 3
311
+ },
312
+ sourceLabel: {
313
+ fontSize: 12,
314
+ fontWeight: "600"
315
+ },
316
+ title: {
317
+ fontSize: 24,
318
+ fontWeight: "700",
319
+ color: buoyColors.text,
320
+ marginBottom: 4
321
+ },
322
+ subtitle: {
323
+ fontSize: 16,
324
+ color: buoyColors.textMuted,
325
+ marginBottom: 16
326
+ },
327
+ timestampRow: {
328
+ flexDirection: "row",
329
+ justifyContent: "space-between",
330
+ alignItems: "center",
331
+ paddingVertical: 12,
332
+ borderTopWidth: 1,
333
+ borderTopColor: buoyColors.border,
334
+ borderBottomWidth: 1,
335
+ borderBottomColor: buoyColors.border,
336
+ marginBottom: 16
337
+ },
338
+ timestampLabel: {
339
+ fontSize: 14,
340
+ color: buoyColors.textMuted
341
+ },
342
+ timestampValue: {
343
+ fontSize: 14,
344
+ color: buoyColors.text,
345
+ fontFamily: "monospace"
346
+ },
347
+ dataSection: {
348
+ marginTop: 8
349
+ },
350
+ sectionLabel: {
351
+ fontSize: 12,
352
+ fontWeight: "600",
353
+ color: buoyColors.textMuted,
354
+ textTransform: "uppercase",
355
+ letterSpacing: 0.5,
356
+ marginBottom: 8
357
+ },
358
+ dataContainer: {
359
+ backgroundColor: buoyColors.card,
360
+ borderRadius: 8,
361
+ borderWidth: 1,
362
+ borderColor: buoyColors.border,
363
+ overflow: "hidden"
364
+ }
365
+ });
366
+ //# sourceMappingURL=UnifiedEventDetail.js.map
@@ -0,0 +1,109 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * UnifiedEventFilters
5
+ *
6
+ * Filter bar showing toggleable badges for each available event source.
7
+ * Badges are sorted: enabled first, disabled last.
8
+ * Toggling a badge enables/disables event listening for that source.
9
+ */
10
+
11
+ import { View, Text, TouchableOpacity, StyleSheet, ScrollView } from "react-native";
12
+ import { memo } from "react";
13
+ import { buoyColors } from "@buoy-gg/shared-ui";
14
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
15
+ export const UnifiedEventFilters = /*#__PURE__*/memo(function UnifiedEventFilters({
16
+ availableSources,
17
+ onToggleSource,
18
+ totalCount,
19
+ filteredCount
20
+ }) {
21
+ if (availableSources.length === 0) {
22
+ return null;
23
+ }
24
+ return /*#__PURE__*/_jsxs(View, {
25
+ style: styles.container,
26
+ children: [/*#__PURE__*/_jsx(ScrollView, {
27
+ horizontal: true,
28
+ showsHorizontalScrollIndicator: false,
29
+ contentContainerStyle: styles.badgesRow,
30
+ children: availableSources.map(source => {
31
+ const isEnabled = source.enabled !== false;
32
+ return /*#__PURE__*/_jsxs(TouchableOpacity, {
33
+ style: [styles.badge, isEnabled ? {
34
+ backgroundColor: source.color + "20",
35
+ borderColor: source.color + "60"
36
+ } : styles.badgeDisabled],
37
+ onPress: () => onToggleSource(source.source),
38
+ activeOpacity: 0.7,
39
+ children: [/*#__PURE__*/_jsx(View, {
40
+ style: [styles.dot, {
41
+ backgroundColor: isEnabled ? source.color : buoyColors.textMuted + "60"
42
+ }]
43
+ }), /*#__PURE__*/_jsx(Text, {
44
+ style: [styles.badgeLabel, {
45
+ color: isEnabled ? source.color : buoyColors.textMuted + "80"
46
+ }],
47
+ children: source.label
48
+ }), isEnabled && source.count > 0 && /*#__PURE__*/_jsx(Text, {
49
+ style: [styles.badgeCount, {
50
+ color: source.color
51
+ }],
52
+ children: source.count
53
+ })]
54
+ }, source.source);
55
+ })
56
+ }), filteredCount < totalCount && /*#__PURE__*/_jsxs(Text, {
57
+ style: styles.filterInfo,
58
+ children: ["Showing ", filteredCount, " of ", totalCount]
59
+ })]
60
+ });
61
+ });
62
+ const styles = StyleSheet.create({
63
+ container: {
64
+ paddingVertical: 8,
65
+ backgroundColor: buoyColors.base,
66
+ borderBottomWidth: 1,
67
+ borderBottomColor: buoyColors.border
68
+ },
69
+ badgesRow: {
70
+ flexDirection: "row",
71
+ gap: 8,
72
+ paddingHorizontal: 12
73
+ },
74
+ badge: {
75
+ flexDirection: "row",
76
+ alignItems: "center",
77
+ paddingHorizontal: 10,
78
+ paddingVertical: 6,
79
+ borderRadius: 16,
80
+ borderWidth: 1,
81
+ gap: 6
82
+ },
83
+ badgeDisabled: {
84
+ backgroundColor: buoyColors.card,
85
+ borderColor: buoyColors.border,
86
+ opacity: 0.6
87
+ },
88
+ dot: {
89
+ width: 6,
90
+ height: 6,
91
+ borderRadius: 3
92
+ },
93
+ badgeLabel: {
94
+ fontSize: 12,
95
+ fontWeight: "600"
96
+ },
97
+ badgeCount: {
98
+ fontSize: 11,
99
+ fontWeight: "500",
100
+ opacity: 0.8
101
+ },
102
+ filterInfo: {
103
+ marginTop: 6,
104
+ fontSize: 11,
105
+ color: buoyColors.textMuted,
106
+ textAlign: "center"
107
+ }
108
+ });
109
+ //# sourceMappingURL=UnifiedEventFilters.js.map