@buoy-gg/react-query 7.0.33 → 7.0.34

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 (29) hide show
  1. package/lib/commonjs/react-query/components/modals/MutationBrowserFooter.js +7 -19
  2. package/lib/commonjs/react-query/components/modals/QueryBrowserFooter.js +7 -19
  3. package/lib/commonjs/react-query/components/modals/ReactQueryModalHeader.js +23 -71
  4. package/lib/commonjs/react-query/components/query-browser/MutationStatusCount.js +51 -87
  5. package/lib/commonjs/react-query/components/query-browser/QueryBrowser.js +2 -11
  6. package/lib/commonjs/react-query/components/query-browser/QueryStatusCount.js +66 -112
  7. package/lib/commonjs/react-query/components/query-browser/StorageStatusCount.js +22 -67
  8. package/lib/commonjs/react-query/stores/reactQueryEventStore.js +13 -22
  9. package/lib/commonjs/react-query/sync/snapshotProvider.js +17 -62
  10. package/lib/module/react-query/components/modals/MutationBrowserFooter.js +8 -20
  11. package/lib/module/react-query/components/modals/QueryBrowserFooter.js +8 -20
  12. package/lib/module/react-query/components/modals/ReactQueryModalHeader.js +25 -73
  13. package/lib/module/react-query/components/query-browser/MutationStatusCount.js +51 -87
  14. package/lib/module/react-query/components/query-browser/QueryBrowser.js +3 -12
  15. package/lib/module/react-query/components/query-browser/QueryStatusCount.js +66 -112
  16. package/lib/module/react-query/components/query-browser/StorageStatusCount.js +22 -67
  17. package/lib/module/react-query/stores/reactQueryEventStore.js +13 -22
  18. package/lib/module/react-query/sync/snapshotProvider.js +18 -63
  19. package/lib/typescript/react-query/components/modals/MutationBrowserFooter.d.ts.map +1 -1
  20. package/lib/typescript/react-query/components/modals/QueryBrowserFooter.d.ts.map +1 -1
  21. package/lib/typescript/react-query/components/modals/ReactQueryModalHeader.d.ts.map +1 -1
  22. package/lib/typescript/react-query/components/query-browser/MutationStatusCount.d.ts.map +1 -1
  23. package/lib/typescript/react-query/components/query-browser/QueryBrowser.d.ts.map +1 -1
  24. package/lib/typescript/react-query/components/query-browser/QueryStatusCount.d.ts.map +1 -1
  25. package/lib/typescript/react-query/components/query-browser/StorageStatusCount.d.ts.map +1 -1
  26. package/lib/typescript/react-query/stores/reactQueryEventStore.d.ts +3 -8
  27. package/lib/typescript/react-query/stores/reactQueryEventStore.d.ts.map +1 -1
  28. package/lib/typescript/react-query/sync/snapshotProvider.d.ts.map +1 -1
  29. package/package.json +3 -3
@@ -1,9 +1,8 @@
1
1
  "use strict";
2
2
 
3
- import { View, StyleSheet, ScrollView } from "react-native";
3
+ import { ChipStrip, useChipTap } from "@buoy-gg/shared-ui";
4
4
  import QueryStatus from "./QueryStatus";
5
5
  import { useMutationStatusCounts } from "../../hooks/useQueryStatusCounts";
