@buoy-gg/core 1.7.8 → 2.1.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 (49) hide show
  1. package/lib/commonjs/Buoy.js +104 -0
  2. package/lib/commonjs/floatingMenu/AppHost.js +2 -2
  3. package/lib/commonjs/floatingMenu/DevToolsSettingsModal.js +18 -279
  4. package/lib/commonjs/floatingMenu/FloatingDevTools.js +8 -1
  5. package/lib/commonjs/floatingMenu/FloatingDevTools.web.js +1 -2
  6. package/lib/commonjs/floatingMenu/FloatingMenu.js +4 -4
  7. package/lib/commonjs/floatingMenu/MinimizedToolsContext.js +2 -2
  8. package/lib/commonjs/floatingMenu/autoDiscoverPresets.js +15 -0
  9. package/lib/commonjs/floatingMenu/dial/DialDevTools.js +4 -4
  10. package/lib/commonjs/floatingMenu/floatingTools.js +268 -74
  11. package/lib/commonjs/index.js +24 -8
  12. package/lib/module/Buoy.js +100 -0
  13. package/lib/module/floatingMenu/AppHost.js +3 -3
  14. package/lib/module/floatingMenu/DevToolsSettingsModal.js +20 -281
  15. package/lib/module/floatingMenu/FloatingDevTools.js +8 -1
  16. package/lib/module/floatingMenu/FloatingDevTools.web.js +1 -2
  17. package/lib/module/floatingMenu/FloatingMenu.js +5 -5
  18. package/lib/module/floatingMenu/MinimizedToolsContext.js +3 -3
  19. package/lib/module/floatingMenu/autoDiscoverPresets.js +15 -0
  20. package/lib/module/floatingMenu/dial/DialDevTools.js +5 -5
  21. package/lib/module/floatingMenu/floatingTools.js +269 -75
  22. package/lib/module/index.js +3 -1
  23. package/lib/typescript/commonjs/Buoy.d.ts +79 -0
  24. package/lib/typescript/commonjs/Buoy.d.ts.map +1 -0
  25. package/lib/typescript/commonjs/floatingMenu/DevToolsSettingsModal.d.ts.map +1 -1
  26. package/lib/typescript/commonjs/floatingMenu/FloatingDevTools.d.ts +25 -5
  27. package/lib/typescript/commonjs/floatingMenu/FloatingDevTools.d.ts.map +1 -1
  28. package/lib/typescript/commonjs/floatingMenu/FloatingDevTools.web.d.ts.map +1 -1
  29. package/lib/typescript/commonjs/floatingMenu/FloatingMenu.d.ts.map +1 -1
  30. package/lib/typescript/commonjs/floatingMenu/autoDiscoverPresets.d.ts.map +1 -1
  31. package/lib/typescript/commonjs/floatingMenu/dial/DialDevTools.d.ts.map +1 -1
  32. package/lib/typescript/commonjs/floatingMenu/floatingTools.d.ts +1 -1
  33. package/lib/typescript/commonjs/floatingMenu/floatingTools.d.ts.map +1 -1
  34. package/lib/typescript/commonjs/index.d.ts +4 -2
  35. package/lib/typescript/commonjs/index.d.ts.map +1 -1
  36. package/lib/typescript/module/Buoy.d.ts +79 -0
  37. package/lib/typescript/module/Buoy.d.ts.map +1 -0
  38. package/lib/typescript/module/floatingMenu/DevToolsSettingsModal.d.ts.map +1 -1
  39. package/lib/typescript/module/floatingMenu/FloatingDevTools.d.ts +25 -5
  40. package/lib/typescript/module/floatingMenu/FloatingDevTools.d.ts.map +1 -1
  41. package/lib/typescript/module/floatingMenu/FloatingDevTools.web.d.ts.map +1 -1
  42. package/lib/typescript/module/floatingMenu/FloatingMenu.d.ts.map +1 -1
  43. package/lib/typescript/module/floatingMenu/autoDiscoverPresets.d.ts.map +1 -1
  44. package/lib/typescript/module/floatingMenu/dial/DialDevTools.d.ts.map +1 -1
  45. package/lib/typescript/module/floatingMenu/floatingTools.d.ts +1 -1
  46. package/lib/typescript/module/floatingMenu/floatingTools.d.ts.map +1 -1
  47. package/lib/typescript/module/index.d.ts +4 -2
  48. package/lib/typescript/module/index.d.ts.map +1 -1
  49. package/package.json +5 -5
