@onekeyfe/hd-transport-react-native 1.2.3-alpha.9 → 1.2.4-alpha.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.
package/dist/index.js CHANGED
@@ -47,10 +47,10 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
47
47
  };
48
48
 
49
49
  const lastKeyMissingAt = new Map();
50
- const listeners = new Set();
51
- let unsubscribeNative;
52
- const normalizeDeviceId = (deviceId) => deviceId.toLowerCase();
53
- const getCapableBleUtils = () => {
50
+ const listeners$1 = new Set();
51
+ let unsubscribeNative$1;
52
+ const normalizeDeviceId$1 = (deviceId) => deviceId.toLowerCase();
53
+ const getCapableBleUtils$1 = () => {
54
54
  if (reactNative.Platform.OS !== 'android')
55
55
  return undefined;
56
56
  const bleUtils = BleUtils__default["default"];
@@ -60,41 +60,41 @@ const getCapableBleUtils = () => {
60
60
  }
61
61
  return bleUtils.supportsDeviceKeyMissing() ? bleUtils : undefined;
62
62
  };
63
- const isBleKeyMissingSupported = () => getCapableBleUtils() !== undefined;
63
+ const isBleKeyMissingSupported = () => getCapableBleUtils$1() !== undefined;
64
64
  const startBleKeyMissingTracking = () => {
65
- if (unsubscribeNative)
65
+ if (unsubscribeNative$1)
66
66
  return true;
67
- const bleUtils = getCapableBleUtils();
67
+ const bleUtils = getCapableBleUtils$1();
68
68
  if (!(bleUtils === null || bleUtils === void 0 ? void 0 : bleUtils.onDeviceKeyMissing))
69
69
  return false;
70
- unsubscribeNative = bleUtils.onDeviceKeyMissing(event => {
70
+ unsubscribeNative$1 = bleUtils.onDeviceKeyMissing(event => {
71
71
  if (typeof (event === null || event === void 0 ? void 0 : event.id) !== 'string')
72
72
  return;
73
- const deviceId = normalizeDeviceId(event.id);
73
+ const deviceId = normalizeDeviceId$1(event.id);
74
74
  lastKeyMissingAt.set(deviceId, Date.now());
75
- listeners.forEach(listener => listener(deviceId));
75
+ listeners$1.forEach(listener => listener(deviceId));
76
76
  });
77
77
  return true;
78
78
  };
79
79
  const stopBleKeyMissingTracking = () => {
80
- unsubscribeNative === null || unsubscribeNative === void 0 ? void 0 : unsubscribeNative();
81
- unsubscribeNative = undefined;
80
+ unsubscribeNative$1 === null || unsubscribeNative$1 === void 0 ? void 0 : unsubscribeNative$1();
81
+ unsubscribeNative$1 = undefined;
82
82
  lastKeyMissingAt.clear();
83
- listeners.clear();
83
+ listeners$1.clear();
84
84
  };
85
85
  const hasBleKeyMissingSince = (deviceId, sinceMs) => {
86
- const at = lastKeyMissingAt.get(normalizeDeviceId(deviceId));
86
+ const at = lastKeyMissingAt.get(normalizeDeviceId$1(deviceId));
87
87
  return at !== undefined && at >= sinceMs;
88
88
  };
89
89
  const onBleKeyMissing = (deviceId, callback) => {
90
- const target = normalizeDeviceId(deviceId);
90
+ const target = normalizeDeviceId$1(deviceId);
91
91
  const listener = id => {
92
92
  if (id === target)
93
93
  callback();
94
94
  };
95
- listeners.add(listener);
95
+ listeners$1.add(listener);
96
96
  return () => {
97
- listeners.delete(listener);
97
+ listeners$1.delete(listener);
98
98
  };
99
99
  };
100
100
  const waitForBleKeyMissing = (deviceId, sinceMs, timeoutMs) => {
@@ -328,6 +328,172 @@ const subscribeBleOn = (bleManager, ms = 1000) => new Promise((resolve, reject)
328
328
  }, ms);
329
329
  });
330
330
 
331
+ const HCI_PIN_OR_KEY_MISSING = 0x06;
332
+ const lastEncryption = new Map();
333
+ const lastAclDisconnectAt = new Map();
334
+ const listeners = new Set();
335
+ let unsubscribeNative;
336
+ const normalizeDeviceId = (deviceId) => deviceId.toLowerCase();
337
+ const isEncrypted = (record) => record.status === 0 && record.enabled;
338
+ const getCapableBleUtils = () => {
339
+ if (reactNative.Platform.OS !== 'android')
340
+ return undefined;
341
+ const bleUtils = BleUtils__default["default"];
342
+ if (typeof bleUtils.supportsDeviceEncryptionChange !== 'function' ||
343
+ typeof bleUtils.onDeviceEncryptionChange !== 'function' ||
344
+ typeof bleUtils.onDeviceAclDisconnected !== 'function') {
345
+ return undefined;
346
+ }
347
+ return bleUtils.supportsDeviceEncryptionChange() ? bleUtils : undefined;
348
+ };
349
+ const notify = (deviceId) => {
350
+ listeners.forEach(listener => listener(deviceId));
351
+ };
352
+ const startBleEncryptionTracking = () => {
353
+ if (unsubscribeNative)
354
+ return true;
355
+ const bleUtils = getCapableBleUtils();
356
+ if (!(bleUtils === null || bleUtils === void 0 ? void 0 : bleUtils.onDeviceEncryptionChange) || !bleUtils.onDeviceAclDisconnected)
357
+ return false;
358
+ unsubscribeNative = [
359
+ bleUtils.onDeviceEncryptionChange(event => {
360
+ if (typeof (event === null || event === void 0 ? void 0 : event.id) !== 'string')
361
+ return;
362
+ const deviceId = normalizeDeviceId(event.id);
363
+ lastEncryption.set(deviceId, {
364
+ at: Date.now(),
365
+ status: Number(event.status),
366
+ enabled: event.enabled === true,
367
+ });
368
+ notify(deviceId);
369
+ }),
370
+ bleUtils.onDeviceAclDisconnected(event => {
371
+ if (typeof (event === null || event === void 0 ? void 0 : event.id) !== 'string')
372
+ return;
373
+ const deviceId = normalizeDeviceId(event.id);
374
+ lastAclDisconnectAt.set(deviceId, Date.now());
375
+ notify(deviceId);
376
+ }),
377
+ ];
378
+ return true;
379
+ };
380
+ const stopBleEncryptionTracking = () => {
381
+ unsubscribeNative === null || unsubscribeNative === void 0 ? void 0 : unsubscribeNative.forEach(unsubscribe => unsubscribe());
382
+ unsubscribeNative = undefined;
383
+ lastEncryption.clear();
384
+ lastAclDisconnectAt.clear();
385
+ listeners.clear();
386
+ };
387
+ const markBleLinkEncrypted = (deviceId) => {
388
+ if (!unsubscribeNative)
389
+ return;
390
+ lastEncryption.set(normalizeDeviceId(deviceId), { at: Date.now(), status: 0, enabled: true });
391
+ };
392
+ const waitForAndroidLinkEncryption = ({ deviceId, linkStartedAt, resultTimeoutMs, repairTimeoutMs, keyMissingGraceMs, signal, onRepairStarted, }) => {
393
+ if (!startBleEncryptionTracking())
394
+ return Promise.resolve('unresolved');
395
+ startBleKeyMissingTracking();
396
+ const target = normalizeDeviceId(deviceId);
397
+ const previous = lastEncryption.get(target);
398
+ const previousDropAt = lastAclDisconnectAt.get(target);
399
+ if (previous &&
400
+ previous.at < linkStartedAt &&
401
+ isEncrypted(previous) &&
402
+ (previousDropAt === undefined || previousDropAt < previous.at)) {
403
+ return Promise.resolve('already-encrypted');
404
+ }
405
+ return new Promise((resolve, reject) => {
406
+ if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
407
+ reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected));
408
+ return;
409
+ }
410
+ let repairStartedAt;
411
+ let droppedDuringRepair = false;
412
+ let timer;
413
+ let settled = false;
414
+ const cleanup = () => {
415
+ settled = true;
416
+ if (timer)
417
+ clearTimeout(timer);
418
+ listeners.delete(onLinkEvent);
419
+ cleanupKeyMissing();
420
+ signal === null || signal === void 0 ? void 0 : signal.removeEventListener('abort', onAbort);
421
+ };
422
+ const finish = (result) => {
423
+ cleanup();
424
+ resolve(result);
425
+ };
426
+ const fail = (error) => {
427
+ cleanup();
428
+ reject(error);
429
+ };
430
+ const arm = (ms, onExpire) => {
431
+ if (timer)
432
+ clearTimeout(timer);
433
+ timer = setTimeout(onExpire, ms);
434
+ };
435
+ const bondInvalid = () => hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleBondInvalid, undefined, {
436
+ phase: 'connect',
437
+ reason: 'key_missing',
438
+ });
439
+ const evaluate = () => {
440
+ if (settled)
441
+ return;
442
+ const record = lastEncryption.get(target);
443
+ const dropAt = lastAclDisconnectAt.get(target);
444
+ if (repairStartedAt === undefined) {
445
+ if (hasBleKeyMissingSince(target, linkStartedAt)) {
446
+ fail(bondInvalid());
447
+ return;
448
+ }
449
+ if (dropAt !== undefined && dropAt >= linkStartedAt) {
450
+ finish('unresolved');
451
+ return;
452
+ }
453
+ if (!record || record.at < linkStartedAt)
454
+ return;
455
+ if (isEncrypted(record)) {
456
+ finish('encrypted');
457
+ return;
458
+ }
459
+ if (record.status !== HCI_PIN_OR_KEY_MISSING) {
460
+ finish('unresolved');
461
+ return;
462
+ }
463
+ repairStartedAt = record.at;
464
+ onRepairStarted === null || onRepairStarted === void 0 ? void 0 : onRepairStarted();
465
+ arm(repairTimeoutMs, () => fail(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceNotBonded, 'Bluetooth pairing timed out', {
466
+ phase: 'bond',
467
+ reason: 'timeout',
468
+ })));
469
+ return;
470
+ }
471
+ if (hasBleKeyMissingSince(target, repairStartedAt)) {
472
+ fail(bondInvalid());
473
+ return;
474
+ }
475
+ if (record && record.at > repairStartedAt && isEncrypted(record)) {
476
+ finish('re-paired');
477
+ return;
478
+ }
479
+ if (!droppedDuringRepair && dropAt !== undefined && dropAt >= repairStartedAt) {
480
+ droppedDuringRepair = true;
481
+ arm(keyMissingGraceMs, () => fail(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected)));
482
+ }
483
+ };
484
+ const onLinkEvent = id => {
485
+ if (id === target)
486
+ evaluate();
487
+ };
488
+ const onAbort = () => fail(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected));
489
+ listeners.add(onLinkEvent);
490
+ const cleanupKeyMissing = onBleKeyMissing(target, evaluate);
491
+ signal === null || signal === void 0 ? void 0 : signal.addEventListener('abort', onAbort, { once: true });
492
+ arm(resultTimeoutMs, () => finish('unresolved'));
493
+ evaluate();
494
+ });
495
+ };
496
+
331
497
  const BLE_PLX_DEVICE_DISCONNECTED = 201;
