@onekeyfe/hd-transport-web-device 1.1.34-alpha.1 → 1.1.34-alpha.2

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.
@@ -37,6 +37,7 @@ export default class ElectronBleTransport {
37
37
  path: string;
38
38
  }>;
39
39
  release(id: string): Promise<void>;
40
+ disconnect(id: string): Promise<void>;
40
41
  private handleNotificationData;
41
42
  call(uuid: string, name: string, data: Record<string, unknown>): Promise<import("@onekeyfe/hd-transport").MessageFromOneKey>;
42
43
  private processNotificationPacket;
@@ -1 +1 @@
1
- {"version":3,"file":"electron-ble-transport.d.ts","sourceRoot":"","sources":["../src/electron-ble-transport.ts"],"names":[],"mappings":";AAAA,OAAO,SAAkD,MAAM,wBAAwB,CAAC;AASxF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,YAAY,MAAM,QAAQ,CAAC;AAEvC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAKlE,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,UAAU,CAAC,EAAE,UAAU,CAAC;KACzB;CACF;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC,CAAC;AASF,MAAM,CAAC,OAAO,OAAO,oBAAoB;IACvC,SAAS,EAAE,UAAU,CAAC,OAAO,SAAS,CAAC,cAAc,CAAC,GAAG,SAAS,CAAC;IAEnE,IAAI,SAA0B;IAE9B,UAAU,UAAS;IAEnB,UAAU,EAAE,QAAQ,CAAC,GAAG,CAAC,GAAG,IAAI,CAAQ;IAExC,GAAG,CAAC,EAAE,GAAG,CAAC;IAEV,OAAO,CAAC,EAAE,YAAY,CAAC;IAGvB,OAAO,CAAC,gBAAgB,CAA0B;IAGlD,OAAO,CAAC,WAAW,CAAsE;IAGzF,OAAO,CAAC,oBAAoB,CAAsC;IAGlE,OAAO,CAAC,kBAAkB,CAAsC;IAGhE,OAAO,CAAC,oBAAoB;IAmC5B,OAAO,CAAC,kBAAkB;IAmB1B,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,YAAY;IAexC,SAAS,CAAC,UAAU,EAAE,GAAG;IAMzB,MAAM;IAEA,SAAS,IAAI,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAcpD,OAAO,CAAC,KAAK,EAAE,eAAe;;;;IA8E9B,OAAO,CAAC,EAAE,EAAE,MAAM;IAwBxB,OAAO,CAAC,sBAAsB;IA2BxB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IA2EpE,OAAO,CAAC,yBAAyB;CAyDlC"}
1
+ {"version":3,"file":"electron-ble-transport.d.ts","sourceRoot":"","sources":["../src/electron-ble-transport.ts"],"names":[],"mappings":";AAAA,OAAO,SAAkD,MAAM,wBAAwB,CAAC;AASxF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,YAAY,MAAM,QAAQ,CAAC;AAEvC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAKlE,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,UAAU,CAAC,EAAE,UAAU,CAAC;KACzB;CACF;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC,CAAC;AASF,MAAM,CAAC,OAAO,OAAO,oBAAoB;IACvC,SAAS,EAAE,UAAU,CAAC,OAAO,SAAS,CAAC,cAAc,CAAC,GAAG,SAAS,CAAC;IAEnE,IAAI,SAA0B;IAE9B,UAAU,UAAS;IAEnB,UAAU,EAAE,QAAQ,CAAC,GAAG,CAAC,GAAG,IAAI,CAAQ;IAExC,GAAG,CAAC,EAAE,GAAG,CAAC;IAEV,OAAO,CAAC,EAAE,YAAY,CAAC;IAGvB,OAAO,CAAC,gBAAgB,CAA0B;IAGlD,OAAO,CAAC,WAAW,CAAsE;IAGzF,OAAO,CAAC,oBAAoB,CAAsC;IAGlE,OAAO,CAAC,kBAAkB,CAAsC;IAGhE,OAAO,CAAC,oBAAoB;IAmC5B,OAAO,CAAC,kBAAkB;IAmB1B,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,YAAY;IAexC,SAAS,CAAC,UAAU,EAAE,GAAG;IAMzB,MAAM;IAEA,SAAS,IAAI,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAcpD,OAAO,CAAC,KAAK,EAAE,eAAe;;;;IA4F9B,OAAO,CAAC,EAAE,EAAE,MAAM;IAoBlB,UAAU,CAAC,EAAE,EAAE,MAAM;IAsB3B,OAAO,CAAC,sBAAsB;IA2BxB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IA2EpE,OAAO,CAAC,yBAAyB;CAyDlC"}
package/dist/index.d.ts CHANGED
@@ -75,6 +75,7 @@ declare class ElectronBleTransport {
75
75
  path: string;
76
76
  }>;
