@onekeyfe/hd-transport-react-native 1.2.2-alpha.105 → 1.2.2-alpha.107
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 +1 -1
- package/dist/BleManager.d.ts.map +1 -1
- package/dist/bleNativeDisconnect.d.ts +3 -0
- package/dist/bleNativeDisconnect.d.ts.map +1 -0
- package/dist/index.d.ts +5 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +298 -78
- package/package.json +6 -6
- package/src/BleManager.ts +58 -4
- package/src/__tests__/bleNativeDisconnect.test.ts +33 -0
- package/src/__tests__/connectTimeout.test.ts +282 -3
- package/src/__tests__/protocolV2Link.test.ts +193 -31
- package/src/__tests__/staleCallTimeout.test.ts +34 -5
- package/src/bleNativeDisconnect.ts +40 -0
- package/src/index.ts +246 -85
|
@@ -4,7 +4,7 @@ import transportPackage, {
|
|
|
4
4
|
ProtocolV2,
|
|
5
5
|
TRANSPORT_EVENT,
|
|
6
6
|
} from '@onekeyfe/hd-transport';
|
|
7
|
-
import { HardwareErrorCode, createDeferred } from '@onekeyfe/hd-shared';
|
|
7
|
+
import { ERRORS, HardwareErrorCode, createDeferred } from '@onekeyfe/hd-shared';
|
|
8
8
|
|
|
9
9
|
import ReactNativeBleTransport, {
|
|
10
10
|
BLE_NATIVE_TEARDOWN_TIMEOUT_MS,
|
|
@@ -28,7 +28,7 @@ jest.mock('react-native-ble-plx', () => ({
|
|
|
28
28
|
BleError: class BleError extends Error {},
|
|
29
29
|
BleErrorCode: {
|
|
30
30
|
DeviceAlreadyConnected: 203,
|
|
31
|
-
DeviceDisconnected:
|
|
31
|
+
DeviceDisconnected: 201,
|
|
32
32
|
DeviceMTUChangeFailed: 206,
|
|
33
33
|
OperationCancelled: 2,
|
|
34
34
|
CharacteristicNotFound: 404,
|
|
@@ -360,32 +360,46 @@ describe('ReactNativeBleTransport Protocol V2 link lifecycle', () => {
|
|
|
360
360
|
expect(new ReactNativeBleTransport({}).scanTimeout).toBe(3000);
|
|
361
361
|
});
|
|
362
362
|
|
|
363
|
-
test('
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
363
|
+
test.each(['V1', 'V2'] as const)(
|
|
364
|
+
'waits for Android bonding before connecting the %s GATT link',
|
|
365
|
+
async protocol => {
|
|
366
|
+
setPlatformOS('android');
|
|
367
|
+
const { transport, uuid, device } = protocol === 'V1' ? createV1Harness() : createHarness();
|
|
368
|
+
const operationOrder: string[] = [];
|
|
369
|
+
const pairDeviceMock = jest.requireMock('../BleManager').pairDevice as jest.Mock;
|
|
370
|
+
const bondStateMock = jest.requireMock('../BleManager').onDeviceBondState as jest.Mock;
|
|
371
|
+
const bonding = createDeferred<void>();
|
|
368
372
|
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
373
|
+
device.isConnected.mockResolvedValueOnce(false);
|
|
374
|
+
device.connect = jest.fn(() => {
|
|
375
|
+
operationOrder.push('connect');
|
|
376
|
+
return Promise.resolve(device);
|
|
377
|
+
});
|
|
378
|
+
pairDeviceMock.mockImplementationOnce(() => {
|
|
379
|
+
operationOrder.push('bond');
|
|
380
|
+
return Promise.resolve({ bonded: false, bonding: true });
|
|
381
|
+
});
|
|
382
|
+
bondStateMock.mockImplementationOnce(() => bonding.promise);
|
|
378
383
|
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
384
|
+
const acquiring = transport.acquire({ uuid, expectedProtocol: protocol });
|
|
385
|
+
await new Promise(resolve => {
|
|
386
|
+
setImmediate(resolve);
|
|
387
|
+
});
|
|
388
|
+
expect(operationOrder).toEqual(['bond']);
|
|
389
|
+
expect(device.connect).not.toHaveBeenCalled();
|
|
383
390
|
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
391
|
+
bonding.resolve();
|
|
392
|
+
await expect(acquiring).resolves.toEqual({
|
|
393
|
+
uuid,
|
|
394
|
+
protocolType: protocol,
|
|
395
|
+
});
|
|
387
396
|
|
|
388
|
-
|
|
397
|
+
expect(operationOrder).toEqual(['bond', 'connect']);
|
|
398
|
+
await transport.release(uuid, true);
|
|
399
|
+
}
|
|
400
|
+
);
|
|
401
|
+
|
|
402
|
+
test('preserves Android connect errors after bonding when both reconnect attempts fail', async () => {
|
|
389
403
|
setPlatformOS('android');
|
|
390
404
|
const { transport, uuid, device } = createHarness();
|
|
391
405
|
const BleErrorMock = jest.requireMock('react-native-ble-plx').BleError as new (
|
|
@@ -412,22 +426,35 @@ describe('ReactNativeBleTransport Protocol V2 link lifecycle', () => {
|
|
|
412
426
|
errorCode: HardwareErrorCode.BleConnectedError,
|
|
413
427
|
});
|
|
414
428
|
expect(device.connect).toHaveBeenCalledTimes(2);
|
|
415
|
-
expect(pairDeviceMock).
|
|
429
|
+
expect(pairDeviceMock).toHaveBeenCalledTimes(1);
|
|
416
430
|
});
|
|
417
431
|
|
|
418
|
-
test('
|
|
432
|
+
test('does not connect Android GATT when the system cannot start bonding', async () => {
|
|
419
433
|
setPlatformOS('android');
|
|
420
434
|
const { transport, uuid, device, bleManager } = createHarness();
|
|
421
435
|
const pairDeviceMock = jest.requireMock('../BleManager').pairDevice as jest.Mock;
|
|
422
436
|
|
|
423
|
-
device.isConnected.mockResolvedValueOnce(false).mockResolvedValueOnce(false);
|
|
424
437
|
device.connect = jest.fn().mockResolvedValue(device);
|
|
425
438
|
pairDeviceMock.mockClear();
|
|
439
|
+
pairDeviceMock.mockResolvedValueOnce({ bonded: false, bonding: false });
|
|
440
|
+
|
|
441
|
+
await expect(transport.acquire({ uuid, expectedProtocol: 'V2' })).rejects.toMatchObject({
|
|
442
|
+
errorCode: HardwareErrorCode.BleDeviceNotBonded,
|
|
443
|
+
});
|
|
444
|
+
expect(device.connect).not.toHaveBeenCalled();
|
|
445
|
+
expect(bleManager.devices).not.toHaveBeenCalled();
|
|
446
|
+
expect(bleManager.cancelDeviceConnection).toHaveBeenCalledWith(uuid);
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
test('checks that Android GATT is connected after bonding and reconnecting', async () => {
|
|
450
|
+
setPlatformOS('android');
|
|
451
|
+
const { transport, uuid, device, bleManager } = createHarness();
|
|
452
|
+
device.isConnected.mockResolvedValueOnce(false).mockResolvedValueOnce(false);
|
|
453
|
+
device.connect = jest.fn().mockResolvedValue(device);
|
|
426
454
|
|
|
427
455
|
await expect(transport.acquire({ uuid, expectedProtocol: 'V2' })).rejects.toMatchObject({
|
|
428
456
|
errorCode: HardwareErrorCode.BleConnectedError,
|
|
429
457
|
});
|
|
430
|
-
expect(pairDeviceMock).not.toHaveBeenCalled();
|
|
431
458
|
expect(bleManager.cancelDeviceConnection).toHaveBeenCalledWith(uuid);
|
|
432
459
|
expect(device.cancelConnection).toHaveBeenCalledTimes(1);
|
|
433
460
|
});
|
|
@@ -468,12 +495,12 @@ describe('ReactNativeBleTransport Protocol V2 link lifecycle', () => {
|
|
|
468
495
|
.mockRejectedValue(Object.assign(new BleErrorMock(nativeError.reason), nativeError));
|
|
469
496
|
|
|
470
497
|
await expect(transport.acquire({ uuid })).rejects.toMatchObject({ errorCode });
|
|
471
|
-
expect(pairDeviceMock).
|
|
498
|
+
expect(pairDeviceMock).toHaveBeenCalledTimes(platform === 'android' ? 1 : 0);
|
|
472
499
|
expect(transport.getProtocolType(uuid)).toBeUndefined();
|
|
473
500
|
}
|
|
474
501
|
);
|
|
475
502
|
|
|
476
|
-
test('
|
|
503
|
+
test('cleans up Android bonding failures without starting GATT', async () => {
|
|
477
504
|
setPlatformOS('android');
|
|
478
505
|
const { transport, uuid, device, bleManager } = createHarness();
|
|
479
506
|
const pairDeviceMock = jest.requireMock('../BleManager').pairDevice as jest.Mock;
|
|
@@ -485,7 +512,32 @@ describe('ReactNativeBleTransport Protocol V2 link lifecycle', () => {
|
|
|
485
512
|
);
|
|
486
513
|
|
|
487
514
|
expect(bleManager.cancelDeviceConnection).toHaveBeenCalledWith(uuid);
|
|
488
|
-
expect(
|
|
515
|
+
expect(bleManager.devices).not.toHaveBeenCalled();
|
|
516
|
+
expect(device.isConnected).not.toHaveBeenCalled();
|
|
517
|
+
});
|
|
518
|
+
|
|
519
|
+
test('does not connect after stop while Android bonding is pending', async () => {
|
|
520
|
+
setPlatformOS('android');
|
|
521
|
+
const { transport, uuid, bleManager } = createHarness();
|
|
522
|
+
const pairDeviceMock = jest.requireMock('../BleManager').pairDevice as jest.Mock;
|
|
523
|
+
const bondStateMock = jest.requireMock('../BleManager').onDeviceBondState as jest.Mock;
|
|
524
|
+
const bonding = createDeferred<void>();
|
|
525
|
+
pairDeviceMock.mockResolvedValueOnce({ bonded: false, bonding: true });
|
|
526
|
+
bondStateMock.mockImplementationOnce(() => bonding.promise);
|
|
527
|
+
|
|
528
|
+
const acquiring = transport.acquire({ uuid, expectedProtocol: 'V2' });
|
|
529
|
+
const rejection = expect(acquiring).rejects.toMatchObject({
|
|
530
|
+
errorCode: HardwareErrorCode.BleDeviceDisconnected,
|
|
531
|
+
});
|
|
532
|
+
await new Promise(resolve => {
|
|
533
|
+
setImmediate(resolve);
|
|
534
|
+
});
|
|
535
|
+
const stopping = transport.stop();
|
|
536
|
+
bonding.resolve();
|
|
537
|
+
|
|
538
|
+
await rejection;
|
|
539
|
+
await stopping;
|
|
540
|
+
expect(bleManager.devices).not.toHaveBeenCalled();
|
|
489
541
|
});
|
|
490
542
|
|
|
491
543
|
test('uses withResponse for consecutive iOS Protocol V1 control commands without releasing', async () => {
|
|
@@ -830,6 +882,116 @@ describe('ReactNativeBleTransport Protocol V2 link lifecycle', () => {
|
|
|
830
882
|
BLE_NATIVE_TEARDOWN_TIMEOUT_MS + 5_000
|
|
831
883
|
);
|
|
832
884
|
|
|
885
|
+
test('preserves the unpaired error when iOS disconnects during the first V1 probe', async () => {
|
|
886
|
+
const { transport, uuid, writeCharacteristic } = createHarness({ deviceName: 'Neo Test' });
|
|
887
|
+
writeCharacteristic.writeWithResponse.mockRejectedValueOnce({
|
|
888
|
+
errorCode: 201,
|
|
889
|
+
iosErrorCode: 7,
|
|
890
|
+
reason: 'The specified device has disconnected from us.',
|
|
891
|
+
});
|
|
892
|
+
const probeProtocolV2 = jest.spyOn(transport as any, 'probeProtocolV2');
|
|
893
|
+
|
|
894
|
+
await expect(transport.acquire({ uuid })).rejects.toMatchObject({
|
|
895
|
+
errorCode: HardwareErrorCode.BleDeviceNotBonded,
|
|
896
|
+
});
|
|
897
|
+
|
|
898
|
+
expect(probeProtocolV2).not.toHaveBeenCalled();
|
|
899
|
+
expect(writeCharacteristic.writeWithResponse).toHaveBeenCalledTimes(1);
|
|
900
|
+
expect(transport.getProtocolType(uuid)).toBeUndefined();
|
|
901
|
+
});
|
|
902
|
+
|
|
903
|
+
test('preserves a native iOS disconnect during an expected Protocol V2 probe', async () => {
|
|
904
|
+
const { transport, uuid, writeCharacteristic, bleManager } = createHarness({
|
|
905
|
+
deviceName: 'Neo Test',
|
|
906
|
+
});
|
|
907
|
+
const nativeDisconnect = {
|
|
908
|
+
errorCode: 201,
|
|
909
|
+
iosErrorCode: 7,
|
|
910
|
+
reason: 'The specified device has disconnected from us.',
|
|
911
|
+
};
|
|
912
|
+
writeCharacteristic.writeWithoutResponse.mockRejectedValueOnce(nativeDisconnect);
|
|
913
|
+
const probeProtocolV1 = jest.spyOn(transport as any, 'probeProtocolV1');
|
|
914
|
+
|
|
915
|
+
await expect(transport.acquire({ uuid, expectedProtocol: 'V2' })).rejects.toMatchObject({
|
|
916
|
+
errorCode: HardwareErrorCode.BleDeviceDisconnected,
|
|
917
|
+
});
|
|
918
|
+
|
|
919
|
+
expect(probeProtocolV1).not.toHaveBeenCalled();
|
|
920
|
+
expect(writeCharacteristic.writeWithoutResponse).toHaveBeenCalledTimes(1);
|
|
921
|
+
expect(bleManager.cancelDeviceConnection).toHaveBeenCalledWith(uuid);
|
|
922
|
+
expect(transport.getProtocolType(uuid)).toBeUndefined();
|
|
923
|
+
});
|
|
924
|
+
|
|
925
|
+
test('preserves a native iOS disconnect during a V2-first probe without falling back to V1', async () => {
|
|
926
|
+
const { transport, uuid, writeCharacteristic } = createHarness({ deviceName: 'Neo Test' });
|
|
927
|
+
writeCharacteristic.writeWithoutResponse.mockRejectedValueOnce({
|
|
928
|
+
errorCode: 201,
|
|
929
|
+
iosErrorCode: 7,
|
|
930
|
+
reason: 'The specified device has disconnected from us.',
|
|
931
|
+
});
|
|
932
|
+
const probeProtocolV1 = jest.spyOn(transport as any, 'probeProtocolV1');
|
|
933
|
+
|
|
934
|
+
await expect(transport.acquire({ uuid, protocolHint: 'V2' })).rejects.toMatchObject({
|
|
935
|
+
errorCode: HardwareErrorCode.BleDeviceDisconnected,
|
|
936
|
+
});
|
|
937
|
+
|
|
938
|
+
expect(probeProtocolV1).not.toHaveBeenCalled();
|
|
939
|
+
expect(writeCharacteristic.writeWithoutResponse).toHaveBeenCalledTimes(1);
|
|
940
|
+
expect(transport.getProtocolType(uuid)).toBeUndefined();
|
|
941
|
+
});
|
|
942
|
+
|
|
943
|
+
test.each(['V1', 'V2'] as const)(
|
|
944
|
+
'preserves terminal BLE failures from the %s probe without trying another protocol',
|
|
945
|
+
async protocol => {
|
|
946
|
+
for (const errorCode of [
|
|
947
|
+
HardwareErrorCode.BleDeviceNotBonded,
|
|
948
|
+
HardwareErrorCode.BleDeviceBondedCanceled,
|
|
949
|
+
HardwareErrorCode.BlePeerRemovedPairingInformation,
|
|
950
|
+
HardwareErrorCode.BleDeviceDisconnected,
|
|
951
|
+
HardwareErrorCode.BleCharacteristicNotifyError,
|
|
952
|
+
HardwareErrorCode.BleCharacteristicNotifyChangeFailure,
|
|
953
|
+
HardwareErrorCode.BleWriteCharacteristicError,
|
|
954
|
+
]) {
|
|
955
|
+
const { transport, uuid } = createHarness();
|
|
956
|
+
const error = ERRORS.TypedError(errorCode);
|
|
957
|
+
const call = jest
|
|
958
|
+
.spyOn(transport as any, protocol === 'V1' ? 'callProtocolV1' : 'callProtocolV2')
|
|
959
|
+
.mockRejectedValue(error);
|
|
960
|
+
const otherProbe = jest.spyOn(
|
|
961
|
+
transport as any,
|
|
962
|
+
protocol === 'V1' ? 'probeProtocolV2' : 'probeProtocolV1'
|
|
963
|
+
);
|
|
964
|
+
|
|
965
|
+
await expect(transport.acquire({ uuid, protocolHint: protocol })).rejects.toBe(error);
|
|
966
|
+
|
|
967
|
+
expect(call).toHaveBeenCalledTimes(1);
|
|
968
|
+
expect(otherProbe).not.toHaveBeenCalled();
|
|
969
|
+
expect(transport.getProtocolType(uuid)).toBeUndefined();
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
);
|
|
973
|
+
|
|
974
|
+
test.each(['V1', 'V2'] as const)(
|
|
975
|
+
'still falls back after a silent %s probe timeout',
|
|
976
|
+
async protocol => {
|
|
977
|
+
const { transport, uuid } = createHarness();
|
|
978
|
+
jest
|
|
979
|
+
.spyOn(transport as any, protocol === 'V1' ? 'callProtocolV1' : 'callProtocolV2')
|
|
980
|
+
.mockRejectedValue(ERRORS.TypedError(HardwareErrorCode.BleTimeoutError));
|
|
981
|
+
const otherProbe = jest
|
|
982
|
+
.spyOn(transport as any, protocol === 'V1' ? 'probeProtocolV2' : 'probeProtocolV1')
|
|
983
|
+
.mockResolvedValue(true);
|
|
984
|
+
|
|
985
|
+
await expect(transport.acquire({ uuid, protocolHint: protocol })).resolves.toEqual({
|
|
986
|
+
uuid,
|
|
987
|
+
protocolType: protocol === 'V1' ? 'V2' : 'V1',
|
|
988
|
+
});
|
|
989
|
+
|
|
990
|
+
expect(otherProbe).toHaveBeenCalledTimes(1);
|
|
991
|
+
await transport.release(uuid, true);
|
|
992
|
+
}
|
|
993
|
+
);
|
|
994
|
+
|
|
833
995
|
test('falls back to the other active probe on iOS when protocol metadata is absent', async () => {
|
|
834
996
|
const { transport, uuid } = createHarness({ deviceName: 'OneKey' });
|
|
835
997
|
const probeProtocolV1 = jest
|
|
@@ -56,6 +56,34 @@ function createHarness() {
|
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
describe('Protocol V1 stale call timeout', () => {
|
|
59
|
+
test('settles a cancelled read and waits for native teardown before completing cancel', async () => {
|
|
60
|
+
const { t, disconnectSpy } = createHarness();
|
|
61
|
+
let finishDisconnect!: () => void;
|
|
62
|
+
disconnectSpy.mockImplementationOnce(
|
|
63
|
+
() =>
|
|
64
|
+
new Promise<void>(resolve => {
|
|
65
|
+
finishDisconnect = resolve;
|
|
66
|
+
})
|
|
67
|
+
);
|
|
68
|
+
const call = t.call(UUID, 'Initialize', {}, { timeoutMs: 25000 });
|
|
69
|
+
const result = call.catch(error => error);
|
|
70
|
+
await flush();
|
|
71
|
+
let cancelled = false;
|
|
72
|
+
const cleanup = t.cancel().then(() => {
|
|
73
|
+
cancelled = true;
|
|
74
|
+
});
|
|
75
|
+
await flush();
|
|
76
|
+
expect(await result).toMatchObject({ errorCode: HardwareErrorCode.CallQueueActionCancelled });
|
|
77
|
+
expect(t.runPromise).toBeNull();
|
|
78
|
+
expect(disconnectSpy).toHaveBeenCalledWith(UUID);
|
|
79
|
+
expect(cancelled).toBe(false);
|
|
80
|
+
finishDisconnect();
|
|
81
|
+
await cleanup;
|
|
82
|
+
jest.advanceTimersByTime(25000);
|
|
83
|
+
await flush();
|
|
84
|
+
expect(disconnectSpy).toHaveBeenCalledTimes(1);
|
|
85
|
+
});
|
|
86
|
+
|
|
59
87
|
beforeAll(() => {
|
|
60
88
|
jest.useFakeTimers({ doNotFake: ['setImmediate', 'performance'] });
|
|
61
89
|
});
|
|
@@ -172,24 +200,25 @@ describe('Protocol V1 stale call timeout', () => {
|
|
|
172
200
|
expect(secondErrors).toHaveLength(1);
|
|
173
201
|
});
|
|
174
202
|
|
|
175
|
-
test('
|
|
203
|
+
test('a cancelled read cannot disconnect a later transport when its old deadline passes', async () => {
|
|
176
204
|
const { t, disconnectSpy } = createHarness();
|
|
177
205
|
|
|
178
|
-
// cancel() nulls the ownership slot without settling the deferred, so the
|
|
179
|
-
// call's response timer stays armed (reachable via DeviceCommands.dispose).
|
|
180
206
|
const errors: Array<{ errorCode?: unknown }> = [];
|
|
181
207
|
const p = t.call(UUID, 'GetFeatures', {}, { timeoutMs: 5000 });
|
|
182
208
|
p.catch(e => errors.push(e));
|
|
183
209
|
await flush();
|
|
184
210
|
|
|
185
|
-
t.cancel();
|
|
211
|
+
await t.cancel();
|
|
212
|
+
await flush();
|
|
213
|
+
expect(disconnectSpy).toHaveBeenCalledTimes(1);
|
|
214
|
+
disconnectSpy.mockClear();
|
|
186
215
|
|
|
187
216
|
jest.advanceTimersByTime(5000);
|
|
188
217
|
await flush();
|
|
189
218
|
|
|
190
219
|
expect(disconnectSpy).not.toHaveBeenCalled();
|
|
191
220
|
expect(errors).toHaveLength(1);
|
|
192
|
-
expect(errors[0]?.errorCode).toBe(HardwareErrorCode.
|
|
221
|
+
expect(errors[0]?.errorCode).toBe(HardwareErrorCode.CallQueueActionCancelled);
|
|
193
222
|
});
|
|
194
223
|
|
|
195
224
|
test('timeout on the active call still disconnects the transport', async () => {
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { ERRORS, HardwareErrorCode } from '@onekeyfe/hd-shared';
|
|
2
|
+
|
|
3
|
+
const BLE_PLX_DEVICE_DISCONNECTED = 201;
|
|
4
|
+
const IOS_PERIPHERAL_DISCONNECTED = 7;
|
|
5
|
+
|
|
6
|
+
type NativeBleErrorFields = {
|
|
7
|
+
errorCode?: unknown;
|
|
8
|
+
iosErrorCode?: unknown;
|
|
9
|
+
reason?: unknown;
|
|
10
|
+
message?: unknown;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const nativeErrorText = (error: NativeBleErrorFields) =>
|
|
14
|
+
[error.reason, error.message]
|
|
15
|
+
.filter((value): value is string => typeof value === 'string')
|
|
16
|
+
.join(' ');
|
|
17
|
+
|
|
18
|
+
export const isNativeBleDisconnectError = (error: unknown): boolean => {
|
|
19
|
+
if (!error || typeof error !== 'object') {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const nativeError = error as NativeBleErrorFields;
|
|
24
|
+
return (
|
|
25
|
+
nativeError.errorCode === BLE_PLX_DEVICE_DISCONNECTED ||
|
|
26
|
+
nativeError.iosErrorCode === IOS_PERIPHERAL_DISCONNECTED
|
|
27
|
+
);
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export const toBleDisconnectHardwareError = (error: unknown) => {
|
|
31
|
+
if ((error as { errorCode?: unknown })?.errorCode === HardwareErrorCode.BleDeviceDisconnected) {
|
|
32
|
+
return error as Error;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const nativeError = (error ?? {}) as NativeBleErrorFields;
|
|
36
|
+
return ERRORS.TypedError(
|
|
37
|
+
HardwareErrorCode.BleDeviceDisconnected,
|
|
38
|
+
nativeErrorText(nativeError) || undefined
|
|
39
|
+
);
|
|
40
|
+
};
|