@@ -0,0 +1,104 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = exports.Buoy = void 0;
7
+ var _license = require("@buoy-gg/license");
8
+ /**
9
+ * Buoy SDK - Main entry point for React Buoy configuration
10
+ *
11
+ * Initialize once at app startup, before rendering any components:
12
+ *
13
+ * @example
14
+ * ```tsx
15
+ * import { Buoy } from '@buoy-gg/core';
16
+ *
17
+ * Buoy.init({
18
+ * licenseKey: 'YOUR_LICENSE_KEY',
19
+ * });
20
+ * ```
21
+ */
22
+
23
+ /**
24
+ * Buoy SDK namespace
25
+ *
26
+ * Use `Buoy.init()` to configure your license key at app startup.
27
+ */
28
+ const Buoy = exports.Buoy = {
29
+ /**
30
+ * Initialize Buoy with your license key
31
+ *
32
+ * Call this once at app startup, before rendering FloatingDevTools.
33
+ * Typically placed in App.tsx or index.js.
34
+ *
35
+ * @example
36
+ * ```tsx
37
+ * import { Buoy } from '@buoy-gg/core';
38
+ *
39
+ * // With hardcoded key
40
+ * Buoy.init({
41
+ * licenseKey: '36063C-27282E-8E73F5-55488F-2213DF-V3',
42
+ * });
43
+ *
44
+ * // With environment variable
45
+ * Buoy.init({
46
+ * licenseKey: process.env.BUOY_LICENSE_KEY!,
47
+ * });
48
+ * ```
49
+ */
50
+ init(config) {
51
+ if (!config.licenseKey) {
52
+ console.warn("[Buoy] No license key provided to Buoy.init()");
53
+ return;
54
+ }
55
+
56
+ // Initialize the license manager and set the key
57
+ _license.LicenseManager.initialize().then(() => _license.LicenseManager.setLicenseKey(config.licenseKey)).catch(error => {
58
+ console.warn("[Buoy] License initialization failed:", error);
59
+ });
60
+ },
61
+ /**
62
+ * Initialize Buoy asynchronously
63
+ *
64
+ * Use this if you need to wait for initialization to complete.
65
+ *
66
+ * @example
67
+ * ```tsx
68
+ * await Buoy.initAsync({
69
+ * licenseKey: 'YOUR_LICENSE_KEY',
70
+ * });
71
+ * console.log('Buoy is ready!');
72
+ * ```
73
+ */
74
+ async initAsync(config) {
75
+ if (!config.licenseKey) {
76
+ console.warn("[Buoy] No license key provided to Buoy.initAsync()");
77
+ return false;
78
+ }
79
+ await _license.LicenseManager.initialize();
80
+ return _license.LicenseManager.setLicenseKey(config.licenseKey);
81
+ },
82
+ /**
83
+ * Check if Buoy Pro is active
84
+ */
85
+ isPro() {
86
+ return _license.LicenseManager.isPro();
87
+ },
88
+ /**
89
+ * Get the current license state
90
+ */
91
+ getState() {
92
+ return _license.LicenseManager.getState();
93
+ },
94
+ /**
95
+ * Force device re-registration (debugging helper)
96
+ * Clears cached fingerprint so next init will register device again
97
+ */
98
+ async forceReregister() {
99
+ await _license.LicenseManager.forceReregister();
100
+ }
101
+ };
102
+
103
+ // Also export as default for flexibility
104
+ var _default = exports.default = Buoy;
@@ -92,7 +92,7 @@ const AppHostProvider = ({
92
92
  (0, _react.useEffect)(() => {
93
93
  const restoreOpenApps = async () => {
94
94
  try {
95
- const saved = await (0, _sharedUi.safeGetItem)(STORAGE_KEY_OPEN_APPS);
95
+ const saved = await _sharedUi.persistentStorage.getItem(STORAGE_KEY_OPEN_APPS);
96
96
  if (saved) {
97
97
  const parsed = JSON.parse(saved);
98
98
  // Handle both old format (string[]) and new format (PersistedAppState[])
@@ -138,7 +138,7 @@ const AppHostProvider = ({
138
138
  id: app.id,
139
139
  minimized: app.minimized ?? false
140
140
  }));
141
- (0, _sharedUi.safeSetItem)(STORAGE_KEY_OPEN_APPS, JSON.stringify(appStates));
141
+ _sharedUi.persistentStorage.setItem(STORAGE_KEY_OPEN_APPS, JSON.stringify(appStates));
142
142
  }, PERSISTENCE_DELAY);
143
143
  return () => {
144
144
  if (persistenceTimeoutRef.current) {
@@ -16,8 +16,6 @@ const MAX_DIAL_SLOTS = 6;
16
16
 
17
17
  // Lazy load license hooks to avoid circular dependencies
18
18
  let _useLicense = null;
19
- let _useSeats = null;
20
- let _useDevices = null;
21
19
  function getUseLicense() {
22
20
  if (!_useLicense) {
23
21
  try {
@@ -29,28 +27,6 @@ function getUseLicense() {
29
27
  }
30
28
  return _useLicense;
31
29
  }
32
- function getUseSeats() {
33
- if (!_useSeats) {
34
- try {
35
- const mod = require("@buoy-gg/license");
36
- _useSeats = mod.useSeats;
37
- } catch {
38
- // License package not available
39
- }
40
- }
41
- return _useSeats;
42
- }
43
- function getUseDevices() {
44
- if (!_useDevices) {
45
- try {
46
- const mod = require("@buoy-gg/license");
47
- _useDevices = mod.useDevices;
48
- } catch {
49
- // License package not available
50
- }
51
- }
52
- return _useDevices;
53
- }
54
30
  const enforceDialLimit = dialTools => {
55
31
  let remaining = MAX_DIAL_SLOTS;
56
32
  const limited = {};
@@ -178,13 +154,12 @@ const DevToolsSettingsModal = ({
178
154
  const [activeTabLoaded, setActiveTabLoaded] = (0, _react.useState)(false);
179
155
  const [expandedSettings, setExpandedSettings] = (0, _react.useState)(new Set());
180
156
  const [showLicenseModal, setShowLicenseModal] = (0, _react.useState)(false);
181
- const [licenseModalForDeviceRegistration, setLicenseModalForDeviceRegistration] = (0, _react.useState)(false);
182
157
 
183
158
  // Load persisted active tab on mount
184
159
  (0, _react.useEffect)(() => {
185
160
  const loadActiveTab = async () => {
186
161
  try {
187
- const savedTab = await (0, _sharedUi.safeGetItem)(_sharedUi.devToolsStorageKeys.settings.activeTab());
162
+ const savedTab = await _sharedUi.persistentStorage.getItem(_sharedUi.devToolsStorageKeys.settings.activeTab());
188
163
  if (savedTab && ["dial", "floating", "settings", "pro"].includes(savedTab)) {
189
164
  setActiveTab(savedTab);
190
165
  }
@@ -201,7 +176,7 @@ const DevToolsSettingsModal = ({
201
176
  (0, _react.useEffect)(() => {
202
177
  // Only persist after initial state is loaded to avoid overwriting with default
203
178
  if (!activeTabLoaded) return;
204
- (0, _sharedUi.safeSetItem)(_sharedUi.devToolsStorageKeys.settings.activeTab(), activeTab).catch(error => {
179
+ _sharedUi.persistentStorage.setItem(_sharedUi.devToolsStorageKeys.settings.activeTab(), activeTab).catch(error => {
205
180
  // Failed to save active tab - continue without persistence
206
181
  console.warn("Failed to save settings active tab:", error);
207
182
  });
@@ -209,22 +184,8 @@ const DevToolsSettingsModal = ({
209
184
 
210
185
  // License hooks
211
186
  const useLicenseHook = getUseLicense();
212
- const useSeatsHook = getUseSeats();
213
- const useDevicesHook = getUseDevices();
214
187
  const license = useLicenseHook?.();
215
- const seats = useSeatsHook?.();
216
- const devicesData = useDevicesHook?.();
217
188
  const isPro = license?.isPro ?? false;
218
-
219
- // Devices data
220
- const devices = devicesData?.devices ?? [];
221
- const devicesLoading = devicesData?.isLoading ?? false;
222
- const devicesError = devicesData?.error ?? null;
223
- const refreshDevices = devicesData?.refreshDevices;
224
- const registerDevice = devicesData?.registerDevice;
225
- const deactivateDevice = devicesData?.deactivateDevice;
226
- const isCurrentDeviceRegistered = devicesData?.isCurrentDeviceRegistered ?? false;
227
- const [deactivatingDeviceId, setDeactivatingDeviceId] = (0, _react.useState)(null);
228
189
  const [storageBackend, setStorageBackend] = (0, _react.useState)(null);
229
190
  const [isClearing, setIsClearing] = (0, _react.useState)(false);
230
191
  const [clearSuccess, setClearSuccess] = (0, _react.useState)(false);
@@ -244,7 +205,7 @@ const DevToolsSettingsModal = ({
244
205
 
245
206
  const loadSettings = (0, _react.useCallback)(async () => {
246
207
  try {
247
- const savedSettings = await (0, _sharedUi.safeGetItem)(STORAGE_KEY);
208
+ const savedSettings = await _sharedUi.persistentStorage.getItem(STORAGE_KEY);
248
209
  if (savedSettings) {
249
210
  const parsed = JSON.parse(savedSettings);
250
211
  const merged = mergeWithDefaults(defaultSettings, parsed, {
@@ -288,7 +249,7 @@ const DevToolsSettingsModal = ({
288
249
  ...newSettings,
289
250
  dialTools: enforceDialLimit(newSettings.dialTools)
290
251
  };
291
- await (0, _sharedUi.safeSetItem)(STORAGE_KEY, JSON.stringify(limitedSettings));
252
+ await _sharedUi.persistentStorage.setItem(STORAGE_KEY, JSON.stringify(limitedSettings));
292
253
  setSettings(limitedSettings);
293
254
  onSettingsChange?.(limitedSettings);
294
255
  // Notify listeners (e.g., floating bubble) to refresh immediately
@@ -394,51 +355,6 @@ const DevToolsSettingsModal = ({
394
355
  setTimeout(() => setCopySuccess(false), 2000);
395
356
  }
396
357
  };
397
- const handleRemoveDevice = async (deviceId, deviceName, isCurrentDevice) => {
398
- if (!deactivateDevice) return;
399
- const message = isCurrentDevice ? "This will remove your current device. You'll need to re-register to use Pro features on this device." : `Remove "${deviceName}" from your license?`;
400
- const {
401
- Alert
402
- } = require("react-native");
403
- const doRemove = await new Promise(resolve => {
404
- Alert.alert("Remove Device", message, [{
405
- text: "Cancel",
406
- style: "cancel",
407
- onPress: () => resolve(false)
408
- }, {
409
- text: "Remove",
410
- style: "destructive",
411
- onPress: () => resolve(true)
412
- }]);
413
- });
414
- if (!doRemove) return;
415
- setDeactivatingDeviceId(deviceId);
416
- try {
417
- await deactivateDevice(deviceId);
418
- } catch (error) {
419
- console.error("Failed to remove device:", error);
420
- } finally {
421
- setDeactivatingDeviceId(null);
422
- }
423
- };
424
- const handleRegisterDevice = () => {
425
- // Open the license modal in device registration mode (skip license key entry)
426
- setLicenseModalForDeviceRegistration(true);
427
- setShowLicenseModal(true);
428
- };
429
- const formatDeviceDate = date => {
430
- const now = new Date();
431
- const diffMs = now.getTime() - date.getTime();
432
- const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));
433
- if (diffDays === 0) return "Today";
434
- if (diffDays === 1) return "Yesterday";
435
- if (diffDays < 7) return `${diffDays} days ago`;
436
- return date.toLocaleDateString(undefined, {
437
- month: "short",
438
- day: "numeric",
439
- year: date.getFullYear() !== now.getFullYear() ? "numeric" : undefined
440
- });
441
- };
442
358
 
443
359
  // Modal is fixed to bottom sheet mode
444
360
  const handleModeChange = (0, _react.useCallback)(_mode => {
@@ -1031,8 +947,8 @@ const DevToolsSettingsModal = ({
1031
947
  })]
1032
948
  }), activeTab === "pro" && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
1033
949
  style: styles.proContainer,
1034
- children: isPro ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
1035
- children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
950
+ children: isPro ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_jsxRuntime.Fragment, {
951
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
1036
952
  style: styles.proSection,
1037
953
  children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_sharedUi.SectionHeader, {
1038
954
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.SectionHeader.Icon, {
@@ -1047,173 +963,12 @@ const DevToolsSettingsModal = ({
1047
963
  })]
1048
964
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
1049
965
  style: styles.proSectionContent,
1050
- children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
1051
- style: styles.proStatsRow,
1052
- children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
1053
- style: styles.proStatItem,
1054
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1055
- style: styles.proStatValue,
1056
- children: seats?.used ?? 0
1057
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1058
- style: styles.proStatLabel,
1059
- children: "USED"
1060
- })]
1061
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
1062
- style: styles.proStatDivider
1063
- }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
1064
- style: styles.proStatItem,
1065
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1066
- style: styles.proStatValue,
1067
- children: seats?.total ?? "∞"
1068
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1069
- style: styles.proStatLabel,
1070
- children: "LIMIT"
1071
- })]
1072
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
1073
- style: styles.proStatDivider
1074
- }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
1075
- style: styles.proStatItem,
1076
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1077
- style: [styles.proStatValue, (seats?.remaining ?? 0) <= 0 && styles.proStatValueDanger],
1078
- children: seats?.remaining ?? "∞"
1079
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1080
- style: styles.proStatLabel,
1081
- children: "AVAILABLE"
1082
- })]
1083
- })]
966
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
967
+ style: styles.proActiveDescription,
968
+ children: "You have full access to all Buoy DevTools features."
1084
969
  })
1085
970
  })]
1086
- }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
1087
- style: styles.proSection,
1088
- children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_sharedUi.SectionHeader, {
1089
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.SectionHeader.Icon, {
1090
- icon: _sharedUi.Smartphone,
1091
- color: _sharedUi.buoyColors.info,
1092
- size: 12
1093
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.SectionHeader.Title, {
1094
- children: "REGISTERED DEVICES"
1095
- }), devices.length > 0 && /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.SectionHeader.Badge, {
1096
- count: devices.length,
1097
- color: _sharedUi.buoyColors.info
1098
- }), refreshDevices && /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.SectionHeader.Actions, {
1099
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
1100
- onPress: () => refreshDevices(),
1101
- disabled: devicesLoading,
1102
- style: {
1103
- marginLeft: 8
1104
- },
1105
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.RefreshCw, {
1106
- size: 14,
1107
- color: devicesLoading ? _sharedUi.buoyColors.textMuted : _sharedUi.buoyColors.textSecondary
1108
- })
1109
- })
1110
- })]
1111
- }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
1112
- style: styles.proSectionContent,
1113
- children: [devicesLoading && devices.length === 0 ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
1114
- style: styles.proEmptyState,
1115
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1116
- style: styles.proEmptyStateText,
1117
- children: "Loading devices..."
1118
- })
1119
- }) : devicesError ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
1120
- style: styles.proErrorState,
1121
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.AlertTriangle, {
1122
- size: 16,
1123
- color: _sharedUi.buoyColors.error
1124
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1125
- style: styles.proErrorStateText,
1126
- children: devicesError
1127
- })]
1128
- }) : devices.length === 0 ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
1129
- style: styles.proEmptyState,
1130
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Smartphone, {
1131
- size: 24,
1132
- color: _sharedUi.buoyColors.textMuted
1133
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1134
- style: styles.proEmptyStateText,
1135
- children: "No devices registered"
1136
- })]
1137
- }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
1138
- style: styles.proDevicesList,
1139
- children: devices.map(device => /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
1140
- style: [styles.proDeviceRow, device.isCurrentDevice && styles.proDeviceRowCurrent],
1141
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
1142
- style: styles.proDeviceIcon,
1143
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Smartphone, {
1144
- size: 16,
1145
- color: _sharedUi.buoyColors.text
1146
- })
1147
- }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
1148
- style: styles.proDeviceInfo,
1149
- children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
1150
- style: styles.proDeviceNameRow,
1151
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1152
- style: styles.proDeviceName,
1153
- numberOfLines: 1,
1154
- children: device.name
1155
- }), device.isCurrentDevice && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
1156
- style: styles.proDeviceBadge,
1157
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1158
- style: styles.proDeviceBadgeText,
1159
- children: "THIS DEVICE"
1160
- })
1161
- })]
1162
- }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
1163
- style: styles.proDeviceDetails,
1164
- children: [device.platform, device.osVersion ? ` ${device.osVersion}` : "", device.model ? ` • ${device.model}` : ""]
1165
- }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
1166
- style: styles.proDeviceDate,
1167
- children: ["Registered ", formatDeviceDate(device.registeredAt)]
1168
- })]
1169
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
1170
- style: styles.proDeviceRemoveBtn,
1171
- onPress: () => handleRemoveDevice(device.id, device.name, device.isCurrentDevice),
1172
- disabled: deactivatingDeviceId === device.id,
1173
- children: deactivatingDeviceId === device.id ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.RefreshCw, {
1174
- size: 14,
1175
- color: _sharedUi.buoyColors.textMuted
1176
- }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Trash2, {
1177
- size: 14,
1178
- color: _sharedUi.buoyColors.error
1179
- })
1180
- })]
1181
- }, device.id))
1182
- }), !isCurrentDeviceRegistered && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
1183
- style: styles.proRegisterDeviceBtn,
1184
- onPress: handleRegisterDevice,
1185
- disabled: devicesLoading,
1186
- activeOpacity: 0.7,
1187
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Plus, {
1188
- size: 14,
1189
- color: _sharedUi.buoyColors.primary
1190
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1191
- style: styles.proRegisterDeviceBtnText,
1192
- children: "Register This Device"
1193
- })]
1194
- })]
1195
- })]
1196
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
1197
- style: styles.proSignOutBtn,
1198
- onPress: () => {
1199
- const {
1200
- Alert
1201
- } = require("react-native");
1202
- Alert.alert("Sign Out of Pro?", "This will:\n\n• Remove your license key from this device\n• Deactivate this device from your license\n• Free up a seat for another device\n\nYou can sign back in anytime with your license key.", [{
1203
- text: "Cancel",
1204
- style: "cancel"
1205
- }, {
1206
- text: "Sign Out",
1207
- style: "destructive",
1208
- onPress: () => license?.clearLicense()
1209
- }]);
1210
- },
1211
- activeOpacity: 0.7,
1212
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
1213
- style: styles.proSignOutBtnText,
1214
- children: "Sign Out of Pro"
1215
- })
1216
- })]
971
+ })
1217
972
  }) : /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
