@buoy-gg/storage 7.0.3 → 7.0.5
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/index.js +77 -1
- package/lib/commonjs/storage/components/DiffViewer/TreeDiffViewer.js +10 -3
- package/lib/commonjs/storage/components/DiffViewer/modes/ThemedSplitView.js +26 -8
- package/lib/commonjs/storage/components/GameUIStorageBrowser.js +263 -115
- package/lib/commonjs/storage/components/GameUIStorageStats.js +7 -7
- package/lib/commonjs/storage/components/MMKVInstanceInfoPanel.js +1 -1
- package/lib/commonjs/storage/components/MMKVInstanceSelector.js +1 -1
- package/lib/commonjs/storage/components/SelectionActionBar.js +2 -36
- package/lib/commonjs/storage/components/StorageActions.js +6 -6
- package/lib/commonjs/storage/components/StorageBrowserMode.js +16 -2
- package/lib/commonjs/storage/components/StorageEventDetailContent.js +106 -149
- package/lib/commonjs/storage/components/StorageEventListener.js +13 -13
- package/lib/commonjs/storage/components/StorageFilterCards.js +13 -135
- package/lib/commonjs/storage/components/StorageKeyCard.js +1 -1
- package/lib/commonjs/storage/components/StorageKeyEditorScreen.js +392 -0
- package/lib/commonjs/storage/components/StorageKeyRow.js +53 -15
- package/lib/commonjs/storage/components/StorageKeySection.js +10 -4
- package/lib/commonjs/storage/components/StorageKeyStats.js +10 -10
- package/lib/commonjs/storage/components/StorageModalWithTabs.js +272 -129
- package/lib/commonjs/storage/components/StorageScalarKeyEditor.js +46 -0
- package/lib/commonjs/storage/components/StorageTypeFilterBar.js +141 -0
- package/lib/commonjs/storage/components/StorageValueEditModal.js +361 -0
- package/lib/commonjs/storage/hooks/useKeyEditor.js +104 -0
- package/lib/commonjs/storage/hooks/useMeasuredWidth.js +74 -0
- package/lib/commonjs/storage/hooks/useSecureStoreKeys.js +70 -15
- package/lib/commonjs/storage/hooks/useTreeDraft.js +107 -0
- package/lib/commonjs/storage/index.js +29 -0
- package/lib/commonjs/storage/stores/storageEventStore.js +4 -2
- package/lib/commonjs/storage/sync/storageSyncAdapter.js +125 -3
- package/lib/commonjs/storage/utils/AsyncStorageListener.js +76 -12
- package/lib/commonjs/storage/utils/MMKVInstanceRegistry.js +10 -9
- package/lib/commonjs/storage/utils/MMKVListener.js +40 -4
- package/lib/commonjs/storage/utils/SecureStoreRegistry.js +52 -1
- package/lib/commonjs/storage/utils/deleteStorageKeys.js +53 -0
- package/lib/commonjs/storage/utils/index.js +13 -0
- package/lib/commonjs/storage/utils/lineDiff.js +21 -354
- package/lib/commonjs/storage/utils/setStorageValue.js +218 -0
- package/lib/commonjs/storage/utils/storageBrowserRefresh.js +49 -0
- package/lib/commonjs/storage/utils/storageOps.js +53 -0
- package/lib/commonjs/storage/utils/storageTimeTravelUtils.js +60 -38
- package/lib/commonjs/storage/utils/valueType.js +24 -0
- package/lib/module/index.js +18 -1
- package/lib/module/storage/components/DiffViewer/TreeDiffViewer.js +10 -3
- package/lib/module/storage/components/DiffViewer/modes/ThemedSplitView.js +26 -8
- package/lib/module/storage/components/GameUIStorageBrowser.js +266 -118
- package/lib/module/storage/components/GameUIStorageStats.js +7 -7
- package/lib/module/storage/components/MMKVInstanceInfoPanel.js +1 -1
- package/lib/module/storage/components/MMKVInstanceSelector.js +1 -1
- package/lib/module/storage/components/SelectionActionBar.js +2 -36
- package/lib/module/storage/components/StorageActions.js +7 -7
- package/lib/module/storage/components/StorageBrowserMode.js +16 -2
- package/lib/module/storage/components/StorageEventDetailContent.js +110 -151
- package/lib/module/storage/components/StorageEventListener.js +14 -14
- package/lib/module/storage/components/StorageFilterCards.js +13 -135
- package/lib/module/storage/components/StorageKeyCard.js +1 -1
- package/lib/module/storage/components/StorageKeyEditorScreen.js +388 -0
- package/lib/module/storage/components/StorageKeyRow.js +55 -17
- package/lib/module/storage/components/StorageKeySection.js +11 -5
- package/lib/module/storage/components/StorageKeyStats.js +11 -10
- package/lib/module/storage/components/StorageModalWithTabs.js +272 -130
- package/lib/module/storage/components/StorageScalarKeyEditor.js +42 -0
- package/lib/module/storage/components/StorageTypeFilterBar.js +136 -0
- package/lib/module/storage/components/StorageValueEditModal.js +357 -0
- package/lib/module/storage/hooks/useKeyEditor.js +100 -0
- package/lib/module/storage/hooks/useMeasuredWidth.js +71 -0
- package/lib/module/storage/hooks/useSecureStoreKeys.js +71 -16
- package/lib/module/storage/hooks/useTreeDraft.js +103 -0
- package/lib/module/storage/index.js +3 -0
- package/lib/module/storage/stores/storageEventStore.js +4 -2
- package/lib/module/storage/sync/storageSyncAdapter.js +125 -3
- package/lib/module/storage/utils/AsyncStorageListener.js +76 -12
- package/lib/module/storage/utils/MMKVInstanceRegistry.js +8 -7
- package/lib/module/storage/utils/MMKVListener.js +40 -4
- package/lib/module/storage/utils/SecureStoreRegistry.js +52 -1
- package/lib/module/storage/utils/deleteStorageKeys.js +49 -0
- package/lib/module/storage/utils/index.js +3 -0
- package/lib/module/storage/utils/lineDiff.js +7 -354
- package/lib/module/storage/utils/setStorageValue.js +209 -0
- package/lib/module/storage/utils/storageBrowserRefresh.js +44 -0
- package/lib/module/storage/utils/storageOps.js +46 -0
- package/lib/module/storage/utils/storageTimeTravelUtils.js +61 -40
- package/lib/module/storage/utils/valueType.js +23 -0
- package/lib/typescript/index.d.ts +12 -1
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/storage/components/DiffViewer/TreeDiffViewer.d.ts +4 -1
- package/lib/typescript/storage/components/DiffViewer/TreeDiffViewer.d.ts.map +1 -1
- package/lib/typescript/storage/components/DiffViewer/modes/ThemedSplitView.d.ts +7 -1
- package/lib/typescript/storage/components/DiffViewer/modes/ThemedSplitView.d.ts.map +1 -1
- package/lib/typescript/storage/components/GameUIStorageBrowser.d.ts +27 -1
- package/lib/typescript/storage/components/GameUIStorageBrowser.d.ts.map +1 -1
- package/lib/typescript/storage/components/SelectionActionBar.d.ts.map +1 -1
- package/lib/typescript/storage/components/StorageBrowserMode.d.ts +17 -1
- package/lib/typescript/storage/components/StorageBrowserMode.d.ts.map +1 -1
- package/lib/typescript/storage/components/StorageEventDetailContent.d.ts +4 -1
- package/lib/typescript/storage/components/StorageEventDetailContent.d.ts.map +1 -1
- package/lib/typescript/storage/components/StorageFilterCards.d.ts +9 -3
- package/lib/typescript/storage/components/StorageFilterCards.d.ts.map +1 -1
- package/lib/typescript/storage/components/StorageKeyEditorScreen.d.ts +42 -0
- package/lib/typescript/storage/components/StorageKeyEditorScreen.d.ts.map +1 -0
- package/lib/typescript/storage/components/StorageKeyRow.d.ts +17 -0
- package/lib/typescript/storage/components/StorageKeyRow.d.ts.map +1 -1
- package/lib/typescript/storage/components/StorageKeySection.d.ts +7 -1
- package/lib/typescript/storage/components/StorageKeySection.d.ts.map +1 -1
- package/lib/typescript/storage/components/StorageKeyStats.d.ts.map +1 -1
- package/lib/typescript/storage/components/StorageModalWithTabs.d.ts +28 -1
- package/lib/typescript/storage/components/StorageModalWithTabs.d.ts.map +1 -1
- package/lib/typescript/storage/components/StorageScalarKeyEditor.d.ts +24 -0
- package/lib/typescript/storage/components/StorageScalarKeyEditor.d.ts.map +1 -0
- package/lib/typescript/storage/components/StorageTypeFilterBar.d.ts +29 -0
- package/lib/typescript/storage/components/StorageTypeFilterBar.d.ts.map +1 -0
- package/lib/typescript/storage/components/StorageValueEditModal.d.ts +36 -0
- package/lib/typescript/storage/components/StorageValueEditModal.d.ts.map +1 -0
- package/lib/typescript/storage/hooks/useKeyEditor.d.ts +51 -0
- package/lib/typescript/storage/hooks/useKeyEditor.d.ts.map +1 -0
- package/lib/typescript/storage/hooks/useMeasuredWidth.d.ts +37 -0
- package/lib/typescript/storage/hooks/useMeasuredWidth.d.ts.map +1 -0
- package/lib/typescript/storage/hooks/useSecureStoreKeys.d.ts +8 -1
- package/lib/typescript/storage/hooks/useSecureStoreKeys.d.ts.map +1 -1
- package/lib/typescript/storage/hooks/useTreeDraft.d.ts +67 -0
- package/lib/typescript/storage/hooks/useTreeDraft.d.ts.map +1 -0
- package/lib/typescript/storage/index.d.ts +2 -0
- package/lib/typescript/storage/index.d.ts.map +1 -1
- package/lib/typescript/storage/sync/storageSyncAdapter.d.ts +41 -0
- package/lib/typescript/storage/sync/storageSyncAdapter.d.ts.map +1 -1
- package/lib/typescript/storage/utils/AsyncStorageListener.d.ts +15 -0
- package/lib/typescript/storage/utils/AsyncStorageListener.d.ts.map +1 -1
- package/lib/typescript/storage/utils/MMKVInstanceRegistry.d.ts.map +1 -1
- package/lib/typescript/storage/utils/MMKVListener.d.ts +7 -0
- package/lib/typescript/storage/utils/MMKVListener.d.ts.map +1 -1
- package/lib/typescript/storage/utils/SecureStoreRegistry.d.ts +20 -0
- package/lib/typescript/storage/utils/SecureStoreRegistry.d.ts.map +1 -1
- package/lib/typescript/storage/utils/deleteStorageKeys.d.ts +27 -0
- package/lib/typescript/storage/utils/deleteStorageKeys.d.ts.map +1 -0
- package/lib/typescript/storage/utils/index.d.ts +1 -0
- package/lib/typescript/storage/utils/index.d.ts.map +1 -1
- package/lib/typescript/storage/utils/lineDiff.d.ts +7 -31
- package/lib/typescript/storage/utils/lineDiff.d.ts.map +1 -1
- package/lib/typescript/storage/utils/setStorageValue.d.ts +64 -0
- package/lib/typescript/storage/utils/setStorageValue.d.ts.map +1 -0
- package/lib/typescript/storage/utils/storageBrowserRefresh.d.ts +28 -0
- package/lib/typescript/storage/utils/storageBrowserRefresh.d.ts.map +1 -0
- package/lib/typescript/storage/utils/storageOps.d.ts +25 -0
- package/lib/typescript/storage/utils/storageOps.d.ts.map +1 -0
- package/lib/typescript/storage/utils/storageTimeTravelUtils.d.ts +15 -5
- package/lib/typescript/storage/utils/storageTimeTravelUtils.d.ts.map +1 -1
- package/lib/typescript/storage/utils/valueType.d.ts +13 -0
- package/lib/typescript/storage/utils/valueType.d.ts.map +1 -1
- package/package.json +5 -5
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Writing a storage value back, in one place.
|
|
5
|
+
*
|
|
6
|
+
* The counterpart to `deleteStorageKeys` — and the same reasoning applies: each
|
|
7
|
+
* backend writes differently, and a second copy of that fan-out is how one
|
|
8
|
+
* backend quietly starts corrupting values.
|
|
9
|
+
*
|
|
10
|
+
* The hard part is NOT the write, it's the types:
|
|
11
|
+
*
|
|
12
|
+
* - **AsyncStorage** stores strings only. A value that was stored as JSON must
|
|
13
|
+
* stay valid JSON, or an object silently becomes a quoted string and the app
|
|
14
|
+
* that reads it breaks in a way that looks nothing like a devtools edit.
|
|
15
|
+
* - **MMKV** is natively typed (string / number / boolean / buffer). Writing
|
|
16
|
+
* `"42"` over a number turns it into a string, so the original type is
|
|
17
|
+
* restored from `valueType`. Buffers can't round-trip at all — the snapshot
|
|
18
|
+
* only ever carried a `<ArrayBuffer n bytes>` placeholder.
|
|
19
|
+
* - **SecureStore** stores strings, and biometric-protected keys are never
|
|
20
|
+
* touched (writing needs the same auth prompt reading does).
|
|
21
|
+
*
|
|
22
|
+
* Pro gating and confirmation are deliberately NOT here; they belong to the UI
|
|
23
|
+
* that has the user's attention. This assumes the caller already asked.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import AsyncStorage from "@react-native-async-storage/async-storage";
|
|
27
|
+
import { secureStoreRegistry } from "./SecureStoreRegistry";
|
|
28
|
+
/**
|
|
29
|
+
* Why a key can't be edited, or null when it can. UI uses this both to hide the
|
|
30
|
+
* edit affordance and to explain itself, rather than failing at save time.
|
|
31
|
+
*/
|
|
32
|
+
export function storageEditBlockedReason(storageKey, mmkvInstances = []) {
|
|
33
|
+
if (storageKey.storageType === "mmkv") {
|
|
34
|
+
if (storageKey.valueType === "buffer") {
|
|
35
|
+
return "Buffer values can't be edited — the tool only ever sees their byte length, not their contents.";
|
|
36
|
+
}
|
|
37
|
+
const instance = mmkvInstances.find(i => i.id === (storageKey.instanceId || "default"));
|
|
38
|
+
if (instance?.readOnly) {
|
|
39
|
+
return `MMKV instance "${instance.id}" is registered read-only.`;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (storageKey.storageType === "secure") {
|
|
43
|
+
const entry = secureStoreRegistry.getAll().find(e => e.key === storageKey.key);
|
|
44
|
+
if (entry?.options.requireAuthentication) {
|
|
45
|
+
return "Biometric-protected keys can't be edited — writing one would fire an auth prompt.";
|
|
46
|
+
}
|
|
47
|
+
if (!secureStoreRegistry.getModule()) {
|
|
48
|
+
return "No SecureStore module is registered.";
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Validate `raw` for this key WITHOUT writing. Returns an error message, or
|
|
56
|
+
* null when the text is acceptable. The editor calls this as you type.
|
|
57
|
+
*/
|
|
58
|
+
export function validateStorageValue(storageKey, raw) {
|
|
59
|
+
if (storageKey.storageType === "mmkv") {
|
|
60
|
+
const type = mmkvTargetType(storageKey);
|
|
61
|
+
if (type === "number") {
|
|
62
|
+
if (raw.trim() === "" || Number.isNaN(Number(raw))) {
|
|
63
|
+
return "Must be a number — this MMKV key is stored as a number.";
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
if (type === "boolean") {
|
|
67
|
+
const t = raw.trim().toLowerCase();
|
|
68
|
+
if (t !== "true" && t !== "false") {
|
|
69
|
+
return 'Must be "true" or "false" — this MMKV key is stored as a boolean.';
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// AsyncStorage + SecureStore are string-valued. Only guard the case where
|
|
76
|
+
// the CURRENT value is structured: silently flattening an object into a
|
|
77
|
+
// string is the corruption worth preventing. A plain string stays free-form.
|
|
78
|
+
if (isStructured(storageKey.value)) {
|
|
79
|
+
try {
|
|
80
|
+
JSON.parse(raw);
|
|
81
|
+
} catch (e) {
|
|
82
|
+
return `This key holds JSON — ${e instanceof Error ? e.message : "invalid JSON"}`;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* The text an editor should open with: JSON pretty-printed so it's actually
|
|
90
|
+
* editable, everything else verbatim.
|
|
91
|
+
*/
|
|
92
|
+
export function storageValueToEditableText(value) {
|
|
93
|
+
if (value === undefined || value === null) return "";
|
|
94
|
+
if (typeof value === "string") {
|
|
95
|
+
// Values arrive already parsed when they were JSON, so a string here is a
|
|
96
|
+
// real string — except AsyncStorage hands back raw JSON text sometimes.
|
|
97
|
+
const trimmed = value.trim();
|
|
98
|
+
if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
|
|
99
|
+
try {
|
|
100
|
+
return JSON.stringify(JSON.parse(value), null, 2);
|
|
101
|
+
} catch {
|
|
102
|
+
return value;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return value;
|
|
106
|
+
}
|
|
107
|
+
if (typeof value === "object") return JSON.stringify(value, null, 2);
|
|
108
|
+
return String(value);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* The value as a STRUCTURE, for the tree editor to apply ops against.
|
|
113
|
+
*
|
|
114
|
+
* Backends disagree on how far they've already parsed: `useAsyncStorageKeys`
|
|
115
|
+
* hands back a parsed object, while MMKV reports its native type so a JSON blob
|
|
116
|
+
* arrives as the raw string. Both have to end up as the same thing before an op
|
|
117
|
+
* can address a path inside them.
|
|
118
|
+
*
|
|
119
|
+
* Returns `undefined` when the value isn't a container — scalars are edited
|
|
120
|
+
* through the plain value editor, not the tree.
|
|
121
|
+
*/
|
|
122
|
+
export function structuredStorageValue(storageKey) {
|
|
123
|
+
const {
|
|
124
|
+
value
|
|
125
|
+
} = storageKey;
|
|
126
|
+
if (value !== null && typeof value === "object") return value;
|
|
127
|
+
if (typeof value === "string") {
|
|
128
|
+
const trimmed = value.trim();
|
|
129
|
+
if (!trimmed.startsWith("{") && !trimmed.startsWith("[")) return undefined;
|
|
130
|
+
try {
|
|
131
|
+
const parsed = JSON.parse(value);
|
|
132
|
+
return parsed !== null && typeof parsed === "object" ? parsed : undefined;
|
|
133
|
+
} catch {
|
|
134
|
+
return undefined;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return undefined;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Write `raw` to whichever backend holds this key, restoring the value's
|
|
142
|
+
* original type. Rejects (rather than writing something lossy) when the key
|
|
143
|
+
* isn't editable or the text doesn't fit the type — callers surface that.
|
|
144
|
+
*/
|
|
145
|
+
export async function setStorageValue(storageKey, raw, mmkvInstances = []) {
|
|
146
|
+
const blocked = storageEditBlockedReason(storageKey, mmkvInstances);
|
|
147
|
+
if (blocked) throw new Error(blocked);
|
|
148
|
+
const invalid = validateStorageValue(storageKey, raw);
|
|
149
|
+
if (invalid) throw new Error(invalid);
|
|
150
|
+
switch (storageKey.storageType) {
|
|
151
|
+
case "async":
|
|
152
|
+
{
|
|
153
|
+
await AsyncStorage.setItem(storageKey.key, normalizeJsonText(storageKey, raw));
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
case "secure":
|
|
157
|
+
{
|
|
158
|
+
await secureStoreRegistry.setValue(storageKey.key, normalizeJsonText(storageKey, raw));
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
case "mmkv":
|
|
162
|
+
{
|
|
163
|
+
const instanceId = storageKey.instanceId || "default";
|
|
164
|
+
const target = mmkvInstances.find(i => i.id === instanceId);
|
|
165
|
+
if (!target) {
|
|
166
|
+
throw new Error(`MMKV instance "${instanceId}" is not registered.`);
|
|
167
|
+
}
|
|
168
|
+
target.instance.set(storageKey.key, coerceMMKV(storageKey, raw));
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
default:
|
|
172
|
+
{
|
|
173
|
+
throw new Error(`Unsupported storage type "${String(storageKey.storageType)}"`);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/** True when the value is an object/array (so its text must stay valid JSON). */
|
|
179
|
+
function isStructured(value) {
|
|
180
|
+
return value !== null && typeof value === "object";
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Re-serialize JSON so the stored string is compact and canonical, matching
|
|
185
|
+
* what the app itself would have written with `JSON.stringify`. Free-form
|
|
186
|
+
* strings pass through untouched.
|
|
187
|
+
*/
|
|
188
|
+
function normalizeJsonText(storageKey, raw) {
|
|
189
|
+
if (!isStructured(storageKey.value)) return raw;
|
|
190
|
+
return JSON.stringify(JSON.parse(raw));
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/** The MMKV native type to write back, defaulting to the current JS type. */
|
|
194
|
+
function mmkvTargetType(storageKey) {
|
|
195
|
+
if (storageKey.valueType) return storageKey.valueType;
|
|
196
|
+
if (typeof storageKey.value === "number") return "number";
|
|
197
|
+
if (typeof storageKey.value === "boolean") return "boolean";
|
|
198
|
+
return "string";
|
|
199
|
+
}
|
|
200
|
+
function coerceMMKV(storageKey, raw) {
|
|
201
|
+
switch (mmkvTargetType(storageKey)) {
|
|
202
|
+
case "number":
|
|
203
|
+
return Number(raw);
|
|
204
|
+
case "boolean":
|
|
205
|
+
return raw.trim().toLowerCase() === "true";
|
|
206
|
+
default:
|
|
207
|
+
return raw;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A "the underlying storage changed, re-read it" signal for the storage
|
|
5
|
+
* browser.
|
|
6
|
+
*
|
|
7
|
+
* On device the browser refreshes itself from the AsyncStorage/MMKV listeners,
|
|
8
|
+
* but those never fire in remote-mirror mode (the desktop dashboard suppresses
|
|
9
|
+
* local capture and receives the device's events as snapshots instead). Without
|
|
10
|
+
* this seam the browse tab is a one-shot read at mount — values stay frozen
|
|
11
|
+
* until the panel remounts, which is exactly the "shows old data until I switch
|
|
12
|
+
* tools and come back" behaviour.
|
|
13
|
+
*
|
|
14
|
+
* The dashboard calls {@link requestStorageBrowserRefresh} whenever a fresh
|
|
15
|
+
* device snapshot lands; the browser re-reads all three backends (debounced).
|
|
16
|
+
* It is a no-op when nothing is listening.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
const listeners = new Set();
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Subscribe to external refresh requests. Returns an unsubscribe function.
|
|
23
|
+
* @internal — used by the storage browser.
|
|
24
|
+
*/
|
|
25
|
+
export function onStorageBrowserRefresh(listener) {
|
|
26
|
+
listeners.add(listener);
|
|
27
|
+
return () => {
|
|
28
|
+
listeners.delete(listener);
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Ask any mounted storage browser to re-read AsyncStorage, MMKV and
|
|
34
|
+
* SecureStore. Safe to call at any rate — the browser debounces.
|
|
35
|
+
*/
|
|
36
|
+
export function requestStorageBrowserRefresh() {
|
|
37
|
+
listeners.forEach(listener => {
|
|
38
|
+
try {
|
|
39
|
+
listener();
|
|
40
|
+
} catch {
|
|
41
|
+
// Listener errors are not ours
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The five operations a storage event can be, and how to recognise one.
|
|
5
|
+
*
|
|
6
|
+
* AsyncStorage and MMKV each have their own action union, and neither maps
|
|
7
|
+
* cleanly onto what a reader wants to see — `multiRemove`, `removeItem` and
|
|
8
|
+
* `delete` are one idea wearing three names. These collapse both onto a single
|
|
9
|
+
* vocabulary so every surface labels, filters and colours events the same way.
|
|
10
|
+
*
|
|
11
|
+
* This is semantics, not presentation: it lives in `utils` rather than beside
|
|
12
|
+
* any one view, so a view can be deleted without taking the vocabulary with it.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { macOSColors } from "@buoy-gg/shared-ui";
|
|
16
|
+
export const STORAGE_OPS = ["SET", "GET", "MERGE", "DELETE", "CLEAR"];
|
|
17
|
+
const OP_DOT = {
|
|
18
|
+
SET: macOSColors.semantic.info,
|
|
19
|
+
GET: macOSColors.text.muted,
|
|
20
|
+
MERGE: macOSColors.semantic.debug,
|
|
21
|
+
DELETE: macOSColors.semantic.error,
|
|
22
|
+
CLEAR: macOSColors.semantic.warning
|
|
23
|
+
};
|
|
24
|
+
export function storageOpDot(op) {
|
|
25
|
+
return OP_DOT[op];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Both backends' action unions, collapsed onto the five display operations. */
|
|
29
|
+
export function storageOpOf(event) {
|
|
30
|
+
const action = event.action;
|
|
31
|
+
if (action === "clear" || action === "clearAll") return "CLEAR";
|
|
32
|
+
if (action.startsWith("get.")) return "GET";
|
|
33
|
+
if (action === "removeItem" || action === "multiRemove" || action === "delete") return "DELETE";
|
|
34
|
+
if (action === "mergeItem" || action === "multiMerge") return "MERGE";
|
|
35
|
+
return "SET";
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* The store synthesises one event per existing key when it first subscribes, so
|
|
40
|
+
* the list isn't empty on open. Those are a SNAPSHOT, not a write: the key
|
|
41
|
+
* already held that value, so there is no "before" to diff against and showing
|
|
42
|
+
* one would invent a change that never happened.
|
|
43
|
+
*/
|
|
44
|
+
export function isInitialScan(event) {
|
|
45
|
+
return Boolean(event.data?.initialScan);
|
|
46
|
+
}
|
|
@@ -6,15 +6,20 @@
|
|
|
6
6
|
* Provides jump and undo functionality for AsyncStorage operations.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
import { isDevToolsStorageKey } from "@buoy-gg/shared-ui";
|
|
9
10
|
import AsyncStorage from "@react-native-async-storage/async-storage";
|
|
10
|
-
import { writeMany } from "./asyncStorageCompat";
|
|
11
|
-
import { pauseCapture, resumeCapture } from "./AsyncStorageListener";
|
|
12
|
-
|
|
11
|
+
import { writeMany, removeMany } from "./asyncStorageCompat";
|
|
13
12
|
/**
|
|
14
13
|
* Undo a single storage operation
|
|
15
14
|
*
|
|
16
15
|
* Restores the previous value(s) before the operation occurred.
|
|
17
|
-
*
|
|
16
|
+
*
|
|
17
|
+
* The restore is deliberately NOT capture-paused. Pausing it meant the write
|
|
18
|
+
* landed but emitted no event, so the modal's event list and current-value
|
|
19
|
+
* panel never changed — UNDO looked like a dead button even though it had
|
|
20
|
+
* worked. Letting the restore emit normally makes it visible and keeps the
|
|
21
|
+
* history honest about what the storage actually did. There is no feedback
|
|
22
|
+
* loop: a write emits an event, and an event never triggers a write.
|
|
18
23
|
*
|
|
19
24
|
* @param event - The storage event to undo
|
|
20
25
|
*/
|
|
@@ -23,10 +28,7 @@ export async function undoOperation(event) {
|
|
|
23
28
|
action,
|
|
24
29
|
data
|
|
25
30
|
} = event;
|
|
26
|
-
|
|
27
|
-
// Pause capture to avoid creating events during restoration
|
|
28
|
-
pauseCapture();
|
|
29
|
-
try {
|
|
31
|
+
{
|
|
30
32
|
switch (action) {
|
|
31
33
|
case "setItem":
|
|
32
34
|
case "mergeItem":
|
|
@@ -81,20 +83,21 @@ export async function undoOperation(event) {
|
|
|
81
83
|
default:
|
|
82
84
|
throw new Error(`Cannot undo unknown action type: ${action}`);
|
|
83
85
|
}
|
|
84
|
-
} finally {
|
|
85
|
-
// Always resume capture, even if an error occurred
|
|
86
|
-
resumeCapture();
|
|
87
86
|
}
|
|
88
87
|
}
|
|
89
88
|
|
|
90
89
|
/**
|
|
91
90
|
* Jump to a specific point in storage history
|
|
92
91
|
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
92
|
+
* Reconstructs the state as of `targetEventIndex` by replaying `events` up to
|
|
93
|
+
* that point, then reconciling ONLY the keys that timeline governs.
|
|
95
94
|
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
95
|
+
* This used to begin with `AsyncStorage.clear()`, which was badly out of
|
|
96
|
+
* proportion: the modal's JUMP button passes one key's history, so clearing
|
|
97
|
+
* wiped every unrelated app key — and Buoy's own `@react_buoy*` settings with
|
|
98
|
+
* them — to restore a single value. Now a jump touches exactly the keys that
|
|
99
|
+
* appear in the events it was given, and never Buoy's own keys. Like
|
|
100
|
+
* [undoOperation], the writes emit normally so the change is visible.
|
|
98
101
|
*
|
|
99
102
|
* @param events - All events in chronological order (oldest first)
|
|
100
103
|
* @param targetEventIndex - The index of the event to jump to (0-based)
|
|
@@ -104,34 +107,52 @@ export async function jumpToState(events, targetEventIndex) {
|
|
|
104
107
|
throw new Error(`Invalid event index: ${targetEventIndex}`);
|
|
105
108
|
}
|
|
106
109
|
|
|
107
|
-
//
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
// Build up the state by applying each event up to and including the target
|
|
114
|
-
// We use the final values from each event, not the operations themselves
|
|
115
|
-
const stateMap = new Map();
|
|
116
|
-
for (let i = 0; i <= targetEventIndex; i++) {
|
|
117
|
-
const event = events[i];
|
|
118
|
-
applyEventToStateMap(event, stateMap);
|
|
119
|
-
}
|
|
110
|
+
// Build up the state by applying each event up to and including the target.
|
|
111
|
+
// We use the final values from each event, not the operations themselves.
|
|
112
|
+
const stateMap = new Map();
|
|
113
|
+
for (let i = 0; i <= targetEventIndex; i++) {
|
|
114
|
+
applyEventToStateMap(events[i], stateMap);
|
|
115
|
+
}
|
|
120
116
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
117
|
+
// Every key the WHOLE timeline touches — including events after the target,
|
|
118
|
+
// so a key created later is removed rather than left behind.
|
|
119
|
+
const governedKeys = new Set();
|
|
120
|
+
for (const event of events) {
|
|
121
|
+
collectEventKeys(event, governedKeys);
|
|
122
|
+
}
|
|
123
|
+
const pairsToSet = [];
|
|
124
|
+
const keysToRemove = [];
|
|
125
|
+
for (const key of governedKeys) {
|
|
126
|
+
// Buoy's own settings are never app state to travel through.
|
|
127
|
+
if (isDevToolsStorageKey(key)) continue;
|
|
128
|
+
const value = stateMap.get(key);
|
|
129
|
+
if (value === undefined || value === null) {
|
|
130
|
+
keysToRemove.push(key);
|
|
131
|
+
} else {
|
|
132
|
+
pairsToSet.push([key, value]);
|
|
130
133
|
}
|
|
131
|
-
} finally {
|
|
132
|
-
// Always resume capture
|
|
133
|
-
resumeCapture();
|
|
134
134
|
}
|
|
135
|
+
if (keysToRemove.length > 0) {
|
|
136
|
+
await removeMany(keysToRemove);
|
|
137
|
+
}
|
|
138
|
+
if (pairsToSet.length > 0) {
|
|
139
|
+
await writeMany(pairsToSet);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Collect every key an event refers to, across all action shapes — including
|
|
145
|
+
* `prevPairs`, so keys a `clear` removed are still governed by the timeline.
|
|
146
|
+
*/
|
|
147
|
+
function collectEventKeys(event, into) {
|
|
148
|
+
const {
|
|
149
|
+
data
|
|
150
|
+
} = event;
|
|
151
|
+
if (!data) return;
|
|
152
|
+
if (data.key) into.add(data.key);
|
|
153
|
+
if (data.keys) for (const key of data.keys) into.add(key);
|
|
154
|
+
if (data.pairs) for (const [key] of data.pairs) into.add(key);
|
|
155
|
+
if (data.prevPairs) for (const [key] of data.prevPairs) into.add(key);
|
|
135
156
|
}
|
|
136
157
|
|
|
137
158
|
/**
|
|
@@ -13,6 +13,29 @@ export function getValueTypeLabel(value) {
|
|
|
13
13
|
return "unknown";
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
/**
|
|
17
|
+
* A stored value as a tree can show it.
|
|
18
|
+
*
|
|
19
|
+
* AsyncStorage and SecureStore hold strings, so an object arrives as the text
|
|
20
|
+
* `{"a":1}` — displaying that as a string is technically true and useless. Any
|
|
21
|
+
* surface that renders or edits a value structurally has to do this same
|
|
22
|
+
* un-stringify first, so it lives here rather than being re-derived (slightly
|
|
23
|
+
* differently) in each one.
|
|
24
|
+
*
|
|
25
|
+
* A string that doesn't parse comes back untouched: it was just a string that
|
|
26
|
+
* happened to start with a brace.
|
|
27
|
+
*/
|
|
28
|
+
export function parseStorageValue(value) {
|
|
29
|
+
if (typeof value !== "string") return value;
|
|
30
|
+
const trimmed = value.trim();
|
|
31
|
+
if (!trimmed.startsWith("{") && !trimmed.startsWith("[")) return value;
|
|
32
|
+
try {
|
|
33
|
+
return JSON.parse(value);
|
|
34
|
+
} catch {
|
|
35
|
+
return value;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
16
39
|
/** Longest value preview rendered inline next to the type label. */
|
|
17
40
|
const MAX_INLINE_PREVIEW = 40;
|
|
18
41
|
|
|
@@ -10,12 +10,15 @@
|
|
|
10
10
|
*/
|
|
11
11
|
export { storageToolPreset, createStorageTool } from "./preset";
|
|
12
12
|
export { StorageSection } from "./storage/components/StorageSection";
|
|
13
|
-
export { StorageModalWithTabs } from "./storage/components/StorageModalWithTabs";
|
|
13
|
+
export { StorageModalWithTabs, StorageToolView, } from "./storage/components/StorageModalWithTabs";
|
|
14
14
|
export { StorageKeyCard } from "./storage/components/StorageKeyCard";
|
|
15
15
|
export { StorageKeyStatsSection } from "./storage/components/StorageKeyStats";
|
|
16
16
|
export { StorageKeySection } from "./storage/components/StorageKeySection";
|
|
17
17
|
export { StorageBrowserMode } from "./storage/components/StorageBrowserMode";
|
|
18
|
+
export type { StorageFilterType, StorageTypeFilter, } from "./storage/components/StorageFilterCards";
|
|
19
|
+
export { StorageTypeFilterBar, countByStorageType, type StorageTypeCounts, } from "./storage/components/StorageTypeFilterBar";
|
|
18
20
|
export { StorageEventsSection } from "./storage/components/StorageEventsSection";
|
|
21
|
+
export { STORAGE_OPS, storageOpOf, storageOpDot, isInitialScan, type StorageOp, } from "./storage/utils/storageOps";
|
|
19
22
|
export { StorageEventCard, getValueType, type StorageEventCardData, type StorageValueType, } from "./storage/components/StorageEventCard";
|
|
20
23
|
export { StorageEventDetailContent, StorageEventDetailFooter, } from "./storage/components/StorageEventDetailContent";
|
|
21
24
|
export { MMKVInstanceSelector } from "./storage/components/MMKVInstanceSelector";
|
|
@@ -26,6 +29,7 @@ export { useMMKVInstances, useMMKVInstance, useMMKVInstanceExists, } from "./sto
|
|
|
26
29
|
export { useStorageEvents, type UseStorageEventsOptions, type UseStorageEventsResult, } from "./storage/hooks/useStorageEvents";
|
|
27
30
|
export type { StorageEvent, StorageEventListener, StorageEventCallback, } from "./storage/stores/storageEventStore";
|
|
28
31
|
export { clearAllAppStorage } from "./storage/utils/clearAllStorage";
|
|
32
|
+
export { setStorageValue, storageEditBlockedReason, validateStorageValue, storageValueToEditableText, type EditableMMKVInstance, } from "./storage/utils/setStorageValue";
|
|
29
33
|
export { isMMKVAvailable, getMMKVClass, getMMKVUnavailableMessage, } from "./storage/utils/mmkvAvailability";
|
|
30
34
|
export { detectMMKVType, formatMMKVValue, isTypeMatch, type MMKVValueType, type MMKVValueInfo, } from "./storage/utils/mmkvTypeDetection";
|
|
31
35
|
export { undoOperation, jumpToState, canUndo, } from "./storage/utils/storageTimeTravelUtils";
|
|
@@ -38,4 +42,11 @@ export type { SecureStoreLike, SecureStoreKeyDescriptor, SecureStoreOptionsLike,
|
|
|
38
42
|
export { storageSyncAdapter } from "./storage/sync/storageSyncAdapter";
|
|
39
43
|
/** @internal */
|
|
40
44
|
export { storageEventStore } from "./storage/stores/storageEventStore";
|
|
45
|
+
/**
|
|
46
|
+
* Tell a mounted storage browser to re-read every backend. Used by the desktop
|
|
47
|
+
* dashboard, where local storage listeners are suppressed and device data
|
|
48
|
+
* arrives as snapshots instead.
|
|
49
|
+
* @internal
|
|
50
|
+
*/
|
|
51
|
+
export { requestStorageBrowserRefresh } from "./storage/utils/storageBrowserRefresh";
|
|
41
52
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAKhE,OAAO,EAAE,cAAc,EAAE,MAAM,qCAAqC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
interface TreeDiffViewerProps {
|
|
2
2
|
oldValue: unknown;
|
|
3
3
|
newValue: unknown;
|
|
4
|
+
/** Forwarded to the shared viewer — false renders the tree inline so an
|
|
5
|
+
* ancestor ScrollView scrolls it as part of the page. */
|
|
6
|
+
scrollEnabled?: boolean;
|
|
4
7
|
}
|
|
5
|
-
export declare function TreeDiffViewer({ oldValue, newValue }: TreeDiffViewerProps): import("react").JSX.Element;
|
|
8
|
+
export declare function TreeDiffViewer({ oldValue, newValue, scrollEnabled, }: TreeDiffViewerProps): import("react").JSX.Element;
|
|
6
9
|
export {};
|
|
7
10
|
//# sourceMappingURL=TreeDiffViewer.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TreeDiffViewer.d.ts","sourceRoot":"","sources":["../../../../../src/storage/components/DiffViewer/TreeDiffViewer.tsx"],"names":[],"mappings":"AAIA,UAAU,mBAAmB;IAC3B,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"TreeDiffViewer.d.ts","sourceRoot":"","sources":["../../../../../src/storage/components/DiffViewer/TreeDiffViewer.tsx"],"names":[],"mappings":"AAIA,UAAU,mBAAmB;IAC3B,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB;8DAC0D;IAC1D,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,wBAAgB,cAAc,CAAC,EAC7B,QAAQ,EACR,QAAQ,EACR,aAAoB,GACrB,EAAE,mBAAmB,+BAWrB"}
|
|
@@ -7,7 +7,13 @@ interface ThemedSplitViewProps {
|
|
|
7
7
|
theme: DiffTheme;
|
|
8
8
|
options?: DiffOptions;
|
|
9
9
|
showThemeName?: boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Scroll the rows inside their own fixed-height pane (default). Set false to
|
|
12
|
+
* render every row inline at natural height and let an ancestor ScrollView
|
|
13
|
+
* move them — one page-level scroll instead of a nested scroll region.
|
|
14
|
+
*/
|
|
15
|
+
scrollEnabled?: boolean;
|
|
10
16
|
}
|
|
11
|
-
export declare function ThemedSplitView({ oldValue, newValue, theme, options, showThemeName, }: ThemedSplitViewProps): import("react").JSX.Element;
|
|
17
|
+
export declare function ThemedSplitView({ oldValue, newValue, theme, options, showThemeName, scrollEnabled, }: ThemedSplitViewProps): import("react").JSX.Element;
|
|
12
18
|
export {};
|
|
13
19
|
//# sourceMappingURL=ThemedSplitView.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ThemedSplitView.d.ts","sourceRoot":"","sources":["../../../../../../src/storage/components/DiffViewer/modes/ThemedSplitView.tsx"],"names":[],"mappings":"AAyBA,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEjD,UAAU,oBAAoB;IAC5B,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,EAAE,OAAO,EAAE,CAAC;IACvB,KAAK,EAAE,SAAS,CAAC;IACjB,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAaD,wBAAgB,eAAe,CAAC,EAC9B,QAAQ,EACR,QAAQ,EACR,KAAK,EACL,OAAyB,EACzB,aAAqB,
|
|
1
|
+
{"version":3,"file":"ThemedSplitView.d.ts","sourceRoot":"","sources":["../../../../../../src/storage/components/DiffViewer/modes/ThemedSplitView.tsx"],"names":[],"mappings":"AAyBA,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEjD,UAAU,oBAAoB;IAC5B,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,EAAE,OAAO,EAAE,CAAC;IACvB,KAAK,EAAE,SAAS,CAAC;IACjB,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAaD,wBAAgB,eAAe,CAAC,EAC9B,QAAQ,EACR,QAAQ,EACR,KAAK,EACL,OAAyB,EACzB,aAAqB,EACrB,aAAoB,GACrB,EAAE,oBAAoB,+BAmMtB"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { MutableRefObject } from "react";
|
|
2
2
|
import { RequiredStorageKey } from "../types";
|
|
3
|
+
import { type StorageFilterType, type StorageTypeFilter } from "./StorageFilterCards";
|
|
3
4
|
/** Free tier limit for storage keys */
|
|
4
5
|
export declare const FREE_TIER_KEY_LIMIT = 25;
|
|
5
6
|
interface GameUIStorageBrowserProps {
|
|
@@ -11,13 +12,38 @@ interface GameUIStorageBrowserProps {
|
|
|
11
12
|
searchQuery?: string;
|
|
12
13
|
storageDataRef?: MutableRefObject<any[]>;
|
|
13
14
|
eventCountByKey?: Record<string, number>;
|
|
15
|
+
/**
|
|
16
|
+
* Epoch ms of the most recent recorded write per key, for keys whose write
|
|
17
|
+
* we actually witnessed — a key can exist without us ever having seen it
|
|
18
|
+
* written. Currently unused by the card list; kept because the host computes
|
|
19
|
+
* it for the Events tab anyway.
|
|
20
|
+
*/
|
|
21
|
+
lastWriteByKey?: Record<string, number>;
|
|
14
22
|
onViewHistory?: (key: string) => void;
|
|
15
23
|
enabledStorageTypes?: Set<'async' | 'mmkv' | 'secure'>;
|
|
24
|
+
/**
|
|
25
|
+
* Status filter (valid / missing / issues), lifted so a host that has its own
|
|
26
|
+
* toolbar can render the counters there — the desktop dashboard puts them
|
|
27
|
+
* beside the search field. Omit both to keep the filter internal.
|
|
28
|
+
*/
|
|
29
|
+
statusFilter?: StorageFilterType;
|
|
30
|
+
onStatusFilterChange?: (filter: StorageFilterType) => void;
|
|
31
|
+
/** Reports the three status counts whenever they change, for that host toolbar. */
|
|
32
|
+
onStatusCountsChange?: (counts: {
|
|
33
|
+
validCount: number;
|
|
34
|
+
missingCount: number;
|
|
35
|
+
issuesCount: number;
|
|
36
|
+
}) => void;
|
|
16
37
|
/** Keys pinned to the top of the list */
|
|
17
38
|
pinnedKeys?: Set<string>;
|
|
18
39
|
/** Toggle a key's pinned state */
|
|
19
40
|
onTogglePin?: (key: string) => void;
|
|
41
|
+
/** Backend filter, lifted so the Events tab can share the same selection. */
|
|
42
|
+
storageTypeFilter?: StorageTypeFilter;
|
|
43
|
+
onStorageTypeFilterChange?: (type: StorageTypeFilter) => void;
|
|
44
|
+
/** Pad full-screen views past the home indicator (docked sheet only). */
|
|
45
|
+
applySafeAreaInset?: boolean;
|
|
20
46
|
}
|
|
21
|
-
export declare function GameUIStorageBrowser({ requiredStorageKeys, showFilters, ignoredPatterns, onTogglePattern, onAddPattern, searchQuery, storageDataRef, eventCountByKey, onViewHistory, enabledStorageTypes, pinnedKeys, onTogglePin, }: GameUIStorageBrowserProps): import("react").JSX.Element;
|
|
47
|
+
export declare function GameUIStorageBrowser({ requiredStorageKeys, showFilters, ignoredPatterns, onTogglePattern, onAddPattern, searchQuery, storageDataRef, eventCountByKey, lastWriteByKey, onViewHistory, enabledStorageTypes, statusFilter, onStatusFilterChange, onStatusCountsChange, pinnedKeys, onTogglePin, storageTypeFilter, onStorageTypeFilterChange, applySafeAreaInset, }: GameUIStorageBrowserProps): import("react").JSX.Element;
|
|
22
48
|
export {};
|
|
23
49
|
//# sourceMappingURL=GameUIStorageBrowser.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GameUIStorageBrowser.d.ts","sourceRoot":"","sources":["../../../../src/storage/components/GameUIStorageBrowser.tsx"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"GameUIStorageBrowser.d.ts","sourceRoot":"","sources":["../../../../src/storage/components/GameUIStorageBrowser.tsx"],"names":[],"mappings":"AAAA,OAAO,EAML,gBAAgB,EACjB,MAAM,OAAO,CAAC;AAWf,OAAO,EAAkB,kBAAkB,EAAmB,MAAM,UAAU,CAAC;AAK/E,OAAO,EAEL,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACvB,MAAM,sBAAsB,CAAC;AA2C9B,uCAAuC;AACvC,eAAO,MAAM,mBAAmB,KAAK,CAAC;AAEtC,UAAU,yBAAyB;IACjC,mBAAmB,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAC3C,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC9B,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,gBAAgB,CAAC,GAAG,EAAE,CAAC,CAAC;IACzC,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzC;;;;;OAKG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,mBAAmB,CAAC,EAAE,GAAG,CAAC,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAC,CAAC;IACvD;;;;OAIG;IACH,YAAY,CAAC,EAAE,iBAAiB,CAAC;IACjC,oBAAoB,CAAC,EAAE,CAAC,MAAM,EAAE,iBAAiB,KAAK,IAAI,CAAC;IAC3D,mFAAmF;IACnF,oBAAoB,CAAC,EAAE,CAAC,MAAM,EAAE;QAC9B,UAAU,EAAE,MAAM,CAAC;QACnB,YAAY,EAAE,MAAM,CAAC;QACrB,WAAW,EAAE,MAAM,CAAC;KACrB,KAAK,IAAI,CAAC;IACX,yCAAyC;IACzC,UAAU,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACzB,kCAAkC;IAClC,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,6EAA6E;IAC7E,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;IACtC,yBAAyB,CAAC,EAAE,CAAC,IAAI,EAAE,iBAAiB,KAAK,IAAI,CAAC;IAC9D,yEAAyE;IACzE,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED,wBAAgB,oBAAoB,CAAC,EACnC,mBAAwB,EACxB,WAAmB,EACnB,eAA0C,EAC1C,eAAe,EACf,YAAY,EACZ,WAAgB,EAChB,cAAc,EACd,eAAe,EACf,cAAc,EACd,aAAa,EACb,mBAAmB,EACnB,YAAY,EACZ,oBAAoB,EACpB,oBAAoB,EACpB,UAAU,EACV,WAAW,EACX,iBAAiB,EACjB,yBAAyB,EACzB,kBAAkB,GACnB,EAAE,yBAAyB,+BA+9B3B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SelectionActionBar.d.ts","sourceRoot":"","sources":["../../../../src/storage/components/SelectionActionBar.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"SelectionActionBar.d.ts","sourceRoot":"","sources":["../../../../src/storage/components/SelectionActionBar.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAG1C,UAAU,uBAAuB;IAC/B,4BAA4B;IAC5B,YAAY,EAAE,cAAc,EAAE,CAAC;IAC/B,kCAAkC;IAClC,aAAa,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,GAAG,CAAA;KAAE,CAAC,CAAC;IACpD,yCAAyC;IACzC,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAC;IAC9B,gEAAgE;IAChE,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,cAAc,EAAE,KAAK,IAAI,CAAC;IAC9C,0CAA0C;IAC1C,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB,kCAAkC;IAClC,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAC;IAC9B,mCAAmC;IACnC,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,wBAAgB,kBAAkB,CAAC,EACjC,YAAY,EACZ,aAAa,EACb,gBAAgB,EAChB,UAAU,EACV,WAAW,EACX,gBAAgB,EAChB,gBAAgB,GACjB,EAAE,uBAAuB,sCA6HzB"}
|