@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,148 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* MMKV Type Detection Utilities
|
|
5
|
-
*
|
|
6
|
-
* MMKV stores values with native types (string, number, boolean, ArrayBuffer).
|
|
7
|
-
* This module provides utilities to detect the type of a stored value by trying
|
|
8
|
-
* each getter sequentially.
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
// Use 'any' type for MMKV to avoid hard dependency on react-native-mmkv
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Detect the type of a value stored in MMKV by trying each getter.
|
|
15
|
-
*
|
|
16
|
-
* Since MMKV doesn't provide a getType() method, we must try each getter
|
|
17
|
-
* (getString, getNumber, getBoolean, getBuffer) until one returns a value.
|
|
18
|
-
*
|
|
19
|
-
* Order matters: We try in order of most common types first.
|
|
20
|
-
*
|
|
21
|
-
* @param instance - MMKV instance to read from
|
|
22
|
-
* @param key - Storage key
|
|
23
|
-
* @returns Value and its detected type
|
|
24
|
-
*
|
|
25
|
-
* @example
|
|
26
|
-
* ```typescript
|
|
27
|
-
* const instance = createMMKV();
|
|
28
|
-
* instance.set('name', 'John');
|
|
29
|
-
* instance.set('age', 30);
|
|
30
|
-
* instance.set('active', true);
|
|
31
|
-
*
|
|
32
|
-
* detectMMKVType(instance, 'name'); // { value: 'John', type: 'string' }
|
|
33
|
-
* detectMMKVType(instance, 'age'); // { value: 30, type: 'number' }
|
|
34
|
-
* detectMMKVType(instance, 'active'); // { value: true, type: 'boolean' }
|
|
35
|
-
* detectMMKVType(instance, 'missing');// { value: undefined, type: 'unknown' }
|
|
36
|
-
* ```
|
|
37
|
-
*/
|
|
38
|
-
export function detectMMKVType(instance, key) {
|
|
39
|
-
// MMKV stores no type metadata, so the native getters can cross-read: in
|
|
40
|
-
// particular `getString` returns "" (an empty string, NOT undefined) for many
|
|
41
|
-
// non-string values like numbers and `false`. Trying getString first and
|
|
42
|
-
// trusting its result therefore mis-detects those as empty strings — e.g.
|
|
43
|
-
// a key set to 42 or false would render as "". Probe the getters and only let
|
|
44
|
-
// getString win when it returns a NON-empty string; treat an empty result as
|
|
45
|
-
// ambiguous and prefer the number/boolean getters.
|
|
46
|
-
const stringValue = instance.getString(key);
|
|
47
|
-
|
|
48
|
-
// A non-empty string is unambiguously a string.
|
|
49
|
-
if (stringValue !== undefined && stringValue !== '') {
|
|
50
|
-
return {
|
|
51
|
-
value: stringValue,
|
|
52
|
-
type: 'string'
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// Empty getString result is ambiguous (genuine "" vs a number/boolean the
|
|
57
|
-
// native layer decoded to ""). Prefer typed getters when they have a value.
|
|
58
|
-
const numberValue = instance.getNumber(key);
|
|
59
|
-
if (numberValue !== undefined) {
|
|
60
|
-
return {
|
|
61
|
-
value: numberValue,
|
|
62
|
-
type: 'number'
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
const booleanValue = instance.getBoolean(key);
|
|
66
|
-
if (booleanValue !== undefined) {
|
|
67
|
-
return {
|
|
68
|
-
value: booleanValue,
|
|
69
|
-
type: 'boolean'
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// getString returned "" and nothing else matched -> a genuine empty string.
|
|
74
|
-
if (stringValue === '') {
|
|
75
|
-
return {
|
|
76
|
-
value: '',
|
|
77
|
-
type: 'string'
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Try buffer (least common)
|
|
82
|
-
const bufferValue = instance.getBuffer(key);
|
|
83
|
-
if (bufferValue !== undefined) {
|
|
84
|
-
// Format buffer for display (don't return raw ArrayBuffer)
|
|
85
|
-
return {
|
|
86
|
-
value: `<ArrayBuffer ${bufferValue.byteLength} bytes>`,
|
|
87
|
-
type: 'buffer'
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// Key doesn't exist or unknown type
|
|
92
|
-
return {
|
|
93
|
-
value: undefined,
|
|
94
|
-
type: 'unknown'
|
|
95
|
-
};
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Format an MMKV value for display in the UI.
|
|
100
|
-
*
|
|
101
|
-
* @param value - The value to format
|
|
102
|
-
* @param type - The detected type
|
|
103
|
-
* @returns Formatted string representation
|
|
104
|
-
*
|
|
105
|
-
* @example
|
|
106
|
-
* ```typescript
|
|
107
|
-
* formatMMKVValue('hello', 'string'); // '"hello"'
|
|
108
|
-
* formatMMKVValue(42, 'number'); // '42'
|
|
109
|
-
* formatMMKVValue(true, 'boolean'); // 'true'
|
|
110
|
-
* formatMMKVValue('<ArrayBuffer 1024 bytes>', 'buffer'); // '<ArrayBuffer 1024 bytes>'
|
|
111
|
-
* ```
|
|
112
|
-
*/
|
|
113
|
-
export function formatMMKVValue(value, type) {
|
|
114
|
-
if (value === undefined) return 'undefined';
|
|
115
|
-
if (value === null) return 'null';
|
|
116
|
-
switch (type) {
|
|
117
|
-
case 'string':
|
|
118
|
-
return `"${value}"`;
|
|
119
|
-
case 'number':
|
|
120
|
-
return String(value);
|
|
121
|
-
case 'boolean':
|
|
122
|
-
return value ? 'true' : 'false';
|
|
123
|
-
case 'buffer':
|
|
124
|
-
// Value is already formatted as "<ArrayBuffer X bytes>"
|
|
125
|
-
return value;
|
|
126
|
-
case 'unknown':
|
|
127
|
-
return 'unknown';
|
|
128
|
-
default:
|
|
129
|
-
return String(value);
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* Check if a value type matches an expected type for validation.
|
|
135
|
-
*
|
|
136
|
-
* @param actualType - Detected type
|
|
137
|
-
* @param expectedType - Expected type from configuration
|
|
138
|
-
* @returns True if types match
|
|
139
|
-
*
|
|
140
|
-
* @example
|
|
141
|
-
* ```typescript
|
|
142
|
-
* isTypeMatch('string', 'string'); // true
|
|
143
|
-
* isTypeMatch('number', 'string'); // false
|
|
144
|
-
* ```
|
|
145
|
-
*/
|
|
146
|
-
export function isTypeMatch(actualType, expectedType) {
|
|
147
|
-
return actualType === expectedType;
|
|
148
|
-
}
|
|
1
|
+
"use strict";export function detectMMKVType(e,n){const r=e.getString(n);if(r!==void 0&&r!==""){return{value:r,type:"string"}}const t=e.getNumber(n);if(t!==void 0){return{value:t,type:"number"}}const u=e.getBoolean(n);if(u!==void 0){return{value:u,type:"boolean"}}if(r===""){return{value:"",type:"string"}}const f=e.getBuffer(n);if(f!==void 0){return{value:`<ArrayBuffer ${f.byteLength} bytes>`,type:"buffer"}}return{value:void 0,type:"unknown"}}export function formatMMKVValue(e,n){if(e===void 0)return"undefined";if(e===null)return"null";switch(n){case"string":return`"${e}"`;case"number":return String(e);case"boolean":return e?"true":"false";case"buffer":return e;case"unknown":return"unknown";default:return String(e)}}export function isTypeMatch(e,n){return e===n}
|
|
@@ -1,13 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Whether a required-key declaration should be enforced by a given backend
|
|
5
|
-
* hook. Explicit `storageType` wins; bare string keys default to AsyncStorage
|
|
6
|
-
* (the historical zero-config backend). Objects without `storageType` still
|
|
7
|
-
* apply to every backend — matching prior behavior for apps that never set it.
|
|
8
|
-
*/
|
|
9
|
-
export function requiredKeyAppliesTo(req, backend) {
|
|
10
|
-
if (typeof req === "string") return backend === "async";
|
|
11
|
-
if (req.storageType) return req.storageType === backend;
|
|
12
|
-
return true;
|
|
13
|
-
}
|
|
1
|
+
"use strict";export function requiredKeyAppliesTo(e,r){if(typeof e==="string")return r==="async";if(e.storageType)return e.storageType===r;return true}
|
|
@@ -1,209 +1 @@
|
|
|
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
|
-
}
|
|
1
|
+
"use strict";import l from"@react-native-async-storage/async-storage";import{secureStoreRegistry as i}from"./SecureStoreRegistry";export 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=i.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(!i.getModule()){return"No SecureStore module is registered."}}return null}export function validateStorageValue(e,t){if(e.storageType==="mmkv"){const r=a(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(f(e.value)){try{JSON.parse(t)}catch(r){return`This key holds JSON \u2014 ${r instanceof Error?r.message:"invalid JSON"}`}}return null}export 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)}export 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}export async function setStorageValue(e,t,r=[]){const n=storageEditBlockedReason(e,r);if(n)throw new Error(n);const u=validateStorageValue(e,t);if(u)throw new Error(u);switch(e.storageType){case"async":{await l.setItem(e.key,c(e,t));return}case"secure":{await i.setValue(e.key,c(e,t));return}case"mmkv":{const o=e.instanceId||"default";const s=r.find(d=>d.id===o);if(!s){throw new Error(`MMKV instance "${o}" is not registered.`)}s.instance.set(e.key,p(e,t));return}default:{throw new Error(`Unsupported storage type "${String(e.storageType)}"`)}}}function f(e){return e!==null&&typeof e==="object"}function c(e,t){if(!f(e.value))return t;return JSON.stringify(JSON.parse(t))}function a(e){if(e.valueType)return e.valueType;if(typeof e.value==="number")return"number";if(typeof e.value==="boolean")return"boolean";return"string"}function p(e,t){switch(a(e)){case"number":return Number(t);case"boolean":return t.trim().toLowerCase()==="true";default:return t}}
|