@ukeyfe/hardware-transport-electron 1.1.25 → 1.1.27

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.
@@ -32,7 +32,7 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
32
32
 
33
33
  function initNobleBleSupport(webContents) {
34
34
  return __awaiter(this, void 0, void 0, function* () {
35
- const { setupNobleBleHandlers } = yield Promise.resolve().then(function () { return require('./noble-ble-handler-37d3b074.js'); });
35
+ const { setupNobleBleHandlers } = yield Promise.resolve().then(function () { return require('./noble-ble-handler-3c136b8c.js'); });
36
36
  setupNobleBleHandlers(webContents);
37
37
  });
38
38
  }
package/dist/index.d.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  import { WebContents } from 'electron';
2
2
  import { Characteristic, Peripheral } from '@stoprocent/noble';
3
+ import { UKeyDeviceInfoBase } from '@ukeyfe/hardware-transport';
3
4
 
4
- interface DeviceInfo {
5
+ interface DeviceInfo extends UKeyDeviceInfoBase {
5
6
  id: string;
6
7
  name: string;
7
8
  state: string;
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var index = require('./index-60176982.js');
5
+ var index = require('./index-5c4c1f33.js');
6
6
 
7
7
 
8
8
 
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var index = require('./index-60176982.js');
3
+ var index = require('./index-5c4c1f33.js');
4
4
  var hardwareShared = require('@ukeyfe/hardware-shared');
5
5
  var hardwareTransport = require('@ukeyfe/hardware-transport');
6
6
  var pRetry = require('p-retry');
@@ -614,6 +614,7 @@ function enumerateDevices() {
614
614
  if (!existingDevice) {
615
615
  const deviceName = ((_a = peripheral.advertisement) === null || _a === void 0 ? void 0 : _a.localName) || 'Unknown Device';
616
616
  devices.push({
617
+ commType: 'electron-ble',
617
618
  id,
618
619
  name: deviceName,
619
620
  state: peripheral.state || 'disconnected',
@@ -663,6 +664,7 @@ function getDevice(deviceId) {
663
664
  if (peripheral) {
664
665
  const deviceName = ((_a = peripheral.advertisement) === null || _a === void 0 ? void 0 : _a.localName) || 'Unknown Device';
665
666
  return {
667
+ commType: 'electron-ble',
666
668
  id: peripheral.id,
667
669
  name: deviceName,
668
670
  state: peripheral.state || 'disconnected',
@@ -672,12 +674,14 @@ function getDevice(deviceId) {
672
674
  if (connectedPeripheral) {
673
675
  const deviceName = ((_b = connectedPeripheral.advertisement) === null || _b === void 0 ? void 0 : _b.localName) || 'Unknown Device';
674
676
  return {
677
+ commType: 'electron-ble',
675
678
  id: connectedPeripheral.id,
676
679
  name: deviceName,
677
680
  state: connectedPeripheral.state || 'connected',
678
681
  };
679
682
  }
680
683
  return {
684
+ commType: 'electron-ble',
681
685
  id: deviceId,
682
686
  name: 'UKey Device',
683
687
  state: 'disconnected',
@@ -1001,22 +1005,27 @@ function unsubscribeNotifications(deviceId) {
1001
1005
  const { notify: notifyCharacteristic } = characteristics;
1002
1006
  logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Unsubscribing from notifications for device:', deviceId);
1003
1007
  subscriptionOperations.set(deviceId, 'unsubscribing');
1004
- return new Promise(resolve => {
1005
- notifyCharacteristic.unsubscribe((error) => {
1006
- if (error) {
1007
- logger === null || logger === void 0 ? void 0 : logger.error('[NobleBLE] Notification unsubscription failed:', error);
1008
- }
1009
- else {
1010
- logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Notification unsubscription successful');
1011
- }
1012
- notifyCharacteristic.removeAllListeners('data');
1013
- notificationCallbacks.delete(deviceId);
1014
- devicePacketStates.delete(deviceId);
1015
- subscribedDevices.delete(deviceId);
1016
- subscriptionOperations.set(deviceId, 'idle');
1017
- resolve();
1008
+ try {
1009
+ yield new Promise((resolve, reject) => {
1010
+ notifyCharacteristic.unsubscribe((error) => {
1011
+ if (error) {
1012
+ logger === null || logger === void 0 ? void 0 : logger.error('[NobleBLE] Notification unsubscription failed:', error);
1013
+ reject(error);
1014
+ }
1015
+ else {
1016
+ logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Notification unsubscription successful');
1017
+ resolve();
1018
+ }
1019
+ });
1018
1020
  });
1019
- });
1021
+ notifyCharacteristic.removeAllListeners('data');
1022
+ notificationCallbacks.delete(deviceId);
1023
+ devicePacketStates.delete(deviceId);
1024
+ subscribedDevices.delete(deviceId);
1025
+ }
1026
+ finally {
1027
+ subscriptionOperations.set(deviceId, 'idle');
1028
+ }
1020
1029
  });
1021
1030
  }
1022
1031
  function subscribeNotifications(deviceId, callback) {
@@ -1028,17 +1037,25 @@ function subscribeNotifications(deviceId, callback) {
1028
1037
  }
1029
1038
  const { notify: notifyCharacteristic } = characteristics;
1030
1039
  logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Subscribing to notifications for device:', deviceId);
1040
+ const opState = subscriptionOperations.get(deviceId);
1031
1041
  logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Subscribe context', {
1032
1042
  deviceId,
1033
- opStateBefore: subscriptionOperations.get(deviceId) || 'idle',
1043
+ opStateBefore: opState || 'idle',
1034
1044
  paired: false,
1035
1045
  hasController: false,
1036
1046
  });
1037
- const opState = subscriptionOperations.get(deviceId);
1038
1047
  if (opState === 'subscribing') {
1048
+ logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Subscription already in progress, updating callback only');
1039
1049
  notificationCallbacks.set(deviceId, callback);
1040
1050
  return Promise.resolve();
1041
1051
  }
1052
+ if (opState === 'unsubscribing') {
1053
+ logger === null || logger === void 0 ? void 0 : logger.error('[NobleBLE] Cannot subscribe while unsubscribe is in progress', {
1054
+ deviceId,
1055
+ opState,
1056
+ });
1057
+ throw hardwareShared.ERRORS.TypedError(hardwareShared.HardwareErrorCode.DeviceBusy, `Device ${deviceId} is currently unsubscribing, please retry after reconnection`);
1058
+ }
1042
1059
  subscriptionOperations.set(deviceId, 'subscribing');
1043
1060
  if (subscribedDevices.get(deviceId)) {
1044
1061
  logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Device already subscribed to characteristic, updating callback only');
@@ -1 +1 @@
1
- {"version":3,"file":"noble-ble-handler.d.ts","sourceRoot":"","sources":["../src/noble-ble-handler.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,WAAW,EAAsB,MAAM,UAAU,CAAC;AAq9ChE,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI,CAsKpE"}
1
+ {"version":3,"file":"noble-ble-handler.d.ts","sourceRoot":"","sources":["../src/noble-ble-handler.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAsB,WAAW,EAAE,MAAM,UAAU,CAAC;AA0+ChE,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI,CAsKpE"}
@@ -1,5 +1,6 @@
1
- import type { Peripheral, Characteristic } from '@stoprocent/noble';
2
- export interface DeviceInfo {
1
+ import type { Characteristic, Peripheral } from '@stoprocent/noble';
2
+ import type { UKeyDeviceInfoBase } from '@ukeyfe/hardware-transport';
3
+ export interface DeviceInfo extends UKeyDeviceInfoBase {
3
4
  id: string;
4
5
  name: string;
5
6
  state: string;
@@ -1 +1 @@
1
- {"version":3,"file":"noble-extended.d.ts","sourceRoot":"","sources":["../../src/types/noble-extended.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAGpE,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAGD,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,cAAc,CAAC;IACtB,MAAM,EAAE,cAAc,CAAC;CACxB;AAGD,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,CACX,YAAY,EAAE,MAAM,EAAE,EACtB,eAAe,EAAE,OAAO,EACxB,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,KAAK,IAAI,GACjC,IAAI,CAAC;IACR,YAAY,CAAC,QAAQ,CAAC,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;IAC1C,EAAE,CAAC,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC;IAClE,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC,UAAU,EAAE,UAAU,KAAK,IAAI,GAAG,IAAI,CAAC;IACxE,cAAc,CAAC,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC;IAC9E,cAAc,CAAC,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC,UAAU,EAAE,UAAU,KAAK,IAAI,GAAG,IAAI,CAAC;CACrF;AAGD,MAAM,WAAW,MAAM;IACrB,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;IAC5C,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;IAC7C,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;CAC9C;AAGD,wBAAgB,OAAO,CACrB,MAAM,EAAE,MAAM,GAAG,IAAI,EACrB,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,OAAO,EACjC,OAAO,EAAE,MAAM,EACf,GAAG,IAAI,EAAE,GAAG,EAAE,GACb,IAAI,CAMN"}
1
+ {"version":3,"file":"noble-extended.d.ts","sourceRoot":"","sources":["../../src/types/noble-extended.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAGrE,MAAM,WAAW,UAAW,SAAQ,kBAAkB;IACpD,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAGD,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,cAAc,CAAC;IACtB,MAAM,EAAE,cAAc,CAAC;CACxB;AAGD,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,CACX,YAAY,EAAE,MAAM,EAAE,EACtB,eAAe,EAAE,OAAO,EACxB,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,KAAK,IAAI,GACjC,IAAI,CAAC;IACR,YAAY,CAAC,QAAQ,CAAC,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;IAC1C,EAAE,CAAC,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC;IAClE,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC,UAAU,EAAE,UAAU,KAAK,IAAI,GAAG,IAAI,CAAC;IACxE,cAAc,CAAC,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC;IAC9E,cAAc,CAAC,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC,UAAU,EAAE,UAAU,KAAK,IAAI,GAAG,IAAI,CAAC;CACrF;AAGD,MAAM,WAAW,MAAM;IACrB,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;IAC5C,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;IAC7C,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;CAC9C;AAGD,wBAAgB,OAAO,CACrB,MAAM,EAAE,MAAM,GAAG,IAAI,EACrB,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,OAAO,EACjC,OAAO,EAAE,MAAM,EACf,GAAG,IAAI,EAAE,GAAG,EAAE,GACb,IAAI,CAMN"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ukeyfe/hardware-transport-electron",
3
- "version": "1.1.25",
3
+ "version": "1.1.27",
4
4
  "author": "UKey",
5
5
  "homepage": "https://github.com/UKeyHQ/hardware-js-sdk#readme",
6
6
  "license": "MIT",
@@ -11,7 +11,7 @@
11
11
  },
12
12
  "repository": {
13
13
  "type": "git",
14
- "url": "git+https://github.com/bestyourwallet/hardware-js-sdk"
14
+ "url": "git+https://github.com/UKeyHQ/hardware-js-sdk.git"
15
15
  },
16
16
  "scripts": {
17
17
  "dev": "rimraf dist && rollup -c ../../build/rollup.config.js -w",
@@ -26,9 +26,9 @@
26
26
  },
27
27
  "dependencies": {
28
28
  "@stoprocent/noble": "2.3.4",
29
- "@ukeyfe/hardware-core": "1.1.25",
30
- "@ukeyfe/hardware-shared": "1.1.25",
31
- "@ukeyfe/hardware-transport": "1.1.25",
29
+ "@ukeyfe/hardware-core": "1.1.27",
30
+ "@ukeyfe/hardware-shared": "1.1.27",
31
+ "@ukeyfe/hardware-transport": "1.1.27",
32
32
  "p-retry": "^4.6.2"
33
33
  },
34
34
  "devDependencies": {
@@ -36,5 +36,5 @@
36
36
  "electron": "^25.0.0",
37
37
  "typescript": "^5.3.3"
38
38
  },
39
- "gitHead": "8f4ecd5e78a8cade44224204c4cf102e6e2a1712"
39
+ "gitHead": "4ee8e8dcee0fd7e1a361d4f8935856c80e292805"
40
40
  }
@@ -6,24 +6,26 @@
6
6
  /* eslint-disable @typescript-eslint/no-var-requires, import/no-extraneous-dependencies */
7
7
 
8
8
  import {
9
- isUkeyDevice,
10
9
  EUKeyBleMessageKeys,
10
+ ERRORS,
11
+ HardwareErrorCode,
12
+ UKEY_NOTIFY_CHARACTERISTIC_UUID,
11
13
  UKEY_SERVICE_UUID,
12
14
  UKEY_WRITE_CHARACTERISTIC_UUID,
13
- UKEY_NOTIFY_CHARACTERISTIC_UUID,
14
15
  isHeaderChunk,
15
- ERRORS,
16
- HardwareErrorCode,
16
+ isUkeyDevice,
17
17
  wait,
18
18
  } from '@ukeyfe/hardware-shared';
19
19
  import { COMMON_HEADER_SIZE } from '@ukeyfe/hardware-transport';
20
- import type { WebContents, IpcMainInvokeEvent } from 'electron';
21
- import type { Peripheral, Service, Characteristic } from '@stoprocent/noble';
22
20
  import pRetry from 'p-retry';
23
- import type { NobleModule, Logger, DeviceInfo, CharacteristicPair } from './types/noble-extended';
21
+
24
22
  import { safeLog } from './types/noble-extended';
25
23
  import { softRefreshSubscription } from './ble-ops';
26
24
 
25
+ import type { IpcMainInvokeEvent, WebContents } from 'electron';
26
+ import type { Characteristic, Peripheral, Service } from '@stoprocent/noble';
27
+ import type { CharacteristicPair, DeviceInfo, Logger, NobleModule } from './types/noble-extended';
28
+
27
29
  // Noble will be dynamically imported to avoid bundlinpissues
28
30
  let noble: NobleModule | null = null;
29
31
  let logger: Logger | null = null;
@@ -50,7 +52,7 @@ const deviceCharacteristics = new Map<string, CharacteristicPair>();
50
52
  const notificationCallbacks = new Map<string, (data: string) => void>();
51
53
  const subscribedDevices = new Map<string, boolean>(); // Track subscription status
52
54
 
53
- // 🔒 Add subscription operation state tracking to prevent race conditions
55
+ // 🔒 Subscription operation state tracking to prevent race conditions
54
56
  const subscriptionOperations = new Map<string, 'subscribing' | 'unsubscribing' | 'idle'>();
55
57
 
56
58
  // Packet reassembly state for each device
@@ -824,6 +826,7 @@ async function enumerateDevices(): Promise<DeviceInfo[]> {
824
826
  if (!existingDevice) {
825
827
  const deviceName = peripheral.advertisement?.localName || 'Unknown Device';
826
828
  devices.push({
829
+ commType: 'electron-ble',
827
830
  id,
828
831
  name: deviceName,
829
832
  state: peripheral.state || 'disconnected',
@@ -882,6 +885,7 @@ function getDevice(deviceId: string): DeviceInfo | null {
882
885
  if (peripheral) {
883
886
  const deviceName = peripheral.advertisement?.localName || 'Unknown Device';
884
887
  return {
888
+ commType: 'electron-ble',
885
889
  id: peripheral.id,
886
890
  name: deviceName,
887
891
  state: peripheral.state || 'disconnected',
@@ -893,6 +897,7 @@ function getDevice(deviceId: string): DeviceInfo | null {
893
897
  if (connectedPeripheral) {
894
898
  const deviceName = connectedPeripheral.advertisement?.localName || 'Unknown Device';
895
899
  return {
900
+ commType: 'electron-ble',
896
901
  id: connectedPeripheral.id,
897
902
  name: deviceName,
898
903
  state: connectedPeripheral.state || 'connected',
@@ -902,6 +907,7 @@ function getDevice(deviceId: string): DeviceInfo | null {
902
907
  // For direct connection mode, return a placeholder device info
903
908
  // This allows the connection process to proceed without prior discovery
904
909
  return {
910
+ commType: 'electron-ble',
905
911
  id: deviceId,
906
912
  name: 'UKey Device',
907
913
  state: 'disconnected',
@@ -1367,25 +1373,28 @@ async function unsubscribeNotifications(deviceId: string): Promise<void> {
1367
1373
  // 🔒 Set operation state to prevent race conditions
1368
1374
  subscriptionOperations.set(deviceId, 'unsubscribing');
1369
1375
 
1370
- return new Promise<void>(resolve => {
1371
- notifyCharacteristic.unsubscribe((error: Error | undefined) => {
1372
- if (error) {
1373
- logger?.error('[NobleBLE] Notification unsubscription failed:', error);
1374
- } else {
1375
- logger?.info('[NobleBLE] Notification unsubscription successful');
1376
- }
1377
-
1378
- // Remove all listeners and clear subscription status
1379
- notifyCharacteristic.removeAllListeners('data');
1380
- notificationCallbacks.delete(deviceId);
1381
- devicePacketStates.delete(deviceId);
1382
- subscribedDevices.delete(deviceId);
1383
-
1384
- // 🔒 Clear operation state
1385
- subscriptionOperations.set(deviceId, 'idle');
1386
- resolve();
1376
+ try {
1377
+ await new Promise<void>((resolve, reject) => {
1378
+ notifyCharacteristic.unsubscribe((error: Error | undefined) => {
1379
+ if (error) {
1380
+ logger?.error('[NobleBLE] Notification unsubscription failed:', error);
1381
+ reject(error);
1382
+ } else {
1383
+ logger?.info('[NobleBLE] Notification unsubscription successful');
1384
+ resolve();
1385
+ }
1386
+ });
1387
1387
  });
1388
- });
1388
+
1389
+ // Remove all listeners and clear subscription status
1390
+ notifyCharacteristic.removeAllListeners('data');
1391
+ notificationCallbacks.delete(deviceId);
1392
+ devicePacketStates.delete(deviceId);
1393
+ subscribedDevices.delete(deviceId);
1394
+ } finally {
1395
+ // 🔒 CRITICAL: Always clear operation state (even on error)
1396
+ subscriptionOperations.set(deviceId, 'idle');
1397
+ }
1389
1398
  }
1390
1399
 
1391
1400
  // Subscribe to notifications
@@ -1406,20 +1415,37 @@ async function subscribeNotifications(
1406
1415
  const { notify: notifyCharacteristic } = characteristics;
1407
1416
 
1408
1417
  logger?.info('[NobleBLE] Subscribing to notifications for device:', deviceId);
1418
+
1419
+ // 🔒 CRITICAL: Check operation state FIRST to prevent race conditions
1420
+ const opState = subscriptionOperations.get(deviceId);
1421
+
1409
1422
  logger?.info('[NobleBLE] Subscribe context', {
1410
1423
  deviceId,
1411
- opStateBefore: subscriptionOperations.get(deviceId) || 'idle',
1424
+ opStateBefore: opState || 'idle',
1412
1425
  paired: false,
1413
1426
  hasController: false,
1414
1427
  });
1428
+
1415
1429
  // If a subscription is already in progress, dedupe
1416
- const opState = subscriptionOperations.get(deviceId);
1417
1430
  if (opState === 'subscribing') {
1418
- // Subscription in progress; update callback and return
1431
+ logger?.info('[NobleBLE] Subscription already in progress, updating callback only');
1419
1432
  notificationCallbacks.set(deviceId, callback);
1420
1433
  return Promise.resolve();
1421
1434
  }
1422
1435
 
1436
+ // 🚨 CRITICAL: Reject subscribe if unsubscribe is in progress
1437
+ // Let upper layer handle retry after device reconnection
1438
+ if (opState === 'unsubscribing') {
1439
+ logger?.error('[NobleBLE] Cannot subscribe while unsubscribe is in progress', {
1440
+ deviceId,
1441
+ opState,
1442
+ });
1443
+ throw ERRORS.TypedError(
1444
+ HardwareErrorCode.DeviceBusy,
1445
+ `Device ${deviceId} is currently unsubscribing, please retry after reconnection`
1446
+ );
1447
+ }
1448
+
1423
1449
  // 🔒 Set operation state to prevent race conditions
1424
1450
  subscriptionOperations.set(deviceId, 'subscribing');
1425
1451
 
@@ -3,10 +3,11 @@
3
3
  * Supplements @types/noble with additional interfaces
4
4
  */
5
5
 
6
- import type { Peripheral, Characteristic } from '@stoprocent/noble';
6
+ import type { Characteristic, Peripheral } from '@stoprocent/noble';
7
+ import type { UKeyDeviceInfoBase } from '@ukeyfe/hardware-transport';
7
8
 
8
9
  // Device info interface for our API
9
- export interface DeviceInfo {
10
+ export interface DeviceInfo extends UKeyDeviceInfoBase {
10
11
  id: string;
11
12
  name: string;
12
13
  state: string;