@buoy-gg/storage 5.0.0 → 6.0.1
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 +45 -572
- package/lib/commonjs/index.js +13 -0
- package/lib/commonjs/storage/components/GameUIStorageBrowser.js +21 -18
- package/lib/commonjs/storage/components/SelectionActionBar.js +8 -0
- package/lib/commonjs/storage/components/StorageEventCard.js +3 -2
- package/lib/commonjs/storage/components/StorageFilterCards.js +1 -2
- package/lib/commonjs/storage/components/StorageKeyRow.js +8 -3
- package/lib/commonjs/storage/hooks/useMMKVInstances.js +9 -20
- package/lib/commonjs/storage/hooks/useMMKVKeys.js +12 -21
- package/lib/commonjs/storage/hooks/useSecureStoreKeys.js +104 -0
- package/lib/commonjs/storage/hooks/useStorageEvents.js +25 -11
- package/lib/commonjs/storage/sync/storageSyncAdapter.js +82 -1
- package/lib/commonjs/storage/utils/SecureStoreRegistry.js +149 -0
- package/lib/module/index.js +5 -0
- package/lib/module/storage/components/GameUIStorageBrowser.js +20 -18
- package/lib/module/storage/components/SelectionActionBar.js +8 -0
- package/lib/module/storage/components/StorageEventCard.js +4 -3
- package/lib/module/storage/components/StorageFilterCards.js +1 -2
- package/lib/module/storage/components/StorageKeyRow.js +7 -2
- package/lib/module/storage/hooks/useMMKVInstances.js +6 -18
- package/lib/module/storage/hooks/useMMKVKeys.js +7 -18
- package/lib/module/storage/hooks/useSecureStoreKeys.js +101 -0
- package/lib/module/storage/hooks/useStorageEvents.js +25 -11
- package/lib/module/storage/sync/storageSyncAdapter.js +83 -1
- package/lib/module/storage/utils/SecureStoreRegistry.js +143 -0
- package/lib/typescript/index.d.ts +2 -0
- package/lib/typescript/index.d.ts.map +1 -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/StorageEventCard.d.ts.map +1 -1
- package/lib/typescript/storage/components/StorageFilterCards.d.ts.map +1 -1
- package/lib/typescript/storage/components/StorageKeyRow.d.ts +1 -1
- package/lib/typescript/storage/components/StorageKeyRow.d.ts.map +1 -1
- package/lib/typescript/storage/hooks/useMMKVInstances.d.ts.map +1 -1
- package/lib/typescript/storage/hooks/useMMKVKeys.d.ts.map +1 -1
- package/lib/typescript/storage/hooks/useSecureStoreKeys.d.ts +18 -0
- package/lib/typescript/storage/hooks/useSecureStoreKeys.d.ts.map +1 -0
- package/lib/typescript/storage/hooks/useStorageEvents.d.ts.map +1 -1
- package/lib/typescript/storage/sync/storageSyncAdapter.d.ts +24 -0
- package/lib/typescript/storage/sync/storageSyncAdapter.d.ts.map +1 -1
- package/lib/typescript/storage/utils/SecureStoreRegistry.d.ts +115 -0
- package/lib/typescript/storage/utils/SecureStoreRegistry.d.ts.map +1 -0
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -1,607 +1,80 @@
|
|
|
1
|
-
# @buoy/storage
|
|
1
|
+
# @buoy-gg/storage
|
|
2
2
|
|
|
3
|
-
[](https://www.npmjs.com/package/@buoy-gg/storage) [](https://www.npmjs.com/package/@buoy-gg/storage)
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
**Browse and edit every key-value pair your React Native app persists — AsyncStorage, MMKV, and SecureStore in one explorer with real-time updates.**
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Part of [Buoy](https://github.com/Buoy-gg/buoy) — devtools that live inside your React Native app. Install it and it auto-appears in the floating menu from [`@buoy-gg/core`](https://www.npmjs.com/package/@buoy-gg/core).
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
- **MMKV Support**: Monitor and debug MMKV instances (including encrypted storage)
|
|
11
|
-
- **Multiple Storage Types**: Support for AsyncStorage, MMKV, and multiple MMKV instances
|
|
12
|
-
- **Live Event Monitoring**: Track all storage operations in real-time
|
|
13
|
-
- **Edit & Delete**: Modify or remove storage items directly
|
|
14
|
-
- **Add New Items**: Create new storage entries
|
|
15
|
-
- **Required Key Validation**: Define and validate required storage keys
|
|
16
|
-
- **Type Checking**: Validate storage value types
|
|
17
|
-
- **Value Validation**: Check if values match expected patterns
|
|
18
|
-
- **Search & Filter**: Search through keys and filter by status
|
|
19
|
-
- **Copy Functionality**: Easily copy keys and values
|
|
20
|
-
- **Beautiful UI**: Modern, game-themed interface matching other React Buoy tools
|
|
9
|
+

|
|
21
10
|
|
|
22
|
-
##
|
|
23
|
-
|
|
24
|
-
This package is part of the React Buoy monorepo and is automatically available to other packages and the example app.
|
|
25
|
-
|
|
26
|
-
For external projects:
|
|
27
|
-
|
|
28
|
-
```bash
|
|
29
|
-
# Required: Core storage package and AsyncStorage
|
|
30
|
-
npm install @buoy/storage @react-native-async-storage/async-storage
|
|
31
|
-
|
|
32
|
-
# Optional: MMKV support (recommended for better performance)
|
|
33
|
-
npm install react-native-mmkv
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
Or with pnpm/yarn:
|
|
11
|
+
## Install
|
|
37
12
|
|
|
38
13
|
```bash
|
|
39
|
-
|
|
40
|
-
pnpm add @buoy/storage @react-native-async-storage/async-storage
|
|
41
|
-
|
|
42
|
-
# Optional: MMKV support
|
|
43
|
-
pnpm add react-native-mmkv
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
## Quick Start
|
|
47
|
-
|
|
48
|
-
### Simplest Setup - Just 1 Line!
|
|
49
|
-
|
|
50
|
-
**Import the preset and add it to your tools array. Done!**
|
|
51
|
-
|
|
52
|
-
```typescript
|
|
53
|
-
import { storageToolPreset } from '@buoy/storage';
|
|
54
|
-
import { FloatingDevTools } from '@buoy/core';
|
|
55
|
-
|
|
56
|
-
const installedApps = [
|
|
57
|
-
storageToolPreset, // That's it! One line.
|
|
58
|
-
// ...your other tools
|
|
59
|
-
];
|
|
60
|
-
|
|
61
|
-
function App() {
|
|
62
|
-
return (
|
|
63
|
-
<FloatingDevTools
|
|
64
|
-
apps={installedApps}
|
|
65
|
-
environment="local"
|
|
66
|
-
userRole="admin"
|
|
67
|
-
/>
|
|
68
|
-
);
|
|
69
|
-
}
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
**Done!** The preset automatically:
|
|
73
|
-
- ✅ Browses all AsyncStorage keys
|
|
74
|
-
- ✅ Monitors storage operations
|
|
75
|
-
- ✅ Provides edit/delete/add functionality
|
|
76
|
-
- ✅ No configuration required
|
|
77
|
-
|
|
78
|
-
### Custom Configuration
|
|
79
|
-
|
|
80
|
-
If you need to validate specific storage keys:
|
|
81
|
-
|
|
82
|
-
```typescript
|
|
83
|
-
import { createStorageTool } from '@buoy/storage';
|
|
84
|
-
|
|
85
|
-
const requiredStorageKeys = [
|
|
86
|
-
{
|
|
87
|
-
key: "@app/session",
|
|
88
|
-
expectedType: "string",
|
|
89
|
-
description: "User session token",
|
|
90
|
-
storageType: "async",
|
|
91
|
-
},
|
|
92
|
-
{
|
|
93
|
-
key: "@app/settings:theme",
|
|
94
|
-
expectedValue: "dark",
|
|
95
|
-
description: "Preferred theme",
|
|
96
|
-
storageType: "async",
|
|
97
|
-
},
|
|
98
|
-
];
|
|
99
|
-
|
|
100
|
-
const myStorageTool = createStorageTool({
|
|
101
|
-
requiredStorageKeys,
|
|
102
|
-
colorPreset: "purple",
|
|
103
|
-
enableSharedModalDimensions: true,
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
const installedApps = [
|
|
107
|
-
myStorageTool,
|
|
108
|
-
// ...other tools
|
|
109
|
-
];
|
|
14
|
+
npm install @buoy-gg/core @buoy-gg/storage
|
|
110
15
|
```
|
|
111
16
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
If you're not using FloatingDevTools or want more control:
|
|
17
|
+
## Quick start
|
|
115
18
|
|
|
116
|
-
|
|
117
|
-
import { StorageModalWithTabs } from '@buoy/storage';
|
|
19
|
+
AsyncStorage works out of the box. Render the floating menu once — the Storage Explorer is auto-discovered as soon as this package is installed:
|
|
118
20
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
key: "@app/session",
|
|
122
|
-
expectedType: "string",
|
|
123
|
-
description: "User session token",
|
|
124
|
-
storageType: "async",
|
|
125
|
-
},
|
|
126
|
-
];
|
|
127
|
-
|
|
128
|
-
function App() {
|
|
129
|
-
const [showStorage, setShowStorage] = useState(false);
|
|
21
|
+
```tsx
|
|
22
|
+
import { FloatingDevTools } from "@buoy-gg/core";
|
|
130
23
|
|
|
24
|
+
export default function App() {
|
|
131
25
|
return (
|
|
132
26
|
<>
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
</Button>
|
|
136
|
-
|
|
137
|
-
<StorageModalWithTabs
|
|
138
|
-
visible={showStorage}
|
|
139
|
-
onClose={() => setShowStorage(false)}
|
|
140
|
-
requiredStorageKeys={requiredStorageKeys}
|
|
141
|
-
/>
|
|
27
|
+
{/* your app */}
|
|
28
|
+
<FloatingDevTools />
|
|
142
29
|
</>
|
|
143
30
|
);
|
|
144
31
|
}
|
|
145
32
|
```
|
|
146
33
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
React Buoy Storage fully supports [react-native-mmkv](https://github.com/mrousavy/react-native-mmkv), a fast, efficient storage solution for React Native.
|
|
150
|
-
|
|
151
|
-
### Why MMKV?
|
|
152
|
-
|
|
153
|
-
- **10x faster** than AsyncStorage
|
|
154
|
-
- **Synchronous API** - no async/await needed
|
|
155
|
-
- **Encryption support** - built-in AES encryption
|
|
156
|
-
- **Multi-process support** - share data between extensions
|
|
157
|
-
- **Small bundle size** - ~30KB
|
|
158
|
-
|
|
159
|
-
### Setup Requirements
|
|
160
|
-
|
|
161
|
-
**⚠️ IMPORTANT:** Manual registration is **required** for MMKV v4. Auto-detection is not possible due to Metro bundler and ES6 module limitations.
|
|
162
|
-
|
|
163
|
-
You must call `registerMMKVInstance()` for each MMKV instance you want to monitor in the DevTools.
|
|
164
|
-
|
|
165
|
-
### Basic MMKV Setup
|
|
166
|
-
|
|
167
|
-
```typescript
|
|
168
|
-
import { createMMKV } from 'react-native-mmkv';
|
|
169
|
-
import { registerMMKVInstance } from '@buoy/storage';
|
|
170
|
-
|
|
171
|
-
// 1. Create your MMKV instance
|
|
172
|
-
export const storage = createMMKV({
|
|
173
|
-
id: 'mmkv.default'
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
// 2. Register it with DevTools (required!)
|
|
177
|
-
registerMMKVInstance('mmkv.default', storage);
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
**That's it!** Your MMKV instance is now visible in the Storage DevTools.
|
|
181
|
-
|
|
182
|
-
### Encrypted MMKV Setup
|
|
183
|
-
|
|
184
|
-
```typescript
|
|
185
|
-
import { createMMKV } from 'react-native-mmkv';
|
|
186
|
-
import { registerMMKVInstance } from '@buoy/storage';
|
|
187
|
-
|
|
188
|
-
// Create encrypted instance
|
|
189
|
-
export const secureStorage = createMMKV({
|
|
190
|
-
id: 'secure-storage',
|
|
191
|
-
encryptionKey: 'my-encryption-key'
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
// Register with encrypted flag
|
|
195
|
-
registerMMKVInstance('secure-storage', secureStorage, {
|
|
196
|
-
encrypted: true
|
|
197
|
-
});
|
|
198
|
-
```
|
|
199
|
-
|
|
200
|
-
### Multiple MMKV Instances
|
|
201
|
-
|
|
202
|
-
You can create and monitor multiple MMKV instances for different purposes:
|
|
203
|
-
|
|
204
|
-
```typescript
|
|
205
|
-
import { createMMKV } from 'react-native-mmkv';
|
|
206
|
-
import { registerMMKVInstance } from '@buoy/storage';
|
|
207
|
-
|
|
208
|
-
// User preferences
|
|
209
|
-
export const userPrefs = createMMKV({ id: 'user-prefs' });
|
|
210
|
-
registerMMKVInstance('user-prefs', userPrefs);
|
|
211
|
-
|
|
212
|
-
// API cache
|
|
213
|
-
export const apiCache = createMMKV({ id: 'api-cache' });
|
|
214
|
-
registerMMKVInstance('api-cache', apiCache);
|
|
215
|
-
|
|
216
|
-
// Secure auth storage
|
|
217
|
-
export const authStorage = createMMKV({
|
|
218
|
-
id: 'auth',
|
|
219
|
-
encryptionKey: process.env.ENCRYPTION_KEY
|
|
220
|
-
});
|
|
221
|
-
registerMMKVInstance('auth', authStorage, { encrypted: true });
|
|
222
|
-
```
|
|
223
|
-
|
|
224
|
-
### MMKV with FloatingDevTools
|
|
225
|
-
|
|
226
|
-
Once registered, MMKV instances automatically appear in the Storage Browser:
|
|
227
|
-
|
|
228
|
-
```typescript
|
|
229
|
-
import { FloatingDevTools } from '@buoy/core';
|
|
230
|
-
import { storageToolPreset } from '@buoy/storage';
|
|
231
|
-
import './mmkv-setup'; // Import your MMKV setup file
|
|
232
|
-
|
|
233
|
-
function App() {
|
|
234
|
-
return (
|
|
235
|
-
<FloatingDevTools
|
|
236
|
-
apps={[storageToolPreset]}
|
|
237
|
-
environment="local"
|
|
238
|
-
userRole="admin"
|
|
239
|
-
/>
|
|
240
|
-
);
|
|
241
|
-
}
|
|
242
|
-
```
|
|
243
|
-
|
|
244
|
-
The Storage Browser will show:
|
|
245
|
-
- All your MMKV instances (default, user-prefs, api-cache, auth, etc.)
|
|
246
|
-
- All AsyncStorage keys
|
|
247
|
-
- Real-time updates when data changes
|
|
248
|
-
- Ability to edit, delete, and add keys
|
|
249
|
-
|
|
250
|
-
### MMKV Registration API
|
|
251
|
-
|
|
252
|
-
#### `registerMMKVInstance(id, instance, config?)`
|
|
253
|
-
|
|
254
|
-
Register an MMKV instance with DevTools for monitoring and debugging.
|
|
255
|
-
|
|
256
|
-
**Parameters:**
|
|
257
|
-
- `id` (string) - Unique identifier for this instance (should match the `id` used in `createMMKV`)
|
|
258
|
-
- `instance` (MMKV) - The MMKV instance returned from `createMMKV()`
|
|
259
|
-
- `config` (optional) - Configuration object
|
|
260
|
-
- `encrypted` (boolean) - Set to `true` if instance uses encryption
|
|
261
|
-
|
|
262
|
-
**Returns:** `void`
|
|
263
|
-
|
|
264
|
-
**Example:**
|
|
265
|
-
```typescript
|
|
266
|
-
import { createMMKV } from 'react-native-mmkv';
|
|
267
|
-
import { registerMMKVInstance } from '@buoy/storage';
|
|
268
|
-
|
|
269
|
-
const storage = createMMKV({ id: 'my-storage' });
|
|
270
|
-
registerMMKVInstance('my-storage', storage);
|
|
271
|
-
```
|
|
272
|
-
|
|
273
|
-
#### `unregisterMMKVInstance(id)`
|
|
274
|
-
|
|
275
|
-
Unregister an MMKV instance from DevTools monitoring. Typically not needed unless you're dynamically creating/destroying instances.
|
|
276
|
-
|
|
277
|
-
**Parameters:**
|
|
278
|
-
- `id` (string) - The instance ID to unregister
|
|
279
|
-
|
|
280
|
-
**Returns:** `void`
|
|
281
|
-
|
|
282
|
-
**Example:**
|
|
283
|
-
```typescript
|
|
284
|
-
import { unregisterMMKVInstance } from '@buoy/storage';
|
|
285
|
-
|
|
286
|
-
unregisterMMKVInstance('my-storage');
|
|
287
|
-
```
|
|
288
|
-
|
|
289
|
-
### Why Manual Registration?
|
|
290
|
-
|
|
291
|
-
Auto-detection is fundamentally impossible for MMKV v4 due to:
|
|
292
|
-
|
|
293
|
-
1. **ES6 Module Exports are Sealed** - Cannot monkey-patch `createMMKV` function
|
|
294
|
-
2. **Metro Bundler Limitations** - No access to `require.cache` or module interception
|
|
295
|
-
3. **Nitro Modules Architecture** - MMKV instances created in native C++ layer
|
|
296
|
-
|
|
297
|
-
Manual registration is a simple one-line call per instance and provides explicit control over what's monitored.
|
|
298
|
-
|
|
299
|
-
### MMKV Best Practices
|
|
300
|
-
|
|
301
|
-
**Recommended structure:**
|
|
302
|
-
|
|
303
|
-
```typescript
|
|
304
|
-
// utils/storage.ts
|
|
305
|
-
import { createMMKV } from 'react-native-mmkv';
|
|
306
|
-
import { registerMMKVInstance } from '@buoy/storage';
|
|
307
|
-
|
|
308
|
-
export const storage = createMMKV({ id: 'mmkv.default' });
|
|
309
|
-
export const secureStorage = createMMKV({
|
|
310
|
-
id: 'secure',
|
|
311
|
-
encryptionKey: 'your-key'
|
|
312
|
-
});
|
|
313
|
-
|
|
314
|
-
if (__DEV__) {
|
|
315
|
-
registerMMKVInstance('mmkv.default', storage);
|
|
316
|
-
registerMMKVInstance('secure', secureStorage, { encrypted: true });
|
|
317
|
-
}
|
|
318
|
-
```
|
|
319
|
-
|
|
320
|
-
Then import in your app:
|
|
321
|
-
|
|
322
|
-
```typescript
|
|
323
|
-
import { storage, secureStorage } from './utils/storage';
|
|
324
|
-
|
|
325
|
-
// Use anywhere in your app
|
|
326
|
-
storage.set('user.name', 'John Doe');
|
|
327
|
-
secureStorage.set('auth.token', 'secret-token');
|
|
328
|
-
```
|
|
329
|
-
|
|
330
|
-
## API Reference
|
|
331
|
-
|
|
332
|
-
### Presets
|
|
333
|
-
|
|
334
|
-
#### `storageToolPreset`
|
|
335
|
-
|
|
336
|
-
Pre-configured AsyncStorage browser tool ready to use with FloatingDevTools.
|
|
337
|
-
|
|
338
|
-
**Example:**
|
|
339
|
-
```typescript
|
|
340
|
-
import { storageToolPreset } from '@buoy/storage';
|
|
341
|
-
|
|
342
|
-
const installedApps = [storageToolPreset];
|
|
343
|
-
```
|
|
344
|
-
|
|
345
|
-
#### `createStorageTool(options?)`
|
|
346
|
-
|
|
347
|
-
Create a custom AsyncStorage browser tool configuration.
|
|
348
|
-
|
|
349
|
-
**Options:**
|
|
350
|
-
```typescript
|
|
351
|
-
{
|
|
352
|
-
/** Tool name (default: "STORAGE") */
|
|
353
|
-
name?: string;
|
|
354
|
-
/** Tool description */
|
|
355
|
-
description?: string;
|
|
356
|
-
/** Icon color preset (default: "green") */
|
|
357
|
-
colorPreset?: "orange" | "cyan" | "purple" | "pink" | "yellow" | "green";
|
|
358
|
-
/** Custom tool ID (default: "storage") */
|
|
359
|
-
id?: string;
|
|
360
|
-
/** Array of required storage keys to validate */
|
|
361
|
-
requiredStorageKeys?: RequiredStorageKey[];
|
|
362
|
-
/** Enable shared modal dimensions */
|
|
363
|
-
enableSharedModalDimensions?: boolean;
|
|
364
|
-
}
|
|
365
|
-
```
|
|
366
|
-
|
|
367
|
-
**Example:**
|
|
368
|
-
```typescript
|
|
369
|
-
import { createStorageTool } from '@buoy/storage';
|
|
370
|
-
|
|
371
|
-
const requiredStorageKeys = [
|
|
372
|
-
{
|
|
373
|
-
key: "@app/session",
|
|
374
|
-
expectedType: "string",
|
|
375
|
-
description: "User session token",
|
|
376
|
-
storageType: "async",
|
|
377
|
-
},
|
|
378
|
-
];
|
|
379
|
-
|
|
380
|
-
const myStorageTool = createStorageTool({
|
|
381
|
-
name: "APP STORAGE",
|
|
382
|
-
requiredStorageKeys,
|
|
383
|
-
colorPreset: "cyan",
|
|
384
|
-
enableSharedModalDimensions: true,
|
|
385
|
-
});
|
|
386
|
-
```
|
|
387
|
-
|
|
388
|
-
### Components
|
|
389
|
-
|
|
390
|
-
#### `StorageModalWithTabs`
|
|
391
|
-
|
|
392
|
-
Main modal component with two tabs: Browser and Events.
|
|
393
|
-
|
|
394
|
-
**Props:**
|
|
395
|
-
```typescript
|
|
396
|
-
interface StorageModalWithTabsProps {
|
|
397
|
-
/** Whether the modal is visible */
|
|
398
|
-
visible: boolean;
|
|
399
|
-
/** Callback when modal is closed */
|
|
400
|
-
onClose: () => void;
|
|
401
|
-
/** Optional back button handler */
|
|
402
|
-
onBack?: () => void;
|
|
403
|
-
/** Whether to use shared modal dimensions */
|
|
404
|
-
enableSharedModalDimensions?: boolean;
|
|
405
|
-
/** Array of required storage keys to validate */
|
|
406
|
-
requiredStorageKeys?: RequiredStorageKey[];
|
|
407
|
-
}
|
|
408
|
-
```
|
|
409
|
-
|
|
410
|
-
**Example:**
|
|
411
|
-
```typescript
|
|
412
|
-
<StorageModalWithTabs
|
|
413
|
-
visible={isVisible}
|
|
414
|
-
onClose={handleClose}
|
|
415
|
-
requiredStorageKeys={requiredKeys}
|
|
416
|
-
enableSharedModalDimensions={true}
|
|
417
|
-
/>
|
|
418
|
-
```
|
|
419
|
-
|
|
420
|
-
### Types
|
|
421
|
-
|
|
422
|
-
#### `RequiredStorageKey`
|
|
423
|
-
|
|
424
|
-
```typescript
|
|
425
|
-
interface RequiredStorageKey {
|
|
426
|
-
/** Storage key to validate */
|
|
427
|
-
key: string;
|
|
428
|
-
/** Optional description of the key */
|
|
429
|
-
description?: string;
|
|
430
|
-
/** Expected value type */
|
|
431
|
-
expectedType?: "string" | "number" | "boolean" | "object" | "array";
|
|
432
|
-
/** Expected value */
|
|
433
|
-
expectedValue?: any;
|
|
434
|
-
/** Storage type: "async" for AsyncStorage, "mmkv" for MMKV, "secure" for Secure Storage */
|
|
435
|
-
storageType: "async" | "mmkv" | "secure";
|
|
436
|
-
/** Whether the key is required */
|
|
437
|
-
required?: boolean;
|
|
438
|
-
}
|
|
439
|
-
```
|
|
440
|
-
|
|
441
|
-
#### `AsyncStorageEvent`
|
|
442
|
-
|
|
443
|
-
```typescript
|
|
444
|
-
interface AsyncStorageEvent {
|
|
445
|
-
/** Unique event ID */
|
|
446
|
-
id: string;
|
|
447
|
-
/** Event type (set, get, remove, clear, etc.) */
|
|
448
|
-
type: "set" | "get" | "remove" | "clear" | "multiGet" | "multiSet" | "multiRemove";
|
|
449
|
-
/** Storage key(s) involved */
|
|
450
|
-
key?: string | string[];
|
|
451
|
-
/** Value (for set operations) */
|
|
452
|
-
value?: any;
|
|
453
|
-
/** Timestamp of the event */
|
|
454
|
-
timestamp: number;
|
|
455
|
-
/** Whether the operation succeeded */
|
|
456
|
-
success: boolean;
|
|
457
|
-
/** Error message if operation failed */
|
|
458
|
-
error?: string;
|
|
459
|
-
}
|
|
460
|
-
```
|
|
461
|
-
|
|
462
|
-
## Use Cases
|
|
463
|
-
|
|
464
|
-
### Session Management
|
|
465
|
-
|
|
466
|
-
Monitor and validate user session storage:
|
|
467
|
-
|
|
468
|
-
```typescript
|
|
469
|
-
import { createStorageTool } from '@buoy/storage';
|
|
470
|
-
|
|
471
|
-
const requiredStorageKeys = [
|
|
472
|
-
{
|
|
473
|
-
key: "@app/session:token",
|
|
474
|
-
expectedType: "string",
|
|
475
|
-
description: "JWT auth token",
|
|
476
|
-
storageType: "async",
|
|
477
|
-
required: true,
|
|
478
|
-
},
|
|
479
|
-
{
|
|
480
|
-
key: "@app/session:userId",
|
|
481
|
-
expectedType: "string",
|
|
482
|
-
description: "Current user ID",
|
|
483
|
-
storageType: "async",
|
|
484
|
-
required: true,
|
|
485
|
-
},
|
|
486
|
-
];
|
|
487
|
-
|
|
488
|
-
const storageTool = createStorageTool({ requiredStorageKeys });
|
|
489
|
-
```
|
|
490
|
-
|
|
491
|
-
### App Settings
|
|
34
|
+
**MMKV** — register each instance once so the explorer can see it (required for MMKV v4; Metro can't auto-detect instances):
|
|
492
35
|
|
|
493
|
-
|
|
36
|
+
```ts
|
|
37
|
+
import { createMMKV } from "react-native-mmkv";
|
|
38
|
+
import { registerMMKVInstance } from "@buoy-gg/storage";
|
|
494
39
|
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
{
|
|
498
|
-
key: "@app/settings:theme",
|
|
499
|
-
expectedValue: "dark",
|
|
500
|
-
description: "UI theme preference",
|
|
501
|
-
storageType: "async",
|
|
502
|
-
},
|
|
503
|
-
{
|
|
504
|
-
key: "@app/settings:notifications",
|
|
505
|
-
expectedType: "boolean",
|
|
506
|
-
description: "Notifications enabled",
|
|
507
|
-
storageType: "async",
|
|
508
|
-
},
|
|
509
|
-
{
|
|
510
|
-
key: "@app/settings:language",
|
|
511
|
-
expectedType: "string",
|
|
512
|
-
description: "User language preference",
|
|
513
|
-
storageType: "async",
|
|
514
|
-
},
|
|
515
|
-
];
|
|
40
|
+
export const storage = createMMKV({ id: "mmkv.default" });
|
|
41
|
+
registerMMKVInstance("mmkv.default", storage);
|
|
516
42
|
```
|
|
517
43
|
|
|
518
|
-
|
|
44
|
+
**SecureStore** — the iOS Keychain / Android KeyStore has no key-listing API, so register the keys you want visible:
|
|
519
45
|
|
|
520
|
-
|
|
46
|
+
```ts
|
|
47
|
+
import * as SecureStore from "expo-secure-store";
|
|
48
|
+
import { registerSecureStoreKeys } from "@buoy-gg/storage";
|
|
521
49
|
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
{
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
storageType: "async",
|
|
529
|
-
},
|
|
530
|
-
{
|
|
531
|
-
key: "@app/cache:timestamp",
|
|
532
|
-
expectedType: "number",
|
|
533
|
-
description: "Cache timestamp",
|
|
534
|
-
storageType: "async",
|
|
535
|
-
},
|
|
536
|
-
];
|
|
50
|
+
registerSecureStoreKeys(SecureStore, [
|
|
51
|
+
"auth.accessToken",
|
|
52
|
+
{ key: "session", keychainService: "com.myapp.auth" },
|
|
53
|
+
// Biometric-protected keys are listed but never auto-read (no surprise Face ID prompts)
|
|
54
|
+
{ key: "pin", requireAuthentication: true },
|
|
55
|
+
]);
|
|
537
56
|
```
|
|
538
57
|
|
|
539
|
-
##
|
|
58
|
+
## What you get
|
|
540
59
|
|
|
541
|
-
|
|
60
|
+
- **Three backends, one explorer** — AsyncStorage, MMKV (multiple instances, including encrypted), and Expo SecureStore, with per-instance key counts and an instance switcher.
|
|
61
|
+
- **Edit in place** — modify, delete, and add keys directly; bulk-select to delete or export many at once.
|
|
62
|
+
- **Live events** — watch storage reads and writes stream in as your app runs.
|
|
63
|
+
- **Pin and hide** — pin the keys you're watching to the top (persists across sessions); one tap hides noisy keys non-destructively.
|
|
64
|
+
- **Inline previews** — short values show on the card (`number · 42`, `string · "en"`), booleans get color-coded true/false badges, and valid JSON is auto pretty-printed.
|
|
65
|
+
- **Biometric keys stay safe** — SecureStore keys behind Face ID / fingerprint are listed but never auto-read.
|
|
66
|
+
- **Required-key validation** — declare keys with expected types or values via `createStorageTool({ requiredStorageKeys })` and see what's missing or wrong.
|
|
542
67
|
|
|
543
|
-
|
|
544
|
-
- **Search**: Search through keys by name
|
|
545
|
-
- **Filter**: Filter by validation status (all, missing, issues)
|
|
546
|
-
- **Edit**: Modify existing values directly
|
|
547
|
-
- **Delete**: Remove storage entries
|
|
548
|
-
- **Add**: Create new storage entries
|
|
549
|
-
- **Copy**: Copy keys and values to clipboard
|
|
550
|
-
- **Validation**: See which required keys are missing or invalid
|
|
551
|
-
|
|
552
|
-
### Events Tab
|
|
553
|
-
|
|
554
|
-
- **Live Monitoring**: Watch all storage operations in real-time
|
|
555
|
-
- **Event Types**: Track set, get, remove, clear, and multi-operations
|
|
556
|
-
- **Filtering**: Filter events by type or key
|
|
557
|
-
- **Search**: Search through event history
|
|
558
|
-
- **Timeline**: See chronological order of operations
|
|
559
|
-
- **Pause/Resume**: Control event capture
|
|
560
|
-
- **Clear**: Clear event history
|
|
561
|
-
|
|
562
|
-
### Validation
|
|
563
|
-
|
|
564
|
-
Required storage keys can be validated for:
|
|
565
|
-
- **Existence**: Check if the key exists
|
|
566
|
-
- **Type**: Validate the value type (string, number, boolean, object, array)
|
|
567
|
-
- **Value**: Check if the value matches an expected value
|
|
568
|
-
- **Custom Validation**: Implement custom validation logic
|
|
569
|
-
|
|
570
|
-
## Dependencies
|
|
571
|
-
|
|
572
|
-
- `@buoy/shared-ui` - Common UI components and utilities
|
|
573
|
-
- `@react-native-async-storage/async-storage` - AsyncStorage implementation (peer dependency; supports v2 and v3 — `^2.0.0 || ^3.1.0`. Avoid 3.0.x, which has an Android build issue fixed upstream in 3.1.0.)
|
|
574
|
-
- `react-native-mmkv` - MMKV storage implementation (optional peer dependency)
|
|
575
|
-
- React and React Native (peer dependencies)
|
|
576
|
-
|
|
577
|
-
## Development
|
|
578
|
-
|
|
579
|
-
### Building
|
|
580
|
-
|
|
581
|
-
```bash
|
|
582
|
-
pnpm build
|
|
583
|
-
```
|
|
584
|
-
|
|
585
|
-
### Type Checking
|
|
586
|
-
|
|
587
|
-
```bash
|
|
588
|
-
pnpm typecheck
|
|
589
|
-
```
|
|
590
|
-
|
|
591
|
-
### Clean Build
|
|
592
|
-
|
|
593
|
-
```bash
|
|
594
|
-
pnpm clean
|
|
595
|
-
```
|
|
68
|
+
## Desktop & AI
|
|
596
69
|
|
|
597
|
-
|
|
70
|
+
The same live session streams to [Buoy Desktop](https://github.com/Buoy-gg/Buoy-Desktop) (free, macOS/Windows/Linux) and to Claude Code or Cursor via the [Buoy MCP server](https://buoy.gg/buoy/latest/docs/mcp).
|
|
598
71
|
|
|
599
|
-
|
|
72
|
+
## Free vs Pro
|
|
600
73
|
|
|
601
|
-
|
|
74
|
+
Every tool is free. [Pro](https://buoy.gg/pricing) unlocks production builds, the MCP server, and unlimited capture. Every weekend, Pro features unlock free for everyone.
|
|
602
75
|
|
|
603
|
-
|
|
76
|
+
---
|
|
604
77
|
|
|
605
|
-
|
|
78
|
+
📚 [Full docs](https://buoy.gg/buoy/latest/docs/tools/storage) · [All Buoy tools](https://github.com/Buoy-gg/buoy)
|
|
606
79
|
|
|
607
|
-
|
|
80
|
+
Proprietary software. © Buoy LLC. [Terms](https://buoy.gg/terms)
|
package/lib/commonjs/index.js
CHANGED
|
@@ -147,6 +147,12 @@ Object.defineProperty(exports, "registerMMKVInstance", {
|
|
|
147
147
|
return _MMKVInstanceRegistry.registerMMKVInstance;
|
|
148
148
|
}
|
|
149
149
|
});
|
|
150
|
+
Object.defineProperty(exports, "registerSecureStoreKeys", {
|
|
151
|
+
enumerable: true,
|
|
152
|
+
get: function () {
|
|
153
|
+
return _SecureStoreRegistry.registerSecureStoreKeys;
|
|
154
|
+
}
|
|
155
|
+
});
|
|
150
156
|
Object.defineProperty(exports, "storageEventStore", {
|
|
151
157
|
enumerable: true,
|
|
152
158
|
get: function () {
|
|
@@ -177,6 +183,12 @@ Object.defineProperty(exports, "unregisterMMKVInstance", {
|
|
|
177
183
|
return _MMKVInstanceRegistry.unregisterMMKVInstance;
|
|
178
184
|
}
|
|
179
185
|
});
|
|
186
|
+
Object.defineProperty(exports, "unregisterSecureStoreKey", {
|
|
187
|
+
enumerable: true,
|
|
188
|
+
get: function () {
|
|
189
|
+
return _SecureStoreRegistry.unregisterSecureStoreKey;
|
|
190
|
+
}
|
|
191
|
+
});
|
|
180
192
|
Object.defineProperty(exports, "useAsyncStorageKeys", {
|
|
181
193
|
enumerable: true,
|
|
182
194
|
get: function () {
|
|
@@ -240,5 +252,6 @@ var _mmkvAvailability = require("./storage/utils/mmkvAvailability");
|
|
|
240
252
|
var _mmkvTypeDetection = require("./storage/utils/mmkvTypeDetection");
|
|
241
253
|
var _storageTimeTravelUtils = require("./storage/utils/storageTimeTravelUtils");
|
|
242
254
|
var _MMKVInstanceRegistry = require("./storage/utils/MMKVInstanceRegistry");
|
|
255
|
+
var _SecureStoreRegistry = require("./storage/utils/SecureStoreRegistry");
|
|
243
256
|
var _storageSyncAdapter = require("./storage/sync/storageSyncAdapter");
|
|
244
257
|
var _storageEventStore = require("./storage/stores/storageEventStore");
|