@buoy-gg/external-sync 6.0.1 → 7.0.0

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.
@@ -3,12 +3,48 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
+ Object.defineProperty(exports, "DEFAULT_BROKER_PORT", {
7
+ enumerable: true,
8
+ get: function () {
9
+ return _getDefaultSocketURL.DEFAULT_BROKER_PORT;
10
+ }
11
+ });
6
12
  Object.defineProperty(exports, "SYNC_PROTOCOL_VERSION", {
7
13
  enumerable: true,
8
14
  get: function () {
9
15
  return _types.SYNC_PROTOCOL_VERSION;
10
16
  }
11
17
  });
18
+ Object.defineProperty(exports, "getDefaultSocketURL", {
19
+ enumerable: true,
20
+ get: function () {
21
+ return _getDefaultSocketURL.getDefaultSocketURL;
22
+ }
23
+ });
24
+ Object.defineProperty(exports, "getMetroHost", {
25
+ enumerable: true,
26
+ get: function () {
27
+ return _getDefaultSocketURL.getMetroHost;
28
+ }
29
+ });
30
+ Object.defineProperty(exports, "getSyncStatus", {
31
+ enumerable: true,
32
+ get: function () {
33
+ return _syncStatusStore.getSyncStatus;
34
+ }
35
+ });
36
+ Object.defineProperty(exports, "setSyncStatus", {
37
+ enumerable: true,
38
+ get: function () {
39
+ return _syncStatusStore.setSyncStatus;
40
+ }
41
+ });
42
+ Object.defineProperty(exports, "subscribeSyncStatus", {
43
+ enumerable: true,
44
+ get: function () {
45
+ return _syncStatusStore.subscribeSyncStatus;
46
+ }
47
+ });
12
48
  Object.defineProperty(exports, "useExternalSync", {
13
49
  enumerable: true,
14
50
  get: function () {
@@ -23,4 +59,6 @@ Object.defineProperty(exports, "useExternalSyncSocket", {
23
59
  });
24
60
  var _useExternalSync = require("./useExternalSync");
25
61
  var _useExternalSyncSocket = require("./useExternalSyncSocket");
62
+ var _getDefaultSocketURL = require("./utils/getDefaultSocketURL");
63
+ var _syncStatusStore = require("./syncStatusStore");
26
64
  var _types = require("./types");
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.getSyncStatus = getSyncStatus;
7
+ exports.setSyncStatus = setSyncStatus;
8
+ exports.subscribeSyncStatus = subscribeSyncStatus;
9
+ /**
10
+ * Module-level desktop-sync status, written by useExternalSyncSocket and
11
+ * read by the floating menu's settings modal (via useSyncExternalStore).
12
+ * Lives here rather than in core because only the socket hook knows the
13
+ * platform-rewritten URL and every connection transition — including for
14
+ * apps that call the hook directly instead of using zero-config sync.
15
+ */
16
+
17
+ let status = {
18
+ targetURL: null,
19
+ state: "idle",
20
+ lastError: null,
21
+ since: 0
22
+ };
23
+ const listeners = new Set();
24
+ function setSyncStatus(patch) {
25
+ status = {
26
+ ...status,
27
+ ...patch,
28
+ since: Date.now()
29
+ };
30
+ listeners.forEach(listener => listener());
31
+ }
32
+ function getSyncStatus() {
33
+ return status;
34
+ }
35
+ function subscribeSyncStatus(listener) {
36
+ listeners.add(listener);
37
+ return () => {
38
+ listeners.delete(listener);
39
+ };
40
+ }
@@ -7,7 +7,9 @@ exports.useExternalSyncSocket = useExternalSyncSocket;
7
7
  var _react = require("react");
8
8
  var _socket = require("socket.io-client");
9
9
  var _platformUtils = require("./utils/platformUtils");
10
+ var _getDefaultSocketURL = require("./utils/getDefaultSocketURL");
10
11
  var _logger = require("./utils/logger");
12
+ var _syncStatusStore = require("./syncStatusStore");
11
13
  // True only in development. Guarded so it doesn't throw in environments
12
14
  // (web/electron bundles) where __DEV__ may be undefined.
13
15
  const isDev = typeof __DEV__ !== "undefined" ? __DEV__ : false;
@@ -50,6 +52,8 @@ function useExternalSyncSocket({
50
52
  const [socket, setSocket] = (0, _react.useState)(null);
51
53
  const [isConnected, setIsConnected] = (0, _react.useState)(false);
52
54
  const initialized = (0, _react.useRef)(false);
55
+ // Derived once per render; stable string, so effect deps stay quiet.
56
+ const resolvedSocketURL = socketURL ?? (0, _getDefaultSocketURL.getDefaultSocketURL)();
53
57
  // Tracks whether we've already logged a connection error for the current
54
58
  // outage, so the reconnection backoff doesn't spam an error on every retry.
55
59
  const hasLoggedConnectError = (0, _react.useRef)(false);
@@ -58,19 +62,30 @@ function useExternalSyncSocket({
58
62
  (0, _logger.log)(`${logPrefix} Socket connected successfully`, enableLogs);
59
63
  hasLoggedConnectError.current = false;
60
64
  setIsConnected(true);
65
+ (0, _syncStatusStore.setSyncStatus)({
66
+ state: "connected",
67
+ lastError: null
68
+ });
61
69
  };
62
70
  const onDisconnect = reason => {
63
71
  (0, _logger.log)(`${logPrefix} Socket disconnected. Reason: ${reason}`, enableLogs);
64
72
  setIsConnected(false);
73
+ (0, _syncStatusStore.setSyncStatus)({
74
+ state: "retrying"
75
+ });
65
76
  };
66
77
  const onConnectError = error => {
78
+ (0, _syncStatusStore.setSyncStatus)({
79
+ state: "retrying",
80
+ lastError: error.message
81
+ });
67
82
  // Never surface this in production builds.
68
83
  if (!isDev) return;
69
84
  // Reconnection retries indefinitely; only log the first failure of an
70
85
  // outage to avoid flooding the console until the server comes back up.
71
86
  if (hasLoggedConnectError.current) return;
72
87
  hasLoggedConnectError.current = true;
73
- (0, _logger.log)(`${logPrefix} Socket connection error: ${error.message}. Retrying in the background until the dashboard is available.`, enableLogs, "warn");
88
+ (0, _logger.log)(`[buoy] desktop sync: can't reach ${currentSocketURL} (is Buoy Desktop running?). ` + `Retrying in the background. If it's running on another machine or port, ` + `pass socketURL via the externalSync prop. (${error.message})`, enableLogs, "warn");
74
89
  };
75
90
  const onConnectTimeout = () => {
76
91
  (0, _logger.log)(`${logPrefix} Socket connection timeout`, enableLogs, "error");
@@ -81,8 +96,13 @@ function useExternalSyncSocket({
81
96
  if (!persistentDeviceId) return;
82
97
  if (initialized.current) return;
83
98
  initialized.current = true;
84
- const platformUrl = (0, _platformUtils.getPlatformSpecificURL)(socketURL, platform);
99
+ const platformUrl = (0, _platformUtils.getPlatformSpecificURL)(resolvedSocketURL, platform);
85
100
  currentSocketURL = platformUrl;
101
+ (0, _syncStatusStore.setSyncStatus)({
102
+ targetURL: platformUrl,
103
+ state: "connecting",
104
+ lastError: null
105
+ });
86
106
  (0, _logger.log)(`${logPrefix} Platform: ${platform}, using URL: ${platformUrl}`, enableLogs);
87
107
  try {
88
108
  if (!globalSocketInstance) {
@@ -145,12 +165,17 @@ function useExternalSyncSocket({
145
165
 
146
166
  // Update socket URL when socketURL changes
147
167
  (0, _react.useEffect)(() => {
148
- const platformUrl = (0, _platformUtils.getPlatformSpecificURL)(socketURL, platform);
168
+ const platformUrl = (0, _platformUtils.getPlatformSpecificURL)(resolvedSocketURL, platform);
149
169
  if (socketRef.current && currentSocketURL !== platformUrl && persistentDeviceId) {
150
170
  (0, _logger.log)(`${logPrefix} Socket URL changed from ${currentSocketURL} to ${platformUrl}`, enableLogs);
151
171
  try {
152
172
  socketRef.current.disconnect();
153
173
  currentSocketURL = platformUrl;
174
+ (0, _syncStatusStore.setSyncStatus)({
175
+ targetURL: platformUrl,
176
+ state: "connecting",
177
+ lastError: null
178
+ });
154
179
  (0, _logger.log)(`${logPrefix} Creating new socket connection to ${platformUrl}`, enableLogs);
155
180
  globalSocketInstance = (0, _socket.io)(platformUrl, {
156
181
  autoConnect: true,
@@ -174,7 +199,7 @@ function useExternalSyncSocket({
174
199
  (0, _logger.log)(`${logPrefix} Failed to update socket connection: ${error}`, enableLogs, "error");
175
200
  }
176
201
  }
177
- }, [socketURL, deviceName, logPrefix, persistentDeviceId, platform, enableLogs]);
202
+ }, [resolvedSocketURL, deviceName, logPrefix, persistentDeviceId, platform, enableLogs]);
178
203
  function connect() {
179
204
  if (socketRef.current && !socketRef.current.connected) {
180
205
  (0, _logger.log)(`${logPrefix} Manually connecting to socket server`, enableLogs);
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.DEFAULT_BROKER_PORT = void 0;
7
+ exports.getDefaultSocketURL = getDefaultSocketURL;
8
+ exports.getMetroHost = getMetroHost;
9
+ /**
10
+ * Default broker-URL derivation. Kept in its own module (and never imported
11
+ * from types.ts) because the deep react-native require below must not reach
12
+ * non-Metro bundles — the desktop app imports this package's types only.
13
+ */
14
+
15
+ /** Port Buoy Desktop's broker listens on. */
16
+ const DEFAULT_BROKER_PORT = exports.DEFAULT_BROKER_PORT = 42831;
17
+ const HOST_RE = /^https?:\/\/([^:/]+)/;
18
+
19
+ /**
20
+ * Host of the Metro dev server that served this bundle — the machine most
21
+ * likely running Buoy Desktop. On a physical device this is the computer's
22
+ * LAN IP, where "localhost" would be the phone itself.
23
+ *
24
+ * scriptURL is the only source that works everywhere we've tested:
25
+ * NativeModules.SourceCode.scriptURL is undefined on bridgeless, and
26
+ * expo-constants hostUri/experienceUrl/linkingUri are all undefined in
27
+ * Expo dev-client builds. Returns null on web or if RN internals move.
28
+ */
29
+ function getMetroHost() {
30
+ try {
31
+ // Requires stay lexically inside try{} so Metro treats them as optional;
32
+ // react-native-web has neither path and falls through to null.
33
+ const NativeSourceCode =
34
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
35
+ require("react-native/Libraries/NativeModules/specs/NativeSourceCode").default;
36
+ const scriptURL = NativeSourceCode?.getConstants?.().scriptURL;
37
+ const match = scriptURL?.match(HOST_RE);
38
+ if (match) return match[1];
39
+ } catch {
40
+ // web / RN internals moved — try the old-architecture module
41
+ }
42
+ try {
43
+ const {
44
+ NativeModules
45
+ } = require("react-native");
46
+ const scriptURL = NativeModules?.SourceCode?.getConstants?.().scriptURL ?? NativeModules?.SourceCode?.scriptURL;
47
+ const match = scriptURL?.match(HOST_RE);
48
+ if (match) return match[1];
49
+ } catch {
50
+ // not React Native
51
+ }
52
+ return null;
53
+ }
54
+
55
+ /**
56
+ * Default Buoy Desktop broker URL: the Metro host (falling back to
57
+ * localhost) on port 42831. Android-emulator 10.0.2.2 rewriting is applied
58
+ * later by getPlatformSpecificURL, so localhost still works there.
59
+ */
60
+ function getDefaultSocketURL() {
61
+ return `http://${getMetroHost() ?? "localhost"}:${DEFAULT_BROKER_PORT}`;
62
+ }
@@ -6,6 +6,15 @@
6
6
  export { useExternalSync } from "./useExternalSync";
7
7
  export { useExternalSyncSocket } from "./useExternalSyncSocket";
8
8
 
9
+ // ============================================================
10
+ // BROKER URL DERIVATION
11
+ // ============================================================
12
+ export { getDefaultSocketURL, getMetroHost, DEFAULT_BROKER_PORT } from "./utils/getDefaultSocketURL";
13
+
14
+ // ============================================================
15
+ // SYNC STATUS (read by the floating menu's settings modal)
16
+ // ============================================================
17
+ export { getSyncStatus, setSyncStatus, subscribeSyncStatus } from "./syncStatusStore";
9
18
  // ============================================================
10
19
  // PROTOCOL
11
20
  // ============================================================
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * Module-level desktop-sync status, written by useExternalSyncSocket and
5
+ * read by the floating menu's settings modal (via useSyncExternalStore).
6
+ * Lives here rather than in core because only the socket hook knows the
7
+ * platform-rewritten URL and every connection transition — including for
8
+ * apps that call the hook directly instead of using zero-config sync.
9
+ */
10
+
11
+ let status = {
12
+ targetURL: null,
13
+ state: "idle",
14
+ lastError: null,
15
+ since: 0
16
+ };
17
+ const listeners = new Set();
18
+ export function setSyncStatus(patch) {
19
+ status = {
20
+ ...status,
21
+ ...patch,
22
+ since: Date.now()
23
+ };
24
+ listeners.forEach(listener => listener());
25
+ }
26
+ export function getSyncStatus() {
27
+ return status;
28
+ }
29
+ export function subscribeSyncStatus(listener) {
30
+ listeners.add(listener);
31
+ return () => {
32
+ listeners.delete(listener);
33
+ };
34
+ }
@@ -3,7 +3,9 @@
3
3
  import { useEffect, useRef, useState } from "react";
4
4
  import { io as socketIO } from "socket.io-client";
5
5
  import { getPlatformSpecificURL } from "./utils/platformUtils";
6
+ import { getDefaultSocketURL } from "./utils/getDefaultSocketURL";
6
7
  import { log } from "./utils/logger";
8
+ import { setSyncStatus } from "./syncStatusStore";
7
9
  // True only in development. Guarded so it doesn't throw in environments
8
10
  // (web/electron bundles) where __DEV__ may be undefined.
9
11
  const isDev = typeof __DEV__ !== "undefined" ? __DEV__ : false;
@@ -46,6 +48,8 @@ export function useExternalSyncSocket({
46
48
  const [socket, setSocket] = useState(null);
47
49
  const [isConnected, setIsConnected] = useState(false);
48
50
  const initialized = useRef(false);
51
+ // Derived once per render; stable string, so effect deps stay quiet.
52
+ const resolvedSocketURL = socketURL ?? getDefaultSocketURL();
49
53
  // Tracks whether we've already logged a connection error for the current
50
54
  // outage, so the reconnection backoff doesn't spam an error on every retry.
51
55
  const hasLoggedConnectError = useRef(false);
@@ -54,19 +58,30 @@ export function useExternalSyncSocket({
54
58
  log(`${logPrefix} Socket connected successfully`, enableLogs);
55
59
  hasLoggedConnectError.current = false;
56
60
  setIsConnected(true);
61
+ setSyncStatus({
62
+ state: "connected",
63
+ lastError: null
64
+ });
57
65
  };
58
66
  const onDisconnect = reason => {
59
67
  log(`${logPrefix} Socket disconnected. Reason: ${reason}`, enableLogs);
60
68
  setIsConnected(false);
69
+ setSyncStatus({
70
+ state: "retrying"
71
+ });
61
72
  };
62
73
  const onConnectError = error => {
74
+ setSyncStatus({
75
+ state: "retrying",
76
+ lastError: error.message
77
+ });
63
78
  // Never surface this in production builds.
64
79
  if (!isDev) return;
65
80
  // Reconnection retries indefinitely; only log the first failure of an
66
81
  // outage to avoid flooding the console until the server comes back up.
67
82
  if (hasLoggedConnectError.current) return;
68
83
  hasLoggedConnectError.current = true;
69
- log(`${logPrefix} Socket connection error: ${error.message}. Retrying in the background until the dashboard is available.`, enableLogs, "warn");
84
+ log(`[buoy] desktop sync: can't reach ${currentSocketURL} (is Buoy Desktop running?). ` + `Retrying in the background. If it's running on another machine or port, ` + `pass socketURL via the externalSync prop. (${error.message})`, enableLogs, "warn");
70
85
  };
71
86
  const onConnectTimeout = () => {
72
87
  log(`${logPrefix} Socket connection timeout`, enableLogs, "error");
@@ -77,8 +92,13 @@ export function useExternalSyncSocket({
77
92
  if (!persistentDeviceId) return;
78
93
  if (initialized.current) return;
79
94
  initialized.current = true;
80
- const platformUrl = getPlatformSpecificURL(socketURL, platform);
95
+ const platformUrl = getPlatformSpecificURL(resolvedSocketURL, platform);
81
96
  currentSocketURL = platformUrl;
97
+ setSyncStatus({
98
+ targetURL: platformUrl,
99
+ state: "connecting",
100
+ lastError: null
101
+ });
82
102
  log(`${logPrefix} Platform: ${platform}, using URL: ${platformUrl}`, enableLogs);
83
103
  try {
84
104
  if (!globalSocketInstance) {
@@ -141,12 +161,17 @@ export function useExternalSyncSocket({
141
161
 
142
162
  // Update socket URL when socketURL changes
143
163
  useEffect(() => {
144
- const platformUrl = getPlatformSpecificURL(socketURL, platform);
164
+ const platformUrl = getPlatformSpecificURL(resolvedSocketURL, platform);
145
165
  if (socketRef.current && currentSocketURL !== platformUrl && persistentDeviceId) {
146
166
  log(`${logPrefix} Socket URL changed from ${currentSocketURL} to ${platformUrl}`, enableLogs);
147
167
  try {
148
168
  socketRef.current.disconnect();
149
169
  currentSocketURL = platformUrl;
170
+ setSyncStatus({
171
+ targetURL: platformUrl,
172
+ state: "connecting",
173
+ lastError: null
174
+ });
150
175
  log(`${logPrefix} Creating new socket connection to ${platformUrl}`, enableLogs);
151
176
  globalSocketInstance = socketIO(platformUrl, {
152
177
  autoConnect: true,
@@ -170,7 +195,7 @@ export function useExternalSyncSocket({
170
195
  log(`${logPrefix} Failed to update socket connection: ${error}`, enableLogs, "error");
171
196
  }
172
197
  }
173
- }, [socketURL, deviceName, logPrefix, persistentDeviceId, platform, enableLogs]);
198
+ }, [resolvedSocketURL, deviceName, logPrefix, persistentDeviceId, platform, enableLogs]);
174
199
  function connect() {
175
200
  if (socketRef.current && !socketRef.current.connected) {
176
201
  log(`${logPrefix} Manually connecting to socket server`, enableLogs);
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * Default broker-URL derivation. Kept in its own module (and never imported
5
+ * from types.ts) because the deep react-native require below must not reach
6
+ * non-Metro bundles — the desktop app imports this package's types only.
7
+ */
8
+
9
+ /** Port Buoy Desktop's broker listens on. */
10
+ export const DEFAULT_BROKER_PORT = 42831;
11
+ const HOST_RE = /^https?:\/\/([^:/]+)/;
12
+
13
+ /**
14
+ * Host of the Metro dev server that served this bundle — the machine most
15
+ * likely running Buoy Desktop. On a physical device this is the computer's
16
+ * LAN IP, where "localhost" would be the phone itself.
17
+ *
18
+ * scriptURL is the only source that works everywhere we've tested:
19
+ * NativeModules.SourceCode.scriptURL is undefined on bridgeless, and
20
+ * expo-constants hostUri/experienceUrl/linkingUri are all undefined in
21
+ * Expo dev-client builds. Returns null on web or if RN internals move.
22
+ */
23
+ export function getMetroHost() {
24
+ try {
25
+ // Requires stay lexically inside try{} so Metro treats them as optional;
26
+ // react-native-web has neither path and falls through to null.
27
+ const NativeSourceCode =
28
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
29
+ require("react-native/Libraries/NativeModules/specs/NativeSourceCode").default;
30
+ const scriptURL = NativeSourceCode?.getConstants?.().scriptURL;
31
+ const match = scriptURL?.match(HOST_RE);
32
+ if (match) return match[1];
33
+ } catch {
34
+ // web / RN internals moved — try the old-architecture module
35
+ }
36
+ try {
37
+ const {
38
+ NativeModules
39
+ } = require("react-native");
40
+ const scriptURL = NativeModules?.SourceCode?.getConstants?.().scriptURL ?? NativeModules?.SourceCode?.scriptURL;
41
+ const match = scriptURL?.match(HOST_RE);
42
+ if (match) return match[1];
43
+ } catch {
44
+ // not React Native
45
+ }
46
+ return null;
47
+ }
48
+
49
+ /**
50
+ * Default Buoy Desktop broker URL: the Metro host (falling back to
51
+ * localhost) on port 42831. Android-emulator 10.0.2.2 rewriting is applied
52
+ * later by getPlatformSpecificURL, so localhost still works there.
53
+ */
54
+ export function getDefaultSocketURL() {
55
+ return `http://${getMetroHost() ?? "localhost"}:${DEFAULT_BROKER_PORT}`;
56
+ }
@@ -1,5 +1,8 @@
1
1
  export { useExternalSync } from "./useExternalSync";
2
2
  export { useExternalSyncSocket } from "./useExternalSyncSocket";
3
+ export { getDefaultSocketURL, getMetroHost, DEFAULT_BROKER_PORT, } from "./utils/getDefaultSocketURL";
4
+ export { getSyncStatus, setSyncStatus, subscribeSyncStatus, } from "./syncStatusStore";
5
+ export type { SyncStatus } from "./syncStatusStore";
3
6
  export { SYNC_PROTOCOL_VERSION } from "./types";
4
7
  export type { ToolSyncAdapter, ToolAction, ToolCapability, SyncKind, UseExternalSyncProps, UseExternalSyncSocketProps, DeviceCapabilitiesMessage, DevToolSyncMessage, DevToolActionMessage, DevToolActionResultMessage, DevToolWatchMessage, DevToolRequestMessage, PlatformOS, } from "./types";
5
8
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAKhE,OAAO,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAC;AAKhD,YAAY,EACV,eAAe,EACf,UAAU,EACV,cAAc,EACd,QAAQ,EACR,oBAAoB,EACpB,0BAA0B,EAC1B,yBAAyB,EACzB,kBAAkB,EAClB,oBAAoB,EACpB,0BAA0B,EAC1B,mBAAmB,EACnB,qBAAqB,EACrB,UAAU,GACX,MAAM,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAKhE,OAAO,EACL,mBAAmB,EACnB,YAAY,EACZ,mBAAmB,GACpB,MAAM,6BAA6B,CAAC;AAKrC,OAAO,EACL,aAAa,EACb,aAAa,EACb,mBAAmB,GACpB,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAKpD,OAAO,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAC;AAKhD,YAAY,EACV,eAAe,EACf,UAAU,EACV,cAAc,EACd,QAAQ,EACR,oBAAoB,EACpB,0BAA0B,EAC1B,yBAAyB,EACzB,kBAAkB,EAClB,oBAAoB,EACpB,0BAA0B,EAC1B,mBAAmB,EACnB,qBAAqB,EACrB,UAAU,GACX,MAAM,SAAS,CAAC"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Module-level desktop-sync status, written by useExternalSyncSocket and
3
+ * read by the floating menu's settings modal (via useSyncExternalStore).
4
+ * Lives here rather than in core because only the socket hook knows the
5
+ * platform-rewritten URL and every connection transition — including for
6
+ * apps that call the hook directly instead of using zero-config sync.
7
+ */
8
+ export interface SyncStatus {
9
+ /** Final (platform-rewritten) broker URL being dialed; null before init. */
10
+ targetURL: string | null;
11
+ state: "idle" | "connecting" | "connected" | "retrying";
12
+ /** Message of the most recent connect error; cleared on connect. */
13
+ lastError: string | null;
14
+ /** Epoch ms of the last state change. */
15
+ since: number;
16
+ }
17
+ export declare function setSyncStatus(patch: Partial<SyncStatus>): void;
18
+ export declare function getSyncStatus(): SyncStatus;
19
+ export declare function subscribeSyncStatus(listener: () => void): () => void;
20
+ //# sourceMappingURL=syncStatusStore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"syncStatusStore.d.ts","sourceRoot":"","sources":["../../src/syncStatusStore.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,WAAW,UAAU;IACzB,4EAA4E;IAC5E,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,KAAK,EAAE,MAAM,GAAG,YAAY,GAAG,WAAW,GAAG,UAAU,CAAC;IACxD,oEAAoE;IACpE,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,yCAAyC;IACzC,KAAK,EAAE,MAAM,CAAC;CACf;AAWD,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,CAAC,UAAU,CAAC,GAAG,IAAI,CAG9D;AAED,wBAAgB,aAAa,IAAI,UAAU,CAE1C;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAKpE"}
@@ -103,7 +103,13 @@ export interface UseExternalSyncProps {
103
103
  export type PlatformOS = "ios" | "android" | "web" | "windows" | "macos" | "native" | "tv" | "tvos" | "visionos" | "maccatalyst";
104
104
  export interface UseExternalSyncSocketProps {
105
105
  deviceName: string;
106
- socketURL: string;
106
+ /**
107
+ * Broker URL to dial. @default derived from Metro's scriptURL host
108
+ * (the machine that served the bundle — Buoy Desktop's machine) on port
109
+ * 42831, so physical devices work zero-config. Pass explicitly for
110
+ * tunnels, adb-reverse USB setups, or a broker on another machine.
111
+ */
112
+ socketURL?: string;
107
113
  persistentDeviceId: string | null;
108
114
  extraDeviceInfo?: Record<string, string>;
109
115
  envVariables?: Record<string, string>;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"useExternalSyncSocket.d.ts","sourceRoot":"","sources":["../../src/useExternalSyncSocket.ts"],"names":[],"mappings":"AACA,OAAO,EAAkB,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAI1D,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,SAAS,CAAC;AA0B1D;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,EACpC,UAAU,EACV,SAAS,EACT,kBAAkB,EAClB,eAAe,EACf,YAAY,EACZ,QAAQ,EACR,UAAkB,GACnB,EAAE,0BAA0B;;;;;EAsN5B"}
1
+ {"version":3,"file":"useExternalSyncSocket.d.ts","sourceRoot":"","sources":["../../src/useExternalSyncSocket.ts"],"names":[],"mappings":"AACA,OAAO,EAAkB,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAM1D,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,SAAS,CAAC;AA0B1D;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,EACpC,UAAU,EACV,SAAS,EACT,kBAAkB,EAClB,eAAe,EACf,YAAY,EACZ,QAAQ,EACR,UAAkB,GACnB,EAAE,0BAA0B;;;;;EAuO5B"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Default broker-URL derivation. Kept in its own module (and never imported
3
+ * from types.ts) because the deep react-native require below must not reach
4
+ * non-Metro bundles — the desktop app imports this package's types only.
5
+ */
6
+ /** Port Buoy Desktop's broker listens on. */
7
+ export declare const DEFAULT_BROKER_PORT = 42831;
8
+ /**
9
+ * Host of the Metro dev server that served this bundle — the machine most
10
+ * likely running Buoy Desktop. On a physical device this is the computer's
11
+ * LAN IP, where "localhost" would be the phone itself.
12
+ *
13
+ * scriptURL is the only source that works everywhere we've tested:
14
+ * NativeModules.SourceCode.scriptURL is undefined on bridgeless, and
15
+ * expo-constants hostUri/experienceUrl/linkingUri are all undefined in
16
+ * Expo dev-client builds. Returns null on web or if RN internals move.
17
+ */
18
+ export declare function getMetroHost(): string | null;
19
+ /**
20
+ * Default Buoy Desktop broker URL: the Metro host (falling back to
21
+ * localhost) on port 42831. Android-emulator 10.0.2.2 rewriting is applied
22
+ * later by getPlatformSpecificURL, so localhost still works there.
23
+ */
24
+ export declare function getDefaultSocketURL(): string;
25
+ //# sourceMappingURL=getDefaultSocketURL.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getDefaultSocketURL.d.ts","sourceRoot":"","sources":["../../../src/utils/getDefaultSocketURL.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,6CAA6C;AAC7C,eAAO,MAAM,mBAAmB,QAAQ,CAAC;AAIzC;;;;;;;;;GASG;AACH,wBAAgB,YAAY,IAAI,MAAM,GAAG,IAAI,CAyB5C;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,CAE5C"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@buoy-gg/external-sync",
3
- "version": "6.0.1",
3
+ "version": "7.0.0",
4
4
  "description": "Generic device-to-desktop sync for Buoy dev tools",
5
5
  "main": "lib/commonjs/index.js",
6
6
  "module": "lib/module/index.js",
@@ -25,16 +25,16 @@
25
25
  "lib"
26
26
  ],
27
27
  "sideEffects": false,
28
- "dependencies": {},
28
+ "dependencies": {
29
+ "socket.io-client": "^4.8.1"
30
+ },
29
31
  "peerDependencies": {
30
32
  "react": "*",
31
- "react-native": "*",
32
- "socket.io-client": ">=4.0.0"
33
+ "react-native": "*"
33
34
  },
34
35
  "devDependencies": {
35
36
  "@types/react": "^19.1.0",
36
37
  "@types/react-native": "^0.73.0",
37
- "socket.io-client": "^4.8.1",
38
38
  "typescript": "~5.8.3"
39
39
  },
40
40
  "react-native-builder-bob": {
@@ -58,13 +58,12 @@
58
58
  },
59
59
  "repository": {
60
60
  "type": "git",
61
- "url": "https://github.com/LovesWorking/react-native-buoy.git",
62
- "directory": "packages/external-sync"
61
+ "url": "https://github.com/Buoy-gg/buoy.git"
63
62
  },
64
63
  "bugs": {
65
64
  "url": "https://github.com/LovesWorking/react-native-buoy/issues"
66
65
  },
67
- "homepage": "https://github.com/LovesWorking/react-native-buoy/tree/main/packages/external-sync#readme",
66
+ "homepage": "https://buoy.gg",
68
67
  "publishConfig": {
69
68
  "access": "public",
70
69
  "tag": "latest"