332
498
  const IOS_PERIPHERAL_DISCONNECTED = 7;
333
499
  const nativeErrorText$1 = (error) => [error.reason, error.message]
@@ -485,6 +651,8 @@ const shouldRethrowProtocolProbeError = (error) => {
485
651
  };
486
652
  const ANDROID_KEY_MISSING_LINK_WINDOW_MS = 10000;
487
653
  const ANDROID_KEY_MISSING_GRACE_MS = 500;
654
+ const ANDROID_ENCRYPTION_RESULT_TIMEOUT_MS = 1500;
655
+ const ANDROID_SYSTEM_REPAIR_TIMEOUT_MS = 35000;
488
656
  const isAndroidLinkLossError = (error) => {
489
657
  const code = error === null || error === void 0 ? void 0 : error.errorCode;
490
658
  return (isNativeBleDisconnectError(error) ||
@@ -493,6 +661,33 @@ const isAndroidLinkLossError = (error) => {
493
661
  code === hdShared.HardwareErrorCode.BleCharacteristicNotifyError ||
494
662
  code === hdShared.HardwareErrorCode.BleConnectedError);
495
663
  };
664
+ const logIosBleBondDiagnostic = (phase, error, outcome) => {
665
+ if (reactNative.Platform.OS !== 'ios')
666
+ return;
667
+ const nativeError = (error !== null && error !== void 0 ? error : {});
668
+ const scalar = (value) => typeof value === 'string' || typeof value === 'number' ? value : undefined;
669
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport][BleBondDiagnostic] probe error', {
670
+ phase,
671
+ outcome,
672
+ errorName: scalar(nativeError.name),
673
+ errorCode: scalar(nativeError.errorCode),
674
+ attErrorCode: scalar(nativeError.attErrorCode),
675
+ iosErrorCode: scalar(nativeError.iosErrorCode),
676
+ androidErrorCode: scalar(nativeError.androidErrorCode),
677
+ nativeStaleBond: isNativeBleStaleBondError(error),
678
+ hardwareStaleBond: hdShared.isBleStaleBondHardwareError(error),
679
+ nativeDisconnect: isNativeBleDisconnectError(error),
680
+ });
681
+ };
682
+ const IOS_PROBE_DISCONNECT_EVIDENCE_TTL_MS = 5 * 60000;
683
+ const isIosProbeDisconnectError = (error) => {
684
+ if (reactNative.Platform.OS !== 'ios')
685
+ return false;
686
+ const code = error === null || error === void 0 ? void 0 : error.errorCode;
687
+ return (isNativeBleDisconnectError(error) ||
688
+ code === hdShared.HardwareErrorCode.BleDeviceNotBonded ||
689
+ code === hdShared.HardwareErrorCode.BleDeviceDisconnected);
690
+ };
496
691
  const BLE_WRITE_TIMEOUT_MANAGER_RESET_THRESHOLD = 2;
