@buoy-gg/core 3.0.1 → 4.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/commonjs/floatingMenu/DevToolsSettingsModal.js +1 -1
- package/lib/commonjs/floatingMenu/FloatingDevTools.js +25 -5
- package/lib/commonjs/floatingMenu/FloatingMenu.js +3 -7
- package/lib/commonjs/floatingMenu/allToolsRegistry.js +193 -0
- package/lib/commonjs/floatingMenu/autoExternalSync.js +254 -0
- package/lib/commonjs/floatingMenu/defaultConfig.js +1 -1
- package/lib/commonjs/floatingMenu/dial/DialDevTools.js +115 -53
- package/lib/commonjs/floatingMenu/dial/DialIcon.js +53 -13
- package/lib/commonjs/floatingMenu/dial/OnboardingTooltip.js +1 -1
- package/lib/module/floatingMenu/DevToolsSettingsModal.js +2 -2
- package/lib/module/floatingMenu/FloatingDevTools.js +26 -6
- package/lib/module/floatingMenu/FloatingMenu.js +4 -7
- package/lib/module/floatingMenu/allToolsRegistry.js +190 -0
- package/lib/module/floatingMenu/autoExternalSync.js +248 -0
- package/lib/module/floatingMenu/defaultConfig.js +1 -1
- package/lib/module/floatingMenu/dial/DialDevTools.js +119 -55
- package/lib/module/floatingMenu/dial/DialIcon.js +56 -15
- package/lib/module/floatingMenu/dial/OnboardingTooltip.js +2 -1
- package/lib/typescript/commonjs/floatingMenu/DevToolsSettingsModal.d.ts.map +1 -1
- package/lib/typescript/commonjs/floatingMenu/FloatingDevTools.d.ts +19 -1
- package/lib/typescript/commonjs/floatingMenu/FloatingDevTools.d.ts.map +1 -1
- package/lib/typescript/commonjs/floatingMenu/FloatingMenu.d.ts.map +1 -1
- package/lib/typescript/commonjs/floatingMenu/allToolsRegistry.d.ts +42 -0
- package/lib/typescript/commonjs/floatingMenu/allToolsRegistry.d.ts.map +1 -0
- package/lib/typescript/commonjs/floatingMenu/autoExternalSync.d.ts +25 -0
- package/lib/typescript/commonjs/floatingMenu/autoExternalSync.d.ts.map +1 -0
- package/lib/typescript/commonjs/floatingMenu/defaultConfig.d.ts +1 -1
- package/lib/typescript/commonjs/floatingMenu/defaultConfig.d.ts.map +1 -1
- package/lib/typescript/commonjs/floatingMenu/dial/DialDevTools.d.ts +7 -0
- package/lib/typescript/commonjs/floatingMenu/dial/DialDevTools.d.ts.map +1 -1
- package/lib/typescript/commonjs/floatingMenu/dial/DialIcon.d.ts.map +1 -1
- package/lib/typescript/commonjs/floatingMenu/dial/OnboardingTooltip.d.ts.map +1 -1
- package/lib/typescript/commonjs/index.d.ts +1 -0
- package/lib/typescript/commonjs/index.d.ts.map +1 -1
- package/lib/typescript/module/floatingMenu/DevToolsSettingsModal.d.ts.map +1 -1
- package/lib/typescript/module/floatingMenu/FloatingDevTools.d.ts +19 -1
- package/lib/typescript/module/floatingMenu/FloatingDevTools.d.ts.map +1 -1
- package/lib/typescript/module/floatingMenu/FloatingMenu.d.ts.map +1 -1
- package/lib/typescript/module/floatingMenu/allToolsRegistry.d.ts +42 -0
- package/lib/typescript/module/floatingMenu/allToolsRegistry.d.ts.map +1 -0
- package/lib/typescript/module/floatingMenu/autoExternalSync.d.ts +25 -0
- package/lib/typescript/module/floatingMenu/autoExternalSync.d.ts.map +1 -0
- package/lib/typescript/module/floatingMenu/defaultConfig.d.ts +1 -1
- package/lib/typescript/module/floatingMenu/defaultConfig.d.ts.map +1 -1
- package/lib/typescript/module/floatingMenu/dial/DialDevTools.d.ts +7 -0
- package/lib/typescript/module/floatingMenu/dial/DialDevTools.d.ts.map +1 -1
- package/lib/typescript/module/floatingMenu/dial/DialIcon.d.ts.map +1 -1
- package/lib/typescript/module/floatingMenu/dial/OnboardingTooltip.d.ts.map +1 -1
- package/lib/typescript/module/index.d.ts +1 -0
- package/lib/typescript/module/index.d.ts.map +1 -1
- package/package.json +5 -5
|
@@ -808,7 +808,7 @@ const DevToolsSettingsModal = ({
|
|
|
808
808
|
children: clearSuccess ? "CLEARED" : isClearing ? "CLEARING..." : "CLEAR ALL SETTINGS"
|
|
809
809
|
})]
|
|
810
810
|
})]
|
|
811
|
-
}), renderGlobalSettingCard("enableSharedModalDimensions", "SHARED MODAL SIZE", "MODAL", "Sync dimensions across all tools", "When enabled, all tool modals will share the same size and position. Resizing one modal will affect all others. When disabled, each tool remembers its own size and position independently.", "Keep OFF for the best experience. This allows you to customize each tool's modal size separately. Enable only if you prefer uniform modal sizes across all dev tools."), renderGlobalSettingCard("expandableWindowControls", "EXPAND CONTROLS", "MODAL", "iPad-style expandable window buttons", "When enabled, the window control buttons (minimize, toggle mode, close) start as small dots and expand into larger, easy-to-tap buttons when pressed — similar to iPad window controls. When disabled, buttons are directly tappable at their small size.", "Keep ON for touch devices where the small buttons are hard to press. Turn OFF if you prefer direct single-tap access (e.g. when using a mouse or simulator)."), isDevelopmentMode && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
811
|
+
}), renderGlobalSettingCard("enableSharedModalDimensions", "SHARED MODAL SIZE", "MODAL", "Sync dimensions across all tools", "When enabled, all tool modals will share the same size and position. Resizing one modal will affect all others. When disabled, each tool remembers its own size and position independently.", "Keep OFF for the best experience. This allows you to customize each tool's modal size separately. Enable only if you prefer uniform modal sizes across all dev tools."), _reactNative.Platform.OS !== "web" && renderGlobalSettingCard("expandableWindowControls", "EXPAND CONTROLS", "MODAL", "iPad-style expandable window buttons", "When enabled, the window control buttons (minimize, toggle mode, close) start as small dots and expand into larger, easy-to-tap buttons when pressed — similar to iPad window controls. When disabled, buttons are directly tappable at their small size.", "Keep ON for touch devices where the small buttons are hard to press. Turn OFF if you prefer direct single-tap access (e.g. when using a mouse or simulator)."), isDevelopmentMode && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
812
812
|
style: styles.exportConfigCard,
|
|
813
813
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
|
|
814
814
|
activeOpacity: 0.85,
|
|
@@ -15,6 +15,7 @@ var _MinimizedToolsContext = require("./MinimizedToolsContext.js");
|
|
|
15
15
|
var _defaultConfig = require("./defaultConfig.js");
|
|
16
16
|
var _DefaultConfigContext = require("./DefaultConfigContext.js");
|
|
17
17
|
var _license = require("@buoy-gg/license");
|
|
18
|
+
var _autoExternalSync = require("./autoExternalSync.js");
|
|
18
19
|
var _jsxRuntime = require("react/jsx-runtime");
|
|
19
20
|
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
|
20
21
|
/**
|
|
@@ -113,11 +114,18 @@ const FloatingDevTools = ({
|
|
|
113
114
|
licenseKey: licenseKeyProp,
|
|
114
115
|
zustandStores,
|
|
115
116
|
environment,
|
|
117
|
+
externalSync = true,
|
|
116
118
|
...props
|
|
117
119
|
}) => {
|
|
118
120
|
const resolvedEnvironment = environment ?? (0, _sharedUi.normalizeEnvironment)(process.env.NODE_ENV ?? "dev");
|
|
119
|
-
//
|
|
120
|
-
|
|
121
|
+
// Production gating + the device→dashboard license handshake must use a REAL
|
|
122
|
+
// license only — NOT the free Weekend Pass. Otherwise shipping Buoy would
|
|
123
|
+
// expose the devtools to end users every weekend, and the dashboard would try
|
|
124
|
+
// to adopt a non-existent key. (Feature unlocks inside the tools still honor
|
|
125
|
+
// the Weekend Pass via their own useIsPro().)
|
|
126
|
+
const {
|
|
127
|
+
isLicensed
|
|
128
|
+
} = (0, _license.useProAccess)();
|
|
121
129
|
|
|
122
130
|
// Get full license state for requireLicense gating
|
|
123
131
|
const {
|
|
@@ -126,10 +134,17 @@ const FloatingDevTools = ({
|
|
|
126
134
|
} = (0, _license.useLicense)();
|
|
127
135
|
const [showLicenseModal, setShowLicenseModal] = (0, _react.useState)(false);
|
|
128
136
|
|
|
129
|
-
// Initialize license manager on mount, and set/clear license key when prop changes
|
|
137
|
+
// Initialize license manager on mount, and set/clear license key when prop changes.
|
|
138
|
+
// The `licenseKey` prop is the source of truth WHEN PROVIDED:
|
|
139
|
+
// - non-empty → validate + activate that key
|
|
140
|
+
// - "" (blank) → EXPLICITLY clear the cached license (key was removed)
|
|
141
|
+
// - undefined → don't touch it (the app may set a key via Buoy.init())
|
|
130
142
|
(0, _react.useEffect)(() => {
|
|
131
143
|
if (licenseKeyProp && licenseKeyProp.trim() !== "") {
|
|
132
144
|
_license.LicenseManager.initialize().then(() => _license.LicenseManager.setLicenseKey(licenseKeyProp)).catch(() => {});
|
|
145
|
+
} else if (licenseKeyProp === "") {
|
|
146
|
+
// Explicit removal: wipe the 30-day cache so Pro actually turns off.
|
|
147
|
+
_license.LicenseManager.initialize().then(() => _license.LicenseManager.clearLicense()).catch(() => {});
|
|
133
148
|
} else {
|
|
134
149
|
_license.LicenseManager.initialize();
|
|
135
150
|
}
|
|
@@ -306,7 +321,7 @@ const FloatingDevTools = ({
|
|
|
306
321
|
// Gate: Free tier only works in development mode
|
|
307
322
|
// Pro users can use DevTools everywhere (dev + production)
|
|
308
323
|
const isDevelopment = typeof __DEV__ !== "undefined" && __DEV__;
|
|
309
|
-
if (!isDevelopment && !
|
|
324
|
+
if (!isDevelopment && !isLicensed) {
|
|
310
325
|
// Free user in production - don't render DevTools
|
|
311
326
|
return null;
|
|
312
327
|
}
|
|
@@ -342,7 +357,12 @@ const FloatingDevTools = ({
|
|
|
342
357
|
environment: resolvedEnvironment
|
|
343
358
|
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_AppHost.AppOverlay, {})]
|
|
344
359
|
})
|
|
345
|
-
}), children, DebugBordersOverlay && /*#__PURE__*/(0, _jsxRuntime.jsx)(DebugBordersOverlay, {}), HighlightUpdatesOverlay && /*#__PURE__*/(0, _jsxRuntime.jsx)(HighlightUpdatesOverlay, {}), ImageOverlayOverlay && /*#__PURE__*/(0, _jsxRuntime.jsx)(ImageOverlayOverlay, {}), PerfMonitorOverlay && /*#__PURE__*/(0, _jsxRuntime.jsx)(PerfMonitorOverlay, {}), ImpersonateOverlay && /*#__PURE__*/(0, _jsxRuntime.jsx)(ImpersonateOverlay, {}), RouteTracker && /*#__PURE__*/(0, _jsxRuntime.jsx)(RouteTracker, {})
|
|
360
|
+
}), children, DebugBordersOverlay && /*#__PURE__*/(0, _jsxRuntime.jsx)(DebugBordersOverlay, {}), HighlightUpdatesOverlay && /*#__PURE__*/(0, _jsxRuntime.jsx)(HighlightUpdatesOverlay, {}), ImageOverlayOverlay && /*#__PURE__*/(0, _jsxRuntime.jsx)(ImageOverlayOverlay, {}), PerfMonitorOverlay && /*#__PURE__*/(0, _jsxRuntime.jsx)(PerfMonitorOverlay, {}), ImpersonateOverlay && /*#__PURE__*/(0, _jsxRuntime.jsx)(ImpersonateOverlay, {}), RouteTracker && /*#__PURE__*/(0, _jsxRuntime.jsx)(RouteTracker, {}), isDevelopment && externalSync !== false && (0, _autoExternalSync.isExternalSyncAvailable)() && /*#__PURE__*/(0, _jsxRuntime.jsx)(_autoExternalSync.AutoExternalSync, {
|
|
361
|
+
options: typeof externalSync === "object" ? externalSync : undefined,
|
|
362
|
+
requiredEnvVars: requiredEnvVars,
|
|
363
|
+
isPro: isLicensed,
|
|
364
|
+
licenseKey: licenseKey
|
|
365
|
+
})]
|
|
346
366
|
})
|
|
347
367
|
})
|
|
348
368
|
})
|
|
@@ -6,9 +6,9 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
exports.FloatingMenu = void 0;
|
|
7
7
|
var _react = _interopRequireWildcard(require("react"));
|
|
8
8
|
var _reactNative = require("react-native");
|
|
9
|
+
var _sharedUi = require("@buoy-gg/shared-ui");
|
|
9
10
|
var _floatingTools = require("./floatingTools");
|
|
10
11
|
var _DialDevTools = require("./dial/DialDevTools");
|
|
11
|
-
var _sharedUi = require("@buoy-gg/shared-ui");
|
|
12
12
|
var _DevToolsSettingsModal = require("./DevToolsSettingsModal");
|
|
13
13
|
var _AppHost = require("./AppHost.js");
|
|
14
14
|
var _DevToolsVisibilityContext = require("./DevToolsVisibilityContext.js");
|
|
@@ -27,10 +27,6 @@ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r
|
|
|
27
27
|
*/
|
|
28
28
|
const FLOATING_MENU_ONBOARDING_KEY = "@react_buoy_floating_menu_tooltip_shown";
|
|
29
29
|
const ONBOARDING_STEP_KEY = "@react_buoy_onboarding_step";
|
|
30
|
-
const {
|
|
31
|
-
width: SCREEN_WIDTH,
|
|
32
|
-
height: SCREEN_HEIGHT
|
|
33
|
-
} = _reactNative.Dimensions.get("window");
|
|
34
30
|
const FloatingMenu = ({
|
|
35
31
|
apps,
|
|
36
32
|
state,
|
|
@@ -328,11 +324,11 @@ const styles = _reactNative.StyleSheet.create({
|
|
|
328
324
|
fontWeight: "900"
|
|
329
325
|
},
|
|
330
326
|
onboardingContainer: {
|
|
331
|
-
...
|
|
327
|
+
..._sharedUi.absoluteFill,
|
|
332
328
|
zIndex: 10000
|
|
333
329
|
},
|
|
334
330
|
onboardingBackdrop: {
|
|
335
|
-
...
|
|
331
|
+
..._sharedUi.absoluteFill,
|
|
336
332
|
backgroundColor: "rgba(0, 0, 0, 0.85)"
|
|
337
333
|
}
|
|
338
334
|
});
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.ALL_TOOLS_REGISTRY = void 0;
|
|
7
|
+
var _react = _interopRequireDefault(require("react"));
|
|
8
|
+
var _reactNative = require("react-native");
|
|
9
|
+
var _floatingToolsCore = require("@buoy-gg/floating-tools-core");
|
|
10
|
+
var _sharedUi = require("@buoy-gg/shared-ui");
|
|
11
|
+
var _jsxRuntime = require("react/jsx-runtime");
|
|
12
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
13
|
+
/**
|
|
14
|
+
* Canonical registry of ALL dial-eligible tools React Buoy offers on mobile.
|
|
15
|
+
*
|
|
16
|
+
* This is the single source of truth used to compute which tools are
|
|
17
|
+
* "unavailable" (offered but not installed in the current app). It lives
|
|
18
|
+
* inside the floating-menu package so nothing outside needs to be imported.
|
|
19
|
+
*
|
|
20
|
+
* Rules for this file:
|
|
21
|
+
* - Only import from REQUIRED dependencies (@buoy-gg/floating-tools-core,
|
|
22
|
+
* @buoy-gg/shared-ui, react-native) so the icons are always resolvable,
|
|
23
|
+
* even when the optional tool packages are not installed.
|
|
24
|
+
* - Only include tools whose preset slot is NOT "row" (row-only tools never
|
|
25
|
+
* appear in the dial and have no "unavailable" state to show).
|
|
26
|
+
* - Keep the order intentional: this order is the fallback when no usage
|
|
27
|
+
* data exists for new/unavailable tools.
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
// ─── Color constants for tools whose icons live in optional packages ─────────
|
|
31
|
+
// Copied verbatim from the source icon components so the vendored copies below
|
|
32
|
+
// render identically to the real tool icons.
|
|
33
|
+
|
|
34
|
+
/** Zustand brand color — copied from @buoy-gg/zustand ZustandIcon.tsx */const ZUSTAND_ICON_COLOR = "#463B3F";
|
|
35
|
+
/** Jotai brand color — copied from @buoy-gg/jotai JotaiIcon.tsx */
|
|
36
|
+
const JOTAI_ICON_COLOR = "#6C47FF";
|
|
37
|
+
/** Image overlay purple — matches the preset */
|
|
38
|
+
const IMAGE_OVERLAY_ICON_COLOR = "#A855F7";
|
|
39
|
+
|
|
40
|
+
// ─── Vendored copies of optional-package icons ───────────────────────────────
|
|
41
|
+
// Zustand and Jotai ship their real icons inside their own packages (which may
|
|
42
|
+
// not be installed), so we cannot import them from a required dependency.
|
|
43
|
+
//
|
|
44
|
+
// The REAL icons in @buoy-gg/zustand and @buoy-gg/jotai are themselves a single
|
|
45
|
+
// centered letter glyph (verified — there are no SVG logos in those packages).
|
|
46
|
+
// These are faithful copies of those source components, so unavailable items
|
|
47
|
+
// render the ACTUAL tool icon (just dimmed by DialIcon), not a placeholder.
|
|
48
|
+
|
|
49
|
+
/** Faithful copy of @buoy-gg/zustand `ZustandIcon` */
|
|
50
|
+
const ZustandIcon = ({
|
|
51
|
+
size,
|
|
52
|
+
color
|
|
53
|
+
}) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
54
|
+
style: {
|
|
55
|
+
width: size,
|
|
56
|
+
height: size,
|
|
57
|
+
justifyContent: "center",
|
|
58
|
+
alignItems: "center"
|
|
59
|
+
},
|
|
60
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
61
|
+
style: {
|
|
62
|
+
fontSize: size * 0.75,
|
|
63
|
+
color: color || ZUSTAND_ICON_COLOR,
|
|
64
|
+
fontWeight: "700"
|
|
65
|
+
},
|
|
66
|
+
children: "Z"
|
|
67
|
+
})
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
/** Faithful copy of @buoy-gg/jotai `JotaiIcon` */
|
|
71
|
+
const JotaiIcon = ({
|
|
72
|
+
size,
|
|
73
|
+
color
|
|
74
|
+
}) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
75
|
+
style: {
|
|
76
|
+
width: size,
|
|
77
|
+
height: size,
|
|
78
|
+
justifyContent: "center",
|
|
79
|
+
alignItems: "center"
|
|
80
|
+
},
|
|
81
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
82
|
+
style: {
|
|
83
|
+
fontSize: size * 0.75,
|
|
84
|
+
color: color || JOTAI_ICON_COLOR,
|
|
85
|
+
fontWeight: "700"
|
|
86
|
+
},
|
|
87
|
+
children: "J"
|
|
88
|
+
})
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// ─── Registry entry type ──────────────────────────────────────────────────────
|
|
92
|
+
|
|
93
|
+
// ─── Canonical catalog ────────────────────────────────────────────────────────
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Full list of every dial-eligible tool React Buoy offers on mobile.
|
|
97
|
+
*
|
|
98
|
+
* Available (installed) tools are shown normally in the dial.
|
|
99
|
+
* Unavailable (not installed) tools are appended at the end of the dial and look
|
|
100
|
+
* like a normal item (real icon + real name) with a small muted "Unavailable"
|
|
101
|
+
* caption added; they are non-interactive.
|
|
102
|
+
*
|
|
103
|
+
* To add a new tool to Buoy:
|
|
104
|
+
* 1. Add its preset to autoDiscoverPresets.ts
|
|
105
|
+
* 2. Add an entry here so it appears in the "unavailable" section for apps
|
|
106
|
+
* that haven't installed it yet.
|
|
107
|
+
*/
|
|
108
|
+
const ALL_TOOLS_REGISTRY = exports.ALL_TOOLS_REGISTRY = [{
|
|
109
|
+
id: "env",
|
|
110
|
+
name: "ENV",
|
|
111
|
+
color: _floatingToolsCore.ENV_ICON_COLOR,
|
|
112
|
+
renderIcon: size => /*#__PURE__*/(0, _jsxRuntime.jsx)(_floatingToolsCore.EnvIcon, {
|
|
113
|
+
size: size
|
|
114
|
+
})
|
|
115
|
+
}, {
|
|
116
|
+
id: "network",
|
|
117
|
+
name: "NETWORK",
|
|
118
|
+
color: _floatingToolsCore.NETWORK_ICON_COLOR,
|
|
119
|
+
renderIcon: size => /*#__PURE__*/(0, _jsxRuntime.jsx)(_floatingToolsCore.NetworkIcon, {
|
|
120
|
+
size: size
|
|
121
|
+
})
|
|
122
|
+
}, {
|
|
123
|
+
id: "storage",
|
|
124
|
+
name: "STORAGE",
|
|
125
|
+
color: _floatingToolsCore.STORAGE_ICON_COLOR,
|
|
126
|
+
renderIcon: size => /*#__PURE__*/(0, _jsxRuntime.jsx)(_floatingToolsCore.StorageIcon, {
|
|
127
|
+
size: size
|
|
128
|
+
})
|
|
129
|
+
}, {
|
|
130
|
+
id: "query",
|
|
131
|
+
name: "QUERY",
|
|
132
|
+
color: _floatingToolsCore.QUERY_ICON_COLOR,
|
|
133
|
+
renderIcon: size => /*#__PURE__*/(0, _jsxRuntime.jsx)(_floatingToolsCore.QueryIcon, {
|
|
134
|
+
size: size
|
|
135
|
+
})
|
|
136
|
+
}, {
|
|
137
|
+
id: "route-events",
|
|
138
|
+
name: "ROUTES",
|
|
139
|
+
color: _floatingToolsCore.ROUTES_ICON_COLOR,
|
|
140
|
+
renderIcon: size => /*#__PURE__*/(0, _jsxRuntime.jsx)(_floatingToolsCore.RoutesIcon, {
|
|
141
|
+
size: size
|
|
142
|
+
})
|
|
143
|
+
}, {
|
|
144
|
+
id: "highlight-updates-modal",
|
|
145
|
+
name: "HIGHLIGHT",
|
|
146
|
+
color: _floatingToolsCore.HIGHLIGHTER_ICON_COLOR,
|
|
147
|
+
renderIcon: size => /*#__PURE__*/(0, _jsxRuntime.jsx)(_floatingToolsCore.HighlighterIcon, {
|
|
148
|
+
size: size
|
|
149
|
+
})
|
|
150
|
+
}, {
|
|
151
|
+
id: "redux",
|
|
152
|
+
name: "REDUX",
|
|
153
|
+
color: _floatingToolsCore.REDUX_ICON_COLOR,
|
|
154
|
+
renderIcon: size => /*#__PURE__*/(0, _jsxRuntime.jsx)(_floatingToolsCore.ReduxIcon, {
|
|
155
|
+
size: size
|
|
156
|
+
})
|
|
157
|
+
}, {
|
|
158
|
+
id: "zustand",
|
|
159
|
+
name: "ZUSTAND",
|
|
160
|
+
color: ZUSTAND_ICON_COLOR,
|
|
161
|
+
renderIcon: size => /*#__PURE__*/(0, _jsxRuntime.jsx)(ZustandIcon, {
|
|
162
|
+
size: size
|
|
163
|
+
})
|
|
164
|
+
}, {
|
|
165
|
+
id: "events",
|
|
166
|
+
name: "EVENTS",
|
|
167
|
+
color: _floatingToolsCore.EVENTS_ICON_COLOR,
|
|
168
|
+
renderIcon: size => /*#__PURE__*/(0, _jsxRuntime.jsx)(_floatingToolsCore.EventsIcon, {
|
|
169
|
+
size: size
|
|
170
|
+
})
|
|
171
|
+
}, {
|
|
172
|
+
id: "jotai",
|
|
173
|
+
name: "JOTAI",
|
|
174
|
+
color: JOTAI_ICON_COLOR,
|
|
175
|
+
renderIcon: size => /*#__PURE__*/(0, _jsxRuntime.jsx)(JotaiIcon, {
|
|
176
|
+
size: size
|
|
177
|
+
})
|
|
178
|
+
}, {
|
|
179
|
+
id: "image-overlay",
|
|
180
|
+
name: "IMG",
|
|
181
|
+
color: IMAGE_OVERLAY_ICON_COLOR,
|
|
182
|
+
renderIcon: size => /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ImageOverlayIcon, {
|
|
183
|
+
size: size,
|
|
184
|
+
color: IMAGE_OVERLAY_ICON_COLOR
|
|
185
|
+
})
|
|
186
|
+
}, {
|
|
187
|
+
id: "perf-monitor-modal",
|
|
188
|
+
name: "BENCH",
|
|
189
|
+
color: _floatingToolsCore.BENCHMARK_ICON_COLOR,
|
|
190
|
+
renderIcon: size => /*#__PURE__*/(0, _jsxRuntime.jsx)(_floatingToolsCore.BenchmarkIcon, {
|
|
191
|
+
size: size
|
|
192
|
+
})
|
|
193
|
+
}];
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.AutoExternalSync = AutoExternalSync;
|
|
7
|
+
exports.isExternalSyncAvailable = isExternalSyncAvailable;
|
|
8
|
+
var _react = require("react");
|
|
9
|
+
var _reactNative = require("react-native");
|
|
10
|
+
/**
|
|
11
|
+
* Zero-config device→desktop sync for FloatingDevTools.
|
|
12
|
+
*
|
|
13
|
+
* When @buoy-gg/external-sync is installed, FloatingDevTools renders
|
|
14
|
+
* <AutoExternalSync /> in dev builds: it connects to the Buoy Desktop broker
|
|
15
|
+
* (localhost:42831 — a silent no-op when the desktop app isn't running) and
|
|
16
|
+
* registers a sync adapter for every installed tool package, discovered with
|
|
17
|
+
* the same guarded-require pattern as autoDiscoverPresets. No <DevToolsSync>
|
|
18
|
+
* wiring needed in the app.
|
|
19
|
+
*
|
|
20
|
+
* Identity defaults come from expo-constants when available (app name →
|
|
21
|
+
* "MyApp (ios)" / "myapp-ios"), overridable via the `externalSync` prop.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
25
|
+
|
|
26
|
+
// Module-level guarded requires: presence is constant for the app lifetime,
|
|
27
|
+
// so hooks pulled from these modules keep a stable call order.
|
|
28
|
+
//
|
|
29
|
+
// IMPORTANT: each require() must sit LEXICALLY inside its own try block
|
|
30
|
+
// (same pattern as autoDiscoverPresets) — Metro only marks a dependency as
|
|
31
|
+
// optional when the require is directly inside a try statement. Wrapping it
|
|
32
|
+
// in a helper/arrow makes Metro hard-fail the bundle for apps that don't
|
|
33
|
+
// install that package.
|
|
34
|
+
let externalSyncModule = null;
|
|
35
|
+
let storageModule = null;
|
|
36
|
+
let networkModule = null;
|
|
37
|
+
let reactQueryModule = null;
|
|
38
|
+
let routeEventsModule = null;
|
|
39
|
+
let reduxModule = null;
|
|
40
|
+
let zustandModule = null;
|
|
41
|
+
let jotaiModule = null;
|
|
42
|
+
let eventsModule = null;
|
|
43
|
+
let consoleModule = null;
|
|
44
|
+
let envModule = null;
|
|
45
|
+
let highlightUpdatesModule = null;
|
|
46
|
+
let debugBordersModule = null;
|
|
47
|
+
let impersonateModule = null;
|
|
48
|
+
let perfMonitorModule = null;
|
|
49
|
+
let expoConstantsModule = null;
|
|
50
|
+
try {
|
|
51
|
+
externalSyncModule = require("@buoy-gg/external-sync");
|
|
52
|
+
} catch {
|
|
53
|
+
// not installed
|
|
54
|
+
}
|
|
55
|
+
try {
|
|
56
|
+
storageModule = require("@buoy-gg/storage");
|
|
57
|
+
} catch {
|
|
58
|
+
// not installed
|
|
59
|
+
}
|
|
60
|
+
try {
|
|
61
|
+
networkModule = require("@buoy-gg/network");
|
|
62
|
+
} catch {
|
|
63
|
+
// not installed
|
|
64
|
+
}
|
|
65
|
+
try {
|
|
66
|
+
reactQueryModule = require("@buoy-gg/react-query");
|
|
67
|
+
} catch {
|
|
68
|
+
// not installed
|
|
69
|
+
}
|
|
70
|
+
try {
|
|
71
|
+
routeEventsModule = require("@buoy-gg/route-events");
|
|
72
|
+
} catch {
|
|
73
|
+
// not installed
|
|
74
|
+
}
|
|
75
|
+
try {
|
|
76
|
+
reduxModule = require("@buoy-gg/redux");
|
|
77
|
+
} catch {
|
|
78
|
+
// not installed
|
|
79
|
+
}
|
|
80
|
+
try {
|
|
81
|
+
zustandModule = require("@buoy-gg/zustand");
|
|
82
|
+
} catch {
|
|
83
|
+
// not installed
|
|
84
|
+
}
|
|
85
|
+
try {
|
|
86
|
+
jotaiModule = require("@buoy-gg/jotai");
|
|
87
|
+
} catch {
|
|
88
|
+
// not installed
|
|
89
|
+
}
|
|
90
|
+
try {
|
|
91
|
+
eventsModule = require("@buoy-gg/events");
|
|
92
|
+
} catch {
|
|
93
|
+
// not installed
|
|
94
|
+
}
|
|
95
|
+
try {
|
|
96
|
+
consoleModule = require("@buoy-gg/console");
|
|
97
|
+
} catch {
|
|
98
|
+
// not installed
|
|
99
|
+
}
|
|
100
|
+
try {
|
|
101
|
+
envModule = require("@buoy-gg/env");
|
|
102
|
+
} catch {
|
|
103
|
+
// not installed
|
|
104
|
+
}
|
|
105
|
+
try {
|
|
106
|
+
highlightUpdatesModule = require("@buoy-gg/highlight-updates");
|
|
107
|
+
} catch {
|
|
108
|
+
// not installed
|
|
109
|
+
}
|
|
110
|
+
try {
|
|
111
|
+
debugBordersModule = require("@buoy-gg/debug-borders");
|
|
112
|
+
} catch {
|
|
113
|
+
// not installed
|
|
114
|
+
}
|
|
115
|
+
try {
|
|
116
|
+
impersonateModule = require("@buoy-gg/impersonate");
|
|
117
|
+
} catch {
|
|
118
|
+
// not installed
|
|
119
|
+
}
|
|
120
|
+
try {
|
|
121
|
+
perfMonitorModule = require("@buoy-gg/perf-monitor");
|
|
122
|
+
} catch {
|
|
123
|
+
// not installed
|
|
124
|
+
}
|
|
125
|
+
try {
|
|
126
|
+
expoConstantsModule = require("expo-constants");
|
|
127
|
+
} catch {
|
|
128
|
+
// not installed (RN CLI apps)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/** Whether zero-config sync can run (the external-sync package is installed). */
|
|
132
|
+
function isExternalSyncAvailable() {
|
|
133
|
+
return !!externalSyncModule?.useExternalSyncSocket;
|
|
134
|
+
}
|
|
135
|
+
function getAppName() {
|
|
136
|
+
const constants = expoConstantsModule?.default ?? expoConstantsModule;
|
|
137
|
+
return constants?.expoConfig?.name ?? constants?.manifest2?.extra?.expoClient?.name ?? null;
|
|
138
|
+
}
|
|
139
|
+
function defaultIdentity() {
|
|
140
|
+
const appName = getAppName();
|
|
141
|
+
const slug = (appName ?? "buoy").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "");
|
|
142
|
+
return {
|
|
143
|
+
deviceName: `${appName ?? "Buoy Device"} (${_reactNative.Platform.OS})`,
|
|
144
|
+
deviceId: `${slug || "buoy"}-${_reactNative.Platform.OS}`
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
function AutoExternalSync({
|
|
148
|
+
options,
|
|
149
|
+
requiredEnvVars,
|
|
150
|
+
isPro,
|
|
151
|
+
licenseKey
|
|
152
|
+
}) {
|
|
153
|
+
const {
|
|
154
|
+
useExternalSyncSocket,
|
|
155
|
+
useExternalSync
|
|
156
|
+
} = externalSyncModule;
|
|
157
|
+
|
|
158
|
+
// Context-based query adapter; null when there is no QueryClientProvider
|
|
159
|
+
// above FloatingDevTools (or the installed @buoy-gg/react-query predates
|
|
160
|
+
// the hook).
|
|
161
|
+
const queryAdapter = reactQueryModule?.useReactQuerySyncAdapter ? reactQueryModule.useReactQuerySyncAdapter() : null;
|
|
162
|
+
const identity = (0, _react.useMemo)(defaultIdentity, []);
|
|
163
|
+
const deviceId = options?.deviceId ?? identity.deviceId;
|
|
164
|
+
const {
|
|
165
|
+
socket
|
|
166
|
+
} = useExternalSyncSocket({
|
|
167
|
+
deviceName: options?.deviceName ?? identity.deviceName,
|
|
168
|
+
socketURL: options?.socketURL ?? "http://localhost:42831",
|
|
169
|
+
persistentDeviceId: deviceId,
|
|
170
|
+
platform: _reactNative.Platform.OS,
|
|
171
|
+
enableLogs: options?.enableLogs
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
// The license validates asynchronously (Keygen call on mount), usually AFTER
|
|
175
|
+
// the socket handshake is already sent — so the one-shot handshake query
|
|
176
|
+
// can't carry Pro status reliably. Emit it as an event whenever it resolves
|
|
177
|
+
// or changes, and on every (re)connect. The broker stores it on the device
|
|
178
|
+
// record and rebroadcasts, so the desktop dashboard can auto-adopt the key.
|
|
179
|
+
const licenseRef = (0, _react.useRef)({
|
|
180
|
+
isPro,
|
|
181
|
+
licenseKey
|
|
182
|
+
});
|
|
183
|
+
licenseRef.current = {
|
|
184
|
+
isPro,
|
|
185
|
+
licenseKey
|
|
186
|
+
};
|
|
187
|
+
(0, _react.useEffect)(() => {
|
|
188
|
+
if (!socket) return;
|
|
189
|
+
const emitLicense = () => {
|
|
190
|
+
socket.emit("device-license", {
|
|
191
|
+
isPro: licenseRef.current.isPro ? "1" : "0",
|
|
192
|
+
licenseKey: licenseRef.current.licenseKey ?? ""
|
|
193
|
+
});
|
|
194
|
+
};
|
|
195
|
+
if (socket.connected) emitLicense();
|
|
196
|
+
socket.on("connect", emitLicense);
|
|
197
|
+
return () => {
|
|
198
|
+
socket.off("connect", emitLicense);
|
|
199
|
+
};
|
|
200
|
+
}, [socket, isPro, licenseKey]);
|
|
201
|
+
const tools = (0, _react.useMemo)(() => {
|
|
202
|
+
const map = {};
|
|
203
|
+
if (storageModule?.storageSyncAdapter) {
|
|
204
|
+
map.storage = storageModule.storageSyncAdapter;
|
|
205
|
+
}
|
|
206
|
+
if (networkModule?.networkSyncAdapter) {
|
|
207
|
+
map.network = networkModule.networkSyncAdapter;
|
|
208
|
+
}
|
|
209
|
+
if (queryAdapter) {
|
|
210
|
+
map.query = queryAdapter;
|
|
211
|
+
}
|
|
212
|
+
if (routeEventsModule?.routeEventsSyncAdapter) {
|
|
213
|
+
map["route-events"] = routeEventsModule.routeEventsSyncAdapter;
|
|
214
|
+
}
|
|
215
|
+
if (reduxModule?.reduxSyncAdapter) {
|
|
216
|
+
map.redux = reduxModule.reduxSyncAdapter;
|
|
217
|
+
}
|
|
218
|
+
if (zustandModule?.zustandSyncAdapter) {
|
|
219
|
+
map.zustand = zustandModule.zustandSyncAdapter;
|
|
220
|
+
}
|
|
221
|
+
if (jotaiModule?.jotaiSyncAdapter) {
|
|
222
|
+
map.jotai = jotaiModule.jotaiSyncAdapter;
|
|
223
|
+
}
|
|
224
|
+
if (eventsModule?.eventsSyncAdapter) {
|
|
225
|
+
map.events = eventsModule.eventsSyncAdapter;
|
|
226
|
+
}
|
|
227
|
+
if (consoleModule?.consoleSyncAdapter) {
|
|
228
|
+
map.console = consoleModule.consoleSyncAdapter;
|
|
229
|
+
}
|
|
230
|
+
if (envModule?.createEnvSyncAdapter) {
|
|
231
|
+
map.env = envModule.createEnvSyncAdapter(requiredEnvVars ?? []);
|
|
232
|
+
}
|
|
233
|
+
if (highlightUpdatesModule?.highlightUpdatesSyncAdapter) {
|
|
234
|
+
map["highlight-updates"] = highlightUpdatesModule.highlightUpdatesSyncAdapter;
|
|
235
|
+
}
|
|
236
|
+
if (debugBordersModule?.debugBordersSyncAdapter) {
|
|
237
|
+
map["debug-borders"] = debugBordersModule.debugBordersSyncAdapter;
|
|
238
|
+
}
|
|
239
|
+
if (impersonateModule?.impersonateSyncAdapter) {
|
|
240
|
+
map.impersonate = impersonateModule.impersonateSyncAdapter;
|
|
241
|
+
}
|
|
242
|
+
if (perfMonitorModule?.perfMonitorSyncAdapter) {
|
|
243
|
+
map["perf-monitor"] = perfMonitorModule.perfMonitorSyncAdapter;
|
|
244
|
+
}
|
|
245
|
+
return map;
|
|
246
|
+
}, [queryAdapter, requiredEnvVars]);
|
|
247
|
+
useExternalSync({
|
|
248
|
+
tools,
|
|
249
|
+
socket,
|
|
250
|
+
deviceId,
|
|
251
|
+
enableLogs: options?.enableLogs
|
|
252
|
+
});
|
|
253
|
+
return null;
|
|
254
|
+
}
|
|
@@ -32,7 +32,7 @@ exports.validateDialConfig = validateDialConfig;
|
|
|
32
32
|
* This is a union type of all auto-discovered tool IDs.
|
|
33
33
|
*/
|
|
34
34
|
|
|
35
|
-
//
|
|
35
|
+
// Benchmark recording modal (@buoy-gg/perf-monitor)
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
38
|
* Special floating-only tool IDs that only appear in the floating bubble row.
|