@buoy-gg/zustand 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/zustand/components/ZustandActionButton.js +1 -1
- package/lib/commonjs/zustand/components/ZustandDetailViewToggle.js +13 -107
- package/lib/commonjs/zustand/components/ZustandEventFilterView.js +24 -288
- package/lib/commonjs/zustand/components/ZustandModal.js +20 -85
- package/lib/commonjs/zustand/components/ZustandStateChangeItem.js +8 -61
- package/lib/commonjs/zustand/components/ZustandStateDetailContent.js +5 -5
- package/lib/commonjs/zustand/components/ZustandStateInfoView.js +8 -52
- package/lib/commonjs/zustand/components/ZustandStoreBrowser.js +2 -2
- package/lib/commonjs/zustand/components/ZustandStoreDetailContent.js +4 -4
- package/lib/commonjs/zustand/components/ZustandStoreEditorScreen.js +3 -3
- package/lib/commonjs/zustand/hooks/useZustandStateChanges.js +33 -53
- package/lib/commonjs/zustand/sync/zustandSyncAdapter.js +24 -78
- package/lib/commonjs/zustand/utils/snapshotProvider.js +17 -60
- package/lib/commonjs/zustand/utils/zustandStateStore.js +37 -223
- package/lib/module/zustand/components/ZustandActionButton.js +2 -2
- package/lib/module/zustand/components/ZustandDetailViewToggle.js +15 -109
- package/lib/module/zustand/components/ZustandEventFilterView.js +28 -292
- package/lib/module/zustand/components/ZustandModal.js +22 -87
- package/lib/module/zustand/components/ZustandStateChangeItem.js +10 -63
- package/lib/module/zustand/components/ZustandStateDetailContent.js +6 -6
- package/lib/module/zustand/components/ZustandStateInfoView.js +7 -51
- package/lib/module/zustand/components/ZustandStoreBrowser.js +3 -3
- package/lib/module/zustand/components/ZustandStoreDetailContent.js +5 -5
- package/lib/module/zustand/components/ZustandStoreEditorScreen.js +4 -4
- package/lib/module/zustand/hooks/useZustandStateChanges.js +34 -54
- package/lib/module/zustand/sync/zustandSyncAdapter.js +25 -79
- package/lib/module/zustand/utils/snapshotProvider.js +18 -61
- package/lib/module/zustand/utils/zustandStateStore.js +37 -223
- package/lib/typescript/zustand/components/ZustandDetailViewToggle.d.ts +2 -1
- package/lib/typescript/zustand/components/ZustandDetailViewToggle.d.ts.map +1 -1
- package/lib/typescript/zustand/components/ZustandEventFilterView.d.ts +6 -0
- package/lib/typescript/zustand/components/ZustandEventFilterView.d.ts.map +1 -1
- package/lib/typescript/zustand/components/ZustandModal.d.ts.map +1 -1
- package/lib/typescript/zustand/components/ZustandStateChangeItem.d.ts.map +1 -1
- package/lib/typescript/zustand/components/ZustandStateDetailContent.d.ts.map +1 -1
- package/lib/typescript/zustand/components/ZustandStateInfoView.d.ts.map +1 -1
- package/lib/typescript/zustand/components/ZustandStoreDetailContent.d.ts.map +1 -1
- package/lib/typescript/zustand/components/ZustandStoreEditorScreen.d.ts.map +1 -1
- package/lib/typescript/zustand/hooks/useZustandStateChanges.d.ts +2 -1
- package/lib/typescript/zustand/hooks/useZustandStateChanges.d.ts.map +1 -1
- package/lib/typescript/zustand/sync/zustandSyncAdapter.d.ts +103 -117
- package/lib/typescript/zustand/sync/zustandSyncAdapter.d.ts.map +1 -1
- package/lib/typescript/zustand/utils/zustandStateStore.d.ts +6 -26
- package/lib/typescript/zustand/utils/zustandStateStore.d.ts.map +1 -1
- package/package.json +3 -3
|
@@ -5,7 +5,6 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.ZustandStateChangeItem = void 0;
|
|
7
7
|
var _react = require("react");
|
|
8
|
-
var _reactNative = require("react-native");
|
|
9
8
|
var _sharedUi = require("@buoy-gg/shared-ui");
|
|
10
9
|
var _zustandStateStore = require("../utils/zustandStateStore");
|
|
11
10
|
var _jsxRuntime = require("react/jsx-runtime");
|
|
@@ -103,68 +102,16 @@ const ZustandStateChangeItem = exports.ZustandStateChangeItem = /*#__PURE__*/(0,
|
|
|
103
102
|
const sublabel = getSublabel(change);
|
|
104
103
|
const primaryText = getPrimaryText(change);
|
|
105
104
|
const badgeText = getBadgeText(change);
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
// alternative — letting CompactRow draw `badgeText` itself — leaves the one
|
|
109
|
-
// row whose badge matters most (a set that changed NOTHING) as the only row
|
|
110
|
-
// in the list with no handle on its badge.
|
|
111
|
-
const customBadge = /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
112
|
-
style: styles.badgeContainer,
|
|
113
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
114
|
-
style: [styles.badgeText, {
|
|
115
|
-
color: statusColor
|
|
116
|
-
}],
|
|
117
|
-
testID: testID ? `${testID}-badge` : undefined,
|
|
118
|
-
children: badgeText
|
|
119
|
-
}), change.isSlowUpdate ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
120
|
-
style: styles.slowBadge,
|
|
121
|
-
testID: testID ? `${testID}-slow` : undefined,
|
|
122
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Clock, {
|
|
123
|
-
size: 12,
|
|
124
|
-
color: _sharedUi.buoyColors.error
|
|
125
|
-
})
|
|
126
|
-
}) : change.hasStateChange ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
127
|
-
style: styles.changeBadge,
|
|
128
|
-
testID: testID ? `${testID}-change` : undefined,
|
|
129
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Zap, {
|
|
130
|
-
size: 12,
|
|
131
|
-
color: _sharedUi.buoyColors.warning
|
|
132
|
-
})
|
|
133
|
-
}) : null]
|
|
134
|
-
});
|
|
135
|
-
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.CompactRow, {
|
|
136
|
-
statusDotColor: statusColor,
|
|
105
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ChangeRow, {
|
|
106
|
+
statusColor: statusColor,
|
|
137
107
|
statusLabel: statusLabel,
|
|
138
|
-
|
|
108
|
+
sublabel: sublabel,
|
|
139
109
|
primaryText: primaryText,
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
badgeColor: statusColor,
|
|
145
|
-
showChevron: true,
|
|
110
|
+
timestamp: change.timestamp,
|
|
111
|
+
badgeText: badgeText,
|
|
112
|
+
changed: change.hasStateChange,
|
|
113
|
+
slow: change.isSlowUpdate,
|
|
146
114
|
onPress: () => onPress(change),
|
|
147
|
-
testID: testID
|
|
148
|
-
statusTestID: testID ? `${testID}-status` : undefined,
|
|
149
|
-
statusSublabelTestID: testID ? `${testID}-sublabel` : undefined,
|
|
150
|
-
primaryTestID: testID ? `${testID}-keys` : undefined
|
|
115
|
+
testID: testID
|
|
151
116
|
});
|
|
152
|
-
});
|
|
153
|
-
const styles = _reactNative.StyleSheet.create({
|
|
154
|
-
badgeContainer: {
|
|
155
|
-
flexDirection: "row",
|
|
156
|
-
alignItems: "center",
|
|
157
|
-
gap: 4
|
|
158
|
-
},
|
|
159
|
-
badgeText: {
|
|
160
|
-
fontSize: 11,
|
|
161
|
-
fontWeight: "600",
|
|
162
|
-
fontFamily: "monospace"
|
|
163
|
-
},
|
|
164
|
-
changeBadge: {
|
|
165
|
-
paddingHorizontal: 4
|
|
166
|
-
},
|
|
167
|
-
slowBadge: {
|
|
168
|
-
paddingHorizontal: 4
|
|
169
|
-
}
|
|
170
117
|
});
|
|
@@ -301,7 +301,7 @@ const styles = _reactNative.StyleSheet.create({
|
|
|
301
301
|
valueLabel: {
|
|
302
302
|
fontSize: 10,
|
|
303
303
|
color: _sharedUi.night.color.textSecondary,
|
|
304
|
-
fontFamily:
|
|
304
|
+
fontFamily: _sharedUi.monoFont,
|
|
305
305
|
letterSpacing: 0.5,
|
|
306
306
|
fontWeight: "600"
|
|
307
307
|
},
|
|
@@ -318,7 +318,7 @@ const styles = _reactNative.StyleSheet.create({
|
|
|
318
318
|
changeText: {
|
|
319
319
|
fontSize: 9,
|
|
320
320
|
fontWeight: "700",
|
|
321
|
-
fontFamily:
|
|
321
|
+
fontFamily: _sharedUi.monoFont,
|
|
322
322
|
letterSpacing: 0.3
|
|
323
323
|
},
|
|
324
324
|
typeBadge: {
|
|
@@ -331,7 +331,7 @@ const styles = _reactNative.StyleSheet.create({
|
|
|
331
331
|
fontSize: 9,
|
|
332
332
|
fontWeight: "600",
|
|
333
333
|
color: _sharedUi.night.color.textTertiary,
|
|
334
|
-
fontFamily:
|
|
334
|
+
fontFamily: _sharedUi.monoFont
|
|
335
335
|
},
|
|
336
336
|
valueBox: {
|
|
337
337
|
// Inset code box — darker than the card, the night track color.
|
|
@@ -344,7 +344,7 @@ const styles = _reactNative.StyleSheet.create({
|
|
|
344
344
|
valueText: {
|
|
345
345
|
fontSize: 12,
|
|
346
346
|
color: _sharedUi.night.color.text,
|
|
347
|
-
fontFamily:
|
|
347
|
+
fontFamily: _sharedUi.monoFont,
|
|
348
348
|
lineHeight: 18
|
|
349
349
|
},
|
|
350
350
|
diffContainer: {
|
|
@@ -362,7 +362,7 @@ const styles = _reactNative.StyleSheet.create({
|
|
|
362
362
|
changeTextSmall: {
|
|
363
363
|
fontSize: 8,
|
|
364
364
|
fontWeight: "700",
|
|
365
|
-
fontFamily:
|
|
365
|
+
fontFamily: _sharedUi.monoFont
|
|
366
366
|
},
|
|
367
367
|
dataViewerContainer: {
|
|
368
368
|
marginTop: -12,
|
|
@@ -79,29 +79,6 @@ function SectionHeader({
|
|
|
79
79
|
}), badge]
|
|
80
80
|
});
|
|
81
81
|
}
|
|
82
|
-
function InfoRow({
|
|
83
|
-
label,
|
|
84
|
-
value,
|
|
85
|
-
valueColor,
|
|
86
|
-
mono = false,
|
|
87
|
-
testID
|
|
88
|
-
}) {
|
|
89
|
-
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
90
|
-
style: styles.infoRow,
|
|
91
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
92
|
-
style: styles.infoLabel,
|
|
93
|
-
children: label
|
|
94
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
95
|
-
testID: testID,
|
|
96
|
-
style: [styles.infoValue, mono && styles.infoValueMono, valueColor ? {
|
|
97
|
-
color: valueColor
|
|
98
|
-
} : undefined],
|
|
99
|
-
numberOfLines: 1,
|
|
100
|
-
ellipsizeMode: "middle",
|
|
101
|
-
children: value
|
|
102
|
-
})]
|
|
103
|
-
});
|
|
104
|
-
}
|
|
105
82
|
function formatTime(timestamp) {
|
|
106
83
|
const date = new Date(timestamp);
|
|
107
84
|
const hours = date.getHours().toString().padStart(2, "0");
|
|
@@ -157,13 +134,13 @@ const ZustandStateInfoView = exports.ZustandStateInfoView = /*#__PURE__*/(0, _re
|
|
|
157
134
|
title: "CHANGE INFO"
|
|
158
135
|
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
159
136
|
style: styles.cardContent,
|
|
160
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(InfoRow, {
|
|
137
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.InfoRow, {
|
|
161
138
|
label: "Store",
|
|
162
139
|
value: change.storeName,
|
|
163
140
|
mono: true,
|
|
164
141
|
valueColor: storeColor,
|
|
165
142
|
testID: `${_testIDs.ZUSTAND_TEST_ID}-info-store`
|
|
166
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(InfoRow, {
|
|
143
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.InfoRow, {
|
|
167
144
|
label: "Time",
|
|
168
145
|
value: formatTime(change.timestamp),
|
|
169
146
|
mono: true,
|
|
@@ -360,33 +337,12 @@ const styles = _reactNative.StyleSheet.create({
|
|
|
360
337
|
fontWeight: "600",
|
|
361
338
|
letterSpacing: 0.5,
|
|
362
339
|
color: _sharedUi.night.color.accent,
|
|
363
|
-
fontFamily:
|
|
340
|
+
fontFamily: _sharedUi.monoFont
|
|
364
341
|
},
|
|
365
342
|
cardContent: {
|
|
366
343
|
padding: 14,
|
|
367
344
|
gap: 10
|
|
368
345
|
},
|
|
369
|
-
infoRow: {
|
|
370
|
-
flexDirection: "row",
|
|
371
|
-
alignItems: "center",
|
|
372
|
-
justifyContent: "space-between"
|
|
373
|
-
},
|
|
374
|
-
infoLabel: {
|
|
375
|
-
fontSize: 11,
|
|
376
|
-
color: _sharedUi.night.color.textTertiary,
|
|
377
|
-
fontWeight: "500"
|
|
378
|
-
},
|
|
379
|
-
infoValue: {
|
|
380
|
-
fontSize: 11,
|
|
381
|
-
color: _sharedUi.night.color.text,
|
|
382
|
-
fontWeight: "500",
|
|
383
|
-
flex: 1,
|
|
384
|
-
textAlign: "right",
|
|
385
|
-
marginLeft: 12
|
|
386
|
-
},
|
|
387
|
-
infoValueMono: {
|
|
388
|
-
fontFamily: "monospace"
|
|
389
|
-
},
|
|
390
346
|
badgeRow: {
|
|
391
347
|
flexDirection: "row",
|
|
392
348
|
flexWrap: "wrap",
|
|
@@ -419,7 +375,7 @@ const styles = _reactNative.StyleSheet.create({
|
|
|
419
375
|
fontSize: 9,
|
|
420
376
|
fontWeight: "600",
|
|
421
377
|
color: _sharedUi.night.color.textSecondary,
|
|
422
|
-
fontFamily:
|
|
378
|
+
fontFamily: _sharedUi.monoFont
|
|
423
379
|
},
|
|
424
380
|
durationTextSlow: {
|
|
425
381
|
color: _sharedUi.buoyColors.error
|
|
@@ -481,7 +437,7 @@ const styles = _reactNative.StyleSheet.create({
|
|
|
481
437
|
fontSize: 11,
|
|
482
438
|
fontWeight: "600",
|
|
483
439
|
color: _sharedUi.night.color.accent,
|
|
484
|
-
fontFamily:
|
|
440
|
+
fontFamily: _sharedUi.monoFont
|
|
485
441
|
},
|
|
486
442
|
countBadge: {
|
|
487
443
|
paddingHorizontal: 8,
|
|
@@ -493,7 +449,7 @@ const styles = _reactNative.StyleSheet.create({
|
|
|
493
449
|
fontSize: 9,
|
|
494
450
|
fontWeight: "700",
|
|
495
451
|
color: _sharedUi.night.color.accent,
|
|
496
|
-
fontFamily:
|
|
452
|
+
fontFamily: _sharedUi.monoFont
|
|
497
453
|
},
|
|
498
454
|
typeBadge: {
|
|
499
455
|
paddingHorizontal: 6,
|
|
@@ -505,7 +461,7 @@ const styles = _reactNative.StyleSheet.create({
|
|
|
505
461
|
fontSize: 8,
|
|
506
462
|
fontWeight: "600",
|
|
507
463
|
color: _sharedUi.night.color.textTertiary,
|
|
508
|
-
fontFamily:
|
|
464
|
+
fontFamily: _sharedUi.monoFont
|
|
509
465
|
},
|
|
510
466
|
dataViewerContainer: {
|
|
511
467
|
// Inset display panel — darker than the card, the night track color.
|
|
@@ -515,7 +471,7 @@ const styles = _reactNative.StyleSheet.create({
|
|
|
515
471
|
updaterText: {
|
|
516
472
|
fontSize: 12,
|
|
517
473
|
color: _sharedUi.night.color.text,
|
|
518
|
-
fontFamily:
|
|
474
|
+
fontFamily: _sharedUi.monoFont
|
|
519
475
|
},
|
|
520
476
|
updaterSubtext: {
|
|
521
477
|
fontSize: 11,
|
|
@@ -170,7 +170,7 @@ const styles = _reactNative.StyleSheet.create({
|
|
|
170
170
|
absCountText: {
|
|
171
171
|
fontSize: 9,
|
|
172
172
|
fontWeight: "700",
|
|
173
|
-
fontFamily:
|
|
173
|
+
fontFamily: _sharedUi.monoFont
|
|
174
174
|
},
|
|
175
175
|
scrollContent: {
|
|
176
176
|
paddingTop: 8,
|
|
@@ -199,6 +199,6 @@ const styles = _reactNative.StyleSheet.create({
|
|
|
199
199
|
fontSize: 10,
|
|
200
200
|
fontWeight: "700",
|
|
201
201
|
color: _sharedUi.night.color.accent,
|
|
202
|
-
fontFamily:
|
|
202
|
+
fontFamily: _sharedUi.monoFont
|
|
203
203
|
}
|
|
204
204
|
});
|
|
@@ -396,7 +396,7 @@ const styles = _reactNative.StyleSheet.create({
|
|
|
396
396
|
color: _sharedUi.night.color.accent,
|
|
397
397
|
letterSpacing: 0.5,
|
|
398
398
|
textTransform: "uppercase",
|
|
399
|
-
fontFamily:
|
|
399
|
+
fontFamily: _sharedUi.monoFont
|
|
400
400
|
},
|
|
401
401
|
rawButton: {
|
|
402
402
|
flexDirection: "row",
|
|
@@ -443,7 +443,7 @@ const styles = _reactNative.StyleSheet.create({
|
|
|
443
443
|
borderBottomColor: _sharedUi.night.color.border,
|
|
444
444
|
letterSpacing: 0.5,
|
|
445
445
|
textTransform: "uppercase",
|
|
446
|
-
fontFamily:
|
|
446
|
+
fontFamily: _sharedUi.monoFont
|
|
447
447
|
},
|
|
448
448
|
infoBody: {
|
|
449
449
|
padding: 12,
|
|
@@ -459,13 +459,13 @@ const styles = _reactNative.StyleSheet.create({
|
|
|
459
459
|
inlineLinkText: {
|
|
460
460
|
fontSize: 10,
|
|
461
461
|
fontWeight: "600",
|
|
462
|
-
fontFamily:
|
|
462
|
+
fontFamily: _sharedUi.monoFont
|
|
463
463
|
},
|
|
464
464
|
actionsText: {
|
|
465
465
|
flex: 1,
|
|
466
466
|
color: _sharedUi.night.color.textSecondary,
|
|
467
467
|
fontSize: 10,
|
|
468
|
-
fontFamily:
|
|
468
|
+
fontFamily: _sharedUi.monoFont,
|
|
469
469
|
lineHeight: 15
|
|
470
470
|
}
|
|
471
471
|
});
|
|
@@ -301,7 +301,7 @@ const styles = _reactNative.StyleSheet.create({
|
|
|
301
301
|
color: _sharedUi.night.color.text,
|
|
302
302
|
fontSize: 13,
|
|
303
303
|
fontWeight: "600",
|
|
304
|
-
fontFamily:
|
|
304
|
+
fontFamily: _sharedUi.monoFont
|
|
305
305
|
},
|
|
306
306
|
headerState: {
|
|
307
307
|
color: _sharedUi.night.color.textTertiary,
|
|
@@ -320,7 +320,7 @@ const styles = _reactNative.StyleSheet.create({
|
|
|
320
320
|
metaText: {
|
|
321
321
|
color: _sharedUi.night.color.textTertiary,
|
|
322
322
|
fontSize: 11,
|
|
323
|
-
fontFamily:
|
|
323
|
+
fontFamily: _sharedUi.monoFont
|
|
324
324
|
},
|
|
325
325
|
treeScroll: {
|
|
326
326
|
flex: 1
|
|
@@ -345,7 +345,7 @@ const styles = _reactNative.StyleSheet.create({
|
|
|
345
345
|
error: {
|
|
346
346
|
color: _sharedUi.night.color.danger,
|
|
347
347
|
fontSize: 11,
|
|
348
|
-
fontFamily:
|
|
348
|
+
fontFamily: _sharedUi.monoFont,
|
|
349
349
|
paddingHorizontal: 12,
|
|
350
350
|
paddingBottom: 6
|
|
351
351
|
},
|
|
@@ -5,53 +5,41 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.useZustandStateChanges = useZustandStateChanges;
|
|
7
7
|
var _react = require("react");
|
|
8
|
+
var _sharedUi = require("@buoy-gg/shared-ui");
|
|
8
9
|
var _zustandStateStore = require("../utils/zustandStateStore");
|
|
9
10
|
/**
|
|
10
11
|
* Hook for consuming Zustand state changes from the store
|
|
11
12
|
*
|
|
12
|
-
*
|
|
13
|
+
* The subscribe / filter / pause / clear plumbing is shared `useChangeLog`;
|
|
14
|
+
* this file owns the zustand-specific filter, stats and store registry.
|
|
13
15
|
*/
|
|
14
16
|
|
|
17
|
+
function filterChanges(changes, filter) {
|
|
18
|
+
let filtered = changes;
|
|
19
|
+
if (filter.searchText) {
|
|
20
|
+
const search = filter.searchText.toLowerCase();
|
|
21
|
+
filtered = filtered.filter(c => c.storeName.toLowerCase().includes(search) || c.partialPreview.toLowerCase().includes(search) || c.changedKeys.some(k => k.toLowerCase().includes(search)));
|
|
22
|
+
}
|
|
23
|
+
if (filter.storeNames && filter.storeNames.length > 0) {
|
|
24
|
+
filtered = filtered.filter(c => filter.storeNames.includes(c.storeName));
|
|
25
|
+
}
|
|
26
|
+
if (filter.onlyWithChanges) {
|
|
27
|
+
filtered = filtered.filter(c => c.hasStateChange);
|
|
28
|
+
}
|
|
29
|
+
return filtered;
|
|
30
|
+
}
|
|
31
|
+
const readStores = () => _zustandStateStore.zustandStateStore.getStores();
|
|
32
|
+
const subscribeToStores = listener => _zustandStateStore.zustandStateStore.subscribeToStores(listener);
|
|
15
33
|
function useZustandStateChanges() {
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
// Subscribe to state changes
|
|
22
|
-
(0, _react.useEffect)(() => {
|
|
23
|
-
const unsubChanges = _zustandStateStore.zustandStateStore.subscribe(newChanges => {
|
|
24
|
-
setStateChanges(newChanges);
|
|
25
|
-
});
|
|
26
|
-
const unsubStores = _zustandStateStore.zustandStateStore.subscribeToStores(newStores => {
|
|
27
|
-
setStores(newStores);
|
|
28
|
-
});
|
|
29
|
-
return () => {
|
|
30
|
-
unsubChanges();
|
|
31
|
-
unsubStores();
|
|
32
|
-
};
|
|
33
|
-
}, []);
|
|
34
|
-
|
|
35
|
-
// Filter state changes — derive directly from state to avoid stale reads
|
|
36
|
-
const filteredChanges = (0, _react.useMemo)(() => {
|
|
37
|
-
let filtered = stateChanges;
|
|
38
|
-
if (filter.searchText) {
|
|
39
|
-
const search = filter.searchText.toLowerCase();
|
|
40
|
-
filtered = filtered.filter(c => c.storeName.toLowerCase().includes(search) || c.partialPreview.toLowerCase().includes(search) || c.changedKeys.some(k => k.toLowerCase().includes(search)));
|
|
41
|
-
}
|
|
42
|
-
if (filter.storeNames && filter.storeNames.length > 0) {
|
|
43
|
-
filtered = filtered.filter(c => filter.storeNames.includes(c.storeName));
|
|
44
|
-
}
|
|
45
|
-
if (filter.onlyWithChanges) {
|
|
46
|
-
filtered = filtered.filter(c => c.hasStateChange);
|
|
47
|
-
}
|
|
48
|
-
return filtered;
|
|
49
|
-
}, [stateChanges, filter]);
|
|
34
|
+
const log = (0, _sharedUi.useChangeLog)(_zustandStateStore.zustandStateStore, {
|
|
35
|
+
filterItems: filterChanges
|
|
36
|
+
});
|
|
37
|
+
const stores = (0, _sharedUi.useSubscribedValue)(readStores, subscribeToStores);
|
|
50
38
|
|
|
51
39
|
// Get stats — derive directly from state
|
|
52
40
|
const stats = (0, _react.useMemo)(() => {
|
|
53
|
-
const total =
|
|
54
|
-
const withChanges =
|
|
41
|
+
const total = log.items.length;
|
|
42
|
+
const withChanges = log.items.filter(c => c.hasStateChange).length;
|
|
55
43
|
return {
|
|
56
44
|
totalChanges: total,
|
|
57
45
|
changesWithStateChange: withChanges,
|
|
@@ -59,33 +47,25 @@ function useZustandStateChanges() {
|
|
|
59
47
|
storeCount: stores.length,
|
|
60
48
|
averageDuration: 0
|
|
61
49
|
};
|
|
62
|
-
}, [
|
|
50
|
+
}, [log.items, stores]);
|
|
63
51
|
|
|
64
52
|
// Get unique store names
|
|
65
53
|
const storeNames = (0, _react.useMemo)(() => {
|
|
66
54
|
return _zustandStateStore.zustandStateStore.getUniqueStoreNames();
|
|
67
55
|
}, [stores]);
|
|
68
|
-
const clearChanges = (0, _react.useCallback)(() => {
|
|
69
|
-
_zustandStateStore.zustandStateStore.clearStateChanges();
|
|
70
|
-
}, []);
|
|
71
|
-
const toggleCapture = (0, _react.useCallback)(() => {
|
|
72
|
-
const newEnabled = !isEnabled;
|
|
73
|
-
_zustandStateStore.zustandStateStore.setEnabled(newEnabled);
|
|
74
|
-
setIsEnabled(newEnabled);
|
|
75
|
-
}, [isEnabled]);
|
|
76
56
|
const getChangeById = (0, _react.useCallback)(id => {
|
|
77
57
|
return _zustandStateStore.zustandStateStore.getStateChangeById(id);
|
|
78
58
|
}, []);
|
|
79
59
|
return {
|
|
80
|
-
stateChanges,
|
|
81
|
-
filteredChanges,
|
|
82
|
-
filter,
|
|
83
|
-
setFilter,
|
|
60
|
+
stateChanges: log.items,
|
|
61
|
+
filteredChanges: log.filteredItems,
|
|
62
|
+
filter: log.filter,
|
|
63
|
+
setFilter: log.setFilter,
|
|
84
64
|
stats,
|
|
85
65
|
stores,
|
|
86
|
-
clearChanges,
|
|
87
|
-
isEnabled,
|
|
88
|
-
toggleCapture,
|
|
66
|
+
clearChanges: log.clear,
|
|
67
|
+
isEnabled: log.isEnabled,
|
|
68
|
+
toggleCapture: log.toggleCapture,
|
|
89
69
|
storeNames,
|
|
90
70
|
getChangeById
|
|
91
71
|
};
|
|
@@ -11,18 +11,10 @@ var _sharedUi = require("@buoy-gg/shared-ui");
|
|
|
11
11
|
* Same hazard as redux: up to 200 changes × 2 full trees on every snapshot
|
|
12
12
|
* freeze/OOM-killed large apps. Dashboards fetch trees via `getChangeDetail`.
|
|
13
13
|
*/
|
|
14
|
-
const STATE_ON_DEVICE = exports.STATE_ON_DEVICE =
|
|
15
|
-
__buoyStateOnDevice: true,
|
|
16
|
-
note: "State trees stay on the device — fetched on demand via getChangeDetail / getStoreState."
|
|
17
|
-
});
|
|
14
|
+
const STATE_ON_DEVICE = exports.STATE_ON_DEVICE = (0, _sharedUi.onDeviceMarker)("State", "State trees stay on the device — fetched on demand via getChangeDetail / getStoreState.");
|
|
18
15
|
|
|
19
16
|
/** Wire-form sentinel for an oversized `partial` (replace can carry a whole tree). */
|
|
20
|
-
const PAYLOAD_ON_DEVICE = exports.PAYLOAD_ON_DEVICE =
|
|
21
|
-
__buoyPayloadOnDevice: true,
|
|
22
|
-
note: "Partial stays on the device — fetched on demand via getChangeDetail."
|
|
23
|
-
});
|
|
24
|
-
const MAX_CHANGE_DETAIL_BYTES = 8 * 1024 * 1024;
|
|
25
|
-
const MAX_WIRE_PAYLOAD_BYTES = 16 * 1024;
|
|
17
|
+
const PAYLOAD_ON_DEVICE = exports.PAYLOAD_ON_DEVICE = (0, _sharedUi.onDeviceMarker)("Payload", "Partial stays on the device — fetched on demand via getChangeDetail.");
|
|
26
18
|
/** Top-level keys of an object state, for the compact (no-values) view. */
|
|
27
19
|
function topLevelKeys(state) {
|
|
28
20
|
return state && typeof state === "object" && !Array.isArray(state) ? Object.keys(state) : undefined;
|
|
@@ -33,31 +25,17 @@ function topLevelKeys(state) {
|
|
|
33
25
|
* change, so keying on identity is correct and self-invalidating — without it
|
|
34
26
|
* every `partial` in the list is re-measured on all ~5 snapshots per second.
|
|
35
27
|
*/
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
nextState: STATE_ON_DEVICE,
|
|
44
|
-
partial: toWirePartial(change.partial)
|
|
45
|
-
};
|
|
46
|
-
changeCache.set(change, wire);
|
|
47
|
-
return wire;
|
|
48
|
-
}
|
|
49
|
-
function toWirePartial(value) {
|
|
50
|
-
if (value === undefined) return value;
|
|
51
|
-
return (0, _sharedUi.isOverWireBudget)(value, MAX_WIRE_PAYLOAD_BYTES) ? PAYLOAD_ON_DEVICE : value;
|
|
52
|
-
}
|
|
53
|
-
function toWireState(value) {
|
|
54
|
-
return (0, _sharedUi.isOverWireBudget)(value, MAX_WIRE_PAYLOAD_BYTES) ? STATE_ON_DEVICE : value;
|
|
55
|
-
}
|
|
28
|
+
const toWireChange = (0, _sharedUi.memoByIdentity)(change => ({
|
|
29
|
+
...change,
|
|
30
|
+
prevState: STATE_ON_DEVICE,
|
|
31
|
+
nextState: STATE_ON_DEVICE,
|
|
32
|
+
partial: (0, _sharedUi.toWire)(change.partial, PAYLOAD_ON_DEVICE)
|
|
33
|
+
}));
|
|
34
|
+
const toWireState = value => (0, _sharedUi.toWire)(value, STATE_ON_DEVICE);
|
|
56
35
|
|
|
57
36
|
/**
|
|
58
37
|
* Sync adapter for the zustand tool, consumed by @buoy-gg/external-sync's
|
|
59
|
-
* `useExternalSync
|
|
60
|
-
* this package doesn't need a dependency on it).
|
|
38
|
+
* `useExternalSync`.
|
|
61
39
|
*
|
|
62
40
|
* State changes are captured by the middleware (watchStores/buoyDevTools),
|
|
63
41
|
* independent of whether a dashboard is watching — subscribing here only
|
|
@@ -72,7 +50,7 @@ function toWireState(value) {
|
|
|
72
50
|
*
|
|
73
51
|
* The `setState` action powers remote time-travel/reset from the dashboard.
|
|
74
52
|
*/
|
|
75
|
-
const zustandSyncAdapter = exports.zustandSyncAdapter = {
|
|
53
|
+
const zustandSyncAdapter = exports.zustandSyncAdapter = (0, _sharedUi.createSyncAdapter)({
|
|
76
54
|
version: 2,
|
|
77
55
|
getSnapshot: () => ({
|
|
78
56
|
changes: _zustandStateStore.zustandStateStore.getStateChanges().map(toWireChange),
|
|
@@ -81,14 +59,7 @@ const zustandSyncAdapter = exports.zustandSyncAdapter = {
|
|
|
81
59
|
currentState: toWireState(store.currentState)
|
|
82
60
|
}))
|
|
83
61
|
}),
|
|
84
|
-
subscribe: onChange =>
|
|
85
|
-
const unsubscribeChanges = _zustandStateStore.zustandStateStore.subscribe(onChange);
|
|
86
|
-
const unsubscribeStores = _zustandStateStore.zustandStateStore.subscribeToStores(onChange);
|
|
87
|
-
return () => {
|
|
88
|
-
unsubscribeChanges();
|
|
89
|
-
unsubscribeStores();
|
|
90
|
-
};
|
|
91
|
-
},
|
|
62
|
+
subscribe: [onChange => _zustandStateStore.zustandStateStore.subscribe(onChange), onChange => _zustandStateStore.zustandStateStore.subscribeToStores(onChange)],
|
|
92
63
|
actions: {
|
|
93
64
|
clearEvents: () => {
|
|
94
65
|
_zustandStateStore.zustandStateStore.clearStateChanges();
|
|
@@ -98,32 +69,11 @@ const zustandSyncAdapter = exports.zustandSyncAdapter = {
|
|
|
98
69
|
* The per-snapshot stream stays tree-free; this is the explicit,
|
|
99
70
|
* size-guarded channel for the detail pane.
|
|
100
71
|
*/
|
|
101
|
-
getChangeDetail:
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
found: false,
|
|
107
|
-
reason: "missing id"
|
|
108
|
-
};
|
|
109
|
-
const change = _zustandStateStore.zustandStateStore.getStateChangeById(id);
|
|
110
|
-
if (!change) return {
|
|
111
|
-
found: false,
|
|
112
|
-
reason: "unknown id"
|
|
113
|
-
};
|
|
114
|
-
const cappedNote = {
|
|
115
|
-
__buoyTruncated: true,
|
|
116
|
-
note: `Exceeds the ${MAX_CHANGE_DETAIL_BYTES / (1024 * 1024)}MB detail limit — inspect it on-device.`
|
|
117
|
-
};
|
|
118
|
-
const cap = value => (0, _sharedUi.isOverWireBudget)(value, MAX_CHANGE_DETAIL_BYTES) ? cappedNote : value;
|
|
119
|
-
return {
|
|
120
|
-
found: true,
|
|
121
|
-
id,
|
|
122
|
-
prevState: cap(change.prevState),
|
|
123
|
-
nextState: cap(change.nextState),
|
|
124
|
-
partial: cap(change.partial)
|
|
125
|
-
};
|
|
126
|
-
},
|
|
72
|
+
getChangeDetail: (0, _sharedUi.detailByIdAction)(id => _zustandStateStore.zustandStateStore.getStateChangeById(id), (change, cap) => ({
|
|
73
|
+
prevState: cap(change.prevState),
|
|
74
|
+
nextState: cap(change.nextState),
|
|
75
|
+
partial: cap(change.partial)
|
|
76
|
+
})),
|
|
127
77
|
/**
|
|
128
78
|
* On-demand current state for one store. Wire-form snapshots replace
|
|
129
79
|
* oversized / unserializable `currentState` with STATE_ON_DEVICE.
|
|
@@ -131,7 +81,7 @@ const zustandSyncAdapter = exports.zustandSyncAdapter = {
|
|
|
131
81
|
getStoreState: params => {
|
|
132
82
|
const {
|
|
133
83
|
storeName
|
|
134
|
-
} = params
|
|
84
|
+
} = (0, _sharedUi.readParams)(params);
|
|
135
85
|
if (!storeName) return {
|
|
136
86
|
found: false,
|
|
137
87
|
reason: "missing storeName"
|
|
@@ -147,11 +97,7 @@ const zustandSyncAdapter = exports.zustandSyncAdapter = {
|
|
|
147
97
|
} catch {
|
|
148
98
|
currentState = undefined;
|
|
149
99
|
}
|
|
150
|
-
|
|
151
|
-
__buoyTruncated: true,
|
|
152
|
-
note: `Exceeds the ${MAX_CHANGE_DETAIL_BYTES / (1024 * 1024)}MB detail limit — inspect it on-device.`
|
|
153
|
-
};
|
|
154
|
-
if (!(0, _sharedUi.isOverWireBudget)(currentState, MAX_CHANGE_DETAIL_BYTES)) {
|
|
100
|
+
if (!(0, _sharedUi.isOverWireBudget)(currentState, _sharedUi.WIRE_DETAIL_LIMIT_BYTES)) {
|
|
155
101
|
return {
|
|
156
102
|
found: true,
|
|
157
103
|
storeName,
|
|
@@ -161,7 +107,7 @@ const zustandSyncAdapter = exports.zustandSyncAdapter = {
|
|
|
161
107
|
return {
|
|
162
108
|
found: true,
|
|
163
109
|
storeName,
|
|
164
|
-
currentState: (0, _sharedUi.isJsonSerializable)(currentState) ?
|
|
110
|
+
currentState: (0, _sharedUi.isJsonSerializable)(currentState) ? (0, _sharedUi.truncatedNote)(_sharedUi.WIRE_DETAIL_LIMIT_BYTES) : STATE_ON_DEVICE
|
|
165
111
|
};
|
|
166
112
|
},
|
|
167
113
|
/**
|
|
@@ -174,7 +120,7 @@ const zustandSyncAdapter = exports.zustandSyncAdapter = {
|
|
|
174
120
|
const {
|
|
175
121
|
includeValues = false,
|
|
176
122
|
limit
|
|
177
|
-
} = params
|
|
123
|
+
} = (0, _sharedUi.readParams)(params);
|
|
178
124
|
const all = _zustandStateStore.zustandStateStore.getStoreSnapshots();
|
|
179
125
|
const capped = typeof limit === "number" && limit > 0 ? all.slice(0, limit) : all;
|
|
180
126
|
const stores = capped.map(s => ({
|
|
@@ -201,7 +147,7 @@ const zustandSyncAdapter = exports.zustandSyncAdapter = {
|
|
|
201
147
|
storeName,
|
|
202
148
|
state,
|
|
203
149
|
replace
|
|
204
|
-
} = params
|
|
150
|
+
} = (0, _sharedUi.readParams)(params);
|
|
205
151
|
if (!storeName) return {
|
|
206
152
|
ok: false,
|
|
207
153
|
error: "Missing storeName."
|
|
@@ -240,7 +186,7 @@ const zustandSyncAdapter = exports.zustandSyncAdapter = {
|
|
|
240
186
|
rehydrate: async params => {
|
|
241
187
|
const {
|
|
242
188
|
storeName
|
|
243
|
-
} = params
|
|
189
|
+
} = (0, _sharedUi.readParams)(params);
|
|
244
190
|
if (!storeName) return {
|
|
245
191
|
ok: false,
|
|
246
192
|
error: "Missing storeName."
|
|
@@ -270,4 +216,4 @@ const zustandSyncAdapter = exports.zustandSyncAdapter = {
|
|
|
270
216
|
};
|
|
271
217
|
}
|
|
272
218
|
}
|
|
273
|
-
};
|
|
219
|
+
});
|