@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.
Files changed (180) hide show
  1. package/README.md +11 -90
  2. package/lib/commonjs/index.js +1 -353
  3. package/lib/commonjs/preset.js +1 -85
  4. package/lib/commonjs/storage/components/DiffViewer/TreeDiffViewer.js +1 -36
  5. package/lib/commonjs/storage/components/DiffViewer/modes/ThemedSplitView.js +1 -12
  6. package/lib/commonjs/storage/components/DiffViewer/themes/diffThemes.js +1 -24
  7. package/lib/commonjs/storage/components/GameUIStorageBrowser.js +3 -1259
  8. package/lib/commonjs/storage/components/MMKVInstanceInfoPanel.js +1 -257
  9. package/lib/commonjs/storage/components/MMKVInstanceSelector.js +1 -419
  10. package/lib/commonjs/storage/components/SelectionActionBar.js +1 -207
  11. package/lib/commonjs/storage/components/StorageActionButtons.js +1 -242
  12. package/lib/commonjs/storage/components/StorageBrowserMode.js +1 -61
  13. package/lib/commonjs/storage/components/StorageEventActionButton.js +1 -121
  14. package/lib/commonjs/storage/components/StorageEventCard.js +1 -118
  15. package/lib/commonjs/storage/components/StorageEventDetailContent.js +1 -494
  16. package/lib/commonjs/storage/components/StorageEventFilterView.js +1 -160
  17. package/lib/commonjs/storage/components/StorageEventsSection.js +1 -24
  18. package/lib/commonjs/storage/components/StorageFilterCards.js +1 -231
  19. package/lib/commonjs/storage/components/StorageKeyCard.js +1 -520
  20. package/lib/commonjs/storage/components/StorageKeyDetailScreen.js +1 -579
  21. package/lib/commonjs/storage/components/StorageKeyRow.js +1 -559
  22. package/lib/commonjs/storage/components/StorageKeySection.js +1 -160
  23. package/lib/commonjs/storage/components/StorageKeyStats.js +1 -345
  24. package/lib/commonjs/storage/components/StorageModalWithTabs.js +1 -954
  25. package/lib/commonjs/storage/components/StorageSaveNotice.js +1 -171
  26. package/lib/commonjs/storage/components/StorageSection.js +1 -43
  27. package/lib/commonjs/storage/components/StorageTypeFilterBar.js +1 -144
  28. package/lib/commonjs/storage/hooks/useAsyncStorageKeys.js +1 -141
  29. package/lib/commonjs/storage/hooks/useMMKVInstances.js +1 -210
  30. package/lib/commonjs/storage/hooks/useMMKVKeys.js +1 -376
  31. package/lib/commonjs/storage/hooks/useSecureStoreKeys.js +1 -202
  32. package/lib/commonjs/storage/hooks/useStorageEvents.js +1 -61
  33. package/lib/commonjs/storage/stores/storageEventStore.js +1 -312
  34. package/lib/commonjs/storage/sync/storageSyncAdapter.js +1 -492
  35. package/lib/commonjs/storage/types.js +1 -5
  36. package/lib/commonjs/storage/utils/AsyncStorageListener.js +1 -691
  37. package/lib/commonjs/storage/utils/AsyncStorageListener.web.js +1 -89
  38. package/lib/commonjs/storage/utils/MMKVInstanceRegistry.js +1 -203
  39. package/lib/commonjs/storage/utils/MMKVListener.js +1 -416
  40. package/lib/commonjs/storage/utils/SecureStoreRegistry.js +1 -200
  41. package/lib/commonjs/storage/utils/asyncStorageCompat.js +1 -89
  42. package/lib/commonjs/storage/utils/browserStorageLifecycle.js +1 -10
  43. package/lib/commonjs/storage/utils/browserStorageLifecycle.web.js +1 -70
  44. package/lib/commonjs/storage/utils/clearAllStorage.js +1 -48
  45. package/lib/commonjs/storage/utils/deleteStorageKeys.js +1 -82
  46. package/lib/commonjs/storage/utils/lineDiff.js +1 -30
  47. package/lib/commonjs/storage/utils/mmkvAvailability.js +1 -62
  48. package/lib/commonjs/storage/utils/mmkvAvailability.web.js +1 -21
  49. package/lib/commonjs/storage/utils/mmkvTypeDetection.js +1 -154
  50. package/lib/commonjs/storage/utils/requiredStorageKeyScope.js +1 -17
  51. package/lib/commonjs/storage/utils/setStorageValue.js +1 -218
  52. package/lib/commonjs/storage/utils/snapshotProvider.js +1 -382
  53. package/lib/commonjs/storage/utils/storageActionHelpers.js +1 -46
  54. package/lib/commonjs/storage/utils/storageBrowserRefresh.js +1 -49
  55. package/lib/commonjs/storage/utils/storageLabels.js +1 -13
  56. package/lib/commonjs/storage/utils/storageLabels.web.js +1 -13
  57. package/lib/commonjs/storage/utils/storageOps.js +1 -53
  58. package/lib/commonjs/storage/utils/storageQueryUtils.js +1 -35
  59. package/lib/commonjs/storage/utils/storageTimeTravelUtils.js +1 -288
  60. package/lib/commonjs/storage/utils/valueType.js +1 -83
  61. package/lib/module/index.js +1 -114
  62. package/lib/module/preset.js +1 -82
  63. package/lib/module/storage/components/DiffViewer/TreeDiffViewer.js +1 -32
  64. package/lib/module/storage/components/DiffViewer/modes/ThemedSplitView.js +1 -9
  65. package/lib/module/storage/components/DiffViewer/themes/diffThemes.js +1 -10
  66. package/lib/module/storage/components/GameUIStorageBrowser.js +3 -1257
  67. package/lib/module/storage/components/MMKVInstanceInfoPanel.js +1 -253
  68. package/lib/module/storage/components/MMKVInstanceSelector.js +1 -415
  69. package/lib/module/storage/components/SelectionActionBar.js +1 -204
  70. package/lib/module/storage/components/StorageActionButtons.js +1 -238
  71. package/lib/module/storage/components/StorageBrowserMode.js +1 -57
  72. package/lib/module/storage/components/StorageEventActionButton.js +1 -118
  73. package/lib/module/storage/components/StorageEventCard.js +1 -113
  74. package/lib/module/storage/components/StorageEventDetailContent.js +1 -490
  75. package/lib/module/storage/components/StorageEventFilterView.js +1 -156
  76. package/lib/module/storage/components/StorageEventsSection.js +1 -20
  77. package/lib/module/storage/components/StorageFilterCards.js +1 -227
  78. package/lib/module/storage/components/StorageKeyCard.js +1 -517
  79. package/lib/module/storage/components/StorageKeyDetailScreen.js +1 -577
  80. package/lib/module/storage/components/StorageKeyRow.js +1 -554
  81. package/lib/module/storage/components/StorageKeySection.js +1 -155
  82. package/lib/module/storage/components/StorageKeyStats.js +1 -342
  83. package/lib/module/storage/components/StorageModalWithTabs.js +1 -949
  84. package/lib/module/storage/components/StorageSaveNotice.js +1 -168
  85. package/lib/module/storage/components/StorageSection.js +1 -40
  86. package/lib/module/storage/components/StorageTypeFilterBar.js +1 -139
  87. package/lib/module/storage/hooks/useAsyncStorageKeys.js +1 -136
  88. package/lib/module/storage/hooks/useMMKVInstances.js +1 -204
  89. package/lib/module/storage/hooks/useMMKVKeys.js +1 -371
  90. package/lib/module/storage/hooks/useSecureStoreKeys.js +1 -199
  91. package/lib/module/storage/hooks/useStorageEvents.js +1 -58
  92. package/lib/module/storage/stores/storageEventStore.js +1 -301
  93. package/lib/module/storage/sync/storageSyncAdapter.js +1 -486
  94. package/lib/module/storage/types.js +1 -3
  95. package/lib/module/storage/utils/AsyncStorageListener.js +1 -679
  96. package/lib/module/storage/utils/AsyncStorageListener.web.js +1 -76
  97. package/lib/module/storage/utils/MMKVInstanceRegistry.js +1 -197
  98. package/lib/module/storage/utils/MMKVListener.js +1 -403
  99. package/lib/module/storage/utils/SecureStoreRegistry.js +1 -194
  100. package/lib/module/storage/utils/asyncStorageCompat.js +1 -81
  101. package/lib/module/storage/utils/browserStorageLifecycle.js +1 -6
  102. package/lib/module/storage/utils/browserStorageLifecycle.web.js +1 -66
  103. package/lib/module/storage/utils/clearAllStorage.js +1 -43
  104. package/lib/module/storage/utils/deleteStorageKeys.js +1 -78
  105. package/lib/module/storage/utils/lineDiff.js +1 -12
  106. package/lib/module/storage/utils/mmkvAvailability.js +1 -56
  107. package/lib/module/storage/utils/mmkvAvailability.web.js +1 -15
  108. package/lib/module/storage/utils/mmkvTypeDetection.js +1 -148
  109. package/lib/module/storage/utils/requiredStorageKeyScope.js +1 -13
  110. package/lib/module/storage/utils/setStorageValue.js +1 -209
  111. package/lib/module/storage/utils/snapshotProvider.js +1 -380
  112. package/lib/module/storage/utils/storageActionHelpers.js +1 -42
  113. package/lib/module/storage/utils/storageBrowserRefresh.js +1 -44
  114. package/lib/module/storage/utils/storageLabels.js +1 -9
  115. package/lib/module/storage/utils/storageLabels.web.js +1 -9
  116. package/lib/module/storage/utils/storageOps.js +1 -46
  117. package/lib/module/storage/utils/storageQueryUtils.js +1 -30
  118. package/lib/module/storage/utils/storageTimeTravelUtils.js +1 -281
  119. package/lib/module/storage/utils/valueType.js +1 -76
  120. package/lib/web/index.mjs +2 -3
  121. package/package.json +5 -5
  122. package/lib/typescript/index.d.ts.map +0 -1
  123. package/lib/typescript/preset.d.ts.map +0 -1
  124. package/lib/typescript/storage/components/DiffViewer/TreeDiffViewer.d.ts.map +0 -1
  125. package/lib/typescript/storage/components/DiffViewer/modes/ThemedSplitView.d.ts.map +0 -1
  126. package/lib/typescript/storage/components/DiffViewer/themes/diffThemes.d.ts.map +0 -1
  127. package/lib/typescript/storage/components/GameUIStorageBrowser.d.ts.map +0 -1
  128. package/lib/typescript/storage/components/MMKVInstanceInfoPanel.d.ts.map +0 -1
  129. package/lib/typescript/storage/components/MMKVInstanceSelector.d.ts.map +0 -1
  130. package/lib/typescript/storage/components/SelectionActionBar.d.ts.map +0 -1
  131. package/lib/typescript/storage/components/StorageActionButtons.d.ts.map +0 -1
  132. package/lib/typescript/storage/components/StorageBrowserMode.d.ts.map +0 -1
  133. package/lib/typescript/storage/components/StorageEventActionButton.d.ts.map +0 -1
  134. package/lib/typescript/storage/components/StorageEventCard.d.ts.map +0 -1
  135. package/lib/typescript/storage/components/StorageEventDetailContent.d.ts.map +0 -1
  136. package/lib/typescript/storage/components/StorageEventFilterView.d.ts.map +0 -1
  137. package/lib/typescript/storage/components/StorageEventsSection.d.ts.map +0 -1
  138. package/lib/typescript/storage/components/StorageFilterCards.d.ts.map +0 -1
  139. package/lib/typescript/storage/components/StorageKeyCard.d.ts.map +0 -1
  140. package/lib/typescript/storage/components/StorageKeyDetailScreen.d.ts.map +0 -1
  141. package/lib/typescript/storage/components/StorageKeyRow.d.ts.map +0 -1
  142. package/lib/typescript/storage/components/StorageKeySection.d.ts.map +0 -1
  143. package/lib/typescript/storage/components/StorageKeyStats.d.ts.map +0 -1
  144. package/lib/typescript/storage/components/StorageModalWithTabs.d.ts.map +0 -1
  145. package/lib/typescript/storage/components/StorageSaveNotice.d.ts.map +0 -1
  146. package/lib/typescript/storage/components/StorageSection.d.ts.map +0 -1
  147. package/lib/typescript/storage/components/StorageTypeFilterBar.d.ts.map +0 -1
  148. package/lib/typescript/storage/hooks/useAsyncStorageKeys.d.ts.map +0 -1
  149. package/lib/typescript/storage/hooks/useMMKVInstances.d.ts.map +0 -1
  150. package/lib/typescript/storage/hooks/useMMKVKeys.d.ts.map +0 -1
  151. package/lib/typescript/storage/hooks/useSecureStoreKeys.d.ts.map +0 -1
  152. package/lib/typescript/storage/hooks/useStorageEvents.d.ts.map +0 -1
  153. package/lib/typescript/storage/stores/storageEventStore.d.ts.map +0 -1
  154. package/lib/typescript/storage/sync/storageSyncAdapter.d.ts.map +0 -1
  155. package/lib/typescript/storage/types.d.ts.map +0 -1
  156. package/lib/typescript/storage/utils/AsyncStorageListener.d.ts.map +0 -1
  157. package/lib/typescript/storage/utils/AsyncStorageListener.web.d.ts.map +0 -1
  158. package/lib/typescript/storage/utils/MMKVInstanceRegistry.d.ts.map +0 -1
  159. package/lib/typescript/storage/utils/MMKVListener.d.ts.map +0 -1
  160. package/lib/typescript/storage/utils/SecureStoreRegistry.d.ts.map +0 -1
  161. package/lib/typescript/storage/utils/asyncStorageCompat.d.ts.map +0 -1
  162. package/lib/typescript/storage/utils/browserStorageLifecycle.d.ts.map +0 -1
  163. package/lib/typescript/storage/utils/browserStorageLifecycle.web.d.ts.map +0 -1
  164. package/lib/typescript/storage/utils/clearAllStorage.d.ts.map +0 -1
  165. package/lib/typescript/storage/utils/deleteStorageKeys.d.ts.map +0 -1
  166. package/lib/typescript/storage/utils/lineDiff.d.ts.map +0 -1
  167. package/lib/typescript/storage/utils/mmkvAvailability.d.ts.map +0 -1
  168. package/lib/typescript/storage/utils/mmkvAvailability.web.d.ts.map +0 -1
  169. package/lib/typescript/storage/utils/mmkvTypeDetection.d.ts.map +0 -1
  170. package/lib/typescript/storage/utils/requiredStorageKeyScope.d.ts.map +0 -1
  171. package/lib/typescript/storage/utils/setStorageValue.d.ts.map +0 -1
  172. package/lib/typescript/storage/utils/snapshotProvider.d.ts.map +0 -1
  173. package/lib/typescript/storage/utils/storageActionHelpers.d.ts.map +0 -1
  174. package/lib/typescript/storage/utils/storageBrowserRefresh.d.ts.map +0 -1
  175. package/lib/typescript/storage/utils/storageLabels.d.ts.map +0 -1
  176. package/lib/typescript/storage/utils/storageLabels.web.d.ts.map +0 -1
  177. package/lib/typescript/storage/utils/storageOps.d.ts.map +0 -1
  178. package/lib/typescript/storage/utils/storageQueryUtils.d.ts.map +0 -1
  179. package/lib/typescript/storage/utils/storageTimeTravelUtils.d.ts.map +0 -1
  180. package/lib/typescript/storage/utils/valueType.d.ts.map +0 -1
