@buoy-gg/storage 7.0.17 → 7.0.19

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.
Files changed (38) hide show
  1. package/lib/commonjs/index.js +12 -0
  2. package/lib/commonjs/storage/components/DiffViewer/modes/ThemedSplitView.js +5 -602
  3. package/lib/commonjs/storage/components/StorageModalWithTabs.js +17 -1
  4. package/lib/commonjs/storage/hooks/useAsyncStorageKeys.js +13 -10
  5. package/lib/commonjs/storage/hooks/useMMKVKeys.js +28 -23
  6. package/lib/commonjs/storage/stores/storageEventStore.js +85 -1
  7. package/lib/commonjs/storage/sync/storageSyncAdapter.js +214 -6
  8. package/lib/commonjs/storage/utils/requiredStorageKeyScope.js +17 -0
  9. package/lib/commonjs/storage/utils/snapshotProvider.js +173 -5
  10. package/lib/commonjs/storage/utils/storageTimeTravelUtils.js +17 -3
  11. package/lib/module/index.js +6 -1
  12. package/lib/module/storage/components/DiffViewer/modes/ThemedSplitView.js +7 -603
  13. package/lib/module/storage/components/StorageModalWithTabs.js +17 -1
  14. package/lib/module/storage/hooks/useAsyncStorageKeys.js +13 -10
  15. package/lib/module/storage/hooks/useMMKVKeys.js +28 -23
  16. package/lib/module/storage/stores/storageEventStore.js +81 -0
  17. package/lib/module/storage/sync/storageSyncAdapter.js +215 -7
  18. package/lib/module/storage/utils/requiredStorageKeyScope.js +13 -0
  19. package/lib/module/storage/utils/snapshotProvider.js +173 -5
  20. package/lib/module/storage/utils/storageTimeTravelUtils.js +17 -3
  21. package/lib/typescript/index.d.ts +2 -1
  22. package/lib/typescript/index.d.ts.map +1 -1
  23. package/lib/typescript/storage/components/DiffViewer/modes/ThemedSplitView.d.ts +7 -18
  24. package/lib/typescript/storage/components/DiffViewer/modes/ThemedSplitView.d.ts.map +1 -1
  25. package/lib/typescript/storage/components/StorageModalWithTabs.d.ts +8 -1
  26. package/lib/typescript/storage/components/StorageModalWithTabs.d.ts.map +1 -1
  27. package/lib/typescript/storage/hooks/useAsyncStorageKeys.d.ts.map +1 -1
  28. package/lib/typescript/storage/hooks/useMMKVKeys.d.ts.map +1 -1
  29. package/lib/typescript/storage/stores/storageEventStore.d.ts +26 -0
  30. package/lib/typescript/storage/stores/storageEventStore.d.ts.map +1 -1
  31. package/lib/typescript/storage/sync/storageSyncAdapter.d.ts +80 -14
  32. package/lib/typescript/storage/sync/storageSyncAdapter.d.ts.map +1 -1
  33. package/lib/typescript/storage/types.d.ts +9 -9
  34. package/lib/typescript/storage/types.d.ts.map +1 -1
  35. package/lib/typescript/storage/utils/requiredStorageKeyScope.d.ts +10 -0
  36. package/lib/typescript/storage/utils/requiredStorageKeyScope.d.ts.map +1 -0
  37. package/lib/typescript/storage/utils/storageTimeTravelUtils.d.ts.map +1 -1
  38. package/package.json +11 -6
@@ -34,7 +34,9 @@ function status() {
34
34
  canRestore: true
35
35
  };
36
36
  }