1218
973
  children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
1219
974
  style: styles.proSection,
@@ -1304,19 +1059,8 @@ const DevToolsSettingsModal = ({
1304
1059
  })]
1305
1060
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.LicenseEntryModal, {
1306
1061
  visible: showLicenseModal,
1307
- onClose: () => {
1308
- setShowLicenseModal(false);
1309
- setLicenseModalForDeviceRegistration(false);
1310
- },
1311
- onSuccess: () => {
1312
- setShowLicenseModal(false);
1313
- setLicenseModalForDeviceRegistration(false);
1314
- },
1315
- license: license,
1316
- startAtDeviceRegistration: licenseModalForDeviceRegistration,
1317
- initialExistingDevices: licenseModalForDeviceRegistration ? devices : [],
1318
- initialMaxDevices: licenseModalForDeviceRegistration ? seats?.total ?? undefined : undefined,
1319
- initialCurrentDeviceCount: licenseModalForDeviceRegistration ? seats?.used ?? undefined : undefined
1062
+ onClose: () => setShowLicenseModal(false),
1063
+ onSuccess: () => setShowLicenseModal(false)
1320
1064
  })]
1321
1065
  });
1322
1066
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.JsModal, {
@@ -1438,7 +1182,7 @@ const useDevToolsSettings = () => {
1438
1182
  const [settings, setSettings] = (0, _react.useState)(effectiveDefaults);
1439
1183
  const loadSettings = (0, _react.useCallback)(async () => {
1440
1184
  try {
1441
- const savedSettings = await (0, _sharedUi.safeGetItem)(STORAGE_KEY);
1185
+ const savedSettings = await _sharedUi.persistentStorage.getItem(STORAGE_KEY);
1442
1186
  if (savedSettings) {
1443
1187
  const parsed = JSON.parse(savedSettings);
1444
1188
  const merged = mergeWithDefaults(effectiveDefaults, parsed);
@@ -2235,21 +1979,16 @@ const styles = _reactNative.StyleSheet.create({
2235
1979
  fontWeight: "600",
2236
1980
  color: _sharedUi.buoyColors.primary
2237
1981
  },
2238
- proSignOutBtn: {
2239
- alignItems: "center",
2240
- justifyContent: "center",
2241
- paddingVertical: 12,
2242
- marginTop: 8
2243
- },
2244
- proSignOutBtnText: {
2245
- fontSize: 12,
2246
- color: _sharedUi.buoyColors.textMuted
2247
- },
2248
1982
  proFreeDescription: {
2249
1983
  fontSize: 11,
2250
1984
  color: _sharedUi.buoyColors.textSecondary,
2251
1985
  lineHeight: 16
2252
1986
  },
1987
+ proActiveDescription: {
1988
+ fontSize: 11,
1989
+ color: _sharedUi.buoyColors.textSecondary,
1990
+ lineHeight: 16
1991
+ },
2253
1992
  proFeaturesList: {
2254
1993
  gap: 8
2255
1994
  },
@@ -41,7 +41,10 @@ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r
41
41
 
42
42
  /**
43
43
  * Props for FloatingDevTools component.
44
- * Apps prop is optional - if not provided, all installed dev tools are auto-discovered.
44
+ *
45
+ * ZERO-CONFIG: All @buoy-gg/* tools are auto-discovered when installed.
46
+ * You don't need to pass anything to use network, storage, redux, etc. tools!
47
+ * Just install the package and it works automatically.
45
48
  */
46
49
 
47
50
  /**
@@ -230,6 +233,10 @@ const FloatingDevTools = ({
230
233
  // Free user in production - don't render DevTools
231
234
  return null;
232
235
  }
236
+
237
+ // Session blocking is handled inline by JsModal's SessionBlockedOverlay
238
+ // No need to replace the entire UI - tools still render, but content is blocked
239
+
233
240
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_DefaultConfigContext.DefaultConfigProvider, {
234
241
  defaultFloatingTools: defaultFloatingTools,
235
242
  defaultDialTools: normalizedDialTools,
@@ -141,9 +141,8 @@ function FloatingDevTools({
141
141
  visible: isSettingsOpen,
142
142
  onClose: handleCloseSettings,
143
143
  availableTools: availableTools,
144
- onSettingsChange: newSettings => {
144
+ onSettingsChange: _newSettings => {
145
145
  // Settings are already saved by the hook
146
- console.log('Settings updated:', newSettings);
147
146
  }
148
147
  })]
149
148
  });
@@ -53,7 +53,7 @@ const FloatingMenu = ({
53
53
  (0, _react.useEffect)(() => {
54
54
  const loadDialState = async () => {
55
55
  try {
56
- const savedDialOpen = await (0, _sharedUi.safeGetItem)(_sharedUi.devToolsStorageKeys.dial.isOpen());
56
+ const savedDialOpen = await _sharedUi.persistentStorage.getItem(_sharedUi.devToolsStorageKeys.dial.isOpen());
57
57
  if (savedDialOpen === "true") {
58
58
  setShowDial(true);
59
59
  }
@@ -70,7 +70,7 @@ const FloatingMenu = ({
70
70
  (0, _react.useEffect)(() => {
71
71
  // Only persist after initial state is loaded to avoid overwriting with default
72
72
  if (!dialStateLoaded) return;
73
- (0, _sharedUi.safeSetItem)(_sharedUi.devToolsStorageKeys.dial.isOpen(), showDial ? "true" : "false").catch(error => {
73
+ _sharedUi.persistentStorage.setItem(_sharedUi.devToolsStorageKeys.dial.isOpen(), showDial ? "true" : "false").catch(error => {
74
74
  // Failed to save dial state - continue without persistence
75
75
  console.warn("Failed to save dial state:", error);
76
76
  });
@@ -97,7 +97,7 @@ const FloatingMenu = ({
97
97
  }
98
98
  const checkOnboarding = async () => {
99
99
  try {
100
- const hasSeenOnboarding = await (0, _sharedUi.safeGetItem)(FLOATING_MENU_ONBOARDING_KEY);
100
+ const hasSeenOnboarding = await _sharedUi.persistentStorage.getItem(FLOATING_MENU_ONBOARDING_KEY);
101
101
  if (!hasSeenOnboarding) {
102
102
  // Small delay to let the UI settle before showing tooltip
103
103
  setTimeout(() => {
@@ -202,7 +202,7 @@ const FloatingMenu = ({
202
202
  setOnboardingStep(null);
203
203
 
204
204
  // Save to storage asynchronously in the background
205
- (0, _sharedUi.safeSetItem)(FLOATING_MENU_ONBOARDING_KEY, "true").catch(error => {
205
+ _sharedUi.persistentStorage.setItem(FLOATING_MENU_ONBOARDING_KEY, "true").catch(error => {
206
206
  // Silently fail - user already saw onboarding, just won't persist
207
207
  console.warn("Failed to save onboarding state:", error);
208
208
  });
@@ -115,7 +115,7 @@ function MinimizedToolsProvider({
115
115
  (0, _react.useEffect)(() => {
116
116
  const restoreMinimizedTools = async () => {
117
117
  try {
118
- const saved = await (0, _sharedUi.safeGetItem)(STORAGE_KEY);
118
+ const saved = await _sharedUi.persistentStorage.getItem(STORAGE_KEY);
119
119
  if (saved) {
120
120
  const serialized = JSON.parse(saved);
121
121
  // Reconstruct tools with icons
@@ -145,7 +145,7 @@ function MinimizedToolsProvider({
145
145
  icon,
146
146
  ...rest
147
147
  }) => rest);
148
- (0, _sharedUi.safeSetItem)(STORAGE_KEY, JSON.stringify(serialized));
148
+ _sharedUi.persistentStorage.setItem(STORAGE_KEY, JSON.stringify(serialized));
149
149
  }, PERSISTENCE_DELAY);
150
150
  return () => {
151
151
  if (persistenceTimeoutRef.current) {
@@ -194,6 +194,21 @@ function autoDiscoverPresets() {
194
194
  return null;
195
195
  }
196
196
  }
197
+ },
198
+ // Events Timeline
199
+ {
200
+ name: "@buoy-gg/events",
201
+ loader: () => {
202
+ try {
203
+ // @ts-ignore - Dynamic import that may not exist
204
+ const {
205
+ eventsToolPreset
206
+ } = require("@buoy-gg/events");
207
+ return eventsToolPreset;
208
+ } catch {
209
+ return null;
210
+ }
211
+ }
197
212
  }];
198
213
 
199
214
  // Attempt to load each preset
@@ -60,7 +60,7 @@ const DialDevTools = ({
60
60
  (0, _react.useEffect)(() => {
61
61
  const loadSettingsModalState = async () => {
62
62
  try {
63
- const savedModalOpen = await (0, _sharedUi.safeGetItem)(_sharedUi.devToolsStorageKeys.settings.modalOpen());
63
+ const savedModalOpen = await _sharedUi.persistentStorage.getItem(_sharedUi.devToolsStorageKeys.settings.modalOpen());
64
64
  if (savedModalOpen === "true") {
65
65
  setIsSettingsModalOpen(true);
66
66
  }
@@ -77,7 +77,7 @@ const DialDevTools = ({
77
77
  (0, _react.useEffect)(() => {
78
78
  // Only persist after initial state is loaded to avoid overwriting with default
79
79
  if (!settingsModalStateLoaded) return;
80
- (0, _sharedUi.safeSetItem)(_sharedUi.devToolsStorageKeys.settings.modalOpen(), isSettingsModalOpen ? "true" : "false").catch(error => {
80
+ _sharedUi.persistentStorage.setItem(_sharedUi.devToolsStorageKeys.settings.modalOpen(), isSettingsModalOpen ? "true" : "false").catch(error => {
81
81
  // Failed to save settings modal state - continue without persistence
82
82
  console.warn("Failed to save settings modal state:", error);
83
83
  });
@@ -112,7 +112,7 @@ const DialDevTools = ({
112
112
  }
113
113
  const checkOnboarding = async () => {
114
114
  try {
115
- const hasSeenTooltip = await (0, _sharedUi.safeGetItem)(ONBOARDING_STORAGE_KEY);
115
+ const hasSeenTooltip = await _sharedUi.persistentStorage.getItem(ONBOARDING_STORAGE_KEY);
116
116
  if (!hasSeenTooltip) {
117
117
  // Small delay to let the entrance animations play first
118
118
  setTimeout(() => {
@@ -411,7 +411,7 @@ const DialDevTools = ({
411
411
  setShowOnboardingTooltip(false);
412
412
 
413
413
  // Save to storage asynchronously in the background
414
- (0, _sharedUi.safeSetItem)(ONBOARDING_STORAGE_KEY, "true").catch(error => {
414
+ _sharedUi.persistentStorage.setItem(ONBOARDING_STORAGE_KEY, "true").catch(error => {
415
415
  // Silently fail - user already saw onboarding, just won't persist
416
416
  console.warn("Failed to save dial onboarding state:", error);
417
417
  });