6
- import { useRef, useState } from "react";
7
6
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
8
7
  /**
9
8
  * Horizontal status filter bar tailored for mutations. Integrates scroll detection to avoid
@@ -20,96 +19,61 @@ const MutationStatusCount = ({
20
19
  error,
21
20
  paused
22
21
  } = useMutationStatusCounts();
23
- const [isScrolling, setIsScrolling] = useState(false);
24
- const touchStartX = useRef(0);
25
- const touchStartY = useRef(0);
22
+ const {
23
+ scrollProps,
24
+ onTouchStart: handleTouchStart,
25
+ isTap
26
+ } = useChipTap();
26
27
  const handleFilterClick = (filter, event) => {
27
- if (event) {
28
- const dx = Math.abs(event.nativeEvent.pageX - touchStartX.current);
29
- const dy = Math.abs(event.nativeEvent.pageY - touchStartY.current);
30
- if (dx > 5 || dy > 5 || isScrolling) {
31
- return;
32
- }
33
- }
28
+ if (!isTap(event)) return;
34
29
  if (onFilterChange) {
35
30
  onFilterChange(activeFilter === filter ? null : filter);
36
31
  }
37
32
  };
38
- const handleTouchStart = event => {
39
- touchStartX.current = event.nativeEvent.pageX;
40
- touchStartY.current = event.nativeEvent.pageY;
41
- };
42
- return /*#__PURE__*/_jsx(View, {
43
- style: styles.mutationStatusContainer,
44
- children: /*#__PURE__*/_jsxs(ScrollView, {
45
- "sentry-label": "ignore devtools mutation status count scroll",
46
- horizontal: true,
47
- showsHorizontalScrollIndicator: false,
48
- style: styles.scrollView,
49
- contentContainerStyle: styles.scrollContent,
50
- onScrollBeginDrag: () => setIsScrolling(true),
51
- onScrollEndDrag: () => setTimeout(() => setIsScrolling(false), 300),
52
- onMomentumScrollBegin: () => setIsScrolling(true),
53
- onMomentumScrollEnd: () => setTimeout(() => setIsScrolling(false), 300),
54
- children: [/*#__PURE__*/_jsx(QueryStatus, {
55
- label: "Pending",
56
- color: "blue",
57
- count: pending,
58
- isActive: activeFilter === "pending",
59
- onPress: event => handleFilterClick("pending", event),
60
- onTouchStart: handleTouchStart,
61
- testID: "buoy-rq-mstatus-pending",
62
- showLabel: true,
63
- size: size
64
- }), /*#__PURE__*/_jsx(QueryStatus, {
65
- label: "Success",
66
- color: "green",
67
- count: success,
68
- isActive: activeFilter === "success",
69
- onPress: event => handleFilterClick("success", event),
70
- onTouchStart: handleTouchStart,
71
- testID: "buoy-rq-mstatus-success",
72
- showLabel: true,
73
- size: size
74
- }), /*#__PURE__*/_jsx(QueryStatus, {
75
- label: "Error",
76
- color: "red",
77
- count: error,
78
- isActive: activeFilter === "error",
79
- onPress: event => handleFilterClick("error", event),
80
- onTouchStart: handleTouchStart,
81
- testID: "buoy-rq-mstatus-error",
82
- showLabel: true,
83
- size: size
84
- }), /*#__PURE__*/_jsx(QueryStatus, {
85
- label: "Paused",
86
- color: "purple",
87
- count: paused,
88
- isActive: activeFilter === "paused",
89
- onPress: event => handleFilterClick("paused", event),
90
- onTouchStart: handleTouchStart,
91
- testID: "buoy-rq-mstatus-paused",
92
- showLabel: true,
93
- size: size
94
- })]
95
- })
33
+ return /*#__PURE__*/_jsxs(ChipStrip, {
34
+ scrollProps: scrollProps,
35
+ sentryLabel: "ignore devtools mutation status count scroll",
36
+ children: [/*#__PURE__*/_jsx(QueryStatus, {
37
+ label: "Pending",
38
+ color: "blue",
39
+ count: pending,
40
+ isActive: activeFilter === "pending",
41
+ onPress: event => handleFilterClick("pending", event),
42
+ onTouchStart: handleTouchStart,
43
+ testID: "buoy-rq-mstatus-pending",
44
+ showLabel: true,
45
+ size: size
46
+ }), /*#__PURE__*/_jsx(QueryStatus, {
47
+ label: "Success",
48
+ color: "green",
49
+ count: success,
50
+ isActive: activeFilter === "success",
51
+ onPress: event => handleFilterClick("success", event),
52
+ onTouchStart: handleTouchStart,
53
+ testID: "buoy-rq-mstatus-success",
54
+ showLabel: true,
55
+ size: size
56
+ }), /*#__PURE__*/_jsx(QueryStatus, {
57
+ label: "Error",
58
+ color: "red",
59
+ count: error,
60
+ isActive: activeFilter === "error",
61
+ onPress: event => handleFilterClick("error", event),
62
+ onTouchStart: handleTouchStart,
63
+ testID: "buoy-rq-mstatus-error",
64
+ showLabel: true,
65
+ size: size
66
+ }), /*#__PURE__*/_jsx(QueryStatus, {
67
+ label: "Paused",
68
+ color: "purple",
69
+ count: paused,
70
+ isActive: activeFilter === "paused",
71
+ onPress: event => handleFilterClick("paused", event),
72
+ onTouchStart: handleTouchStart,
73
+ testID: "buoy-rq-mstatus-paused",
74
+ showLabel: true,
75
+ size: size
76
+ })]
96
77
  });
97
78
  };
98
- const styles = StyleSheet.create({
99
- mutationStatusContainer: {
100
- flex: 1,
101
- minWidth: 0
102
- },
103
- scrollView: {
104
- flex: 1
105
- },
106
- scrollContent: {
107
- flexDirection: "row",
108
- alignItems: "center",
109
- gap: 8,
110
- paddingHorizontal: 4,
111
- paddingVertical: 4,
112
- flexGrow: 1
113
- }
114
- });
115
79
  export default MutationStatusCount;
@@ -5,7 +5,7 @@ import { StyleSheet, FlatList } from "react-native";
5
5
  import QueryRow from "./QueryRow";
6
6
  import useAllQueries from "../../hooks/useAllQueries";
7
7
  import { getQueryStatusLabel } from "../../utils/getQueryStatusLabel";
8
- import { night, ToolEmptyState } from "@buoy-gg/shared-ui";
8
+ import { night, ToolEmptyState, EVENT_LIST_PRESET } from "@buoy-gg/shared-ui";
9
9
  import { jsx as _jsx } from "react/jsx-runtime";
10
10
  /**
11
11
  * Scrollable list view of cached queries with filtering support and selection handling.
@@ -126,17 +126,8 @@ export default function QueryBrowser({
126
126
  isSelected: selectedQuery?.queryHash === query.queryHash,
127
127
  onSelect: handleQuerySelect
128
128
  }),
129
- showsVerticalScrollIndicator: true
130
- // Clipped cells fail Detox's hittability check even when they are on
131
- // screen, so e2e bundles (Metro with EXPO_PUBLIC_E2E=1) turn clipping
132
- // off. Inlined at bundle time; a non-inlining bundler keeps prod
133
- // behavior.
134
- ,
135
- removeClippedSubviews: !(typeof process !== "undefined" && process.env?.EXPO_PUBLIC_E2E),
136
- initialNumToRender: 12,
137
- maxToRenderPerBatch: 8,
138
- windowSize: 5,
139
- updateCellsBatchingPeriod: 50
129
+ showsVerticalScrollIndicator: true,
130
+ ...EVENT_LIST_PRESET
140
131
  })
141
132
  );
142
133
  }
@@ -1,7 +1,6 @@
1
1
  "use strict";
2
2
 
3
- import { useRef, useState } from "react";
4
- import { View, StyleSheet, ScrollView } from "react-native";
3
+ import { ChipStrip, useChipTap } from "@buoy-gg/shared-ui";
5
4
  import QueryStatus from "./QueryStatus";
6
5
  import useQueryStatusCounts from "../../hooks/useQueryStatusCounts";
7
6
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
@@ -20,122 +19,77 @@ const QueryStatusCount = ({
20
19
  paused,
21
20
  inactive
22
21
  } = useQueryStatusCounts();
23
-
24
- // Scroll state management like ChipTabs
25
- const [isScrolling, setIsScrolling] = useState(false);
26
- const touchStartX = useRef(0);
27
- const touchStartY = useRef(0);
22
+ const {
23
+ scrollProps,
24
+ onTouchStart: handleTouchStart,
25
+ isTap
26
+ } = useChipTap();
28
27
  const handleFilterClick = (filter, event) => {
29
- if (event) {
30
- // Calculate distance moved during touch (like ChipTabs)
31
- const dx = Math.abs(event.nativeEvent.pageX - touchStartX.current);
32
- const dy = Math.abs(event.nativeEvent.pageY - touchStartY.current);
33
-
34
- // If touch moved more than 5px in any direction, it's a swipe, not a tap
35
- if (dx > 5 || dy > 5 || isScrolling) {
36
- return; // Don't trigger filter change
37
- }
38
- }
28
+ if (!isTap(event)) return;
39
29
  if (onFilterChange) {
40
30
  // Toggle filter: if already active, clear it; otherwise set it
41
31
  onFilterChange(activeFilter === filter ? null : filter);
42
32
  }
43
33
  };
44
- const handleTouchStart = event => {
45
- touchStartX.current = event.nativeEvent.pageX;
46
- touchStartY.current = event.nativeEvent.pageY;
47
- };
48
- return /*#__PURE__*/_jsx(View, {
49
- style: styles.queryStatusContainer,
50
- children: /*#__PURE__*/_jsxs(ScrollView, {
51
- "sentry-label": "ignore devtools query status count scroll",
52
- horizontal: true,
53
- showsHorizontalScrollIndicator: false,
54
- style: styles.scrollView,
55
- contentContainerStyle: styles.scrollContent,
56
- onScrollBeginDrag: () => setIsScrolling(true),
57
- onScrollEndDrag: () => setTimeout(() => setIsScrolling(false), 300),
58
- onMomentumScrollBegin: () => setIsScrolling(true),
59
- onMomentumScrollEnd: () => setTimeout(() => setIsScrolling(false), 300),
60
- children: [/*#__PURE__*/_jsx(QueryStatus, {
61
- label: "Fresh",
62
- color: "green",
63
- count: fresh,
64
- isActive: activeFilter === "fresh",
65
- onPress: event => handleFilterClick("fresh", event),
66
- onTouchStart: handleTouchStart,
67
- testID: "buoy-rq-status-fresh",
68
- showLabel: true // Always show labels now
69
- ,
70
- size: size
71
- }), /*#__PURE__*/_jsx(QueryStatus, {
72
- label: "Loading",
73
- color: "blue",
74
- count: fetching,
75
- isActive: activeFilter === "fetching",
76
- onPress: event => handleFilterClick("fetching", event),
77
- onTouchStart: handleTouchStart,
78
- testID: "buoy-rq-status-fetching",
79
- showLabel: true // Always show labels now
80
- ,
81
- size: size
82
- }), /*#__PURE__*/_jsx(QueryStatus, {
83
- label: "Paused",
84
- color: "purple",
85
- count: paused,
86
- isActive: activeFilter === "paused",
87
- onPress: event => handleFilterClick("paused", event),
88
- onTouchStart: handleTouchStart,
89
- testID: "buoy-rq-status-paused",
90
- showLabel: true // Always show labels now
91
- ,
92
- size: size
93
- }), /*#__PURE__*/_jsx(QueryStatus, {
94
- label: "Stale",
95
- color: "yellow",
96
- count: stale,
97
- isActive: activeFilter === "stale",
98
- onPress: event => handleFilterClick("stale", event),
99
- onTouchStart: handleTouchStart,
100
- testID: "buoy-rq-status-stale",
101
- showLabel: true // Always show labels now
102
- ,
103
- size: size
104
- }), /*#__PURE__*/_jsx(QueryStatus, {
105
- label: "Idle",
106
- color: "gray",
107
- count: inactive,
108
- isActive: activeFilter === "inactive",
109
- onPress: event => handleFilterClick("inactive", event),
110
- onTouchStart: handleTouchStart,
111
- testID: "buoy-rq-status-inactive",
112
- showLabel: true // Always show labels now
113
- ,
114
- size: size
115
- })]
116
- })
34
+ return /*#__PURE__*/_jsxs(ChipStrip, {
35
+ scrollProps: scrollProps,
36
+ sentryLabel: "ignore devtools query status count scroll",
37
+ children: [/*#__PURE__*/_jsx(QueryStatus, {
38
+ label: "Fresh",
39
+ color: "green",
40
+ count: fresh,
41
+ isActive: activeFilter === "fresh",
42
+ onPress: event => handleFilterClick("fresh", event),
43
+ onTouchStart: handleTouchStart,
44
+ testID: "buoy-rq-status-fresh",
45
+ showLabel: true // Always show labels now
46
+ ,
47
+ size: size
48
+ }), /*#__PURE__*/_jsx(QueryStatus, {
49
+ label: "Loading",
50
+ color: "blue",
51
+ count: fetching,
52
+ isActive: activeFilter === "fetching",
53
+ onPress: event => handleFilterClick("fetching", event),
54
+ onTouchStart: handleTouchStart,
55
+ testID: "buoy-rq-status-fetching",
56
+ showLabel: true // Always show labels now
57
+ ,
58
+ size: size
59
+ }), /*#__PURE__*/_jsx(QueryStatus, {
60
+ label: "Paused",
61
+ color: "purple",
62
+ count: paused,
63
+ isActive: activeFilter === "paused",
64
+ onPress: event => handleFilterClick("paused", event),
65
+ onTouchStart: handleTouchStart,
66
+ testID: "buoy-rq-status-paused",
67
+ showLabel: true // Always show labels now
68
+ ,
69
+ size: size
70
+ }), /*#__PURE__*/_jsx(QueryStatus, {
71
+ label: "Stale",
72
+ color: "yellow",
73
+ count: stale,
74
+ isActive: activeFilter === "stale",
75
+ onPress: event => handleFilterClick("stale", event),
76
+ onTouchStart: handleTouchStart,
77
+ testID: "buoy-rq-status-stale",
78
+ showLabel: true // Always show labels now
79
+ ,
80
+ size: size
81
+ }), /*#__PURE__*/_jsx(QueryStatus, {
82
+ label: "Idle",
83
+ color: "gray",
84
+ count: inactive,
85
+ isActive: activeFilter === "inactive",
86
+ onPress: event => handleFilterClick("inactive", event),
87
+ onTouchStart: handleTouchStart,
88
+ testID: "buoy-rq-status-inactive",
89
+ showLabel: true // Always show labels now
90
+ ,
91
+ size: size
92
+ })]
117
93
  });
118
94
  };
119
- const styles = StyleSheet.create({
120
- queryStatusContainer: {
121
- // Container for ScrollView - take full width
122
- flex: 1,
123
- minWidth: 0
124
- },
125
- scrollView: {
126
- // ScrollView itself styles
127
- flex: 1
128
- },
129
- scrollContent: {
130
- // ScrollView content styles
131
- flexDirection: "row",
132
- alignItems: "center",
133
- gap: 8,
134
- // Spacing between chips
135
- paddingHorizontal: 4,
136
- // Small padding on ends
137
- paddingVertical: 4,
138
- flexGrow: 1 // Allow content to grow to fill available space
139
- }
140
- });
141
95
  export default QueryStatusCount;
@@ -1,7 +1,6 @@
1
1
  "use strict";
2
2
 
3
- import { useRef, useState } from "react";
4
- import { View, StyleSheet, ScrollView } from "react-native";
3
+ import { ChipStrip, useChipTap } from "@buoy-gg/shared-ui";
5
4
  import QueryStatus from "./QueryStatus";
6
5
  import { getStorageTypeLabel, getStorageTypeColor } from "../../utils/storageQueryUtils";
7
6
  import { jsx as _jsx } from "react/jsx-runtime";
@@ -19,21 +18,13 @@ const StorageStatusCount = ({
19
18
  onStorageTypesChange,
20
19
  counts
21
20
  }) => {
22
- // Scroll state management like QueryStatusCount
23
- const [isScrolling, setIsScrolling] = useState(false);
24
- const touchStartX = useRef(0);
25
- const touchStartY = useRef(0);
21
+ const {
22
+ scrollProps,
23
+ onTouchStart: handleTouchStart,
24
+ isTap
25
+ } = useChipTap();
26
26
  const handleStorageTypeToggle = (storageType, event) => {
27
- if (event) {
28
- // Calculate distance moved during touch (like QueryStatusCount)
29
- const dx = Math.abs(event.nativeEvent.pageX - touchStartX.current);
30
- const dy = Math.abs(event.nativeEvent.pageY - touchStartY.current);
31
-
32
- // If touch moved more than 5px in any direction, it's a swipe, not a tap
33
- if (dx > 5 || dy > 5 || isScrolling) {
34
- return; // Don't trigger filter change
35
- }
36
- }
27
+ if (!isTap(event)) return;
37
28
  if (onStorageTypesChange) {
38
29
  const newStorageTypes = new Set(activeStorageTypes);
39
30
  if (newStorageTypes.has(storageType)) {
@@ -44,58 +35,22 @@ const StorageStatusCount = ({
44
35
  onStorageTypesChange(newStorageTypes);
45
36
  }
46
37
  };
47
- const handleTouchStart = event => {
48
- touchStartX.current = event.nativeEvent.pageX;
49
- touchStartY.current = event.nativeEvent.pageY;
50
- };
51
- return /*#__PURE__*/_jsx(View, {
52
- style: styles.storageStatusContainer,
53
- children: /*#__PURE__*/_jsx(ScrollView, {
54
- "sentry-label": "ignore devtools storage status count scroll",
55
- horizontal: true,
56
- showsHorizontalScrollIndicator: false,
57
- style: styles.scrollView,
58
- contentContainerStyle: styles.scrollContent,
59
- onScrollBeginDrag: () => setIsScrolling(true),
60
- onScrollEndDrag: () => setTimeout(() => setIsScrolling(false), 300),
61
- onMomentumScrollBegin: () => setIsScrolling(true),
62
- onMomentumScrollEnd: () => setTimeout(() => setIsScrolling(false), 300),
63
- children: allStorageTypes.map(storageType => {
64
- const count = counts?.[storageType] ?? 0;
65
- return /*#__PURE__*/_jsx(QueryStatus, {
66
- label: getStorageTypeLabel(storageType),
67
- color: getStorageTypeColor(storageType),
68
- count: count // Show actual storage query counts
69
- ,
70
- isActive: activeStorageTypes.has(storageType),
71
- onPress: event => handleStorageTypeToggle(storageType, event),
72
- onTouchStart: handleTouchStart,
73
- showLabel: true
74
- }, storageType);
75
- })
38
+ return /*#__PURE__*/_jsx(ChipStrip, {
39
+ scrollProps: scrollProps,
40
+ sentryLabel: "ignore devtools storage status count scroll",
41
+ children: allStorageTypes.map(storageType => {
42
+ const count = counts?.[storageType] ?? 0;
43
+ return /*#__PURE__*/_jsx(QueryStatus, {
44
+ label: getStorageTypeLabel(storageType),
45
+ color: getStorageTypeColor(storageType),
46
+ count: count // Show actual storage query counts
47
+ ,
48
+ isActive: activeStorageTypes.has(storageType),
49
+ onPress: event => handleStorageTypeToggle(storageType, event),
50
+ onTouchStart: handleTouchStart,
51
+ showLabel: true
52
+ }, storageType);
76
53
  })
77
54
  });
78
55
  };
79
- const styles = StyleSheet.create({
80
- storageStatusContainer: {
81
- // Container for ScrollView - take full width
82
- flex: 1,
83
- minWidth: 0
84
- },
85
- scrollView: {
86
- // ScrollView itself styles
87
- flex: 1
88
- },
89
- scrollContent: {
90
- // ScrollView content styles
91
- flexDirection: "row",
92
- alignItems: "center",
93
- gap: 8,
94
- // Spacing between chips
95
- paddingHorizontal: 4,
96
- // Small padding on ends
97
- paddingVertical: 4,
98
- flexGrow: 1 // Allow content to grow to fill available space
99
- }
100
- });
101
56
  export default StorageStatusCount;
@@ -12,6 +12,7 @@
12
12
  * 3. The Events DevTools subscribes to these events
13
13
  */
14
14
 
15
+ import { ChangeLog } from "@buoy-gg/shared-ui";
15
16
  import { isStorageQuery } from "../utils/storageQueryUtils";
16
17
 
17
18
  /**
@@ -26,13 +27,15 @@ let eventIdCounter = 0;
26
27
  function generateEventId() {
27
28
  return `rq-${Date.now()}-${++eventIdCounter}`;
28
29
  }
29
- class ReactQueryEventStore {
30
- events = [];
31
- listeners = new Set();
30
+ class ReactQueryEventStore extends ChangeLog {
32
31
  queryClient = null;
33
32
  queryUnsubscribe = null;
34
33
  mutationUnsubscribe = null;
35
- maxEvents = 200;
34
+ constructor() {
35
+ super({
36
+ max: 200
37
+ });
38
+ }
36
39
 
37
40
  // Track fetch start times for duration calculation
38
41
  fetchStartTimes = new Map();
@@ -243,43 +246,31 @@ class ReactQueryEventStore {
243
246
  * Add an event to the store
244
247
  */
245
248
  addEvent(event) {
246
- this.events = [event, ...this.events].slice(0, this.maxEvents);
247
- this.notifyListeners();
249
+ this.record(event);
248
250
  }
249
251
 
250
252
  /**
251
253
  * Get all events
252
254
  */
253
255
  getEvents() {
254
- return this.events;
256
+ return this.items;
255
257
  }
256
258
 
257
259
  /**
258
260
  * Subscribe to event changes
259
261
  */
260
262
  subscribe(listener) {
261
- this.listeners.add(listener);
263
+ const unsubscribe = super.subscribe(listener);
262
264
  // Immediately call with current events
263
- listener(this.events);
264
- return () => {
265
- this.listeners.delete(listener);
266
- };
267
- }
268
-
269
- /**
270
- * Notify all listeners
271
- */
272
- notifyListeners() {
273
- const events = this.events;
274
- this.listeners.forEach(listener => listener(events));
265
+ listener(this.items);
266
+ return unsubscribe;
275
267
  }
276
268
 
277
269
  /**
278
270
  * Clear all events
279
271
  */
280
272
  clearEvents() {
281
- this.events = [];
282
- this.notifyListeners();
273
+ this.clear();
283
274
  }
284
275
 
285
276
  /**