@@ -1,202 +1 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.useSecureStoreKeys = useSecureStoreKeys;
7
- var _react = require("react");
8
- var _requiredStorageKeyScope = require("../utils/requiredStorageKeyScope");
9
- var _SecureStoreRegistry = require("../utils/SecureStoreRegistry");
10
- /**
11
- * Placeholder value shown for `requireAuthentication` keys. Reading those
12
- * triggers a biometric (Face ID / fingerprint) prompt, so the tool never
13
- * auto-reads them — it just shows they exist.
14
- */
15
- const BIOMETRIC_PLACEHOLDER = "•••••• (biometric protected)";
16
-
17
- /**
18
- * How often to re-read registered SecureStore values.
19
- *
20
- * SecureStore is the one backend with no change feed at all: AsyncStorage and
21
- * MMKV writes are intercepted (and MMKV has a native value-changed listener),
22
- * but the keychain gives no notification, so a value written by the app while
23
- * the tool is open would otherwise stay stale until the browser remounts.
24
- * Polling is the only option — kept cheap by re-reading a handful of registered
25
- * keys and only committing state when a value actually changed.
26
- */
27
- const DEFAULT_POLL_MS = 3000;
28
- /** Identity signature used to skip no-op state updates. */
29
- function signature(keys) {
30
- return JSON.stringify(keys);
31
- }
32
-
33
- /**
34
- * Read all registered SecureStore keys into StorageKeyInfo[] for the browser.
35
- *
36
- * SecureStore has no enumeration API, so this only surfaces keys declared via
37
- * `registerSecureStoreKeys()` (see SecureStoreRegistry). Values are read with
38
- * the options each key was registered with (keychainService must match), and
39
- * biometric-protected keys are listed without being read.
40
- *
41
- * Values are re-read on a poll and whenever the registry changes, so the
42
- * browser tracks writes the app makes while the tool is open.
43
- */
44
- function useSecureStoreKeys(requiredStorageKeys = [], options = {}) {
45
- const {
46
- pollMs = DEFAULT_POLL_MS
47
- } = options;
48
- // Read through a ref so a fresh array literal each render doesn't restart the poll.
49
- const requiredRef = (0, _react.useRef)(requiredStorageKeys);
50
- requiredRef.current = requiredStorageKeys;
51
- const requiredSignature = JSON.stringify(requiredStorageKeys);
52
- const [storageKeys, setStorageKeys] = (0, _react.useState)([]);
53
- const [isLoading, setIsLoading] = (0, _react.useState)(true);
54
- const [error, setError] = (0, _react.useState)(null);
55
-
56
- // Last committed content, so a poll that finds nothing new costs zero
57
- // renders (this hook feeds a non-virtualized list of every storage key).
58
- const signatureRef = (0, _react.useRef)(signature([]));
59
- const hasLoadedRef = (0, _react.useRef)(false);
60
- const inFlightRef = (0, _react.useRef)(false);
61
- const commit = (0, _react.useCallback)(keys => {
62
- const next = signature(keys);
63
- if (next === signatureRef.current) return;
64
- signatureRef.current = next;
65
- setStorageKeys(keys);
66
- }, []);
67
- const fetchSecureStoreData = (0, _react.useCallback)(async () => {
68
- // Reads are async and the poll is unconditional — never stack them.
69
- if (inFlightRef.current) return;
70
- inFlightRef.current = true;
71
- try {
72
- const module = _SecureStoreRegistry.secureStoreRegistry.getModule();
73
- const entries = _SecureStoreRegistry.secureStoreRegistry.getAll();
74
- // Required keys scoped to SecureStore. Registration is what lets the tool
75
- // read a key; `requiredStorageKeys` is what says the app needs it. A
76
- // registered key with no value that nobody requires is simply absent.
77
- const required = requiredRef.current.filter(req => (0, _requiredStorageKeyScope.requiredKeyAppliesTo)(req, "secure"));
78
- const requiredFor = key => required.find(req => (typeof req === "string" ? req : req.key) === key);
79
- if (!module || entries.length === 0 && required.length === 0) {
80
- commit([]);
81
- hasLoadedRef.current = true;
82
- setIsLoading(false);
83
- return;
84
- }
85
-
86
- // Only the first read is a "loading" state; polls refresh in place so the
87
- // browser never flashes its spinner over data it already has.
88
- if (!hasLoadedRef.current) setIsLoading(true);
89
- setError(null);
90
- const keys = [];
91
-
92
- // Required keys that were never registered are still readable by name,
93
- // with the default keychain options.
94
- const toRead = [...entries, ...required.map(req => typeof req === "string" ? req : req.key).filter(key => !entries.some(e => e.key === key)).map(key => ({
95
- key,
96
- options: {},
97
- description: undefined
98
- }))];
99
- for (const entry of toRead) {
100
- const req = requiredFor(entry.key);
101
- const reqObj = typeof req === "object" ? req : undefined;
102
- const expectations = {
103
- ...(reqObj?.expectedValue !== undefined && {
104
- expectedValue: reqObj.expectedValue
105
- }),
106
- ...(reqObj?.expectedType !== undefined && {
107
- expectedType: reqObj.expectedType
108
- })
109
- };
110
- const description = reqObj?.description ?? entry.description;
111
- if (entry.options.requireAuthentication) {
112
- // Never auto-read: reading would fire a biometric prompt.
113
- keys.push({
114
- key: entry.key,
115
- value: BIOMETRIC_PLACEHOLDER,
116
- storageType: "secure",
117
- status: req ? "required_present" : "optional_present",
118
- category: req ? "required" : "optional",
119
- description: description ?? "Protected by biometric authentication — value not read by DevTools",
120
- ...expectations,
121
- ...(entry.options.keychainService && {
122
- instanceId: entry.options.keychainService
123
- })
124
- });
125
- continue;
126
- }
127
- let rawValue = null;
128
- try {
129
- rawValue = await module.getItemAsync(entry.key, entry.options);
130
- } catch {
131
- // Key unreadable (e.g. keychain state changed) — treat as absent.
132
- }
133
- if (rawValue === null && !req) continue;
134
-
135
- // Parse JSON values for the DataViewer, same as the AsyncStorage hook.
136
- let parsedValue = rawValue;
137
- if (rawValue) {
138
- try {
139
- parsedValue = JSON.parse(rawValue);
140
- } catch {
141
- parsedValue = rawValue;
142
- }
143
- }
144
- let status = "optional_present";
145
- if (req) {
146
- if (rawValue === null) status = "required_missing";else if (reqObj?.expectedValue !== undefined) status = String(parsedValue) === String(reqObj.expectedValue) ? "required_present" : "required_wrong_value";else if (reqObj?.expectedType !== undefined) {
147
- const actualType = parsedValue === null ? "null" : Array.isArray(parsedValue) ? "array" : typeof parsedValue;
148
- // A keychain value is always stored as a string, so a string is
149
- // acceptable wherever the parsed form would be.
150
- const want = reqObj.expectedType.toLowerCase();
151
- status = actualType === want || want === "string" && typeof rawValue === "string" ? "required_present" : "required_wrong_type";
152
- } else status = "required_present";
153
- }
154
- keys.push({
155
- key: entry.key,
156
- value: rawValue === null ? undefined : parsedValue,
157
- storageType: "secure",
158
- status,
159
- category: req ? "required" : "optional",
160
- ...(description && {
161
- description
162
- }),
163
- ...expectations,
164
- ...(entry.options.keychainService && {
165
- instanceId: entry.options.keychainService
166
- })
167
- });
168
- }
169
- commit(keys);
170
- } catch (err) {
171
- setError(err instanceof Error ? err : new Error("Failed to read SecureStore"));
172
- commit([]);
173
- } finally {
174
- hasLoadedRef.current = true;
175
- inFlightRef.current = false;
176
- setIsLoading(false);
177
- }
178
- // eslint-disable-next-line react-hooks/exhaustive-deps
179
- }, [commit, requiredSignature]);
180
-
181
- // Initial fetch + poll. Registration usually happens at app startup, but the
182
- // registry is also refilled on the dashboard every time a device syncs, so
183
- // subscribe as well rather than assuming the key list is final at mount.
184
- (0, _react.useEffect)(() => {
185
- fetchSecureStoreData();
186
- const unsubscribe = _SecureStoreRegistry.secureStoreRegistry.subscribe(() => {
187
- fetchSecureStoreData();
188
- });
189
- if (pollMs <= 0) return unsubscribe;
190
- const interval = setInterval(fetchSecureStoreData, pollMs);
191
- return () => {
192
- unsubscribe();
193
- clearInterval(interval);
194
- };
195
- }, [fetchSecureStoreData, pollMs]);
196
- return {
197
- storageKeys,
198
- isLoading,
199
- error,
200
- refresh: fetchSecureStoreData
201
- };
202
- }
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.useSecureStoreKeys=useSecureStoreKeys;var _react=require("react");var _requiredStorageKeyScope=require("../utils/requiredStorageKeyScope");var _SecureStoreRegistry=require("../utils/SecureStoreRegistry");const BIOMETRIC_PLACEHOLDER="\u2022\u2022\u2022\u2022\u2022\u2022 (biometric protected)";const DEFAULT_POLL_MS=3e3;function signature(u){return JSON.stringify(u)}function useSecureStoreKeys(u=[],x={}){const{pollMs:p=DEFAULT_POLL_MS}=x;const h=(0,_react.useRef)(u);h.current=u;const b=JSON.stringify(u);const[T,m]=(0,_react.useState)([]);const[L,d]=(0,_react.useState)(true);const[A,q]=(0,_react.useState)(null);const v=(0,_react.useRef)(signature([]));const y=(0,_react.useRef)(false);const f=(0,_react.useRef)(false);const l=(0,_react.useCallback)(r=>{const i=signature(r);if(i===v.current)return;v.current=i;m(r)},[]);const c=(0,_react.useCallback)(async()=>{if(f.current)return;f.current=true;try{const r=_SecureStoreRegistry.secureStoreRegistry.getModule();const i=_SecureStoreRegistry.secureStoreRegistry.getAll();const g=h.current.filter(e=>(0,_requiredStorageKeyScope.requiredKeyAppliesTo)(e,"secure"));const E=e=>g.find(t=>(typeof t==="string"?t:t.key)===e);if(!r||i.length===0&&g.length===0){l([]);y.current=true;d(false);return}if(!y.current)d(true);q(null);const S=[];const I=[...i,...g.map(e=>typeof e==="string"?e:e.key).filter(e=>!i.some(t=>t.key===e)).map(e=>({key:e,options:{},description:void 0}))];for(const e of I){const t=E(e.key);const n=typeof t==="object"?t:void 0;const R={...n?.expectedValue!==void 0&&{expectedValue:n.expectedValue},...n?.expectedType!==void 0&&{expectedType:n.expectedType}};const _=n?.description??e.description;if(e.options.requireAuthentication){S.push({key:e.key,value:BIOMETRIC_PLACEHOLDER,storageType:"secure",status:t?"required_present":"optional_present",category:t?"required":"optional",description:_??"Protected by biometric authentication \u2014 value not read by DevTools",...R,...e.options.keychainService&&{instanceId:e.options.keychainService}});continue}let s=null;try{s=await r.getItemAsync(e.key,e.options)}catch{}if(s===null&&!t)continue;let o=s;if(s){try{o=JSON.parse(s)}catch{o=s}}let a="optional_present";if(t){if(s===null)a="required_missing";else if(n?.expectedValue!==void 0)a=String(o)===String(n.expectedValue)?"required_present":"required_wrong_value";else if(n?.expectedType!==void 0){const O=o===null?"null":Array.isArray(o)?"array":typeof o;const k=n.expectedType.toLowerCase();a=O===k||k==="string"&&typeof s==="string"?"required_present":"required_wrong_type"}else a="required_present"}S.push({key:e.key,value:s===null?void 0:o,storageType:"secure",status:a,category:t?"required":"optional",..._&&{description:_},...R,...e.options.keychainService&&{instanceId:e.options.keychainService}})}l(S)}catch(r){q(r instanceof Error?r:new Error("Failed to read SecureStore"));l([])}finally{y.current=true;f.current=false;d(false)}},[l,b]);(0,_react.useEffect)(()=>{c();const r=_SecureStoreRegistry.secureStoreRegistry.subscribe(()=>{c()});if(p<=0)return r;const i=setInterval(c,p);return()=>{r();clearInterval(i)}},[c,p]);return{storageKeys:T,isLoading:L,error:A,refresh:c}}
@@ -1,61 +1 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.useStorageEvents = useStorageEvents;
7
- var _react = require("react");
8
- var _sharedUi = require("@buoy-gg/shared-ui");
9
- var _storageEventStore = require("../stores/storageEventStore");
10
- /**
11
- * useStorageEvents Hook
12
- *
13
- * React hook for subscribing to storage events from the centralized store.
14
- * Uses self-managing Subscribable pattern - the storage listener automatically
15
- * starts when this hook mounts and stops when all subscribers unmount.
16
- *
17
- * @example
18
- * ```typescript
19
- * function MyComponent() {
20
- * const { events, clearEvents, isCapturing } = useStorageEvents();
21
- *
22
- * return (
23
- * <View>
24
- * {events.map((event) => (
25
- * <Text key={event.timestamp.toString()}>
26
- * {event.action}: {event.data?.key}
27
- * </Text>
28
- * ))}
29
- * </View>
30
- * );
31
- * }
32
- * ```
33
- */
34
-
35
- // Re-export StorageEvent for convenience
36
-
37
- function useStorageEvents(options = {}) {
38
- const {
39
- storageType = "all",
40
- maxEvents = 500,
41
- enabled = true
42
- } = options;
43
- // Stable per storageType so the shared hook doesn't resubscribe every render.
44
- const select = (0, _react.useMemo)(() => storageType === "all" ? undefined : events => events.filter(e => e.storageType === storageType), [storageType]);
45
- // Subscribing auto-starts the storage listener (Subscribable pattern), and
46
- // the shared hook frame-coalesces write bursts into one commit.
47
- const {
48
- events,
49
- clearEvents,
50
- isActive
51
- } = (0, _sharedUi.useEventStoreEvents)(_storageEventStore.storageEventStore, {
52
- maxEvents,
53
- enabled,
54
- select
55
- });
56
- return {
57
- events,
58
- clearEvents,
59
- isCapturing: isActive
60
- };
61
- }
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.useStorageEvents=useStorageEvents;var _react=require("react");var _sharedUi=require("@buoy-gg/shared-ui");var _storageEventStore=require("../stores/storageEventStore");function useStorageEvents(t={}){const{storageType:e="all",maxEvents:r=500,enabled:s=true}=t;const o=(0,_react.useMemo)(()=>e==="all"?void 0:v=>v.filter(i=>i.storageType===e),[e]);const{events:a,clearEvents:n,isActive:u}=(0,_sharedUi.useEventStoreEvents)(_storageEventStore.storageEventStore,{maxEvents:r,enabled:s,select:o});return{events:a,clearEvents:n,isCapturing:u}}
@@ -1,312 +1 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.batchPairsOf = batchPairsOf;
7
- exports.isStorageCapturing = exports.getStorageEvents = exports.clearStorageEvents = void 0;
8
- exports.isValueOnDevice = isValueOnDevice;
9
- exports.subscribeToStorageEvents = exports.storageEventStore = exports.onStorageEvent = void 0;
10
- var _sharedUi = require("@buoy-gg/shared-ui");
11
- var _AsyncStorageListener = require("../utils/AsyncStorageListener");
12
- var _MMKVListener = require("../utils/MMKVListener");
13
- var _MMKVInstanceRegistry = require("../utils/MMKVInstanceRegistry");
14
- var _mmkvTypeDetection = require("../utils/mmkvTypeDetection");
15
- /**
16
- * Storage Event Store
17
- *
18
- * Centralized store that aggregates storage events from AsyncStorage and MMKV
19
- * into a single event stream. Uses BaseEventStore pattern - the storage listener
20
- * automatically starts when the first subscriber joins and stops when the last
21
- * subscriber leaves.
22
- *
23
- * @example
24
- * ```typescript
25
- * import { storageEventStore } from '@buoy-gg/storage';
26
- *
27
- * // Subscribe to storage events - automatically starts capturing!
28
- * const unsubscribe = storageEventStore.subscribeToEvents((events) => {
29
- * console.log('Storage events:', events);
30
- * });
31
- *
32
- * // Later, clean up - automatically stops if no other subscribers
33
- * unsubscribe();
34
- * ```
35
- */
36
-
37
- /**
38
- * Unified storage event type combining AsyncStorage and MMKV events.
39
- * `id` is assigned by the store when the event enters — needed because raw
40
- * events have no unique identifier (rapid same-key writes can share a
41
- * millisecond timestamp), and React keys must be unique per render.
42
- */
43
-
44
- /** True when a field is the wire-form VALUE_ON_DEVICE marker. */
45
- function isValueOnDevice(value) {
46
- return !!value && typeof value === "object" && value.__buoyValueOnDevice === true;
47
- }
48
-
49
- /**
50
- * `pairs` / `prevPairs` are AsyncStorage-only — they carry the batch
51
- * operations (multiSet / multiRemove / multiMerge / clear), and MMKV has no
52
- * batch API, so its `data` has no such fields. Reading them off the
53
- * `StorageEvent` union needs narrowing, and this is the one place that does
54
- * it; writing them unconditionally would also graft meaningless keys onto
55
- * every MMKV event on the wire.
56
- */
57
- function batchPairsOf(event) {
58
- if (event.storageType !== "async" || !event.data) return {};
59
- return {
60
- pairs: event.data.pairs,
61
- prevPairs: event.data.prevPairs
62
- };
63
- }
64
- function eventHasOnDeviceValues(event) {
65
- const data = event.data;
66
- if (!data) return false;
67
- const {
68
- pairs,
69
- prevPairs
70
- } = batchPairsOf(event);
71
- return isValueOnDevice(data.value) || isValueOnDevice(data.prevValue) || isValueOnDevice(pairs) || isValueOnDevice(prevPairs);
72
- }
73
- let storageEventIdCounter = 0;
74
- function nextStorageEventId() {
75
- return `se-${Date.now()}-${++storageEventIdCounter}`;
76
- }
77
-
78
- /**
79
- * Listener callback type for storage events array
80
- */
81
-
82
- /**
83
- * Listener callback for individual new events
84
- */
85
-
86
- class StorageEventStore extends _sharedUi.BaseEventStore {
87
- // Unsubscribe functions for raw listeners
88
- asyncStorageUnsubscribe = null;
89
- mmkvUnsubscribe = null;
90
- hasScannedInitialState = false;
91
- constructor() {
92
- super({
93
- storeName: "storage",
94
- maxEvents: 500
95
- });
96
- }
97
-
98
- /**
99
- * Scan all registered MMKV instances and AsyncStorage for existing keys,
100
- * creating synthetic events so that getEvents() includes the current state
101
- * (not just changes made after capture started). Only runs once per store
102
- * lifetime to avoid duplicates.
103
- */
104
- async scanExistingState() {
105
- if (this.hasScannedInitialState) return;
106
- this.hasScannedInitialState = true;
107
- const now = new Date();
108
-
109
- // ── MMKV: synchronous scan ──
110
- const instances = _MMKVInstanceRegistry.mmkvInstanceRegistry.getAll();
111
- for (const {
112
- id: instanceId,
113
- instance
114
- } of instances) {
115
- try {
116
- const keys = instance.getAllKeys();
117
- for (const key of keys) {
118
- const {
119
- value,
120
- type: valueType
121
- } = (0, _mmkvTypeDetection.detectMMKVType)(instance, key);
122
- const actionMap = {
123
- string: "set.string",
124
- number: "set.number",
125
- boolean: "set.boolean",
126
- buffer: "set.buffer"
127
- };
128
- const action = actionMap[valueType] ?? "set.string";
129
- this.addEvent({
130
- action,
131
- timestamp: now,
132
- instanceId,
133
- data: {
134
- key,
135
- value,
136
- valueType,
137
- initialScan: true
138
- },
139
- storageType: "mmkv",
140
- id: nextStorageEventId()
141
- });
142
- }
143
- } catch {
144
- // Instance may not be accessible — skip silently
145
- }
146
- }
147
-
148
- // ── AsyncStorage: async scan ──
149
- try {
150
- const {
151
- asyncStorage,
152
- readMany
153
- } = require("../utils/asyncStorageCompat");
154
- if (asyncStorage) {
155
- const allKeys = await asyncStorage.getAllKeys();
156
- if (allKeys.length > 0) {
157
- const pairs = await readMany(allKeys);
158
- for (const [key, rawValue] of pairs) {
159
- this.addEvent({
160
- action: "setItem",
161
- timestamp: now,
162
- data: {
163
- key,
164
- value: rawValue ?? undefined,
165
- initialScan: true
166
- },
167
- storageType: "async",
168
- id: nextStorageEventId()
169
- });
170
- }
171
- }
172
- }
173
- } catch {
174
- // AsyncStorage not available — skip silently
175
- }
176
- }
177
-
178
- /**
179
- * Start capturing storage events from both AsyncStorage and MMKV
180
- */
181
- async startCapturing() {
182
- // Start AsyncStorage listening if not already active
183
- if (!(0, _AsyncStorageListener.isListening)()) {
184
- await (0, _AsyncStorageListener.startListening)();
185
- }
186
-
187
- // Subscribe to AsyncStorage events
188
- if (!this.asyncStorageUnsubscribe) {
189
- this.asyncStorageUnsubscribe = (0, _AsyncStorageListener.addListener)(event => {
190
- const storageEvent = {
191
- ...event,
192
- storageType: "async",
193
- id: nextStorageEventId()
194
- };
195
- this.addEvent(storageEvent);
196
- });
197
- }
198
-
199
- // Subscribe to MMKV events
200
- if (!this.mmkvUnsubscribe) {
201
- this.mmkvUnsubscribe = (0, _MMKVListener.addMMKVListener)(event => {
202
- const storageEvent = {
203
- ...event,
204
- storageType: "mmkv",
205
- id: nextStorageEventId()
206
- };
207
- this.addEvent(storageEvent);
208
- });
209
- }
210
-
211
- // Scan existing keys so getEvents() includes pre-existing state
212
- await this.scanExistingState();
213
- }
214
-
215
- /**
216
- * Stop capturing storage events
217
- */
218
- stopCapturing() {
219
- // Unsubscribe from AsyncStorage
220
- if (this.asyncStorageUnsubscribe) {
221
- this.asyncStorageUnsubscribe();
222
- this.asyncStorageUnsubscribe = null;
223
- }
224
-
225
- // Unsubscribe from MMKV
226
- if (this.mmkvUnsubscribe) {
227
- this.mmkvUnsubscribe();
228
- this.mmkvUnsubscribe = null;
229
- }
230
- }
231
-
232
- /**
233
- * Check if currently capturing events (has subscribers)
234
- */
235
- isCapturing() {
236
- return this.asyncStorageUnsubscribe !== null || this.mmkvUnsubscribe !== null;
237
- }
238
-
239
- /**
240
- * Get events filtered by storage type
241
- */
242
- getEventsByType(storageType) {
243
- return this.events.filter(event => event.storageType === storageType);
244
- }
245
-
246
- /**
247
- * Replace the event list, keeping values a remote mirror already hydrated.
248
- * Wire-form snapshots always carry VALUE_ON_DEVICE markers for oversized
249
- * payloads; a later snapshot must not blank the detail pane (or wipe
250
- * `prevValue` that time-travel undo needs).
251
- */
252
- replaceEvents(events) {
253
- const hydrated = new Map();
254
- for (const existing of this.events) {
255
- if (!eventHasOnDeviceValues(existing)) {
256
- hydrated.set(existing.id, existing);
257
- }
258
- }
259
- const merged = events.map(incoming => {
260
- const kept = hydrated.get(incoming.id);
261
- if (!kept || !eventHasOnDeviceValues(incoming)) return incoming;
262
- // Restore only the fields this event's storage type actually has, so an
263
- // MMKV event never grows `pairs`/`prevPairs` it has no meaning for.
264
- return {
265
- ...incoming,
266
- data: {
267
- ...incoming.data,
268
- value: kept.data?.value,
269
- prevValue: kept.data?.prevValue,
270
- ...batchPairsOf(kept)
271
- }
272
- };
273
- });
274
- super.replaceEvents(merged);
275
- }
276
-
277
- /**
278
- * Hydrate one mirrored event with real values fetched on demand from the
279
- * device via the adapter's `getEventDetail`. Remote-mirror (desktop) only.
280
- */
281
- hydrateEvent(event) {
282
- const index = this.events.findIndex(e => e.id === event.id);
283
- if (index === -1) return;
284
- const current = this.events[index];
285
- const next = this.events.slice();
286
- next[index] = {
287
- ...current,
288
- ...event,
289
- timestamp: current.timestamp,
290
- data: {
291
- ...current.data,
292
- ...event.data
293
- }
294
- };
295
- super.replaceEvents(next);
296
- }
297
- }
298
-
299
- // Singleton instance
300
- const storageEventStore = exports.storageEventStore = new StorageEventStore();
301
-
302
- // Convenience exports
303
- const subscribeToStorageEvents = listener => storageEventStore.subscribeToEvents(listener);
304
- exports.subscribeToStorageEvents = subscribeToStorageEvents;
305
- const onStorageEvent = callback => storageEventStore.onEvent(callback);
306
- exports.onStorageEvent = onStorageEvent;
307
- const getStorageEvents = () => storageEventStore.getEvents();
308
- exports.getStorageEvents = getStorageEvents;
309
- const clearStorageEvents = () => storageEventStore.clearEvents();
310
- exports.clearStorageEvents = clearStorageEvents;
311
- const isStorageCapturing = () => storageEventStore.isCapturing();
312
- exports.isStorageCapturing = isStorageCapturing;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.batchPairsOf=batchPairsOf;exports.isStorageCapturing=exports.getStorageEvents=exports.clearStorageEvents=void 0;exports.isValueOnDevice=isValueOnDevice;exports.subscribeToStorageEvents=exports.storageEventStore=exports.onStorageEvent=void 0;var _sharedUi=require("@buoy-gg/shared-ui");var _AsyncStorageListener=require("../utils/AsyncStorageListener");var _MMKVListener=require("../utils/MMKVListener");var _MMKVInstanceRegistry=require("../utils/MMKVInstanceRegistry");var _mmkvTypeDetection=require("../utils/mmkvTypeDetection");function isValueOnDevice(s){return!!s&&typeof s==="object"&&s.__buoyValueOnDevice===true}function batchPairsOf(s){if(s.storageType!=="async"||!s.data)return{};return{pairs:s.data.pairs,prevPairs:s.data.prevPairs}}function eventHasOnDeviceValues(s){const e=s.data;if(!e)return false;const{pairs:a,prevPairs:n}=batchPairsOf(s);return isValueOnDevice(e.value)||isValueOnDevice(e.prevValue)||isValueOnDevice(a)||isValueOnDevice(n)}let storageEventIdCounter=0;function nextStorageEventId(){return`se-${Date.now()}-${++storageEventIdCounter}`}class StorageEventStore extends _sharedUi.BaseEventStore{asyncStorageUnsubscribe=null;mmkvUnsubscribe=null;hasScannedInitialState=false;constructor(){super({storeName:"storage",maxEvents:500})}async scanExistingState(){if(this.hasScannedInitialState)return;this.hasScannedInitialState=true;const e=new Date;const a=_MMKVInstanceRegistry.mmkvInstanceRegistry.getAll();for(const{id:n,instance:t}of a){try{const r=t.getAllKeys();for(const i of r){const{value:c,type:o}=(0,_mmkvTypeDetection.detectMMKVType)(t,i);const u={string:"set.string",number:"set.number",boolean:"set.boolean",buffer:"set.buffer"};const v=u[o]??"set.string";this.addEvent({action:v,timestamp:e,instanceId:n,data:{key:i,value:c,valueType:o,initialScan:true},storageType:"mmkv",id:nextStorageEventId()})}}catch{}}try{const{asyncStorage:n,readMany:t}=require("../utils/asyncStorageCompat");if(n){const r=await n.getAllKeys();if(r.length>0){const i=await t(r);for(const[c,o]of i){this.addEvent({action:"setItem",timestamp:e,data:{key:c,value:o??void 0,initialScan:true},storageType:"async",id:nextStorageEventId()})}}}}catch{}}async startCapturing(){if(!(0,_AsyncStorageListener.isListening)()){await(0,_AsyncStorageListener.startListening)()}if(!this.asyncStorageUnsubscribe){this.asyncStorageUnsubscribe=(0,_AsyncStorageListener.addListener)(e=>{const a={...e,storageType:"async",id:nextStorageEventId()};this.addEvent(a)})}if(!this.mmkvUnsubscribe){this.mmkvUnsubscribe=(0,_MMKVListener.addMMKVListener)(e=>{const a={...e,storageType:"mmkv",id:nextStorageEventId()};this.addEvent(a)})}await this.scanExistingState()}stopCapturing(){if(this.asyncStorageUnsubscribe){this.asyncStorageUnsubscribe();this.asyncStorageUnsubscribe=null}if(this.mmkvUnsubscribe){this.mmkvUnsubscribe();this.mmkvUnsubscribe=null}}isCapturing(){return this.asyncStorageUnsubscribe!==null||this.mmkvUnsubscribe!==null}getEventsByType(e){return this.events.filter(a=>a.storageType===e)}replaceEvents(e){const a=new Map;for(const t of this.events){if(!eventHasOnDeviceValues(t)){a.set(t.id,t)}}const n=e.map(t=>{const r=a.get(t.id);if(!r||!eventHasOnDeviceValues(t))return t;return{...t,data:{...t.data,value:r.data?.value,prevValue:r.data?.prevValue,...batchPairsOf(r)}}});super.replaceEvents(n)}hydrateEvent(e){const a=this.events.findIndex(r=>r.id===e.id);if(a===-1)return;const n=this.events[a];const t=this.events.slice();t[a]={...n,...e,timestamp:n.timestamp,data:{...n.data,...e.data}};super.replaceEvents(t)}}const storageEventStore=exports.storageEventStore=new StorageEventStore;const subscribeToStorageEvents=s=>storageEventStore.subscribeToEvents(s);exports.subscribeToStorageEvents=subscribeToStorageEvents;const onStorageEvent=s=>storageEventStore.onEvent(s);exports.onStorageEvent=onStorageEvent;const getStorageEvents=()=>storageEventStore.getEvents();exports.getStorageEvents=getStorageEvents;const clearStorageEvents=()=>storageEventStore.clearEvents();exports.clearStorageEvents=clearStorageEvents;const isStorageCapturing=()=>storageEventStore.isCapturing();exports.isStorageCapturing=isStorageCapturing;