37
- async function capture() {
37
+
38
+ /** Shared by capture() and the live side of previewItems(). */
39
+ async function captureStorageData() {
38
40
  const warnings = [];
39
41
  const appKeys = (await AsyncStorage.getAllKeys()).filter(k => !isDevToolsStorageKey(k));
40
42
  const asyncPairs = (await readMany(appKeys)).filter(pair => pair[1] !== null);
@@ -92,8 +94,23 @@ async function capture() {
92
94
  warnings
93
95
  };
94
96
  }
95
- async function restore(data) {
97
+ async function capture() {
98
+ const {
99
+ data,
100
+ warnings
101
+ } = await captureStorageData();
102
+ return {
103
+ data,
104
+ warnings
105
+ };
106
+ }
107
+ async function restore(data, options) {
96
108
  const snapshot = data;
109
+ const excludedSet = new Set(options?.excludeKeys ?? []);
110
+ const includedSet = options?.includeKeys ? new Set(options.includeKeys) : null;
111
+ /** True when this item may be touched (scope + exclusions agree). */
112
+ const touch = key => !excludedSet.has(key) && (!includedSet || includedSet.has(key));
113
+ let excludedHits = 0;
97
114
  const result = {
98
115
  ok: true,
99
116
  applied: 0,
@@ -111,10 +128,11 @@ async function restore(data) {
111
128
 
112
129
  // ── AsyncStorage: delete app keys missing from the snapshot, write the rest ──
113
130
  try {
114
- const snapPairs = (snapshot.async ?? []).filter(([k]) => !isDevToolsStorageKey(k));
131
+ const snapPairs = (snapshot.async ?? []).filter(([k]) => !isDevToolsStorageKey(k) && touch(`async:${k}`));
115
132
  const snapKeys = new Set(snapPairs.map(([k]) => k));
116
133
  const liveKeys = (await AsyncStorage.getAllKeys()).filter(k => !isDevToolsStorageKey(k));
117
- const toRemove = liveKeys.filter(k => !snapKeys.has(k));
134
+ const toRemove = liveKeys.filter(k => !snapKeys.has(k) && touch(`async:${k}`));
135
+ excludedHits += (snapshot.async ?? []).length - snapPairs.length;
118
136
  if (toRemove.length > 0) await removeMany(toRemove);
119
137
  if (snapPairs.length > 0) await writeMany(snapPairs);
120
138
  result.applied += snapPairs.length + toRemove.length;
@@ -147,6 +165,10 @@ async function restore(data) {
147
165
  const snapKeys = new Set(entries.map(e => e.key));
148
166
  const liveKeys = instance.getAllKeys().filter(key => !isDevToolsStorageKey(key));
149
167
  for (const key of liveKeys) {
168
+ if (!touch(`mmkv:${id}/${key}`)) {
169
+ excludedHits += 1;
170
+ continue;
171
+ }
150
172
  if (!snapKeys.has(key)) {
151
173
  deleteMMKVKey(instance, key);
152
174
  result.applied += 1;
@@ -154,6 +176,7 @@ async function restore(data) {
154
176
  }
155
177
  for (const entry of entries) {
156
178
  if (isDevToolsStorageKey(entry.key)) continue;
179
+ if (!touch(`mmkv:${id}/${entry.key}`)) continue;
157
180
  if (entry.valueType === "buffer") {
158
181
  result.skipped.push({
159
182
  id: `mmkv:${id}/${entry.key}`,
@@ -176,6 +199,10 @@ async function restore(data) {
176
199
  key,
177
200
  options
178
201
  } of secureStoreRegistry.getAll()) {
202
+ if (!touch(`secure:${key}`)) {
203
+ excludedHits += 1;
204
+ continue;
205
+ }
179
206
  if (options.requireAuthentication) {
180
207
  if (key in secureSnap) {
181
208
  result.skipped.push({
@@ -200,6 +227,7 @@ async function restore(data) {
200
227
  }
201
228
  }
202
229
  for (const key of Object.keys(secureSnap)) {
230
+ if (!touch(`secure:${key}`)) continue;
203
231
  if (!secureStoreRegistry.getAll().some(e => e.key === key)) {
204
232
  result.skipped.push({
205
233
  id: `secure:${key}`,
@@ -207,6 +235,9 @@ async function restore(data) {
207
235
  });
208
236
  }
209
237
  }
238
+ if (excludedHits > 0) {
239
+ result.warnings.push(`${excludedHits} item(s) excluded by you`);
240
+ }
210
241
  return result;
211
242
  }
212
243
 
@@ -267,11 +298,148 @@ async function clear() {
267
298
  }
268
299
  return result;
269
300
  }
301
+ const ITEM_RENDER_CHAR_LIMIT = 256 * 1024;
302
+ function classifyValue(key, label, oldValue, newValue, inOld, inNew) {
303
+ if (!inNew) return {
304
+ key,
305
+ label,
306
+ verdict: "removed",
307
+ oldValue
308
+ };
309
+ if (!inOld) return {
310
+ key,
311
+ label,
312
+ verdict: "added",
313
+ newValue
314
+ };
315
+ if (Object.is(oldValue, newValue)) return {
316
+ key,
317
+ label,
318
+ verdict: "unchanged"
319
+ };
320
+ const tooLarge = typeof oldValue === "string" && oldValue.length > ITEM_RENDER_CHAR_LIMIT || typeof newValue === "string" && newValue.length > ITEM_RENDER_CHAR_LIMIT;
321
+ if (tooLarge) {
322
+ return {
323
+ key,
324
+ label,
325
+ verdict: "too-large",
326
+ reason: "value too large to render a diff — restore still applies it"
327
+ };
328
+ }
329
+ return {
330
+ key,
331
+ label,
332
+ verdict: "changed",
333
+ oldValue,
334
+ newValue
335
+ };
336
+ }
337
+
338
+ /** Per-key restore preview across all three backends. */
339
+ async function previewItems(target, base) {
340
+ const targetData = target ?? {
341
+ async: [],
342
+ mmkv: {},
343
+ secure: {}
344
+ };
345
+ const liveMode = base === undefined;
346
+ const baseData = liveMode ? (await captureStorageData()).data : base ?? {
347
+ async: [],
348
+ mmkv: {},
349
+ secure: {}
350
+ };
351
+ const items = [];
352
+ const notes = [];
353
+
354
+ // ── AsyncStorage ──
355
+ const oldAsync = new Map(baseData.async ?? []);
356
+ const newAsync = new Map(targetData.async ?? []);
357
+ for (const key of new Set([...oldAsync.keys(), ...newAsync.keys()])) {
358
+ if (isDevToolsStorageKey(key)) continue;
359
+ items.push(classifyValue(`async:${key}`, key, oldAsync.get(key), newAsync.get(key), oldAsync.has(key), newAsync.has(key)));
360
+ }
361
+
362
+ // ── MMKV ──
363
+ const instanceIds = new Set([...Object.keys(baseData.mmkv ?? {}), ...Object.keys(targetData.mmkv ?? {})]);
364
+ for (const id of instanceIds) {
365
+ const registered = liveMode ? mmkvInstanceRegistry.get(id) : null;
366
+ const instanceUnavailable = liveMode && !registered;
367
+ const readOnly = liveMode && registered?.instance.isReadOnly === true;
368
+ const oldEntries = new Map((baseData.mmkv?.[id] ?? []).map(e => [e.key, e]));
369
+ const newEntries = new Map((targetData.mmkv?.[id] ?? []).map(e => [e.key, e]));
370
+ for (const key of new Set([...oldEntries.keys(), ...newEntries.keys()])) {
371
+ if (isDevToolsStorageKey(key)) continue;
372
+ const itemKey = `mmkv:${id}/${key}`;
373
+ const label = `${id} · ${key}`;
374
+ const oldE = oldEntries.get(key);
375
+ const newE = newEntries.get(key);
376
+ let item = classifyValue(itemKey, label, oldE?.value, newE?.value, oldEntries.has(key), newEntries.has(key));
377
+ if (item.verdict !== "unchanged") {
378
+ if (instanceUnavailable) {
379
+ item = {
380
+ ...item,
381
+ verdict: "wont-apply",
382
+ reason: "MMKV instance not registered"
383
+ };
384
+ } else if (readOnly) {
385
+ item = {
386
+ ...item,
387
+ verdict: "wont-apply",
388
+ reason: "MMKV instance registered read-only"
389
+ };
390
+ } else if (newE?.valueType === "buffer" || oldE?.valueType === "buffer") {
391
+ item = {
392
+ ...item,
393
+ verdict: "wont-apply",
394
+ reason: "ArrayBuffer values cannot be restored"
395
+ };
396
+ }
397
+ }
398
+ items.push(item);
399
+ }
400
+ }
401
+
402
+ // ── SecureStore ──
403
+ const oldSecure = baseData.secure ?? {};
404
+ const newSecure = targetData.secure ?? {};
405
+ const registeredSecure = liveMode ? new Map(secureStoreRegistry.getAll().map(e => [e.key, e])) : null;
406
+ for (const key of new Set([...Object.keys(oldSecure), ...Object.keys(newSecure)])) {
407
+ let item = classifyValue(`secure:${key}`, key, oldSecure[key], newSecure[key], key in oldSecure, key in newSecure);
408
+ if (liveMode && item.verdict !== "unchanged") {
409
+ const entry = registeredSecure?.get(key);
410
+ if (!entry) {
411
+ item = {
412
+ ...item,
413
+ verdict: "wont-apply",
414
+ reason: "key no longer registered with registerSecureStoreKeys"
415
+ };
416
+ } else if (entry.options.requireAuthentication) {
417
+ item = {
418
+ ...item,
419
+ verdict: "wont-apply",
420
+ reason: "biometric-protected keys are never written"
421
+ };
422
+ }
423
+ }
424
+ items.push(item);
425
+ }
426
+ if (liveMode) {
427
+ const biometric = secureStoreRegistry.getAll().filter(e => e.options.requireAuthentication).length;
428
+ if (biometric > 0) {
429
+ notes.push(`${biometric} biometric-protected secure key(s) are never read or written`);
430
+ }
431
+ }
432
+ return {
433
+ items,
434
+ notes
435
+ };
436
+ }
270
437
  registerStateSnapshotProvider({
271
438
  id: "storage",
272
439
  label: "Storage",
273
440
  status,
274
441
  capture,
275
442
  restore,
276
- clear
443
+ clear,
444
+ previewItems
277
445
  });
@@ -9,6 +9,10 @@
9
9
  import { isDevToolsStorageKey } from "@buoy-gg/shared-ui";
10
10
  import AsyncStorage from "@react-native-async-storage/async-storage";
11
11
  import { writeMany, removeMany } from "./asyncStorageCompat";
12
+ function isOmittedStorageValue(value) {
13
+ return !!value && typeof value === "object" && value.__buoyValueOnDevice === true;
14
+ }
15
+
12
16
  /**
13
17
  * Undo a single storage operation
14
18
  *
@@ -28,6 +32,9 @@ export async function undoOperation(event) {
28
32
  action,
29
33
  data
30
34
  } = event;
35
+ if (isOmittedStorageValue(data?.prevValue) || isOmittedStorageValue(data?.prevPairs)) {
36
+ throw new Error("Cannot undo: previous value is still on the device — fetch getEventDetail first");
37
+ }
31
38
  {
32
39
  switch (action) {
33
40
  case "setItem":
@@ -106,6 +113,12 @@ export async function jumpToState(events, targetEventIndex) {
106
113
  if (targetEventIndex < 0 || targetEventIndex >= events.length) {
107
114
  throw new Error(`Invalid event index: ${targetEventIndex}`);
108
115
  }
116
+ for (const event of events) {
117
+ const data = event.data;
118
+ if (isOmittedStorageValue(data?.value) || isOmittedStorageValue(data?.prevValue) || isOmittedStorageValue(data?.pairs) || isOmittedStorageValue(data?.prevPairs)) {
119
+ throw new Error("Cannot jump: some event values are still on the device — fetch getEventDetail first");
120
+ }
121
+ }
109
122
 
110
123
  // Build up the state by applying each event up to and including the target.
111
124
  // We use the final values from each event, not the operations themselves.
@@ -253,14 +266,15 @@ export function canUndo(event) {
253
266
  case "setItem":
254
267
  case "mergeItem":
255
268
  case "removeItem":
256
- // Can undo if we have the key
257
- return !!data?.key;
269
+ // Can undo if we have the key — but not while prevValue is still a
270
+ // wire-form on-device marker (restoring that would write garbage).
271
+ return !!data?.key && !isOmittedStorageValue(data.prevValue);
258
272
  case "multiSet":
259
273
  case "multiRemove":
260
274
  case "multiMerge":
261
275
  case "clear":
262
276
  // Can undo if we have previous pairs
263
- return !!data?.prevPairs && data.prevPairs.length > 0;
277
+ return !!data?.prevPairs && data.prevPairs.length > 0 && !isOmittedStorageValue(data.prevPairs);
264
278
  default:
265
279
  return false;
266
280
  }
@@ -29,6 +29,7 @@ export { useMMKVKeys, useMultiMMKVKeys } from "./storage/hooks/useMMKVKeys";
29
29
  export { useMMKVInstances, useMMKVInstance, useMMKVInstanceExists, } from "./storage/hooks/useMMKVInstances";
30
30
  export { useStorageEvents, type UseStorageEventsOptions, type UseStorageEventsResult, } from "./storage/hooks/useStorageEvents";
31
31
  export type { StorageEvent, StorageEventListener, StorageEventCallback, } from "./storage/stores/storageEventStore";
32
+ export type { RequiredStorageKey, StorageKeyInfo } from "./storage/types";
32
33
  export { clearAllAppStorage } from "./storage/utils/clearAllStorage";
33
34
  export { setStorageValue, storageEditBlockedReason, validateStorageValue, storageValueToEditableText, type EditableMMKVInstance, } from "./storage/utils/setStorageValue";
34
35
  export { isMMKVAvailable, getMMKVClass, getMMKVUnavailableMessage, } from "./storage/utils/mmkvAvailability";
@@ -42,7 +43,7 @@ export { registerSecureStoreKeys, unregisterSecureStoreKey, } from "./storage/ut
42
43
  export type { SecureStoreLike, SecureStoreKeyDescriptor, SecureStoreOptionsLike, } from "./storage/utils/SecureStoreRegistry";
43
44
  export { storageSyncAdapter } from "./storage/sync/storageSyncAdapter";
44
45
  /** @internal */
45
- export { storageEventStore } from "./storage/stores/storageEventStore";
46
+ export { storageEventStore, isValueOnDevice, batchPairsOf, } from "./storage/stores/storageEventStore";
46
47
  /**
47
48
  * Tell a mounted storage browser to re-read every backend. Used by the desktop
48
49
  * dashboard, where local storage listeners are suppressed and device data
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,kCAAkC,CAAC;AAK1C,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAKhE,OAAO,EAAE,cAAc,EAAE,MAAM,qCAAqC,CAAC;AAGrE,OAAO,EACL,oBAAoB,EACpB,eAAe,GAChB,MAAM,2CAA2C,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,qCAAqC,CAAC;AACrE,OAAO,EAAE,sBAAsB,EAAE,MAAM,sCAAsC,CAAC;AAC9E,OAAO,EAAE,iBAAiB,EAAE,MAAM,wCAAwC,CAAC;AAC3E,OAAO,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AAC7E,YAAY,EACV,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,yCAAyC,CAAC;AAEjD,OAAO,EACL,oBAAoB,EACpB,kBAAkB,EAClB,KAAK,iBAAiB,GACvB,MAAM,2CAA2C,CAAC;AACnD,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AAGjF,OAAO,EACL,WAAW,EACX,WAAW,EACX,YAAY,EACZ,aAAa,EACb,KAAK,SAAS,GACf,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,gBAAgB,EAChB,YAAY,EACZ,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,GACtB,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EACL,yBAAyB,EACzB,wBAAwB,GACzB,MAAM,gDAAgD,CAAC;AACxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,qBAAqB,EAAE,MAAM,4CAA4C,CAAC;AAKnF,OAAO,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAC;AAC1E,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC5E,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,qBAAqB,GACtB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EACL,gBAAgB,EAChB,KAAK,uBAAuB,EAC5B,KAAK,sBAAsB,GAC5B,MAAM,kCAAkC,CAAC;AAK1C,YAAY,EACV,YAAY,EACZ,oBAAoB,EACpB,oBAAoB,GACrB,MAAM,oCAAoC,CAAC;AAC5C,YAAY,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAK1E,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AAGrE,OAAO,EACL,eAAe,EACf,wBAAwB,EACxB,oBAAoB,EACpB,0BAA0B,EAC1B,KAAK,oBAAoB,GAC1B,MAAM,iCAAiC,CAAC;AACzC,OAAO,EACL,eAAe,EACf,YAAY,EACZ,yBAAyB,GAC1B,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EACL,cAAc,EACd,eAAe,EACf,WAAW,EACX,KAAK,aAAa,EAClB,KAAK,aAAa,GACnB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EACL,aAAa,EACb,WAAW,EACX,OAAO,GACR,MAAM,wCAAwC,CAAC;AAChD,YAAY,EACV,iBAAiB,EACjB,yBAAyB,GAC1B,MAAM,sCAAsC,CAAC;AAC9C,YAAY,EACV,SAAS,EACT,iBAAiB,GAClB,MAAM,8BAA8B,CAAC;AACtC,YAAY,EAAE,gBAAgB,EAAE,MAAM,sCAAsC,CAAC;AAK7E,OAAO,EACL,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,sCAAsC,CAAC;AAM9C,OAAO,EACL,uBAAuB,EACvB,wBAAwB,GACzB,MAAM,qCAAqC,CAAC;AAC7C,YAAY,EACV,eAAe,EACf,wBAAwB,EACxB,sBAAsB,GACvB,MAAM,qCAAqC,CAAC;AAK7C,OAAO,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AAKvE,gBAAgB;AAChB,OAAO,EACL,iBAAiB,EAKjB,eAAe,EACf,YAAY,GACb,MAAM,oCAAoC,CAAC;AAC5C;;;;;GAKG;AACH,OAAO,EAAE,4BAA4B,EAAE,MAAM,uCAAuC,CAAC"}
@@ -1,19 +1,8 @@
1
- import { DiffOptions } from "../DiffOptionsPanel";
2
- import { DiffTheme } from "../themes/diffThemes";
3
- interface ThemedSplitViewProps {
4
- oldValue: unknown;
5
- newValue: unknown;
6
- differences: unknown[];
7
- theme: DiffTheme;
8
- options?: DiffOptions;
9
- showThemeName?: boolean;
10
- /**
11
- * Scroll the rows inside their own fixed-height pane (default). Set false to
12
- * render every row inline at natural height and let an ancestor ScrollView
13
- * move them — one page-level scroll instead of a nested scroll region.
14
- */
15
- scrollEnabled?: boolean;
16
- }
17
- export declare function ThemedSplitView({ oldValue, newValue, theme, options, showThemeName, scrollEnabled, }: ThemedSplitViewProps): import("react").JSX.Element;
18
- export {};
1
+ /**
2
+ * Re-export shim — ThemedSplitView now lives in @buoy-gg/shared-ui/dataViewer
3
+ * (promoted so redux/zustand/jotai/time-machine share one copy; this used to
4
+ * be the only fork with folding + virtualization, and fixes had to be made
5
+ * twice). Keep importing from here inside the storage package.
6
+ */
7
+ export { ThemedSplitView, type DiffOptions, type DiffCompareMethod, } from "@buoy-gg/shared-ui/dataViewer";
19
8
  //# sourceMappingURL=ThemedSplitView.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ThemedSplitView.d.ts","sourceRoot":"","sources":["../../../../../../src/storage/components/DiffViewer/modes/ThemedSplitView.tsx"],"names":[],"mappings":"AAyBA,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEjD,UAAU,oBAAoB;IAC5B,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,EAAE,OAAO,EAAE,CAAC;IACvB,KAAK,EAAE,SAAS,CAAC;IACjB,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAaD,wBAAgB,eAAe,CAAC,EAC9B,QAAQ,EACR,QAAQ,EACR,KAAK,EACL,OAAyB,EACzB,aAAqB,EACrB,aAAoB,GACrB,EAAE,oBAAoB,+BAmMtB"}
1
+ {"version":3,"file":"ThemedSplitView.d.ts","sourceRoot":"","sources":["../../../../../../src/storage/components/DiffViewer/modes/ThemedSplitView.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EACL,eAAe,EACf,KAAK,WAAW,EAChB,KAAK,iBAAiB,GACvB,MAAM,+BAA+B,CAAC"}
@@ -1,4 +1,5 @@
1
1
  import { RequiredStorageKey } from "../types";
2
+ import { type StorageEvent } from "../hooks/useStorageEvents";
2
3
  export declare const FREE_TIER_EVENT_LIMIT = 25;
3
4
  interface StorageModalWithTabsProps {
4
5
  visible: boolean;
@@ -27,8 +28,14 @@ interface StorageModalWithTabsProps {
27
28
  * pull is the only way to refresh a backend that has not pushed.
28
29
  */
29
30
  onRefresh?: () => void;
31
+ /**
32
+ * Fired when the user opens an event's detail view (and its neighbor, for
33
+ * the diff). Remote mirrors (Buoy Desktop) use this to fetch oversized
34
+ * values on demand — wire-form snapshots omit payloads over 16KB.
35
+ */
36
+ onEventSelect?: (event: StorageEvent) => void;
30
37
  }
31
- export declare function StorageModalWithTabs({ visible, onClose, onBack, onMinimize, enableSharedModalDimensions, requiredStorageKeys, inline, onTabChange, onRefresh, }: StorageModalWithTabsProps): import("react").JSX.Element | null;
38
+ export declare function StorageModalWithTabs({ visible, onClose, onBack, onMinimize, enableSharedModalDimensions, requiredStorageKeys, inline, onTabChange, onRefresh, onEventSelect, }: StorageModalWithTabsProps): import("react").JSX.Element | null;
32
39
  /**
33
40
  * The same storage tool as `StorageModalWithTabs`, rendered INLINE for hosts
34
41
  * that place tools in a panel rather than a modal. Exists so there is exactly
@@ -1 +1 @@
1
- {"version":3,"file":"StorageModalWithTabs.d.ts","sourceRoot":"","sources":["../../../../src/storage/components/StorageModalWithTabs.tsx"],"names":[],"mappings":"AA6BA,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AA2B9C,eAAO,MAAM,qBAAqB,KAAK,CAAC;AAExC,UAAU,yBAAyB;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,UAAU,CAAC,EAAE,CAAC,UAAU,EAAE,GAAG,KAAK,IAAI,CAAC;IACvC,2BAA2B,CAAC,EAAE,OAAO,CAAC;IACtC,mBAAmB,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAC3C;;;;;OAKG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;;OAIG;IACH,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,SAAS,GAAG,QAAQ,KAAK,IAAI,CAAC;IAClD;;;;;OAKG;IACH,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;CACxB;AAqBD,wBAAgB,oBAAoB,CAAC,EACnC,OAAO,EACP,OAAO,EACP,MAAM,EACN,UAAU,EACV,2BAAmC,EACnC,mBAAwB,EACxB,MAAc,EACd,WAAW,EACX,SAAS,GACV,EAAE,yBAAyB,sCAu9B3B;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,KAAK,GAAE,IAAI,CAAC,yBAAyB,EAAE,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAM,+BAG9E"}
1
+ {"version":3,"file":"StorageModalWithTabs.d.ts","sourceRoot":"","sources":["../../../../src/storage/components/StorageModalWithTabs.tsx"],"names":[],"mappings":"AA6BA,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAY9C,OAAO,EAAoB,KAAK,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAehF,eAAO,MAAM,qBAAqB,KAAK,CAAC;AAExC,UAAU,yBAAyB;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,UAAU,CAAC,EAAE,CAAC,UAAU,EAAE,GAAG,KAAK,IAAI,CAAC;IACvC,2BAA2B,CAAC,EAAE,OAAO,CAAC;IACtC,mBAAmB,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAC3C;;;;;OAKG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;;OAIG;IACH,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,SAAS,GAAG,QAAQ,KAAK,IAAI,CAAC;IAClD;;;;;OAKG;IACH,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB;;;;OAIG;IACH,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;CAC/C;AAqBD,wBAAgB,oBAAoB,CAAC,EACnC,OAAO,EACP,OAAO,EACP,MAAM,EACN,UAAU,EACV,2BAAmC,EACnC,mBAAwB,EACxB,MAAc,EACd,WAAW,EACX,SAAS,EACT,aAAa,GACd,EAAE,yBAAyB,sCAo/B3B;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,KAAK,GAAE,IAAI,CAAC,yBAAyB,EAAE,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAM,+BAG9E"}
@@ -1 +1 @@
1
- {"version":3,"file":"useAsyncStorageKeys.d.ts","sourceRoot":"","sources":["../../../../src/storage/hooks/useAsyncStorageKeys.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAE9D,UAAU,yBAAyB;IACjC,WAAW,EAAE,cAAc,EAAE,CAAC;IAC9B,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B;AAED,wBAAgB,mBAAmB,CACjC,mBAAmB,GAAE,kBAAkB,EAAO,GAC7C,yBAAyB,CA2J3B"}
1
+ {"version":3,"file":"useAsyncStorageKeys.d.ts","sourceRoot":"","sources":["../../../../src/storage/hooks/useAsyncStorageKeys.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAG9D,UAAU,yBAAyB;IACjC,WAAW,EAAE,cAAc,EAAE,CAAC;IAC9B,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B;AAED,wBAAgB,mBAAmB,CACjC,mBAAmB,GAAE,kBAAkB,EAAO,GAC7C,yBAAyB,CA6J3B"}
@@ -1 +1 @@
1
- {"version":3,"file":"useMMKVKeys.d.ts","sourceRoot":"","sources":["../../../../src/storage/hooks/useMMKVKeys.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAO9D,KAAK,IAAI,GAAG,GAAG,CAAC;AAEhB,UAAU,iBAAiB;IACzB,WAAW,EAAE,cAAc,EAAE,CAAC;IAC9B,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,wBAAgB,WAAW,CACzB,QAAQ,EAAE,IAAI,GAAG,IAAI,GAAG,SAAS,EACjC,UAAU,EAAE,MAAM,EAClB,mBAAmB,GAAE,kBAAkB,EAAO,GAC7C,iBAAiB,CA8LnB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,KAAK,CAAC;IAAE,QAAQ,EAAE,IAAI,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC,EAChD,mBAAmB,GAAE,kBAAkB,EAAO,GAC7C,iBAAiB,CAkJnB"}
1
+ {"version":3,"file":"useMMKVKeys.d.ts","sourceRoot":"","sources":["../../../../src/storage/hooks/useMMKVKeys.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAQ9D,KAAK,IAAI,GAAG,GAAG,CAAC;AAEhB,UAAU,iBAAiB;IACzB,WAAW,EAAE,cAAc,EAAE,CAAC;IAC9B,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,wBAAgB,WAAW,CACzB,QAAQ,EAAE,IAAI,GAAG,IAAI,GAAG,SAAS,EACjC,UAAU,EAAE,MAAM,EAClB,mBAAmB,GAAE,kBAAkB,EAAO,GAC7C,iBAAiB,CA4LnB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,KAAK,CAAC;IAAE,QAAQ,EAAE,IAAI,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC,EAChD,mBAAmB,GAAE,kBAAkB,EAAO,GAC7C,iBAAiB,CAoJnB"}
@@ -35,6 +35,20 @@ export type StorageEvent = (AsyncStorageEvent & {
35
35
  storageType: "mmkv";
36
36
  id: string;
37
37
  });
38
+ /** True when a field is the wire-form VALUE_ON_DEVICE marker. */
39
+ export declare function isValueOnDevice(value: unknown): boolean;
40
+ /**
41
+ * `pairs` / `prevPairs` are AsyncStorage-only — they carry the batch
42
+ * operations (multiSet / multiRemove / multiMerge / clear), and MMKV has no
43
+ * batch API, so its `data` has no such fields. Reading them off the
44
+ * `StorageEvent` union needs narrowing, and this is the one place that does
45
+ * it; writing them unconditionally would also graft meaningless keys onto
46
+ * every MMKV event on the wire.
47
+ */
48
+ export declare function batchPairsOf(event: StorageEvent): {
49
+ pairs?: unknown;
50
+ prevPairs?: unknown;
51
+ };
38
52
  /**
39
53
  * Listener callback type for storage events array
40
54
  */
@@ -71,6 +85,18 @@ declare class StorageEventStore extends BaseEventStore<StorageEvent> {
71
85
  * Get events filtered by storage type
72
86
  */
73
87
  getEventsByType(storageType: "async" | "mmkv"): StorageEvent[];
88
+ /**
89
+ * Replace the event list, keeping values a remote mirror already hydrated.
90
+ * Wire-form snapshots always carry VALUE_ON_DEVICE markers for oversized
91
+ * payloads; a later snapshot must not blank the detail pane (or wipe
92
+ * `prevValue` that time-travel undo needs).
93
+ */
94
+ replaceEvents(events: StorageEvent[]): void;
95
+ /**
96
+ * Hydrate one mirrored event with real values fetched on demand from the
97
+ * device via the adapter's `getEventDetail`. Remote-mirror (desktop) only.
98
+ */
99
+ hydrateEvent(event: StorageEvent): void;
74
100
  }
75
101
  export declare const storageEventStore: StorageEventStore;
76
102
  export declare const subscribeToStorageEvents: (listener: StorageEventListener) => () => void;
@@ -1 +1 @@
1
- {"version":3,"file":"storageEventStore.d.ts","sourceRoot":"","sources":["../../../../src/storage/stores/storageEventStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAIL,KAAK,iBAAiB,EACvB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAEL,KAAK,SAAS,EACf,MAAM,uBAAuB,CAAC;AAI/B;;;;;GAKG;AACH,MAAM,MAAM,YAAY,GACpB,CAAC,iBAAiB,GAAG;IAAE,WAAW,EAAE,OAAO,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC,GAC1D,CAAC,SAAS,GAAG;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAOtD;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,MAAM,EAAE,YAAY,EAAE,KAAK,IAAI,CAAC;AAEpE;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;AAEjE,cAAM,iBAAkB,SAAQ,cAAc,CAAC,YAAY,CAAC;IAE1D,OAAO,CAAC,uBAAuB,CAA6B;IAC5D,OAAO,CAAC,eAAe,CAA6B;IACpD,OAAO,CAAC,sBAAsB,CAAS;;IASvC;;;;;OAKG;YACW,iBAAiB;IA0D/B;;OAEG;cACa,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAoC/C;;OAEG;IACH,SAAS,CAAC,aAAa,IAAI,IAAI;IAc/B;;OAEG;IACH,WAAW,IAAI,OAAO;IAItB;;OAEG;IACH,eAAe,CAAC,WAAW,EAAE,OAAO,GAAG,MAAM,GAAG,YAAY,EAAE;CAG/D;AAGD,eAAO,MAAM,iBAAiB,mBAA0B,CAAC;AAGzD,eAAO,MAAM,wBAAwB,GAAI,UAAU,oBAAoB,eACxB,CAAC;AAChD,eAAO,MAAM,cAAc,GAAI,UAAU,oBAAoB,eACxB,CAAC;AACtC,eAAO,MAAM,gBAAgB,sBAAsC,CAAC;AACpE,eAAO,MAAM,kBAAkB,YAAwC,CAAC;AACxE,eAAO,MAAM,kBAAkB,eAAwC,CAAC"}
1
+ {"version":3,"file":"storageEventStore.d.ts","sourceRoot":"","sources":["../../../../src/storage/stores/storageEventStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAIL,KAAK,iBAAiB,EACvB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAEL,KAAK,SAAS,EACf,MAAM,uBAAuB,CAAC;AAI/B;;;;;GAKG;AACH,MAAM,MAAM,YAAY,GACpB,CAAC,iBAAiB,GAAG;IAAE,WAAW,EAAE,OAAO,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC,GAC1D,CAAC,SAAS,GAAG;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAEtD,iEAAiE;AACjE,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAMvD;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,YAAY,GAAG;IACjD,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB,CAGA;AAmBD;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,MAAM,EAAE,YAAY,EAAE,KAAK,IAAI,CAAC;AAEpE;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;AAEjE,cAAM,iBAAkB,SAAQ,cAAc,CAAC,YAAY,CAAC;IAE1D,OAAO,CAAC,uBAAuB,CAA6B;IAC5D,OAAO,CAAC,eAAe,CAA6B;IACpD,OAAO,CAAC,sBAAsB,CAAS;;IASvC;;;;;OAKG;YACW,iBAAiB;IA0D/B;;OAEG;cACa,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAoC/C;;OAEG;IACH,SAAS,CAAC,aAAa,IAAI,IAAI;IAc/B;;OAEG;IACH,WAAW,IAAI,OAAO;IAItB;;OAEG;IACH,eAAe,CAAC,WAAW,EAAE,OAAO,GAAG,MAAM,GAAG,YAAY,EAAE;IAI9D;;;;;OAKG;IACH,aAAa,CAAC,MAAM,EAAE,YAAY,EAAE,GAAG,IAAI;IAyB3C;;;OAGG;IACH,YAAY,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI;CAaxC;AAGD,eAAO,MAAM,iBAAiB,mBAA0B,CAAC;AAGzD,eAAO,MAAM,wBAAwB,GAAI,UAAU,oBAAoB,eACxB,CAAC;AAChD,eAAO,MAAM,cAAc,GAAI,UAAU,oBAAoB,eACxB,CAAC;AACtC,eAAO,MAAM,gBAAgB,sBAAsC,CAAC;AACpE,eAAO,MAAM,kBAAkB,YAAwC,CAAC;AACxE,eAAO,MAAM,kBAAkB,eAAwC,CAAC"}
@@ -1,6 +1,29 @@
1
+ import { type StorageEvent } from "../stores/storageEventStore";
2
+ /**
3
+ * Sentinel used in WIRE-FORM snapshots in place of oversized values.
4
+ * Storage events, MMKV browse dumps, and SecureStore dumps all reuse this
5
+ * marker. Dashboards fetch the real payload via `getEventDetail` / `mmkv.get`
6
+ * / `secure.get`.
7
+ */
8
+ export declare const VALUE_ON_DEVICE: Readonly<{
9
+ __buoyValueOnDevice: true;
10
+ note: "Value stays on the device — fetched on demand via getEventDetail / mmkv.get / secure.get.";
11
+ }>;
12
+ /** Max serialized bytes of one storage value on the list snapshot. */
13
+ export declare const SNAPSHOT_VALUE_INLINE_LIMIT: number;
14
+ /**
15
+ * Total inline budget for one snapshot's event list, held under the emit
16
+ * layer's 2MB so a snapshot is never DROPPED (a drop leaves the whole panel
17
+ * stale). Per-value caps alone don't get there: the store keeps 500 events, so
18
+ * 500 writes of an individually-legal 9KB value still total ~4.7MB. Newest
19
+ * events keep their values inline; once the budget is spent, older ones
20
+ * degrade to metadata + fetch-on-demand.
21
+ */
22
+ export declare const SNAPSHOT_EVENTS_BUDGET: number;
1
23
  /** One MMKV entry in a `mmkv.snapshot` result. */
2
24
  export interface MMKVSnapshotEntry {
3
25
  key: string;
26
+ /** Oversized values are replaced with VALUE_ON_DEVICE on the wire. */
4
27
  value: unknown;
5
28
  valueType: string;
6
29
  }
@@ -17,8 +40,11 @@ export interface SecureSnapshotEntry {
17
40
  description?: string;
18
41
  keychainService?: string;
19
42
  requireAuthentication: boolean;
20
- /** `null` when unset, or when the key is biometric-protected (never read). */
21
- value: string | null;
43
+ /**
44
+ * `null` when unset, or when the key is biometric-protected (never read).
45
+ * Oversized values are replaced with VALUE_ON_DEVICE on the wire.
46
+ */
47
+ value: unknown;
22
48
  }
23
49
  /**
24
50
  * Sync adapter for the storage tool, consumed by @buoy-gg/external-sync's
@@ -31,17 +57,37 @@ export interface SecureSnapshotEntry {
31
57
  *
32
58
  * The `async.*` actions mirror the AsyncStorage API so the desktop dashboard
33
59
  * can proxy its browse/edit mode against the device's real storage.
60
+ *
61
+ * v2: oversized / unserializable event values are replaced with
62
+ * VALUE_ON_DEVICE. Dashboards fetch them via `getEventDetail`.
34
63
  */
35
64
  export declare const storageSyncAdapter: {
36
65
  version: number;
37
- getSnapshot: () => import("../..").StorageEvent[];
66
+ getSnapshot: () => StorageEvent[];
38
67
  subscribe: (onChange: () => void) => () => void;
39
68
  actions: {
40
69
  clearEvents: () => void;
70
+ /**
71
+ * On-demand detail: one event's real value/prevValue/pairs.
72
+ * The per-snapshot stream stays payload-light; this is the explicit,
73
+ * size-guarded channel for the detail pane (and for time-travel undo,
74
+ * which needs `prevValue`).
75
+ */
76
+ getEventDetail: (params?: unknown) => {
77
+ found: false;
78
+ reason: string;
79
+ id?: undefined;
80
+ event?: undefined;
81
+ } | {
82
+ found: true;
83
+ id: string;
84
+ event: StorageEvent;
85
+ reason?: undefined;
86
+ };
41
87
  /** Clears all app storage keys, preserving dev tools settings. */
42
88
  clearAppStorage: () => Promise<void>;
43
89
  /** Undo one event, addressed by the `id` the store assigned it. */
44
- "timeTravel.undo": (params: unknown) => Promise<{
90
+ "timeTravel.undo": (params?: unknown) => Promise<{
45
91
  undone: boolean;
46
92
  action: "mergeItem" | "multiSet" | "multiRemove" | "clear" | "setItem" | "removeItem" | "multiMerge";
47
93
  key: string | undefined;
@@ -60,15 +106,35 @@ export declare const storageSyncAdapter: {
60
106
  }>;
61
107
  "async.getAllKeys": () => Promise<string[]>;
62
108
  "async.multiGet": (params: unknown) => Promise<[string, string | null][]>;
63
- "async.getItem": (params: unknown) => Promise<string | null>;
64
- "async.setItem": (params: unknown) => Promise<void>;
65
- "async.removeItem": (params: unknown) => Promise<void>;
66
- "async.multiRemove": (params: unknown) => Promise<void>;
67
- "async.multiSet": (params: unknown) => Promise<void>;
109
+ "async.getItem": (params?: unknown) => Promise<string | null>;
110
+ "async.setItem": (params?: unknown) => Promise<void>;
111
+ "async.removeItem": (params?: unknown) => Promise<void>;
112
+ "async.multiRemove": (params?: unknown) => Promise<void>;
113
+ "async.multiSet": (params?: unknown) => Promise<void>;
68
114
  "async.clear": () => Promise<void>;
69
115
  "mmkv.snapshot": () => MMKVSnapshotInstance[];
70
- "mmkv.set": (params: unknown) => void;
71
- "mmkv.remove": (params: unknown) => void;
116
+ /**
117
+ * On-demand MMKV value. `mmkv.snapshot` omits oversized strings so a
118
+ * browse poll cannot blow the action-result budget; this is the
119
+ * size-guarded channel for one key.
120
+ */
121
+ "mmkv.get": (params?: unknown) => {
122
+ found: false;
123
+ reason: string;
124
+ instanceId?: undefined;
125
+ key?: undefined;
126
+ value?: undefined;
127
+ valueType?: undefined;
128
+ } | {
129
+ found: true;
130
+ instanceId: string;
131
+ key: string;
132
+ value: unknown;
133
+ valueType: import("../..").MMKVValueType;
134
+ reason?: undefined;
135
+ };
136
+ "mmkv.set": (params?: unknown) => void;
137
+ "mmkv.remove": (params?: unknown) => void;
72
138
  "secure.keys": () => {
73
139
  key: string;
74
140
  description: string | undefined;
@@ -82,15 +148,15 @@ export declare const storageSyncAdapter: {
82
148
  * firing one `secure.get` per key per refresh.
83
149
  */
84
150
  "secure.snapshot": () => Promise<SecureSnapshotEntry[]>;
85
- "secure.get": (params: unknown) => Promise<string | null>;
151
+ "secure.get": (params?: unknown) => Promise<string | null>;
86
152
  /**
87
153
  * Write a registered SecureStore key. Goes through the registry so the
88
154
  * value is written with the SAME options it was registered with — writing
89
155
  * with different `keychainService` options creates a second entry the app
90
156
  * can't read. Biometric-protected keys throw rather than prompting.
91
157
  */
92
- "secure.set": (params: unknown) => Promise<void>;
93
- "secure.delete": (params: unknown) => Promise<void>;
158
+ "secure.set": (params?: unknown) => Promise<void>;
159
+ "secure.delete": (params?: unknown) => Promise<void>;
94
160
  };
95
161
  };
96
162
  //# sourceMappingURL=storageSyncAdapter.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"storageSyncAdapter.d.ts","sourceRoot":"","sources":["../../../../src/storage/sync/storageSyncAdapter.ts"],"names":[],"mappings":"AAsCA,kDAAkD;AAClD,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,OAAO,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,qDAAqD;AACrD,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,iBAAiB,EAAE,CAAC;CAC9B;AAED,wDAAwD;AACxD,MAAM,WAAW,mBAAmB;IAClC,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,qBAAqB,EAAE,OAAO,CAAC;IAC/B,8EAA8E;IAC9E,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAsBD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,kBAAkB;;;0BAaP,MAAM,IAAI;;;QAM9B,kEAAkE;;QAOlE,mEAAmE;oCACjC,OAAO;;;;;QAkBzC;;;;WAIG;oCAC+B,OAAO;;;;;;;;mCAyCR,OAAO;kCAId,OAAO;kCAMP,OAAO;qCAIJ,OAAO;sCAEN,OAAO;mCAEV,OAAO;;+BAOb,oBAAoB,EAAE;6BAgBtB,OAAO;gCAIJ,OAAO;;;;;;;QAkB/B;;;;;WAKG;iCAC0B,OAAO,CAAC,mBAAmB,EAAE,CAAC;+BAwBpC,OAAO;QAW9B;;;;;WAKG;+BACoB,OAAO;kCAIJ,OAAO;;CAGpC,CAAC"}
1
+ {"version":3,"file":"storageSyncAdapter.d.ts","sourceRoot":"","sources":["../../../../src/storage/sync/storageSyncAdapter.ts"],"names":[],"mappings":"AAQA,OAAO,EAGL,KAAK,YAAY,EAClB,MAAM,6BAA6B,CAAC;AAYrC;;;;;GAKG;AACH,eAAO,MAAM,eAAe;;;EAG1B,CAAC;AAEH,sEAAsE;AACtE,eAAO,MAAM,2BAA2B,QAAY,CAAC;AAErD;;;;;;;GAOG;AACH,eAAO,MAAM,sBAAsB,QAAqB,CAAC;AA4JzD,kDAAkD;AAClD,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,sEAAsE;IACtE,KAAK,EAAE,OAAO,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,qDAAqD;AACrD,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,iBAAiB,EAAE,CAAC;CAC9B;AAED,wDAAwD;AACxD,MAAM,WAAW,mBAAmB;IAClC,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,qBAAqB,EAAE,OAAO,CAAC;IAC/B;;;OAGG;IACH,KAAK,EAAE,OAAO,CAAC;CAChB;AAsBD;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,kBAAkB;;;0BAeP,MAAM,IAAI;;;QAM9B;;;;;WAKG;kCACuB,OAAO;;;;;;;;;;;QAUjC,kEAAkE;;QAOlE,mEAAmE;qCAChC,OAAO;;;;;QAkB1C;;;;WAIG;oCAC+B,OAAO;;;;;;;;mCAyCR,OAAO;mCAIb,OAAO;mCAMP,OAAO;sCAIJ,OAAO;uCAEN,OAAO;oCAEV,OAAO;;+BAOd,oBAAoB,EAAE;QAgB3C;;;;WAIG;8BACmB,OAAO;;;;;;;;;;;;;;;8BAkBP,OAAO;iCAIJ,OAAO;;;;;;;QAkBhC;;;;;WAKG;iCAC0B,OAAO,CAAC,mBAAmB,EAAE,CAAC;gCAwBnC,OAAO;QAW/B;;;;;WAKG;gCACqB,OAAO;mCAIJ,OAAO;;CAGrC,CAAC"}
@@ -12,17 +12,17 @@ export interface StorageKeyInfo {
12
12
  category: "required" | "optional";
13
13
  lastUpdated?: Date;
14
14
  }
15
+ /**
16
+ * A required key the browser validates. `storageType` scopes the check to one
17
+ * backend — without it, every backend's hook historically synthesized its own
18
+ * Missing row for the same key (Async + MMKV both counting it). Prefer always
19
+ * setting `storageType` when more than one backend is registered.
20
+ */
15
21
  export type RequiredStorageKey = string | {
16
22
  key: string;
17
- expectedValue: string;
18
- description?: string;
19
- } | {
20
- key: string;
21
- expectedType: string;
22
- description?: string;
23
- } | {
24
- key: string;
25
- storageType: StorageType;
23
+ expectedValue?: string;
24
+ expectedType?: string;
25
+ storageType?: StorageType;
26
26
  description?: string;
27
27
  };
28
28
  export interface StorageKeyStats {
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/storage/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAExD,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,OAAO,CAAC;IACf,SAAS,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,CAAC;IACvD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,WAAW,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EACF,kBAAkB,GAClB,kBAAkB,GAClB,sBAAsB,GACtB,qBAAqB,GACrB,kBAAkB,CAAC;IACvB,QAAQ,EAAE,UAAU,GAAG,UAAU,CAAC;IAClC,WAAW,CAAC,EAAE,IAAI,CAAC;CACpB;AAED,MAAM,MAAM,kBAAkB,GAC1B,MAAM,GACN;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,GAC5D;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,GAC3D;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,WAAW,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEpE,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,aAAa,EAAE,MAAM,CAAC;IAEtB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IAEpB,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACzC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/storage/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAExD,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,OAAO,CAAC;IACf,SAAS,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,CAAC;IACvD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,WAAW,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EACF,kBAAkB,GAClB,kBAAkB,GAClB,sBAAsB,GACtB,qBAAqB,GACrB,kBAAkB,CAAC;IACvB,QAAQ,EAAE,UAAU,GAAG,UAAU,CAAC;IAClC,WAAW,CAAC,EAAE,IAAI,CAAC;CACpB;AAED;;;;;GAKG;AACH,MAAM,MAAM,kBAAkB,GAC1B,MAAM,GACN;IACE,GAAG,EAAE,MAAM,CAAC;IACZ,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEN,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,aAAa,EAAE,MAAM,CAAC;IAEtB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IAEpB,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACzC"}