@buoy-gg/core 7.0.32 → 7.0.34
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/FloatingDevTools.js +24 -1
- package/lib/commonjs/floatingMenu/autoDiscoverPresets.js +21 -5
- package/lib/commonjs/floatingMenu/autoExternalSync.js +32 -17
- package/lib/commonjs/floatingMenu/deviceIdentity.js +173 -0
- package/lib/commonjs/floatingMenu/dial/DialDevTools.js +5 -46
- package/lib/commonjs/floatingMenu/dial/DialIcon.js +2 -46
- package/lib/commonjs/version.js +1 -1
- package/lib/module/floatingMenu/FloatingDevTools.js +24 -1
- package/lib/module/floatingMenu/autoDiscoverPresets.js +21 -5
- package/lib/module/floatingMenu/autoExternalSync.js +32 -17
- package/lib/module/floatingMenu/deviceIdentity.js +163 -0
- package/lib/module/floatingMenu/dial/DialDevTools.js +6 -47
- package/lib/module/floatingMenu/dial/DialIcon.js +2 -46
- package/lib/module/version.js +1 -1
- package/lib/typescript/commonjs/floatingMenu/FloatingDevTools.d.ts +38 -1
- package/lib/typescript/commonjs/floatingMenu/FloatingDevTools.d.ts.map +1 -1
- package/lib/typescript/commonjs/floatingMenu/autoDiscoverPresets.d.ts.map +1 -1
- package/lib/typescript/commonjs/floatingMenu/autoExternalSync.d.ts +12 -2
- package/lib/typescript/commonjs/floatingMenu/autoExternalSync.d.ts.map +1 -1
- 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/deviceIdentity.d.ts +66 -0
- package/lib/typescript/commonjs/floatingMenu/deviceIdentity.d.ts.map +1 -0
- package/lib/typescript/commonjs/floatingMenu/dial/DialDevTools.d.ts +0 -7
- 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/version.d.ts +1 -1
- package/lib/typescript/module/floatingMenu/FloatingDevTools.d.ts +38 -1
- package/lib/typescript/module/floatingMenu/FloatingDevTools.d.ts.map +1 -1
- package/lib/typescript/module/floatingMenu/autoDiscoverPresets.d.ts.map +1 -1
- package/lib/typescript/module/floatingMenu/autoExternalSync.d.ts +12 -2
- package/lib/typescript/module/floatingMenu/autoExternalSync.d.ts.map +1 -1
- 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/deviceIdentity.d.ts +66 -0
- package/lib/typescript/module/floatingMenu/deviceIdentity.d.ts.map +1 -0
- package/lib/typescript/module/floatingMenu/dial/DialDevTools.d.ts +0 -7
- 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/version.d.ts +1 -1
- package/package.json +5 -5
- package/lib/commonjs/floatingMenu/allToolsRegistry.js +0 -159
- package/lib/module/floatingMenu/allToolsRegistry.js +0 -155
- package/lib/typescript/commonjs/floatingMenu/allToolsRegistry.d.ts +0 -42
- package/lib/typescript/commonjs/floatingMenu/allToolsRegistry.d.ts.map +0 -1
- package/lib/typescript/module/floatingMenu/allToolsRegistry.d.ts +0 -42
- package/lib/typescript/module/floatingMenu/allToolsRegistry.d.ts.map +0 -1
|
@@ -12,13 +12,16 @@
|
|
|
12
12
|
* package, discovered with the same guarded-require pattern as
|
|
13
13
|
* autoDiscoverPresets. No <DevToolsSync> wiring needed in the app.
|
|
14
14
|
*
|
|
15
|
-
* Identity defaults come from
|
|
16
|
-
*
|
|
15
|
+
* Identity defaults come from deviceIdentity.ts: the app name (expo-constants)
|
|
16
|
+
* plus a persisted per-install tail, so two devices on one build register as
|
|
17
|
+
* two devices — "MyApp (iPhone 17 Pro · 2c1d)" / "myapp-ios-3f9a2c1d".
|
|
18
|
+
* Overridable via the `externalSync` prop.
|
|
17
19
|
*/
|
|
18
20
|
import { useEffect, useMemo, useRef } from "react";
|
|
19
21
|
import { Platform } from "react-native";
|
|
20
22
|
import { reportOptionalRequireError } from "./optionalRequire.js";
|
|
21
23
|
import { appSyncAdapter } from "./sync/appSyncAdapter.js";
|
|
24
|
+
import { useDeviceIdentity } from "./deviceIdentity.js";
|
|
22
25
|
import { registerToolAdapters } from "@buoy-gg/shared-ui";
|
|
23
26
|
|
|
24
27
|
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
@@ -41,6 +44,7 @@ let zustandModule = null;
|
|
|
41
44
|
let jotaiModule = null;
|
|
42
45
|
let eventsModule = null;
|
|
43
46
|
let consoleModule = null;
|
|
47
|
+
let sentryModule = null;
|
|
44
48
|
let envModule = null;
|
|
45
49
|
let highlightUpdatesModule = null;
|
|
46
50
|
let debugBordersModule = null;
|
|
@@ -106,6 +110,11 @@ try {
|
|
|
106
110
|
} catch (e) {
|
|
107
111
|
reportOptionalRequireError("@buoy-gg/console", e);
|
|
108
112
|
}
|
|
113
|
+
try {
|
|
114
|
+
sentryModule = require("@buoy-gg/sentry");
|
|
115
|
+
} catch (e) {
|
|
116
|
+
reportOptionalRequireError("@buoy-gg/sentry", e);
|
|
117
|
+
}
|
|
109
118
|
try {
|
|
110
119
|
envModule = require("@buoy-gg/env");
|
|
111
120
|
} catch (e) {
|
|
@@ -171,13 +180,12 @@ function getAppName() {
|
|
|
171
180
|
const constants = expoConstantsModule?.default ?? expoConstantsModule;
|
|
172
181
|
return constants?.expoConfig?.name ?? constants?.manifest2?.extra?.expoClient?.name ?? null;
|
|
173
182
|
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
};
|
|
183
|
+
|
|
184
|
+
/** expo-constants' `deviceName`: the simulator's name on a sim, the model on Android. */
|
|
185
|
+
function getHardwareName() {
|
|
186
|
+
const constants = expoConstantsModule?.default ?? expoConstantsModule;
|
|
187
|
+
const name = constants?.deviceName;
|
|
188
|
+
return typeof name === "string" && name.length > 0 ? name : null;
|
|
181
189
|
}
|
|
182
190
|
/**
|
|
183
191
|
* Build the `toolId -> sync adapter` map from whatever tool packages the app
|
|
@@ -241,12 +249,16 @@ export function AutoExternalSync({
|
|
|
241
249
|
requiredEnvVars,
|
|
242
250
|
customApps
|
|
243
251
|
});
|
|
244
|
-
const identity =
|
|
245
|
-
|
|
252
|
+
const identity = useDeviceIdentity(options, {
|
|
253
|
+
appName: getAppName(),
|
|
254
|
+
hardwareName: getHardwareName(),
|
|
255
|
+
platform: Platform.OS
|
|
256
|
+
});
|
|
257
|
+
const deviceId = identity?.deviceId ?? null;
|
|
246
258
|
const {
|
|
247
259
|
socket
|
|
248
260
|
} = useExternalSyncSocket({
|
|
249
|
-
deviceName:
|
|
261
|
+
deviceName: identity?.deviceName ?? "Buoy Device",
|
|
250
262
|
// Older external-sync versions predate getDefaultSocketURL and require
|
|
251
263
|
// an explicit URL — keep the literal fallback for them.
|
|
252
264
|
socketURL: options?.socketURL ?? externalSyncModule.getDefaultSocketURL?.() ?? "http://localhost:42831",
|
|
@@ -335,6 +347,9 @@ function useToolAdapterMapInner(queryAdapter, requiredEnvVars, customApps) {
|
|
|
335
347
|
if (consoleModule?.consoleSyncAdapter) {
|
|
336
348
|
map.console = consoleModule.consoleSyncAdapter;
|
|
337
349
|
}
|
|
350
|
+
if (sentryModule?.sentrySyncAdapter) {
|
|
351
|
+
map.sentry = sentryModule.sentrySyncAdapter;
|
|
352
|
+
}
|
|
338
353
|
// Lazy: time-machine imports `@buoy-gg/core` (useToolHost), and this file
|
|
339
354
|
// is loaded from core's index. Requiring it at module top-level is a
|
|
340
355
|
// require cycle (LogBox on every reload). Waiting until first render
|
|
@@ -358,14 +373,14 @@ function useToolAdapterMapInner(queryAdapter, requiredEnvVars, customApps) {
|
|
|
358
373
|
reportOptionalRequireError("@buoy-gg/scenarios", e);
|
|
359
374
|
}
|
|
360
375
|
// Lazy, same require-cycle reason as time-machine and scenarios: the
|
|
361
|
-
//
|
|
376
|
+
// ask-buoy package imports `@buoy-gg/core` for the tool-host hooks.
|
|
362
377
|
try {
|
|
363
|
-
const
|
|
364
|
-
if (
|
|
365
|
-
map
|
|
378
|
+
const askBuoyModule = require("@buoy-gg/ask-buoy");
|
|
379
|
+
if (askBuoyModule?.askBuoySyncAdapter) {
|
|
380
|
+
map["ask-buoy"] = askBuoyModule.askBuoySyncAdapter;
|
|
366
381
|
}
|
|
367
382
|
} catch (e) {
|
|
368
|
-
reportOptionalRequireError("@buoy-gg/
|
|
383
|
+
reportOptionalRequireError("@buoy-gg/ask-buoy", e);
|
|
369
384
|
}
|
|
370
385
|
if (envModule?.createEnvSyncAdapter) {
|
|
371
386
|
map.env = envModule.createEnvSyncAdapter(requiredEnvVars ?? []);
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* How a device introduces itself to the Buoy Desktop broker.
|
|
5
|
+
*
|
|
6
|
+
* The id used to be `<app-slug>-<platform>` — a BUILD identity, not a device
|
|
7
|
+
* identity. Every phone and simulator running the same app registered under
|
|
8
|
+
* the same id, and the broker (which deliberately lets one device hold
|
|
9
|
+
* several sockets for Fast Refresh) treated each newcomer as a reconnect and
|
|
10
|
+
* handed it the identity. Actions then landed on whichever device connected
|
|
11
|
+
* most recently, silently. See DEVICE_IDENTITY_COLLISION.md.
|
|
12
|
+
*
|
|
13
|
+
* Now the id carries a per-install tail minted once and persisted:
|
|
14
|
+
*
|
|
15
|
+
* deviceId = "<app-slug>-<platform>-<8 hex>" e.g. acme-app-ios-3f9a2c1d
|
|
16
|
+
* deviceName = "<App Name> (<hardware> · <last 4>)" e.g. Acme App (iPhone 17 Pro · 2c1d)
|
|
17
|
+
*
|
|
18
|
+
* The tail is what makes two devices on one build two devices. The name's
|
|
19
|
+
* hardware label comes from expo-constants' `deviceName` when available (the
|
|
20
|
+
* simulator's own name on a sim, "iPhone" on iOS 16+ hardware, the model on
|
|
21
|
+
* Android) and falls back to the platform; the 4-char tail is always on so
|
|
22
|
+
* two identical simulators never share a label.
|
|
23
|
+
*
|
|
24
|
+
* Persistence: native goes through shared's `persistentStorage` (file system
|
|
25
|
+
* → AsyncStorage → memory); web uses `sessionStorage` so every browser TAB
|
|
26
|
+
* is its own device — `localStorage` is shared across tabs and would collide
|
|
27
|
+
* exactly the way the old default did. The id does not survive a reinstall
|
|
28
|
+
* on purpose: it crosses an unauthenticated LAN socket, and deleting the app
|
|
29
|
+
* should reset it.
|
|
30
|
+
*
|
|
31
|
+
* An explicit `externalSync.deviceId` bypasses all of this; whoever pins an
|
|
32
|
+
* id owns its uniqueness.
|
|
33
|
+
*/
|
|
34
|
+
import { useEffect, useMemo, useState } from "react";
|
|
35
|
+
import { Platform } from "react-native";
|
|
36
|
+
import { devToolsStorageKeys, persistentStorage } from "@buoy-gg/shared-ui";
|
|
37
|
+
|
|
38
|
+
/** Minimal getItem/setItem surface, so storage can be injected in tests. */
|
|
39
|
+
|
|
40
|
+
export const INSTALL_ID_LENGTH = 8;
|
|
41
|
+
|
|
42
|
+
/** 8 lowercase hex chars — short enough to read, random enough for a LAN. */
|
|
43
|
+
export function generateInstallId() {
|
|
44
|
+
let out = "";
|
|
45
|
+
while (out.length < INSTALL_ID_LENGTH) {
|
|
46
|
+
out += (Math.random() * 16 | 0).toString(16);
|
|
47
|
+
}
|
|
48
|
+
return out;
|
|
49
|
+
}
|
|
50
|
+
function slugify(name) {
|
|
51
|
+
return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "");
|
|
52
|
+
}
|
|
53
|
+
/** Pure: turns the inputs into the id/name pair the broker sees. */
|
|
54
|
+
export function buildDeviceIdentity({
|
|
55
|
+
appName,
|
|
56
|
+
hardwareName,
|
|
57
|
+
platform,
|
|
58
|
+
installId,
|
|
59
|
+
deviceId
|
|
60
|
+
}) {
|
|
61
|
+
const slug = slugify(appName ?? "buoy") || "buoy";
|
|
62
|
+
const label = appName ?? "Buoy Device";
|
|
63
|
+
const hardware = hardwareName?.trim() || platform;
|
|
64
|
+
if (deviceId) {
|
|
65
|
+
// The app pinned its own id: it can also pin its own name, so keep the
|
|
66
|
+
// default name free of a tail that would refer to an id nobody sees.
|
|
67
|
+
return {
|
|
68
|
+
deviceId,
|
|
69
|
+
deviceName: `${label} (${hardware})`
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
const id = `${slug}-${platform}-${installId}`;
|
|
73
|
+
return {
|
|
74
|
+
deviceId: id,
|
|
75
|
+
deviceName: `${label} (${hardware} · ${installId.slice(-4)})`
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Web: every tab is a device, so the id lives in the tab's sessionStorage.
|
|
80
|
+
function sessionStore() {
|
|
81
|
+
const g = globalThis;
|
|
82
|
+
try {
|
|
83
|
+
return g.sessionStorage ?? null;
|
|
84
|
+
} catch {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* The persisted per-install tail: read it, or mint and store it on the first
|
|
90
|
+
* dial. Storage failures degrade to a fresh in-memory id rather than blocking
|
|
91
|
+
* the socket — a per-launch id still beats the old colliding one.
|
|
92
|
+
*/
|
|
93
|
+
export async function loadInstallId({
|
|
94
|
+
platform = Platform.OS,
|
|
95
|
+
store,
|
|
96
|
+
mint = generateInstallId
|
|
97
|
+
} = {}) {
|
|
98
|
+
const key = devToolsStorageKeys.sync.deviceId();
|
|
99
|
+
const target = store === undefined ? platform === "web" ? sessionStore() : persistentStorage : store;
|
|
100
|
+
if (!target) return mint();
|
|
101
|
+
try {
|
|
102
|
+
const existing = await target.getItem(key);
|
|
103
|
+
if (existing && existing.length > 0) return existing;
|
|
104
|
+
const fresh = mint();
|
|
105
|
+
await target.setItem(key, fresh);
|
|
106
|
+
return fresh;
|
|
107
|
+
} catch {
|
|
108
|
+
return mint();
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
let installIdPromise = null;
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Process-wide memo so every mount (and every Fast Refresh of the component
|
|
115
|
+
* that calls it) shares one storage round-trip and one id.
|
|
116
|
+
*/
|
|
117
|
+
export function getInstallId() {
|
|
118
|
+
if (!installIdPromise) installIdPromise = loadInstallId();
|
|
119
|
+
return installIdPromise;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** Tests only. */
|
|
123
|
+
export function resetInstallIdForTests() {
|
|
124
|
+
installIdPromise = null;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* The identity to dial with. Null until the per-install id is read from
|
|
128
|
+
* storage (one round-trip on first mount; memoized process-wide after) —
|
|
129
|
+
* both sync hooks no-op on a null id, so the socket simply dials a beat
|
|
130
|
+
* later. An explicit `deviceId` skips the read entirely; an explicit
|
|
131
|
+
* `deviceName` is used verbatim.
|
|
132
|
+
*/
|
|
133
|
+
export function useDeviceIdentity(options, env) {
|
|
134
|
+
const pinnedId = options?.deviceId;
|
|
135
|
+
const pinnedName = options?.deviceName;
|
|
136
|
+
const loadId = env.loadId ?? getInstallId;
|
|
137
|
+
const platform = env.platform ?? Platform.OS;
|
|
138
|
+
const [installId, setInstallId] = useState(null);
|
|
139
|
+
useEffect(() => {
|
|
140
|
+
if (pinnedId) return;
|
|
141
|
+
let cancelled = false;
|
|
142
|
+
loadId().then(id => {
|
|
143
|
+
if (!cancelled) setInstallId(id);
|
|
144
|
+
});
|
|
145
|
+
return () => {
|
|
146
|
+
cancelled = true;
|
|
147
|
+
};
|
|
148
|
+
}, [pinnedId, loadId]);
|
|
149
|
+
return useMemo(() => {
|
|
150
|
+
if (!pinnedId && !installId) return null;
|
|
151
|
+
const identity = buildDeviceIdentity({
|
|
152
|
+
appName: env.appName,
|
|
153
|
+
hardwareName: env.hardwareName,
|
|
154
|
+
platform,
|
|
155
|
+
installId: installId ?? "",
|
|
156
|
+
deviceId: pinnedId
|
|
157
|
+
});
|
|
158
|
+
return pinnedName ? {
|
|
159
|
+
...identity,
|
|
160
|
+
deviceName: pinnedName
|
|
161
|
+
} : identity;
|
|
162
|
+
}, [pinnedId, pinnedName, installId, env.appName, env.hardwareName, platform]);
|
|
163
|
+
}
|
|
@@ -6,7 +6,6 @@ import { absoluteFill } from "@buoy-gg/shared-ui";
|
|
|
6
6
|
// Icons are provided by installedApps; no direct icon imports here.
|
|
7
7
|
import { DialIcon } from "./DialIcon.js";
|
|
8
8
|
import { DialHyperspace } from "./DialHyperspace.js";
|
|
9
|
-
import { ALL_TOOLS_REGISTRY } from "../allToolsRegistry.js";
|
|
10
9
|
import { DialPagination } from "./DialPagination.js";
|
|
11
10
|
import { getRankedToolIds, isDialUsageLoaded, loadDialUsage, recordToolUsage } from "./dialUsageStore.js";
|
|
12
11
|
import { persistentStorage, useHintsDisabled, devToolsStorageKeys, buoyColors, ToolBackground, useToolBackground } from "@buoy-gg/shared-ui";
|
|
@@ -15,7 +14,7 @@ import { useProAccess } from "@buoy-gg/license";
|
|
|
15
14
|
import { renderAppIcon } from "../AppIcon.js";
|
|
16
15
|
import { useAppHost } from "../AppHost";
|
|
17
16
|
import { OnboardingTooltip } from "./OnboardingTooltip";
|
|
18
|
-
import { getDialLayout, MAX_DIAL_SLOTS, DIAL_BUTTON_SIZE,
|
|
17
|
+
import { getDialLayout, MAX_DIAL_SLOTS, DIAL_BUTTON_SIZE, dialAnimationConfig, dialColors } from "@buoy-gg/floating-tools-core";
|
|
19
18
|
|
|
20
19
|
// The circle size depends on the live window width, so it's computed inside
|
|
21
20
|
// the component via useWindowDimensions — a module-scope Dimensions.get
|
|
@@ -258,38 +257,6 @@ export const DialDevTools = ({
|
|
|
258
257
|
return map;
|
|
259
258
|
}, [dialApps, actions, open, onClose]);
|
|
260
259
|
|
|
261
|
-
// Tools from the global registry that are NOT installed in this app.
|
|
262
|
-
// These are appended after all available tools so paging "next" eventually
|
|
263
|
-
// reveals them. They are display-only (real icon + real name + "Unavailable").
|
|
264
|
-
const unavailableTools = useMemo(() => {
|
|
265
|
-
const installedIds = new Set(dialApps.map(a => a.id));
|
|
266
|
-
return ALL_TOOLS_REGISTRY.filter(t => !installedIds.has(t.id));
|
|
267
|
-
}, [dialApps]);
|
|
268
|
-
|
|
269
|
-
// Build stable IconType entries for each unavailable tool.
|
|
270
|
-
const unavailableIconsById = useMemo(() => {
|
|
271
|
-
const map = new Map();
|
|
272
|
-
for (const tool of unavailableTools) {
|
|
273
|
-
map.set(tool.id, {
|
|
274
|
-
id: tool.id,
|
|
275
|
-
name: tool.name,
|
|
276
|
-
// Pre-render the icon at the standard GLYPH size (not the slot size —
|
|
277
|
-
// the slot also holds the label + "Unavailable" caption, so a glyph
|
|
278
|
-
// rendered at DIAL_ICON_SIZE overflows the slot and looks ~2x bigger
|
|
279
|
-
// than installed tools' icons).
|
|
280
|
-
icon: tool.renderIcon(DIAL_ICON_GLYPH_SIZE),
|
|
281
|
-
iconComponent: undefined,
|
|
282
|
-
color: tool.color,
|
|
283
|
-
unavailable: true,
|
|
284
|
-
// Tapping an unavailable tool is intentionally a no-op: the dial stays
|
|
285
|
-
// open and no modal launches, signalling the tool is not installed.
|
|
286
|
-
// Future: add a brief Toast with an install link here.
|
|
287
|
-
onPress: () => {}
|
|
288
|
-
});
|
|
289
|
-
}
|
|
290
|
-
return map;
|
|
291
|
-
}, [unavailableTools]);
|
|
292
|
-
|
|
293
260
|
// Snapshot the usage-ranked order when the dial opens. It stays stable while
|
|
294
261
|
// open so icons don't jump positions mid-interaction.
|
|
295
262
|
const [rankedIds, setRankedIds] = useState(() => getRankedToolIds(dialApps.map(a => a.id)));
|
|
@@ -309,8 +276,9 @@ export const DialDevTools = ({
|
|
|
309
276
|
};
|
|
310
277
|
}, [dialApps]);
|
|
311
278
|
|
|
312
|
-
// Page count spans
|
|
313
|
-
|
|
279
|
+
// Page count spans the installed tools (usage-ranked). Only tools the app
|
|
280
|
+
// actually has appear in the dial — nothing is shown for uninstalled ones.
|
|
281
|
+
const pageCount = Math.max(1, Math.ceil(rankedIds.length / MAX_DIAL_SLOTS));
|
|
314
282
|
const [currentPage, setCurrentPage] = useState(0);
|
|
315
283
|
const safePage = Math.min(currentPage, pageCount - 1);
|
|
316
284
|
|
|
@@ -318,18 +286,13 @@ export const DialDevTools = ({
|
|
|
318
286
|
// snapshotted on open, so each icon's page and slot are fixed for the
|
|
319
287
|
// session — which lets us mount all icons once and paginate purely by
|
|
320
288
|
// toggling visibility (no remounts on page change).
|
|
321
|
-
//
|
|
322
|
-
// Order: usage-ranked available tools first, unavailable tools appended at
|
|
323
|
-
// the very end. This guarantees unavailable items always appear on the last
|
|
324
|
-
// pages and never displace available tools.
|
|
325
289
|
const allDialIcons = useMemo(() => {
|
|
326
|
-
|
|
327
|
-
return allIds.map(id => iconsById.get(id) ?? unavailableIconsById.get(id)).filter(icon => Boolean(icon)).map((icon, i) => ({
|
|
290
|
+
return rankedIds.map(id => iconsById.get(id)).filter(icon => Boolean(icon)).map((icon, i) => ({
|
|
328
291
|
icon,
|
|
329
292
|
page: Math.floor(i / MAX_DIAL_SLOTS),
|
|
330
293
|
slot: i % MAX_DIAL_SLOTS
|
|
331
294
|
}));
|
|
332
|
-
}, [rankedIds, iconsById
|
|
295
|
+
}, [rankedIds, iconsById]);
|
|
333
296
|
|
|
334
297
|
// Empty slot indices for the current page (only the last page can be
|
|
335
298
|
// partial). These are cheap placeholder dots.
|
|
@@ -532,10 +495,6 @@ export const DialDevTools = ({
|
|
|
532
495
|
});
|
|
533
496
|
};
|
|
534
497
|
const handleIconPress = icon => {
|
|
535
|
-
// Unavailable tools are display-only. Return early so the dial stays open
|
|
536
|
-
// and no modal or animation is triggered. The dimmed appearance already
|
|
537
|
-
// communicates that the tool is not installed.
|
|
538
|
-
if (icon.unavailable) return;
|
|
539
498
|
setSelectedIcon(1);
|
|
540
499
|
const interaction = dialAnimationConfig?.interaction ?? {
|
|
541
500
|
iconSelect: {
|
|
@@ -183,35 +183,6 @@ export const DialIcon = ({
|
|
|
183
183
|
children: /*#__PURE__*/_jsx(View, {
|
|
184
184
|
style: styles.emptyDot
|
|
185
185
|
})
|
|
186
|
-
}) : icon.unavailable ?
|
|
187
|
-
/*#__PURE__*/
|
|
188
|
-
// ── Unavailable tool ──────────────────────────────────────────────────
|
|
189
|
-
// Renders the real icon + real name at NORMAL styling (visually identical
|
|
190
|
-
// to an installed tool). The ONLY signal that it's unavailable is the small
|
|
191
|
-
// muted "Unavailable" caption under the name. It's non-interactive: no
|
|
192
|
-
// Pressable, and the dial stays open when tapped because
|
|
193
|
-
// DialDevTools.handleIconPress returns early for unavailable icons.
|
|
194
|
-
_jsxs(View, {
|
|
195
|
-
style: styles.pressable,
|
|
196
|
-
children: [/*#__PURE__*/_jsx(View, {
|
|
197
|
-
style: styles.iconWrapper,
|
|
198
|
-
children: /*#__PURE__*/_jsx(View, {
|
|
199
|
-
style: styles.iconClamp,
|
|
200
|
-
children: icon.icon
|
|
201
|
-
})
|
|
202
|
-
}), /*#__PURE__*/_jsx(Text, {
|
|
203
|
-
style: styles.label,
|
|
204
|
-
numberOfLines: 1,
|
|
205
|
-
adjustsFontSizeToFit: true,
|
|
206
|
-
minimumFontScale: 0.7,
|
|
207
|
-
children: icon.name.toUpperCase()
|
|
208
|
-
}), /*#__PURE__*/_jsx(Text, {
|
|
209
|
-
style: styles.unavailableCaption,
|
|
210
|
-
numberOfLines: 1,
|
|
211
|
-
adjustsFontSizeToFit: true,
|
|
212
|
-
minimumFontScale: 0.6,
|
|
213
|
-
children: "Unavailable"
|
|
214
|
-
})]
|
|
215
186
|
}) : /*#__PURE__*/_jsxs(Pressable, {
|
|
216
187
|
onPress: () => onPress(icon),
|
|
217
188
|
onPressIn: handlePressIn,
|
|
@@ -289,8 +260,8 @@ const styles = StyleSheet.create({
|
|
|
289
260
|
},
|
|
290
261
|
/**
|
|
291
262
|
* Hard clamp for PRE-RENDERED icon nodes (icon.icon) — the path where the
|
|
292
|
-
* glyph's size is baked in by whoever created the node (
|
|
293
|
-
*
|
|
263
|
+
* glyph's size is baked in by whoever created the node (consumer custom
|
|
264
|
+
* tools) rather than controlled here. The
|
|
294
265
|
* fixed overflow-hidden box guarantees an oversized node can never blow past
|
|
295
266
|
* its slot and dwarf neighboring icons — worst case it center-crops. The
|
|
296
267
|
* iconComponent path stays unclipped: we render it at DIAL_ICON_GLYPH_SIZE
|
|
@@ -324,20 +295,5 @@ const styles = StyleSheet.create({
|
|
|
324
295
|
backgroundColor: dialColors.emptyDotBackground,
|
|
325
296
|
borderWidth: dialStyles.emptySlot.borderWidth,
|
|
326
297
|
borderColor: dialColors.emptyDotBorder
|
|
327
|
-
},
|
|
328
|
-
// ── Unavailable tool styles ────────────────────────────────────────────────
|
|
329
|
-
/**
|
|
330
|
-
* Small muted caption shown under the (normal-styled) tool name — the only
|
|
331
|
-
* signal that the tool is not installed. Kept compact (smaller than the label)
|
|
332
|
-
* so the extra line doesn't disturb the arc layout. Uses the shared muted
|
|
333
|
-
* theme token rather than a hardcoded color.
|
|
334
|
-
*/
|
|
335
|
-
unavailableCaption: {
|
|
336
|
-
fontSize: dialStyles.icon.label.fontSize - 1,
|
|
337
|
-
fontWeight: dialStyles.icon.label.fontWeight,
|
|
338
|
-
letterSpacing: dialStyles.icon.label.letterSpacing,
|
|
339
|
-
fontFamily: dialStyles.icon.label.fontFamily,
|
|
340
|
-
color: dialColors.iconLabelMuted,
|
|
341
|
-
textTransform: "uppercase"
|
|
342
298
|
}
|
|
343
299
|
});
|
package/lib/module/version.js
CHANGED
|
@@ -39,6 +39,25 @@ export interface StorageKeyConfig {
|
|
|
39
39
|
description?: string;
|
|
40
40
|
storageType: "async" | "secure" | "mmkv";
|
|
41
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* Ask Buoy's config, mirrored structurally so core never depends on the
|
|
44
|
+
* optional `@buoy-gg/ask-buoy` package (it is required lazily, like every other
|
|
45
|
+
* tool). The object is handed to `createAskBuoyTool` untouched, so any field
|
|
46
|
+
* that package accepts passes through — the index signature is the seam.
|
|
47
|
+
*/
|
|
48
|
+
export interface FloatingAskBuoyConfig {
|
|
49
|
+
/** Your company's own LLM gateway. Buoy never proxies or holds a key. */
|
|
50
|
+
endpoint: string;
|
|
51
|
+
/** Model id passed through to the endpoint. */
|
|
52
|
+
model: string;
|
|
53
|
+
/** Which request/response shape the endpoint speaks. @default "anthropic" */
|
|
54
|
+
protocol?: "anthropic" | "openai";
|
|
55
|
+
/** Resolved fresh per request — the app's own short-lived session token. */
|
|
56
|
+
headers?: () => Record<string, string> | Promise<Record<string, string>>;
|
|
57
|
+
/** DEV ONLY — compiled into the bundle in plaintext. Use `headers` + a gateway. */
|
|
58
|
+
apiKey?: string;
|
|
59
|
+
[key: string]: unknown;
|
|
60
|
+
}
|
|
42
61
|
/**
|
|
43
62
|
* Props for FloatingDevTools component.
|
|
44
63
|
*
|
|
@@ -101,6 +120,24 @@ export interface FloatingDevToolsProps extends Omit<FloatingMenuProps, "apps"> {
|
|
|
101
120
|
* ```
|
|
102
121
|
*/
|
|
103
122
|
requiredStorageKeys?: StorageKeyConfig[];
|
|
123
|
+
/**
|
|
124
|
+
* Wire Ask Buoy (the in-app AI chat) to your team's AI endpoint — the
|
|
125
|
+
* documented one-prop setup. Requires `@buoy-gg/ask-buoy` to be installed;
|
|
126
|
+
* the config is exactly what `createAskBuoyTool` takes and passes through
|
|
127
|
+
* untouched.
|
|
128
|
+
*
|
|
129
|
+
* @example
|
|
130
|
+
* ```tsx
|
|
131
|
+
* <FloatingDevTools
|
|
132
|
+
* askBuoy={{
|
|
133
|
+
* endpoint: "https://ai.acme.com/v1/messages",
|
|
134
|
+
* model: "claude-sonnet-4-5",
|
|
135
|
+
* headers: async () => ({ Authorization: `Bearer ${await auth.getToken()}` }),
|
|
136
|
+
* }}
|
|
137
|
+
* />
|
|
138
|
+
* ```
|
|
139
|
+
*/
|
|
140
|
+
askBuoy?: FloatingAskBuoyConfig;
|
|
104
141
|
/**
|
|
105
142
|
* Optional children to render within the DevToolsVisibilityProvider context.
|
|
106
143
|
* Useful for tools that need to react to DevTools visibility (like DebugBordersStandaloneOverlay).
|
|
@@ -331,5 +368,5 @@ export interface FloatingDevToolsProps extends Omit<FloatingMenuProps, "apps"> {
|
|
|
331
368
|
*
|
|
332
369
|
* @param props - FloatingDevTools props
|
|
333
370
|
*/
|
|
334
|
-
export declare const FloatingDevTools: ({ apps, requiredEnvVars, requiredStorageKeys, children, disableHints, defaultFloatingTools, defaultDialTools, requireLicense, licenseKey: licenseKeyProp, zustandStores, environment, externalSync, headless, ...props }: FloatingDevToolsProps) => React.JSX.Element | null;
|
|
371
|
+
export declare const FloatingDevTools: ({ apps, requiredEnvVars, requiredStorageKeys, askBuoy, children, disableHints, defaultFloatingTools, defaultDialTools, requireLicense, licenseKey: licenseKeyProp, zustandStores, environment, externalSync, headless, ...props }: FloatingDevToolsProps) => React.JSX.Element | null;
|
|
335
372
|
//# sourceMappingURL=FloatingDevTools.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FloatingDevTools.d.ts","sourceRoot":"","sources":["../../../../src/floatingMenu/FloatingDevTools.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA+D,MAAM,OAAO,CAAC;AAGpF,OAAO,EAAgB,KAAK,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAOtE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAQ5C,OAAO,EACL,KAAK,qBAAqB,EAC1B,KAAK,iBAAiB,EAEvB,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAIL,KAAK,mBAAmB,EACzB,MAAM,oBAAoB,CAAC;AAM5B;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,MAAM,YAAY,GACpB,MAAM,GACN;IACE,GAAG,EAAE,MAAM,CAAC;IACZ,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,GACD;IACE,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,EACR,QAAQ,GACR,QAAQ,GACR,SAAS,GACT,QAAQ,GACR,OAAO,GACP,KAAK,CAAC;IACV,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEN;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,CAAC;IAC1D,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;CAC1C;AAED;;;;;;GAMG;AACH,MAAM,WAAW,qBAAsB,SAAQ,IAAI,CAAC,iBAAiB,EAAE,MAAM,CAAC;IAC5E;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,IAAI,CAAC,EAAE,YAAY,EAAE,CAAC;IAEtB;;;;;;;;;;;;;;OAcG;IACH,eAAe,CAAC,EAAE,YAAY,EAAE,CAAC;IAEjC;;;;;;;;;;;;OAYG;IACH,mBAAmB,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAEzC;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAE3B;;;;;;;;;OASG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB;;;;;;;;;;;;;OAaG;IACH,oBAAoB,CAAC,EAAE,qBAAqB,CAAC;IAE7C;;;;;;;;;;;;;;OAcG;IACH,gBAAgB,CAAC,EAAE,iBAAiB,CAAC;IAErC;;;;;;;;;;;;;;;;OAgBG;IACH,qBAAqB,CAAC,EAAE,OAAO,oBAAoB,EAAE,WAAW,EAAE,CAAC;IAEnE;;;;;;;;;;;;;OAaG;IACH,mBAAmB,CAAC,EAAE,CAAC,WAAW,EAAE,OAAO,oBAAoB,EAAE,WAAW,KAAK,IAAI,CAAC;IAEtF;;;;;;;;;;OAUG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IAEzB;;;;;;;;OAQG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;;;;;;;;;;;;;;;;OAkBG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAEpC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAgCG;IACH,YAAY,CAAC,EAAE,OAAO,GAAG,mBAAmB,CAAC;IAE7C;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AACH,eAAO,MAAM,gBAAgB,GAAI,
|
|
1
|
+
{"version":3,"file":"FloatingDevTools.d.ts","sourceRoot":"","sources":["../../../../src/floatingMenu/FloatingDevTools.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"autoDiscoverPresets.d.ts","sourceRoot":"","sources":["../../../../src/floatingMenu/autoDiscoverPresets.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAG5C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AACH,wBAAgB,mBAAmB,IAAI,YAAY,EAAE,
|
|
1
|
+
{"version":3,"file":"autoDiscoverPresets.d.ts","sourceRoot":"","sources":["../../../../src/floatingMenu/autoDiscoverPresets.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAG5C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AACH,wBAAgB,mBAAmB,IAAI,YAAY,EAAE,CA4UpD;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,6BAA6B,CAC3C,WAAW,EAAE,YAAY,EAAE,GAC1B,YAAY,EAAE,CAahB"}
|
|
@@ -12,9 +12,19 @@ export interface ExternalSyncOptions {
|
|
|
12
12
|
* broker on another machine.
|
|
13
13
|
*/
|
|
14
14
|
socketURL?: string;
|
|
15
|
-
/**
|
|
15
|
+
/**
|
|
16
|
+
* Shown in the desktop device list.
|
|
17
|
+
* @default "<app name> (<hardware> · <last 4 of the id>)"
|
|
18
|
+
*/
|
|
16
19
|
deviceName?: string;
|
|
17
|
-
/**
|
|
20
|
+
/**
|
|
21
|
+
* Stable device identity across restarts. Leave unset: the default is
|
|
22
|
+
* `<app-slug>-<platform>-<per-install id>`, minted once and persisted, so
|
|
23
|
+
* every device running this build is its own entry in Buoy Desktop and
|
|
24
|
+
* `list_devices`. If you do pin one, it MUST be unique per device — two
|
|
25
|
+
* devices sharing an id look like one device to the broker, and actions
|
|
26
|
+
* land on whichever connected last.
|
|
27
|
+
*/
|
|
18
28
|
deviceId?: string;
|
|
19
29
|
/**
|
|
20
30
|
* Allow this build to dial the broker when `__DEV__` is false (a release /
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"autoExternalSync.d.ts","sourceRoot":"","sources":["../../../../src/floatingMenu/autoExternalSync.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"autoExternalSync.d.ts","sourceRoot":"","sources":["../../../../src/floatingMenu/autoExternalSync.tsx"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AA6JjD,iFAAiF;AACjF,wBAAgB,uBAAuB,IAAI,OAAO,CAEjD;AAED,MAAM,WAAW,mBAAmB;IAClC;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;;;;;;;;;;;;;;OAiBG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,qBAAqB;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAkBD,UAAU,qBAAqB;IAC7B,OAAO,CAAC,EAAE,mBAAmB,CAAC;IAC9B,6EAA6E;IAC7E,eAAe,CAAC,EAAE,YAAY,EAAE,CAAC;IACjC,8EAA8E;IAC9E,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB;;;;OAIG;IACH,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,mEAAmE;IACnE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B;;;;OAIG;IACH,UAAU,CAAC,EAAE,YAAY,EAAE,CAAC;CAC7B;AAED,MAAM,WAAW,mBAAmB;IAClC,eAAe,CAAC,EAAE,YAAY,EAAE,CAAC;IACjC,UAAU,CAAC,EAAE,YAAY,EAAE,CAAC;CAC7B;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,eAAe,EACf,UAAU,GACX,EAAE,mBAAmB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAS/C;AAED;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,EACpC,eAAe,EACf,UAAU,GACX,EAAE,mBAAmB,QAYrB;AAED,wBAAgB,gBAAgB,CAAC,EAC/B,OAAO,EACP,eAAe,EACf,KAAK,EACL,IAAI,EACJ,UAAU,EACV,UAAU,GACX,EAAE,qBAAqB,QA2DvB"}
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
* All known tool IDs that can appear in the floating menu or dial menu.
|
|
20
20
|
* This is a union type of all auto-discovered tool IDs.
|
|
21
21
|
*/
|
|
22
|
-
export type BuiltInToolId = 'env' | 'network' | 'storage' | 'query' | 'query-wifi-toggle' | 'route-events' | 'debug-borders' | 'highlight-updates' | 'highlight-updates-modal' | 'redux' | 'zustand' | 'jotai' | 'events' | 'time-machine' | 'scenarios' | '
|
|
22
|
+
export type BuiltInToolId = 'env' | 'network' | 'storage' | 'query' | 'query-wifi-toggle' | 'route-events' | 'debug-borders' | 'highlight-updates' | 'highlight-updates-modal' | 'redux' | 'zustand' | 'jotai' | 'events' | 'time-machine' | 'scenarios' | 'ask-buoy' | 'image-overlay' | 'perf-monitor' | 'perf-monitor-modal';
|
|
23
23
|
/**
|
|
24
24
|
* Special floating-only tool IDs that only appear in the floating bubble row.
|
|
25
25
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"defaultConfig.d.ts","sourceRoot":"","sources":["../../../../src/floatingMenu/defaultConfig.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH;;;GAGG;AACH,MAAM,MAAM,aAAa,GACrB,KAAK,GACL,SAAS,GACT,SAAS,GACT,OAAO,GACP,mBAAmB,GACnB,cAAc,GACd,eAAe,GACf,mBAAmB,GACnB,yBAAyB,GACzB,OAAO,GACP,SAAS,GACT,OAAO,GACP,QAAQ,GACR,cAAc,GACd,WAAW,GACX,
|
|
1
|
+
{"version":3,"file":"defaultConfig.d.ts","sourceRoot":"","sources":["../../../../src/floatingMenu/defaultConfig.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH;;;GAGG;AACH,MAAM,MAAM,aAAa,GACrB,KAAK,GACL,SAAS,GACT,SAAS,GACT,OAAO,GACP,mBAAmB,GACnB,cAAc,GACd,eAAe,GACf,mBAAmB,GACnB,yBAAyB,GACzB,OAAO,GACP,SAAS,GACT,OAAO,GACP,QAAQ,GACR,cAAc,GACd,WAAW,GACX,UAAU,GACV,eAAe,GACf,cAAc,GACd,oBAAoB,CAAC;AAEzB;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG,aAAa,CAAC;AAE/C;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG,aAAa,GAAG,kBAAkB,CAAC;AAEhE;;;GAGG;AACH,MAAM,MAAM,UAAU,GAAG,aAAa,CAAC;AAEvC;;GAEG;AACH,eAAO,MAAM,cAAc,IAAI,CAAC;AAEhC;;;;;;;;GAQG;AACH,MAAM,MAAM,qBAAqB,GAAG,cAAc,EAAE,CAAC;AAErD;;;;;;;;GAQG;AACH,MAAM,MAAM,iBAAiB,GAAG,UAAU,EAAE,CAAC;AAE7C;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,iBAAiB,GAAG,iBAAiB,CAW9E;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,mBAAmB,CACjC,CAAC,SAAS,cAAc,EAAE,EAC1B,CAAC,SAAS,UAAU,EAAE,EACtB,MAAM,EAAE;IACR,QAAQ,CAAC,EAAE,CAAC,CAAC;IACb,IAAI,CAAC,EAAE,CAAC,CAAC;CACV,GAAG;IACF,QAAQ,EAAE,CAAC,GAAG,SAAS,CAAC;IACxB,IAAI,EAAE,CAAC,GAAG,SAAS,CAAC;CACrB,CAUA;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,EAAE,IAAI,cAAc,CAcjE;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,EAAE,IAAI,UAAU,CAazD;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,MAAM,EAC9C,GAAG,EAAE,CAAC,EAAE,EACR,cAAc,EAAE,CAAC,EAAE,GAClB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CASzB"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
export interface DeviceIdentity {
|
|
2
|
+
deviceName: string;
|
|
3
|
+
deviceId: string;
|
|
4
|
+
}
|
|
5
|
+
/** Minimal getItem/setItem surface, so storage can be injected in tests. */
|
|
6
|
+
export interface IdentityStore {
|
|
7
|
+
getItem(key: string): Promise<string | null> | string | null;
|
|
8
|
+
setItem(key: string, value: string): Promise<void> | void;
|
|
9
|
+
}
|
|
10
|
+
export declare const INSTALL_ID_LENGTH = 8;
|
|
11
|
+
/** 8 lowercase hex chars — short enough to read, random enough for a LAN. */
|
|
12
|
+
export declare function generateInstallId(): string;
|
|
13
|
+
export interface BuildIdentityInput {
|
|
14
|
+
/** Expo config name; null for bare RN. */
|
|
15
|
+
appName: string | null;
|
|
16
|
+
/** expo-constants `deviceName`; null when unavailable. */
|
|
17
|
+
hardwareName?: string | null;
|
|
18
|
+
platform: string;
|
|
19
|
+
/** The persisted per-install tail. */
|
|
20
|
+
installId: string;
|
|
21
|
+
/** An explicit `externalSync.deviceId` — used verbatim, no tail in the name. */
|
|
22
|
+
deviceId?: string;
|
|
23
|
+
}
|
|
24
|
+
/** Pure: turns the inputs into the id/name pair the broker sees. */
|
|
25
|
+
export declare function buildDeviceIdentity({ appName, hardwareName, platform, installId, deviceId, }: BuildIdentityInput): DeviceIdentity;
|
|
26
|
+
export interface LoadInstallIdOptions {
|
|
27
|
+
platform?: string;
|
|
28
|
+
/** Storage override (tests). Defaults to sessionStorage on web, persistentStorage elsewhere. */
|
|
29
|
+
store?: IdentityStore | null;
|
|
30
|
+
mint?: () => string;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* The persisted per-install tail: read it, or mint and store it on the first
|
|
34
|
+
* dial. Storage failures degrade to a fresh in-memory id rather than blocking
|
|
35
|
+
* the socket — a per-launch id still beats the old colliding one.
|
|
36
|
+
*/
|
|
37
|
+
export declare function loadInstallId({ platform, store, mint, }?: LoadInstallIdOptions): Promise<string>;
|
|
38
|
+
/**
|
|
39
|
+
* Process-wide memo so every mount (and every Fast Refresh of the component
|
|
40
|
+
* that calls it) shares one storage round-trip and one id.
|
|
41
|
+
*/
|
|
42
|
+
export declare function getInstallId(): Promise<string>;
|
|
43
|
+
/** Tests only. */
|
|
44
|
+
export declare function resetInstallIdForTests(): void;
|
|
45
|
+
export interface DeviceIdentityOptions {
|
|
46
|
+
deviceId?: string;
|
|
47
|
+
deviceName?: string;
|
|
48
|
+
}
|
|
49
|
+
export interface DeviceIdentityEnvironment {
|
|
50
|
+
/** Expo config name; null for bare RN. */
|
|
51
|
+
appName: string | null;
|
|
52
|
+
/** expo-constants `deviceName`; null when unavailable. */
|
|
53
|
+
hardwareName: string | null;
|
|
54
|
+
platform?: string;
|
|
55
|
+
/** The install-id loader (tests inject one; production uses the memo). */
|
|
56
|
+
loadId?: () => Promise<string>;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* The identity to dial with. Null until the per-install id is read from
|
|
60
|
+
* storage (one round-trip on first mount; memoized process-wide after) —
|
|
61
|
+
* both sync hooks no-op on a null id, so the socket simply dials a beat
|
|
62
|
+
* later. An explicit `deviceId` skips the read entirely; an explicit
|
|
63
|
+
* `deviceName` is used verbatim.
|
|
64
|
+
*/
|
|
65
|
+
export declare function useDeviceIdentity(options: DeviceIdentityOptions | undefined, env: DeviceIdentityEnvironment): DeviceIdentity | null;
|
|
66
|
+
//# sourceMappingURL=deviceIdentity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deviceIdentity.d.ts","sourceRoot":"","sources":["../../../../src/floatingMenu/deviceIdentity.ts"],"names":[],"mappings":"AAmCA,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,4EAA4E;AAC5E,MAAM,WAAW,aAAa;IAC5B,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,MAAM,GAAG,IAAI,CAAC;IAC7D,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CAC3D;AAED,eAAO,MAAM,iBAAiB,IAAI,CAAC;AAEnC,6EAA6E;AAC7E,wBAAgB,iBAAiB,IAAI,MAAM,CAM1C;AASD,MAAM,WAAW,kBAAkB;IACjC,0CAA0C;IAC1C,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,0DAA0D;IAC1D,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,sCAAsC;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,gFAAgF;IAChF,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,oEAAoE;AACpE,wBAAgB,mBAAmB,CAAC,EAClC,OAAO,EACP,YAAY,EACZ,QAAQ,EACR,SAAS,EACT,QAAQ,GACT,EAAE,kBAAkB,GAAG,cAAc,CAcrC;AAYD,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gGAAgG;IAChG,KAAK,CAAC,EAAE,aAAa,GAAG,IAAI,CAAC;IAC7B,IAAI,CAAC,EAAE,MAAM,MAAM,CAAC;CACrB;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,EAClC,QAAsB,EACtB,KAAK,EACL,IAAwB,GACzB,GAAE,oBAAyB,GAAG,OAAO,CAAC,MAAM,CAAC,CAkB7C;AAID;;;GAGG;AACH,wBAAgB,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,CAG9C;AAED,kBAAkB;AAClB,wBAAgB,sBAAsB,IAAI,IAAI,CAE7C;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,yBAAyB;IACxC,0CAA0C;IAC1C,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,0DAA0D;IAC1D,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,0EAA0E;IAC1E,MAAM,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;CAChC;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,qBAAqB,GAAG,SAAS,EAC1C,GAAG,EAAE,yBAAyB,GAC7B,cAAc,GAAG,IAAI,CA4BvB"}
|