497
692
  const DEVICE_SCAN_TIMEOUT_MS = 3000;
498
693
  const IOS_NOTIFY_READY_DELAY_MS = 150;
@@ -688,6 +883,7 @@ class ReactNativeBleTransport {
688
883
  this.confirmedProtocolV2 = new Set();
689
884
  this.protocolReprobeFailures = new Map();
690
885
  this.silentDetections = new Map();
886
+ this.iosProbeDisconnectEvidence = new Map();
691
887
  this.androidGattCacheRefreshes = new Set();
692
888
  this.staleBondErrors = new Map();
693
889
  this.androidLinkStartedAt = new Map();
@@ -738,6 +934,10 @@ class ReactNativeBleTransport {
738
934
  init(logger, emitter) {
739
935
  setBleLogger(logger);
740
936
  this.emitter = emitter;
937
+ if (reactNative.Platform.OS === 'android') {
938
+ startBleKeyMissingTracking();
939
+ startBleEncryptionTracking();
940
+ }
741
941
  }
742
942
  configure(signedData) {
743
943
  const messages = parseConfigure(signedData);
@@ -1186,6 +1386,7 @@ class ReactNativeBleTransport {
1186
1386
  }
1187
1387
  let device = null;
1188
1388
  const isAndroid = reactNative.Platform.OS === 'android';
1389
+ let androidBondedBeforeConnect = false;
1189
1390
  const refreshAndroidGattCache = isAndroid && (!!skipProtocolProbe || this.androidGattCacheRefreshes.has(uuid));
1190
1391
  let nativeConnectOptions = connectOptions;
1191
1392
  if (isAndroid) {
@@ -1214,9 +1415,11 @@ class ReactNativeBleTransport {
1214
1415
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
1215
1416
  if (reactNative.Platform.OS === 'android') {
1216
1417
  startBleKeyMissingTracking();
1418
+ startBleEncryptionTracking();
1217
1419
  this.androidLinkStartedAt.delete(uuid);
1218
1420
  try {
1219
1421
  const bondState = yield pairDevice(uuid);
1422
+ androidBondedBeforeConnect = !bondState.bonding && bondState.bonded;
1220
1423
  if (bondState.bonding) {
1221
1424
  yield onDeviceBondState(uuid, this.bondAbortController.signal, {
1222
1425
  systemInitiated: bondState.initiated === false,
@@ -1390,7 +1593,13 @@ class ReactNativeBleTransport {
1390
1593
  if (shouldMapProtocolV2StaleBond) {
1391
1594
  this.acquiringProtocolV2.add(uuid);
1392
1595
  }
1596
+ let linkEncryption;
1393
1597
  try {
1598
+ if (androidBondedBeforeConnect && !skipProtocolProbe) {
1599
+ linkEncryption = yield this.waitForAndroidLinkSecurity(uuid);
1600
+ if (this.stopped)
1601
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
1602
+ }
1394
1603
  yield this.installTransportForAcquire(uuid, acquiredDevice, {
1395
1604
  writeCharacteristic,
1396
1605
  notifyCharacteristic,
@@ -1429,6 +1638,9 @@ class ReactNativeBleTransport {
1429
1638
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotFound);
1430
1639
  }
1431
1640
  this.attachDisconnectSubscription(currentTransport, currentTransport.device, uuid);
1641
+ if (linkEncryption === 'unresolved') {
1642
+ markBleLinkEncrypted(uuid);
1643
+ }
1432
1644
  return { uuid, protocolType };
1433
1645
  }
1434
1646
  catch (error) {
@@ -1665,6 +1877,31 @@ class ReactNativeBleTransport {
1665
1877
  });
1666
1878
  });
1667
1879
  }
1880
+ waitForAndroidLinkSecurity(uuid) {
1881
+ return __awaiter(this, void 0, void 0, function* () {
1882
+ const linkStartedAt = this.androidLinkStartedAt.get(uuid);
1883
+ if (linkStartedAt === undefined)
1884
+ return 'unresolved';
1885
+ const waitStartedAt = Date.now();
1886
+ const result = yield waitForAndroidLinkEncryption({
1887
+ deviceId: uuid,
1888
+ linkStartedAt,
1889
+ resultTimeoutMs: ANDROID_ENCRYPTION_RESULT_TIMEOUT_MS,
1890
+ repairTimeoutMs: ANDROID_SYSTEM_REPAIR_TIMEOUT_MS,
1891
+ keyMissingGraceMs: ANDROID_KEY_MISSING_GRACE_MS,
1892
+ signal: this.bondAbortController.signal,
1893
+ onRepairStarted: () => {
1894
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Android bond lost, waiting for system re-pairing:', uuid);
1895
+ },
1896
+ });
1897
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Android link encryption', {
1898
+ connectIdSuffix: uuid.slice(-8),
1899
+ result,
1900
+ waitedMs: Date.now() - waitStartedAt,
1901
+ });
1902
+ return result;
1903
+ });
1904
+ }
1668
1905
  callProtocolV1(uuid, name, data, options) {
1669
1906
  return __awaiter(this, void 0, void 0, function* () {
1670
1907
  if (!this._messages) {
@@ -1880,6 +2117,8 @@ class ReactNativeBleTransport {
1880
2117
  this.androidHighPriorityDevices.clear();
1881
2118
  this.androidLinkStartedAt.clear();
1882
2119
  stopBleKeyMissingTracking();
2120
+ stopBleEncryptionTracking();
2121
+ this.iosProbeDisconnectEvidence.clear();
1883
2122
  const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
1884
2123
  (_a = this.runPromise) === null || _a === void 0 ? void 0 : _a.reject(error);
1885
2124
  this.runPromise = null;
@@ -2365,6 +2604,50 @@ class ReactNativeBleTransport {
2365
2604
  createProtocolDetectionError() {
2366
2605
  return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleTimeoutError, 'Unable to detect BLE protocol: device did not respond to Protocol V1 GetFeatures or Protocol V2 Ping');
2367
2606
  }
2607
+ rememberIosProbeDisconnect(uuid, phase, error) {
2608
+ if (!isIosProbeDisconnectError(error))
2609
+ return undefined;
2610
+ const previous = this.getIosProbeDisconnectEvidence(uuid);
2611
+ const errorCode = error === null || error === void 0 ? void 0 : error.errorCode;
2612
+ const evidence = Object.assign(Object.assign({ phase }, (typeof errorCode === 'string' || typeof errorCode === 'number' ? { errorCode } : {})), { recordedAt: Date.now() });
2613
+ this.iosProbeDisconnectEvidence.set(uuid, evidence);
2614
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport][BleBondDiagnostic] probe disconnect recorded', {
2615
+ phase,
2616
+ errorCode: evidence.errorCode,
2617
+ repeated: Boolean(previous),
2618
+ });
2619
+ if (!previous)
2620
+ return undefined;
2621
+ return this.confirmIosProbeDisconnect(uuid, 'repeated-probe-disconnect');
2622
+ }
2623
+ getIosProbeDisconnectEvidence(uuid) {
2624
+ const evidence = this.iosProbeDisconnectEvidence.get(uuid);
2625
+ if (!evidence)
2626
+ return undefined;
2627
+ const ageMs = Date.now() - evidence.recordedAt;
2628
+ if (ageMs <= IOS_PROBE_DISCONNECT_EVIDENCE_TTL_MS)
2629
+ return evidence;
2630
+ this.iosProbeDisconnectEvidence.delete(uuid);
2631
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport][BleBondDiagnostic] probe disconnect expired', {
2632
+ triggerPhase: evidence.phase,
2633
+ triggerErrorCode: evidence.errorCode,
2634
+ ageMs,
2635
+ });
2636
+ return undefined;
2637
+ }
2638
+ confirmIosProbeDisconnect(uuid, confirmation) {
2639
+ const evidence = this.getIosProbeDisconnectEvidence(uuid);
2640
+ if (!evidence)
2641
+ return undefined;
2642
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport][BleBondDiagnostic] stale bond confirmed', {
2643
+ confirmation,
2644
+ triggerPhase: evidence.phase,
2645
+ triggerErrorCode: evidence.errorCode,
2646
+ evidenceAgeMs: Date.now() - evidence.recordedAt,
2647
+ finalErrorCode: hdShared.HardwareErrorCode.BleBondInvalid,
2648
+ });
2649
+ return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleBondInvalid);
2650
+ }
2368
2651
  clearProbeProtocol(uuid, protocol) {
2369
2652
  if (this.probingProtocols.get(uuid) === protocol) {
2370
2653
  this.probingProtocols.delete(uuid);
@@ -2378,9 +2661,10 @@ class ReactNativeBleTransport {
2378
2661
  return (_a = this.deviceProtocol.get(uuid)) !== null && _a !== void 0 ? _a : this.probingProtocols.get(uuid);
2379
2662
  }
2380
2663
  detectProtocol(uuid, expectedProtocol, protocolHint, rebuildTransport) {
2381
- var _a;
2664
+ var _a, _b;
2382
2665
  return __awaiter(this, void 0, void 0, function* () {
2383
2666
  if (expectedProtocol === 'V1') {
2667
+ this.iosProbeDisconnectEvidence.delete(uuid);
2384
2668
  this.deviceProtocol.set(uuid, 'V1');
2385
2669
  Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] protocol selected', {
2386
2670
  deviceId: uuid,
@@ -2394,6 +2678,7 @@ class ReactNativeBleTransport {
2394
2678
  }
2395
2679
  if (expectedProtocol === 'V2') {
2396
2680
  if (yield this.probeProtocolV2(uuid)) {
2681
+ this.iosProbeDisconnectEvidence.delete(uuid);
2397
2682
  this.deviceProtocol.set(uuid, 'V2');
2398
2683
  this.sessionProtocols.set(uuid, 'V2');
2399
2684
  this.confirmedProtocolV2.add(uuid);
@@ -2404,6 +2689,19 @@ class ReactNativeBleTransport {
2404
2689
  });
2405
2690
  return 'V2';
2406
2691
  }
2692
+ const staleBondError = this.confirmIosProbeDisconnect(uuid, 'follow-up-no-response');
2693
+ if (reactNative.Platform.OS === 'ios') {
2694
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport][BleBondDiagnostic] protocol detection ended', {
2695
+ outcome: 'expected-v2-no-response',
2696
+ expectedProtocol,
2697
+ protocolHint: protocolHint !== null && protocolHint !== void 0 ? protocolHint : 'none',
2698
+ finalErrorCode: staleBondError
2699
+ ? hdShared.HardwareErrorCode.BleBondInvalid
2700
+ : hdShared.HardwareErrorCode.RuntimeError,
2701
+ });
2702
+ }
2703
+ if (staleBondError)
2704
+ throw staleBondError;
2407
2705
  throw this.createProtocolMismatchError(expectedProtocol);
2408
2706
  }
2409
2707
  const sessionProtocol = this.sessionProtocols.get(uuid);
@@ -2427,6 +2725,7 @@ class ReactNativeBleTransport {
2427
2725
  }
2428
2726
  const detected = protocol === 'V1' ? yield this.probeProtocolV1(uuid) : yield this.probeProtocolV2(uuid);
2429
2727
  if (detected) {
2728
+ this.iosProbeDisconnectEvidence.delete(uuid);
2430
2729
  this.deviceProtocol.set(uuid, protocol);
2431
2730
  this.sessionProtocols.set(uuid, protocol);
2432
2731
  if (protocol === 'V2') {
@@ -2452,6 +2751,26 @@ class ReactNativeBleTransport {
2452
2751
  }
2453
2752
  this.deviceProtocol.delete(uuid);
2454
2753
  this.probingProtocols.delete(uuid);
2754
+ const staleBondError = this.confirmIosProbeDisconnect(uuid, 'follow-up-no-response');
2755
+ if (reactNative.Platform.OS === 'ios') {
2756
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport][BleBondDiagnostic] protocol detection ended', {
2757
+ outcome: 'all-probes-no-response',
2758
+ expectedProtocol: expectedProtocol !== null && expectedProtocol !== void 0 ? expectedProtocol : 'none',
2759
+ protocolHint: protocolHint !== null && protocolHint !== void 0 ? protocolHint : 'none',
2760
+ sessionProtocol: sessionProtocol !== null && sessionProtocol !== void 0 ? sessionProtocol : 'none',
2761
+ probeOrder: probeOrder.join(','),
2762
+ trustSessionProtocol,
2763
+ reprobeFailures,
2764
+ transportCached: Boolean(transportCache[uuid]),
2765
+ notifyActive: Boolean((_b = transportCache[uuid]) === null || _b === void 0 ? void 0 : _b.notifySubscription),
2766
+ staleBondRecorded: this.iosProbeDisconnectEvidence.has(uuid),
2767
+ finalErrorCode: staleBondError
2768
+ ? hdShared.HardwareErrorCode.BleBondInvalid
2769
+ : hdShared.HardwareErrorCode.BleTimeoutError,
2770
+ });
2771
+ }
2772
+ if (staleBondError)
2773
+ throw staleBondError;
2455
2774
  throw this.createProtocolDetectionError();
2456
2775
  });
