@buoy-gg/storage 1.7.2

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 (187) hide show
  1. package/README.md +607 -0
  2. package/lib/commonjs/index.js +34 -0
  3. package/lib/commonjs/package.json +1 -0
  4. package/lib/commonjs/preset.js +94 -0
  5. package/lib/commonjs/storage/components/DiffViewer/DiffOptionsPanel.js +356 -0
  6. package/lib/commonjs/storage/components/DiffViewer/TreeDiffViewer.js +29 -0
  7. package/lib/commonjs/storage/components/DiffViewer/components/DiffSummary.js +121 -0
  8. package/lib/commonjs/storage/components/DiffViewer/modes/ThemedSplitView.js +419 -0
  9. package/lib/commonjs/storage/components/DiffViewer/themes/diffThemes.js +122 -0
  10. package/lib/commonjs/storage/components/GameUIStorageBrowser.js +924 -0
  11. package/lib/commonjs/storage/components/GameUIStorageStats.js +746 -0
  12. package/lib/commonjs/storage/components/MMKVInstanceInfoPanel.js +257 -0
  13. package/lib/commonjs/storage/components/MMKVInstanceSelector.js +418 -0
  14. package/lib/commonjs/storage/components/SelectionActionBar.js +224 -0
  15. package/lib/commonjs/storage/components/StorageActionButtons.js +239 -0
  16. package/lib/commonjs/storage/components/StorageActions.js +192 -0
  17. package/lib/commonjs/storage/components/StorageBrowserMode.js +31 -0
  18. package/lib/commonjs/storage/components/StorageEventDetailContent.js +1025 -0
  19. package/lib/commonjs/storage/components/StorageEventFilterView.js +141 -0
  20. package/lib/commonjs/storage/components/StorageEventListener.js +357 -0
  21. package/lib/commonjs/storage/components/StorageEventsSection.js +24 -0
  22. package/lib/commonjs/storage/components/StorageFilterCards.js +345 -0
  23. package/lib/commonjs/storage/components/StorageFilterViewV2.js +42 -0
  24. package/lib/commonjs/storage/components/StorageKeyCard.js +516 -0
  25. package/lib/commonjs/storage/components/StorageKeyRow.js +356 -0
  26. package/lib/commonjs/storage/components/StorageKeySection.js +105 -0
  27. package/lib/commonjs/storage/components/StorageKeyStats.js +344 -0
  28. package/lib/commonjs/storage/components/StorageModalWithTabs.js +871 -0
  29. package/lib/commonjs/storage/components/StorageSection.js +43 -0
  30. package/lib/commonjs/storage/hooks/useAsyncStorageKeys.js +126 -0
  31. package/lib/commonjs/storage/hooks/useMMKVInstances.js +221 -0
  32. package/lib/commonjs/storage/hooks/useMMKVKeys.js +362 -0
  33. package/lib/commonjs/storage/hooks/useTickEverySecond.js +21 -0
  34. package/lib/commonjs/storage/index.js +148 -0
  35. package/lib/commonjs/storage/types.js +5 -0
  36. package/lib/commonjs/storage/utils/AsyncStorageListener.js +510 -0
  37. package/lib/commonjs/storage/utils/MMKVInstanceRegistry.js +202 -0
  38. package/lib/commonjs/storage/utils/MMKVListener.js +380 -0
  39. package/lib/commonjs/storage/utils/clearAllStorage.js +47 -0
  40. package/lib/commonjs/storage/utils/index.js +180 -0
  41. package/lib/commonjs/storage/utils/lineDiff.js +363 -0
  42. package/lib/commonjs/storage/utils/mmkvAvailability.js +62 -0
  43. package/lib/commonjs/storage/utils/mmkvTypeDetection.js +139 -0
  44. package/lib/commonjs/storage/utils/objectDiff.js +157 -0
  45. package/lib/commonjs/storage/utils/safeAsyncStorage.js +140 -0
  46. package/lib/commonjs/storage/utils/storageActionHelpers.js +46 -0
  47. package/lib/commonjs/storage/utils/storageQueryUtils.js +35 -0
  48. package/lib/commonjs/storage/utils/valueType.js +18 -0
  49. package/lib/module/index.js +7 -0
  50. package/lib/module/preset.js +89 -0
  51. package/lib/module/storage/components/DiffViewer/DiffOptionsPanel.js +352 -0
  52. package/lib/module/storage/components/DiffViewer/TreeDiffViewer.js +25 -0
  53. package/lib/module/storage/components/DiffViewer/components/DiffSummary.js +117 -0
  54. package/lib/module/storage/components/DiffViewer/modes/ThemedSplitView.js +415 -0
  55. package/lib/module/storage/components/DiffViewer/themes/diffThemes.js +118 -0
  56. package/lib/module/storage/components/GameUIStorageBrowser.js +922 -0
  57. package/lib/module/storage/components/GameUIStorageStats.js +742 -0
  58. package/lib/module/storage/components/MMKVInstanceInfoPanel.js +253 -0
  59. package/lib/module/storage/components/MMKVInstanceSelector.js +414 -0
  60. package/lib/module/storage/components/SelectionActionBar.js +221 -0
  61. package/lib/module/storage/components/StorageActionButtons.js +236 -0
  62. package/lib/module/storage/components/StorageActions.js +189 -0
  63. package/lib/module/storage/components/StorageBrowserMode.js +27 -0
  64. package/lib/module/storage/components/StorageEventDetailContent.js +1020 -0
  65. package/lib/module/storage/components/StorageEventFilterView.js +137 -0
  66. package/lib/module/storage/components/StorageEventListener.js +354 -0
  67. package/lib/module/storage/components/StorageEventsSection.js +20 -0
  68. package/lib/module/storage/components/StorageFilterCards.js +341 -0
  69. package/lib/module/storage/components/StorageFilterViewV2.js +38 -0
  70. package/lib/module/storage/components/StorageKeyCard.js +513 -0
  71. package/lib/module/storage/components/StorageKeyRow.js +353 -0
  72. package/lib/module/storage/components/StorageKeySection.js +101 -0
  73. package/lib/module/storage/components/StorageKeyStats.js +340 -0
  74. package/lib/module/storage/components/StorageModalWithTabs.js +867 -0
  75. package/lib/module/storage/components/StorageSection.js +40 -0
  76. package/lib/module/storage/hooks/useAsyncStorageKeys.js +121 -0
  77. package/lib/module/storage/hooks/useMMKVInstances.js +216 -0
  78. package/lib/module/storage/hooks/useMMKVKeys.js +359 -0
  79. package/lib/module/storage/hooks/useTickEverySecond.js +18 -0
  80. package/lib/module/storage/index.js +25 -0
  81. package/lib/module/storage/types.js +3 -0
  82. package/lib/module/storage/utils/AsyncStorageListener.js +500 -0
  83. package/lib/module/storage/utils/MMKVInstanceRegistry.js +196 -0
  84. package/lib/module/storage/utils/MMKVListener.js +367 -0
  85. package/lib/module/storage/utils/clearAllStorage.js +42 -0
  86. package/lib/module/storage/utils/index.js +22 -0
  87. package/lib/module/storage/utils/lineDiff.js +359 -0
  88. package/lib/module/storage/utils/mmkvAvailability.js +56 -0
  89. package/lib/module/storage/utils/mmkvTypeDetection.js +133 -0
  90. package/lib/module/storage/utils/objectDiff.js +153 -0
  91. package/lib/module/storage/utils/safeAsyncStorage.js +134 -0
  92. package/lib/module/storage/utils/storageActionHelpers.js +42 -0
  93. package/lib/module/storage/utils/storageQueryUtils.js +30 -0
  94. package/lib/module/storage/utils/valueType.js +14 -0
  95. package/lib/typescript/index.d.ts +3 -0
  96. package/lib/typescript/index.d.ts.map +1 -0
  97. package/lib/typescript/preset.d.ts +90 -0
  98. package/lib/typescript/preset.d.ts.map +1 -0
  99. package/lib/typescript/storage/components/DiffViewer/DiffOptionsPanel.d.ts +18 -0
  100. package/lib/typescript/storage/components/DiffViewer/DiffOptionsPanel.d.ts.map +1 -0
  101. package/lib/typescript/storage/components/DiffViewer/TreeDiffViewer.d.ts +7 -0
  102. package/lib/typescript/storage/components/DiffViewer/TreeDiffViewer.d.ts.map +1 -0
  103. package/lib/typescript/storage/components/DiffViewer/components/DiffSummary.d.ts +12 -0
  104. package/lib/typescript/storage/components/DiffViewer/components/DiffSummary.d.ts.map +1 -0
  105. package/lib/typescript/storage/components/DiffViewer/modes/ThemedSplitView.d.ts +13 -0
  106. package/lib/typescript/storage/components/DiffViewer/modes/ThemedSplitView.d.ts.map +1 -0
  107. package/lib/typescript/storage/components/DiffViewer/themes/diffThemes.d.ts +64 -0
  108. package/lib/typescript/storage/components/DiffViewer/themes/diffThemes.d.ts.map +1 -0
  109. package/lib/typescript/storage/components/GameUIStorageBrowser.d.ts +16 -0
  110. package/lib/typescript/storage/components/GameUIStorageBrowser.d.ts.map +1 -0
  111. package/lib/typescript/storage/components/GameUIStorageStats.d.ts +7 -0
  112. package/lib/typescript/storage/components/GameUIStorageStats.d.ts.map +1 -0
  113. package/lib/typescript/storage/components/MMKVInstanceInfoPanel.d.ts +42 -0
  114. package/lib/typescript/storage/components/MMKVInstanceInfoPanel.d.ts.map +1 -0
  115. package/lib/typescript/storage/components/MMKVInstanceSelector.d.ts +35 -0
  116. package/lib/typescript/storage/components/MMKVInstanceSelector.d.ts.map +1 -0
  117. package/lib/typescript/storage/components/SelectionActionBar.d.ts +21 -0
  118. package/lib/typescript/storage/components/SelectionActionBar.d.ts.map +1 -0
  119. package/lib/typescript/storage/components/StorageActionButtons.d.ts +21 -0
  120. package/lib/typescript/storage/components/StorageActionButtons.d.ts.map +1 -0
  121. package/lib/typescript/storage/components/StorageActions.d.ts +10 -0
  122. package/lib/typescript/storage/components/StorageActions.d.ts.map +1 -0
  123. package/lib/typescript/storage/components/StorageBrowserMode.d.ts +18 -0
  124. package/lib/typescript/storage/components/StorageBrowserMode.d.ts.map +1 -0
  125. package/lib/typescript/storage/components/StorageEventDetailContent.d.ts +40 -0
  126. package/lib/typescript/storage/components/StorageEventDetailContent.d.ts.map +1 -0
  127. package/lib/typescript/storage/components/StorageEventFilterView.d.ts +11 -0
  128. package/lib/typescript/storage/components/StorageEventFilterView.d.ts.map +1 -0
  129. package/lib/typescript/storage/components/StorageEventListener.d.ts +6 -0
  130. package/lib/typescript/storage/components/StorageEventListener.d.ts.map +1 -0
  131. package/lib/typescript/storage/components/StorageEventsSection.d.ts +7 -0
  132. package/lib/typescript/storage/components/StorageEventsSection.d.ts.map +1 -0
  133. package/lib/typescript/storage/components/StorageFilterCards.d.ts +36 -0
  134. package/lib/typescript/storage/components/StorageFilterCards.d.ts.map +1 -0
  135. package/lib/typescript/storage/components/StorageFilterViewV2.d.ts +9 -0
  136. package/lib/typescript/storage/components/StorageFilterViewV2.d.ts.map +1 -0
  137. package/lib/typescript/storage/components/StorageKeyCard.d.ts +17 -0
  138. package/lib/typescript/storage/components/StorageKeyCard.d.ts.map +1 -0
  139. package/lib/typescript/storage/components/StorageKeyRow.d.ts +15 -0
  140. package/lib/typescript/storage/components/StorageKeyRow.d.ts.map +1 -0
  141. package/lib/typescript/storage/components/StorageKeySection.d.ts +25 -0
  142. package/lib/typescript/storage/components/StorageKeySection.d.ts.map +1 -0
  143. package/lib/typescript/storage/components/StorageKeyStats.d.ts +15 -0
  144. package/lib/typescript/storage/components/StorageKeyStats.d.ts.map +1 -0
  145. package/lib/typescript/storage/components/StorageModalWithTabs.d.ts +13 -0
  146. package/lib/typescript/storage/components/StorageModalWithTabs.d.ts.map +1 -0
  147. package/lib/typescript/storage/components/StorageSection.d.ts +10 -0
  148. package/lib/typescript/storage/components/StorageSection.d.ts.map +1 -0
  149. package/lib/typescript/storage/hooks/useAsyncStorageKeys.d.ts +10 -0
  150. package/lib/typescript/storage/hooks/useAsyncStorageKeys.d.ts.map +1 -0
  151. package/lib/typescript/storage/hooks/useMMKVInstances.d.ts +114 -0
  152. package/lib/typescript/storage/hooks/useMMKVInstances.d.ts.map +1 -0
  153. package/lib/typescript/storage/hooks/useMMKVKeys.d.ts +94 -0
  154. package/lib/typescript/storage/hooks/useMMKVKeys.d.ts.map +1 -0
  155. package/lib/typescript/storage/hooks/useTickEverySecond.d.ts +6 -0
  156. package/lib/typescript/storage/hooks/useTickEverySecond.d.ts.map +1 -0
  157. package/lib/typescript/storage/index.d.ts +15 -0
  158. package/lib/typescript/storage/index.d.ts.map +1 -0
  159. package/lib/typescript/storage/types.d.ts +41 -0
  160. package/lib/typescript/storage/types.d.ts.map +1 -0
  161. package/lib/typescript/storage/utils/AsyncStorageListener.d.ts +195 -0
  162. package/lib/typescript/storage/utils/AsyncStorageListener.d.ts.map +1 -0
  163. package/lib/typescript/storage/utils/MMKVInstanceRegistry.d.ts +224 -0
  164. package/lib/typescript/storage/utils/MMKVInstanceRegistry.d.ts.map +1 -0
  165. package/lib/typescript/storage/utils/MMKVListener.d.ts +218 -0
  166. package/lib/typescript/storage/utils/MMKVListener.d.ts.map +1 -0
  167. package/lib/typescript/storage/utils/clearAllStorage.d.ts +11 -0
  168. package/lib/typescript/storage/utils/clearAllStorage.d.ts.map +1 -0
  169. package/lib/typescript/storage/utils/index.d.ts +8 -0
  170. package/lib/typescript/storage/utils/index.d.ts.map +1 -0
  171. package/lib/typescript/storage/utils/lineDiff.d.ts +34 -0
  172. package/lib/typescript/storage/utils/lineDiff.d.ts.map +1 -0
  173. package/lib/typescript/storage/utils/mmkvAvailability.d.ts +23 -0
  174. package/lib/typescript/storage/utils/mmkvAvailability.d.ts.map +1 -0
  175. package/lib/typescript/storage/utils/mmkvTypeDetection.d.ts +71 -0
  176. package/lib/typescript/storage/utils/mmkvTypeDetection.d.ts.map +1 -0
  177. package/lib/typescript/storage/utils/objectDiff.d.ts +35 -0
  178. package/lib/typescript/storage/utils/objectDiff.d.ts.map +1 -0
  179. package/lib/typescript/storage/utils/safeAsyncStorage.d.ts +56 -0
  180. package/lib/typescript/storage/utils/safeAsyncStorage.d.ts.map +1 -0
  181. package/lib/typescript/storage/utils/storageActionHelpers.d.ts +5 -0
  182. package/lib/typescript/storage/utils/storageActionHelpers.d.ts.map +1 -0
  183. package/lib/typescript/storage/utils/storageQueryUtils.d.ts +6 -0
  184. package/lib/typescript/storage/utils/storageQueryUtils.d.ts.map +1 -0
  185. package/lib/typescript/storage/utils/valueType.d.ts +3 -0
  186. package/lib/typescript/storage/utils/valueType.d.ts.map +1 -0
  187. package/package.json +68 -0
