@buoy-gg/redux 5.0.0 → 6.0.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.
package/README.md CHANGED
@@ -1,55 +1,71 @@
1
1
  # @buoy-gg/redux
2
2
 
3
- ## Description
3
+ [![npm version](https://img.shields.io/npm/v/@buoy-gg/redux?style=flat-square&labelColor=1c1c1c&color=10B981)](https://www.npmjs.com/package/@buoy-gg/redux) [![npm downloads](https://img.shields.io/npm/dm/@buoy-gg/redux?style=flat-square&labelColor=1c1c1c&color=10B981)](https://www.npmjs.com/package/@buoy-gg/redux)
4
4
 
5
- redux package for the monorepo.
5
+ **Redux DevTools on the device — action log, state diffs, and time travel with zero store changes.**
6
6
 
7
- ## Installation
7
+ Part of [Buoy](https://github.com/Buoy-gg/buoy) — devtools that live inside your React Native app. Install it and it auto-appears in the floating menu from [`@buoy-gg/core`](https://www.npmjs.com/package/@buoy-gg/core).
8
8
 
9
- This package is part of the monorepo and is automatically available to other packages and the example app.
9
+ ## Install
10
10
 
11
- ## Usage
11
+ ```bash
12
+ npm install @buoy-gg/core @buoy-gg/redux
13
+ ```
12
14
 
13
- ```typescript
14
- import { ReduxComponent } from '@buoy-gg/redux';
15
+ ## Quick start
15
16
 
16
- // Use in your component
17
- <ReduxComponent title="Hello World" />
18
- ```
17
+ Zero config. Your existing store works as-is — no middleware, no wrapper. The tool auto-instruments the store when `FloatingDevTools` mounts.
19
18
 
20
- ## Development
19
+ ```tsx
20
+ import { configureStore } from '@reduxjs/toolkit';
21
+ import { Provider } from 'react-redux';
22
+ import { FloatingDevTools } from '@buoy-gg/core';
21
23
 
22
- ### Building
24
+ const store = configureStore({ reducer: rootReducer }); // unchanged
23
25
 
24
- ```bash
25
- pnpm build
26
+ export default function App() {
27
+ return (
28
+ <Provider store={store}>
29
+ <YourApp />
30
+ <FloatingDevTools />
31
+ </Provider>
32
+ );
33
+ }
26
34
  ```
27
35
 
28
- ### Type Checking
36
+ ### Optional: full time travel
29
37
 
30
- ```bash
31
- pnpm typecheck
32
- ```
38
+ To jump back to past states (not just view them), wrap your reducer:
33
39
 
34
- ### Clean Build
40
+ ```tsx
41
+ import { withBuoyDevTools } from '@buoy-gg/redux';
35
42
 
36
- ```bash
37
- pnpm clean
43
+ const store = configureStore({
44
+ reducer: withBuoyDevTools(rootReducer),
45
+ });
38
46
  ```
39
47
 
40
- ## Structure
48
+ ## What you get
41
49
 
42
- ```
43
- redux/
44
- ├── src/
45
- │ └── index.ts # Main export file
46
- ├── lib/ # Built output (git ignored)
47
- ├── package.json
48
- ├── tsconfig.json
49
- └── README.md
50
- ```
50
+ - **Every action, captured** — type, payload, timestamp, and a diff summary (`+added -removed ~modified`) per dispatch
51
+ - **Frame-budget warnings** — actions taking longer than 16ms are flagged so slow reducers can't hide
52
+ - **RTK async thunk linking** — pending → fulfilled/rejected automatically connected by Request ID, with a visual timeline and per-request durations
53
+ - **Time travel** — jump to the state after any action, or replay an action to re-test your reducers
54
+ - **Three-tab detail view** — full action payload, full state tree, and a side-by-side diff (tree or split view)
55
+ - **Search & filter** — find actions by type, or show only actions that actually changed state
56
+ - **Export & copy** — dump action history as JSON for bug reports or test fixtures
57
+ - **Recording toggle** — pause capture when you need to focus, resume when ready
58
+
59
+ ## Desktop & AI
60
+
61
+ The same live session streams to [Buoy Desktop](https://github.com/Buoy-gg/Buoy-Desktop) (free, macOS/Windows/Linux) and to Claude Code or Cursor via the [Buoy MCP server](https://buoy.gg/buoy/latest/docs/mcp).
62
+
63
+ ## Free vs Pro
64
+
65
+ Every tool is free. [Pro](https://buoy.gg/pricing) unlocks production builds, the MCP server, and unlimited capture. Every weekend, Pro features unlock free for everyone.
66
+
67
+ ---
51
68
 
52
- ## Dependencies
69
+ 📚 [Full docs](https://buoy.gg/buoy/latest/docs/tools/redux) · [All Buoy tools](https://github.com/Buoy-gg/buoy)
53
70
 
54
- - Uses `@buoy-gg/shared-ui` for common components and utilities
55
- - React and React Native as peer dependencies
71
+ Proprietary software. © Buoy LLC. [Terms](https://buoy.gg/terms)
@@ -3,7 +3,8 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.ReduxActionItem = ReduxActionItem;
6
+ exports.ReduxActionItem = void 0;
7
+ var _react = require("react");
7
8
  var _reactNative = require("react-native");
8
9
  var _sharedUi = require("@buoy-gg/shared-ui");
9
10
  var _reduxActionStore = require("../utils/reduxActionStore");
@@ -206,11 +207,15 @@ function getPrimaryText(action) {
206
207
  }
207
208
  return action.type;
208
209
  }
209
- function ReduxActionItem({
210
+
211
+ // Memo justified by profiling (tool-bench 2026-07-06): ReduxActionItem
212
+ // x172 renders during a 5s idle dwell at 200 seeded actions. The relative
213
+ // timestamp is delegated to the shared <RelativeTime/> leaf so the 5s
214
+ // tick re-renders only that Text, not this row.
215
+ const ReduxActionItem = exports.ReduxActionItem = /*#__PURE__*/(0, _react.memo)(function ReduxActionItem({
210
216
  action,
211
217
  onPress
212
218
  }) {
213
- const relativeTime = (0, _sharedUi.useRelativeTime)(action.timestamp);
214
219
  const sliceName = action.sliceName ?? undefined;
215
220
  const statusColor = getStatusColor(action.category, action.hasStateChange, sliceName);
216
221
  const statusLabel = getStatusLabel(action.category, sliceName);
@@ -323,7 +328,9 @@ function ReduxActionItem({
323
328
  statusLabel: statusLabel,
324
329
  statusSublabel: sublabel,
325
330
  primaryText: primaryText,
326
- bottomRightText: relativeTime
331
+ bottomRightText: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.RelativeTime, {
332
+ timestamp: action.timestamp
333
+ })
327
334
  // Use customBadge if we have special indicators, otherwise show action badge as text
328
335
  ,
329
336
  customBadge: customBadge,
@@ -332,7 +339,7 @@ function ReduxActionItem({
332
339
  showChevron: true,
333
340
  onPress: () => onPress(action)
334
341
  });
335
- }
342
+ });
336
343
  const styles = _reactNative.StyleSheet.create({
337
344
  badgeContainer: {
338
345
  flexDirection: "row",
@@ -281,6 +281,10 @@ function ReduxModal({
281
281
  onIndexChange: handleIndexChange
282
282
  }) : null;
283
283
  const footerHeight = selectedAction && visibleActions.length > 1 ? 68 : 0;
284
+
285
+ // The action list owns its scrolling so FlatList virtualization works
286
+ // (see ZustandModal — same pattern, same tool-bench evidence).
287
+ const listOwnsScroll = selectedAction == null;
284
288
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_sharedUi.TickProvider, {
285
289
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.JsModal, {
286
290
  visible: visible,
@@ -295,6 +299,7 @@ function ReduxModal({
295
299
  enablePersistence: true,
296
300
  initialMode: "bottomSheet",
297
301
  enableGlitchEffects: true,
302
+ disableScrollWrapper: listOwnsScroll,
298
303
  styles: {},
299
304
  footer: footerNode,
300
305
  footerHeight: footerHeight,
@@ -350,10 +355,10 @@ function ReduxModal({
350
355
  contentContainerStyle: styles.listContent,
351
356
  showsVerticalScrollIndicator: true,
352
357
  removeClippedSubviews: true,
353
- initialNumToRender: 15,
354
- maxToRenderPerBatch: 10,
355
- windowSize: 10,
356
- scrollEnabled: false
358
+ initialNumToRender: 12,
359
+ maxToRenderPerBatch: 8,
360
+ windowSize: 5,
361
+ updateCellsBatchingPeriod: 50
357
362
  }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(EmptyState, {
358
363
  isEnabled: isEnabled
359
364
  })]
@@ -5,8 +5,9 @@
5
5
  * Uses shared CompactRow for consistent styling with React Query devtools
6
6
  */
7
7
 
8
+ import { memo } from "react";
8
9
  import { View, Text, StyleSheet } from "react-native";
9
- import { CompactRow, buoyColors, Zap, AlertCircle, Clock, useRelativeTime } from "@buoy-gg/shared-ui";
10
+ import { CompactRow, buoyColors, Zap, AlertCircle, Clock, RelativeTime } from "@buoy-gg/shared-ui";
10
11
  import { reduxActionStore } from "../utils/reduxActionStore";
11
12
  import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
12
13
  /**
@@ -202,11 +203,15 @@ function getPrimaryText(action) {
202
203
  }
203
204
  return action.type;
204
205
  }
205
- export function ReduxActionItem({
206
+
207
+ // Memo justified by profiling (tool-bench 2026-07-06): ReduxActionItem
208
+ // x172 renders during a 5s idle dwell at 200 seeded actions. The relative
209
+ // timestamp is delegated to the shared <RelativeTime/> leaf so the 5s
210
+ // tick re-renders only that Text, not this row.
211
+ export const ReduxActionItem = /*#__PURE__*/memo(function ReduxActionItem({
206
212
  action,
207
213
  onPress
208
214
  }) {
209
- const relativeTime = useRelativeTime(action.timestamp);
210
215
  const sliceName = action.sliceName ?? undefined;
211
216
  const statusColor = getStatusColor(action.category, action.hasStateChange, sliceName);
212
217
  const statusLabel = getStatusLabel(action.category, sliceName);
@@ -319,7 +324,9 @@ export function ReduxActionItem({
319
324
  statusLabel: statusLabel,
320
325
  statusSublabel: sublabel,
321
326
  primaryText: primaryText,
322
- bottomRightText: relativeTime
327
+ bottomRightText: /*#__PURE__*/_jsx(RelativeTime, {
328
+ timestamp: action.timestamp
329
+ })
323
330
  // Use customBadge if we have special indicators, otherwise show action badge as text
324
331
  ,
325
332
  customBadge: customBadge,
@@ -328,7 +335,7 @@ export function ReduxActionItem({
328
335
  showChevron: true,
329
336
  onPress: () => onPress(action)
330
337
  });
331
- }
338
+ });
332
339
  const styles = StyleSheet.create({
333
340
  badgeContainer: {
334
341
  flexDirection: "row",
@@ -276,6 +276,10 @@ export function ReduxModal({
276
276
  onIndexChange: handleIndexChange
277
277
  }) : null;
278
278
  const footerHeight = selectedAction && visibleActions.length > 1 ? 68 : 0;
279
+
280
+ // The action list owns its scrolling so FlatList virtualization works
281
+ // (see ZustandModal — same pattern, same tool-bench evidence).
282
+ const listOwnsScroll = selectedAction == null;
279
283
  return /*#__PURE__*/_jsxs(TickProvider, {
280
284
  children: [/*#__PURE__*/_jsx(JsModal, {
281
285
  visible: visible,
@@ -290,6 +294,7 @@ export function ReduxModal({
290
294
  enablePersistence: true,
291
295
  initialMode: "bottomSheet",
292
296
  enableGlitchEffects: true,
297
+ disableScrollWrapper: listOwnsScroll,
293
298
  styles: {},
294
299
  footer: footerNode,
295
300
  footerHeight: footerHeight,
@@ -345,10 +350,10 @@ export function ReduxModal({
345
350
  contentContainerStyle: styles.listContent,
346
351
  showsVerticalScrollIndicator: true,
347
352
  removeClippedSubviews: true,
348
- initialNumToRender: 15,
349
- maxToRenderPerBatch: 10,
350
- windowSize: 10,
351
- scrollEnabled: false
353
+ initialNumToRender: 12,
354
+ maxToRenderPerBatch: 8,
355
+ windowSize: 5,
356
+ updateCellsBatchingPeriod: 50
352
357
  }) : /*#__PURE__*/_jsx(EmptyState, {
353
358
  isEnabled: isEnabled
354
359
  })]
@@ -7,6 +7,6 @@ interface ReduxActionItemProps {
7
7
  action: ReduxAction;
8
8
  onPress: (action: ReduxAction) => void;
9
9
  }
10
- export declare function ReduxActionItem({ action, onPress }: ReduxActionItemProps): import("react").JSX.Element;
10
+ export declare const ReduxActionItem: import("react").NamedExoticComponent<ReduxActionItemProps>;
11
11
  export {};
12
12
  //# sourceMappingURL=ReduxActionItem.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ReduxActionItem.d.ts","sourceRoot":"","sources":["../../../../src/redux/components/ReduxActionItem.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAkB,MAAM,UAAU,CAAC;AAG5D,UAAU,oBAAoB;IAC5B,MAAM,EAAE,WAAW,CAAC;IACpB,OAAO,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,IAAI,CAAC;CACxC;AA+JD,wBAAgB,eAAe,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,oBAAoB,+BAmGxE"}
1
+ {"version":3,"file":"ReduxActionItem.d.ts","sourceRoot":"","sources":["../../../../src/redux/components/ReduxActionItem.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,KAAK,EAAE,WAAW,EAAkB,MAAM,UAAU,CAAC;AAG5D,UAAU,oBAAoB;IAC5B,MAAM,EAAE,WAAW,CAAC;IACpB,OAAO,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,IAAI,CAAC;CACxC;AAmKD,eAAO,MAAM,eAAe,4DAkG1B,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"ReduxModal.d.ts","sourceRoot":"","sources":["../../../../src/redux/components/ReduxModal.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AA2CH,yCAAyC;AACzC,eAAO,MAAM,sBAAsB,KAAK,CAAC;AAEzC,UAAU,eAAe;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,UAAU,CAAC,EAAE,CAAC,UAAU,EAAE,OAAO,KAAK,IAAI,CAAC;IAC3C,2BAA2B,CAAC,EAAE,OAAO,CAAC;CACvC;AAgBD,wBAAgB,UAAU,CAAC,EACzB,OAAO,EACP,OAAO,EACP,MAAM,EACN,UAAU,EACV,2BAAmC,GACpC,EAAE,eAAe,sCA4XjB"}
1
+ {"version":3,"file":"ReduxModal.d.ts","sourceRoot":"","sources":["../../../../src/redux/components/ReduxModal.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AA2CH,yCAAyC;AACzC,eAAO,MAAM,sBAAsB,KAAK,CAAC;AAEzC,UAAU,eAAe;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,UAAU,CAAC,EAAE,CAAC,UAAU,EAAE,OAAO,KAAK,IAAI,CAAC;IAC3C,2BAA2B,CAAC,EAAE,OAAO,CAAC;CACvC;AAgBD,wBAAgB,UAAU,CAAC,EACzB,OAAO,EACP,OAAO,EACP,MAAM,EACN,UAAU,EACV,2BAAmC,GACpC,EAAE,eAAe,sCAiYjB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@buoy-gg/redux",
3
- "version": "5.0.0",
3
+ "version": "6.0.1",
4
4
  "description": "Redux Toolkit DevTools for React Native",
5
5
  "main": "lib/commonjs/index.js",
6
6
  "module": "lib/module/index.js",
@@ -26,9 +26,9 @@
26
26
  ],
27
27
  "sideEffects": false,
28
28
  "dependencies": {
29
- "@buoy-gg/shared-ui": "5.0.0",
30
- "@buoy-gg/license": "5.0.0",
31
- "@buoy-gg/floating-tools-core": "5.0.0"
29
+ "@buoy-gg/license": "6.0.1",
30
+ "@buoy-gg/floating-tools-core": "6.0.1",
31
+ "@buoy-gg/shared-ui": "6.0.1"
32
32
  },
33
33
  "peerDependencies": {
34
34
  "@reduxjs/toolkit": ">=2.0.0",