@onekeyfe/hd-transport-electron 1.2.8-alpha.3 → 1.2.8-alpha.4
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-98d6f724.js → index-e2e3d2ba.js} +2 -2
- package/dist/index.js +1 -1
- package/dist/{noble-ble-handler-688faeb6.js → noble-ble-handler-d0991fa0.js} +28 -9
- package/dist/noble-ble-handler.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/__tests__/noble-ble-handler.test.ts +104 -38
- package/src/noble-ble-handler.ts +31 -7
|
@@ -55,13 +55,13 @@ function invokeNobleBleIpc(request) {
|
|
|
55
55
|
|
|
56
56
|
function initNobleBleSupport(webContents) {
|
|
57
57
|
return __awaiter(this, void 0, void 0, function* () {
|
|
58
|
-
const { setupNobleBleHandlers } = yield Promise.resolve().then(function () { return require('./noble-ble-handler-
|
|
58
|
+
const { setupNobleBleHandlers } = yield Promise.resolve().then(function () { return require('./noble-ble-handler-d0991fa0.js'); });
|
|
59
59
|
setupNobleBleHandlers(webContents);
|
|
60
60
|
});
|
|
61
61
|
}
|
|
62
62
|
function disposeNobleBleSupport(releaseNoble) {
|
|
63
63
|
return __awaiter(this, void 0, void 0, function* () {
|
|
64
|
-
const handler = yield Promise.resolve().then(function () { return require('./noble-ble-handler-
|
|
64
|
+
const handler = yield Promise.resolve().then(function () { return require('./noble-ble-handler-d0991fa0.js'); });
|
|
65
65
|
yield handler.disposeNobleBleSupport(releaseNoble);
|
|
66
66
|
});
|
|
67
67
|
}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var index = require('./index-
|
|
3
|
+
var index = require('./index-e2e3d2ba.js');
|
|
4
4
|
var hdShared = require('@onekeyfe/hd-shared');
|
|
5
5
|
var pRetry = require('p-retry');
|
|
6
6
|
|
|
@@ -123,6 +123,13 @@ function assertBleActive() {
|
|
|
123
123
|
}
|
|
124
124
|
function createNobleBleConnectionError(error, messagePrefix = '') {
|
|
125
125
|
const errorMessage = error.message;
|
|
126
|
+
const isInvalidMacOsBond = error.nativeErrorCode === 14 && error.nativeErrorDomain === 'CBErrorDomain';
|
|
127
|
+
if (isInvalidMacOsBond) {
|
|
128
|
+
const nativeErrorMessage = `${messagePrefix}${errorMessage}`;
|
|
129
|
+
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleBondInvalid, `${hdShared.HardwareErrorCodeMessage[hdShared.HardwareErrorCode.BleBondInvalid]} (${nativeErrorMessage})`, {
|
|
130
|
+
nativeErrorMessage,
|
|
131
|
+
});
|
|
132
|
+
}
|
|
126
133
|
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleConnectedError, `${messagePrefix}${errorMessage}`);
|
|
127
134
|
}
|
|
128
135
|
function createNobleBleIpcErrorResponse(error) {
|
|
@@ -418,7 +425,7 @@ function initializeNoble() {
|
|
|
418
425
|
}
|
|
419
426
|
else if (state === 'unauthorized') {
|
|
420
427
|
cleanup();
|
|
421
|
-
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.
|
|
428
|
+
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BlePermissionError));
|
|
422
429
|
}
|
|
423
430
|
};
|
|
424
431
|
const cancel = () => {
|
|
@@ -427,7 +434,6 @@ function initializeNoble() {
|
|
|
427
434
|
};
|
|
428
435
|
pendingCancellations.add(cancel);
|
|
429
436
|
noble.on('stateChange', onStateChange);
|
|
430
|
-
onStateChange(noble.state);
|
|
431
437
|
});
|
|
432
438
|
assertBleActive();
|
|
433
439
|
if (!persistentDiscoverListener) {
|
|
@@ -440,7 +446,7 @@ function initializeNoble() {
|
|
|
440
446
|
}
|
|
441
447
|
catch (error) {
|
|
442
448
|
logger === null || logger === void 0 ? void 0 : logger.error('[NobleBLE] Failed to initialize Noble:', error);
|
|
443
|
-
bluetoothState.unsupported =
|
|
449
|
+
bluetoothState.unsupported = true;
|
|
444
450
|
bluetoothState.initialized = true;
|
|
445
451
|
throw error;
|
|
446
452
|
}
|
|
@@ -1170,7 +1176,8 @@ function setupConnectionAndDiscoverServices(peripheral, deviceId, webContents) {
|
|
|
1170
1176
|
yield forceReconnectPeripheral(peripheral, deviceId);
|
|
1171
1177
|
}
|
|
1172
1178
|
catch (resetError) {
|
|
1173
|
-
if ((resetError
|
|
1179
|
+
if (hdShared.isBleStaleBondHardwareError(resetError) ||
|
|
1180
|
+
(resetError === null || resetError === void 0 ? void 0 : resetError.errorCode) === hdShared.HardwareErrorCode.BleDeviceDisconnected) {
|
|
1174
1181
|
throw resetError;
|
|
1175
1182
|
}
|
|
1176
1183
|
logger === null || logger === void 0 ? void 0 : logger.error('[NobleBLE] Connection reset before discovery failed, continuing', resetError);
|
|
@@ -1306,17 +1313,29 @@ function connectDevice(deviceId, webContents) {
|
|
|
1306
1313
|
return undefined;
|
|
1307
1314
|
}
|
|
1308
1315
|
});
|
|
1316
|
+
let staleBondError;
|
|
1309
1317
|
const connectById = () => index.__awaiter(this, void 0, void 0, function* () {
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1318
|
+
try {
|
|
1319
|
+
const found = yield tryDirectConnectById(deviceId);
|
|
1320
|
+
if (found) {
|
|
1321
|
+
discoveredDevices.set(deviceId, found);
|
|
1322
|
+
}
|
|
1323
|
+
return found;
|
|
1324
|
+
}
|
|
1325
|
+
catch (error) {
|
|
1326
|
+
if (error.errorCode !== hdShared.HardwareErrorCode.BleBondInvalid) {
|
|
1327
|
+
throw error;
|
|
1328
|
+
}
|
|
1329
|
+
staleBondError = error;
|
|
1330
|
+
return undefined;
|
|
1313
1331
|
}
|
|
1314
|
-
return found;
|
|
1315
1332
|
});
|
|
1316
1333
|
peripheral = byIdFirst ? yield connectById() : yield scanForPeripheral();
|
|
1317
1334
|
if (!peripheral) {
|
|
1318
1335
|
peripheral = byIdFirst ? yield scanForPeripheral() : yield connectById();
|
|
1319
1336
|
}
|
|
1337
|
+
if (!peripheral && staleBondError)
|
|
1338
|
+
throw staleBondError;
|
|
1320
1339
|
}
|
|
1321
1340
|
assertBleActive();
|
|
1322
1341
|
if (!peripheral) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"noble-ble-handler.d.ts","sourceRoot":"","sources":["../src/noble-ble-handler.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"noble-ble-handler.d.ts","sourceRoot":"","sources":["../src/noble-ble-handler.ts"],"names":[],"mappings":"AAkCA,OAAO,KAAK,EAA+B,WAAW,EAAE,MAAM,UAAU,CAAC;AAEzE,OAAO,KAAK,EAAE,wBAAwB,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAiC1F,KAAK,mBAAmB,GAAG,KAAK,GAAG;IACjC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,mBAAmB,EAAE,aAAa,SAAK,+CAgB3F;AAED,wBAAgB,8BAA8B,CAAC,KAAK,EAAE,OAAO,GAAG,wBAAwB,CAgCvF;AA+KD,wBAAgB,+BAA+B,CAAC,OAAO,CAAC,EAAE,oBAAoB,UAI7E;AA2zDD,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI,CAkOpE;AAOD,wBAAgB,sBAAsB,CACpC,YAAY,GAAE,CAAC,QAAQ,EAAE;IAAE,IAAI,IAAI,IAAI,CAAA;CAAE,KAAK,IAAkC,GAC/E,OAAO,CAAC,IAAI,CAAC,CAiEf"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onekeyfe/hd-transport-electron",
|
|
3
|
-
"version": "1.2.8-alpha.
|
|
3
|
+
"version": "1.2.8-alpha.4",
|
|
4
4
|
"author": "OneKey",
|
|
5
5
|
"homepage": "https://github.com/OneKeyHQ/hardware-js-sdk#readme",
|
|
6
6
|
"license": "MIT",
|
|
@@ -25,9 +25,9 @@
|
|
|
25
25
|
"electron-log": ">=4.0.0"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@onekeyfe/hd-core": "1.2.8-alpha.
|
|
29
|
-
"@onekeyfe/hd-shared": "1.2.8-alpha.
|
|
30
|
-
"@onekeyfe/hd-transport": "1.2.8-alpha.
|
|
28
|
+
"@onekeyfe/hd-core": "1.2.8-alpha.4",
|
|
29
|
+
"@onekeyfe/hd-shared": "1.2.8-alpha.4",
|
|
30
|
+
"@onekeyfe/hd-transport": "1.2.8-alpha.4",
|
|
31
31
|
"@stoprocent/noble": "2.3.16",
|
|
32
32
|
"p-retry": "^4.6.2"
|
|
33
33
|
},
|
|
@@ -36,5 +36,5 @@
|
|
|
36
36
|
"electron": "^25.0.0",
|
|
37
37
|
"typescript": "^5.3.3"
|
|
38
38
|
},
|
|
39
|
-
"gitHead": "
|
|
39
|
+
"gitHead": "82fcab32fa1a37d1b82f73da825e39360624e0c9"
|
|
40
40
|
}
|
|
@@ -31,17 +31,22 @@ describe('Electron Noble BLE device discovery', () => {
|
|
|
31
31
|
expect(NOBLE_BLE_SUBSCRIBE_TIMEOUT_MS).toBe(10_000);
|
|
32
32
|
});
|
|
33
33
|
|
|
34
|
-
test('maps
|
|
34
|
+
test('maps structured macOS stale pairing failures without parsing localized text', async () => {
|
|
35
35
|
const { createNobleBleConnectionError } = await import('../noble-ble-handler');
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
37
|
+
const staleBondError = createNobleBleConnectionError(
|
|
38
|
+
Object.assign(new Error('Peer removed pairing information on the device side'), {
|
|
39
|
+
nativeErrorCode: 14,
|
|
40
|
+
nativeErrorDomain: 'CBErrorDomain',
|
|
41
|
+
})
|
|
42
|
+
);
|
|
43
|
+
expect(staleBondError).toMatchObject({
|
|
44
|
+
errorCode: HardwareErrorCode.BleBondInvalid,
|
|
45
|
+
params: {
|
|
46
|
+
nativeErrorMessage: 'Peer removed pairing information on the device side',
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
expect(staleBondError.message).toContain('Peer removed pairing information on the device side');
|
|
45
50
|
expect(createNobleBleConnectionError(new Error('Encryption is insufficient'))).toMatchObject({
|
|
46
51
|
errorCode: HardwareErrorCode.BleConnectedError,
|
|
47
52
|
});
|
|
@@ -76,16 +81,18 @@ describe('Electron Noble BLE device discovery', () => {
|
|
|
76
81
|
expect(
|
|
77
82
|
createNobleBleIpcErrorResponse({
|
|
78
83
|
name: 'HardwareError',
|
|
79
|
-
message: 'Bluetooth
|
|
80
|
-
errorCode: HardwareErrorCode.
|
|
84
|
+
message: 'Bluetooth pairing information is no longer valid',
|
|
85
|
+
errorCode: HardwareErrorCode.BleBondInvalid,
|
|
86
|
+
params: { nativeErrorMessage: 'native message' },
|
|
81
87
|
})
|
|
82
88
|
).toEqual({
|
|
83
89
|
type: 'NobleBleIpcError',
|
|
84
90
|
success: false,
|
|
85
91
|
error: {
|
|
86
92
|
name: 'HardwareError',
|
|
87
|
-
message: 'Bluetooth
|
|
88
|
-
errorCode: HardwareErrorCode.
|
|
93
|
+
message: 'Bluetooth pairing information is no longer valid',
|
|
94
|
+
errorCode: HardwareErrorCode.BleBondInvalid,
|
|
95
|
+
params: { nativeErrorMessage: 'native message' },
|
|
89
96
|
},
|
|
90
97
|
});
|
|
91
98
|
|
|
@@ -128,14 +135,14 @@ describe('Electron Noble BLE device discovery', () => {
|
|
|
128
135
|
success: false as const,
|
|
129
136
|
error: {
|
|
130
137
|
name: 'HardwareError',
|
|
131
|
-
message: 'Bluetooth
|
|
132
|
-
errorCode: HardwareErrorCode.
|
|
138
|
+
message: 'Bluetooth pairing information is no longer valid',
|
|
139
|
+
errorCode: HardwareErrorCode.BleBondInvalid,
|
|
133
140
|
},
|
|
134
141
|
})
|
|
135
142
|
)
|
|
136
143
|
).rejects.toMatchObject({
|
|
137
144
|
name: 'HardwareError',
|
|
138
|
-
errorCode: HardwareErrorCode.
|
|
145
|
+
errorCode: HardwareErrorCode.BleBondInvalid,
|
|
139
146
|
});
|
|
140
147
|
|
|
141
148
|
await expect(invokeNobleBleIpc(Promise.resolve('connected'))).resolves.toBe('connected');
|
|
@@ -345,6 +352,87 @@ describe('Electron Noble BLE device discovery', () => {
|
|
|
345
352
|
}
|
|
346
353
|
);
|
|
347
354
|
|
|
355
|
+
test.each([
|
|
356
|
+
{ rediscovered: false, expectedCode: HardwareErrorCode.BleBondInvalid },
|
|
357
|
+
{ rediscovered: true, expectedCode: HardwareErrorCode.BleConnectedError },
|
|
358
|
+
])(
|
|
359
|
+
'reports a macOS stale bond only when fallback scan misses (rediscovered=$rediscovered)',
|
|
360
|
+
async ({ rediscovered, expectedCode }) => {
|
|
361
|
+
jest.useFakeTimers({ doNotFake: ['performance'] });
|
|
362
|
+
const handlers = new Map<string, IpcHandler>();
|
|
363
|
+
const stalePeripheral = createPeripheral('device', 'Pro2 A1B2');
|
|
364
|
+
const freshPeripheral = Object.assign(
|
|
365
|
+
new EventEmitter(),
|
|
366
|
+
createPeripheral('device', 'Pro2 A1B2'),
|
|
367
|
+
{
|
|
368
|
+
connect: jest.fn((callback: (error?: Error) => void) => {
|
|
369
|
+
callback(new Error('fresh connection failed'));
|
|
370
|
+
}),
|
|
371
|
+
}
|
|
372
|
+
);
|
|
373
|
+
const staleBondError = Object.assign(new Error('Peer removed pairing information'), {
|
|
374
|
+
nativeErrorCode: 14,
|
|
375
|
+
nativeErrorDomain: 'CBErrorDomain',
|
|
376
|
+
});
|
|
377
|
+
let scanStarted: (() => void) | undefined;
|
|
378
|
+
const scanning = new Promise<void>(resolve => {
|
|
379
|
+
scanStarted = resolve;
|
|
380
|
+
});
|
|
381
|
+
const noble = Object.assign(new EventEmitter(), {
|
|
382
|
+
state: 'poweredOn',
|
|
383
|
+
startScanning: jest.fn((_services, _duplicates, callback) => {
|
|
384
|
+
callback?.();
|
|
385
|
+
if (rediscovered) noble.emit('discover', freshPeripheral);
|
|
386
|
+
scanStarted?.();
|
|
387
|
+
}),
|
|
388
|
+
stopScanning: jest.fn(callback => callback?.()),
|
|
389
|
+
connectAsync: jest.fn(() => Promise.reject(staleBondError)),
|
|
390
|
+
});
|
|
391
|
+
jest.doMock('@stoprocent/noble', () => noble);
|
|
392
|
+
jest.doMock('electron', () => ({
|
|
393
|
+
ipcMain: {
|
|
394
|
+
handle: (channel: string, handler: IpcHandler) => handlers.set(channel, handler),
|
|
395
|
+
removeHandler: (channel: string) => handlers.delete(channel),
|
|
396
|
+
},
|
|
397
|
+
}));
|
|
398
|
+
jest.doMock('electron-log', () => ({
|
|
399
|
+
info: jest.fn(),
|
|
400
|
+
debug: jest.fn(),
|
|
401
|
+
error: jest.fn(),
|
|
402
|
+
}));
|
|
403
|
+
const { setupNobleBleHandlers } = await import('../noble-ble-handler');
|
|
404
|
+
setupNobleBleHandlers({ on: jest.fn(), send: jest.fn() } as unknown as WebContents);
|
|
405
|
+
const availability = handlers.get(EOneKeyBleMessageKeys.BLE_AVAILABILITY_CHECK);
|
|
406
|
+
const connect = handlers.get(EOneKeyBleMessageKeys.NOBLE_BLE_CONNECT);
|
|
407
|
+
if (!availability || !connect) throw new Error('Noble handlers were not registered');
|
|
408
|
+
await availability();
|
|
409
|
+
noble.emit('discover', stalePeripheral);
|
|
410
|
+
|
|
411
|
+
const connecting = Promise.resolve(connect(undefined, stalePeripheral.id));
|
|
412
|
+
await scanning;
|
|
413
|
+
jest.advanceTimersByTime(1500);
|
|
414
|
+
await expect(connecting).resolves.toMatchObject({
|
|
415
|
+
success: false,
|
|
416
|
+
error: { errorCode: expectedCode },
|
|
417
|
+
});
|
|
418
|
+
if (!rediscovered) {
|
|
419
|
+
const secondScan = new Promise<void>(resolve => {
|
|
420
|
+
scanStarted = resolve;
|
|
421
|
+
});
|
|
422
|
+
const retry = Promise.resolve(connect(undefined, stalePeripheral.id));
|
|
423
|
+
await secondScan;
|
|
424
|
+
jest.advanceTimersByTime(1500);
|
|
425
|
+
await expect(retry).resolves.toMatchObject({
|
|
426
|
+
success: false,
|
|
427
|
+
error: { errorCode: HardwareErrorCode.BleBondInvalid },
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
expect(noble.connectAsync).toHaveBeenCalledTimes(rediscovered ? 1 : 2);
|
|
431
|
+
expect(noble.startScanning).toHaveBeenCalledTimes(rediscovered ? 1 : 2);
|
|
432
|
+
expect(freshPeripheral.connect).toHaveBeenCalledTimes(rediscovered ? 1 : 0);
|
|
433
|
+
}
|
|
434
|
+
);
|
|
435
|
+
|
|
348
436
|
test('waits for a targeted scan to stop before connecting', async () => {
|
|
349
437
|
jest.useFakeTimers({ doNotFake: ['performance'] });
|
|
350
438
|
|
|
@@ -918,28 +1006,6 @@ describe('Noble BLE process shutdown', () => {
|
|
|
918
1006
|
expect(handlers.size).toBe(0);
|
|
919
1007
|
});
|
|
920
1008
|
|
|
921
|
-
test.each([
|
|
922
|
-
['poweredOff', HardwareErrorCode.BlePoweredOff],
|
|
923
|
-
['unauthorized', HardwareErrorCode.BleLocationError],
|
|
924
|
-
['unsupported', HardwareErrorCode.BleUnsupported],
|
|
925
|
-
])(
|
|
926
|
-
'classifies the initial adapter state %s without waiting for another event',
|
|
927
|
-
async (state, errorCode) => {
|
|
928
|
-
jest.useFakeTimers({ doNotFake: ['performance'] });
|
|
929
|
-
const { sdk, native, handlers } = await setup(state);
|
|
930
|
-
await expect(
|
|
931
|
-
handlers.get(EOneKeyBleMessageKeys.NOBLE_BLE_ENUMERATE)?.({})
|
|
932
|
-
).resolves.toMatchObject({
|
|
933
|
-
success: false,
|
|
934
|
-
error: { errorCode },
|
|
935
|
-
});
|
|
936
|
-
expect(native.startScanning).not.toHaveBeenCalled();
|
|
937
|
-
expect(native.listenerCount('stateChange')).toBe(1);
|
|
938
|
-
expect(jest.getTimerCount()).toBe(0);
|
|
939
|
-
await sdk.disposeNobleBleSupport();
|
|
940
|
-
}
|
|
941
|
-
);
|
|
942
|
-
|
|
943
1009
|
test('cancels an active scan, ignores its late callback and releases native once', async () => {
|
|
944
1010
|
jest.useFakeTimers({ doNotFake: ['performance'] });
|
|
945
1011
|
const { sdk, native, handlers } = await setup();
|
package/src/noble-ble-handler.ts
CHANGED
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
ONEKEY_WRITE_CHARACTERISTIC_UUID,
|
|
17
17
|
createKnownBleUuidAliases,
|
|
18
18
|
hasOnekeyCommunicationService,
|
|
19
|
+
isBleStaleBondHardwareError,
|
|
19
20
|
isOnekeyBluetoothDevice,
|
|
20
21
|
isPro2FamilyBleName,
|
|
21
22
|
matchesKnownBleUuid,
|
|
@@ -73,6 +74,19 @@ type NobleBleNativeError = Error & {
|
|
|
73
74
|
|
|
74
75
|
export function createNobleBleConnectionError(error: NobleBleNativeError, messagePrefix = '') {
|
|
75
76
|
const errorMessage = error.message;
|
|
77
|
+
const isInvalidMacOsBond =
|
|
78
|
+
error.nativeErrorCode === 14 && error.nativeErrorDomain === 'CBErrorDomain';
|
|
79
|
+
if (isInvalidMacOsBond) {
|
|
80
|
+
const nativeErrorMessage = `${messagePrefix}${errorMessage}`;
|
|
81
|
+
return ERRORS.TypedError(
|
|
82
|
+
HardwareErrorCode.BleBondInvalid,
|
|
83
|
+
`${HardwareErrorCodeMessage[HardwareErrorCode.BleBondInvalid]} (${nativeErrorMessage})`,
|
|
84
|
+
{
|
|
85
|
+
nativeErrorMessage,
|
|
86
|
+
}
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
76
90
|
return ERRORS.TypedError(HardwareErrorCode.BleConnectedError, `${messagePrefix}${errorMessage}`);
|
|
77
91
|
}
|
|
78
92
|
|
|
@@ -482,7 +496,7 @@ async function initializeNoble(): Promise<void> {
|
|
|
482
496
|
reject(ERRORS.TypedError(HardwareErrorCode.BlePoweredOff));
|
|
483
497
|
} else if (state === 'unauthorized') {
|
|
484
498
|
cleanup();
|
|
485
|
-
reject(ERRORS.TypedError(HardwareErrorCode.
|
|
499
|
+
reject(ERRORS.TypedError(HardwareErrorCode.BlePermissionError));
|
|
486
500
|
}
|
|
487
501
|
};
|
|
488
502
|
|
|
@@ -494,7 +508,6 @@ async function initializeNoble(): Promise<void> {
|
|
|
494
508
|
};
|
|
495
509
|
pendingCancellations.add(cancel);
|
|
496
510
|
noble.on('stateChange', onStateChange);
|
|
497
|
-
onStateChange(noble.state);
|
|
498
511
|
});
|
|
499
512
|
|
|
500
513
|
assertBleActive();
|
|
@@ -509,7 +522,7 @@ async function initializeNoble(): Promise<void> {
|
|
|
509
522
|
logger?.info('[NobleBLE] Noble initialized successfully');
|
|
510
523
|
} catch (error) {
|
|
511
524
|
logger?.error('[NobleBLE] Failed to initialize Noble:', error);
|
|
512
|
-
bluetoothState.unsupported =
|
|
525
|
+
bluetoothState.unsupported = true;
|
|
513
526
|
bluetoothState.initialized = true;
|
|
514
527
|
throw error;
|
|
515
528
|
}
|
|
@@ -1621,6 +1634,7 @@ async function setupConnectionAndDiscoverServices(
|
|
|
1621
1634
|
await forceReconnectPeripheral(peripheral, deviceId);
|
|
1622
1635
|
} catch (resetError) {
|
|
1623
1636
|
if (
|
|
1637
|
+
isBleStaleBondHardwareError(resetError) ||
|
|
1624
1638
|
(resetError as { errorCode?: unknown })?.errorCode === HardwareErrorCode.BleDeviceDisconnected
|
|
1625
1639
|
) {
|
|
1626
1640
|
throw resetError;
|
|
@@ -1798,12 +1812,21 @@ async function connectDevice(deviceId: string, webContents: WebContents): Promis
|
|
|
1798
1812
|
}
|
|
1799
1813
|
};
|
|
1800
1814
|
|
|
1815
|
+
let staleBondError: Error | undefined;
|
|
1801
1816
|
const connectById = async () => {
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1817
|
+
try {
|
|
1818
|
+
const found = await tryDirectConnectById(deviceId);
|
|
1819
|
+
if (found) {
|
|
1820
|
+
discoveredDevices.set(deviceId, found);
|
|
1821
|
+
}
|
|
1822
|
+
return found;
|
|
1823
|
+
} catch (error) {
|
|
1824
|
+
if ((error as { errorCode?: number }).errorCode !== HardwareErrorCode.BleBondInvalid) {
|
|
1825
|
+
throw error;
|
|
1826
|
+
}
|
|
1827
|
+
staleBondError = error as Error;
|
|
1828
|
+
return undefined;
|
|
1805
1829
|
}
|
|
1806
|
-
return found;
|
|
1807
1830
|
};
|
|
1808
1831
|
|
|
1809
1832
|
peripheral = byIdFirst ? await connectById() : await scanForPeripheral();
|
|
@@ -1812,6 +1835,7 @@ async function connectDevice(deviceId: string, webContents: WebContents): Promis
|
|
|
1812
1835
|
// silent), or not reachable by id. Try the other one before giving up.
|
|
1813
1836
|
peripheral = byIdFirst ? await scanForPeripheral() : await connectById();
|
|
1814
1837
|
}
|
|
1838
|
+
if (!peripheral && staleBondError) throw staleBondError;
|
|
1815
1839
|
}
|
|
1816
1840
|
|
|
1817
1841
|
assertBleActive();
|