@buoy-gg/sync-broker 6.0.1 → 7.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/README.md CHANGED
@@ -51,5 +51,7 @@ Topology and message flow:
51
51
  - Dashboards `devtool-watch` tools; the broker **consolidates** watch counts so a device receives a single `watching` true/false per `(device, tool)` regardless of how many dashboards are watching.
52
52
  - Dashboards invoke `devtool-action`; devices reply `devtool-action-result`.
53
53
  - Devices push `devtool-sync` snapshots; the broker forwards them to dashboards.
54
+ - The broker emits `broker-log` entries to dashboards (handshakes, disconnect reasons, duplicate-name renames, protocol-version mismatches), buffering the last 200 so a dashboard that connects late still sees earlier failures.
55
+ - Dashboards emit `forget-device` to remove an **offline** device from history; offline devices also age out automatically after 24h (`User.lastSeenAt`).
54
56
 
55
57
  > **Security:** dev-only. No authentication, CORS is open (`*`), intended for loopback / trusted LAN.
package/dist/index.d.mts CHANGED
@@ -158,6 +158,8 @@ interface User {
158
158
  connectionNonce?: string;
159
159
  /** The socket.io reason for this client's most recent disconnect. */
160
160
  lastDisconnectReason?: string;
161
+ /** Epoch ms of the last connect/reconnect/disconnect; drives age-out. */
162
+ lastSeenAt?: number;
161
163
  /** Whether the device announced an active Buoy Pro license. */
162
164
  isPro?: boolean;
163
165
  /** The device's Buoy Pro license key, if any. Local dev connection only. */
package/dist/index.d.ts CHANGED
@@ -158,6 +158,8 @@ interface User {
158
158
  connectionNonce?: string;
159
159
  /** The socket.io reason for this client's most recent disconnect. */
160
160
  lastDisconnectReason?: string;
161
+ /** Epoch ms of the last connect/reconnect/disconnect; drives age-out. */
162
+ lastSeenAt?: number;
161
163
  /** Whether the device announced an active Buoy Pro license. */
162
164
  isPro?: boolean;
163
165
  /** The device's Buoy Pro license key, if any. Local dev connection only. */
package/dist/index.js CHANGED
@@ -38,6 +38,9 @@ __export(index_exports, {
38
38
  });
39
39
  module.exports = __toCommonJS(index_exports);
40
40
 
41
+ // src/protocol.ts
42
+ var SYNC_PROTOCOL_VERSION = 1;
43
+
41
44
  // src/socketHandle.ts
42
45
  var users = [];
43
46
  var allDevices = [];
@@ -49,8 +52,36 @@ var dashboardWatches = /* @__PURE__ */ new Map();
49
52
  var watchCounts = /* @__PURE__ */ new Map();
50
53
  var toWatchKey = (targetDeviceId, toolId) => JSON.stringify([targetDeviceId, toolId]);
51
54
  var fromWatchKey = (key) => JSON.parse(key);
55
+ var brokerLogBuffer = [];
56
+ var BROKER_LOG_BUFFER_MAX = 200;
57
+ var MAX_OFFLINE_AGE_MS = 24 * 60 * 60 * 1e3;
52
58
  function socketHandle({ io }) {
53
59
  const LOG_PREFIX = "[SERVER]";
60
+ function brokerLog(level, message, data) {
61
+ console.log(`${LOG_PREFIX} ${message}`);
62
+ const entry = { ts: Date.now(), level, message, data };
63
+ brokerLogBuffer.push(entry);
64
+ if (brokerLogBuffer.length > BROKER_LOG_BUFFER_MAX) {
65
+ brokerLogBuffer.shift();
66
+ }
67
+ forwardToDashboards("broker-log", entry);
68
+ }
69
+ function emitAllDevices() {
70
+ const now = Date.now();
71
+ for (let i = allDevices.length - 1; i >= 0; i--) {
72
+ const device = allDevices[i];
73
+ if (!device.isConnected && device.lastSeenAt && now - device.lastSeenAt > MAX_OFFLINE_AGE_MS) {
74
+ allDevices.splice(i, 1);
75
+ if (device.deviceId) {
76
+ deviceCapabilities.delete(device.deviceId);
77
+ }
78
+ }
79
+ }
80
+ io.emit(
81
+ "all-devices-update",
82
+ allDevices.filter((device) => device.deviceName !== "Dashboard")
83
+ );
84
+ }
54
85
  function handleClose(id, reason) {
55
86
  const user = users.find((user2) => user2.id === id);
56
87
  const deviceId = deviceIdMap.get(id);
@@ -66,6 +97,7 @@ function socketHandle({ io }) {
66
97
  if (deviceIndex !== -1) {
67
98
  allDevices[deviceIndex].isConnected = false;
68
99
  allDevices[deviceIndex].lastDisconnectReason = reason;
100
+ allDevices[deviceIndex].lastSeenAt = Date.now();
69
101
  activeConnectionsMap.delete(deviceId);
70
102
  }
71
103
  }
@@ -78,13 +110,12 @@ function socketHandle({ io }) {
78
110
  const wasDashboard = dashboardClients.includes(id);
79
111
  dashboardClients = dashboardClients.filter((clientId) => clientId !== id);
80
112
  releaseDashboardWatches(id);
81
- console.log(
82
- `${LOG_PREFIX} Client disconnected - ID: ${id}, Name: ${user?.deviceName || "Unknown"}, Was Dashboard: ${wasDashboard}, Reason: ${reason ?? "unknown"}`
83
- );
84
- io.emit(
85
- "all-devices-update",
86
- allDevices.filter((device) => device.deviceName !== "Dashboard")
113
+ brokerLog(
114
+ wasDashboard ? "debug" : "warn",
115
+ `Disconnected: ${user?.deviceName || id} (${reason ?? "unknown"})`,
116
+ { socketId: id, reason, wasDashboard }
87
117
  );
118
+ emitAllDevices();
88
119
  console.log(
89
120
  `${LOG_PREFIX} Updated users list: ${users.map((u) => u.deviceName).join(", ")}`
90
121
  );
@@ -109,8 +140,10 @@ function socketHandle({ io }) {
109
140
  (device) => device.deviceId === deviceId
110
141
  );
111
142
  if (existingUserIndex !== -1) {
112
- console.log(
113
- `${LOG_PREFIX} Reconnecting existing device - ID: ${id}, Name: ${deviceName}, DeviceId: ${deviceId}, Platform: ${platform || "Unknown"}, ExtraDeviceInfo: ${extraDeviceInfo}`
143
+ brokerLog(
144
+ "success",
145
+ `Reconnected: ${deviceName} (${platform || "unknown platform"})`,
146
+ { socketId: id, deviceId }
114
147
  );
115
148
  users[existingUserIndex].id = id;
116
149
  if (platform) {
@@ -128,6 +161,7 @@ function socketHandle({ io }) {
128
161
  allDevices[existingDeviceIndex].id = id;
129
162
  allDevices[existingDeviceIndex].isConnected = true;
130
163
  allDevices[existingDeviceIndex].connectionNonce = connectionNonce;
164
+ allDevices[existingDeviceIndex].lastSeenAt = Date.now();
131
165
  if (platform) {
132
166
  allDevices[existingDeviceIndex].platform = platform;
133
167
  }
@@ -145,13 +179,11 @@ function socketHandle({ io }) {
145
179
  platform,
146
180
  isConnected: true,
147
181
  extraDeviceInfo,
148
- envVariables
182
+ envVariables,
183
+ lastSeenAt: Date.now()
149
184
  });
150
185
  }
151
- io.emit(
152
- "all-devices-update",
153
- allDevices.filter((device) => device.deviceName !== "Dashboard")
154
- );
186
+ emitAllDevices();
155
187
  console.log(
156
188
  `${LOG_PREFIX} Updated users list: ${users.map((u) => u.deviceName).join(", ")}`
157
189
  );
@@ -172,7 +204,13 @@ function socketHandle({ io }) {
172
204
  }
173
205
  });
174
206
  if (highestNumber > 0 && !isDashboard) {
175
- deviceName = `${deviceName} #${highestNumber + 1}`;
207
+ const renamed = `${deviceName} #${highestNumber + 1}`;
208
+ brokerLog(
209
+ "warn",
210
+ `Duplicate device name "${deviceName}" \u2014 renamed to "${renamed}"`,
211
+ { socketId: id, deviceId }
212
+ );
213
+ deviceName = renamed;
176
214
  }
177
215
  if (id) {
178
216
  const newUser = {
@@ -183,7 +221,8 @@ function socketHandle({ io }) {
183
221
  isConnected: true,
184
222
  extraDeviceInfo,
185
223
  envVariables,
186
- connectionNonce
224
+ connectionNonce,
225
+ lastSeenAt: Date.now()
187
226
  };
188
227
  users.push(newUser);
189
228
  if (deviceName !== "Dashboard" && deviceId) {
@@ -196,17 +235,16 @@ function socketHandle({ io }) {
196
235
  allDevices.push({ ...newUser });
197
236
  }
198
237
  }
199
- console.log(
200
- `${LOG_PREFIX} New user connected - ID: ${id}, Name: ${deviceName}${deviceId ? `, DeviceId: ${deviceId}` : ""}${platform ? `, Platform: ${platform}` : ""}`
238
+ brokerLog(
239
+ isDashboard ? "debug" : "info",
240
+ `Connected: ${deviceName}${platform ? ` (${platform})` : ""}`,
241
+ { socketId: id, deviceId }
201
242
  );
202
243
  if (isDashboard && id) {
203
244
  dashboardClients.push(id);
204
245
  console.log(`${LOG_PREFIX} Registered dashboard client with ID: ${id}`);
205
246
  }
206
- io.emit(
207
- "all-devices-update",
208
- allDevices.filter((device) => device.deviceName !== "Dashboard")
209
- );
247
+ emitAllDevices();
210
248
  console.log(
211
249
  `${LOG_PREFIX} Updated device list: ${users.map((u) => u.deviceName).join(", ")}`
212
250
  );
@@ -336,6 +374,9 @@ function socketHandle({ io }) {
336
374
  for (const capabilities of deviceCapabilities.values()) {
337
375
  socket.emit("devtool-capabilities", capabilities);
338
376
  }
377
+ for (const entry of brokerLogBuffer) {
378
+ socket.emit("broker-log", entry);
379
+ }
339
380
  }
340
381
  socket.on(
341
382
  "device-license",
@@ -355,13 +396,12 @@ function socketHandle({ io }) {
355
396
  device.licenseKey = nextIsPro ? nextKey : void 0;
356
397
  }
357
398
  }
358
- console.log(
359
- `${LOG_PREFIX} device-license from ${user?.deviceName || socket.id}: isPro=${nextIsPro}${nextKey ? ", key set" : ""}`
360
- );
361
- io.emit(
362
- "all-devices-update",
363
- allDevices.filter((device) => device.deviceName !== "Dashboard")
399
+ brokerLog(
400
+ "debug",
401
+ `device-license from ${user?.deviceName || socket.id}: isPro=${nextIsPro}${nextKey ? ", key set" : ""}`,
402
+ { socketId: socket.id }
364
403
  );
404
+ emitAllDevices();
365
405
  }
366
406
  );
367
407
  socket.on(
@@ -375,6 +415,13 @@ function socketHandle({ io }) {
375
415
  console.log(
376
416
  `${LOG_PREFIX} Capabilities from ${message.persistentDeviceId}: ${message.tools.map((tool) => `${tool.toolId}@v${tool.version}`).join(", ")}`
377
417
  );
418
+ if (message.protocolVersion !== SYNC_PROTOCOL_VERSION) {
419
+ brokerLog(
420
+ "warn",
421
+ `Protocol version mismatch from ${message.persistentDeviceId}: device speaks v${message.protocolVersion}, broker speaks v${SYNC_PROTOCOL_VERSION} \u2014 update @buoy-gg packages or Buoy Desktop`,
422
+ { deviceId: message.persistentDeviceId }
423
+ );
424
+ }
378
425
  deviceCapabilities.set(message.persistentDeviceId, message);
379
426
  forwardToDashboards("devtool-capabilities", message);
380
427
  for (const key of watchCounts.keys()) {
@@ -410,6 +457,31 @@ function socketHandle({ io }) {
410
457
  `devtool state request ${message.toolId}`
411
458
  );
412
459
  });
460
+ socket.on("forget-device", (payload) => {
461
+ const targetDeviceId = payload?.deviceId;
462
+ if (!dashboardClients.includes(socket.id)) return;
463
+ if (!targetDeviceId || activeConnectionsMap.has(targetDeviceId)) return;
464
+ const target = allDevices.find((d) => d.deviceId === targetDeviceId);
465
+ users = users.filter((u) => u.deviceId !== targetDeviceId);
466
+ const historyIndex = allDevices.findIndex(
467
+ (d) => d.deviceId === targetDeviceId
468
+ );
469
+ if (historyIndex !== -1) {
470
+ allDevices.splice(historyIndex, 1);
471
+ }
472
+ deviceCapabilities.delete(targetDeviceId);
473
+ for (const [socketId, mappedDeviceId] of deviceIdMap) {
474
+ if (mappedDeviceId === targetDeviceId) {
475
+ deviceIdMap.delete(socketId);
476
+ }
477
+ }
478
+ brokerLog(
479
+ "info",
480
+ `Forgot device: ${target?.deviceName ?? targetDeviceId}`,
481
+ { deviceId: targetDeviceId }
482
+ );
483
+ emitAllDevices();
484
+ });
413
485
  socket.on("devtool-action", (message) => {
414
486
  console.log(
415
487
  `${LOG_PREFIX} Devtool action from dashboard: ${message.toolId}.${message.action} -> ${message.targetDeviceId}`
@@ -469,9 +541,6 @@ function createBroker(options = {}) {
469
541
  });
470
542
  return { io, httpServer, port, close };
471
543
  }
472
-
473
- // src/protocol.ts
474
- var SYNC_PROTOCOL_VERSION = 1;
475
544
  // Annotate the CommonJS export names for ESM import in node:
476
545
  0 && (module.exports = {
477
546
  DEFAULT_BROKER_PORT,
package/dist/index.mjs CHANGED
@@ -1,3 +1,6 @@
1
+ // src/protocol.ts
2
+ var SYNC_PROTOCOL_VERSION = 1;
3
+
1
4
  // src/socketHandle.ts
2
5
  var users = [];
3
6
  var allDevices = [];
@@ -9,8 +12,36 @@ var dashboardWatches = /* @__PURE__ */ new Map();
9
12
  var watchCounts = /* @__PURE__ */ new Map();
10
13
  var toWatchKey = (targetDeviceId, toolId) => JSON.stringify([targetDeviceId, toolId]);
11
14
  var fromWatchKey = (key) => JSON.parse(key);
15
+ var brokerLogBuffer = [];
16
+ var BROKER_LOG_BUFFER_MAX = 200;
17
+ var MAX_OFFLINE_AGE_MS = 24 * 60 * 60 * 1e3;
12
18
  function socketHandle({ io }) {
13
19
  const LOG_PREFIX = "[SERVER]";
20
+ function brokerLog(level, message, data) {
21
+ console.log(`${LOG_PREFIX} ${message}`);
22
+ const entry = { ts: Date.now(), level, message, data };
23
+ brokerLogBuffer.push(entry);
24
+ if (brokerLogBuffer.length > BROKER_LOG_BUFFER_MAX) {
25
+ brokerLogBuffer.shift();
26
+ }
27
+ forwardToDashboards("broker-log", entry);
28
+ }
29
+ function emitAllDevices() {
30
+ const now = Date.now();
31
+ for (let i = allDevices.length - 1; i >= 0; i--) {
32
+ const device = allDevices[i];
33
+ if (!device.isConnected && device.lastSeenAt && now - device.lastSeenAt > MAX_OFFLINE_AGE_MS) {
34
+ allDevices.splice(i, 1);
35
+ if (device.deviceId) {
36
+ deviceCapabilities.delete(device.deviceId);
37
+ }
38
+ }
39
+ }
40
+ io.emit(
41
+ "all-devices-update",
42
+ allDevices.filter((device) => device.deviceName !== "Dashboard")
43
+ );
44
+ }
14
45
  function handleClose(id, reason) {
15
46
  const user = users.find((user2) => user2.id === id);
16
47
  const deviceId = deviceIdMap.get(id);
@@ -26,6 +57,7 @@ function socketHandle({ io }) {
26
57
  if (deviceIndex !== -1) {
27
58
  allDevices[deviceIndex].isConnected = false;
28
59
  allDevices[deviceIndex].lastDisconnectReason = reason;
60
+ allDevices[deviceIndex].lastSeenAt = Date.now();
29
61
  activeConnectionsMap.delete(deviceId);
30
62
  }
31
63
  }
@@ -38,13 +70,12 @@ function socketHandle({ io }) {
38
70
  const wasDashboard = dashboardClients.includes(id);
39
71
  dashboardClients = dashboardClients.filter((clientId) => clientId !== id);
40
72
  releaseDashboardWatches(id);
41
- console.log(
42
- `${LOG_PREFIX} Client disconnected - ID: ${id}, Name: ${user?.deviceName || "Unknown"}, Was Dashboard: ${wasDashboard}, Reason: ${reason ?? "unknown"}`
43
- );
44
- io.emit(
45
- "all-devices-update",
46
- allDevices.filter((device) => device.deviceName !== "Dashboard")
73
+ brokerLog(
74
+ wasDashboard ? "debug" : "warn",
75
+ `Disconnected: ${user?.deviceName || id} (${reason ?? "unknown"})`,
76
+ { socketId: id, reason, wasDashboard }
47
77
  );
78
+ emitAllDevices();
48
79
  console.log(
49
80
  `${LOG_PREFIX} Updated users list: ${users.map((u) => u.deviceName).join(", ")}`
50
81
  );
@@ -69,8 +100,10 @@ function socketHandle({ io }) {
69
100
  (device) => device.deviceId === deviceId
70
101
  );
71
102
  if (existingUserIndex !== -1) {
72
- console.log(
73
- `${LOG_PREFIX} Reconnecting existing device - ID: ${id}, Name: ${deviceName}, DeviceId: ${deviceId}, Platform: ${platform || "Unknown"}, ExtraDeviceInfo: ${extraDeviceInfo}`
103
+ brokerLog(
104
+ "success",
105
+ `Reconnected: ${deviceName} (${platform || "unknown platform"})`,
106
+ { socketId: id, deviceId }
74
107
  );
75
108
  users[existingUserIndex].id = id;
76
109
  if (platform) {
@@ -88,6 +121,7 @@ function socketHandle({ io }) {
88
121
  allDevices[existingDeviceIndex].id = id;
89
122
  allDevices[existingDeviceIndex].isConnected = true;
90
123
  allDevices[existingDeviceIndex].connectionNonce = connectionNonce;
124
+ allDevices[existingDeviceIndex].lastSeenAt = Date.now();
91
125
  if (platform) {
92
126
  allDevices[existingDeviceIndex].platform = platform;
93
127
  }
@@ -105,13 +139,11 @@ function socketHandle({ io }) {
105
139
  platform,
106
140
  isConnected: true,
107
141
  extraDeviceInfo,
108
- envVariables
142
+ envVariables,
143
+ lastSeenAt: Date.now()
109
144
  });
110
145
  }
111
- io.emit(
112
- "all-devices-update",
113
- allDevices.filter((device) => device.deviceName !== "Dashboard")
114
- );
146
+ emitAllDevices();
115
147
  console.log(
116
148
  `${LOG_PREFIX} Updated users list: ${users.map((u) => u.deviceName).join(", ")}`
117
149
  );
@@ -132,7 +164,13 @@ function socketHandle({ io }) {
132
164
  }
133
165
  });
134
166
  if (highestNumber > 0 && !isDashboard) {
135
- deviceName = `${deviceName} #${highestNumber + 1}`;
167
+ const renamed = `${deviceName} #${highestNumber + 1}`;
168
+ brokerLog(
169
+ "warn",
170
+ `Duplicate device name "${deviceName}" \u2014 renamed to "${renamed}"`,
171
+ { socketId: id, deviceId }
172
+ );
173
+ deviceName = renamed;
136
174
  }
137
175
  if (id) {
138
176
  const newUser = {
@@ -143,7 +181,8 @@ function socketHandle({ io }) {
143
181
  isConnected: true,
144
182
  extraDeviceInfo,
145
183
  envVariables,
146
- connectionNonce
184
+ connectionNonce,
185
+ lastSeenAt: Date.now()
147
186
  };
148
187
  users.push(newUser);
149
188
  if (deviceName !== "Dashboard" && deviceId) {
@@ -156,17 +195,16 @@ function socketHandle({ io }) {
156
195
  allDevices.push({ ...newUser });
157
196
  }
158
197
  }
159
- console.log(
160
- `${LOG_PREFIX} New user connected - ID: ${id}, Name: ${deviceName}${deviceId ? `, DeviceId: ${deviceId}` : ""}${platform ? `, Platform: ${platform}` : ""}`
198
+ brokerLog(
199
+ isDashboard ? "debug" : "info",
200
+ `Connected: ${deviceName}${platform ? ` (${platform})` : ""}`,
201
+ { socketId: id, deviceId }
161
202
  );
162
203
  if (isDashboard && id) {
163
204
  dashboardClients.push(id);
164
205
  console.log(`${LOG_PREFIX} Registered dashboard client with ID: ${id}`);
165
206
  }
166
- io.emit(
167
- "all-devices-update",
168
- allDevices.filter((device) => device.deviceName !== "Dashboard")
169
- );
207
+ emitAllDevices();
170
208
  console.log(
171
209
  `${LOG_PREFIX} Updated device list: ${users.map((u) => u.deviceName).join(", ")}`
172
210
  );
@@ -296,6 +334,9 @@ function socketHandle({ io }) {
296
334
  for (const capabilities of deviceCapabilities.values()) {
297
335
  socket.emit("devtool-capabilities", capabilities);
298
336
  }
337
+ for (const entry of brokerLogBuffer) {
338
+ socket.emit("broker-log", entry);
339
+ }
299
340
  }
300
341
  socket.on(
301
342
  "device-license",
@@ -315,13 +356,12 @@ function socketHandle({ io }) {
315
356
  device.licenseKey = nextIsPro ? nextKey : void 0;
316
357
  }
317
358
  }
318
- console.log(
319
- `${LOG_PREFIX} device-license from ${user?.deviceName || socket.id}: isPro=${nextIsPro}${nextKey ? ", key set" : ""}`
320
- );
321
- io.emit(
322
- "all-devices-update",
323
- allDevices.filter((device) => device.deviceName !== "Dashboard")
359
+ brokerLog(
360
+ "debug",
361
+ `device-license from ${user?.deviceName || socket.id}: isPro=${nextIsPro}${nextKey ? ", key set" : ""}`,
362
+ { socketId: socket.id }
324
363
  );
364
+ emitAllDevices();
325
365
  }
326
366
  );
327
367
  socket.on(
@@ -335,6 +375,13 @@ function socketHandle({ io }) {
335
375
  console.log(
336
376
  `${LOG_PREFIX} Capabilities from ${message.persistentDeviceId}: ${message.tools.map((tool) => `${tool.toolId}@v${tool.version}`).join(", ")}`
337
377
  );
378
+ if (message.protocolVersion !== SYNC_PROTOCOL_VERSION) {
379
+ brokerLog(
380
+ "warn",
381
+ `Protocol version mismatch from ${message.persistentDeviceId}: device speaks v${message.protocolVersion}, broker speaks v${SYNC_PROTOCOL_VERSION} \u2014 update @buoy-gg packages or Buoy Desktop`,
382
+ { deviceId: message.persistentDeviceId }
383
+ );
384
+ }
338
385
  deviceCapabilities.set(message.persistentDeviceId, message);
339
386
  forwardToDashboards("devtool-capabilities", message);
340
387
  for (const key of watchCounts.keys()) {
@@ -370,6 +417,31 @@ function socketHandle({ io }) {
370
417
  `devtool state request ${message.toolId}`
371
418
  );
372
419
  });
420
+ socket.on("forget-device", (payload) => {
421
+ const targetDeviceId = payload?.deviceId;
422
+ if (!dashboardClients.includes(socket.id)) return;
423
+ if (!targetDeviceId || activeConnectionsMap.has(targetDeviceId)) return;
424
+ const target = allDevices.find((d) => d.deviceId === targetDeviceId);
425
+ users = users.filter((u) => u.deviceId !== targetDeviceId);
426
+ const historyIndex = allDevices.findIndex(
427
+ (d) => d.deviceId === targetDeviceId
428
+ );
429
+ if (historyIndex !== -1) {
430
+ allDevices.splice(historyIndex, 1);
431
+ }
432
+ deviceCapabilities.delete(targetDeviceId);
433
+ for (const [socketId, mappedDeviceId] of deviceIdMap) {
434
+ if (mappedDeviceId === targetDeviceId) {
435
+ deviceIdMap.delete(socketId);
436
+ }
437
+ }
438
+ brokerLog(
439
+ "info",
440
+ `Forgot device: ${target?.deviceName ?? targetDeviceId}`,
441
+ { deviceId: targetDeviceId }
442
+ );
443
+ emitAllDevices();
444
+ });
373
445
  socket.on("devtool-action", (message) => {
374
446
  console.log(
375
447
  `${LOG_PREFIX} Devtool action from dashboard: ${message.toolId}.${message.action} -> ${message.targetDeviceId}`
@@ -429,9 +501,6 @@ function createBroker(options = {}) {
429
501
  });
430
502
  return { io, httpServer, port, close };
431
503
  }
432
-
433
- // src/protocol.ts
434
- var SYNC_PROTOCOL_VERSION = 1;
435
504
  export {
436
505
  DEFAULT_BROKER_PORT,
437
506
  SOCKET_CONFIG,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@buoy-gg/sync-broker",
3
- "version": "6.0.1",
3
+ "version": "7.0.1",
4
4
  "description": "Headless Socket.IO broker for the Buoy devtool sync protocol (v1) — routes messages between devices and dashboard/MCP clients",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -36,13 +36,13 @@
36
36
  },
37
37
  "repository": {
38
38
  "type": "git",
39
- "url": "https://github.com/LovesWorking/react-native-buoy.git",
40
- "directory": "packages/sync-broker"
39
+ "url": "https://github.com/Buoy-gg/buoy.git"
41
40
  },
42
41
  "publishConfig": {
43
42
  "access": "public",
44
43
  "tag": "latest"
45
44
  },
45
+ "homepage": "https://buoy.gg",
46
46
  "scripts": {
47
47
  "build": "tsup",
48
48
  "typecheck": "tsc --noEmit",