@buoy-gg/redux 7.0.41 → 7.0.42
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 +11 -106
- package/lib/commonjs/index.js +1 -256
- package/lib/commonjs/preset.js +1 -90
- package/lib/commonjs/redux/components/ReduxActionButton.js +1 -131
- package/lib/commonjs/redux/components/ReduxActionDetailContent.js +1 -437
- package/lib/commonjs/redux/components/ReduxActionDetailView.js +1 -401
- package/lib/commonjs/redux/components/ReduxActionInfoView.js +1 -836
- package/lib/commonjs/redux/components/ReduxActionItem.js +1 -337
- package/lib/commonjs/redux/components/ReduxAutoInstrument.js +1 -20
- package/lib/commonjs/redux/components/ReduxDetailViewToggle.js +1 -50
- package/lib/commonjs/redux/components/ReduxIcon.js +1 -18
- package/lib/commonjs/redux/components/ReduxModal.js +1 -703
- package/lib/commonjs/redux/hooks/reduxPeer.js +1 -17
- package/lib/commonjs/redux/hooks/reduxPeer.web.js +1 -10
- package/lib/commonjs/redux/hooks/useAutoInstrumentRedux.js +1 -177
- package/lib/commonjs/redux/hooks/useReduxActions.js +1 -58
- package/lib/commonjs/redux/sync/reduxSyncAdapter.js +1 -191
- package/lib/commonjs/redux/types/index.js +1 -1
- package/lib/commonjs/redux/utils/activeStoreRegistry.js +1 -104
- package/lib/commonjs/redux/utils/autoInstrument.js +1 -231
- package/lib/commonjs/redux/utils/buoyReduxMiddleware.js +1 -202
- package/lib/commonjs/redux/utils/createReduxHistoryAdapter.js +1 -146
- package/lib/commonjs/redux/utils/devtoolsHook.js +1 -152
- package/lib/commonjs/redux/utils/reduxActionStore.js +1 -473
- package/lib/commonjs/redux/utils/snapshotProvider.js +1 -158
- package/lib/commonjs/redux/utils/testIDs.js +1 -75
- package/lib/module/index.js +1 -125
- package/lib/module/preset.js +1 -87
- package/lib/module/redux/components/ReduxActionButton.js +1 -128
- package/lib/module/redux/components/ReduxActionDetailContent.js +1 -433
- package/lib/module/redux/components/ReduxActionDetailView.js +1 -397
- package/lib/module/redux/components/ReduxActionInfoView.js +1 -831
- package/lib/module/redux/components/ReduxActionItem.js +1 -333
- package/lib/module/redux/components/ReduxAutoInstrument.js +1 -17
- package/lib/module/redux/components/ReduxDetailViewToggle.js +1 -45
- package/lib/module/redux/components/ReduxIcon.js +1 -8
- package/lib/module/redux/components/ReduxModal.js +1 -698
- package/lib/module/redux/hooks/reduxPeer.js +1 -13
- package/lib/module/redux/hooks/reduxPeer.web.js +1 -6
- package/lib/module/redux/hooks/useAutoInstrumentRedux.js +1 -173
- package/lib/module/redux/hooks/useReduxActions.js +1 -54
- package/lib/module/redux/sync/reduxSyncAdapter.js +1 -188
- package/lib/module/redux/types/index.js +1 -1
- package/lib/module/redux/utils/activeStoreRegistry.js +1 -92
- package/lib/module/redux/utils/autoInstrument.js +1 -201
- package/lib/module/redux/utils/buoyReduxMiddleware.js +1 -188
- package/lib/module/redux/utils/createReduxHistoryAdapter.js +1 -142
- package/lib/module/redux/utils/devtoolsHook.js +1 -145
- package/lib/module/redux/utils/reduxActionStore.js +1 -465
- package/lib/module/redux/utils/snapshotProvider.js +1 -157
- package/lib/module/redux/utils/testIDs.js +1 -68
- package/lib/web/index.mjs +1 -2
- package/package.json +4 -4
- package/lib/typescript/index.d.ts.map +0 -1
- package/lib/typescript/preset.d.ts.map +0 -1
- package/lib/typescript/redux/components/ReduxActionButton.d.ts.map +0 -1
- package/lib/typescript/redux/components/ReduxActionDetailContent.d.ts.map +0 -1
- package/lib/typescript/redux/components/ReduxActionDetailView.d.ts.map +0 -1
- package/lib/typescript/redux/components/ReduxActionInfoView.d.ts.map +0 -1
- package/lib/typescript/redux/components/ReduxActionItem.d.ts.map +0 -1
- package/lib/typescript/redux/components/ReduxAutoInstrument.d.ts.map +0 -1
- package/lib/typescript/redux/components/ReduxDetailViewToggle.d.ts.map +0 -1
- package/lib/typescript/redux/components/ReduxIcon.d.ts.map +0 -1
- package/lib/typescript/redux/components/ReduxModal.d.ts.map +0 -1
- package/lib/typescript/redux/hooks/reduxPeer.d.ts.map +0 -1
- package/lib/typescript/redux/hooks/reduxPeer.web.d.ts.map +0 -1
- package/lib/typescript/redux/hooks/useAutoInstrumentRedux.d.ts.map +0 -1
- package/lib/typescript/redux/hooks/useReduxActions.d.ts.map +0 -1
- package/lib/typescript/redux/sync/reduxSyncAdapter.d.ts.map +0 -1
- package/lib/typescript/redux/types/index.d.ts.map +0 -1
- package/lib/typescript/redux/utils/activeStoreRegistry.d.ts.map +0 -1
- package/lib/typescript/redux/utils/autoInstrument.d.ts.map +0 -1
- package/lib/typescript/redux/utils/buoyReduxMiddleware.d.ts.map +0 -1
- package/lib/typescript/redux/utils/createReduxHistoryAdapter.d.ts.map +0 -1
- package/lib/typescript/redux/utils/devtoolsHook.d.ts.map +0 -1
- package/lib/typescript/redux/utils/reduxActionStore.d.ts.map +0 -1
- package/lib/typescript/redux/utils/snapshotProvider.d.ts.map +0 -1
- package/lib/typescript/redux/utils/testIDs.d.ts.map +0 -1
|
@@ -1,201 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Fallback auto-instrumentation for Redux stores.
|
|
5
|
-
*
|
|
6
|
-
* The PRIMARY capture path is the store-creation-time enhancer in
|
|
7
|
-
* devtoolsHook.ts (full capture, real time travel). This module is the
|
|
8
|
-
* fallback for stores created before our module loaded: it patches
|
|
9
|
-
* store.dispatch after the fact.
|
|
10
|
-
*
|
|
11
|
-
* Fallback limitation (inherent to patching, verified against redux 5.x):
|
|
12
|
-
* `middlewareAPI.dispatch` is a separate closure from `store.dispatch`, so
|
|
13
|
-
* actions dispatched from INSIDE middleware/thunks (RTK pending/fulfilled/
|
|
14
|
-
* rejected, RTK Query) bypass the patch. That's why this mechanism reports
|
|
15
|
-
* capture as "top-level-only" — see activeStoreRegistry.getInstrumentationStatus.
|
|
16
|
-
*/
|
|
17
|
-
|
|
18
|
-
import { reduxActionStore } from "./reduxActionStore";
|
|
19
|
-
import { isMiddlewareActive } from "./buoyReduxMiddleware";
|
|
20
|
-
import { registerActiveStore, unregisterActiveStore, getActiveStore as getRegisteredStore, ENHANCER_SYMBOL } from "./activeStoreRegistry";
|
|
21
|
-
|
|
22
|
-
// Re-exported for non-React callers (sync adapter, app code).
|
|
23
|
-
export { getInstrumentationStatus } from "./activeStoreRegistry";
|
|
24
|
-
|
|
25
|
-
// ============================================
|
|
26
|
-
// Store Tracking
|
|
27
|
-
// ============================================
|
|
28
|
-
|
|
29
|
-
/** Symbol to mark stores that have been instrumented */
|
|
30
|
-
const INSTRUMENTED_SYMBOL = Symbol.for("@@buoy/instrumented");
|
|
31
|
-
|
|
32
|
-
/** Symbol to store original dispatch reference */
|
|
33
|
-
const ORIGINAL_DISPATCH_SYMBOL = Symbol.for("@@buoy/originalDispatch");
|
|
34
|
-
|
|
35
|
-
// ============================================
|
|
36
|
-
// Type Definitions
|
|
37
|
-
// ============================================
|
|
38
|
-
|
|
39
|
-
// ============================================
|
|
40
|
-
// Core Instrumentation
|
|
41
|
-
// ============================================
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Check if a store has already been instrumented (either mechanism)
|
|
45
|
-
*/
|
|
46
|
-
export function isStoreInstrumented(store) {
|
|
47
|
-
const s = store;
|
|
48
|
-
return s[INSTRUMENTED_SYMBOL] === true || s[ENHANCER_SYMBOL] === true;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Instrument a Redux store for action capture (fallback path).
|
|
53
|
-
*
|
|
54
|
-
* Patches store.dispatch to capture top-level dispatches. No-ops (but still
|
|
55
|
-
* registers the store for getState/dispatch) when the enhancer or the
|
|
56
|
-
* explicit middleware is already capturing.
|
|
57
|
-
*
|
|
58
|
-
* @returns Cleanup function to restore original dispatch
|
|
59
|
-
*/
|
|
60
|
-
export function instrumentStore(store, options = {}) {
|
|
61
|
-
const instrumentedStore = store;
|
|
62
|
-
|
|
63
|
-
// Store was created through the devtools-hook enhancer — full capture is
|
|
64
|
-
// already live; just (re)point the registry at it.
|
|
65
|
-
if (instrumentedStore[ENHANCER_SYMBOL]) {
|
|
66
|
-
registerActiveStore(store, "enhancer");
|
|
67
|
-
return () => {};
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// Skip if middleware is already handling action capture
|
|
71
|
-
if (isMiddlewareActive()) {
|
|
72
|
-
registerActiveStore(store, "middleware");
|
|
73
|
-
return () => {};
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// Skip if already patched — update the registry even so (store swap case)
|
|
77
|
-
if (instrumentedStore[INSTRUMENTED_SYMBOL]) {
|
|
78
|
-
registerActiveStore(store, "patch");
|
|
79
|
-
return () => {};
|
|
80
|
-
}
|
|
81
|
-
const {
|
|
82
|
-
maxActions = 200,
|
|
83
|
-
ignoreActions = []
|
|
84
|
-
} = options;
|
|
85
|
-
|
|
86
|
-
// Configure store
|
|
87
|
-
reduxActionStore.setMaxActions(maxActions);
|
|
88
|
-
|
|
89
|
-
// Store original dispatch
|
|
90
|
-
const originalDispatch = store.dispatch.bind(store);
|
|
91
|
-
instrumentedStore[ORIGINAL_DISPATCH_SYMBOL] = originalDispatch;
|
|
92
|
-
|
|
93
|
-
// Create instrumented dispatch
|
|
94
|
-
const instrumentedDispatch = action => {
|
|
95
|
-
// Skip if action is not a plain object with a type property
|
|
96
|
-
// This filters out thunk functions, promises, and other non-action dispatches
|
|
97
|
-
if (typeof action !== "object" || action === null || typeof action.type !== "string") {
|
|
98
|
-
return originalDispatch(action);
|
|
99
|
-
}
|
|
100
|
-
const actionType = action.type;
|
|
101
|
-
|
|
102
|
-
// Don't record devtools internal actions
|
|
103
|
-
if (actionType.startsWith("@@buoy/")) {
|
|
104
|
-
return originalDispatch(action);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// Don't record Redux internal actions
|
|
108
|
-
if (actionType.startsWith("@@redux/")) {
|
|
109
|
-
return originalDispatch(action);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// Check ignore list
|
|
113
|
-
if (ignoreActions.includes(actionType)) {
|
|
114
|
-
return originalDispatch(action);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// Capture timing and state
|
|
118
|
-
const startTime = performance.now();
|
|
119
|
-
const prevState = store.getState();
|
|
120
|
-
const result = originalDispatch(action);
|
|
121
|
-
const nextState = store.getState();
|
|
122
|
-
const duration = performance.now() - startTime;
|
|
123
|
-
|
|
124
|
-
// Record the action
|
|
125
|
-
reduxActionStore.addAction(action, prevState, nextState, duration);
|
|
126
|
-
return result;
|
|
127
|
-
};
|
|
128
|
-
|
|
129
|
-
// Replace dispatch
|
|
130
|
-
store.dispatch = instrumentedDispatch;
|
|
131
|
-
instrumentedStore[INSTRUMENTED_SYMBOL] = true;
|
|
132
|
-
registerActiveStore(store, "patch");
|
|
133
|
-
|
|
134
|
-
// Return cleanup function
|
|
135
|
-
return () => {
|
|
136
|
-
uninstrumentStore(store);
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* Remove dispatch-patch instrumentation from a store.
|
|
142
|
-
*
|
|
143
|
-
* Only restores the patched dispatch. (This used to also replaceReducer with a
|
|
144
|
-
* synthetic reducer that froze the host store permanently — that path is gone.)
|
|
145
|
-
* Enhancer-created stores are left untouched apart from the registry.
|
|
146
|
-
*/
|
|
147
|
-
export function uninstrumentStore(store) {
|
|
148
|
-
const instrumentedStore = store;
|
|
149
|
-
if (instrumentedStore[INSTRUMENTED_SYMBOL]) {
|
|
150
|
-
const originalDispatch = instrumentedStore[ORIGINAL_DISPATCH_SYMBOL];
|
|
151
|
-
if (originalDispatch) {
|
|
152
|
-
store.dispatch = originalDispatch;
|
|
153
|
-
}
|
|
154
|
-
delete instrumentedStore[INSTRUMENTED_SYMBOL];
|
|
155
|
-
delete instrumentedStore[ORIGINAL_DISPATCH_SYMBOL];
|
|
156
|
-
}
|
|
157
|
-
unregisterActiveStore(store);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* Manually register a store with Buoy — the escape hatch for apps that can't
|
|
162
|
-
* render FloatingDevTools inside a react-redux Provider (or don't use
|
|
163
|
-
* react-redux at all). Instruments via the fallback dispatch patch.
|
|
164
|
-
*
|
|
165
|
-
* Prefer the zero-config paths; this exists so no app is ever stuck.
|
|
166
|
-
*/
|
|
167
|
-
export function registerReduxStore(store, options = {}) {
|
|
168
|
-
return instrumentStore(store, options);
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
// ============================================
|
|
172
|
-
// Time-Travel / Introspection
|
|
173
|
-
// ============================================
|
|
174
|
-
|
|
175
|
-
/**
|
|
176
|
-
* Time travel lives in buoyReduxMiddleware.ts and is re-exported here.
|
|
177
|
-
*
|
|
178
|
-
* It used to be reimplemented in this file, and the two copies drifted: this
|
|
179
|
-
* one learned to notice that a jump had been ignored, the one the modal's JUMP
|
|
180
|
-
* button actually calls never did. So the detection existed and no user could
|
|
181
|
-
* ever have seen it. One implementation, one behaviour.
|
|
182
|
-
*/
|
|
183
|
-
export { jumpToState, replayAction, isTimeTravelAvailable } from "./buoyReduxMiddleware";
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* Get the currently active (instrumented) store.
|
|
187
|
-
*
|
|
188
|
-
* NOTE: on the middleware path this is the middleware `storeApi`
|
|
189
|
-
* ({getState, dispatch}) rather than the full Store object — every consumer
|
|
190
|
-
* in this package only needs those two.
|
|
191
|
-
*/
|
|
192
|
-
export function getActiveStore() {
|
|
193
|
-
return getRegisteredStore();
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
/**
|
|
197
|
-
* Check if auto-instrumentation is active
|
|
198
|
-
*/
|
|
199
|
-
export function isAutoInstrumentActive() {
|
|
200
|
-
return getRegisteredStore() !== null;
|
|
201
|
-
}
|
|
1
|
+
"use strict";import{reduxActionStore as p}from"./reduxActionStore";import{isMiddlewareActive as y}from"./buoyReduxMiddleware";import{registerActiveStore as u,unregisterActiveStore as v,getActiveStore as a,ENHANCER_SYMBOL as f}from"./activeStoreRegistry";export{getInstrumentationStatus}from"./activeStoreRegistry";const o=Symbol.for("@@buoy/instrumented");const c=Symbol.for("@@buoy/originalDispatch");export function isStoreInstrumented(t){const e=t;return e[o]===true||e[f]===true}export function instrumentStore(t,e={}){const n=t;if(n[f]){u(t,"enhancer");return()=>{}}if(y()){u(t,"middleware");return()=>{}}if(n[o]){u(t,"patch");return()=>{}}const{maxActions:m=200,ignoreActions:S=[]}=e;p.setMaxActions(m);const i=t.dispatch.bind(t);n[c]=i;const d=r=>{if(typeof r!=="object"||r===null||typeof r.type!=="string"){return i(r)}const s=r.type;if(s.startsWith("@@buoy/")){return i(r)}if(s.startsWith("@@redux/")){return i(r)}if(S.includes(s)){return i(r)}const l=performance.now();const A=t.getState();const g=i(r);const x=t.getState();const h=performance.now()-l;p.addAction(r,A,x,h);return g};t.dispatch=d;n[o]=true;u(t,"patch");return()=>{uninstrumentStore(t)}}export function uninstrumentStore(t){const e=t;if(e[o]){const n=e[c];if(n){t.dispatch=n}delete e[o];delete e[c]}v(t)}export function registerReduxStore(t,e={}){return instrumentStore(t,e)}export{jumpToState,replayAction,isTimeTravelAvailable}from"./buoyReduxMiddleware";export function getActiveStore(){return a()}export function isAutoInstrumentActive(){return a()!==null}
|
|
@@ -1,188 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Buoy Redux Middleware for Redux Toolkit
|
|
5
|
-
*
|
|
6
|
-
* @example
|
|
7
|
-
* ```tsx
|
|
8
|
-
* import { configureStore } from '@reduxjs/toolkit';
|
|
9
|
-
* import { buoyReduxMiddleware, withBuoyDevTools } from '@buoy-gg/redux';
|
|
10
|
-
*
|
|
11
|
-
* const store = configureStore({
|
|
12
|
-
* reducer: withBuoyDevTools(rootReducer), // Enable time-travel
|
|
13
|
-
* middleware: (getDefaultMiddleware) =>
|
|
14
|
-
* getDefaultMiddleware().concat(buoyReduxMiddleware),
|
|
15
|
-
* });
|
|
16
|
-
* ```
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
import { reduxActionStore, isEvictedState } from "./reduxActionStore";
|
|
20
|
-
import { registerActiveStore, getActiveStore, markTimeTravelReducer, isTimeTravelAvailable } from "./activeStoreRegistry";
|
|
21
|
-
|
|
22
|
-
// ============================================
|
|
23
|
-
// Middleware Active Tracking
|
|
24
|
-
// ============================================
|
|
25
|
-
|
|
26
|
-
/** Flag to indicate middleware is handling action capture */
|
|
27
|
-
let middlewareActive = false;
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Check if the explicit middleware is active
|
|
31
|
-
* Used by auto-instrument to avoid duplicate capture
|
|
32
|
-
*/
|
|
33
|
-
export function isMiddlewareActive() {
|
|
34
|
-
return middlewareActive;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// ============================================
|
|
38
|
-
// Time-Travel Action Types
|
|
39
|
-
// ============================================
|
|
40
|
-
|
|
41
|
-
export const BUOY_JUMP_TO_STATE = "@@buoy/JUMP_TO_STATE";
|
|
42
|
-
export const BUOY_REPLAY_ACTION = "@@buoy/REPLAY_ACTION";
|
|
43
|
-
/**
|
|
44
|
-
* Jump to a specific state (time-travel).
|
|
45
|
-
*
|
|
46
|
-
* Registry-backed, so it reaches the store on every capture path — but
|
|
47
|
-
* REACHING the store is not the same as being able to jump, and conflating the
|
|
48
|
-
* two is what made this fail invisibly. A jump is an action like any other: it
|
|
49
|
-
* only does something if a reducer handles it, and the only two things that
|
|
50
|
-
* install such a reducer are the devtools-hook enhancer and `withBuoyDevTools`.
|
|
51
|
-
* An app that captures through `buoyReduxMiddleware` alone dispatches the jump
|
|
52
|
-
* into a store that has never heard of it, gets its own state back, and shows
|
|
53
|
-
* a screen that does not move — with no error, because nothing went wrong.
|
|
54
|
-
*
|
|
55
|
-
* So the capability is checked up front and refused out loud. The UI asks the
|
|
56
|
-
* same question (`isTimeTravelAvailable`) and disables the button, which is the
|
|
57
|
-
* half a warning cannot do.
|
|
58
|
-
*/
|
|
59
|
-
export function jumpToState(state) {
|
|
60
|
-
if (isEvictedState(state)) {
|
|
61
|
-
console.warn("[BuoyRedux] Cannot jump - this action's state was evicted (raw state is retained for recent actions only)");
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
const store = getActiveStore();
|
|
65
|
-
if (!store) {
|
|
66
|
-
console.warn("[BuoyRedux] Cannot jump to state - no store instrumented");
|
|
67
|
-
return;
|
|
68
|
-
}
|
|
69
|
-
if (!isTimeTravelAvailable()) {
|
|
70
|
-
console.warn("[BuoyRedux] Cannot jump to state - the root reducer cannot serve a " + "state jump. Capture and time travel are wired separately: either put " + "`import '@buoy-gg/redux';` first in your app entry (so Buoy is the " + "store enhancer), or wrap your root reducer with withBuoyDevTools().");
|
|
71
|
-
return;
|
|
72
|
-
}
|
|
73
|
-
store.dispatch({
|
|
74
|
-
type: BUOY_JUMP_TO_STATE,
|
|
75
|
-
payload: state
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Whether the JUMP affordance can do anything in this app. Re-exported from
|
|
81
|
-
* the registry so hosts have one import for the whole time-travel surface.
|
|
82
|
-
*/
|
|
83
|
-
export { isTimeTravelAvailable } from "./activeStoreRegistry";
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Replay an action (dispatch it again)
|
|
87
|
-
*/
|
|
88
|
-
export function replayAction(action) {
|
|
89
|
-
const store = getActiveStore();
|
|
90
|
-
if (store) {
|
|
91
|
-
store.dispatch(action);
|
|
92
|
-
} else {
|
|
93
|
-
console.warn("[BuoyRedux] Cannot replay action - no store instrumented");
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Wrap your root reducer to enable time-travel support
|
|
99
|
-
*
|
|
100
|
-
* @example
|
|
101
|
-
* ```tsx
|
|
102
|
-
* const store = configureStore({
|
|
103
|
-
* reducer: withBuoyDevTools(rootReducer),
|
|
104
|
-
* middleware: (getDefault) => getDefault().concat(buoyReduxMiddleware),
|
|
105
|
-
* });
|
|
106
|
-
* ```
|
|
107
|
-
*/
|
|
108
|
-
export function withBuoyDevTools(reducer) {
|
|
109
|
-
// The other half of the time-travel wiring (see jumpToState): this is one of
|
|
110
|
-
// exactly two places that can answer BUOY_JUMP_TO_STATE.
|
|
111
|
-
markTimeTravelReducer();
|
|
112
|
-
return (state, action) => {
|
|
113
|
-
// Handle jump to state action
|
|
114
|
-
if (action.type === BUOY_JUMP_TO_STATE) {
|
|
115
|
-
const jumpAction = action;
|
|
116
|
-
return jumpAction.payload;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// Pass through to original reducer
|
|
120
|
-
return reducer(state, action);
|
|
121
|
-
};
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
* Default middleware - just add to your store!
|
|
126
|
-
*/
|
|
127
|
-
export const buoyReduxMiddleware = storeApi => {
|
|
128
|
-
// Mark middleware as active so auto-instrument knows to skip
|
|
129
|
-
middlewareActive = true;
|
|
130
|
-
|
|
131
|
-
// Register as the active store so getState/dispatch (MCP, desktop, time
|
|
132
|
-
// travel) work on the middleware path too — storeApi has both getState and
|
|
133
|
-
// dispatch, which is all the registry needs.
|
|
134
|
-
registerActiveStore(storeApi, "middleware");
|
|
135
|
-
return next => action => {
|
|
136
|
-
const actionObj = action;
|
|
137
|
-
const actionType = actionObj.type;
|
|
138
|
-
|
|
139
|
-
// Don't record devtools internal actions
|
|
140
|
-
if (actionType?.startsWith("@@buoy/")) {
|
|
141
|
-
return next(action);
|
|
142
|
-
}
|
|
143
|
-
const startTime = performance.now();
|
|
144
|
-
const prevState = storeApi.getState();
|
|
145
|
-
const result = next(action);
|
|
146
|
-
const nextState = storeApi.getState();
|
|
147
|
-
const duration = performance.now() - startTime;
|
|
148
|
-
reduxActionStore.addAction(actionObj, prevState, nextState, duration);
|
|
149
|
-
return result;
|
|
150
|
-
};
|
|
151
|
-
};
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* Create middleware with custom options
|
|
155
|
-
*/
|
|
156
|
-
export function createBuoyReduxMiddleware(options = {}) {
|
|
157
|
-
const {
|
|
158
|
-
maxActions = 200,
|
|
159
|
-
ignoreActions = []
|
|
160
|
-
} = options;
|
|
161
|
-
reduxActionStore.setMaxActions(maxActions);
|
|
162
|
-
return storeApi => {
|
|
163
|
-
// Mark middleware as active so auto-instrument knows to skip
|
|
164
|
-
middlewareActive = true;
|
|
165
|
-
|
|
166
|
-
// Register as the active store (see buoyReduxMiddleware above).
|
|
167
|
-
registerActiveStore(storeApi, "middleware");
|
|
168
|
-
return next => action => {
|
|
169
|
-
const actionObj = action;
|
|
170
|
-
const actionType = actionObj.type || "";
|
|
171
|
-
|
|
172
|
-
// Don't record devtools internal actions
|
|
173
|
-
if (actionType?.startsWith("@@buoy/")) {
|
|
174
|
-
return next(action);
|
|
175
|
-
}
|
|
176
|
-
if (ignoreActions.includes(actionType)) {
|
|
177
|
-
return next(action);
|
|
178
|
-
}
|
|
179
|
-
const startTime = performance.now();
|
|
180
|
-
const prevState = storeApi.getState();
|
|
181
|
-
const result = next(action);
|
|
182
|
-
const nextState = storeApi.getState();
|
|
183
|
-
const duration = performance.now() - startTime;
|
|
184
|
-
reduxActionStore.addAction(actionObj, prevState, nextState, duration);
|
|
185
|
-
return result;
|
|
186
|
-
};
|
|
187
|
-
};
|
|
188
|
-
}
|
|
1
|
+
"use strict";import{reduxActionStore as d,isEvictedState as T}from"./reduxActionStore";import{registerActiveStore as l,getActiveStore as m,markTimeTravelReducer as x,isTimeTravelAvailable as v}from"./activeStoreRegistry";let p=false;export function isMiddlewareActive(){return p}export const BUOY_JUMP_TO_STATE="@@buoy/JUMP_TO_STATE";export const BUOY_REPLAY_ACTION="@@buoy/REPLAY_ACTION";export function jumpToState(t){if(T(t)){console.warn("[BuoyRedux] Cannot jump - this action's state was evicted (raw state is retained for recent actions only)");return}const e=m();if(!e){console.warn("[BuoyRedux] Cannot jump to state - no store instrumented");return}if(!v()){console.warn("[BuoyRedux] Cannot jump to state - the root reducer cannot serve a state jump. Capture and time travel are wired separately: either put `import '@buoy-gg/redux';` first in your app entry (so Buoy is the store enhancer), or wrap your root reducer with withBuoyDevTools().");return}e.dispatch({type:BUOY_JUMP_TO_STATE,payload:t})}export{isTimeTravelAvailable}from"./activeStoreRegistry";export function replayAction(t){const e=m();if(e){e.dispatch(t)}else{console.warn("[BuoyRedux] Cannot replay action - no store instrumented")}}export function withBuoyDevTools(t){x();return(e,r)=>{if(r.type===BUOY_JUMP_TO_STATE){const o=r;return o.payload}return t(e,r)}}export const buoyReduxMiddleware=t=>{p=true;l(t,"middleware");return e=>r=>{const o=r;const a=o.type;if(a?.startsWith("@@buoy/")){return e(r)}const n=performance.now();const s=t.getState();const i=e(r);const u=t.getState();const c=performance.now()-n;d.addAction(o,s,u,c);return i}};export function createBuoyReduxMiddleware(t={}){const{maxActions:e=200,ignoreActions:r=[]}=t;d.setMaxActions(e);return o=>{p=true;l(o,"middleware");return a=>n=>{const s=n;const i=s.type||"";if(i?.startsWith("@@buoy/")){return a(n)}if(r.includes(i)){return a(n)}const u=performance.now();const c=o.getState();const y=a(n);const f=o.getState();const w=performance.now()-u;d.addAction(s,c,f,w);return y}}}
|
|
@@ -1,142 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Redux History Adapter
|
|
5
|
-
*
|
|
6
|
-
* Wraps the existing reduxActionStore to implement the universal HistoryAdapter interface.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { reduxActionStore } from "./reduxActionStore";
|
|
10
|
-
import { ReduxIcon } from "../components/ReduxIcon";
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Redux adapter capabilities
|
|
14
|
-
* Note: Full time-travel requires the instrument() pattern from redux-devtools.
|
|
15
|
-
* This adapter provides history viewing with basic navigation.
|
|
16
|
-
*/
|
|
17
|
-
const REDUX_CAPABILITIES = {
|
|
18
|
-
timeTravel: false,
|
|
19
|
-
// Would need instrument() for true time travel
|
|
20
|
-
toggle: false,
|
|
21
|
-
// Would need instrument() for skip/toggle
|
|
22
|
-
edit: false,
|
|
23
|
-
diff: true,
|
|
24
|
-
// We have prevState/nextState
|
|
25
|
-
export: true,
|
|
26
|
-
import: false,
|
|
27
|
-
reset: true,
|
|
28
|
-
recording: true
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Convert ReduxAction to HistoryEntry
|
|
33
|
-
*/
|
|
34
|
-
function toHistoryEntry(action, index, _total) {
|
|
35
|
-
return {
|
|
36
|
-
id: action.id,
|
|
37
|
-
label: action.type,
|
|
38
|
-
timestamp: action.timestamp,
|
|
39
|
-
data: action.payload ?? action.action,
|
|
40
|
-
prevState: action.prevState,
|
|
41
|
-
nextState: action.nextState,
|
|
42
|
-
hasStateChange: action.hasStateChange,
|
|
43
|
-
duration: action.duration,
|
|
44
|
-
source: "redux",
|
|
45
|
-
isCurrent: index === 0,
|
|
46
|
-
// Most recent is current
|
|
47
|
-
isInFuture: false,
|
|
48
|
-
isSkipped: false,
|
|
49
|
-
meta: {
|
|
50
|
-
fullAction: action.action
|
|
51
|
-
}
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Options for creating a Redux history adapter
|
|
57
|
-
*/
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Create a Redux history adapter
|
|
61
|
-
*
|
|
62
|
-
* @param options - Optional configuration
|
|
63
|
-
* @returns HistoryAdapter instance
|
|
64
|
-
*/
|
|
65
|
-
export function createReduxHistoryAdapter(options) {
|
|
66
|
-
const {
|
|
67
|
-
icon = ReduxIcon,
|
|
68
|
-
color = "#764ABC",
|
|
69
|
-
// Redux purple
|
|
70
|
-
name = "Redux"
|
|
71
|
-
} = options ?? {};
|
|
72
|
-
let currentIndex = 0;
|
|
73
|
-
const adapter = {
|
|
74
|
-
// === Identity ===
|
|
75
|
-
id: "redux",
|
|
76
|
-
name,
|
|
77
|
-
icon,
|
|
78
|
-
color,
|
|
79
|
-
capabilities: REDUX_CAPABILITIES,
|
|
80
|
-
// === Subscription ===
|
|
81
|
-
subscribe: callback => {
|
|
82
|
-
return reduxActionStore.subscribe(() => {
|
|
83
|
-
callback();
|
|
84
|
-
});
|
|
85
|
-
},
|
|
86
|
-
// === Data Access ===
|
|
87
|
-
getEntries: () => {
|
|
88
|
-
const actions = reduxActionStore.getActions();
|
|
89
|
-
return actions.map((action, index) => toHistoryEntry(action, index, actions.length));
|
|
90
|
-
},
|
|
91
|
-
getEntryCount: () => {
|
|
92
|
-
return reduxActionStore.getActions().length;
|
|
93
|
-
},
|
|
94
|
-
getCurrentState: () => {
|
|
95
|
-
const actions = reduxActionStore.getActions();
|
|
96
|
-
if (actions.length === 0) return undefined;
|
|
97
|
-
// Most recent action's nextState is current state
|
|
98
|
-
return actions[0].nextState;
|
|
99
|
-
},
|
|
100
|
-
getStateAtEntry: entryId => {
|
|
101
|
-
const action = reduxActionStore.getActionById(String(entryId));
|
|
102
|
-
return action?.nextState;
|
|
103
|
-
},
|
|
104
|
-
// === Navigation ===
|
|
105
|
-
get currentIndex() {
|
|
106
|
-
return currentIndex;
|
|
107
|
-
},
|
|
108
|
-
jumpTo: entryId => {
|
|
109
|
-
const actions = reduxActionStore.getActions();
|
|
110
|
-
const index = actions.findIndex(a => a.id === String(entryId));
|
|
111
|
-
if (index !== -1) {
|
|
112
|
-
currentIndex = index;
|
|
113
|
-
// Note: This doesn't actually change app state without instrument()
|
|
114
|
-
// It just updates which entry is "selected" for viewing
|
|
115
|
-
}
|
|
116
|
-
},
|
|
117
|
-
// === Recording ===
|
|
118
|
-
get isRecording() {
|
|
119
|
-
return reduxActionStore.getEnabled();
|
|
120
|
-
},
|
|
121
|
-
setRecording: enabled => {
|
|
122
|
-
reduxActionStore.setEnabled(enabled);
|
|
123
|
-
},
|
|
124
|
-
// === Reset ===
|
|
125
|
-
reset: () => {
|
|
126
|
-
reduxActionStore.clearActions();
|
|
127
|
-
currentIndex = 0;
|
|
128
|
-
},
|
|
129
|
-
// === Export ===
|
|
130
|
-
exportHistory: () => {
|
|
131
|
-
const actions = reduxActionStore.getActions();
|
|
132
|
-
return JSON.stringify(actions, null, 2);
|
|
133
|
-
}
|
|
134
|
-
};
|
|
135
|
-
return adapter;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
-
* Default Redux adapter instance
|
|
140
|
-
* Use this if you only have one Redux store
|
|
141
|
-
*/
|
|
142
|
-
export const reduxHistoryAdapter = createReduxHistoryAdapter();
|
|
1
|
+
"use strict";import{reduxActionStore as r}from"./reduxActionStore";import{ReduxIcon as g}from"../components/ReduxIcon";const l={timeTravel:false,toggle:false,edit:false,diff:true,export:true,import:false,reset:true,recording:true};function p(e,s,a){return{id:e.id,label:e.type,timestamp:e.timestamp,data:e.payload??e.action,prevState:e.prevState,nextState:e.nextState,hasStateChange:e.hasStateChange,duration:e.duration,source:"redux",isCurrent:s===0,isInFuture:false,isSkipped:false,meta:{fullAction:e.action}}}export function createReduxHistoryAdapter(e){const{icon:s=g,color:a="#764ABC",name:u="Redux"}=e??{};let o=0;const c={id:"redux",name:u,icon:s,color:a,capabilities:l,subscribe:t=>{return r.subscribe(()=>{t()})},getEntries:()=>{const t=r.getActions();return t.map((n,i)=>p(n,i,t.length))},getEntryCount:()=>{return r.getActions().length},getCurrentState:()=>{const t=r.getActions();if(t.length===0)return void 0;return t[0].nextState},getStateAtEntry:t=>{const n=r.getActionById(String(t));return n?.nextState},get currentIndex(){return o},jumpTo:t=>{const n=r.getActions();const i=n.findIndex(d=>d.id===String(t));if(i!==-1){o=i}},get isRecording(){return r.getEnabled()},setRecording:t=>{r.setEnabled(t)},reset:()=>{r.clearActions();o=0},exportHistory:()=>{const t=r.getActions();return JSON.stringify(t,null,2)}};return c}export const reduxHistoryAdapter=createReduxHistoryAdapter();
|
|
@@ -1,145 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Store-creation-time capture via the OFFICIAL Redux DevTools hook.
|
|
5
|
-
*
|
|
6
|
-
* `configureStore` defaults `devTools: true` and, at RTK module-evaluation
|
|
7
|
-
* time, snapshots `window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__` if defined.
|
|
8
|
-
* That global doesn't exist in React Native — so Buoy claims it (dev builds
|
|
9
|
-
* only, and only when nothing else has). This makes Buoy a real store
|
|
10
|
-
* ENHANCER, present from the store's birth:
|
|
11
|
-
*
|
|
12
|
-
* - FULL capture: actions dispatched from inside middleware/thunks (RTK
|
|
13
|
-
* `pending`/`fulfilled`/`rejected`, RTK Query) hit our dispatch because the
|
|
14
|
-
* enhancer sits BELOW applyMiddleware in the compose chain.
|
|
15
|
-
* - Real time travel: we wrap the reducer, so BUOY_JUMP_TO_STATE actually
|
|
16
|
-
* jumps — and replaceReducer is re-wrapped, so hosts that inject reducers
|
|
17
|
-
* dynamically keep working.
|
|
18
|
-
* - Nothing is monkey-patched: this is the integration point Redux itself
|
|
19
|
-
* ships for devtools (same one react-native-debugger used).
|
|
20
|
-
*
|
|
21
|
-
* Race note: RTK snapshots the global when ITS module first evaluates, so this
|
|
22
|
-
* module must load before `@reduxjs/toolkit` does. `@buoy-gg/core` requires us
|
|
23
|
-
* at module scope, which usually wins; when it doesn't, the dispatch-patch
|
|
24
|
-
* fallback in autoInstrument.ts still binds at first mount. Apps that want a
|
|
25
|
-
* guarantee put `import '@buoy-gg/redux';` as the FIRST import of their entry.
|
|
26
|
-
*/
|
|
27
|
-
|
|
28
|
-
import { reduxActionStore } from "./reduxActionStore";
|
|
29
|
-
import { BUOY_JUMP_TO_STATE, isMiddlewareActive } from "./buoyReduxMiddleware";
|
|
30
|
-
import { registerActiveStore, markTimeTravelReducer, ENHANCER_SYMBOL } from "./activeStoreRegistry";
|
|
31
|
-
/** Standard redux compose. */
|
|
32
|
-
function composeFns(...funcs) {
|
|
33
|
-
if (funcs.length === 0) return arg => arg;
|
|
34
|
-
if (funcs.length === 1) return funcs[0];
|
|
35
|
-
return funcs.reduce((a, b) => (...args) => a(b(...args)));
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/** Wrap a reducer so BUOY_JUMP_TO_STATE performs a real state jump. */
|
|
39
|
-
function wrapReducer(reducer) {
|
|
40
|
-
// Announce the capability, not just perform it: with nothing wrapped, a jump
|
|
41
|
-
// is dispatched, ignored, and silent — so the UI needs to know in advance
|
|
42
|
-
// whether the button it is drawing can keep its promise.
|
|
43
|
-
markTimeTravelReducer();
|
|
44
|
-
return (state, action) => {
|
|
45
|
-
if (action && action.type === BUOY_JUMP_TO_STATE) {
|
|
46
|
-
return action.payload;
|
|
47
|
-
}
|
|
48
|
-
return reducer(state, action);
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/** Should this action be recorded? (Mirrors autoInstrument's filters.) */
|
|
53
|
-
function isRecordable(action) {
|
|
54
|
-
if (typeof action !== "object" || action === null) return false;
|
|
55
|
-
const type = action.type;
|
|
56
|
-
if (typeof type !== "string") return false;
|
|
57
|
-
return !type.startsWith("@@buoy/") && !type.startsWith("@@redux/");
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* The Buoy store enhancer. Innermost in the compose chain (below
|
|
62
|
-
* applyMiddleware), so every action that reaches the reducer — including ones
|
|
63
|
-
* dispatched from inside middleware and thunks — passes through here.
|
|
64
|
-
*/
|
|
65
|
-
export const buoyDevtoolsEnhancer = createStore => (reducer, preloadedState) => {
|
|
66
|
-
const store = createStore(wrapReducer(reducer), preloadedState);
|
|
67
|
-
const dispatch = action => {
|
|
68
|
-
// If the explicit middleware is installed it already records — the
|
|
69
|
-
// enhancer stays passive to avoid double capture.
|
|
70
|
-
if (!isRecordable(action) || isMiddlewareActive()) {
|
|
71
|
-
return store.dispatch(action);
|
|
72
|
-
}
|
|
73
|
-
const startTime = performance.now();
|
|
74
|
-
const prevState = store.getState();
|
|
75
|
-
const result = store.dispatch(action);
|
|
76
|
-
reduxActionStore.addAction(action, prevState, store.getState(), performance.now() - startTime);
|
|
77
|
-
return result;
|
|
78
|
-
};
|
|
79
|
-
const enhanced = {
|
|
80
|
-
...store,
|
|
81
|
-
dispatch,
|
|
82
|
-
// Keep time travel alive across dynamic reducer injection.
|
|
83
|
-
replaceReducer: next => store.replaceReducer(wrapReducer(next)),
|
|
84
|
-
[ENHANCER_SYMBOL]: true
|
|
85
|
-
};
|
|
86
|
-
registerActiveStore(enhanced, "enhancer");
|
|
87
|
-
return enhanced;
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Implements the `__REDUX_DEVTOOLS_EXTENSION_COMPOSE__` calling conventions:
|
|
92
|
-
* - `compose(options)(...enhancers)` — what RTK's configureStore does
|
|
93
|
-
* - `compose(...enhancers)` — classic createStore usage from the Redux docs
|
|
94
|
-
*/
|
|
95
|
-
function buoyComposeWithDevTools(...args) {
|
|
96
|
-
if (args.length === 0) {
|
|
97
|
-
return composeFns(buoyDevtoolsEnhancer);
|
|
98
|
-
}
|
|
99
|
-
if (args.length === 1 && typeof args[0] === "object" && args[0] !== null) {
|
|
100
|
-
// Options form → return a compose function.
|
|
101
|
-
return (...enhancers) => composeFns(...enhancers, buoyDevtoolsEnhancer);
|
|
102
|
-
}
|
|
103
|
-
return composeFns(...args, buoyDevtoolsEnhancer);
|
|
104
|
-
}
|
|
105
|
-
let claimed = false;
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* Claim the DevTools COMPOSE global — dev builds only, and never over an
|
|
109
|
-
* existing claimant (e.g. the real browser extension on web).
|
|
110
|
-
*
|
|
111
|
-
* Idempotent; runs at module scope so simply importing `@buoy-gg/redux` (which
|
|
112
|
-
* `@buoy-gg/core` does at module scope) performs the claim as early as
|
|
113
|
-
* possible.
|
|
114
|
-
*
|
|
115
|
-
* DO NOT claim `__REDUX_DEVTOOLS_EXTENSION__` here — ever. That global is
|
|
116
|
-
* feature-detected BY PRESENCE by non-redux libraries (zustand's devtools
|
|
117
|
-
* middleware, valtio, jotai-devtools) which then call the extension OBJECT
|
|
118
|
-
* API (`.connect()` etc.) with no shape check. A bare function satisfies only
|
|
119
|
-
* redux's legacy calling convention, so claiming it crashes any host app
|
|
120
|
-
* whose zustand store uses `devtools(...)` — at store-module evaluation, so
|
|
121
|
-
* the app doesn't boot, and the surfaced error is a misleading React
|
|
122
|
-
* "Element type is invalid" from whatever lazy component imports next.
|
|
123
|
-
* (Shipped in 7.0.6/7.0.7; broke a large enterprise app; removed in the next
|
|
124
|
-
* patch.) Absent, all those libraries no-op gracefully. The COMPOSE global is
|
|
125
|
-
* safe because every known consumer CALLS it as a function — that is its
|
|
126
|
-
* whole contract — and it covers the dominant path (RTK's configureStore
|
|
127
|
-
* default). The legacy `createStore(reducer, __REDUX_DEVTOOLS_EXTENSION__())`
|
|
128
|
-
* pattern simply falls back to Buoy's dispatch-patch instrumentation.
|
|
129
|
-
*/
|
|
130
|
-
export function claimDevtoolsHook() {
|
|
131
|
-
const isDev = typeof __DEV__ !== "undefined" && __DEV__;
|
|
132
|
-
if (!isDev) return false;
|
|
133
|
-
const g = globalThis;
|
|
134
|
-
if (!g.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__) {
|
|
135
|
-
g.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ = buoyComposeWithDevTools;
|
|
136
|
-
claimed = true;
|
|
137
|
-
}
|
|
138
|
-
return claimed;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
/** Whether Buoy owns the DevTools compose global (i.e. won the load race). */
|
|
142
|
-
export function isDevtoolsHookClaimed() {
|
|
143
|
-
return claimed;
|
|
144
|
-
}
|
|
145
|
-
claimDevtoolsHook();
|
|
1
|
+
"use strict";import{reduxActionStore as d}from"./reduxActionStore";import{BUOY_JUMP_TO_STATE as a,isMiddlewareActive as m}from"./buoyReduxMiddleware";import{registerActiveStore as E,markTimeTravelReducer as h,ENHANCER_SYMBOL as O}from"./activeStoreRegistry";function u(...e){if(e.length===0)return t=>t;if(e.length===1)return e[0];return e.reduce((t,r)=>(...o)=>t(r(...o)))}function c(e){h();return(t,r)=>{if(r&&r.type===a){return r.payload}return e(t,r)}}function S(e){if(typeof e!=="object"||e===null)return false;const t=e.type;if(typeof t!=="string")return false;return!t.startsWith("@@buoy/")&&!t.startsWith("@@redux/")}export const buoyDevtoolsEnhancer=e=>(t,r)=>{const o=e(c(t),r);const l=n=>{if(!S(n)||m()){return o.dispatch(n)}const f=performance.now();const _=o.getState();const p=o.dispatch(n);d.addAction(n,_,o.getState(),performance.now()-f);return p};const s={...o,dispatch:l,replaceReducer:n=>o.replaceReducer(c(n)),[O]:true};E(s,"enhancer");return s};function T(...e){if(e.length===0){return u(buoyDevtoolsEnhancer)}if(e.length===1&&typeof e[0]==="object"&&e[0]!==null){return(...t)=>u(...t,buoyDevtoolsEnhancer)}return u(...e,buoyDevtoolsEnhancer)}let i=false;export function claimDevtoolsHook(){const e=typeof __DEV__!=="undefined"&&__DEV__;if(!e)return false;const t=globalThis;if(!t.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__){t.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__=T;i=true}return i}export function isDevtoolsHookClaimed(){return i}claimDevtoolsHook();
|