@onekeyfe/hd-transport-web-device 1.2.2-alpha.8 → 1.2.3-alpha.1
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.
|
@@ -182,6 +182,40 @@ describe('ElectronBleTransport protocol detection', () => {
|
|
|
182
182
|
jest.clearAllMocks();
|
|
183
183
|
});
|
|
184
184
|
|
|
185
|
+
test('does not treat an error envelope from a legacy preload as a successful connect', async () => {
|
|
186
|
+
const device = { id: 'stale-bond-id', name: 'OneKey Pro 2' };
|
|
187
|
+
const nobleBle = createNobleBle(device);
|
|
188
|
+
nobleBle.connect.mockResolvedValue({
|
|
189
|
+
type: 'NobleBleIpcError',
|
|
190
|
+
success: false,
|
|
191
|
+
error: {
|
|
192
|
+
name: 'HardwareError',
|
|
193
|
+
message: 'Bluetooth pairing information is no longer valid',
|
|
194
|
+
errorCode: HardwareErrorCode.BleBondInvalid,
|
|
195
|
+
},
|
|
196
|
+
} as never);
|
|
197
|
+
const bleTransport = configureTransport(nobleBle);
|
|
198
|
+
|
|
199
|
+
await expect(
|
|
200
|
+
bleTransport.acquire({ uuid: device.id, expectedProtocol: 'V2' })
|
|
201
|
+
).rejects.toMatchObject({
|
|
202
|
+
errorCode: HardwareErrorCode.BleBondInvalid,
|
|
203
|
+
});
|
|
204
|
+
expect(nobleBle.subscribe).not.toHaveBeenCalled();
|
|
205
|
+
expect(nobleBle.disconnect).toHaveBeenCalledWith(device.id);
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
test('sends a native disconnect even before acquire marks the device connected', async () => {
|
|
209
|
+
const device = { id: 'pending-connect-id', name: 'OneKey Pro 2' };
|
|
210
|
+
const nobleBle = createNobleBle(device);
|
|
211
|
+
const bleTransport = configureTransport(nobleBle) as any;
|
|
212
|
+
|
|
213
|
+
await bleTransport.releaseNative(device.id);
|
|
214
|
+
|
|
215
|
+
expect(nobleBle.unsubscribe).not.toHaveBeenCalled();
|
|
216
|
+
expect(nobleBle.disconnect).toHaveBeenCalledWith(device.id);
|
|
217
|
+
});
|
|
218
|
+
|
|
185
219
|
test('keeps raw BLE lifecycle payloads off the public device event channel', async () => {
|
|
186
220
|
const device = { id: 'lifecycle-pro2-id', name: 'OneKey Pro 2' };
|
|
187
221
|
const nobleBle = createNobleBle(device);
|
|
@@ -553,14 +587,19 @@ describe('ElectronBleTransport protocol detection', () => {
|
|
|
553
587
|
test('fails Protocol V2 acquire immediately when subscribe reports insufficient encryption', async () => {
|
|
554
588
|
const device = { id: 'stale-bond-pro2-id', name: 'OneKey Pro 2' };
|
|
555
589
|
const nobleBle = createNobleBle(device);
|
|
556
|
-
nobleBle.subscribe.mockRejectedValue(
|
|
590
|
+
nobleBle.subscribe.mockRejectedValue({
|
|
591
|
+
name: 'HardwareError',
|
|
592
|
+
message: 'Bluetooth pairing information is no longer valid',
|
|
593
|
+
errorCode: HardwareErrorCode.BleBondInvalid,
|
|
594
|
+
params: { nativeErrorMessage: 'Encryption is insufficient' },
|
|
595
|
+
});
|
|
557
596
|
const transport = configureTransport(nobleBle);
|
|
558
597
|
const probe = jest.spyOn(transport as any, 'probeProtocolV2');
|
|
559
598
|
|
|
560
599
|
await expect(
|
|
561
600
|
transport.acquire({ uuid: device.id, expectedProtocol: 'V2' })
|
|
562
601
|
).rejects.toMatchObject({
|
|
563
|
-
errorCode: HardwareErrorCode.
|
|
602
|
+
errorCode: HardwareErrorCode.BleBondInvalid,
|
|
564
603
|
});
|
|
565
604
|
|
|
566
605
|
expect(probe).not.toHaveBeenCalled();
|
|
@@ -568,6 +607,56 @@ describe('ElectronBleTransport protocol detection', () => {
|
|
|
568
607
|
expect(nobleBle.disconnect).toHaveBeenCalledWith(device.id);
|
|
569
608
|
});
|
|
570
609
|
|
|
610
|
+
test('rehydrates a structured stale-bond error before the protocol is known', async () => {
|
|
611
|
+
const device = { id: 'reset-unknown-protocol-id', name: 'OneKey Pro 2' };
|
|
612
|
+
const nobleBle = createNobleBle(device);
|
|
613
|
+
nobleBle.connect.mockRejectedValue({
|
|
614
|
+
name: 'HardwareError',
|
|
615
|
+
message: 'Bluetooth pairing information is no longer valid',
|
|
616
|
+
errorCode: HardwareErrorCode.BleBondInvalid,
|
|
617
|
+
params: { nativeErrorMessage: 'CBErrorDomain:14 native message' },
|
|
618
|
+
});
|
|
619
|
+
const transport = configureTransport(nobleBle);
|
|
620
|
+
|
|
621
|
+
await expect(transport.acquire({ uuid: device.id })).rejects.toMatchObject({
|
|
622
|
+
name: 'HardwareError',
|
|
623
|
+
errorCode: HardwareErrorCode.BleBondInvalid,
|
|
624
|
+
params: { nativeErrorMessage: 'CBErrorDomain:14 native message' },
|
|
625
|
+
});
|
|
626
|
+
});
|
|
627
|
+
|
|
628
|
+
test('does not infer hardware errors from native error text in the renderer', async () => {
|
|
629
|
+
const device = { id: 'reset-pro2-localized-id', name: 'OneKey Pro 2' };
|
|
630
|
+
const nobleBle = createNobleBle(device);
|
|
631
|
+
nobleBle.connect.mockRejectedValue(new Error('CBATTErrorDomain:14 localized native message'));
|
|
632
|
+
const transport = configureTransport(nobleBle);
|
|
633
|
+
|
|
634
|
+
try {
|
|
635
|
+
await transport.acquire({ uuid: device.id, expectedProtocol: 'V2' });
|
|
636
|
+
throw new Error('Expected acquire to fail');
|
|
637
|
+
} catch (error) {
|
|
638
|
+
expect(error).toBeInstanceOf(Error);
|
|
639
|
+
expect((error as Error).message).toBe('CBATTErrorDomain:14 localized native message');
|
|
640
|
+
expect((error as { errorCode?: unknown }).errorCode).toBeUndefined();
|
|
641
|
+
}
|
|
642
|
+
});
|
|
643
|
+
|
|
644
|
+
test('does not classify a generic macOS connection failure as a stale bond', async () => {
|
|
645
|
+
const device = { id: 'offline-pro2-macos-id', name: 'OneKey Pro 2' };
|
|
646
|
+
const nobleBle = createNobleBle(device);
|
|
647
|
+
nobleBle.connect.mockRejectedValue(new Error('connection failed'));
|
|
648
|
+
const transport = configureTransport(nobleBle);
|
|
649
|
+
|
|
650
|
+
try {
|
|
651
|
+
await transport.acquire({ uuid: device.id, expectedProtocol: 'V2' });
|
|
652
|
+
throw new Error('Expected acquire to fail');
|
|
653
|
+
} catch (error) {
|
|
654
|
+
expect(error).toBeInstanceOf(Error);
|
|
655
|
+
expect((error as Error).message).toBe('connection failed');
|
|
656
|
+
expect((error as { errorCode?: unknown }).errorCode).toBeUndefined();
|
|
657
|
+
}
|
|
658
|
+
});
|
|
659
|
+
|
|
571
660
|
test('keeps stale-bond subscribe mapping out of Protocol V1 acquire', async () => {
|
|
572
661
|
const device = { id: 'classic-v1-id', name: 'OneKey Classic' };
|
|
573
662
|
const nobleBle = createNobleBle(device);
|
|
@@ -41,7 +41,7 @@ export default class ElectronBleTransport {
|
|
|
41
41
|
private hostDisconnectCleanup?;
|
|
42
42
|
private notificationTokens;
|
|
43
43
|
private nextNotificationToken;
|
|
44
|
-
private
|
|
44
|
+
private normalizeBluetoothError;
|
|
45
45
|
private handleBluetoothError;
|
|
46
46
|
private cleanupDeviceState;
|
|
47
47
|
init(logger: any, emitter?: EventEmitter): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"electron-ble-transport.d.ts","sourceRoot":"","sources":["../src/electron-ble-transport.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"electron-ble-transport.d.ts","sourceRoot":"","sources":["../src/electron-ble-transport.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -242,7 +242,7 @@ declare class ElectronBleTransport {
|
|
|
242
242
|
private hostDisconnectCleanup?;
|
|
243
243
|
private notificationTokens;
|
|
244
244
|
private nextNotificationToken;
|
|
245
|
-
private
|
|
245
|
+
private normalizeBluetoothError;
|
|
246
246
|
private handleBluetoothError;
|
|
247
247
|
private cleanupDeviceState;
|
|
248
248
|
init(logger: any, emitter?: EventEmitter): void;
|
package/dist/index.js
CHANGED
|
@@ -823,6 +823,19 @@ function resolveBlePacketCapacity(mtu, maximumPacketCapacity, fallbackPacketCapa
|
|
|
823
823
|
|
|
824
824
|
const { parseConfigure, ProtocolV1, check } = transport__default["default"];
|
|
825
825
|
const toBleDescriptor = (device, protocolType) => (Object.assign({ id: device.id, name: device.name, path: device.id, debug: false, commType: 'electron-ble' }, (protocolType ? { protocolType } : {})));
|
|
826
|
+
const invokeNobleBle = (request) => __awaiter(void 0, void 0, void 0, function* () {
|
|
827
|
+
const response = yield request;
|
|
828
|
+
if (response &&
|
|
829
|
+
typeof response === 'object' &&
|
|
830
|
+
'type' in response &&
|
|
831
|
+
response.type === 'NobleBleIpcError' &&
|
|
832
|
+
'success' in response &&
|
|
833
|
+
response.success === false &&
|
|
834
|
+
'error' in response) {
|
|
835
|
+
return Promise.reject(response.error);
|
|
836
|
+
}
|
|
837
|
+
return response;
|
|
838
|
+
});
|
|
826
839
|
const BLE_PACKET_SIZE_FALLBACK = 192;
|
|
827
840
|
const BLE_PACKET_SIZE_MAXIMUM = 244;
|
|
828
841
|
const BLE_WRITE_DELAY_MS = 5;
|
|
@@ -871,39 +884,20 @@ class ElectronBleTransport {
|
|
|
871
884
|
this.notificationTokens = new Map();
|
|
872
885
|
this.nextNotificationToken = 1;
|
|
873
886
|
}
|
|
874
|
-
|
|
875
|
-
var _a;
|
|
876
|
-
if (hdShared.isBleStaleBondHardwareError(error)) {
|
|
877
|
-
return error;
|
|
878
|
-
}
|
|
879
|
-
const errorMessage = error && typeof error === 'object' && 'message' in error
|
|
880
|
-
? String((_a = error.message) !== null && _a !== void 0 ? _a : '')
|
|
881
|
-
: String(error !== null && error !== void 0 ? error : '');
|
|
882
|
-
if (!hdShared.isBleStaleBondErrorText(errorMessage)) {
|
|
883
|
-
return null;
|
|
884
|
-
}
|
|
885
|
-
const normalizedErrorMessage = errorMessage.toLowerCase();
|
|
886
|
-
return hdShared.ERRORS.TypedError(normalizedErrorMessage.includes('peer removed pairing information')
|
|
887
|
-
? hdShared.HardwareErrorCode.BlePeerRemovedPairingInformation
|
|
888
|
-
: hdShared.HardwareErrorCode.BleDeviceBondError, errorMessage);
|
|
889
|
-
}
|
|
890
|
-
handleBluetoothError(error, mapProtocolV2StaleBond = false) {
|
|
891
|
-
if (mapProtocolV2StaleBond) {
|
|
892
|
-
const staleBondError = this.toStaleBondError(error);
|
|
893
|
-
if (staleBondError) {
|
|
894
|
-
throw staleBondError;
|
|
895
|
-
}
|
|
896
|
-
}
|
|
887
|
+
normalizeBluetoothError(error) {
|
|
897
888
|
if (error && typeof error === 'object') {
|
|
889
|
+
if (typeof error.errorCode === 'number') {
|
|
890
|
+
return hdShared.ERRORS.TypedError(error.errorCode, typeof error.message === 'string' ? error.message : undefined, error.params);
|
|
891
|
+
}
|
|
898
892
|
if ('code' in error) {
|
|
899
893
|
if (error.code === hdShared.HardwareErrorCode.BlePoweredOff) {
|
|
900
|
-
|
|
894
|
+
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BlePoweredOff);
|
|
901
895
|
}
|
|
902
896
|
if (error.code === hdShared.HardwareErrorCode.BleUnsupported) {
|
|
903
|
-
|
|
897
|
+
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleUnsupported);
|
|
904
898
|
}
|
|
905
899
|
if (error.code === hdShared.HardwareErrorCode.BlePermissionError) {
|
|
906
|
-
|
|
900
|
+
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BlePermissionError);
|
|
907
901
|
}
|
|
908
902
|
}
|
|
909
903
|
const errorMessage = error.message || String(error);
|
|
@@ -911,16 +905,19 @@ class ElectronBleTransport {
|
|
|
911
905
|
const unsupportedMessage = hdShared.HardwareErrorCodeMessage[hdShared.HardwareErrorCode.BleUnsupported];
|
|
912
906
|
const permissionMessage = hdShared.HardwareErrorCodeMessage[hdShared.HardwareErrorCode.BlePermissionError];
|
|
913
907
|
if (errorMessage.includes(poweredOffMessage) || errorMessage.includes('poweredOff')) {
|
|
914
|
-
|
|
908
|
+
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BlePoweredOff);
|
|
915
909
|
}
|
|
916
910
|
if (errorMessage.includes(unsupportedMessage) || errorMessage.includes('unsupported')) {
|
|
917
|
-
|
|
911
|
+
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleUnsupported);
|
|
918
912
|
}
|
|
919
913
|
if (errorMessage.includes(permissionMessage) || errorMessage.includes('unauthorized')) {
|
|
920
|
-
|
|
914
|
+
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BlePermissionError);
|
|
921
915
|
}
|
|
922
916
|
}
|
|
923
|
-
|
|
917
|
+
return error;
|
|
918
|
+
}
|
|
919
|
+
handleBluetoothError(error) {
|
|
920
|
+
throw this.normalizeBluetoothError(error);
|
|
924
921
|
}
|
|
925
922
|
cleanupDeviceState(deviceId) {
|
|
926
923
|
this.protocolV2Links
|
|
@@ -1007,7 +1004,7 @@ class ElectronBleTransport {
|
|
|
1007
1004
|
if (!((_a = window.desktopApi) === null || _a === void 0 ? void 0 : _a.nobleBle)) {
|
|
1008
1005
|
throw new Error('Noble BLE API not available');
|
|
1009
1006
|
}
|
|
1010
|
-
const devices = yield window.desktopApi.nobleBle.enumerate();
|
|
1007
|
+
const devices = yield invokeNobleBle(window.desktopApi.nobleBle.enumerate());
|
|
1011
1008
|
(_b = this.Log) === null || _b === void 0 ? void 0 : _b.debug(`[Electron BLE] enumerate found ${devices.length} device(s):`);
|
|
1012
1009
|
for (const dev of devices) {
|
|
1013
1010
|
(_c = this.Log) === null || _c === void 0 ? void 0 : _c.debug(`[Electron BLE] id="${dev.id}" name="${dev.name}"`);
|
|
@@ -1024,9 +1021,6 @@ class ElectronBleTransport {
|
|
|
1024
1021
|
var _a, _b, _c, _d, _e, _f, _g;
|
|
1025
1022
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1026
1023
|
const { uuid, forceCleanRunPromise, expectedProtocol } = input;
|
|
1027
|
-
const shouldMapProtocolV2StaleBond = expectedProtocol
|
|
1028
|
-
? expectedProtocol === 'V2'
|
|
1029
|
-
: this.confirmedProtocolV2.has(uuid);
|
|
1030
1024
|
if (!uuid) {
|
|
1031
1025
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleRequiredUUID);
|
|
1032
1026
|
}
|
|
@@ -1043,7 +1037,7 @@ class ElectronBleTransport {
|
|
|
1043
1037
|
if (!((_a = window.desktopApi) === null || _a === void 0 ? void 0 : _a.nobleBle)) {
|
|
1044
1038
|
throw new Error('Noble BLE API not available');
|
|
1045
1039
|
}
|
|
1046
|
-
const device = yield window.desktopApi.nobleBle.getDevice(uuid);
|
|
1040
|
+
const device = yield invokeNobleBle(window.desktopApi.nobleBle.getDevice(uuid));
|
|
1047
1041
|
if (!device) {
|
|
1048
1042
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceNotFound, `Device ${uuid} not found`);
|
|
1049
1043
|
}
|
|
@@ -1054,11 +1048,11 @@ class ElectronBleTransport {
|
|
|
1054
1048
|
this.deviceProtocolHints.set(uuid, protocolHint);
|
|
1055
1049
|
}
|
|
1056
1050
|
try {
|
|
1057
|
-
yield window.desktopApi.nobleBle.connect(uuid);
|
|
1051
|
+
yield invokeNobleBle(window.desktopApi.nobleBle.connect(uuid));
|
|
1058
1052
|
this.connectedDevices.add(uuid);
|
|
1059
1053
|
}
|
|
1060
1054
|
catch (error) {
|
|
1061
|
-
this.handleBluetoothError(error
|
|
1055
|
+
this.handleBluetoothError(error);
|
|
1062
1056
|
}
|
|
1063
1057
|
const mtuCleanup = this.createMtuSubscription(uuid);
|
|
1064
1058
|
if (mtuCleanup) {
|
|
@@ -1067,10 +1061,10 @@ class ElectronBleTransport {
|
|
|
1067
1061
|
this.v1Buffers.set(uuid, { buffer: [], bufferLength: 0 });
|
|
1068
1062
|
this.v2Assemblers.set(uuid, new transport.ProtocolV2FrameAssembler(transport.PROTOCOL_V2_BLE_FRAME_MAX_BYTES));
|
|
1069
1063
|
try {
|
|
1070
|
-
yield window.desktopApi.nobleBle.subscribe(uuid);
|
|
1064
|
+
yield invokeNobleBle(window.desktopApi.nobleBle.subscribe(uuid));
|
|
1071
1065
|
}
|
|
1072
1066
|
catch (error) {
|
|
1073
|
-
this.handleBluetoothError(error
|
|
1067
|
+
this.handleBluetoothError(error);
|
|
1074
1068
|
}
|
|
1075
1069
|
yield this.refreshBlePacketCapacity(uuid);
|
|
1076
1070
|
const cleanup = this.createNotificationSubscription(uuid);
|
|
@@ -1088,16 +1082,22 @@ class ElectronBleTransport {
|
|
|
1088
1082
|
catch (error) {
|
|
1089
1083
|
(_e = this.Log) === null || _e === void 0 ? void 0 : _e.error('[Electron BLE] acquire failed:', error);
|
|
1090
1084
|
try {
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1085
|
+
const nobleBle = (_f = window.desktopApi) === null || _f === void 0 ? void 0 : _f.nobleBle;
|
|
1086
|
+
if (nobleBle) {
|
|
1087
|
+
if (this.connectedDevices.has(uuid)) {
|
|
1088
|
+
yield invokeNobleBle(nobleBle.unsubscribe(uuid)).catch(cleanupError => {
|
|
1089
|
+
var _a;
|
|
1090
|
+
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[Electron BLE] acquire unsubscribe failed:', cleanupError);
|
|
1091
|
+
});
|
|
1092
|
+
}
|
|
1093
|
+
yield invokeNobleBle(nobleBle.disconnect(uuid));
|
|
1094
1094
|
}
|
|
1095
1095
|
}
|
|
1096
1096
|
catch (cleanupError) {
|
|
1097
1097
|
(_g = this.Log) === null || _g === void 0 ? void 0 : _g.debug('[Electron BLE] acquire cleanup failed:', cleanupError);
|
|
1098
1098
|
}
|
|
1099
1099
|
this.cleanupDeviceState(uuid);
|
|
1100
|
-
|
|
1100
|
+
this.handleBluetoothError(error);
|
|
1101
1101
|
}
|
|
1102
1102
|
});
|
|
1103
1103
|
}
|
|
@@ -1123,13 +1123,17 @@ class ElectronBleTransport {
|
|
|
1123
1123
|
var _a, _b;
|
|
1124
1124
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1125
1125
|
try {
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
yield
|
|
1126
|
+
const nobleBle = (_a = window.desktopApi) === null || _a === void 0 ? void 0 : _a.nobleBle;
|
|
1127
|
+
if (nobleBle) {
|
|
1128
|
+
if (this.connectedDevices.has(id)) {
|
|
1129
|
+
yield invokeNobleBle(nobleBle.unsubscribe(id)).catch(error => {
|
|
1130
|
+
var _a;
|
|
1131
|
+
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[Electron BLE] release unsubscribe failed:', error);
|
|
1132
|
+
});
|
|
1130
1133
|
}
|
|
1131
|
-
|
|
1134
|
+
yield invokeNobleBle(nobleBle.disconnect(id));
|
|
1132
1135
|
}
|
|
1136
|
+
this.cleanupDeviceState(id);
|
|
1133
1137
|
}
|
|
1134
1138
|
catch (error) {
|
|
1135
1139
|
(_b = this.Log) === null || _b === void 0 ? void 0 : _b.error('[Electron BLE] release failed:', error);
|
|
@@ -1153,7 +1157,7 @@ class ElectronBleTransport {
|
|
|
1153
1157
|
}
|
|
1154
1158
|
return;
|
|
1155
1159
|
}
|
|
1156
|
-
yield release(id, keepSession);
|
|
1160
|
+
yield invokeNobleBle(release(id, keepSession));
|
|
1157
1161
|
}
|
|
1158
1162
|
catch (error) {
|
|
1159
1163
|
(_d = this.Log) === null || _d === void 0 ? void 0 : _d.error('[Electron BLE] logical release failed:', error);
|
|
@@ -1298,21 +1302,18 @@ class ElectronBleTransport {
|
|
|
1298
1302
|
throw new Error('Noble BLE API not available');
|
|
1299
1303
|
}
|
|
1300
1304
|
try {
|
|
1301
|
-
yield nobleBle.write(uuid, hexData, { pacingDelayMs: 0 });
|
|
1305
|
+
yield invokeNobleBle(nobleBle.write(uuid, hexData, { pacingDelayMs: 0 }));
|
|
1302
1306
|
}
|
|
1303
1307
|
catch (error) {
|
|
1304
|
-
|
|
1305
|
-
if (staleBondError) {
|
|
1306
|
-
throw staleBondError;
|
|
1307
|
-
}
|
|
1308
|
-
throw error;
|
|
1308
|
+
this.handleBluetoothError(error);
|
|
1309
1309
|
}
|
|
1310
1310
|
});
|
|
1311
1311
|
}
|
|
1312
1312
|
refreshBlePacketCapacity(uuid) {
|
|
1313
|
-
var _a
|
|
1313
|
+
var _a;
|
|
1314
1314
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1315
|
-
const
|
|
1315
|
+
const nobleBle = (_a = window.desktopApi) === null || _a === void 0 ? void 0 : _a.nobleBle;
|
|
1316
|
+
const device = nobleBle ? yield invokeNobleBle(nobleBle.getDevice(uuid)) : undefined;
|
|
1316
1317
|
this.updateBlePacketCapacity(uuid, device === null || device === void 0 ? void 0 : device.mtu);
|
|
1317
1318
|
});
|
|
1318
1319
|
}
|
|
@@ -1535,7 +1536,7 @@ class ElectronBleTransport {
|
|
|
1535
1536
|
if (hexString.length === 0) {
|
|
1536
1537
|
throw new Error(`Buffer ${i + 1} is empty`);
|
|
1537
1538
|
}
|
|
1538
|
-
yield window.desktopApi.nobleBle.write(uuid, hexString);
|
|
1539
|
+
yield invokeNobleBle(window.desktopApi.nobleBle.write(uuid, hexString));
|
|
1539
1540
|
}
|
|
1540
1541
|
const response = yield Promise.race([
|
|
1541
1542
|
runPromise.promise,
|
|
@@ -1568,7 +1569,7 @@ class ElectronBleTransport {
|
|
|
1568
1569
|
yield this.releaseNative(uuid);
|
|
1569
1570
|
}
|
|
1570
1571
|
}
|
|
1571
|
-
throw e;
|
|
1572
|
+
throw this.normalizeBluetoothError(e);
|
|
1572
1573
|
}
|
|
1573
1574
|
finally {
|
|
1574
1575
|
if (timeout)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onekeyfe/hd-transport-web-device",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.3-alpha.1",
|
|
4
4
|
"author": "OneKey",
|
|
5
5
|
"homepage": "https://github.com/OneKeyHQ/hardware-js-sdk#readme",
|
|
6
6
|
"license": "MIT",
|
|
@@ -21,13 +21,13 @@
|
|
|
21
21
|
"lint:fix": "eslint . --fix"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@onekeyfe/hd-shared": "1.2.
|
|
25
|
-
"@onekeyfe/hd-transport": "1.2.
|
|
24
|
+
"@onekeyfe/hd-shared": "1.2.3-alpha.1",
|
|
25
|
+
"@onekeyfe/hd-transport": "1.2.3-alpha.1"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
|
-
"@onekeyfe/hd-transport-electron": "1.2.
|
|
28
|
+
"@onekeyfe/hd-transport-electron": "1.2.3-alpha.1",
|
|
29
29
|
"@types/w3c-web-usb": "^1.0.6",
|
|
30
30
|
"@types/web-bluetooth": "^0.0.17"
|
|
31
31
|
},
|
|
32
|
-
"gitHead": "
|
|
32
|
+
"gitHead": "fd4221863c00240fc4870fc50f8c517d97426de2"
|
|
33
33
|
}
|
|
@@ -18,7 +18,6 @@ import {
|
|
|
18
18
|
HardwareErrorCode,
|
|
19
19
|
HardwareErrorCodeMessage,
|
|
20
20
|
createDeferred,
|
|
21
|
-
isBleStaleBondErrorText,
|
|
22
21
|
isBleStaleBondHardwareError,
|
|
23
22
|
isHeaderChunk,
|
|
24
23
|
} from '@onekeyfe/hd-shared';
|
|
@@ -26,7 +25,7 @@ import {
|
|
|
26
25
|
import { resolveBlePacketCapacity } from './ble-packet-capacity';
|
|
27
26
|
|
|
28
27
|
import type { Deferred } from '@onekeyfe/hd-shared';
|
|
29
|
-
import type { DesktopAPI } from '@onekeyfe/hd-transport-electron';
|
|
28
|
+
import type { DesktopAPI, NobleBleIpcErrorResponse } from '@onekeyfe/hd-transport-electron';
|
|
30
29
|
import type {
|
|
31
30
|
OneKeyDeviceInfo,
|
|
32
31
|
ProtocolType,
|
|
@@ -69,6 +68,22 @@ const toBleDescriptor = (
|
|
|
69
68
|
...(protocolType ? { protocolType } : {}),
|
|
70
69
|
} as OneKeyDeviceInfo);
|
|
71
70
|
|
|
71
|
+
const invokeNobleBle = async <T>(request: Promise<T>): Promise<T> => {
|
|
72
|
+
const response = await (request as Promise<T | NobleBleIpcErrorResponse>);
|
|
73
|
+
if (
|
|
74
|
+
response &&
|
|
75
|
+
typeof response === 'object' &&
|
|
76
|
+
'type' in response &&
|
|
77
|
+
response.type === 'NobleBleIpcError' &&
|
|
78
|
+
'success' in response &&
|
|
79
|
+
response.success === false &&
|
|
80
|
+
'error' in response
|
|
81
|
+
) {
|
|
82
|
+
return Promise.reject(response.error);
|
|
83
|
+
}
|
|
84
|
+
return response as T;
|
|
85
|
+
};
|
|
86
|
+
|
|
72
87
|
const BLE_PACKET_SIZE_FALLBACK = 192;
|
|
73
88
|
const BLE_PACKET_SIZE_MAXIMUM = 244;
|
|
74
89
|
const BLE_WRITE_DELAY_MS = 5;
|
|
@@ -163,43 +178,24 @@ export default class ElectronBleTransport {
|
|
|
163
178
|
|
|
164
179
|
private nextNotificationToken = 1;
|
|
165
180
|
|
|
166
|
-
private
|
|
167
|
-
if (isBleStaleBondHardwareError(error)) {
|
|
168
|
-
return error as Error;
|
|
169
|
-
}
|
|
170
|
-
const errorMessage =
|
|
171
|
-
error && typeof error === 'object' && 'message' in error
|
|
172
|
-
? String((error as { message?: unknown }).message ?? '')
|
|
173
|
-
: String(error ?? '');
|
|
174
|
-
if (!isBleStaleBondErrorText(errorMessage)) {
|
|
175
|
-
return null;
|
|
176
|
-
}
|
|
177
|
-
const normalizedErrorMessage = errorMessage.toLowerCase();
|
|
178
|
-
return ERRORS.TypedError(
|
|
179
|
-
normalizedErrorMessage.includes('peer removed pairing information')
|
|
180
|
-
? HardwareErrorCode.BlePeerRemovedPairingInformation
|
|
181
|
-
: HardwareErrorCode.BleDeviceBondError,
|
|
182
|
-
errorMessage
|
|
183
|
-
);
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
private handleBluetoothError(error: any, mapProtocolV2StaleBond = false): never {
|
|
187
|
-
if (mapProtocolV2StaleBond) {
|
|
188
|
-
const staleBondError = this.toStaleBondError(error);
|
|
189
|
-
if (staleBondError) {
|
|
190
|
-
throw staleBondError;
|
|
191
|
-
}
|
|
192
|
-
}
|
|
181
|
+
private normalizeBluetoothError(error: any): any {
|
|
193
182
|
if (error && typeof error === 'object') {
|
|
183
|
+
if (typeof error.errorCode === 'number') {
|
|
184
|
+
return ERRORS.TypedError(
|
|
185
|
+
error.errorCode,
|
|
186
|
+
typeof error.message === 'string' ? error.message : undefined,
|
|
187
|
+
error.params
|
|
188
|
+
);
|
|
189
|
+
}
|
|
194
190
|
if ('code' in error) {
|
|
195
191
|
if (error.code === HardwareErrorCode.BlePoweredOff) {
|
|
196
|
-
|
|
192
|
+
return ERRORS.TypedError(HardwareErrorCode.BlePoweredOff);
|
|
197
193
|
}
|
|
198
194
|
if (error.code === HardwareErrorCode.BleUnsupported) {
|
|
199
|
-
|
|
195
|
+
return ERRORS.TypedError(HardwareErrorCode.BleUnsupported);
|
|
200
196
|
}
|
|
201
197
|
if (error.code === HardwareErrorCode.BlePermissionError) {
|
|
202
|
-
|
|
198
|
+
return ERRORS.TypedError(HardwareErrorCode.BlePermissionError);
|
|
203
199
|
}
|
|
204
200
|
}
|
|
205
201
|
const errorMessage = error.message || String(error);
|
|
@@ -208,16 +204,20 @@ export default class ElectronBleTransport {
|
|
|
208
204
|
const permissionMessage = HardwareErrorCodeMessage[HardwareErrorCode.BlePermissionError];
|
|
209
205
|
|
|
210
206
|
if (errorMessage.includes(poweredOffMessage) || errorMessage.includes('poweredOff')) {
|
|
211
|
-
|
|
207
|
+
return ERRORS.TypedError(HardwareErrorCode.BlePoweredOff);
|
|
212
208
|
}
|
|
213
209
|
if (errorMessage.includes(unsupportedMessage) || errorMessage.includes('unsupported')) {
|
|
214
|
-
|
|
210
|
+
return ERRORS.TypedError(HardwareErrorCode.BleUnsupported);
|
|
215
211
|
}
|
|
216
212
|
if (errorMessage.includes(permissionMessage) || errorMessage.includes('unauthorized')) {
|
|
217
|
-
|
|
213
|
+
return ERRORS.TypedError(HardwareErrorCode.BlePermissionError);
|
|
218
214
|
}
|
|
219
215
|
}
|
|
220
|
-
|
|
216
|
+
return error;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
private handleBluetoothError(error: any): never {
|
|
220
|
+
throw this.normalizeBluetoothError(error);
|
|
221
221
|
}
|
|
222
222
|
|
|
223
223
|
private cleanupDeviceState(deviceId: string): void {
|
|
@@ -336,7 +336,7 @@ export default class ElectronBleTransport {
|
|
|
336
336
|
if (!window.desktopApi?.nobleBle) {
|
|
337
337
|
throw new Error('Noble BLE API not available');
|
|
338
338
|
}
|
|
339
|
-
const devices = await window.desktopApi.nobleBle.enumerate();
|
|
339
|
+
const devices = await invokeNobleBle(window.desktopApi.nobleBle.enumerate());
|
|
340
340
|
this.Log?.debug(`[Electron BLE] enumerate found ${devices.length} device(s):`);
|
|
341
341
|
for (const dev of devices) {
|
|
342
342
|
this.Log?.debug(`[Electron BLE] id="${dev.id}" name="${dev.name}"`);
|
|
@@ -350,9 +350,6 @@ export default class ElectronBleTransport {
|
|
|
350
350
|
|
|
351
351
|
async acquire(input: BleAcquireInput) {
|
|
352
352
|
const { uuid, forceCleanRunPromise, expectedProtocol } = input;
|
|
353
|
-
const shouldMapProtocolV2StaleBond = expectedProtocol
|
|
354
|
-
? expectedProtocol === 'V2'
|
|
355
|
-
: this.confirmedProtocolV2.has(uuid);
|
|
356
353
|
|
|
357
354
|
if (!uuid) {
|
|
358
355
|
throw ERRORS.TypedError(HardwareErrorCode.BleRequiredUUID);
|
|
@@ -374,7 +371,7 @@ export default class ElectronBleTransport {
|
|
|
374
371
|
throw new Error('Noble BLE API not available');
|
|
375
372
|
}
|
|
376
373
|
|
|
377
|
-
const device = await window.desktopApi.nobleBle.getDevice(uuid);
|
|
374
|
+
const device = await invokeNobleBle(window.desktopApi.nobleBle.getDevice(uuid));
|
|
378
375
|
if (!device) {
|
|
379
376
|
throw ERRORS.TypedError(HardwareErrorCode.DeviceNotFound, `Device ${uuid} not found`);
|
|
380
377
|
}
|
|
@@ -386,10 +383,10 @@ export default class ElectronBleTransport {
|
|
|
386
383
|
}
|
|
387
384
|
|
|
388
385
|
try {
|
|
389
|
-
await window.desktopApi.nobleBle.connect(uuid);
|
|
386
|
+
await invokeNobleBle(window.desktopApi.nobleBle.connect(uuid));
|
|
390
387
|
this.connectedDevices.add(uuid);
|
|
391
388
|
} catch (error) {
|
|
392
|
-
this.handleBluetoothError(error
|
|
389
|
+
this.handleBluetoothError(error);
|
|
393
390
|
}
|
|
394
391
|
|
|
395
392
|
const mtuCleanup = this.createMtuSubscription(uuid);
|
|
@@ -401,9 +398,9 @@ export default class ElectronBleTransport {
|
|
|
401
398
|
this.v2Assemblers.set(uuid, new ProtocolV2FrameAssembler(PROTOCOL_V2_BLE_FRAME_MAX_BYTES));
|
|
402
399
|
|
|
403
400
|
try {
|
|
404
|
-
await window.desktopApi.nobleBle.subscribe(uuid);
|
|
401
|
+
await invokeNobleBle(window.desktopApi.nobleBle.subscribe(uuid));
|
|
405
402
|
} catch (error) {
|
|
406
|
-
this.handleBluetoothError(error
|
|
403
|
+
this.handleBluetoothError(error);
|
|
407
404
|
}
|
|
408
405
|
await this.refreshBlePacketCapacity(uuid);
|
|
409
406
|
|
|
@@ -426,15 +423,20 @@ export default class ElectronBleTransport {
|
|
|
426
423
|
} catch (error) {
|
|
427
424
|
this.Log?.error('[Electron BLE] acquire failed:', error);
|
|
428
425
|
try {
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
426
|
+
const nobleBle = window.desktopApi?.nobleBle;
|
|
427
|
+
if (nobleBle) {
|
|
428
|
+
if (this.connectedDevices.has(uuid)) {
|
|
429
|
+
await invokeNobleBle(nobleBle.unsubscribe(uuid)).catch(cleanupError => {
|
|
430
|
+
this.Log?.debug('[Electron BLE] acquire unsubscribe failed:', cleanupError);
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
await invokeNobleBle(nobleBle.disconnect(uuid));
|
|
432
434
|
}
|
|
433
435
|
} catch (cleanupError) {
|
|
434
436
|
this.Log?.debug('[Electron BLE] acquire cleanup failed:', cleanupError);
|
|
435
437
|
}
|
|
436
438
|
this.cleanupDeviceState(uuid);
|
|
437
|
-
|
|
439
|
+
this.handleBluetoothError(error);
|
|
438
440
|
}
|
|
439
441
|
}
|
|
440
442
|
|
|
@@ -457,13 +459,16 @@ export default class ElectronBleTransport {
|
|
|
457
459
|
// Hard teardown, error paths only: a link presumed dead must not be reused.
|
|
458
460
|
private async releaseNative(id: string) {
|
|
459
461
|
try {
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
await
|
|
462
|
+
const nobleBle = window.desktopApi?.nobleBle;
|
|
463
|
+
if (nobleBle) {
|
|
464
|
+
if (this.connectedDevices.has(id)) {
|
|
465
|
+
await invokeNobleBle(nobleBle.unsubscribe(id)).catch(error => {
|
|
466
|
+
this.Log?.debug('[Electron BLE] release unsubscribe failed:', error);
|
|
467
|
+
});
|
|
464
468
|
}
|
|
465
|
-
|
|
469
|
+
await invokeNobleBle(nobleBle.disconnect(id));
|
|
466
470
|
}
|
|
471
|
+
this.cleanupDeviceState(id);
|
|
467
472
|
} catch (error) {
|
|
468
473
|
this.Log?.error('[Electron BLE] release failed:', error);
|
|
469
474
|
this.cleanupDeviceState(id);
|
|
@@ -489,7 +494,7 @@ export default class ElectronBleTransport {
|
|
|
489
494
|
}
|
|
490
495
|
return;
|
|
491
496
|
}
|
|
492
|
-
await release(id, keepSession);
|
|
497
|
+
await invokeNobleBle(release(id, keepSession));
|
|
493
498
|
} catch (error) {
|
|
494
499
|
this.Log?.error('[Electron BLE] logical release failed:', error);
|
|
495
500
|
this.cleanupDeviceState(id);
|
|
@@ -671,18 +676,15 @@ export default class ElectronBleTransport {
|
|
|
671
676
|
}
|
|
672
677
|
|
|
673
678
|
try {
|
|
674
|
-
await nobleBle.write(uuid, hexData, { pacingDelayMs: 0 });
|
|
679
|
+
await invokeNobleBle(nobleBle.write(uuid, hexData, { pacingDelayMs: 0 }));
|
|
675
680
|
} catch (error) {
|
|
676
|
-
|
|
677
|
-
if (staleBondError) {
|
|
678
|
-
throw staleBondError;
|
|
679
|
-
}
|
|
680
|
-
throw error;
|
|
681
|
+
this.handleBluetoothError(error);
|
|
681
682
|
}
|
|
682
683
|
}
|
|
683
684
|
|
|
684
685
|
private async refreshBlePacketCapacity(uuid: string): Promise<void> {
|
|
685
|
-
const
|
|
686
|
+
const nobleBle = window.desktopApi?.nobleBle;
|
|
687
|
+
const device = nobleBle ? await invokeNobleBle(nobleBle.getDevice(uuid)) : undefined;
|
|
686
688
|
this.updateBlePacketCapacity(uuid, device?.mtu);
|
|
687
689
|
}
|
|
688
690
|
|
|
@@ -940,7 +942,7 @@ export default class ElectronBleTransport {
|
|
|
940
942
|
if (hexString.length === 0) {
|
|
941
943
|
throw new Error(`Buffer ${i + 1} is empty`);
|
|
942
944
|
}
|
|
943
|
-
await window.desktopApi.nobleBle.write(uuid, hexString);
|
|
945
|
+
await invokeNobleBle(window.desktopApi.nobleBle.write(uuid, hexString));
|
|
944
946
|
}
|
|
945
947
|
|
|
946
948
|
const response = await Promise.race([
|
|
@@ -978,7 +980,7 @@ export default class ElectronBleTransport {
|
|
|
978
980
|
await this.releaseNative(uuid);
|
|
979
981
|
}
|
|
980
982
|
}
|
|
981
|
-
throw e;
|
|
983
|
+
throw this.normalizeBluetoothError(e);
|
|
982
984
|
} finally {
|
|
983
985
|
if (timeout) clearTimeout(timeout);
|
|
984
986
|
if (this.runPromise === runPromise) {
|