2457
2776
  }
@@ -2535,7 +2854,12 @@ class ReactNativeBleTransport {
2535
2854
  catch (error) {
2536
2855
  this.clearProbeProtocol(uuid, 'V1');
2537
2856
  Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V1 GetFeatures probe failed:', error);
2538
- if (shouldRethrowProtocolProbeError(error)) {
2857
+ const shouldRethrow = shouldRethrowProtocolProbeError(error);
2858
+ const staleBondError = this.rememberIosProbeDisconnect(uuid, 'protocol-v1-get-features', error);
2859
+ logIosBleBondDiagnostic('protocol-v1-get-features', error, shouldRethrow ? 'rethrow' : 'fallback');
2860
+ if (staleBondError)
2861
+ throw staleBondError;
2862
+ if (shouldRethrow) {
2539
2863
  throw error;
2540
2864
  }
2541
2865
  return false;
@@ -2551,18 +2875,28 @@ class ReactNativeBleTransport {
2551
2875
  this.probingProtocols.set(uuid, 'V2');
2552
2876
  (_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
2553
2877
  this.throwIfStaleBondError(uuid);
2554
- const detected = yield transport.probeProtocolV2({
2555
- call: (name, data, options) => this.callProtocolV2(uuid, name, data, options),
2556
- timeoutMs: PROTOCOL_V2_PROBE_TIMEOUT_MS,
2557
- logger: Log,
2558
- logPrefix: 'ProtocolV2 RN-BLE',
2559
- onProbeFailed: () => {
2560
- var _a;
2561
- (_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
2562
- this.resetProtocolV2Frames(uuid);
2563
- },
2564
- shouldRethrow: shouldRethrowProtocolProbeError,
2565
- });
2878
+ let detected;
2879
+ try {
2880
+ detected = yield transport.probeProtocolV2({
2881
+ call: (name, data, options) => this.callProtocolV2(uuid, name, data, options),
2882
+ timeoutMs: PROTOCOL_V2_PROBE_TIMEOUT_MS,
2883
+ logger: Log,
2884
+ logPrefix: 'ProtocolV2 RN-BLE',
2885
+ onProbeFailed: () => {
2886
+ var _a;
2887
+ (_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
2888
+ this.resetProtocolV2Frames(uuid);
2889
+ },
2890
+ shouldRethrow: shouldRethrowProtocolProbeError,
2891
+ });
2892
+ }
2893
+ catch (error) {
2894
+ const staleBondError = this.rememberIosProbeDisconnect(uuid, 'protocol-v2-ping', error);
2895
+ logIosBleBondDiagnostic('protocol-v2-ping', error, 'rethrow');
2896
+ if (staleBondError)
2897
+ throw staleBondError;
2898
+ throw error;
2899
+ }
2566
2900
  if (!detected) {
2567
2901
  this.clearProbeProtocol(uuid, 'V2');
2568
2902
  }
@@ -2913,10 +3247,12 @@ class ReactNativeBleTransport {
2913
3247
  }
2914
3248
  }
2915
3249
 
3250
+ exports.ANDROID_ENCRYPTION_RESULT_TIMEOUT_MS = ANDROID_ENCRYPTION_RESULT_TIMEOUT_MS;
2916
3251
  exports.ANDROID_KEY_MISSING_GRACE_MS = ANDROID_KEY_MISSING_GRACE_MS;
2917
3252
  exports.ANDROID_KEY_MISSING_LINK_WINDOW_MS = ANDROID_KEY_MISSING_LINK_WINDOW_MS;
2918
3253
  exports.ANDROID_LINK_DROP_QUIET_MS = ANDROID_LINK_DROP_QUIET_MS;
2919
3254
  exports.ANDROID_MTU_EXCHANGE_TIMEOUT_MS = ANDROID_MTU_EXCHANGE_TIMEOUT_MS;
3255
+ exports.ANDROID_SYSTEM_REPAIR_TIMEOUT_MS = ANDROID_SYSTEM_REPAIR_TIMEOUT_MS;
2920
3256
  exports.BLE_CONNECT_TIMEOUT_MANAGER_RESET_THRESHOLD = BLE_CONNECT_TIMEOUT_MANAGER_RESET_THRESHOLD;
2921
3257
  exports.BLE_CONNECT_TIMEOUT_MS = BLE_CONNECT_TIMEOUT_MS;
2922
3258
  exports.BLE_GATT_SETUP_TIMEOUT_MS = BLE_GATT_SETUP_TIMEOUT_MS;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onekeyfe/hd-transport-react-native",
3
- "version": "1.2.3-alpha.9",
3
+ "version": "1.2.4-alpha.0",
4
4
  "homepage": "https://github.com/OneKeyHQ/hardware-js-sdk#readme",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -20,11 +20,11 @@
20
20
  "lint:fix": "eslint . --fix"
21
21
  },
22
22
  "dependencies": {
23
- "@onekeyfe/hd-core": "1.2.3-alpha.9",
24
- "@onekeyfe/hd-shared": "1.2.3-alpha.9",
25
- "@onekeyfe/hd-transport": "1.2.3-alpha.9",
26
- "@onekeyfe/react-native-ble-utils": "0.1.8",
23
+ "@onekeyfe/hd-core": "1.2.4-alpha.0",
24
+ "@onekeyfe/hd-shared": "1.2.4-alpha.0",
25
+ "@onekeyfe/hd-transport": "1.2.4-alpha.0",
26
+ "@onekeyfe/react-native-ble-utils": "0.1.9",
27
27
  "react-native-ble-plx": "3.5.1"
28
28
  },
29
- "gitHead": "0fc494d4b87cf3dcc4eb1fbe3910a3cbc914e5f5"
29
+ "gitHead": "4996c67dbb5a3ac85c2559b164d9a931274890a7"
30
30
  }