@buoy-gg/storage 7.0.41 → 7.0.42
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -90
- package/lib/commonjs/index.js +1 -353
- package/lib/commonjs/preset.js +1 -85
- package/lib/commonjs/storage/components/DiffViewer/TreeDiffViewer.js +1 -36
- package/lib/commonjs/storage/components/DiffViewer/modes/ThemedSplitView.js +1 -12
- package/lib/commonjs/storage/components/DiffViewer/themes/diffThemes.js +1 -24
- package/lib/commonjs/storage/components/GameUIStorageBrowser.js +3 -1259
- package/lib/commonjs/storage/components/MMKVInstanceInfoPanel.js +1 -257
- package/lib/commonjs/storage/components/MMKVInstanceSelector.js +1 -419
- package/lib/commonjs/storage/components/SelectionActionBar.js +1 -207
- package/lib/commonjs/storage/components/StorageActionButtons.js +1 -242
- package/lib/commonjs/storage/components/StorageBrowserMode.js +1 -61
- package/lib/commonjs/storage/components/StorageEventActionButton.js +1 -121
- package/lib/commonjs/storage/components/StorageEventCard.js +1 -118
- package/lib/commonjs/storage/components/StorageEventDetailContent.js +1 -494
- package/lib/commonjs/storage/components/StorageEventFilterView.js +1 -160
- package/lib/commonjs/storage/components/StorageEventsSection.js +1 -24
- package/lib/commonjs/storage/components/StorageFilterCards.js +1 -231
- package/lib/commonjs/storage/components/StorageKeyCard.js +1 -520
- package/lib/commonjs/storage/components/StorageKeyDetailScreen.js +1 -579
- package/lib/commonjs/storage/components/StorageKeyRow.js +1 -559
- package/lib/commonjs/storage/components/StorageKeySection.js +1 -160
- package/lib/commonjs/storage/components/StorageKeyStats.js +1 -345
- package/lib/commonjs/storage/components/StorageModalWithTabs.js +1 -954
- package/lib/commonjs/storage/components/StorageSaveNotice.js +1 -171
- package/lib/commonjs/storage/components/StorageSection.js +1 -43
- package/lib/commonjs/storage/components/StorageTypeFilterBar.js +1 -144
- package/lib/commonjs/storage/hooks/useAsyncStorageKeys.js +1 -141
- package/lib/commonjs/storage/hooks/useMMKVInstances.js +1 -210
- package/lib/commonjs/storage/hooks/useMMKVKeys.js +1 -376
- package/lib/commonjs/storage/hooks/useSecureStoreKeys.js +1 -202
- package/lib/commonjs/storage/hooks/useStorageEvents.js +1 -61
- package/lib/commonjs/storage/stores/storageEventStore.js +1 -312
- package/lib/commonjs/storage/sync/storageSyncAdapter.js +1 -492
- package/lib/commonjs/storage/types.js +1 -5
- package/lib/commonjs/storage/utils/AsyncStorageListener.js +1 -691
- package/lib/commonjs/storage/utils/AsyncStorageListener.web.js +1 -89
- package/lib/commonjs/storage/utils/MMKVInstanceRegistry.js +1 -203
- package/lib/commonjs/storage/utils/MMKVListener.js +1 -416
- package/lib/commonjs/storage/utils/SecureStoreRegistry.js +1 -200
- package/lib/commonjs/storage/utils/asyncStorageCompat.js +1 -89
- package/lib/commonjs/storage/utils/browserStorageLifecycle.js +1 -10
- package/lib/commonjs/storage/utils/browserStorageLifecycle.web.js +1 -70
- package/lib/commonjs/storage/utils/clearAllStorage.js +1 -48
- package/lib/commonjs/storage/utils/deleteStorageKeys.js +1 -82
- package/lib/commonjs/storage/utils/lineDiff.js +1 -30
- package/lib/commonjs/storage/utils/mmkvAvailability.js +1 -62
- package/lib/commonjs/storage/utils/mmkvAvailability.web.js +1 -21
- package/lib/commonjs/storage/utils/mmkvTypeDetection.js +1 -154
- package/lib/commonjs/storage/utils/requiredStorageKeyScope.js +1 -17
- package/lib/commonjs/storage/utils/setStorageValue.js +1 -218
- package/lib/commonjs/storage/utils/snapshotProvider.js +1 -382
- package/lib/commonjs/storage/utils/storageActionHelpers.js +1 -46
- package/lib/commonjs/storage/utils/storageBrowserRefresh.js +1 -49
- package/lib/commonjs/storage/utils/storageLabels.js +1 -13
- package/lib/commonjs/storage/utils/storageLabels.web.js +1 -13
- package/lib/commonjs/storage/utils/storageOps.js +1 -53
- package/lib/commonjs/storage/utils/storageQueryUtils.js +1 -35
- package/lib/commonjs/storage/utils/storageTimeTravelUtils.js +1 -288
- package/lib/commonjs/storage/utils/valueType.js +1 -83
- package/lib/module/index.js +1 -114
- package/lib/module/preset.js +1 -82
- package/lib/module/storage/components/DiffViewer/TreeDiffViewer.js +1 -32
- package/lib/module/storage/components/DiffViewer/modes/ThemedSplitView.js +1 -9
- package/lib/module/storage/components/DiffViewer/themes/diffThemes.js +1 -10
- package/lib/module/storage/components/GameUIStorageBrowser.js +3 -1257
- package/lib/module/storage/components/MMKVInstanceInfoPanel.js +1 -253
- package/lib/module/storage/components/MMKVInstanceSelector.js +1 -415
- package/lib/module/storage/components/SelectionActionBar.js +1 -204
- package/lib/module/storage/components/StorageActionButtons.js +1 -238
- package/lib/module/storage/components/StorageBrowserMode.js +1 -57
- package/lib/module/storage/components/StorageEventActionButton.js +1 -118
- package/lib/module/storage/components/StorageEventCard.js +1 -113
- package/lib/module/storage/components/StorageEventDetailContent.js +1 -490
- package/lib/module/storage/components/StorageEventFilterView.js +1 -156
- package/lib/module/storage/components/StorageEventsSection.js +1 -20
- package/lib/module/storage/components/StorageFilterCards.js +1 -227
- package/lib/module/storage/components/StorageKeyCard.js +1 -517
- package/lib/module/storage/components/StorageKeyDetailScreen.js +1 -577
- package/lib/module/storage/components/StorageKeyRow.js +1 -554
- package/lib/module/storage/components/StorageKeySection.js +1 -155
- package/lib/module/storage/components/StorageKeyStats.js +1 -342
- package/lib/module/storage/components/StorageModalWithTabs.js +1 -949
- package/lib/module/storage/components/StorageSaveNotice.js +1 -168
- package/lib/module/storage/components/StorageSection.js +1 -40
- package/lib/module/storage/components/StorageTypeFilterBar.js +1 -139
- package/lib/module/storage/hooks/useAsyncStorageKeys.js +1 -136
- package/lib/module/storage/hooks/useMMKVInstances.js +1 -204
- package/lib/module/storage/hooks/useMMKVKeys.js +1 -371
- package/lib/module/storage/hooks/useSecureStoreKeys.js +1 -199
- package/lib/module/storage/hooks/useStorageEvents.js +1 -58
- package/lib/module/storage/stores/storageEventStore.js +1 -301
- package/lib/module/storage/sync/storageSyncAdapter.js +1 -486
- package/lib/module/storage/types.js +1 -3
- package/lib/module/storage/utils/AsyncStorageListener.js +1 -679
- package/lib/module/storage/utils/AsyncStorageListener.web.js +1 -76
- package/lib/module/storage/utils/MMKVInstanceRegistry.js +1 -197
- package/lib/module/storage/utils/MMKVListener.js +1 -403
- package/lib/module/storage/utils/SecureStoreRegistry.js +1 -194
- package/lib/module/storage/utils/asyncStorageCompat.js +1 -81
- package/lib/module/storage/utils/browserStorageLifecycle.js +1 -6
- package/lib/module/storage/utils/browserStorageLifecycle.web.js +1 -66
- package/lib/module/storage/utils/clearAllStorage.js +1 -43
- package/lib/module/storage/utils/deleteStorageKeys.js +1 -78
- package/lib/module/storage/utils/lineDiff.js +1 -12
- package/lib/module/storage/utils/mmkvAvailability.js +1 -56
- package/lib/module/storage/utils/mmkvAvailability.web.js +1 -15
- package/lib/module/storage/utils/mmkvTypeDetection.js +1 -148
- package/lib/module/storage/utils/requiredStorageKeyScope.js +1 -13
- package/lib/module/storage/utils/setStorageValue.js +1 -209
- package/lib/module/storage/utils/snapshotProvider.js +1 -380
- package/lib/module/storage/utils/storageActionHelpers.js +1 -42
- package/lib/module/storage/utils/storageBrowserRefresh.js +1 -44
- package/lib/module/storage/utils/storageLabels.js +1 -9
- package/lib/module/storage/utils/storageLabels.web.js +1 -9
- package/lib/module/storage/utils/storageOps.js +1 -46
- package/lib/module/storage/utils/storageQueryUtils.js +1 -30
- package/lib/module/storage/utils/storageTimeTravelUtils.js +1 -281
- package/lib/module/storage/utils/valueType.js +1 -76
- package/lib/web/index.mjs +2 -3
- package/package.json +5 -5
- package/lib/typescript/index.d.ts.map +0 -1
- package/lib/typescript/preset.d.ts.map +0 -1
- package/lib/typescript/storage/components/DiffViewer/TreeDiffViewer.d.ts.map +0 -1
- package/lib/typescript/storage/components/DiffViewer/modes/ThemedSplitView.d.ts.map +0 -1
- package/lib/typescript/storage/components/DiffViewer/themes/diffThemes.d.ts.map +0 -1
- package/lib/typescript/storage/components/GameUIStorageBrowser.d.ts.map +0 -1
- package/lib/typescript/storage/components/MMKVInstanceInfoPanel.d.ts.map +0 -1
- package/lib/typescript/storage/components/MMKVInstanceSelector.d.ts.map +0 -1
- package/lib/typescript/storage/components/SelectionActionBar.d.ts.map +0 -1
- package/lib/typescript/storage/components/StorageActionButtons.d.ts.map +0 -1
- package/lib/typescript/storage/components/StorageBrowserMode.d.ts.map +0 -1
- package/lib/typescript/storage/components/StorageEventActionButton.d.ts.map +0 -1
- package/lib/typescript/storage/components/StorageEventCard.d.ts.map +0 -1
- package/lib/typescript/storage/components/StorageEventDetailContent.d.ts.map +0 -1
- package/lib/typescript/storage/components/StorageEventFilterView.d.ts.map +0 -1
- package/lib/typescript/storage/components/StorageEventsSection.d.ts.map +0 -1
- package/lib/typescript/storage/components/StorageFilterCards.d.ts.map +0 -1
- package/lib/typescript/storage/components/StorageKeyCard.d.ts.map +0 -1
- package/lib/typescript/storage/components/StorageKeyDetailScreen.d.ts.map +0 -1
- package/lib/typescript/storage/components/StorageKeyRow.d.ts.map +0 -1
- package/lib/typescript/storage/components/StorageKeySection.d.ts.map +0 -1
- package/lib/typescript/storage/components/StorageKeyStats.d.ts.map +0 -1
- package/lib/typescript/storage/components/StorageModalWithTabs.d.ts.map +0 -1
- package/lib/typescript/storage/components/StorageSaveNotice.d.ts.map +0 -1
- package/lib/typescript/storage/components/StorageSection.d.ts.map +0 -1
- package/lib/typescript/storage/components/StorageTypeFilterBar.d.ts.map +0 -1
- package/lib/typescript/storage/hooks/useAsyncStorageKeys.d.ts.map +0 -1
- package/lib/typescript/storage/hooks/useMMKVInstances.d.ts.map +0 -1
- package/lib/typescript/storage/hooks/useMMKVKeys.d.ts.map +0 -1
- package/lib/typescript/storage/hooks/useSecureStoreKeys.d.ts.map +0 -1
- package/lib/typescript/storage/hooks/useStorageEvents.d.ts.map +0 -1
- package/lib/typescript/storage/stores/storageEventStore.d.ts.map +0 -1
- package/lib/typescript/storage/sync/storageSyncAdapter.d.ts.map +0 -1
- package/lib/typescript/storage/types.d.ts.map +0 -1
- package/lib/typescript/storage/utils/AsyncStorageListener.d.ts.map +0 -1
- package/lib/typescript/storage/utils/AsyncStorageListener.web.d.ts.map +0 -1
- package/lib/typescript/storage/utils/MMKVInstanceRegistry.d.ts.map +0 -1
- package/lib/typescript/storage/utils/MMKVListener.d.ts.map +0 -1
- package/lib/typescript/storage/utils/SecureStoreRegistry.d.ts.map +0 -1
- package/lib/typescript/storage/utils/asyncStorageCompat.d.ts.map +0 -1
- package/lib/typescript/storage/utils/browserStorageLifecycle.d.ts.map +0 -1
- package/lib/typescript/storage/utils/browserStorageLifecycle.web.d.ts.map +0 -1
- package/lib/typescript/storage/utils/clearAllStorage.d.ts.map +0 -1
- package/lib/typescript/storage/utils/deleteStorageKeys.d.ts.map +0 -1
- package/lib/typescript/storage/utils/lineDiff.d.ts.map +0 -1
- package/lib/typescript/storage/utils/mmkvAvailability.d.ts.map +0 -1
- package/lib/typescript/storage/utils/mmkvAvailability.web.d.ts.map +0 -1
- package/lib/typescript/storage/utils/mmkvTypeDetection.d.ts.map +0 -1
- package/lib/typescript/storage/utils/requiredStorageKeyScope.d.ts.map +0 -1
- package/lib/typescript/storage/utils/setStorageValue.d.ts.map +0 -1
- package/lib/typescript/storage/utils/snapshotProvider.d.ts.map +0 -1
- package/lib/typescript/storage/utils/storageActionHelpers.d.ts.map +0 -1
- package/lib/typescript/storage/utils/storageBrowserRefresh.d.ts.map +0 -1
- package/lib/typescript/storage/utils/storageLabels.d.ts.map +0 -1
- package/lib/typescript/storage/utils/storageLabels.web.d.ts.map +0 -1
- package/lib/typescript/storage/utils/storageOps.d.ts.map +0 -1
- package/lib/typescript/storage/utils/storageQueryUtils.d.ts.map +0 -1
- package/lib/typescript/storage/utils/storageTimeTravelUtils.d.ts.map +0 -1
- package/lib/typescript/storage/utils/valueType.d.ts.map +0 -1
|
@@ -1,218 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.setStorageValue = setStorageValue;
|
|
7
|
-
exports.storageEditBlockedReason = storageEditBlockedReason;
|
|
8
|
-
exports.storageValueToEditableText = storageValueToEditableText;
|
|
9
|
-
exports.structuredStorageValue = structuredStorageValue;
|
|
10
|
-
exports.validateStorageValue = validateStorageValue;
|
|
11
|
-
var _asyncStorage = _interopRequireDefault(require("@react-native-async-storage/async-storage"));
|
|
12
|
-
var _SecureStoreRegistry = require("./SecureStoreRegistry");
|
|
13
|
-
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
14
|
-
/**
|
|
15
|
-
* Writing a storage value back, in one place.
|
|
16
|
-
*
|
|
17
|
-
* The counterpart to `deleteStorageKeys` — and the same reasoning applies: each
|
|
18
|
-
* backend writes differently, and a second copy of that fan-out is how one
|
|
19
|
-
* backend quietly starts corrupting values.
|
|
20
|
-
*
|
|
21
|
-
* The hard part is NOT the write, it's the types:
|
|
22
|
-
*
|
|
23
|
-
* - **AsyncStorage** stores strings only. A value that was stored as JSON must
|
|
24
|
-
* stay valid JSON, or an object silently becomes a quoted string and the app
|
|
25
|
-
* that reads it breaks in a way that looks nothing like a devtools edit.
|
|
26
|
-
* - **MMKV** is natively typed (string / number / boolean / buffer). Writing
|
|
27
|
-
* `"42"` over a number turns it into a string, so the original type is
|
|
28
|
-
* restored from `valueType`. Buffers can't round-trip at all — the snapshot
|
|
29
|
-
* only ever carried a `<ArrayBuffer n bytes>` placeholder.
|
|
30
|
-
* - **SecureStore** stores strings, and biometric-protected keys are never
|
|
31
|
-
* touched (writing needs the same auth prompt reading does).
|
|
32
|
-
*
|
|
33
|
-
* Pro gating and confirmation are deliberately NOT here; they belong to the UI
|
|
34
|
-
* that has the user's attention. This assumes the caller already asked.
|
|
35
|
-
*/
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Why a key can't be edited, or null when it can. UI uses this both to hide the
|
|
39
|
-
* edit affordance and to explain itself, rather than failing at save time.
|
|
40
|
-
*/
|
|
41
|
-
function storageEditBlockedReason(storageKey, mmkvInstances = []) {
|
|
42
|
-
if (storageKey.storageType === "mmkv") {
|
|
43
|
-
if (storageKey.valueType === "buffer") {
|
|
44
|
-
return "Buffer values can't be edited — the tool only ever sees their byte length, not their contents.";
|
|
45
|
-
}
|
|
46
|
-
const instance = mmkvInstances.find(i => i.id === (storageKey.instanceId || "default"));
|
|
47
|
-
if (instance?.readOnly) {
|
|
48
|
-
return `MMKV instance "${instance.id}" is registered read-only.`;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
if (storageKey.storageType === "secure") {
|
|
52
|
-
const entry = _SecureStoreRegistry.secureStoreRegistry.getAll().find(e => e.key === storageKey.key);
|
|
53
|
-
if (entry?.options.requireAuthentication) {
|
|
54
|
-
return "Biometric-protected keys can't be edited — writing one would fire an auth prompt.";
|
|
55
|
-
}
|
|
56
|
-
if (!_SecureStoreRegistry.secureStoreRegistry.getModule()) {
|
|
57
|
-
return "No SecureStore module is registered.";
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
return null;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Validate `raw` for this key WITHOUT writing. Returns an error message, or
|
|
65
|
-
* null when the text is acceptable. The editor calls this as you type.
|
|
66
|
-
*/
|
|
67
|
-
function validateStorageValue(storageKey, raw) {
|
|
68
|
-
if (storageKey.storageType === "mmkv") {
|
|
69
|
-
const type = mmkvTargetType(storageKey);
|
|
70
|
-
if (type === "number") {
|
|
71
|
-
if (raw.trim() === "" || Number.isNaN(Number(raw))) {
|
|
72
|
-
return "Must be a number — this MMKV key is stored as a number.";
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
if (type === "boolean") {
|
|
76
|
-
const t = raw.trim().toLowerCase();
|
|
77
|
-
if (t !== "true" && t !== "false") {
|
|
78
|
-
return 'Must be "true" or "false" — this MMKV key is stored as a boolean.';
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
return null;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// AsyncStorage + SecureStore are string-valued. Only guard the case where
|
|
85
|
-
// the CURRENT value is structured: silently flattening an object into a
|
|
86
|
-
// string is the corruption worth preventing. A plain string stays free-form.
|
|
87
|
-
if (isStructured(storageKey.value)) {
|
|
88
|
-
try {
|
|
89
|
-
JSON.parse(raw);
|
|
90
|
-
} catch (e) {
|
|
91
|
-
return `This key holds JSON — ${e instanceof Error ? e.message : "invalid JSON"}`;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
return null;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* The text an editor should open with: JSON pretty-printed so it's actually
|
|
99
|
-
* editable, everything else verbatim.
|
|
100
|
-
*/
|
|
101
|
-
function storageValueToEditableText(value) {
|
|
102
|
-
if (value === undefined || value === null) return "";
|
|
103
|
-
if (typeof value === "string") {
|
|
104
|
-
// Values arrive already parsed when they were JSON, so a string here is a
|
|
105
|
-
// real string — except AsyncStorage hands back raw JSON text sometimes.
|
|
106
|
-
const trimmed = value.trim();
|
|
107
|
-
if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
|
|
108
|
-
try {
|
|
109
|
-
return JSON.stringify(JSON.parse(value), null, 2);
|
|
110
|
-
} catch {
|
|
111
|
-
return value;
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
return value;
|
|
115
|
-
}
|
|
116
|
-
if (typeof value === "object") return JSON.stringify(value, null, 2);
|
|
117
|
-
return String(value);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* The value as a STRUCTURE, for the tree editor to apply ops against.
|
|
122
|
-
*
|
|
123
|
-
* Backends disagree on how far they've already parsed: `useAsyncStorageKeys`
|
|
124
|
-
* hands back a parsed object, while MMKV reports its native type so a JSON blob
|
|
125
|
-
* arrives as the raw string. Both have to end up as the same thing before an op
|
|
126
|
-
* can address a path inside them.
|
|
127
|
-
*
|
|
128
|
-
* Returns `undefined` when the value isn't a container — scalars are edited
|
|
129
|
-
* through the plain value editor, not the tree.
|
|
130
|
-
*/
|
|
131
|
-
function structuredStorageValue(storageKey) {
|
|
132
|
-
const {
|
|
133
|
-
value
|
|
134
|
-
} = storageKey;
|
|
135
|
-
if (value !== null && typeof value === "object") return value;
|
|
136
|
-
if (typeof value === "string") {
|
|
137
|
-
const trimmed = value.trim();
|
|
138
|
-
if (!trimmed.startsWith("{") && !trimmed.startsWith("[")) return undefined;
|
|
139
|
-
try {
|
|
140
|
-
const parsed = JSON.parse(value);
|
|
141
|
-
return parsed !== null && typeof parsed === "object" ? parsed : undefined;
|
|
142
|
-
} catch {
|
|
143
|
-
return undefined;
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
return undefined;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* Write `raw` to whichever backend holds this key, restoring the value's
|
|
151
|
-
* original type. Rejects (rather than writing something lossy) when the key
|
|
152
|
-
* isn't editable or the text doesn't fit the type — callers surface that.
|
|
153
|
-
*/
|
|
154
|
-
async function setStorageValue(storageKey, raw, mmkvInstances = []) {
|
|
155
|
-
const blocked = storageEditBlockedReason(storageKey, mmkvInstances);
|
|
156
|
-
if (blocked) throw new Error(blocked);
|
|
157
|
-
const invalid = validateStorageValue(storageKey, raw);
|
|
158
|
-
if (invalid) throw new Error(invalid);
|
|
159
|
-
switch (storageKey.storageType) {
|
|
160
|
-
case "async":
|
|
161
|
-
{
|
|
162
|
-
await _asyncStorage.default.setItem(storageKey.key, normalizeJsonText(storageKey, raw));
|
|
163
|
-
return;
|
|
164
|
-
}
|
|
165
|
-
case "secure":
|
|
166
|
-
{
|
|
167
|
-
await _SecureStoreRegistry.secureStoreRegistry.setValue(storageKey.key, normalizeJsonText(storageKey, raw));
|
|
168
|
-
return;
|
|
169
|
-
}
|
|
170
|
-
case "mmkv":
|
|
171
|
-
{
|
|
172
|
-
const instanceId = storageKey.instanceId || "default";
|
|
173
|
-
const target = mmkvInstances.find(i => i.id === instanceId);
|
|
174
|
-
if (!target) {
|
|
175
|
-
throw new Error(`MMKV instance "${instanceId}" is not registered.`);
|
|
176
|
-
}
|
|
177
|
-
target.instance.set(storageKey.key, coerceMMKV(storageKey, raw));
|
|
178
|
-
return;
|
|
179
|
-
}
|
|
180
|
-
default:
|
|
181
|
-
{
|
|
182
|
-
throw new Error(`Unsupported storage type "${String(storageKey.storageType)}"`);
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
/** True when the value is an object/array (so its text must stay valid JSON). */
|
|
188
|
-
function isStructured(value) {
|
|
189
|
-
return value !== null && typeof value === "object";
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
/**
|
|
193
|
-
* Re-serialize JSON so the stored string is compact and canonical, matching
|
|
194
|
-
* what the app itself would have written with `JSON.stringify`. Free-form
|
|
195
|
-
* strings pass through untouched.
|
|
196
|
-
*/
|
|
197
|
-
function normalizeJsonText(storageKey, raw) {
|
|
198
|
-
if (!isStructured(storageKey.value)) return raw;
|
|
199
|
-
return JSON.stringify(JSON.parse(raw));
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
/** The MMKV native type to write back, defaulting to the current JS type. */
|
|
203
|
-
function mmkvTargetType(storageKey) {
|
|
204
|
-
if (storageKey.valueType) return storageKey.valueType;
|
|
205
|
-
if (typeof storageKey.value === "number") return "number";
|
|
206
|
-
if (typeof storageKey.value === "boolean") return "boolean";
|
|
207
|
-
return "string";
|
|
208
|
-
}
|
|
209
|
-
function coerceMMKV(storageKey, raw) {
|
|
210
|
-
switch (mmkvTargetType(storageKey)) {
|
|
211
|
-
case "number":
|
|
212
|
-
return Number(raw);
|
|
213
|
-
case "boolean":
|
|
214
|
-
return raw.trim().toLowerCase() === "true";
|
|
215
|
-
default:
|
|
216
|
-
return raw;
|
|
217
|
-
}
|
|
218
|
-
}
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.setStorageValue=setStorageValue;exports.storageEditBlockedReason=storageEditBlockedReason;exports.storageValueToEditableText=storageValueToEditableText;exports.structuredStorageValue=structuredStorageValue;exports.validateStorageValue=validateStorageValue;var _asyncStorage=_interopRequireDefault(require("@react-native-async-storage/async-storage"));var _SecureStoreRegistry=require("./SecureStoreRegistry");function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e}}function storageEditBlockedReason(e,t=[]){if(e.storageType==="mmkv"){if(e.valueType==="buffer"){return"Buffer values can't be edited \u2014 the tool only ever sees their byte length, not their contents."}const r=t.find(n=>n.id===(e.instanceId||"default"));if(r?.readOnly){return`MMKV instance "${r.id}" is registered read-only.`}}if(e.storageType==="secure"){const r=_SecureStoreRegistry.secureStoreRegistry.getAll().find(n=>n.key===e.key);if(r?.options.requireAuthentication){return"Biometric-protected keys can't be edited \u2014 writing one would fire an auth prompt."}if(!_SecureStoreRegistry.secureStoreRegistry.getModule()){return"No SecureStore module is registered."}}return null}function validateStorageValue(e,t){if(e.storageType==="mmkv"){const r=mmkvTargetType(e);if(r==="number"){if(t.trim()===""||Number.isNaN(Number(t))){return"Must be a number \u2014 this MMKV key is stored as a number."}}if(r==="boolean"){const n=t.trim().toLowerCase();if(n!=="true"&&n!=="false"){return'Must be "true" or "false" \u2014 this MMKV key is stored as a boolean.'}}return null}if(isStructured(e.value)){try{JSON.parse(t)}catch(r){return`This key holds JSON \u2014 ${r instanceof Error?r.message:"invalid JSON"}`}}return null}function storageValueToEditableText(e){if(e===void 0||e===null)return"";if(typeof e==="string"){const t=e.trim();if(t.startsWith("{")||t.startsWith("[")){try{return JSON.stringify(JSON.parse(e),null,2)}catch{return e}}return e}if(typeof e==="object")return JSON.stringify(e,null,2);return String(e)}function structuredStorageValue(e){const{value:t}=e;if(t!==null&&typeof t==="object")return t;if(typeof t==="string"){const r=t.trim();if(!r.startsWith("{")&&!r.startsWith("["))return void 0;try{const n=JSON.parse(t);return n!==null&&typeof n==="object"?n:void 0}catch{return void 0}}return void 0}async function setStorageValue(e,t,r=[]){const n=storageEditBlockedReason(e,r);if(n)throw new Error(n);const i=validateStorageValue(e,t);if(i)throw new Error(i);switch(e.storageType){case"async":{await _asyncStorage.default.setItem(e.key,normalizeJsonText(e,t));return}case"secure":{await _SecureStoreRegistry.secureStoreRegistry.setValue(e.key,normalizeJsonText(e,t));return}case"mmkv":{const u=e.instanceId||"default";const o=r.find(s=>s.id===u);if(!o){throw new Error(`MMKV instance "${u}" is not registered.`)}o.instance.set(e.key,coerceMMKV(e,t));return}default:{throw new Error(`Unsupported storage type "${String(e.storageType)}"`)}}}function isStructured(e){return e!==null&&typeof e==="object"}function normalizeJsonText(e,t){if(!isStructured(e.value))return t;return JSON.stringify(JSON.parse(t))}function mmkvTargetType(e){if(e.valueType)return e.valueType;if(typeof e.value==="number")return"number";if(typeof e.value==="boolean")return"boolean";return"string"}function coerceMMKV(e,t){switch(mmkvTargetType(e)){case"number":return Number(t);case"boolean":return t.trim().toLowerCase()==="true";default:return t}}
|
|
@@ -1,382 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
var _asyncStorage = _interopRequireDefault(require("@react-native-async-storage/async-storage"));
|
|
4
|
-
var _sharedUi = require("@buoy-gg/shared-ui");
|
|
5
|
-
var _asyncStorageCompat = require("./asyncStorageCompat");
|
|
6
|
-
var _clearAllStorage = require("./clearAllStorage");
|
|
7
|
-
var _MMKVInstanceRegistry = require("./MMKVInstanceRegistry");
|
|
8
|
-
var _mmkvTypeDetection = require("./mmkvTypeDetection");
|
|
9
|
-
var _SecureStoreRegistry = require("./SecureStoreRegistry");
|
|
10
|
-
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
11
|
-
/**
|
|
12
|
-
* Time Machine snapshot provider for device storage (AsyncStorage + MMKV +
|
|
13
|
-
* SecureStore).
|
|
14
|
-
*
|
|
15
|
-
* Registered into @buoy-gg/shared-ui's stateSnapshotRegistry at module init;
|
|
16
|
-
* consumed by @buoy-gg/time-machine.
|
|
17
|
-
*
|
|
18
|
-
* Buoy's own keys (isDevToolsStorageKey — @react_buoy*, @buoy*, buoy-*,
|
|
19
|
-
* legacy patterns) are excluded on BOTH capture and restore, so a snapshot
|
|
20
|
-
* can never clobber dev-tool settings. Restore is a diff: app keys missing
|
|
21
|
-
* from the snapshot are deleted, snapshot entries are written back.
|
|
22
|
-
*
|
|
23
|
-
* Known-lossy by design (each surfaces a warning/skip):
|
|
24
|
-
* - MMKV ArrayBuffer values are never transported.
|
|
25
|
-
* - SecureStore biometric keys are never read or written (auth prompt).
|
|
26
|
-
* - SecureStore keys outside the registered descriptor list are invisible.
|
|
27
|
-
*/
|
|
28
|
-
|
|
29
|
-
function deleteMMKVKey(instance, key) {
|
|
30
|
-
// v4 renamed delete() to remove() — support both
|
|
31
|
-
if (instance.remove) instance.remove(key);else instance.delete?.(key);
|
|
32
|
-
}
|
|
33
|
-
function status() {
|
|
34
|
-
return {
|
|
35
|
-
canCapture: true,
|
|
36
|
-
canRestore: true
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/** Shared by capture() and the live side of previewItems(). */
|
|
41
|
-
async function captureStorageData() {
|
|
42
|
-
const warnings = [];
|
|
43
|
-
const appKeys = (await _asyncStorage.default.getAllKeys()).filter(k => !(0, _sharedUi.isDevToolsStorageKey)(k));
|
|
44
|
-
const asyncPairs = (await (0, _asyncStorageCompat.readMany)(appKeys)).filter(pair => pair[1] !== null);
|
|
45
|
-
const mmkv = {};
|
|
46
|
-
for (const {
|
|
47
|
-
id,
|
|
48
|
-
instance
|
|
49
|
-
} of _MMKVInstanceRegistry.mmkvInstanceRegistry.getAll()) {
|
|
50
|
-
try {
|
|
51
|
-
mmkv[id] = instance.getAllKeys().filter(key => !(0, _sharedUi.isDevToolsStorageKey)(key)).map(key => {
|
|
52
|
-
const {
|
|
53
|
-
value,
|
|
54
|
-
type: valueType
|
|
55
|
-
} = (0, _mmkvTypeDetection.detectMMKVType)(instance, key);
|
|
56
|
-
if (valueType === "buffer") {
|
|
57
|
-
warnings.push(`mmkv "${id}"/"${key}": ArrayBuffer value not capturable`);
|
|
58
|
-
}
|
|
59
|
-
return {
|
|
60
|
-
key,
|
|
61
|
-
value,
|
|
62
|
-
valueType
|
|
63
|
-
};
|
|
64
|
-
});
|
|
65
|
-
} catch {
|
|
66
|
-
warnings.push(`mmkv "${id}": unreadable, captured without entries`);
|
|
67
|
-
mmkv[id] = [];
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
const secure = {};
|
|
71
|
-
const secureModule = _SecureStoreRegistry.secureStoreRegistry.getModule();
|
|
72
|
-
for (const {
|
|
73
|
-
key,
|
|
74
|
-
options
|
|
75
|
-
} of _SecureStoreRegistry.secureStoreRegistry.getAll()) {
|
|
76
|
-
if (options.requireAuthentication) {
|
|
77
|
-
warnings.push(`secure "${key}": biometric-protected, not capturable`);
|
|
78
|
-
continue;
|
|
79
|
-
}
|
|
80
|
-
let value = null;
|
|
81
|
-
if (secureModule) {
|
|
82
|
-
try {
|
|
83
|
-
value = await secureModule.getItemAsync(key, options);
|
|
84
|
-
} catch {
|
|
85
|
-
warnings.push(`secure "${key}": unreadable, captured as unset`);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
secure[key] = value;
|
|
89
|
-
}
|
|
90
|
-
return {
|
|
91
|
-
data: {
|
|
92
|
-
async: asyncPairs,
|
|
93
|
-
mmkv,
|
|
94
|
-
secure
|
|
95
|
-
},
|
|
96
|
-
warnings
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
async function capture() {
|
|
100
|
-
const {
|
|
101
|
-
data,
|
|
102
|
-
warnings
|
|
103
|
-
} = await captureStorageData();
|
|
104
|
-
return {
|
|
105
|
-
data,
|
|
106
|
-
warnings
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
async function restore(data, options) {
|
|
110
|
-
const snapshot = data;
|
|
111
|
-
const scope = (0, _sharedUi.createRestoreScope)(options);
|
|
112
|
-
/** True when this item may be touched (scope + exclusions agree). */
|
|
113
|
-
const touch = scope.touch;
|
|
114
|
-
const result = (0, _sharedUi.emptyRestoreResult)();
|
|
115
|
-
if (!snapshot) {
|
|
116
|
-
return (0, _sharedUi.failedRestore)("empty storage snapshot");
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// ── AsyncStorage: delete app keys missing from the snapshot, write the rest ──
|
|
120
|
-
try {
|
|
121
|
-
const snapPairs = (snapshot.async ?? []).filter(([k]) => !(0, _sharedUi.isDevToolsStorageKey)(k) && touch(`async:${k}`));
|
|
122
|
-
const snapKeys = new Set(snapPairs.map(([k]) => k));
|
|
123
|
-
const liveKeys = (await _asyncStorage.default.getAllKeys()).filter(k => !(0, _sharedUi.isDevToolsStorageKey)(k));
|
|
124
|
-
const toRemove = liveKeys.filter(k => !snapKeys.has(k) && touch(`async:${k}`));
|
|
125
|
-
scope.countExcluded((snapshot.async ?? []).length - snapPairs.length);
|
|
126
|
-
if (toRemove.length > 0) await (0, _asyncStorageCompat.removeMany)(toRemove);
|
|
127
|
-
if (snapPairs.length > 0) await (0, _asyncStorageCompat.writeMany)(snapPairs);
|
|
128
|
-
result.applied += snapPairs.length + toRemove.length;
|
|
129
|
-
} catch (e) {
|
|
130
|
-
result.ok = false;
|
|
131
|
-
result.warnings.push(`asyncstorage restore failed: ${String(e)}`);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// ── MMKV: per registered writable instance, diff against the snapshot ──
|
|
135
|
-
for (const [id, entries] of Object.entries(snapshot.mmkv ?? {})) {
|
|
136
|
-
const registered = _MMKVInstanceRegistry.mmkvInstanceRegistry.get(id);
|
|
137
|
-
if (!registered) {
|
|
138
|
-
result.skipped.push({
|
|
139
|
-
id: `mmkv:${id}`,
|
|
140
|
-
reason: "instance not registered"
|
|
141
|
-
});
|
|
142
|
-
continue;
|
|
143
|
-
}
|
|
144
|
-
if (registered.instance.isReadOnly) {
|
|
145
|
-
result.skipped.push({
|
|
146
|
-
id: `mmkv:${id}`,
|
|
147
|
-
reason: "instance registered read-only"
|
|
148
|
-
});
|
|
149
|
-
continue;
|
|
150
|
-
}
|
|
151
|
-
const {
|
|
152
|
-
instance
|
|
153
|
-
} = registered;
|
|
154
|
-
try {
|
|
155
|
-
const snapKeys = new Set(entries.map(e => e.key));
|
|
156
|
-
const liveKeys = instance.getAllKeys().filter(key => !(0, _sharedUi.isDevToolsStorageKey)(key));
|
|
157
|
-
for (const key of liveKeys) {
|
|
158
|
-
if (!scope.allows(`mmkv:${id}/${key}`)) continue;
|
|
159
|
-
if (!snapKeys.has(key)) {
|
|
160
|
-
deleteMMKVKey(instance, key);
|
|
161
|
-
result.applied += 1;
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
for (const entry of entries) {
|
|
165
|
-
if ((0, _sharedUi.isDevToolsStorageKey)(entry.key)) continue;
|
|
166
|
-
if (!touch(`mmkv:${id}/${entry.key}`)) continue;
|
|
167
|
-
if (entry.valueType === "buffer") {
|
|
168
|
-
result.skipped.push({
|
|
169
|
-
id: `mmkv:${id}/${entry.key}`,
|
|
170
|
-
reason: "ArrayBuffer values cannot be restored"
|
|
171
|
-
});
|
|
172
|
-
continue;
|
|
173
|
-
}
|
|
174
|
-
instance.set(entry.key, entry.value);
|
|
175
|
-
result.applied += 1;
|
|
176
|
-
}
|
|
177
|
-
} catch (e) {
|
|
178
|
-
result.ok = false;
|
|
179
|
-
result.warnings.push(`mmkv "${id}" restore failed: ${String(e)}`);
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
// ── SecureStore: diff over the registered, non-biometric descriptor list ──
|
|
184
|
-
const secureSnap = snapshot.secure ?? {};
|
|
185
|
-
for (const {
|
|
186
|
-
key,
|
|
187
|
-
options
|
|
188
|
-
} of _SecureStoreRegistry.secureStoreRegistry.getAll()) {
|
|
189
|
-
if (!scope.allows(`secure:${key}`)) continue;
|
|
190
|
-
if (options.requireAuthentication) {
|
|
191
|
-
if (key in secureSnap) {
|
|
192
|
-
result.skipped.push({
|
|
193
|
-
id: `secure:${key}`,
|
|
194
|
-
reason: "biometric-protected keys are never written"
|
|
195
|
-
});
|
|
196
|
-
}
|
|
197
|
-
continue;
|
|
198
|
-
}
|
|
199
|
-
try {
|
|
200
|
-
if (key in secureSnap) {
|
|
201
|
-
const value = secureSnap[key];
|
|
202
|
-
if (value === null) await _SecureStoreRegistry.secureStoreRegistry.deleteValue(key);else await _SecureStoreRegistry.secureStoreRegistry.setValue(key, value);
|
|
203
|
-
} else {
|
|
204
|
-
// Registered key with no snapshot entry — snapshot predates it; unset.
|
|
205
|
-
await _SecureStoreRegistry.secureStoreRegistry.deleteValue(key);
|
|
206
|
-
}
|
|
207
|
-
result.applied += 1;
|
|
208
|
-
} catch (e) {
|
|
209
|
-
result.ok = false;
|
|
210
|
-
result.warnings.push(`secure "${key}" restore failed: ${String(e)}`);
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
for (const key of Object.keys(secureSnap)) {
|
|
214
|
-
if (!touch(`secure:${key}`)) continue;
|
|
215
|
-
if (!_SecureStoreRegistry.secureStoreRegistry.getAll().some(e => e.key === key)) {
|
|
216
|
-
result.skipped.push({
|
|
217
|
-
id: `secure:${key}`,
|
|
218
|
-
reason: "key no longer registered with registerSecureStoreKeys"
|
|
219
|
-
});
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
const excludedWarning = scope.excludedWarning("item(s)");
|
|
223
|
-
if (excludedWarning) result.warnings.push(excludedWarning);
|
|
224
|
-
return result;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
/** Wipe to fresh-install state (Buoy keys preserved). Used by baseline restore. */
|
|
228
|
-
async function clear() {
|
|
229
|
-
const result = (0, _sharedUi.emptyRestoreResult)();
|
|
230
|
-
try {
|
|
231
|
-
await (0, _clearAllStorage.clearAllAppStorage)();
|
|
232
|
-
result.applied += 1;
|
|
233
|
-
} catch (e) {
|
|
234
|
-
result.ok = false;
|
|
235
|
-
result.warnings.push(`asyncstorage clear failed: ${String(e)}`);
|
|
236
|
-
}
|
|
237
|
-
for (const {
|
|
238
|
-
id,
|
|
239
|
-
instance
|
|
240
|
-
} of _MMKVInstanceRegistry.mmkvInstanceRegistry.getAll()) {
|
|
241
|
-
if (instance.isReadOnly) {
|
|
242
|
-
result.skipped.push({
|
|
243
|
-
id: `mmkv:${id}`,
|
|
244
|
-
reason: "instance registered read-only"
|
|
245
|
-
});
|
|
246
|
-
continue;
|
|
247
|
-
}
|
|
248
|
-
try {
|
|
249
|
-
for (const key of instance.getAllKeys().filter(k => !(0, _sharedUi.isDevToolsStorageKey)(k))) {
|
|
250
|
-
deleteMMKVKey(instance, key);
|
|
251
|
-
result.applied += 1;
|
|
252
|
-
}
|
|
253
|
-
} catch (e) {
|
|
254
|
-
result.ok = false;
|
|
255
|
-
result.warnings.push(`mmkv "${id}" clear failed: ${String(e)}`);
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
for (const {
|
|
259
|
-
key,
|
|
260
|
-
options
|
|
261
|
-
} of _SecureStoreRegistry.secureStoreRegistry.getAll()) {
|
|
262
|
-
if (options.requireAuthentication) {
|
|
263
|
-
result.skipped.push({
|
|
264
|
-
id: `secure:${key}`,
|
|
265
|
-
reason: "biometric-protected keys are never written"
|
|
266
|
-
});
|
|
267
|
-
continue;
|
|
268
|
-
}
|
|
269
|
-
try {
|
|
270
|
-
await _SecureStoreRegistry.secureStoreRegistry.deleteValue(key);
|
|
271
|
-
result.applied += 1;
|
|
272
|
-
} catch (e) {
|
|
273
|
-
result.ok = false;
|
|
274
|
-
result.warnings.push(`secure "${key}" clear failed: ${String(e)}`);
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
return result;
|
|
278
|
-
}
|
|
279
|
-
const ITEM_RENDER_CHAR_LIMIT = 256 * 1024;
|
|
280
|
-
|
|
281
|
-
/**
|
|
282
|
-
* Storage values are strings (or MMKV primitives): identity equality and a
|
|
283
|
-
* character-length size gate are the right tests, not a deep walk.
|
|
284
|
-
*/
|
|
285
|
-
function classifyValue(key, label, oldValue, newValue, inOld, inNew) {
|
|
286
|
-
return (0, _sharedUi.classifyPreviewItem)({
|
|
287
|
-
key,
|
|
288
|
-
label,
|
|
289
|
-
oldValue,
|
|
290
|
-
newValue,
|
|
291
|
-
inOld,
|
|
292
|
-
inNew
|
|
293
|
-
}, {
|
|
294
|
-
equal: Object.is,
|
|
295
|
-
tooLarge: value => typeof value === "string" && value.length > ITEM_RENDER_CHAR_LIMIT,
|
|
296
|
-
tooLargeReason: "value too large to render a diff — restore still applies it"
|
|
297
|
-
});
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
/** Per-key restore preview across all three backends. */
|
|
301
|
-
async function previewItems(target, base) {
|
|
302
|
-
const targetData = target ?? {
|
|
303
|
-
async: [],
|
|
304
|
-
mmkv: {},
|
|
305
|
-
secure: {}
|
|
306
|
-
};
|
|
307
|
-
const liveMode = base === undefined;
|
|
308
|
-
const baseData = liveMode ? (await captureStorageData()).data : base ?? {
|
|
309
|
-
async: [],
|
|
310
|
-
mmkv: {},
|
|
311
|
-
secure: {}
|
|
312
|
-
};
|
|
313
|
-
const items = [];
|
|
314
|
-
const notes = [];
|
|
315
|
-
|
|
316
|
-
// ── AsyncStorage ──
|
|
317
|
-
const oldAsync = new Map(baseData.async ?? []);
|
|
318
|
-
const newAsync = new Map(targetData.async ?? []);
|
|
319
|
-
for (const key of (0, _sharedUi.unionKeys)(oldAsync, newAsync)) {
|
|
320
|
-
if ((0, _sharedUi.isDevToolsStorageKey)(key)) continue;
|
|
321
|
-
items.push(classifyValue(`async:${key}`, key, oldAsync.get(key), newAsync.get(key), oldAsync.has(key), newAsync.has(key)));
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
// ── MMKV ──
|
|
325
|
-
for (const id of (0, _sharedUi.unionKeys)(baseData.mmkv, targetData.mmkv)) {
|
|
326
|
-
const registered = liveMode ? _MMKVInstanceRegistry.mmkvInstanceRegistry.get(id) : null;
|
|
327
|
-
const instanceUnavailable = liveMode && !registered;
|
|
328
|
-
const readOnly = liveMode && registered?.instance.isReadOnly === true;
|
|
329
|
-
const oldEntries = new Map((baseData.mmkv?.[id] ?? []).map(e => [e.key, e]));
|
|
330
|
-
const newEntries = new Map((targetData.mmkv?.[id] ?? []).map(e => [e.key, e]));
|
|
331
|
-
for (const key of (0, _sharedUi.unionKeys)(oldEntries, newEntries)) {
|
|
332
|
-
if ((0, _sharedUi.isDevToolsStorageKey)(key)) continue;
|
|
333
|
-
const itemKey = `mmkv:${id}/${key}`;
|
|
334
|
-
const label = `${id} · ${key}`;
|
|
335
|
-
const oldE = oldEntries.get(key);
|
|
336
|
-
const newE = newEntries.get(key);
|
|
337
|
-
let item = classifyValue(itemKey, label, oldE?.value, newE?.value, oldEntries.has(key), newEntries.has(key));
|
|
338
|
-
if (instanceUnavailable) {
|
|
339
|
-
item = (0, _sharedUi.wontApply)(item, "MMKV instance not registered");
|
|
340
|
-
} else if (readOnly) {
|
|
341
|
-
item = (0, _sharedUi.wontApply)(item, "MMKV instance registered read-only");
|
|
342
|
-
} else if (newE?.valueType === "buffer" || oldE?.valueType === "buffer") {
|
|
343
|
-
item = (0, _sharedUi.wontApply)(item, "ArrayBuffer values cannot be restored");
|
|
344
|
-
}
|
|
345
|
-
items.push(item);
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
// ── SecureStore ──
|
|
350
|
-
const oldSecure = baseData.secure ?? {};
|
|
351
|
-
const newSecure = targetData.secure ?? {};
|
|
352
|
-
const registeredSecure = liveMode ? new Map(_SecureStoreRegistry.secureStoreRegistry.getAll().map(e => [e.key, e])) : null;
|
|
353
|
-
for (const key of (0, _sharedUi.unionKeys)(oldSecure, newSecure)) {
|
|
354
|
-
let item = classifyValue(`secure:${key}`, key, oldSecure[key], newSecure[key], key in oldSecure, key in newSecure);
|
|
355
|
-
if (liveMode) {
|
|
356
|
-
const entry = registeredSecure?.get(key);
|
|
357
|
-
if (!entry) {
|
|
358
|
-
item = (0, _sharedUi.wontApply)(item, "key no longer registered with registerSecureStoreKeys");
|
|
359
|
-
} else if (entry.options.requireAuthentication) {
|
|
360
|
-
item = (0, _sharedUi.wontApply)(item, "biometric-protected keys are never written");
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
items.push(item);
|
|
364
|
-
}
|
|
365
|
-
// No blanket "N biometric-protected keys" note: a biometric key a restore
|
|
366
|
-
// would actually touch already gets its own won't-apply row carrying that
|
|
367
|
-
// exact reason, so the note only ever restated it for keys nothing was
|
|
368
|
-
// going to do anything with.
|
|
369
|
-
return {
|
|
370
|
-
items,
|
|
371
|
-
notes
|
|
372
|
-
};
|
|
373
|
-
}
|
|
374
|
-
(0, _sharedUi.registerStateSnapshotProvider)({
|
|
375
|
-
id: "storage",
|
|
376
|
-
label: "Storage",
|
|
377
|
-
status,
|
|
378
|
-
capture,
|
|
379
|
-
restore,
|
|
380
|
-
clear,
|
|
381
|
-
previewItems
|
|
382
|
-
});
|
|
1
|
+
"use strict";var _asyncStorage=_interopRequireDefault(require("@react-native-async-storage/async-storage"));var _sharedUi=require("@buoy-gg/shared-ui");var _asyncStorageCompat=require("./asyncStorageCompat");var _clearAllStorage=require("./clearAllStorage");var _MMKVInstanceRegistry=require("./MMKVInstanceRegistry");var _mmkvTypeDetection=require("./mmkvTypeDetection");var _SecureStoreRegistry=require("./SecureStoreRegistry");function _interopRequireDefault(s){return s&&s.__esModule?s:{default:s}}function deleteMMKVKey(s,a){if(s.remove)s.remove(a);else s.delete?.(a)}function status(){return{canCapture:true,canRestore:true}}async function captureStorageData(){const s=[];const a=(await _asyncStorage.default.getAllKeys()).filter(o=>!(0,_sharedUi.isDevToolsStorageKey)(o));const i=(await(0,_asyncStorageCompat.readMany)(a)).filter(o=>o[1]!==null);const n={};for(const{id:o,instance:f}of _MMKVInstanceRegistry.mmkvInstanceRegistry.getAll()){try{n[o]=f.getAllKeys().filter(e=>!(0,_sharedUi.isDevToolsStorageKey)(e)).map(e=>{const{value:y,type:l}=(0,_mmkvTypeDetection.detectMMKVType)(f,e);if(l==="buffer"){s.push(`mmkv "${o}"/"${e}": ArrayBuffer value not capturable`)}return{key:e,value:y,valueType:l}})}catch{s.push(`mmkv "${o}": unreadable, captured without entries`);n[o]=[]}}const u={};const r=_SecureStoreRegistry.secureStoreRegistry.getModule();for(const{key:o,options:f}of _SecureStoreRegistry.secureStoreRegistry.getAll()){if(f.requireAuthentication){s.push(`secure "${o}": biometric-protected, not capturable`);continue}let e=null;if(r){try{e=await r.getItemAsync(o,f)}catch{s.push(`secure "${o}": unreadable, captured as unset`)}}u[o]=e}return{data:{async:i,mmkv:n,secure:u},warnings:s}}async function capture(){const{data:s,warnings:a}=await captureStorageData();return{data:s,warnings:a}}async function restore(s,a){const i=s;const n=(0,_sharedUi.createRestoreScope)(a);const u=n.touch;const r=(0,_sharedUi.emptyRestoreResult)();if(!i){return(0,_sharedUi.failedRestore)("empty storage snapshot")}try{const e=(i.async??[]).filter(([t])=>!(0,_sharedUi.isDevToolsStorageKey)(t)&&u(`async:${t}`));const y=new Set(e.map(([t])=>t));const l=(await _asyncStorage.default.getAllKeys()).filter(t=>!(0,_sharedUi.isDevToolsStorageKey)(t));const d=l.filter(t=>!y.has(t)&&u(`async:${t}`));n.countExcluded((i.async??[]).length-e.length);if(d.length>0)await(0,_asyncStorageCompat.removeMany)(d);if(e.length>0)await(0,_asyncStorageCompat.writeMany)(e);r.applied+=e.length+d.length}catch(e){r.ok=false;r.warnings.push(`asyncstorage restore failed: ${String(e)}`)}for(const[e,y]of Object.entries(i.mmkv??{})){const l=_MMKVInstanceRegistry.mmkvInstanceRegistry.get(e);if(!l){r.skipped.push({id:`mmkv:${e}`,reason:"instance not registered"});continue}if(l.instance.isReadOnly){r.skipped.push({id:`mmkv:${e}`,reason:"instance registered read-only"});continue}const{instance:d}=l;try{const t=new Set(y.map(c=>c.key));const g=d.getAllKeys().filter(c=>!(0,_sharedUi.isDevToolsStorageKey)(c));for(const c of g){if(!n.allows(`mmkv:${e}/${c}`))continue;if(!t.has(c)){deleteMMKVKey(d,c);r.applied+=1}}for(const c of y){if((0,_sharedUi.isDevToolsStorageKey)(c.key))continue;if(!u(`mmkv:${e}/${c.key}`))continue;if(c.valueType==="buffer"){r.skipped.push({id:`mmkv:${e}/${c.key}`,reason:"ArrayBuffer values cannot be restored"});continue}d.set(c.key,c.value);r.applied+=1}}catch(t){r.ok=false;r.warnings.push(`mmkv "${e}" restore failed: ${String(t)}`)}}const o=i.secure??{};for(const{key:e,options:y}of _SecureStoreRegistry.secureStoreRegistry.getAll()){if(!n.allows(`secure:${e}`))continue;if(y.requireAuthentication){if(e in o){r.skipped.push({id:`secure:${e}`,reason:"biometric-protected keys are never written"})}continue}try{if(e in o){const l=o[e];if(l===null)await _SecureStoreRegistry.secureStoreRegistry.deleteValue(e);else await _SecureStoreRegistry.secureStoreRegistry.setValue(e,l)}else{await _SecureStoreRegistry.secureStoreRegistry.deleteValue(e)}r.applied+=1}catch(l){r.ok=false;r.warnings.push(`secure "${e}" restore failed: ${String(l)}`)}}for(const e of Object.keys(o)){if(!u(`secure:${e}`))continue;if(!_SecureStoreRegistry.secureStoreRegistry.getAll().some(y=>y.key===e)){r.skipped.push({id:`secure:${e}`,reason:"key no longer registered with registerSecureStoreKeys"})}}const f=n.excludedWarning("item(s)");if(f)r.warnings.push(f);return r}async function clear(){const s=(0,_sharedUi.emptyRestoreResult)();try{await(0,_clearAllStorage.clearAllAppStorage)();s.applied+=1}catch(a){s.ok=false;s.warnings.push(`asyncstorage clear failed: ${String(a)}`)}for(const{id:a,instance:i}of _MMKVInstanceRegistry.mmkvInstanceRegistry.getAll()){if(i.isReadOnly){s.skipped.push({id:`mmkv:${a}`,reason:"instance registered read-only"});continue}try{for(const n of i.getAllKeys().filter(u=>!(0,_sharedUi.isDevToolsStorageKey)(u))){deleteMMKVKey(i,n);s.applied+=1}}catch(n){s.ok=false;s.warnings.push(`mmkv "${a}" clear failed: ${String(n)}`)}}for(const{key:a,options:i}of _SecureStoreRegistry.secureStoreRegistry.getAll()){if(i.requireAuthentication){s.skipped.push({id:`secure:${a}`,reason:"biometric-protected keys are never written"});continue}try{await _SecureStoreRegistry.secureStoreRegistry.deleteValue(a);s.applied+=1}catch(n){s.ok=false;s.warnings.push(`secure "${a}" clear failed: ${String(n)}`)}}return s}const ITEM_RENDER_CHAR_LIMIT=256*1024;function classifyValue(s,a,i,n,u,r){return(0,_sharedUi.classifyPreviewItem)({key:s,label:a,oldValue:i,newValue:n,inOld:u,inNew:r},{equal:Object.is,tooLarge:o=>typeof o==="string"&&o.length>ITEM_RENDER_CHAR_LIMIT,tooLargeReason:"value too large to render a diff \u2014 restore still applies it"})}async function previewItems(s,a){const i=s??{async:[],mmkv:{},secure:{}};const n=a===void 0;const u=n?(await captureStorageData()).data:a??{async:[],mmkv:{},secure:{}};const r=[];const o=[];const f=new Map(u.async??[]);const e=new Map(i.async??[]);for(const t of(0,_sharedUi.unionKeys)(f,e)){if((0,_sharedUi.isDevToolsStorageKey)(t))continue;r.push(classifyValue(`async:${t}`,t,f.get(t),e.get(t),f.has(t),e.has(t)))}for(const t of(0,_sharedUi.unionKeys)(u.mmkv,i.mmkv)){const g=n?_MMKVInstanceRegistry.mmkvInstanceRegistry.get(t):null;const c=n&&!g;const w=n&&g?.instance.isReadOnly===true;const v=new Map((u.mmkv?.[t]??[]).map(p=>[p.key,p]));const k=new Map((i.mmkv?.[t]??[]).map(p=>[p.key,p]));for(const p of(0,_sharedUi.unionKeys)(v,k)){if((0,_sharedUi.isDevToolsStorageKey)(p))continue;const $=`mmkv:${t}/${p}`;const R=`${t} \xB7 ${p}`;const h=v.get(p);const S=k.get(p);let m=classifyValue($,R,h?.value,S?.value,v.has(p),k.has(p));if(c){m=(0,_sharedUi.wontApply)(m,"MMKV instance not registered")}else if(w){m=(0,_sharedUi.wontApply)(m,"MMKV instance registered read-only")}else if(S?.valueType==="buffer"||h?.valueType==="buffer"){m=(0,_sharedUi.wontApply)(m,"ArrayBuffer values cannot be restored")}r.push(m)}}const y=u.secure??{};const l=i.secure??{};const d=n?new Map(_SecureStoreRegistry.secureStoreRegistry.getAll().map(t=>[t.key,t])):null;for(const t of(0,_sharedUi.unionKeys)(y,l)){let g=classifyValue(`secure:${t}`,t,y[t],l[t],t in y,t in l);if(n){const c=d?.get(t);if(!c){g=(0,_sharedUi.wontApply)(g,"key no longer registered with registerSecureStoreKeys")}else if(c.options.requireAuthentication){g=(0,_sharedUi.wontApply)(g,"biometric-protected keys are never written")}}r.push(g)}return{items:r,notes:o}}(0,_sharedUi.registerStateSnapshotProvider)({id:"storage",label:"Storage",status,capture,restore,clear,previewItems});
|
|
@@ -1,46 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.translateStorageAction = translateStorageAction;
|
|
7
|
-
/**
|
|
8
|
-
* Translates storage action types to human-readable labels
|
|
9
|
-
*/
|
|
10
|
-
function translateStorageAction(action) {
|
|
11
|
-
switch (action) {
|
|
12
|
-
// AsyncStorage actions
|
|
13
|
-
case "setItem":
|
|
14
|
-
return "SET";
|
|
15
|
-
case "removeItem":
|
|
16
|
-
return "REMOVE";
|
|
17
|
-
case "mergeItem":
|
|
18
|
-
return "MERGE";
|
|
19
|
-
case "clear":
|
|
20
|
-
return "CLEAR";
|
|
21
|
-
case "multiSet":
|
|
22
|
-
return "MULTI SET";
|
|
23
|
-
case "multiRemove":
|
|
24
|
-
return "MULTI REMOVE";
|
|
25
|
-
case "multiMerge":
|
|
26
|
-
return "MULTI MERGE";
|
|
27
|
-
|
|
28
|
-
// MMKV actions - simplified to match AsyncStorage
|
|
29
|
-
case "set.string":
|
|
30
|
-
case "set.number":
|
|
31
|
-
case "set.boolean":
|
|
32
|
-
case "set.buffer":
|
|
33
|
-
return "SET";
|
|
34
|
-
case "delete":
|
|
35
|
-
return "REMOVE";
|
|
36
|
-
case "clearAll":
|
|
37
|
-
return "CLEAR";
|
|
38
|
-
case "get.string":
|
|
39
|
-
case "get.number":
|
|
40
|
-
case "get.boolean":
|
|
41
|
-
case "get.buffer":
|
|
42
|
-
return "GET";
|
|
43
|
-
default:
|
|
44
|
-
return "UNKNOWN ACTION";
|
|
45
|
-
}
|
|
46
|
-
}
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.translateStorageAction=translateStorageAction;function translateStorageAction(e){switch(e){case"setItem":return"SET";case"removeItem":return"REMOVE";case"mergeItem":return"MERGE";case"clear":return"CLEAR";case"multiSet":return"MULTI SET";case"multiRemove":return"MULTI REMOVE";case"multiMerge":return"MULTI MERGE";case"set.string":case"set.number":case"set.boolean":case"set.buffer":return"SET";case"delete":return"REMOVE";case"clearAll":return"CLEAR";case"get.string":case"get.number":case"get.boolean":case"get.buffer":return"GET";default:return"UNKNOWN ACTION"}}
|