@stoprocent/noble 2.5.0 → 2.5.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.
@@ -49,6 +49,13 @@ function loadDbus () {
49
49
  }
50
50
  }
51
51
 
52
+ function normalizeId (id) {
53
+ // BlueZ emits MACs uppercase; noble's id form is colon-stripped lowercase.
54
+ // Accept either, plus mixed case, so external callers don't have to care.
55
+ if (id == null) return id;
56
+ return String(id).replace(/:/g, '').toLowerCase();
57
+ }
58
+
52
59
  function unwrapVariant (variant) {
53
60
  if (variant && typeof variant === 'object' && 'value' in variant && 'signature' in variant) {
54
61
  return variant.value;
@@ -485,6 +492,7 @@ class DbusBindings extends EventEmitter {
485
492
  // ---- Connect / disconnect ----
486
493
 
487
494
  connect (peripheralUuid, _parameters) {
495
+ peripheralUuid = normalizeId(peripheralUuid);
488
496
  this._connect(peripheralUuid).catch(err => {
489
497
  this.emit('connect', peripheralUuid, err);
490
498
  });
@@ -518,10 +526,11 @@ class DbusBindings extends EventEmitter {
518
526
  }
519
527
 
520
528
  cancelConnect (peripheralUuid, _parameters) {
521
- this.disconnect(peripheralUuid);
529
+ this.disconnect(normalizeId(peripheralUuid));
522
530
  }
523
531
 
524
532
  disconnect (peripheralUuid) {
533
+ peripheralUuid = normalizeId(peripheralUuid);
525
534
  this._disconnect(peripheralUuid).catch(err => {
526
535
  this.emit('warning', `disconnect failed: ${err.message}`);
527
536
  });
@@ -540,6 +549,7 @@ class DbusBindings extends EventEmitter {
540
549
  }
541
550
 
542
551
  updateRssi (peripheralUuid) {
552
+ peripheralUuid = normalizeId(peripheralUuid);
543
553
  const device = this._devices.get(peripheralUuid);
544
554
  if (!device || !device.path) {
545
555
  this.emit('rssiUpdate', peripheralUuid, 0, new Error('unknown peripheral'));
@@ -596,6 +606,7 @@ class DbusBindings extends EventEmitter {
596
606
  }
597
607
 
598
608
  discoverServices (peripheralUuid, uuids) {
609
+ peripheralUuid = normalizeId(peripheralUuid);
599
610
  const wanted = (uuids || []).map(normalizeUuid);
600
611
  const found = this._findServicesForDevice(peripheralUuid);
601
612
  const filtered = wanted.length === 0 ? found : found.filter(s => wanted.includes(s.uuid));
@@ -605,11 +616,13 @@ class DbusBindings extends EventEmitter {
605
616
  }
606
617
 
607
618
  discoverIncludedServices (peripheralUuid, serviceUuid, _serviceUuids) {
619
+ peripheralUuid = normalizeId(peripheralUuid);
608
620
  // BlueZ does not expose included services directly via D-Bus.
609
621
  this.emit('includedServicesDiscover', peripheralUuid, serviceUuid, []);
610
622
  }
611
623
 
612
624
  discoverCharacteristics (peripheralUuid, serviceUuid, characteristicUuids) {
625
+ peripheralUuid = normalizeId(peripheralUuid);
613
626
  const services = this._findServicesForDevice(peripheralUuid);
614
627
  const service = services.find(s => s.uuid === normalizeUuid(serviceUuid));
615
628
  if (!service) {
@@ -642,6 +655,7 @@ class DbusBindings extends EventEmitter {
642
655
  }
643
656
 
644
657
  read (peripheralUuid, serviceUuid, characteristicUuid) {
658
+ peripheralUuid = normalizeId(peripheralUuid);
645
659
  this._readChar(peripheralUuid, serviceUuid, characteristicUuid).catch(err => {
646
660
  this.emit('read', peripheralUuid, serviceUuid, characteristicUuid, null, false, err);
647
661
  });
@@ -658,6 +672,7 @@ class DbusBindings extends EventEmitter {
658
672
  }
659
673
 
660
674
  write (peripheralUuid, serviceUuid, characteristicUuid, data, withoutResponse) {
675
+ peripheralUuid = normalizeId(peripheralUuid);
661
676
  this._writeChar(peripheralUuid, serviceUuid, characteristicUuid, data, withoutResponse).catch(err => {
662
677
  this.emit('write', peripheralUuid, serviceUuid, characteristicUuid, err);
663
678
  });
@@ -676,11 +691,13 @@ class DbusBindings extends EventEmitter {
676
691
  }
677
692
 
678
693
  broadcast (peripheralUuid, serviceUuid, characteristicUuid, _broadcast) {
694
+ peripheralUuid = normalizeId(peripheralUuid);
679
695
  this.emit('warning', 'broadcast is not supported on the dbus backend');
680
696
  this.emit('broadcast', peripheralUuid, serviceUuid, characteristicUuid, false);
681
697
  }
682
698
 
683
699
  notify (peripheralUuid, serviceUuid, characteristicUuid, notify) {
700
+ peripheralUuid = normalizeId(peripheralUuid);
684
701
  this._setNotify(peripheralUuid, serviceUuid, characteristicUuid, notify).catch(err => {
685
702
  this.emit('notify', peripheralUuid, serviceUuid, characteristicUuid, false, err);
686
703
  });
@@ -724,6 +741,7 @@ class DbusBindings extends EventEmitter {
724
741
  }
725
742
 
726
743
  discoverDescriptors (peripheralUuid, serviceUuid, characteristicUuid) {
744
+ peripheralUuid = normalizeId(peripheralUuid);
727
745
  const charPath = this._findCharacteristicPath(peripheralUuid, serviceUuid, characteristicUuid);
728
746
  if (!charPath) {
729
747
  this.emit('descriptorsDiscover', peripheralUuid, serviceUuid, characteristicUuid, [], new Error('characteristic not found'));
@@ -734,6 +752,7 @@ class DbusBindings extends EventEmitter {
734
752
  }
735
753
 
736
754
  readValue (peripheralUuid, serviceUuid, characteristicUuid, descriptorUuid) {
755
+ peripheralUuid = normalizeId(peripheralUuid);
737
756
  this._readDesc(peripheralUuid, serviceUuid, characteristicUuid, descriptorUuid).catch(err => {
738
757
  this.emit('valueRead', peripheralUuid, serviceUuid, characteristicUuid, descriptorUuid, null, err);
739
758
  });
@@ -750,6 +769,7 @@ class DbusBindings extends EventEmitter {
750
769
  }
751
770
 
752
771
  writeValue (peripheralUuid, serviceUuid, characteristicUuid, descriptorUuid, data) {
772
+ peripheralUuid = normalizeId(peripheralUuid);
753
773
  this._writeDesc(peripheralUuid, serviceUuid, characteristicUuid, descriptorUuid, data).catch(err => {
754
774
  this.emit('valueWrite', peripheralUuid, serviceUuid, characteristicUuid, descriptorUuid, err);
755
775
  });
@@ -766,11 +786,13 @@ class DbusBindings extends EventEmitter {
766
786
  }
767
787
 
768
788
  readHandle (peripheralUuid, handle) {
789
+ peripheralUuid = normalizeId(peripheralUuid);
769
790
  const err = new Error('readHandle is not supported on the dbus backend (BlueZ exposes UUIDs only)');
770
791
  this.emit('handleRead', peripheralUuid, handle, null, err);
771
792
  }
772
793
 
773
794
  writeHandle (peripheralUuid, handle, _data, _withoutResponse) {
795
+ peripheralUuid = normalizeId(peripheralUuid);
774
796
  const err = new Error('writeHandle is not supported on the dbus backend (BlueZ exposes UUIDs only)');
775
797
  this.emit('handleWrite', peripheralUuid, handle, err);
776
798
  }
package/package.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "license": "MIT",
7
7
  "name": "@stoprocent/noble",
8
8
  "description": "A Node.js BLE (Bluetooth Low Energy) central library.",
9
- "version": "2.5.0",
9
+ "version": "2.5.1",
10
10
  "repository": {
11
11
  "type": "git",
12
12
  "url": "https://github.com/stoprocent/noble.git"
@@ -36,6 +36,14 @@
36
36
  "optionalDependencies": {
37
37
  "@stoprocent/bluetooth-hci-socket": "^2.2.6"
38
38
  },
39
+ "peerDependencies": {
40
+ "dbus-next": "^0.10.0"
41
+ },
42
+ "peerDependenciesMeta": {
43
+ "dbus-next": {
44
+ "optional": true
45
+ }
46
+ },
39
47
  "devDependencies": {
40
48
  "@babel/eslint-parser": "^7.27.0",
41
49
  "@commitlint/cli": "^19.3.0",
@@ -409,4 +409,75 @@ describe('dbus/bindings', () => {
409
409
  const bindings = new DbusBindings();
410
410
  expect(bindings.addressToId('AA:BB:CC:DD:EE:FF')).toBe('aabbccddeeff');
411
411
  });
412
+
413
+ describe('peripheral id normalization on public methods', () => {
414
+ const tree = () => adapterTree({
415
+ '/org/bluez/hci0/dev_AA_BB_CC_DD_EE_FF': {
416
+ 'org.bluez.Device1': { Address: 'AA:BB:CC:DD:EE:FF', AddressType: 'public', Connected: false }
417
+ },
418
+ '/org/bluez/hci0/dev_AA_BB_CC_DD_EE_FF/service0001': {
419
+ 'org.bluez.GattService1': { UUID: '0000180d-0000-1000-8000-00805f9b34fb', Primary: true }
420
+ },
421
+ '/org/bluez/hci0/dev_AA_BB_CC_DD_EE_FF/service0001/char0002': {
422
+ 'org.bluez.GattCharacteristic1': {
423
+ UUID: '00002a37-0000-1000-8000-00805f9b34fb',
424
+ Flags: ['read', 'notify']
425
+ }
426
+ }
427
+ });
428
+
429
+ const variants = [
430
+ ['canonical id', 'aabbccddeeff'],
431
+ ['uppercase id', 'AABBCCDDEEFF'],
432
+ ['mixed-case id', 'AaBbCcDdEeFf'],
433
+ ['colon MAC uppercase', 'AA:BB:CC:DD:EE:FF'],
434
+ ['colon MAC lowercase', 'aa:bb:cc:dd:ee:ff'],
435
+ ['colon MAC mixed', 'Aa:Bb:Cc:Dd:Ee:Ff']
436
+ ];
437
+
438
+ test.each(variants)('discoverServices accepts %s and emits canonical id', async (_label, input) => {
439
+ resetState(tree());
440
+ const bindings = new DbusBindings();
441
+ bindings.start();
442
+ await flush();
443
+
444
+ const services = [];
445
+ bindings.on('servicesDiscover', (...a) => services.push(a));
446
+
447
+ bindings.discoverServices(input, []);
448
+
449
+ expect(services[0]).toEqual(['aabbccddeeff', ['180d']]);
450
+ });
451
+
452
+ test.each(variants)('read accepts %s and emits canonical id', async (_label, input) => {
453
+ resetState(tree());
454
+ const bindings = new DbusBindings();
455
+ bindings.start();
456
+ await flush();
457
+
458
+ const reads = [];
459
+ bindings.on('read', (...a) => reads.push(a));
460
+
461
+ bindings.read(input, '180d', '2a37');
462
+ await flush();
463
+
464
+ expect(reads.length).toBe(1);
465
+ expect(reads[0][0]).toBe('aabbccddeeff');
466
+ });
467
+
468
+ test.each(variants)('readHandle (unsupported) emits canonical id for %s', (_label, input) => {
469
+ resetState(tree());
470
+ const bindings = new DbusBindings();
471
+ const events = [];
472
+ bindings.on('handleRead', (...a) => events.push(a));
473
+ bindings.readHandle(input, 0x42);
474
+ expect(events[0][0]).toBe('aabbccddeeff');
475
+ });
476
+
477
+ test('null/undefined peripheralUuid does not throw', () => {
478
+ const bindings = new DbusBindings();
479
+ expect(() => bindings.discoverServices(undefined, [])).not.toThrow();
480
+ expect(() => bindings.discoverServices(null, [])).not.toThrow();
481
+ });
482
+ });
412
483
  });