@@ -0,0 +1,1025 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.StorageEventDetailContent = StorageEventDetailContent;
7
+ exports.StorageEventDetailFooter = StorageEventDetailFooter;
8
+ var _reactNative = require("react-native");
9
+ var _react = require("react");
10
+ var _asyncStorage = _interopRequireDefault(require("@react-native-async-storage/async-storage"));
11
+ var _sharedUi = require("@buoy-gg/shared-ui");
12
+ var _dataViewer = require("@buoy-gg/shared-ui/dataViewer");
13
+ var _ThemedSplitView = require("./DiffViewer/modes/ThemedSplitView");
14
+ var _diffThemes = require("./DiffViewer/themes/diffThemes");
15
+ var _lineDiff = require("../utils/lineDiff");
16
+ var _TreeDiffViewer = require("./DiffViewer/TreeDiffViewer");
17
+ var _storageActionHelpers = require("../utils/storageActionHelpers");
18
+ var _jsxRuntime = require("react/jsx-runtime");
19
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
20
+ // Lazy load the license hooks to avoid circular dependencies
21
+ let _useIsPro = null;
22
+ let _licenseLoadAttempted = false;
23
+ function loadLicenseModule() {
24
+ if (_licenseLoadAttempted) return;
25
+ _licenseLoadAttempted = true;
26
+ try {
27
+ const mod = require("@buoy-gg/license");
28
+ if (mod) {
29
+ _useIsPro = mod.useIsPro ?? null;
30
+ }
31
+ } catch {
32
+ // License package not available
33
+ }
34
+ }
35
+ function getUseIsPro() {
36
+ loadLicenseModule();
37
+ return _useIsPro ?? (() => false);
38
+ }
39
+
40
+ // Free tier limit for event history navigation
41
+ const FREE_TIER_EVENT_HISTORY_LIMIT = 3;
42
+
43
+ // Unified storage event type (supports both AsyncStorage and MMKV)
44
+
45
+ function StorageEventDetailContent({
46
+ conversation,
47
+ selectedEventIndex = 0,
48
+ onEventIndexChange = () => {},
49
+ disableInternalFooter = false
50
+ }) {
51
+ // Check Pro status internally
52
+ const useIsPro = getUseIsPro();
53
+ const isPro = useIsPro();
54
+ // Internal view state - now managed internally instead of via props
55
+ const [internalActiveView, setInternalActiveView] = (0, _react.useState)("current");
56
+ // Compare-any-two state for Diff tab
57
+ const [leftIndex, setLeftIndex] = (0, _react.useState)(Math.max(0, selectedEventIndex - 1));
58
+ const [rightIndex, setRightIndex] = (0, _react.useState)(selectedEventIndex);
59
+ const [isLeftPickerOpen, setIsLeftPickerOpen] = (0, _react.useState)(false);
60
+ const [isRightPickerOpen, setIsRightPickerOpen] = (0, _react.useState)(false);
61
+ const [diffViewerTab, setDiffViewerTab] = (0, _react.useState)("tree");
62
+
63
+ // Track if preferences have been loaded
64
+ const hasLoadedPreferences = (0, _react.useRef)(false);
65
+
66
+ // Load saved preferences on mount
67
+ (0, _react.useEffect)(() => {
68
+ if (hasLoadedPreferences.current) return;
69
+ const loadPreferences = async () => {
70
+ try {
71
+ // Load detail view preference (current/diff)
72
+ const savedDetailView = await _asyncStorage.default.getItem(_sharedUi.devToolsStorageKeys.storage.detailView());
73
+ if (savedDetailView === "current" || savedDetailView === "diff") {
74
+ setInternalActiveView(savedDetailView);
75
+ }
76
+
77
+ // Load diff viewer mode preference (split/tree)
78
+ const savedDiffMode = await _asyncStorage.default.getItem(_sharedUi.devToolsStorageKeys.storage.diffViewerMode());
79
+ if (savedDiffMode === "split" || savedDiffMode === "tree") {
80
+ setDiffViewerTab(savedDiffMode);
81
+ }
82
+ hasLoadedPreferences.current = true;
83
+ } catch (error) {
84
+ // Failed to load view preferences
85
+ }
86
+ };
87
+ loadPreferences();
88
+ }, []);
89
+
90
+ // Save detail view preference when changed
91
+ const handleViewChange = (0, _react.useCallback)(async view => {
92
+ setInternalActiveView(view);
93
+ try {
94
+ await _asyncStorage.default.setItem(_sharedUi.devToolsStorageKeys.storage.detailView(), view);
95
+ } catch (error) {
96
+ // Failed to save detail view preference
97
+ }
98
+ }, []);
99
+
100
+ // Save diff viewer mode preference when changed
101
+ const handleDiffModeChange = (0, _react.useCallback)(async mode => {
102
+ setDiffViewerTab(mode);
103
+ try {
104
+ await _asyncStorage.default.setItem(_sharedUi.devToolsStorageKeys.storage.diffViewerMode(), mode);
105
+ } catch (error) {
106
+ // Failed to save diff viewer mode preference
107
+ }
108
+ }, []);
109
+ const getActionColor = action => {
110
+ switch (action) {
111
+ case "setItem":
112
+ case "multiSet":
113
+ return _sharedUi.macOSColors.semantic.success;
114
+ case "removeItem":
115
+ case "multiRemove":
116
+ case "clear":
117
+ return _sharedUi.macOSColors.semantic.error;
118
+ case "mergeItem":
119
+ case "multiMerge":
120
+ return _sharedUi.macOSColors.semantic.info;
121
+ default:
122
+ return _sharedUi.macOSColors.text.muted;
123
+ }
124
+ };
125
+ const renderValueContent = (value, label, action) => {
126
+ const parsed = (0, _sharedUi.parseValue)(value);
127
+ const type = parsed === null ? "null" : parsed === undefined ? "undefined" : Array.isArray(parsed) ? "array" : typeof parsed;
128
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
129
+ style: styles.valueContent,
130
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
131
+ style: styles.valueHeader,
132
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
133
+ style: styles.valueLabel,
134
+ children: label
135
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
136
+ style: styles.valueHeaderBadges,
137
+ children: [action && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
138
+ style: [styles.actionBadge, {
139
+ backgroundColor: `${getActionColor(action)}20`
140
+ }],
141
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
142
+ style: [styles.actionText, {
143
+ color: getActionColor(action)
144
+ }],
145
+ children: (0, _storageActionHelpers.translateStorageAction)(action)
146
+ })
147
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
148
+ style: [styles.typeBadge],
149
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
150
+ style: styles.typeText,
151
+ children: type.toUpperCase()
152
+ })
153
+ })]
154
+ })]
155
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
156
+ style: styles.valueBox,
157
+ children: type === "object" || type === "array" ? parsed && (Array.isArray(parsed) && parsed.length > 0 || typeof parsed === "object" && Object.keys(parsed).length > 0) ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_dataViewer.DataViewer, {
158
+ title: "",
159
+ data: parsed,
160
+ showTypeFilter: false
161
+ }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
162
+ style: styles.valueText,
163
+ children: type === "array" ? "[]" : "{}"
164
+ }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
165
+ style: styles.valueText,
166
+ children: parsed === null ? "null" : parsed === undefined ? "undefined" : type === "string" ? `"${parsed}"` : String(parsed)
167
+ })
168
+ })]
169
+ });
170
+ };
171
+
172
+ // Get all events sorted by time
173
+ const navigationItems = conversation.events.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());
174
+ const totalEvents = navigationItems.length;
175
+
176
+ // Free tier limit - max event index accessible
177
+ const maxAccessibleEventIndex = isPro ? totalEvents - 1 : Math.min(FREE_TIER_EVENT_HISTORY_LIMIT - 1, totalEvents - 1);
178
+ const lockedEventCount = isPro ? 0 : Math.max(0, totalEvents - FREE_TIER_EVENT_HISTORY_LIMIT);
179
+
180
+ // Keep compare indices synced to selection
181
+ (0, _react.useEffect)(() => {
182
+ const newRight = Math.min(totalEvents - 1, Math.max(0, selectedEventIndex));
183
+ const newLeft = Math.max(0, Math.min(newRight - 1, selectedEventIndex - 1));
184
+ setLeftIndex(newLeft);
185
+ setRightIndex(newRight);
186
+ }, [selectedEventIndex, totalEvents]);
187
+
188
+ // Precise time HH:MM:SS.mmm
189
+ const formatTimeWithMs = (0, _react.useCallback)(date => {
190
+ const h = String(date.getHours()).padStart(2, "0");
191
+ const m = String(date.getMinutes()).padStart(2, "0");
192
+ const s = String(date.getSeconds()).padStart(2, "0");
193
+ const ms = String(date.getMilliseconds()).padStart(3, "0");
194
+ return `${h}:${m}:${s}.${ms}`;
195
+ }, []);
196
+ const bumpLeft = delta => {
197
+ if (totalEvents < 2) return;
198
+ const maxLeft = isPro ? totalEvents - 2 : Math.min(maxAccessibleEventIndex - 1, totalEvents - 2);
199
+ let next = Math.max(0, Math.min(maxLeft, leftIndex + delta));
200
+ if (next >= rightIndex) next = Math.max(0, rightIndex - 1);
201
+ setLeftIndex(next);
202
+ };
203
+ const bumpRight = delta => {
204
+ if (totalEvents < 2) return;
205
+ const maxRight = isPro ? totalEvents - 1 : maxAccessibleEventIndex;
206
+ let next = Math.max(1, Math.min(maxRight, rightIndex + delta));
207
+ if (next <= leftIndex) next = Math.min(maxRight, leftIndex + 1);
208
+ setRightIndex(next);
209
+ };
210
+
211
+ // Render current value tab
212
+ const renderCurrentValue = () => {
213
+ const selectedEvent = navigationItems[selectedEventIndex];
214
+ const valueToShow = selectedEvent?.data?.value ?? conversation.currentValue;
215
+ const action = selectedEvent?.action;
216
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
217
+ style: styles.fullPageSection,
218
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
219
+ style: styles.contentCard,
220
+ children: renderValueContent(valueToShow, "CURRENT VALUE", action)
221
+ })
222
+ });
223
+ };
224
+
225
+ // Render diff tab
226
+ const renderDiff = () => {
227
+ if (navigationItems.length === 0) {
228
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
229
+ style: styles.emptyState,
230
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.AlertCircle, {
231
+ size: 32,
232
+ color: _sharedUi.macOSColors.text.muted
233
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
234
+ style: styles.emptyText,
235
+ children: "No changes to display"
236
+ })]
237
+ });
238
+ }
239
+ const leftEvent = navigationItems[Math.max(0, Math.min(totalEvents - 1, leftIndex))];
240
+ const rightEvent = navigationItems[Math.max(0, Math.min(totalEvents - 1, rightIndex))];
241
+ const previousValue = leftEvent?.data?.value ?? null;
242
+ const currentValue = rightEvent?.data?.value;
243
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
244
+ style: styles.fullPageSection,
245
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
246
+ style: styles.diffViewerTabs,
247
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
248
+ style: [styles.diffViewerTab, diffViewerTab === "split" && styles.diffViewerTabActive],
249
+ onPress: () => handleDiffModeChange("split"),
250
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
251
+ style: [styles.diffViewerTabText, diffViewerTab === "split" && styles.diffViewerTabTextActive],
252
+ children: "SPLIT VIEW"
253
+ })
254
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
255
+ style: [styles.diffViewerTab, diffViewerTab === "tree" && styles.diffViewerTabActive],
256
+ onPress: () => handleDiffModeChange("tree"),
257
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
258
+ style: [styles.diffViewerTabText, diffViewerTab === "tree" && styles.diffViewerTabTextActive],
259
+ children: "TREE VIEW"
260
+ })
261
+ })]
262
+ }), totalEvents > 0 && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
263
+ style: styles.compareBar,
264
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
265
+ style: styles.compareSide,
266
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
267
+ style: styles.compareLabelRow,
268
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
269
+ style: [styles.compareLabel, {
270
+ color: _sharedUi.macOSColors.semantic.debug
271
+ }],
272
+ children: "PREV"
273
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
274
+ style: [styles.compareActionBadge, {
275
+ backgroundColor: `${getActionColor(leftEvent.action)}20`
276
+ }],
277
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
278
+ style: [styles.compareActionText, {
279
+ color: getActionColor(leftEvent.action)
280
+ }],
281
+ children: (0, _storageActionHelpers.translateStorageAction)(leftEvent.action)
282
+ })
283
+ })]
284
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
285
+ style: styles.compareControls,
286
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
287
+ onPress: () => bumpLeft(-1),
288
+ disabled: leftIndex <= 0,
289
+ style: [styles.compareBtn, leftIndex <= 0 && styles.compareBtnDisabled],
290
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ChevronLeft, {
291
+ size: 14,
292
+ color: leftIndex <= 0 ? _sharedUi.macOSColors.text.muted : _sharedUi.macOSColors.text.secondary
293
+ })
294
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
295
+ style: styles.compareMeta,
296
+ onPress: () => setIsLeftPickerOpen(true),
297
+ activeOpacity: 0.8,
298
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
299
+ style: styles.compareIndex,
300
+ children: ["#", leftIndex + 1, " / ", totalEvents]
301
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
302
+ style: styles.compareTime,
303
+ children: formatTimeWithMs(leftEvent.timestamp)
304
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
305
+ style: styles.compareRelative,
306
+ children: ["(", (0, _sharedUi.formatRelativeTime)(leftEvent.timestamp), ")"]
307
+ })]
308
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
309
+ onPress: () => bumpLeft(1),
310
+ disabled: leftIndex >= rightIndex - 1,
311
+ style: [styles.compareBtn, leftIndex >= rightIndex - 1 && styles.compareBtnDisabled],
312
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ChevronRight, {
313
+ size: 14,
314
+ color: leftIndex >= rightIndex - 1 ? _sharedUi.macOSColors.text.muted : _sharedUi.macOSColors.text.secondary
315
+ })
316
+ })]
317
+ })]
318
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
319
+ style: styles.compareDivider
320
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
321
+ style: styles.compareSide,
322
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
323
+ style: styles.compareLabelRow,
324
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
325
+ style: [styles.compareLabel, {
326
+ color: _sharedUi.macOSColors.semantic.success
327
+ }],
328
+ children: "CUR"
329
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
330
+ style: [styles.compareActionBadge, {
331
+ backgroundColor: `${getActionColor(rightEvent.action)}20`
332
+ }],
333
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
334
+ style: [styles.compareActionText, {
335
+ color: getActionColor(rightEvent.action)
336
+ }],
337
+ children: (0, _storageActionHelpers.translateStorageAction)(rightEvent.action)
338
+ })
339
+ })]
340
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
341
+ style: styles.compareControls,
342
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
343
+ onPress: () => bumpRight(-1),
344
+ disabled: rightIndex <= leftIndex + 1,
345
+ style: [styles.compareBtn, rightIndex <= leftIndex + 1 && styles.compareBtnDisabled],
346
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ChevronLeft, {
347
+ size: 14,
348
+ color: rightIndex <= leftIndex + 1 ? _sharedUi.macOSColors.text.muted : _sharedUi.macOSColors.text.secondary
349
+ })
350
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
351
+ style: styles.compareMeta,
352
+ onPress: () => setIsRightPickerOpen(true),
353
+ activeOpacity: 0.8,
354
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
355
+ style: styles.compareIndex,
356
+ children: ["#", rightIndex + 1, " / ", totalEvents]
357
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
358
+ style: styles.compareTime,
359
+ children: formatTimeWithMs(rightEvent.timestamp)
360
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
361
+ style: styles.compareRelative,
362
+ children: ["(", (0, _sharedUi.formatRelativeTime)(rightEvent.timestamp), ")"]
363
+ })]
364
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
365
+ onPress: () => bumpRight(1),
366
+ disabled: rightIndex >= totalEvents - 1,
367
+ style: [styles.compareBtn, rightIndex >= totalEvents - 1 && styles.compareBtnDisabled],
368
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ChevronRight, {
369
+ size: 14,
370
+ color: rightIndex >= totalEvents - 1 ? _sharedUi.macOSColors.text.muted : _sharedUi.macOSColors.text.secondary
371
+ })
372
+ })]
373
+ })]
374
+ })]
375
+ }), diffViewerTab === "split" && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.ScrollView, {
376
+ style: {
377
+ flex: 1
378
+ },
379
+ showsVerticalScrollIndicator: true,
380
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_ThemedSplitView.ThemedSplitView, {
381
+ oldValue: (0, _sharedUi.parseValue)(previousValue),
382
+ newValue: (0, _sharedUi.parseValue)(currentValue),
383
+ differences: [],
384
+ theme: _diffThemes.diffThemes.devToolsDefault,
385
+ options: {
386
+ hideLineNumbers: false,
387
+ disableWordDiff: false,
388
+ showDiffOnly: false,
389
+ compareMethod: "words",
390
+ contextLines: 3,
391
+ lineOffset: 0
392
+ },
393
+ showThemeName: false
394
+ })
395
+ }), diffViewerTab === "tree" && /*#__PURE__*/(0, _jsxRuntime.jsx)(_TreeDiffViewer.TreeDiffViewer, {
396
+ oldValue: (0, _sharedUi.parseValue)(previousValue),
397
+ newValue: (0, _sharedUi.parseValue)(currentValue)
398
+ })]
399
+ });
400
+ };
401
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
402
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
403
+ style: [styles.contentOnly, {
404
+ flex: 1,
405
+ paddingBottom: !disableInternalFooter && totalEvents > 1 ? 80 : 0
406
+ }],
407
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
408
+ style: styles.viewToggleContainer,
409
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
410
+ style: [styles.viewToggleCard, internalActiveView === "current" && styles.viewToggleCardActive],
411
+ onPress: () => handleViewChange("current"),
412
+ activeOpacity: 0.8,
413
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
414
+ style: styles.viewToggleContent,
415
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Database, {
416
+ size: 16,
417
+ color: internalActiveView === "current" ? _sharedUi.macOSColors.semantic.info : _sharedUi.macOSColors.text.secondary
418
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
419
+ style: [styles.viewToggleLabel, internalActiveView === "current" && styles.viewToggleLabelActive],
420
+ children: "CURRENT VALUE"
421
+ })]
422
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
423
+ style: [styles.viewToggleDescription, internalActiveView === "current" && {
424
+ color: _sharedUi.macOSColors.text.primary
425
+ }],
426
+ children: "View the current stored value"
427
+ })]
428
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
429
+ style: [styles.viewToggleCard, internalActiveView === "diff" && styles.viewToggleCardActive],
430
+ onPress: () => handleViewChange("diff"),
431
+ activeOpacity: 0.8,
432
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
433
+ style: styles.viewToggleContent,
434
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.GitBranch, {
435
+ size: 16,
436
+ color: internalActiveView === "diff" ? _sharedUi.macOSColors.semantic.success : _sharedUi.macOSColors.text.secondary
437
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
438
+ style: [styles.viewToggleLabel, internalActiveView === "diff" && styles.viewToggleLabelActive],
439
+ children: "DIFF VIEW"
440
+ })]
441
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
442
+ style: [styles.viewToggleDescription, internalActiveView === "diff" && {
443
+ color: _sharedUi.macOSColors.text.primary
444
+ }],
445
+ children: "Compare changes between versions"
446
+ })]
447
+ })]
448
+ }), lockedEventCount > 0 && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
449
+ style: styles.lockedEventsBannerGlobal,
450
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Lock, {
451
+ size: 14,
452
+ color: _sharedUi.macOSColors.semantic.warning
453
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
454
+ style: styles.lockedEventsBannerText,
455
+ children: [lockedEventCount, " older ", lockedEventCount === 1 ? 'event' : 'events', " locked"]
456
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
457
+ style: styles.lockedEventsBannerSubtext,
458
+ children: "Upgrade to Pro for full history"
459
+ })]
460
+ }), internalActiveView === "current" && renderCurrentValue(), internalActiveView === "diff" && renderDiff()]
461
+ }), (isLeftPickerOpen || isRightPickerOpen) && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
462
+ style: styles.pickerOverlay,
463
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
464
+ style: styles.pickerBackdrop,
465
+ activeOpacity: 1,
466
+ onPress: () => {
467
+ setIsLeftPickerOpen(false);
468
+ setIsRightPickerOpen(false);
469
+ }
470
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
471
+ style: [styles.pickerCard, isLeftPickerOpen && styles.pickerCardLeft, isRightPickerOpen && styles.pickerCardRight],
472
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
473
+ style: styles.pickerHeader,
474
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
475
+ style: [styles.pickerTitle, isLeftPickerOpen && styles.pickerTitleLeft, isRightPickerOpen && styles.pickerTitleRight],
476
+ children: ["Select ", isLeftPickerOpen ? "PREV" : "CUR", " Event"]
477
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
478
+ onPress: () => {
479
+ setIsLeftPickerOpen(false);
480
+ setIsRightPickerOpen(false);
481
+ },
482
+ style: styles.pickerClose,
483
+ accessibilityLabel: "Close event picker",
484
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.X, {
485
+ size: 16,
486
+ color: _sharedUi.macOSColors.text.secondary
487
+ })
488
+ })]
489
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
490
+ style: styles.pickerDivider
491
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.ScrollView, {
492
+ style: styles.pickerScroll,
493
+ contentContainerStyle: styles.pickerList,
494
+ showsVerticalScrollIndicator: true,
495
+ nestedScrollEnabled: true,
496
+ children: navigationItems.slice(0, maxAccessibleEventIndex + 1).map((item, idx) => {
497
+ const disabled = isLeftPickerOpen ? idx >= rightIndex : idx <= leftIndex;
498
+ const isSelected = isLeftPickerOpen ? idx === leftIndex : idx === rightIndex;
499
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
500
+ disabled: disabled,
501
+ onPress: () => {
502
+ if (isLeftPickerOpen) {
503
+ setLeftIndex(Math.min(idx, rightIndex - 1));
504
+ setIsLeftPickerOpen(false);
505
+ } else {
506
+ setRightIndex(Math.max(idx, leftIndex + 1));
507
+ setIsRightPickerOpen(false);
508
+ }
509
+ },
510
+ style: [styles.pickerItem, isSelected && styles.pickerItemSelected, isSelected && isLeftPickerOpen && styles.pickerItemSelectedLeft, isSelected && isRightPickerOpen && styles.pickerItemSelectedRight, disabled && styles.pickerItemDisabled],
511
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
512
+ style: styles.pickerIndex,
513
+ children: ["#", idx + 1]
514
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
515
+ style: styles.pickerTime,
516
+ children: formatTimeWithMs(item.timestamp)
517
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
518
+ style: styles.pickerRelative,
519
+ children: ["(", (0, _sharedUi.formatRelativeTime)(item.timestamp), ")"]
520
+ }), (() => {
521
+ const targetOld = isLeftPickerOpen ? item : navigationItems[leftIndex];
522
+ const targetNew = isLeftPickerOpen ? navigationItems[rightIndex] : item;
523
+ const oldVal = (0, _sharedUi.parseValue)(targetOld.data?.value);
524
+ const newVal = (0, _sharedUi.parseValue)(targetNew.data?.value);
525
+ const diffs = (0, _lineDiff.computeLineDiff)(oldVal, newVal, {
526
+ compareMethod: "words",
527
+ disableWordDiff: false,
528
+ showDiffOnly: false,
529
+ contextLines: 0
530
+ });
531
+ const added = diffs.filter(d => d.type === _lineDiff.DiffType.ADDED).length;
532
+ const removed = diffs.filter(d => d.type === _lineDiff.DiffType.REMOVED).length;
533
+ const modified = diffs.filter(d => d.type === _lineDiff.DiffType.MODIFIED).length;
534
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
535
+ style: styles.pickerCounts,
536
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
537
+ style: [styles.pickerCountText, {
538
+ color: _diffThemes.diffThemes.devToolsDefault.summaryAddedText
539
+ }],
540
+ children: ["+", added]
541
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
542
+ style: [styles.pickerCountText, {
543
+ color: _diffThemes.diffThemes.devToolsDefault.summaryRemovedText
544
+ }],
545
+ children: ["-", removed]
546
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
547
+ style: [styles.pickerCountText, {
548
+ color: _diffThemes.diffThemes.devToolsDefault.summaryModifiedText
549
+ }],
550
+ children: ["~", modified]
551
+ })]
552
+ });
553
+ })()]
554
+ }, idx);
555
+ })
556
+ })]
557
+ })]
558
+ }), !disableInternalFooter && /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.EventStepperFooter, {
559
+ currentIndex: selectedEventIndex,
560
+ totalItems: totalEvents,
561
+ onPrevious: () => onEventIndexChange(Math.max(0, selectedEventIndex - 1)),
562
+ onNext: () => onEventIndexChange(Math.min(totalEvents - 1, selectedEventIndex + 1)),
563
+ itemLabel: "Event",
564
+ subtitle: (0, _sharedUi.formatRelativeTime)(navigationItems[selectedEventIndex]?.timestamp),
565
+ absolute: true
566
+ })]
567
+ });
568
+ }
569
+
570
+ // External footer component to be rendered by the modal outside the ScrollView
571
+ function StorageEventDetailFooter({
572
+ conversation,
573
+ selectedEventIndex = 0,
574
+ onEventIndexChange = () => {}
575
+ }) {
576
+ // Check Pro status internally
577
+ const useIsPro = getUseIsPro();
578
+ const isPro = useIsPro();
579
+ const navigationItems = conversation.events.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());
580
+ const totalEvents = navigationItems.length;
581
+
582
+ // Free tier limit for navigation
583
+ const maxAccessibleIndex = isPro ? totalEvents - 1 : Math.min(FREE_TIER_EVENT_HISTORY_LIMIT - 1, totalEvents - 1);
584
+ const lockedCount = isPro ? 0 : Math.max(0, totalEvents - FREE_TIER_EVENT_HISTORY_LIMIT);
585
+
586
+ // Calculate display total (accessible events for free users)
587
+ const displayTotal = isPro ? totalEvents : Math.min(totalEvents, FREE_TIER_EVENT_HISTORY_LIMIT);
588
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.EventStepperFooter, {
589
+ currentIndex: selectedEventIndex,
590
+ totalItems: displayTotal,
591
+ onPrevious: () => onEventIndexChange(Math.max(0, selectedEventIndex - 1)),
592
+ onNext: () => onEventIndexChange(Math.min(maxAccessibleIndex, selectedEventIndex + 1)),
593
+ itemLabel: "Event",
594
+ subtitle: lockedCount > 0 ? `${(0, _sharedUi.formatRelativeTime)(navigationItems[selectedEventIndex]?.timestamp)} • ${lockedCount} locked` : (0, _sharedUi.formatRelativeTime)(navigationItems[selectedEventIndex]?.timestamp)
595
+ });
596
+ }
597
+ const styles = _reactNative.StyleSheet.create({
598
+ contentOnly: {
599
+ flex: 1,
600
+ backgroundColor: _sharedUi.macOSColors.background.base
601
+ },
602
+ fullPageSection: {
603
+ flex: 1,
604
+ paddingHorizontal: 14,
605
+ paddingVertical: 10
606
+ },
607
+ emptyState: {
608
+ flex: 1,
609
+ alignItems: "center",
610
+ justifyContent: "center",
611
+ paddingVertical: 48
612
+ },
613
+ emptyText: {
614
+ marginTop: 12,
615
+ fontSize: 14,
616
+ color: _sharedUi.macOSColors.text.secondary,
617
+ fontFamily: "monospace"
618
+ },
619
+ card: {
620
+ backgroundColor: _sharedUi.macOSColors.background.card,
621
+ borderRadius: 14,
622
+ padding: 14,
623
+ borderWidth: 1,
624
+ borderColor: _sharedUi.macOSColors.border.default
625
+ },
626
+ valueContent: {
627
+ marginTop: 4
628
+ },
629
+ valueHeader: {
630
+ flexDirection: "row",
631
+ alignItems: "center",
632
+ justifyContent: "space-between",
633
+ marginBottom: 4
634
+ },
635
+ valueLabel: {
636
+ fontSize: 10,
637
+ color: _sharedUi.macOSColors.text.secondary,
638
+ fontFamily: "monospace",
639
+ letterSpacing: 0.5,
640
+ fontWeight: "600",
641
+ textTransform: "uppercase"
642
+ },
643
+ valueHeaderBadges: {
644
+ flexDirection: "row",
645
+ alignItems: "center",
646
+ gap: 6
647
+ },
648
+ actionBadge: {
649
+ paddingHorizontal: 8,
650
+ paddingVertical: 2,
651
+ borderRadius: 4,
652
+ borderWidth: 1,
653
+ borderColor: "transparent"
654
+ },
655
+ actionText: {
656
+ fontSize: 9,
657
+ fontWeight: "700",
658
+ fontFamily: "monospace",
659
+ letterSpacing: 0.3
660
+ },
661
+ typeBadge: {
662
+ paddingHorizontal: 8,
663
+ paddingVertical: 2,
664
+ borderRadius: 4,
665
+ backgroundColor: _sharedUi.macOSColors.background.input
666
+ },
667
+ typeText: {
668
+ fontSize: 9,
669
+ fontWeight: "600",
670
+ color: _sharedUi.macOSColors.text.muted,
671
+ fontFamily: "monospace"
672
+ },
673
+ valueBox: {
674
+ backgroundColor: _sharedUi.macOSColors.background.card,
675
+ borderRadius: 6,
676
+ borderWidth: 1,
677
+ borderColor: _sharedUi.macOSColors.border.input,
678
+ padding: 8
679
+ },
680
+ valueText: {
681
+ fontSize: 12,
682
+ color: _sharedUi.macOSColors.text.primary,
683
+ fontFamily: "monospace",
684
+ lineHeight: 18
685
+ },
686
+ // Compare picker styles
687
+ compareBar: {
688
+ flexDirection: "row",
689
+ alignItems: "center",
690
+ justifyContent: "space-between",
691
+ backgroundColor: _sharedUi.macOSColors.background.card,
692
+ borderWidth: 1,
693
+ borderColor: _sharedUi.macOSColors.border.default,
694
+ borderRadius: 6,
695
+ paddingHorizontal: 8,
696
+ paddingVertical: 6,
697
+ marginBottom: 8,
698
+ gap: 8
699
+ },
700
+ compareSide: {
701
+ flex: 1
702
+ },
703
+ compareLabelRow: {
704
+ flexDirection: "row",
705
+ alignItems: "center",
706
+ gap: 6,
707
+ marginBottom: 2
708
+ },
709
+ compareLabel: {
710
+ fontSize: 10,
711
+ fontFamily: "monospace",
712
+ fontWeight: "700",
713
+ letterSpacing: 0.5,
714
+ textTransform: "uppercase"
715
+ },
716
+ compareActionBadge: {
717
+ paddingHorizontal: 6,
718
+ paddingVertical: 1,
719
+ borderRadius: 3
720
+ },
721
+ compareActionText: {
722
+ fontSize: 8,
723
+ fontWeight: "700",
724
+ fontFamily: "monospace",
725
+ letterSpacing: 0.3
726
+ },
727
+ compareControls: {
728
+ flexDirection: "row",
729
+ alignItems: "center",
730
+ gap: 6
731
+ },
732
+ compareBtn: {
733
+ width: 26,
734
+ height: 26,
735
+ borderRadius: 6,
736
+ backgroundColor: _sharedUi.macOSColors.background.card,
737
+ borderWidth: 1,
738
+ borderColor: _sharedUi.macOSColors.border.default,
739
+ alignItems: "center",
740
+ justifyContent: "center"
741
+ },
742
+ compareBtnDisabled: {
743
+ opacity: 0.4
744
+ },
745
+ compareMeta: {
746
+ flex: 1
747
+ },
748
+ compareTime: {
749
+ fontSize: 11,
750
+ color: _sharedUi.macOSColors.text.primary,
751
+ fontFamily: "monospace"
752
+ },
753
+ compareIndex: {
754
+ fontSize: 10,
755
+ color: _sharedUi.macOSColors.text.secondary,
756
+ fontFamily: "monospace"
757
+ },
758
+ compareRelative: {
759
+ fontSize: 10,
760
+ color: _sharedUi.macOSColors.text.secondary,
761
+ fontFamily: "monospace"
762
+ },
763
+ compareDivider: {
764
+ width: 1,
765
+ height: 34,
766
+ backgroundColor: _sharedUi.macOSColors.background.input
767
+ },
768
+ pickerOverlay: {
769
+ ..._reactNative.StyleSheet.absoluteFillObject,
770
+ zIndex: 20,
771
+ justifyContent: "center",
772
+ alignItems: "center"
773
+ },
774
+ pickerBackdrop: {
775
+ ..._reactNative.StyleSheet.absoluteFillObject,
776
+ backgroundColor: "rgba(0,0,0,0.65)"
777
+ },
778
+ pickerCard: {
779
+ width: "86%",
780
+ maxHeight: 320,
781
+ backgroundColor: _sharedUi.macOSColors.background.card,
782
+ borderRadius: 16,
783
+ borderWidth: 2,
784
+ padding: 16,
785
+ shadowOffset: {
786
+ width: 0,
787
+ height: 0
788
+ },
789
+ shadowOpacity: 0.5,
790
+ shadowRadius: 40,
791
+ elevation: 15
792
+ },
793
+ pickerCardLeft: {
794
+ borderColor: _sharedUi.macOSColors.semantic.debug,
795
+ shadowColor: _sharedUi.macOSColors.semantic.debug
796
+ },
797
+ pickerCardRight: {
798
+ borderColor: _sharedUi.macOSColors.semantic.success,
799
+ shadowColor: _sharedUi.macOSColors.semantic.success
800
+ },
801
+ pickerHeader: {
802
+ flexDirection: "row",
803
+ alignItems: "center",
804
+ justifyContent: "space-between"
805
+ },
806
+ pickerClose: {
807
+ padding: 6,
808
+ borderRadius: 6,
809
+ backgroundColor: _sharedUi.macOSColors.background.card,
810
+ borderWidth: 1,
811
+ borderColor: _sharedUi.macOSColors.border.default
812
+ },
813
+ pickerDivider: {
814
+ height: 1,
815
+ backgroundColor: _sharedUi.macOSColors.background.input,
816
+ marginVertical: 8
817
+ },
818
+ pickerScroll: {
819
+ maxHeight: 260
820
+ },
821
+ pickerTitle: {
822
+ fontSize: 13,
823
+ fontWeight: "700",
824
+ fontFamily: "monospace",
825
+ textTransform: "uppercase",
826
+ marginBottom: 8,
827
+ letterSpacing: 0.6
828
+ },
829
+ pickerTitleLeft: {
830
+ color: _sharedUi.macOSColors.semantic.debug
831
+ },
832
+ pickerTitleRight: {
833
+ color: _sharedUi.macOSColors.semantic.success
834
+ },
835
+ pickerList: {
836
+ gap: 4
837
+ },
838
+ pickerItem: {
839
+ paddingVertical: 10,
840
+ paddingHorizontal: 12,
841
+ borderRadius: 10,
842
+ backgroundColor: _sharedUi.macOSColors.background.base,
843
+ borderWidth: 1,
844
+ borderColor: _sharedUi.macOSColors.border.default,
845
+ flexDirection: "row",
846
+ alignItems: "center",
847
+ gap: 8,
848
+ marginBottom: 6
849
+ },
850
+ pickerItemSelected: {
851
+ borderWidth: 1.5,
852
+ shadowOffset: {
853
+ width: 0,
854
+ height: 2
855
+ },
856
+ shadowOpacity: 0.25,
857
+ shadowRadius: 12,
858
+ elevation: 4
859
+ },
860
+ pickerItemSelectedLeft: {
861
+ backgroundColor: _sharedUi.macOSColors.semantic.debug + "1A",
862
+ borderColor: _sharedUi.macOSColors.semantic.debug,
863
+ shadowColor: _sharedUi.macOSColors.semantic.debug
864
+ },
865
+ pickerItemSelectedRight: {
866
+ backgroundColor: _sharedUi.macOSColors.semantic.successBackground + "30",
867
+ borderColor: _sharedUi.macOSColors.semantic.success,
868
+ shadowColor: _sharedUi.macOSColors.semantic.success
869
+ },
870
+ pickerItemDisabled: {
871
+ opacity: 0.4
872
+ },
873
+ pickerIndex: {
874
+ fontSize: 10,
875
+ color: _sharedUi.macOSColors.text.secondary,
876
+ fontFamily: "monospace",
877
+ width: 40
878
+ },
879
+ pickerTime: {
880
+ fontSize: 11,
881
+ color: _sharedUi.macOSColors.text.primary,
882
+ fontFamily: "monospace",
883
+ flex: 1
884
+ },
885
+ pickerRelative: {
886
+ fontSize: 10,
887
+ color: _sharedUi.macOSColors.text.secondary,
888
+ fontFamily: "monospace"
889
+ },
890
+ pickerCounts: {
891
+ flexDirection: "row",
892
+ alignItems: "center",
893
+ gap: 8,
894
+ marginLeft: "auto"
895
+ },
896
+ pickerCountText: {
897
+ fontSize: 10,
898
+ fontFamily: "monospace",
899
+ fontWeight: "700"
900
+ },
901
+ diffViewerTabs: {
902
+ flexDirection: "row",
903
+ alignItems: "center",
904
+ justifyContent: "space-around",
905
+ backgroundColor: _sharedUi.macOSColors.background.card,
906
+ borderWidth: 1,
907
+ borderColor: _sharedUi.macOSColors.border.default,
908
+ borderRadius: 6,
909
+ paddingHorizontal: 4,
910
+ paddingVertical: 4,
911
+ marginBottom: 8,
912
+ gap: 4
913
+ },
914
+ diffViewerTab: {
915
+ flex: 1,
916
+ paddingVertical: 8,
917
+ paddingHorizontal: 12,
918
+ borderRadius: 4,
919
+ alignItems: "center",
920
+ backgroundColor: "transparent"
921
+ },
922
+ diffViewerTabActive: {
923
+ backgroundColor: _sharedUi.macOSColors.semantic.infoBackground,
924
+ borderWidth: 1,
925
+ borderColor: _sharedUi.macOSColors.semantic.info + "40"
926
+ },
927
+ diffViewerTabText: {
928
+ fontSize: 11,
929
+ fontFamily: "monospace",
930
+ fontWeight: "600",
931
+ color: _sharedUi.macOSColors.text.secondary,
932
+ letterSpacing: 0.5
933
+ },
934
+ diffViewerTabTextActive: {
935
+ color: _sharedUi.macOSColors.text.primary
936
+ },
937
+ contentCard: {
938
+ backgroundColor: _sharedUi.macOSColors.background.card,
939
+ borderRadius: 14,
940
+ padding: 14,
941
+ borderWidth: 1,
942
+ borderColor: _sharedUi.macOSColors.border.default,
943
+ shadowColor: _sharedUi.macOSColors.semantic.info,
944
+ shadowOffset: {
945
+ width: 0,
946
+ height: 2
947
+ },
948
+ shadowOpacity: 0.04,
949
+ shadowRadius: 16,
950
+ elevation: 2
951
+ },
952
+ // View Toggle Cards
953
+ viewToggleContainer: {
954
+ flexDirection: "row",
955
+ gap: 12,
956
+ padding: 14,
957
+ backgroundColor: _sharedUi.macOSColors.background.base
958
+ },
959
+ viewToggleCard: {
960
+ flex: 1,
961
+ backgroundColor: _sharedUi.macOSColors.background.card,
962
+ borderRadius: 14,
963
+ borderWidth: 1,
964
+ borderColor: _sharedUi.macOSColors.border.default,
965
+ padding: 14,
966
+ gap: 8
967
+ },
968
+ viewToggleCardActive: {
969
+ borderWidth: 1.5,
970
+ borderColor: _sharedUi.macOSColors.semantic.info,
971
+ backgroundColor: _sharedUi.macOSColors.semantic.infoBackground + "30",
972
+ shadowColor: _sharedUi.macOSColors.semantic.info,
973
+ shadowOffset: {
974
+ width: 0,
975
+ height: 2
976
+ },
977
+ shadowOpacity: 0.1,
978
+ shadowRadius: 8,
979
+ elevation: 3
980
+ },
981
+ viewToggleContent: {
982
+ flexDirection: "row",
983
+ alignItems: "center",
984
+ gap: 8
985
+ },
986
+ viewToggleLabel: {
987
+ fontSize: 12,
988
+ fontWeight: "700",
989
+ letterSpacing: 0.5,
990
+ color: _sharedUi.macOSColors.text.secondary,
991
+ textTransform: "uppercase"
992
+ },
993
+ viewToggleLabelActive: {
994
+ color: _sharedUi.macOSColors.text.primary
995
+ },
996
+ viewToggleDescription: {
997
+ fontSize: 11,
998
+ color: _sharedUi.macOSColors.text.muted,
999
+ lineHeight: 16
1000
+ },
1001
+ lockedEventsBannerGlobal: {
1002
+ flexDirection: "row",
1003
+ alignItems: "center",
1004
+ gap: 8,
1005
+ backgroundColor: _sharedUi.macOSColors.semantic.warning + "15",
1006
+ borderWidth: 1,
1007
+ borderColor: _sharedUi.macOSColors.semantic.warning + "30",
1008
+ borderRadius: 10,
1009
+ paddingVertical: 12,
1010
+ paddingHorizontal: 14,
1011
+ marginHorizontal: 14,
1012
+ marginBottom: 4
1013
+ },
1014
+ lockedEventsBannerText: {
1015
+ fontSize: 12,
1016
+ fontWeight: "600",
1017
+ color: _sharedUi.macOSColors.semantic.warning,
1018
+ fontFamily: "monospace"
1019
+ },
1020
+ lockedEventsBannerSubtext: {
1021
+ fontSize: 11,
1022
+ color: _sharedUi.macOSColors.text.secondary,
1023
+ marginLeft: "auto"
1024
+ }
1025
+ });