77
77
  release(id: string): Promise<void>;
78
+ disconnect(id: string): Promise<void>;
78
79
  private handleNotificationData;
79
80
  call(uuid: string, name: string, data: Record<string, unknown>): Promise<transport.MessageFromOneKey>;
80
81
  private processNotificationPacket;
package/dist/index.js CHANGED
@@ -461,6 +461,7 @@ class ElectronBleTransport {
461
461
  if (forceCleanRunPromise && this.runPromise) {
462
462
  this.runPromise.reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise));
463
463
  }
464
+ let step = 'getDevice';
464
465
  try {
465
466
  if (!((_a = window.desktopApi) === null || _a === void 0 ? void 0 : _a.nobleBle)) {
466
467
  throw new Error('Noble BLE API not available');
@@ -469,6 +470,7 @@ class ElectronBleTransport {
469
470
  if (!device) {
470
471
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceNotFound, `Device ${uuid} not found`);
471
472
  }
473
+ step = 'connect';
472
474
  try {
473
475
  yield window.desktopApi.nobleBle.connect(uuid);
474
476
  this.connectedDevices.add(uuid);
@@ -477,6 +479,7 @@ class ElectronBleTransport {
477
479
  this.handleBluetoothError(error);
478
480
  }
479
481
  this.dataBuffers.set(uuid, { buffer: [], bufferLength: 0 });
482
+ step = 'subscribe';
480
483
  yield window.desktopApi.nobleBle.subscribe(uuid);
481
484
  const cleanup = window.desktopApi.nobleBle.onNotification((deviceId, data) => {
482
485
  if (deviceId === uuid) {
@@ -487,6 +490,9 @@ class ElectronBleTransport {
487
490
  const disconnectCleanup = window.desktopApi.nobleBle.onDeviceDisconnected((disconnectedDevice) => {
488
491
  var _a;
489
492
  if (disconnectedDevice.id === uuid) {
493
+ if (this.runPromise) {
494
+ this.runPromise.reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected));
495
+ }
490
496
  this.cleanupDeviceState(uuid);
491
497
  (_a = this.emitter) === null || _a === void 0 ? void 0 : _a.emit('device-disconnect', {
492
498
  name: disconnectedDevice.name,
@@ -505,6 +511,9 @@ class ElectronBleTransport {
505
511
  }
506
512
  catch (error) {
507
513
  (_c = this.Log) === null || _c === void 0 ? void 0 : _c.error('[Transport] Noble BLE acquire failed:', error);
514
+ if (step === 'subscribe') {
515
+ yield this.disconnect(uuid);
516
+ }
508
517
  throw error;
509
518
  }
510
519
  });
@@ -512,23 +521,33 @@ class ElectronBleTransport {
512
521
  release(id) {
513
522
  var _a, _b, _c;
514
523
  return __awaiter(this, void 0, void 0, function* () {
524
+ this.cleanupDeviceState(id);
515
525
  try {
516
- if (this.connectedDevices.has(id)) {
517
- if ((_a = window.desktopApi) === null || _a === void 0 ? void 0 : _a.nobleBle) {
518
- yield window.desktopApi.nobleBle.unsubscribe(id);
519
- }
520
- if ((_b = window.desktopApi) === null || _b === void 0 ? void 0 : _b.nobleBle) {
521
- yield window.desktopApi.nobleBle.disconnect(id);
522
- }
523
- this.cleanupDeviceState(id);
524
- }
526
+ yield ((_c = (_b = (_a = window.desktopApi) === null || _a === void 0 ? void 0 : _a.nobleBle) === null || _b === void 0 ? void 0 : _b.release) === null || _c === void 0 ? void 0 : _c.call(_b, id));
525
527
  }
526
- catch (error) {
527
- (_c = this.Log) === null || _c === void 0 ? void 0 : _c.error('[Transport] Noble BLE release failed:', error);
528
- this.cleanupDeviceState(id);
528
+ catch (_d) {
529
529
  }
530
530
  });
531
531
  }
532
+ disconnect(id) {
533
+ return __awaiter(this, void 0, void 0, function* () {
534
+ const bounded = (ms, run) => __awaiter(this, void 0, void 0, function* () {
535
+ try {
536
+ yield Promise.race([
537
+ Promise.resolve(run()),
538
+ new Promise(resolve => {
539
+ setTimeout(resolve, ms);
540
+ }),
541
+ ]);
542
+ }
543
+ catch (_a) {
544
+ }
545
+ });
546
+ yield bounded(2000, () => { var _a, _b; return (_b = (_a = window.desktopApi) === null || _a === void 0 ? void 0 : _a.nobleBle) === null || _b === void 0 ? void 0 : _b.unsubscribe(id); });
547
+ yield bounded(3000, () => { var _a, _b; return (_b = (_a = window.desktopApi) === null || _a === void 0 ? void 0 : _a.nobleBle) === null || _b === void 0 ? void 0 : _b.disconnect(id); });
548
+ this.cleanupDeviceState(id);
549
+ });
550
+ }
532
551
  handleNotificationData(deviceId, hexData) {
533
552
  var _a, _b;
534
553
  if (hexData === 'PAIRING_REJECTED') {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onekeyfe/hd-transport-web-device",
3
- "version": "1.1.34-alpha.1",
3
+ "version": "1.1.34-alpha.2",
4
4
  "author": "OneKey",
5
5
  "homepage": "https://github.com/OneKeyHQ/hardware-js-sdk#readme",
6
6
  "license": "MIT",
@@ -20,13 +20,13 @@
20
20
  "lint:fix": "eslint . --fix"
21
21
  },
22
22
  "dependencies": {
23
- "@onekeyfe/hd-shared": "1.1.34-alpha.1",
24
- "@onekeyfe/hd-transport": "1.1.34-alpha.1"
23
+ "@onekeyfe/hd-shared": "1.1.34-alpha.2",
24
+ "@onekeyfe/hd-transport": "1.1.34-alpha.2"
25
25
  },
26
26
  "devDependencies": {
27
- "@onekeyfe/hd-transport-electron": "1.1.34-alpha.1",
27
+ "@onekeyfe/hd-transport-electron": "1.1.34-alpha.2",
28
28
  "@types/w3c-web-usb": "^1.0.6",
29
29
  "@types/web-bluetooth": "^0.0.17"
30
30
  },
31
- "gitHead": "e017f56235eae6eab82f1c687699a4204f3173f9"
31
+ "gitHead": "dee167c35d191f3f4e02c4cb6228e1f926f929ec"
32
32
  }
@@ -162,6 +162,9 @@ export default class ElectronBleTransport {
162
162
  this.runPromise.reject(ERRORS.TypedError(HardwareErrorCode.BleForceCleanRunPromise));
163
163
  }
164
164
 
165
+ // `step` pins down where a failed acquire died (subscribe = the
166
+ // encryption-gated characteristic, the broken-OS-bond signature).
167
+ let step = 'getDevice';
165
168
  try {
166
169
  if (!window.desktopApi?.nobleBle) {
167
170
  throw new Error('Noble BLE API not available');
@@ -174,6 +177,7 @@ export default class ElectronBleTransport {
174
177
  }
175
178
 
176
179
  // Connect to device
180
+ step = 'connect';
177
181
  try {
178
182
  await window.desktopApi.nobleBle.connect(uuid);
179
183
  this.connectedDevices.add(uuid);
@@ -185,6 +189,7 @@ export default class ElectronBleTransport {
185
189
  this.dataBuffers.set(uuid, { buffer: [], bufferLength: 0 });
186
190
 
187
191
  // Subscribe to notifications
192
+ step = 'subscribe';
188
193
  await window.desktopApi.nobleBle.subscribe(uuid);
189
194
 
190
195
  // Set up notification listener
@@ -201,6 +206,10 @@ export default class ElectronBleTransport {
201
206
  const disconnectCleanup = window.desktopApi.nobleBle.onDeviceDisconnected(
202
207
  (disconnectedDevice: any) => {
203
208
  if (disconnectedDevice.id === uuid) {
209
+ // Fail a call blocked on a dead link instead of hanging.
210
+ if (this.runPromise) {
211
+ this.runPromise.reject(ERRORS.TypedError(HardwareErrorCode.BleDeviceDisconnected));
212
+ }
204
213
  this.cleanupDeviceState(uuid);
205
214
 
206
215
  // Trigger disconnect event
@@ -224,31 +233,54 @@ export default class ElectronBleTransport {
224
233
  return { uuid, path: uuid };
225
234
  } catch (error) {
226
235
  this.Log?.error('[Transport] Noble BLE acquire failed:', error);
236
+ if (step === 'subscribe') {
237
+ // Broken-bond signature: tear the link down so the next attempt
238
+ // cold-connects and macOS can re-negotiate the bond.
239
+ await this.disconnect(uuid);
240
+ }
227
241
  throw error;
228
242
  }
229
243
  }
230
244
 
231
245
  async release(id: string) {
246
+ // Logical release only — the link and subscription stay up for reuse; the
247
+ // main process idle timer does the physical disconnect. Hard teardown is
248
+ // `disconnect()`. Renderer listeners must still go, or the next acquire's
249
+ // fresh listeners would double-process every packet.
250
+ this.cleanupDeviceState(id);
251
+ // Signal logical end-of-operation so the main process starts its 60s idle
252
+ // countdown (during a run it holds the long busy backstop instead). Best-
253
+ // effort: the idle/backstop timer still bounds the link if this never lands.
232
254
  try {
233
- if (this.connectedDevices.has(id)) {
234
- // Unsubscribe from notifications
235
- if (window.desktopApi?.nobleBle) {
236
- await window.desktopApi.nobleBle.unsubscribe(id);
237
- }
238
-
239
- // Disconnect device
240
- if (window.desktopApi?.nobleBle) {
241
- await window.desktopApi.nobleBle.disconnect(id);
242
- }
255
+ await window.desktopApi?.nobleBle?.release?.(id);
256
+ } catch {
257
+ // ignore — timers in the main process still bound the link
258
+ }
259
+ }
243
260
 
244
- // Clean up all device state
245
- this.cleanupDeviceState(id);
261
+ /**
262
+ * Hard teardown for the SDK's error-recovery path (DeviceConnector
263
+ * .disconnect); normal release() deliberately does not come here.
264
+ */
265
+ async disconnect(id: string) {
266
+ // Independent best-effort steps, each time-boxed: on a wedged link the
267
+ // underlying noble callbacks can simply never fire, and this is the
268
+ // error-RECOVERY path — it must never hang the retry ladder.
269
+ const bounded = async (ms: number, run: () => Promise<unknown> | undefined) => {
270
+ try {
271
+ await Promise.race([
272
+ Promise.resolve(run()),
273
+ new Promise<void>(resolve => {
274
+ setTimeout(resolve, ms);
275
+ }),
276
+ ]);
277
+ } catch {
278
+ // ignore — recovery path, best effort
246
279
  }
247
- } catch (error) {
248
- this.Log?.error('[Transport] Noble BLE release failed:', error);
249
- // Clean up local state even if release fails
250
- this.cleanupDeviceState(id);
251
- }
280
+ };
281
+ await bounded(2000, () => window.desktopApi?.nobleBle?.unsubscribe(id));
282
+ await bounded(3000, () => window.desktopApi?.nobleBle?.disconnect(id));
283
+ this.cleanupDeviceState(id);
252
284
  }
253
285
 
254
286
  // Handle notification data from Noble BLE