@buoy-gg/redux 7.0.33 → 7.0.35
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/lib/commonjs/preset.js +14 -22
- package/lib/commonjs/redux/components/ReduxActionButton.js +1 -1
- package/lib/commonjs/redux/components/ReduxActionDetailContent.js +5 -5
- package/lib/commonjs/redux/components/ReduxActionDetailView.js +3 -3
- package/lib/commonjs/redux/components/ReduxActionInfoView.js +16 -68
- package/lib/commonjs/redux/components/ReduxActionItem.js +65 -119
- package/lib/commonjs/redux/components/ReduxDetailViewToggle.js +15 -109
- package/lib/commonjs/redux/components/ReduxModal.js +25 -70
- package/lib/commonjs/redux/hooks/useReduxActions.js +16 -33
- package/lib/commonjs/redux/sync/reduxSyncAdapter.js +11 -29
- package/lib/commonjs/redux/utils/reduxActionStore.js +24 -94
- package/lib/commonjs/redux/utils/snapshotProvider.js +17 -80
- package/lib/module/preset.js +13 -20
- package/lib/module/redux/components/ReduxActionButton.js +2 -2
- package/lib/module/redux/components/ReduxActionDetailContent.js +6 -6
- package/lib/module/redux/components/ReduxActionDetailView.js +4 -4
- package/lib/module/redux/components/ReduxActionInfoView.js +9 -61
- package/lib/module/redux/components/ReduxActionItem.js +66 -120
- package/lib/module/redux/components/ReduxDetailViewToggle.js +17 -111
- package/lib/module/redux/components/ReduxModal.js +27 -72
- package/lib/module/redux/hooks/useReduxActions.js +17 -34
- package/lib/module/redux/sync/reduxSyncAdapter.js +12 -30
- package/lib/module/redux/utils/reduxActionStore.js +25 -95
- package/lib/module/redux/utils/snapshotProvider.js +18 -81
- package/lib/typescript/preset.d.ts +3 -9
- package/lib/typescript/preset.d.ts.map +1 -1
- package/lib/typescript/redux/components/ReduxActionDetailContent.d.ts.map +1 -1
- package/lib/typescript/redux/components/ReduxActionDetailView.d.ts.map +1 -1
- package/lib/typescript/redux/components/ReduxActionInfoView.d.ts.map +1 -1
- package/lib/typescript/redux/components/ReduxActionItem.d.ts.map +1 -1
- package/lib/typescript/redux/components/ReduxDetailViewToggle.d.ts +2 -1
- package/lib/typescript/redux/components/ReduxDetailViewToggle.d.ts.map +1 -1
- package/lib/typescript/redux/components/ReduxModal.d.ts.map +1 -1
- package/lib/typescript/redux/hooks/useReduxActions.d.ts +3 -0
- package/lib/typescript/redux/hooks/useReduxActions.d.ts.map +1 -1
- package/lib/typescript/redux/sync/reduxSyncAdapter.d.ts +68 -82
- package/lib/typescript/redux/sync/reduxSyncAdapter.d.ts.map +1 -1
- package/lib/typescript/redux/utils/reduxActionStore.d.ts +2 -29
- package/lib/typescript/redux/utils/reduxActionStore.d.ts.map +1 -1
- package/package.json +4 -4
|
@@ -1,22 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
import { reduxActionStore, STATE_ON_DEVICE, PAYLOAD_ON_DEVICE, isEvictedState } from "../utils/reduxActionStore";
|
|
4
|
-
import {
|
|
4
|
+
import { WIRE_DETAIL_LIMIT_BYTES, capDetail, createSyncAdapter, memoByIdentity, readParams, toWire } from "@buoy-gg/shared-ui";
|
|
5
5
|
import { getActiveStore, getInstrumentationStatus } from "../utils/autoInstrument";
|
|
6
6
|
|
|
7
|
-
/**
|
|
8
|
-
* Upper bound for one on-demand action-detail response. Generous — this is a
|
|
9
|
-
* single explicit fetch, not a per-action stream — but still guarded so a
|
|
10
|
-
* pathological tree can't OOM the device through the reply emit.
|
|
11
|
-
*/
|
|
12
|
-
const MAX_ACTION_DETAIL_BYTES = 8 * 1024 * 1024;
|
|
13
|
-
|
|
14
7
|
/** Per-action budget for `payload`/`action`/`meta.arg`/`error` on the snapshot wire. */
|
|
15
|
-
const
|
|
16
|
-
function toWireValue(value) {
|
|
17
|
-
if (value === undefined) return value;
|
|
18
|
-
return isOverWireBudget(value, MAX_WIRE_PAYLOAD_BYTES) ? PAYLOAD_ON_DEVICE : value;
|
|
19
|
-
}
|
|
8
|
+
const toWireValue = value => toWire(value, PAYLOAD_ON_DEVICE);
|
|
20
9
|
|
|
21
10
|
/**
|
|
22
11
|
* Per-action wire cache. `reduxActionStore` never mutates an action in place —
|
|
@@ -25,10 +14,7 @@ function toWireValue(value) {
|
|
|
25
14
|
* `action`, `meta.arg` and `error` in the list is re-measured on all ~5
|
|
26
15
|
* snapshots per second for as long as it stays in the list.
|
|
27
16
|
*/
|
|
28
|
-
const
|
|
29
|
-
function toWireAction(a) {
|
|
30
|
-
const cached = wireCache.get(a);
|
|
31
|
-
if (cached) return cached;
|
|
17
|
+
const toWireAction = memoByIdentity(a => {
|
|
32
18
|
const wire = isEvictedState(a.prevState) ? {
|
|
33
19
|
...a
|
|
34
20
|
} : {
|
|
@@ -51,9 +37,8 @@ function toWireAction(a) {
|
|
|
51
37
|
arg
|
|
52
38
|
};
|
|
53
39
|
}
|
|
54
|
-
wireCache.set(a, wire);
|
|
55
40
|
return wire;
|
|
56
|
-
}
|
|
41
|
+
});
|
|
57
42
|
/** Top-level slice names of the state tree, for the compact (no-values) view. */
|
|
58
43
|
function topLevelKeys(state) {
|
|
59
44
|
return state && typeof state === "object" && !Array.isArray(state) ? Object.keys(state) : [];
|
|
@@ -90,7 +75,7 @@ function unavailable() {
|
|
|
90
75
|
* dispatch actions — redux is action-based, so the *current state* isn't in the
|
|
91
76
|
* action-log snapshot.
|
|
92
77
|
*/
|
|
93
|
-
export const reduxSyncAdapter = {
|
|
78
|
+
export const reduxSyncAdapter = createSyncAdapter({
|
|
94
79
|
version: 2,
|
|
95
80
|
/**
|
|
96
81
|
* WIRE-FORM snapshot: actions WITHOUT raw prevState/nextState trees.
|
|
@@ -115,7 +100,7 @@ export const reduxSyncAdapter = {
|
|
|
115
100
|
getActionDetail: params => {
|
|
116
101
|
const {
|
|
117
102
|
id
|
|
118
|
-
} = params
|
|
103
|
+
} = readParams(params);
|
|
119
104
|
if (!id) return {
|
|
120
105
|
found: false,
|
|
121
106
|
reason: "missing id"
|
|
@@ -135,11 +120,7 @@ export const reduxSyncAdapter = {
|
|
|
135
120
|
}
|
|
136
121
|
// Per-field cap: oversized fields degrade individually instead of
|
|
137
122
|
// failing the whole detail (a giant payload shouldn't hide the trees).
|
|
138
|
-
const
|
|
139
|
-
__buoyTruncated: true,
|
|
140
|
-
note: `Exceeds the ${MAX_ACTION_DETAIL_BYTES / (1024 * 1024)}MB detail limit — inspect it on-device.`
|
|
141
|
-
};
|
|
142
|
-
const cap = value => isOverWireBudget(value, MAX_ACTION_DETAIL_BYTES) ? cappedNote : value;
|
|
123
|
+
const cap = value => capDetail(value, WIRE_DETAIL_LIMIT_BYTES);
|
|
143
124
|
const capMeta = meta => {
|
|
144
125
|
if (!meta) return meta;
|
|
145
126
|
const arg = cap(meta.arg);
|
|
@@ -166,7 +147,7 @@ export const reduxSyncAdapter = {
|
|
|
166
147
|
getState: params => {
|
|
167
148
|
const {
|
|
168
149
|
includeValues = false
|
|
169
|
-
} = params
|
|
150
|
+
} = readParams(params);
|
|
170
151
|
const store = getActiveStore();
|
|
171
152
|
if (!store) {
|
|
172
153
|
return unavailable();
|
|
@@ -188,7 +169,7 @@ export const reduxSyncAdapter = {
|
|
|
188
169
|
dispatch: params => {
|
|
189
170
|
const {
|
|
190
171
|
action
|
|
191
|
-
} = params;
|
|
172
|
+
} = readParams(params);
|
|
192
173
|
const store = getActiveStore();
|
|
193
174
|
if (!store) {
|
|
194
175
|
return {
|
|
@@ -196,11 +177,12 @@ export const reduxSyncAdapter = {
|
|
|
196
177
|
...unavailable()
|
|
197
178
|
};
|
|
198
179
|
}
|
|
180
|
+
if (!action) throw new Error("dispatch requires an `action`");
|
|
199
181
|
store.dispatch(action);
|
|
200
182
|
return {
|
|
201
183
|
dispatched: true,
|
|
202
|
-
type: action
|
|
184
|
+
type: action.type
|
|
203
185
|
};
|
|
204
186
|
}
|
|
205
187
|
}
|
|
206
|
-
};
|
|
188
|
+
});
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Redux action store - captures and stores Redux Toolkit actions
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { approxJsonSize } from "@buoy-gg/shared-ui";
|
|
7
|
+
import { ChangeLog, approxJsonSize } from "@buoy-gg/shared-ui";
|
|
8
8
|
/**
|
|
9
9
|
* How many of the most-recent actions keep their raw prevState/nextState
|
|
10
10
|
* trees. Older actions keep all diff metadata but their trees are replaced
|
|
@@ -230,16 +230,9 @@ function extractMeta(action) {
|
|
|
230
230
|
// Redux Action Store
|
|
231
231
|
// ============================================
|
|
232
232
|
|
|
233
|
-
class ReduxActionStore {
|
|
234
|
-
actions = [];
|
|
235
|
-
listeners = new Set();
|
|
236
|
-
clearListeners = new Set();
|
|
237
|
-
maxActions = 200;
|
|
238
|
-
idCounter = 0;
|
|
239
|
-
isEnabled = true;
|
|
240
|
-
captureSuppressed = false;
|
|
233
|
+
class ReduxActionStore extends ChangeLog {
|
|
241
234
|
addAction(action, prevState, nextState, duration) {
|
|
242
|
-
if (!this.
|
|
235
|
+
if (!this.canRecord()) {
|
|
243
236
|
return;
|
|
244
237
|
}
|
|
245
238
|
const actionType = action.type || "";
|
|
@@ -265,7 +258,7 @@ class ReduxActionStore {
|
|
|
265
258
|
const isSlowAction = (duration ?? 0) > 16; // Frame budget
|
|
266
259
|
|
|
267
260
|
const reduxAction = {
|
|
268
|
-
id:
|
|
261
|
+
id: this.nextId(),
|
|
269
262
|
type: actionType,
|
|
270
263
|
payload: action.payload,
|
|
271
264
|
action,
|
|
@@ -285,7 +278,7 @@ class ReduxActionStore {
|
|
|
285
278
|
changedKeysCount,
|
|
286
279
|
isSlowAction
|
|
287
280
|
};
|
|
288
|
-
this.
|
|
281
|
+
this.push(reduxAction);
|
|
289
282
|
|
|
290
283
|
// Bound raw-state retention. Every action holds prevState/nextState by
|
|
291
284
|
// reference; with structural sharing that's normally cheap, but when a
|
|
@@ -294,8 +287,8 @@ class ReduxActionStore {
|
|
|
294
287
|
// pinned by 50 slice-replacing actions, enough to OOM-kill enterprise
|
|
295
288
|
// apps. Detail view + time travel realistically use recent actions, so
|
|
296
289
|
// older ones keep their diff metadata but drop the raw trees.
|
|
297
|
-
for (let i = STATE_RETENTION_LIMIT; i < this.
|
|
298
|
-
const a = this.
|
|
290
|
+
for (let i = STATE_RETENTION_LIMIT; i < this.items.length; i++) {
|
|
291
|
+
const a = this.items[i];
|
|
299
292
|
if (a.prevState !== STATE_EVICTED) {
|
|
300
293
|
a.prevState = STATE_EVICTED;
|
|
301
294
|
a.nextState = STATE_EVICTED;
|
|
@@ -306,63 +299,26 @@ class ReduxActionStore {
|
|
|
306
299
|
this.notifyListeners();
|
|
307
300
|
}
|
|
308
301
|
getActions() {
|
|
309
|
-
return
|
|
302
|
+
return this.getAll();
|
|
310
303
|
}
|
|
311
304
|
getActionById(id) {
|
|
312
|
-
return this.
|
|
305
|
+
return this.getById(id);
|
|
313
306
|
}
|
|
314
307
|
clearActions() {
|
|
315
|
-
this.
|
|
316
|
-
this.notifyListeners();
|
|
317
|
-
this.clearListeners.forEach(listener => {
|
|
318
|
-
try {
|
|
319
|
-
listener();
|
|
320
|
-
} catch {
|
|
321
|
-
// Ignore listener errors
|
|
322
|
-
}
|
|
323
|
-
});
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
/**
|
|
327
|
-
* Listen for clearActions() calls. Used in remote mirror mode to forward a
|
|
328
|
-
* clear performed in the dashboard UI to the synced device.
|
|
329
|
-
*/
|
|
330
|
-
onClear(listener) {
|
|
331
|
-
this.clearListeners.add(listener);
|
|
332
|
-
return () => {
|
|
333
|
-
this.clearListeners.delete(listener);
|
|
334
|
-
};
|
|
308
|
+
this.clear();
|
|
335
309
|
}
|
|
336
310
|
|
|
337
311
|
// ============================================
|
|
338
312
|
// Remote Mirror Mode
|
|
339
313
|
// ============================================
|
|
340
314
|
|
|
341
|
-
/**
|
|
342
|
-
* Permanently suppress local capture. Use when this store acts as a mirror
|
|
343
|
-
* of a remote device's actions (e.g. the desktop dashboard): actions arrive
|
|
344
|
-
* via replaceActions() and local instrumentation must never record.
|
|
345
|
-
*/
|
|
346
|
-
disableCapture() {
|
|
347
|
-
this.captureSuppressed = true;
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
/**
|
|
351
|
-
* Whether the store is in remote mirror mode (capture suppressed). The UI
|
|
352
|
-
* uses this to skip local-instrumentation affordances like the
|
|
353
|
-
* "react-redux not installed" banner.
|
|
354
|
-
*/
|
|
355
|
-
isCaptureSuppressed() {
|
|
356
|
-
return this.captureSuppressed;
|
|
357
|
-
}
|
|
358
|
-
|
|
359
315
|
/**
|
|
360
316
|
* Replace the entire action list and notify listeners. Used in remote
|
|
361
317
|
* mirror mode where full snapshots arrive from a synced device. Respects
|
|
362
318
|
* the enabled flag so the UI's pause button freezes the mirror.
|
|
363
319
|
*/
|
|
364
320
|
replaceActions(actions) {
|
|
365
|
-
if (!this.
|
|
321
|
+
if (!this.getEnabled()) {
|
|
366
322
|
return;
|
|
367
323
|
}
|
|
368
324
|
// Preserve any trees a remote mirror already hydrated via
|
|
@@ -370,12 +326,12 @@ class ReduxActionStore {
|
|
|
370
326
|
// full snapshot arriving after a detail fetch must not blank the detail
|
|
371
327
|
// pane back out.
|
|
372
328
|
const hydrated = new Map();
|
|
373
|
-
for (const existing of this.
|
|
329
|
+
for (const existing of this.items) {
|
|
374
330
|
if (existing.prevState !== undefined && !isEvictedState(existing.prevState)) {
|
|
375
331
|
hydrated.set(existing.id, existing);
|
|
376
332
|
}
|
|
377
333
|
}
|
|
378
|
-
|
|
334
|
+
const merged = actions.slice(0, this.max).map(a => {
|
|
379
335
|
const h = hydrated.get(a.id);
|
|
380
336
|
if (!h || !isEvictedState(a.prevState)) return a;
|
|
381
337
|
return {
|
|
@@ -388,7 +344,7 @@ class ReduxActionStore {
|
|
|
388
344
|
error: isPayloadOnDevice(a.error) ? h.error : a.error
|
|
389
345
|
};
|
|
390
346
|
});
|
|
391
|
-
this.
|
|
347
|
+
this.setItems(merged);
|
|
392
348
|
}
|
|
393
349
|
|
|
394
350
|
/**
|
|
@@ -397,44 +353,18 @@ class ReduxActionStore {
|
|
|
397
353
|
* `getActionDetail` action. Remote-mirror (desktop) use only.
|
|
398
354
|
*/
|
|
399
355
|
hydrateAction(id, patch) {
|
|
400
|
-
|
|
401
|
-
if (index === -1) return;
|
|
402
|
-
this.actions = [...this.actions.slice(0, index), {
|
|
403
|
-
...this.actions[index],
|
|
404
|
-
...patch
|
|
405
|
-
}, ...this.actions.slice(index + 1)];
|
|
406
|
-
this.notifyListeners();
|
|
407
|
-
}
|
|
408
|
-
setEnabled(enabled) {
|
|
409
|
-
this.isEnabled = enabled;
|
|
410
|
-
}
|
|
411
|
-
getEnabled() {
|
|
412
|
-
return this.isEnabled;
|
|
413
|
-
}
|
|
414
|
-
subscribe(listener) {
|
|
415
|
-
this.listeners.add(listener);
|
|
416
|
-
return () => {
|
|
417
|
-
this.listeners.delete(listener);
|
|
418
|
-
};
|
|
419
|
-
}
|
|
420
|
-
notifyListeners() {
|
|
421
|
-
const actions = this.getActions();
|
|
422
|
-
this.listeners.forEach(listener => listener(actions));
|
|
356
|
+
this.hydrateById(id, patch);
|
|
423
357
|
}
|
|
424
358
|
setMaxActions(max) {
|
|
425
|
-
this.
|
|
426
|
-
if (this.actions.length > max) {
|
|
427
|
-
this.actions = this.actions.slice(0, max);
|
|
428
|
-
this.notifyListeners();
|
|
429
|
-
}
|
|
359
|
+
this.setMax(max);
|
|
430
360
|
}
|
|
431
361
|
getStats() {
|
|
432
|
-
const total = this.
|
|
433
|
-
const withChanges = this.
|
|
434
|
-
const actionTypes = new Set(this.
|
|
362
|
+
const total = this.items.length;
|
|
363
|
+
const withChanges = this.items.filter(a => a.hasStateChange).length;
|
|
364
|
+
const actionTypes = new Set(this.items.map(a => a.type));
|
|
435
365
|
|
|
436
366
|
// Calculate average duration
|
|
437
|
-
const durations = this.
|
|
367
|
+
const durations = this.items.filter(a => a.duration !== undefined).map(a => a.duration);
|
|
438
368
|
const avgDuration = durations.length > 0 ? durations.reduce((sum, d) => sum + d, 0) / durations.length : 0;
|
|
439
369
|
return {
|
|
440
370
|
totalActions: total,
|
|
@@ -445,7 +375,7 @@ class ReduxActionStore {
|
|
|
445
375
|
};
|
|
446
376
|
}
|
|
447
377
|
filterActions(filter) {
|
|
448
|
-
let filtered = [...this.
|
|
378
|
+
let filtered = [...this.items];
|
|
449
379
|
if (filter.searchText) {
|
|
450
380
|
const search = filter.searchText.toLowerCase();
|
|
451
381
|
filtered = filtered.filter(a => a.type.toLowerCase().includes(search));
|
|
@@ -459,14 +389,14 @@ class ReduxActionStore {
|
|
|
459
389
|
return filtered;
|
|
460
390
|
}
|
|
461
391
|
getUniqueActionTypes() {
|
|
462
|
-
return Array.from(new Set(this.
|
|
392
|
+
return Array.from(new Set(this.items.map(a => a.type))).sort();
|
|
463
393
|
}
|
|
464
394
|
|
|
465
395
|
/**
|
|
466
396
|
* Find related async actions by requestId
|
|
467
397
|
*/
|
|
468
398
|
getRelatedActions(requestId) {
|
|
469
|
-
return this.
|
|
399
|
+
return this.items.filter(a => a.meta?.requestId === requestId).sort((a, b) => a.timestamp - b.timestamp); // Sort chronologically
|
|
470
400
|
}
|
|
471
401
|
|
|
472
402
|
/**
|
|
@@ -482,7 +412,7 @@ class ReduxActionStore {
|
|
|
482
412
|
*/
|
|
483
413
|
getLinkedActionsCount(action) {
|
|
484
414
|
if (!action.meta?.requestId) return 0;
|
|
485
|
-
return this.
|
|
415
|
+
return this.items.filter(a => a.meta?.requestId === action.meta?.requestId).length;
|
|
486
416
|
}
|
|
487
417
|
|
|
488
418
|
/**
|
|
@@ -520,7 +450,7 @@ class ReduxActionStore {
|
|
|
520
450
|
getAsyncOperationIndex(requestId) {
|
|
521
451
|
// Get all unique requestIds with their first timestamp
|
|
522
452
|
const requestIdTimestamps = new Map();
|
|
523
|
-
for (const action of this.
|
|
453
|
+
for (const action of this.items) {
|
|
524
454
|
if (action.meta?.requestId && !requestIdTimestamps.has(action.meta.requestId)) {
|
|
525
455
|
requestIdTimestamps.set(action.meta.requestId, action.timestamp);
|
|
526
456
|
}
|
|
@@ -14,8 +14,7 @@
|
|
|
14
14
|
* object itself).
|
|
15
15
|
* - patch path: never handled; restore is reported as unavailable up front.
|
|
16
16
|
*/
|
|
17
|
-
import { registerStateSnapshotProvider } from "@buoy-gg/shared-ui";
|
|
18
|
-
import { boundedDeepEqual, jsonLikelyLargerThan } from "@buoy-gg/shared-ui/dataViewer";
|
|
17
|
+
import { classifyPreviewItem, createRestoreScope, registerStateSnapshotProvider, skippedRestore, unionKeys, wontApply } from "@buoy-gg/shared-ui";
|
|
19
18
|
import { getActiveStore, getInstrumentationStatus } from "./activeStoreRegistry";
|
|
20
19
|
import { BUOY_JUMP_TO_STATE } from "./buoyReduxMiddleware";
|
|
21
20
|
const ENABLE_HINT = "enable restore by using the Buoy enhancer or wrapping your root reducer in withBuoyDevTools()";
|
|
@@ -64,36 +63,19 @@ async function restore(data, options) {
|
|
|
64
63
|
const snapshot = data;
|
|
65
64
|
const store = getActiveStore();
|
|
66
65
|
if (!store || snapshot === undefined || snapshot === null) {
|
|
67
|
-
return
|
|
68
|
-
ok: false,
|
|
69
|
-
applied: 0,
|
|
70
|
-
skipped: [{
|
|
71
|
-
id: "redux",
|
|
72
|
-
reason: store ? "empty redux snapshot" : "no Redux store instrumented"
|
|
73
|
-
}],
|
|
74
|
-
warnings: []
|
|
75
|
-
};
|
|
66
|
+
return skippedRestore("redux", store ? "empty redux snapshot" : "no Redux store instrumented");
|
|
76
67
|
}
|
|
77
68
|
const {
|
|
78
69
|
mechanism
|
|
79
70
|
} = getInstrumentationStatus();
|
|
80
71
|
if (mechanism === "patch") {
|
|
81
|
-
return {
|
|
82
|
-
ok: false,
|
|
83
|
-
applied: 0,
|
|
84
|
-
skipped: [{
|
|
85
|
-
id: "redux",
|
|
86
|
-
reason: `restore unavailable on auto-instrumented stores — ${ENABLE_HINT}`
|
|
87
|
-
}],
|
|
88
|
-
warnings: []
|
|
89
|
-
};
|
|
72
|
+
return skippedRestore("redux", `restore unavailable on auto-instrumented stores — ${ENABLE_HINT}`);
|
|
90
73
|
}
|
|
91
74
|
// Untouched slices keep their LIVE values inside the jump payload, so the
|
|
92
75
|
// full-state replace leaves them alone. A slice is untouched when it's
|
|
93
76
|
// explicitly excluded OR outside the includeKeys scope.
|
|
94
|
-
const
|
|
95
|
-
const
|
|
96
|
-
const excluded = Object.keys(snapshot.state ?? {}).filter(k => excludedSet.has(k) || includedSet && !includedSet.has(k));
|
|
77
|
+
const scope = createRestoreScope(options);
|
|
78
|
+
const excluded = Object.keys(snapshot.state ?? {}).filter(k => !scope.touch(k));
|
|
97
79
|
let payload = snapshot.state;
|
|
98
80
|
if (excluded.length > 0) {
|
|
99
81
|
const live = store.getState();
|
|
@@ -119,17 +101,8 @@ async function restore(data, options) {
|
|
|
119
101
|
warnings
|
|
120
102
|
};
|
|
121
103
|
}
|
|
122
|
-
return {
|
|
123
|
-
ok: false,
|
|
124
|
-
applied: 0,
|
|
125
|
-
skipped: [{
|
|
126
|
-
id: "redux",
|
|
127
|
-
reason: `store ignored the state jump — ${ENABLE_HINT}`
|
|
128
|
-
}],
|
|
129
|
-
warnings: []
|
|
130
|
-
};
|
|
104
|
+
return skippedRestore("redux", `store ignored the state jump — ${ENABLE_HINT}`);
|
|
131
105
|
}
|
|
132
|
-
const ITEM_RENDER_BYTE_LIMIT = 256 * 1024;
|
|
133
106
|
|
|
134
107
|
/** Per-slice restore preview. `base` omitted = compare against the live store. */
|
|
135
108
|
async function previewItems(target, base) {
|
|
@@ -154,54 +127,18 @@ async function previewItems(target, base) {
|
|
|
154
127
|
}
|
|
155
128
|
const oldObj = baseState ?? {};
|
|
156
129
|
const newObj = targetState ?? {};
|
|
157
|
-
const
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
} else if (!inOld) {
|
|
170
|
-
item = {
|
|
171
|
-
key,
|
|
172
|
-
label: key,
|
|
173
|
-
verdict: "added",
|
|
174
|
-
newValue: newObj[key]
|
|
175
|
-
};
|
|
176
|
-
} else if (boundedDeepEqual(oldObj[key], newObj[key])) {
|
|
177
|
-
item = {
|
|
178
|
-
key,
|
|
179
|
-
label: key,
|
|
180
|
-
verdict: "unchanged"
|
|
181
|
-
};
|
|
182
|
-
} else if (jsonLikelyLargerThan(oldObj[key], ITEM_RENDER_BYTE_LIMIT) || jsonLikelyLargerThan(newObj[key], ITEM_RENDER_BYTE_LIMIT)) {
|
|
183
|
-
item = {
|
|
184
|
-
key,
|
|
185
|
-
label: key,
|
|
186
|
-
verdict: "too-large",
|
|
187
|
-
reason: "slice too large to render a diff — restore still applies it"
|
|
188
|
-
};
|
|
189
|
-
} else {
|
|
190
|
-
item = {
|
|
191
|
-
key,
|
|
192
|
-
label: key,
|
|
193
|
-
verdict: "changed",
|
|
194
|
-
oldValue: oldObj[key],
|
|
195
|
-
newValue: newObj[key]
|
|
196
|
-
};
|
|
197
|
-
}
|
|
198
|
-
if (wontApplyReason && item.verdict !== "unchanged") {
|
|
199
|
-
item = {
|
|
200
|
-
...item,
|
|
201
|
-
verdict: "wont-apply",
|
|
202
|
-
reason: wontApplyReason
|
|
203
|
-
};
|
|
204
|
-
}
|
|
130
|
+
for (const key of unionKeys(oldObj, newObj)) {
|
|
131
|
+
let item = classifyPreviewItem({
|
|
132
|
+
key,
|
|
133
|
+
label: key,
|
|
134
|
+
oldValue: oldObj[key],
|
|
135
|
+
newValue: newObj[key],
|
|
136
|
+
inOld: Object.prototype.hasOwnProperty.call(oldObj, key),
|
|
137
|
+
inNew: Object.prototype.hasOwnProperty.call(newObj, key)
|
|
138
|
+
}, {
|
|
139
|
+
tooLargeReason: "slice too large to render a diff — restore still applies it"
|
|
140
|
+
});
|
|
141
|
+
if (wontApplyReason) item = wontApply(item, wontApplyReason);
|
|
205
142
|
items.push(item);
|
|
206
143
|
}
|
|
207
144
|
if (wontApplyReason) notes.push(`Redux restore unavailable: ${wontApplyReason}`);
|
|
@@ -65,18 +65,12 @@ export declare const reduxToolPreset: {
|
|
|
65
65
|
* });
|
|
66
66
|
* ```
|
|
67
67
|
*/
|
|
68
|
-
export declare
|
|
69
|
-
/**
|
|
70
|
-
name?: string;
|
|
71
|
-
/** Tool description */
|
|
72
|
-
description?: string;
|
|
73
|
-
/** Custom tool ID (default: "redux") */
|
|
74
|
-
id?: string;
|
|
75
|
-
/** Icon color (default: Redux purple #764ABC) */
|
|
68
|
+
export declare const createReduxTool: (options?: ({
|
|
69
|
+
/** Icon color */
|
|
76
70
|
iconColor?: string;
|
|
77
71
|
/** Enable shared modal dimensions */
|
|
78
72
|
enableSharedModalDimensions?: boolean;
|
|
79
|
-
})
|
|
73
|
+
} & import("@buoy-gg/shared-ui").ToolPresetOverrides) | undefined) => {
|
|
80
74
|
id: string;
|
|
81
75
|
name: string;
|
|
82
76
|
description: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"preset.d.ts","sourceRoot":"","sources":["../../src/preset.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"preset.d.ts","sourceRoot":"","sources":["../../src/preset.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAI3D;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe;;;;;qBAKT;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE;;;;;CAKjC,CAAC;AAEH;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,eAAe;IAGxB,iBAAiB;gBACL,MAAM;IAClB,qCAAqC;kCACP,OAAO;;;;;;qBA3BtB;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE;;;;;CAoClC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ReduxActionDetailContent.d.ts","sourceRoot":"","sources":["../../../../src/redux/components/ReduxActionDetailContent.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;
|
|
1
|
+
{"version":3,"file":"ReduxActionDetailContent.d.ts","sourceRoot":"","sources":["../../../../src/redux/components/ReduxActionDetailContent.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAmBH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,EAEL,KAAK,mBAAmB,EACzB,MAAM,yBAAyB,CAAC;AASjC,UAAU,6BAA6B;IACrC,qCAAqC;IACrC,MAAM,EAAE,WAAW,CAAC;IACpB,iCAAiC;IACjC,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,qCAAqC;IACrC,aAAa,EAAE,MAAM,CAAC;IACtB,kCAAkC;IAClC,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,iDAAiD;IACjD,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC;;;;;OAKG;IACH,WAAW,CAAC,EAAE,mBAAmB,CAAC;CACnC;AAwDD,wBAAgB,wBAAwB,CAAC,EACvC,MAAM,EACN,OAAO,EACP,aAAa,EACb,aAAa,EACb,qBAA6B,EAC7B,WAAsB,GACvB,EAAE,6BAA6B,+BA+P/B;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,EACtC,MAAM,EACN,OAAO,EACP,aAAa,EACb,aAAa,GACd,EAAE;IACD,MAAM,EAAE,WAAW,CAAC;IACpB,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACxC,sCAiBA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ReduxActionDetailView.d.ts","sourceRoot":"","sources":["../../../../src/redux/components/ReduxActionDetailView.tsx"],"names":[],"mappings":"AAAA;;GAEG;
|
|
1
|
+
{"version":3,"file":"ReduxActionDetailView.d.ts","sourceRoot":"","sources":["../../../../src/redux/components/ReduxActionDetailView.tsx"],"names":[],"mappings":"AAAA;;GAEG;AAaH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAE5C,UAAU,0BAA0B;IAClC,MAAM,EAAE,WAAW,CAAC;CACrB;AAID,wBAAgB,qBAAqB,CAAC,EAAE,MAAM,EAAE,EAAE,0BAA0B,+BAkH3E"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ReduxActionInfoView.d.ts","sourceRoot":"","sources":["../../../../src/redux/components/ReduxActionInfoView.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAA0D,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"ReduxActionInfoView.d.ts","sourceRoot":"","sources":["../../../../src/redux/components/ReduxActionInfoView.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAA0D,MAAM,OAAO,CAAC;AAqB/E,OAAO,KAAK,EAAE,WAAW,EAAkB,MAAM,UAAU,CAAC;AAU5D,UAAU,wBAAwB;IAChC,MAAM,EAAE,WAAW,CAAC;IACpB,kBAAkB,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,IAAI,CAAC;CACpD;AAsGD,eAAO,MAAM,mBAAmB,sDAsgB9B,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
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;IACvC;;;;;;;OAOG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAmKD,eAAO,MAAM,eAAe,
|
|
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;IACvC;;;;;;;OAOG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAmKD,eAAO,MAAM,eAAe,4DAqF1B,CAAC"}
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
* ReduxDetailViewToggle
|
|
3
3
|
*
|
|
4
4
|
* Three-card toggle for switching between Action, State, and Diff views.
|
|
5
|
-
*
|
|
5
|
+
* The cards themselves are the shared `DetailViewToggle`; this file owns
|
|
6
|
+
* the redux view list and testID prefix.
|
|
6
7
|
*/
|
|
7
8
|
import React from "react";
|
|
8
9
|
export type ReduxDetailViewMode = "action" | "state" | "diff";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ReduxDetailViewToggle.d.ts","sourceRoot":"","sources":["../../../../src/redux/components/ReduxDetailViewToggle.tsx"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"ReduxDetailViewToggle.d.ts","sourceRoot":"","sources":["../../../../src/redux/components/ReduxDetailViewToggle.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAe,MAAM,OAAO,CAAC;AASpC,MAAM,MAAM,mBAAmB,GAAG,QAAQ,GAAG,OAAO,GAAG,MAAM,CAAC;AAE9D,UAAU,0BAA0B;IAClC,UAAU,EAAE,mBAAmB,CAAC;IAChC,YAAY,EAAE,CAAC,IAAI,EAAE,mBAAmB,KAAK,IAAI,CAAC;IAClD,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAYD,eAAO,MAAM,qBAAqB,wDAchC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ReduxModal.d.ts","sourceRoot":"","sources":["../../../../src/redux/components/ReduxModal.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"ReduxModal.d.ts","sourceRoot":"","sources":["../../../../src/redux/components/ReduxModal.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAiDH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAG5C;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,QAAoC,CAAC;AAExE,UAAU,eAAe;IACvB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,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;IACtC;;;;OAIG;IACH,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,IAAI,CAAC;IAC/C;;;;;;;OAOG;IACH,uBAAuB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxC,+EAA+E;IAC/E,iBAAiB,CAAC,EAAE,mBAAmB,CAAC;CACzC;AAoCD,wBAAgB,UAAU,CAAC,EACzB,OAAO,EACP,OAAO,EACP,MAAM,EACN,UAAU,EACV,2BAAmC,EACnC,MAAc,EACd,cAAc,EACd,uBAAuB,EACvB,iBAAiB,GAClB,EAAE,eAAe,sCAokBjB;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAC3B,KAAK,GAAE,IAAI,CAAC,eAAe,EAAE,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAM,+BAGpE"}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Hook for consuming Redux actions from the store
|
|
3
|
+
*
|
|
4
|
+
* The subscribe / filter / pause / clear plumbing is shared `useChangeLog`;
|
|
5
|
+
* this file owns the redux-specific stats, action types and selection.
|
|
3
6
|
*/
|
|
4
7
|
import type { ReduxAction, ReduxFilter } from "../types";
|
|
5
8
|
export interface UseReduxActionsResult {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useReduxActions.d.ts","sourceRoot":"","sources":["../../../../src/redux/hooks/useReduxActions.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"useReduxActions.d.ts","sourceRoot":"","sources":["../../../../src/redux/hooks/useReduxActions.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAGzD,MAAM,WAAW,qBAAqB;IACpC,2BAA2B;IAC3B,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,+CAA+C;IAC/C,eAAe,EAAE,WAAW,EAAE,CAAC;IAC/B,8BAA8B;IAC9B,MAAM,EAAE,WAAW,CAAC;IACpB,6BAA6B;IAC7B,SAAS,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,WAAW,CAAC,CAAC,CAAC;IAC7D,wCAAwC;IACxC,KAAK,EAAE;QACL,YAAY,EAAE,MAAM,CAAC;QACrB,kBAAkB,EAAE,MAAM,CAAC;QAC3B,qBAAqB,EAAE,MAAM,CAAC;QAC9B,iBAAiB,EAAE,MAAM,CAAC;QAC1B,eAAe,EAAE,MAAM,CAAC;KACzB,CAAC;IACF,iCAAiC;IACjC,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,wCAAwC;IACxC,SAAS,EAAE,OAAO,CAAC;IACnB,mCAAmC;IACnC,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,4CAA4C;IAC5C,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,uBAAuB;IACvB,aAAa,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,WAAW,GAAG,SAAS,CAAC;IACvD,gDAAgD;IAChD,cAAc,EAAE,WAAW,GAAG,IAAI,CAAC;IACnC,0BAA0B;IAC1B,iBAAiB,EAAE,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,KAAK,IAAI,CAAC;CACzD;AAKD,wBAAgB,eAAe,IAAI,qBAAqB,CA2CvD"}
|