@qontinui/ui-bridge-native 0.6.13 → 0.6.15

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.
@@ -4311,7 +4311,7 @@ function createServerHandlers(registry, executor, config) {
4311
4311
  };
4312
4312
  if (config?.appInfo) {
4313
4313
  response.uiBridge = {
4314
- version: "0.6.13",
4314
+ version: "0.6.15",
4315
4315
  ...config.appInfo,
4316
4316
  capabilities: ["elements", "components", "actions", "design"],
4317
4317
  elementCount: stats.elements,
@@ -6234,7 +6234,26 @@ function describeErrorEvent(event) {
6234
6234
  }
6235
6235
 
6236
6236
  // src/transport/DeviceAnnouncer.ts
6237
+ function registeredServiceName(result, requested) {
6238
+ if (result !== null && typeof result === "object") {
6239
+ const name = result.name;
6240
+ if (typeof name === "string" && name.length > 0) return name;
6241
+ }
6242
+ return requested;
6243
+ }
6237
6244
  var DEFAULT_PORT = 8087;
6245
+ async function releaseZeroconf(zeroconf, name) {
6246
+ if (name !== null) {
6247
+ try {
6248
+ await zeroconf.unpublishService(name);
6249
+ } catch {
6250
+ }
6251
+ }
6252
+ try {
6253
+ zeroconf.removeDeviceListeners?.();
6254
+ } catch {
6255
+ }
6256
+ }
6238
6257
  var RECONNECT_INITIAL_DELAY_MS = 2e3;
6239
6258
  var RECONNECT_MAX_DELAY_MS = 6e4;
6240
6259
  var DeviceAnnouncer = class {
@@ -6247,8 +6266,16 @@ var DeviceAnnouncer = class {
6247
6266
  this.reconnectTimer = null;
6248
6267
  this.reconnectDelay = RECONNECT_INITIAL_DELAY_MS;
6249
6268
  this.stopped = false;
6250
- /** Zeroconf instance, set when mDNS is successfully started */
6269
+ /** Zeroconf instance, set when mDNS is started (cleared by `stop()`) */
6251
6270
  this.zeroconf = null;
6271
+ /** The name the library registered — the only name this announcer may unpublish */
6272
+ this.publishedName = null;
6273
+ /**
6274
+ * True while a publish is awaiting the library. A `stop()` that lands in that
6275
+ * window leaves the cleanup to the publish path, which is the only side that
6276
+ * will learn the registered name.
6277
+ */
6278
+ this.publishInFlight = false;
6252
6279
  this.config = config;
6253
6280
  this.pairingToken = generateHex(16);
6254
6281
  }
@@ -6273,19 +6300,38 @@ var DeviceAnnouncer = class {
6273
6300
  );
6274
6301
  return;
6275
6302
  }
6303
+ if (this.stopped) return;
6304
+ let zeroconf = null;
6276
6305
  try {
6277
- this.zeroconf = new ZeroconfCtor();
6306
+ zeroconf = new ZeroconfCtor();
6307
+ this.zeroconf = zeroconf;
6278
6308
  const port = this.config.port ?? DEFAULT_PORT;
6279
6309
  const serviceName = `UIBridge-${this.config.deviceId.slice(0, 8)}`;
6280
- this.zeroconf.publishService("_uibridge", "_tcp.", "local.", serviceName, port, {
6281
- device_id: this.config.deviceId,
6282
- app_id: this.config.appId,
6283
- version: this.config.version ?? "unknown",
6284
- pairing_token: this.pairingToken
6285
- });
6310
+ this.publishInFlight = true;
6311
+ let result;
6312
+ try {
6313
+ result = await zeroconf.publishService("uibridge", "tcp", "local.", serviceName, port, {
6314
+ device_id: this.config.deviceId,
6315
+ app_id: this.config.appId,
6316
+ version: this.config.version ?? "unknown",
6317
+ pairing_token: this.pairingToken
6318
+ });
6319
+ } finally {
6320
+ this.publishInFlight = false;
6321
+ }
6322
+ const registered = registeredServiceName(result, serviceName);
6323
+ if (this.stopped) {
6324
+ await releaseZeroconf(zeroconf, registered);
6325
+ return;
6326
+ }
6327
+ this.publishedName = registered;
6286
6328
  this.state = { ...this.state, mdnsActive: true };
6287
- transportLogger.log(`[DeviceAnnouncer] mDNS: advertising "${serviceName}" on port ${port}`);
6329
+ transportLogger.log(`[DeviceAnnouncer] mDNS: advertising "${registered}" on port ${port}`);
6288
6330
  } catch (err) {
6331
+ if (this.stopped) {
6332
+ if (zeroconf) await releaseZeroconf(zeroconf, null);
6333
+ return;
6334
+ }
6289
6335
  transportLogger.warn("[DeviceAnnouncer] mDNS start failed:", err);
6290
6336
  }
6291
6337
  }
@@ -6358,15 +6404,15 @@ var DeviceAnnouncer = class {
6358
6404
  clearTimeout(this.reconnectTimer);
6359
6405
  this.reconnectTimer = null;
6360
6406
  }
6361
- if (this.zeroconf) {
6362
- try {
6363
- const serviceName = `UIBridge-${this.config.deviceId.slice(0, 8)}`;
6364
- this.zeroconf.unpublishService(serviceName);
6365
- } catch {
6366
- }
6367
- this.zeroconf = null;
6368
- }
6407
+ const zeroconf = this.zeroconf;
6408
+ const publishedName = this.publishedName;
6409
+ const inFlight = this.publishInFlight;
6410
+ this.zeroconf = null;
6411
+ this.publishedName = null;
6369
6412
  this.state = { ...this.state, mdnsActive: false };
6413
+ if (zeroconf && !inFlight) {
6414
+ await releaseZeroconf(zeroconf, publishedName);
6415
+ }
6370
6416
  if (this.cloudWs) {
6371
6417
  this.cloudWs.onclose = null;
6372
6418
  this.cloudWs.close();
@@ -6782,6 +6828,7 @@ function UIBridgeNativeProvider({
6782
6828
  routeProvider,
6783
6829
  cloudRelayConfig,
6784
6830
  enableMdnsAnnounce,
6831
+ zeroconf,
6785
6832
  deviceId
6786
6833
  }) {
6787
6834
  const features = useValueStable(featuresProp);
@@ -6955,7 +7002,7 @@ function UIBridgeNativeProvider({
6955
7002
  cloudToken: cloudRelayConfig?.authToken
6956
7003
  });
6957
7004
  announcerRef.current = announcer;
6958
- void announcer.startMdnsAdvertise().catch((err) => {
7005
+ void announcer.startMdnsAdvertise(zeroconf).catch((err) => {
6959
7006
  console.warn("[ui-bridge-native] mDNS advertise failed:", err);
6960
7007
  });
6961
7008
  } catch (err) {
@@ -6996,6 +7043,7 @@ function UIBridgeNativeProvider({
6996
7043
  cloudRelayConfig?.relayUrl,
6997
7044
  cloudRelayConfig?.authToken,
6998
7045
  enableMdnsAnnounce,
7046
+ zeroconf,
6999
7047
  deviceId
7000
7048
  ]);
7001
7049
  useEffect(() => {