@stoprocent/bleno 0.7.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.
Files changed (77) hide show
  1. package/.jshintrc +5 -0
  2. package/LICENSE +20 -0
  3. package/README.md +409 -0
  4. package/binding.gyp +17 -0
  5. package/examples/battery-service/README.md +14 -0
  6. package/examples/battery-service/battery-level-characteristic.js +45 -0
  7. package/examples/battery-service/battery-service.js +16 -0
  8. package/examples/battery-service/main.js +28 -0
  9. package/examples/battery-service/package-lock.json +1314 -0
  10. package/examples/battery-service/package.json +20 -0
  11. package/examples/blink1/README.md +44 -0
  12. package/examples/blink1/blink1-fade-rgb-characteristic.js +42 -0
  13. package/examples/blink1/blink1-rgb-characteristic.js +38 -0
  14. package/examples/blink1/blink1-service.js +19 -0
  15. package/examples/blink1/device-information-service.js +19 -0
  16. package/examples/blink1/hardware-revision-characteristic.js +32 -0
  17. package/examples/blink1/main.js +32 -0
  18. package/examples/blink1/serial-number-characteristic.js +21 -0
  19. package/examples/echo/characteristic.js +45 -0
  20. package/examples/echo/main.js +33 -0
  21. package/examples/pizza/README.md +16 -0
  22. package/examples/pizza/peripheral.js +57 -0
  23. package/examples/pizza/pizza-bake-characteristic.js +40 -0
  24. package/examples/pizza/pizza-crust-characteristic.js +52 -0
  25. package/examples/pizza/pizza-service.js +20 -0
  26. package/examples/pizza/pizza-toppings-characteristic.js +41 -0
  27. package/examples/pizza/pizza.js +58 -0
  28. package/examples/uart/main.js +23 -0
  29. package/index.d.ts +153 -0
  30. package/index.js +1 -0
  31. package/lib/bleno.js +231 -0
  32. package/lib/characteristic.js +91 -0
  33. package/lib/descriptor.js +17 -0
  34. package/lib/hci-socket/acl-stream.js +37 -0
  35. package/lib/hci-socket/bindings.js +219 -0
  36. package/lib/hci-socket/crypto.js +74 -0
  37. package/lib/hci-socket/gap.js +212 -0
  38. package/lib/hci-socket/gatt.js +1028 -0
  39. package/lib/hci-socket/hci-status.json +67 -0
  40. package/lib/hci-socket/hci.js +796 -0
  41. package/lib/hci-socket/mgmt.js +89 -0
  42. package/lib/hci-socket/smp.js +160 -0
  43. package/lib/hci-socket/vs.js +156 -0
  44. package/lib/mac/binding.gyp +39 -0
  45. package/lib/mac/bindings.js +12 -0
  46. package/lib/mac/src/ble_peripheral_manager.h +32 -0
  47. package/lib/mac/src/ble_peripheral_manager.mm +241 -0
  48. package/lib/mac/src/bleno_mac.h +26 -0
  49. package/lib/mac/src/bleno_mac.mm +167 -0
  50. package/lib/mac/src/callbacks.h +76 -0
  51. package/lib/mac/src/callbacks.mm +124 -0
  52. package/lib/mac/src/napi_objc.h +30 -0
  53. package/lib/mac/src/napi_objc.mm +286 -0
  54. package/lib/mac/src/noble_mac.h +34 -0
  55. package/lib/mac/src/noble_mac.mm +260 -0
  56. package/lib/mac/src/objc_cpp.h +27 -0
  57. package/lib/mac/src/objc_cpp.mm +144 -0
  58. package/lib/mac/src/peripheral.h +23 -0
  59. package/lib/primary-service.js +19 -0
  60. package/lib/resolve-bindings.js +19 -0
  61. package/lib/uuid-util.js +7 -0
  62. package/package.json +77 -0
  63. package/prebuilds/android-arm/node.napi.armv7.node +0 -0
  64. package/prebuilds/android-arm64/node.napi.armv8.node +0 -0
  65. package/prebuilds/darwin-x64+arm64/node.napi.node +0 -0
  66. package/prebuilds/linux-arm/node.napi.armv6.node +0 -0
  67. package/prebuilds/linux-arm/node.napi.armv7.node +0 -0
  68. package/prebuilds/linux-arm64/node.napi.armv8.node +0 -0
  69. package/prebuilds/linux-x64/node.napi.glibc.node +0 -0
  70. package/prebuilds/linux-x64/node.napi.musl.node +0 -0
  71. package/prebuilds/win32-ia32/node.napi.node +0 -0
  72. package/prebuilds/win32-x64/node.napi.node +0 -0
  73. package/test/characteristic.test.js +174 -0
  74. package/test/descriptor.test.js +46 -0
  75. package/test/mocha.setup.js +0 -0
  76. package/with-bindings.js +5 -0
  77. package/with-custom-binding.js +6 -0
@@ -0,0 +1,144 @@
1
+ //
2
+ // objc_cpp.mm
3
+ // bleno-mac-native
4
+ //
5
+ // Created by Georg Vienna on 30.08.18.
6
+ //
7
+ #include "objc_cpp.h"
8
+
9
+ #if defined(MAC_OS_X_VERSION_10_13)
10
+ //#pragma clang diagnostic push
11
+ //#pragma clang diagnostic ignored "-Wunguarded-availability"
12
+ //std::string stateToString(CBManagerState state)
13
+ //{
14
+ // switch(state) {
15
+ // case CBManagerStatePoweredOff:
16
+ // return "poweredOff";
17
+ // case CBManagerStatePoweredOn:
18
+ // return "poweredOn";
19
+ // case CBManagerStateResetting:
20
+ // return "resetting";
21
+ // case CBManagerStateUnauthorized:
22
+ // return "unauthorized";
23
+ // case CBManagerStateUnknown:
24
+ // return "unknown";
25
+ // case CBManagerStateUnsupported:
26
+ // return "unsupported";
27
+ // }
28
+ // return "unknown";
29
+ //}
30
+ //#pragma clang diagnostic pop
31
+
32
+ // In the 10.13 SDK, CBPeripheral became a subclass of CBPeer, which defines
33
+ // -[CBPeer identifier] as partially available. Pretend it still exists on
34
+ // CBPeripheral. At runtime the implementation on CBPeer will be invoked.
35
+ @interface CBPeripheral (HighSierraSDK)
36
+ @property(readonly, nonatomic) NSUUID* identifier;
37
+ @end
38
+ #else
39
+ std::string stateToString(CBCentralManagerState state)
40
+ {
41
+ switch(state) {
42
+ case CBCentralManagerStatePoweredOff:
43
+ return "poweredOff";
44
+ case CBCentralManagerStatePoweredOn:
45
+ return "poweredOn";
46
+ case CBCentralManagerStateResetting:
47
+ return "resetting";
48
+ case CBCentralManagerStateUnauthorized:
49
+ return "unauthorized";
50
+ case CBCentralManagerStateUnknown:
51
+ return "unknown";
52
+ case CBCentralManagerStateUnsupported:
53
+ return "unsupported";
54
+ }
55
+ return "unknown";
56
+ }
57
+ #endif
58
+
59
+ std::string StringFromCBPeripheralState(CBManagerState state) {
60
+ switch(state) {
61
+ case CBManagerStatePoweredOff:
62
+ return "poweredOff";
63
+ case CBManagerStatePoweredOn:
64
+ return "poweredOn";
65
+ case CBManagerStateUnauthorized:
66
+ return "unauthorized";
67
+ case CBManagerStateUnsupported:
68
+ return "unsupported";
69
+ case CBManagerStateResetting:
70
+ return "resetting";
71
+ case CBManagerStateUnknown:
72
+ default:
73
+ return "unknown";
74
+ }
75
+ }
76
+
77
+ NSString* getNSUuid(CBPeripheral* peripheral) {
78
+ return peripheral.identifier.UUIDString;
79
+ }
80
+
81
+ std::string getUuid(CBPeripheral* peripheral) {
82
+ return std::string([peripheral.identifier.UUIDString UTF8String]);
83
+ }
84
+
85
+ std::string getAddress(std::string uuid, AddressType* addressType) {
86
+ NSString* deviceUuid = [[NSString alloc] initWithCString:uuid.c_str() encoding:NSASCIIStringEncoding];
87
+ IF(NSDictionary*, plist, [NSDictionary dictionaryWithContentsOfFile:@"/Library/Preferences/com.apple.Bluetooth.plist"]) {
88
+ IF(NSDictionary*, cache, [plist objectForKey:@"CoreBluetoothCache"]) {
89
+ IF(NSDictionary*, entry, [cache objectForKey:deviceUuid]) {
90
+ IF(NSNumber*, type, [entry objectForKey:@"DeviceAddressType"]) {
91
+ *addressType = [type boolValue] ? RANDOM : PUBLIC;
92
+ }
93
+ IF(NSString*, address, [entry objectForKey:@"DeviceAddress"]) {
94
+ return [address UTF8String];
95
+ }
96
+ }
97
+ }
98
+ }
99
+ return "";
100
+ }
101
+
102
+ std::vector<std::string> getServices(NSArray<CBService*>* services) {
103
+ std::vector<std::string> result;
104
+ if(services) {
105
+ for (CBService* service in services) {
106
+ result.push_back([[service.UUID UUIDString] UTF8String]);
107
+ }
108
+ }
109
+ return result;
110
+ }
111
+
112
+ #define TEST_PROP(type, str) if((characteristic.properties & type) == type) { properties.push_back(str); }
113
+
114
+ std::vector<std::pair<std::string, std::vector<std::string>>> getCharacteristics(NSArray<CBCharacteristic*>* characteristics) {
115
+ std::vector<std::pair<std::string, std::vector<std::string>>> result;
116
+ if(characteristics) {
117
+ for (CBCharacteristic* characteristic in characteristics) {
118
+ auto uuid = [[characteristic.UUID UUIDString] UTF8String];
119
+ auto properties = std::vector<std::string>();
120
+ TEST_PROP(CBCharacteristicPropertyBroadcast, "broadcast");
121
+ TEST_PROP(CBCharacteristicPropertyRead, "read");
122
+ TEST_PROP(CBCharacteristicPropertyWriteWithoutResponse, "writeWithoutResponse");
123
+ TEST_PROP(CBCharacteristicPropertyWrite, "write");
124
+ TEST_PROP(CBCharacteristicPropertyNotify, "notify");
125
+ TEST_PROP(CBCharacteristicPropertyIndicate, "indicate");
126
+ TEST_PROP(CBCharacteristicPropertyAuthenticatedSignedWrites, "authenticatedSignedWrites");
127
+ TEST_PROP(CBCharacteristicPropertyExtendedProperties, "extendedProperties");
128
+ TEST_PROP(CBCharacteristicPropertyNotifyEncryptionRequired, "notifyEncryptionRequired");
129
+ TEST_PROP(CBCharacteristicPropertyIndicateEncryptionRequired, "indicateEncryptionRequired");
130
+ result.push_back(std::make_pair(uuid, properties));
131
+ }
132
+ }
133
+ return result;
134
+ }
135
+
136
+ std::vector<std::string> getDescriptors(NSArray<CBDescriptor*>* descriptors) {
137
+ std::vector<std::string> result;
138
+ if(descriptors) {
139
+ for (CBDescriptor* descriptor in descriptors) {
140
+ result.push_back([[descriptor.UUID UUIDString] UTF8String]);
141
+ }
142
+ }
143
+ return result;
144
+ }
@@ -0,0 +1,23 @@
1
+ #pragma once
2
+
3
+ using Data = std::vector<uint8_t>;
4
+
5
+ enum AddressType {
6
+ PUBLIC,
7
+ RANDOM,
8
+ UNKNOWN,
9
+ };
10
+
11
+ class Peripheral {
12
+ public:
13
+ Peripheral() : address("unknown"), addressType(UNKNOWN), connectable(false) {
14
+ }
15
+ std::string address;
16
+ AddressType addressType;
17
+ bool connectable;
18
+ std::string name;
19
+ int txPowerLevel;
20
+ Data manufacturerData;
21
+ std::vector<std::pair<std::string, Data>> serviceData;
22
+ std::vector<std::string> serviceUuids;
23
+ };
@@ -0,0 +1,19 @@
1
+ const { EventEmitter } = require('events');
2
+ const UuidUtil = require('./uuid-util');
3
+
4
+ class PrimaryService extends EventEmitter {
5
+ constructor (options) {
6
+ super();
7
+ this.uuid = UuidUtil.removeDashes(options.uuid);
8
+ this.characteristics = options.characteristics || [];
9
+ }
10
+
11
+ toString () {
12
+ return JSON.stringify({
13
+ uuid: this.uuid,
14
+ characteristics: this.characteristics
15
+ });
16
+ }
17
+ }
18
+
19
+ module.exports = PrimaryService;
@@ -0,0 +1,19 @@
1
+ const os = require('os');
2
+
3
+ module.exports = function (options = {}) {
4
+ const platform = os.platform();
5
+
6
+ if (
7
+ platform === 'linux' ||
8
+ platform === 'freebsd' ||
9
+ platform === 'win32' ||
10
+ platform === 'android' ||
11
+ process.env.BLUETOOTH_HCI_SOCKET_UART_PORT ||
12
+ process.env.BLUETOOTH_HCI_SOCKET_FORCE_UART) {
13
+ return new (require('./hci-socket/bindings'))(options);
14
+ } else if (platform === 'darwin') {
15
+ return new (require('./mac/bindings'))(options);
16
+ } else {
17
+ throw new Error('Unsupported platform ' + platform);
18
+ }
19
+ };
@@ -0,0 +1,7 @@
1
+ module.exports.removeDashes = function (uuid) {
2
+ if (uuid) {
3
+ uuid = uuid.replace(/-/g, '');
4
+ }
5
+
6
+ return uuid;
7
+ };
package/package.json ADDED
@@ -0,0 +1,77 @@
1
+ {
2
+ "name": "@stoprocent/bleno",
3
+ "version": "0.7.0",
4
+ "description": "A Node.js module for implementing BLE (Bluetooth Low Energy) peripherals",
5
+ "main": "./index.js",
6
+ "types": "./index.d.ts",
7
+ "engines": {
8
+ "node": ">=14"
9
+ },
10
+ "os": [
11
+ "darwin",
12
+ "linux",
13
+ "android",
14
+ "freebsd",
15
+ "win32"
16
+ ],
17
+ "scripts": {
18
+ "install": "node-gyp-build",
19
+ "lint": "eslint \"**/*.js\"",
20
+ "lint-fix": "eslint \"**/*.js\" --fix",
21
+ "prebuildify": "prebuildify --napi --target 14.0.0 --force --strip --verbose",
22
+ "prebuildify-cross": "prebuildify-cross --napi --target 14.0.0 --force --strip --verbose",
23
+ "semantic-release": "semantic-release",
24
+ "pretest": "npm run rebuild",
25
+ "rebuild": "node-gyp rebuild",
26
+ "coverage": "nyc npm test && nyc report --reporter=text-lcov > .nyc_output/lcov.info",
27
+ "test": "cross-env NODE_ENV=test mocha --recursive \"test/*.test.js\" \"test/**/*.test.js\" --exit"
28
+ },
29
+ "repository": {
30
+ "type": "git",
31
+ "url": "https://github.com/stoprocent/bleno"
32
+ },
33
+ "keywords": [
34
+ "BLE",
35
+ "Bluetooth",
36
+ "Bluetooth Low Energy",
37
+ "Bluetooth Smart",
38
+ "peripheral"
39
+ ],
40
+ "author": "Sandeep Mistry <sandeep.mistry@gmail.com>",
41
+ "maintainers": [
42
+ "Marek Serafin <marek@serafin.email>"
43
+ ],
44
+ "license": "MIT",
45
+ "readmeFilename": "README.md",
46
+ "devDependencies": {
47
+ "@semantic-release/exec": "^6.0.3",
48
+ "cross-env": "^7.0.3",
49
+ "jshint": "~2.13.6",
50
+ "eslint": "^8.31.0",
51
+ "eslint-config-semistandard": "^17.0.0",
52
+ "eslint-config-standard": "^17.0.0",
53
+ "eslint-plugin-import": "^2.26.0",
54
+ "eslint-plugin-n": "^15.6.0",
55
+ "eslint-plugin-promise": "^6.1.1",
56
+ "mocha": "~10.2.0",
57
+ "node-blink1": "~0.5.1",
58
+ "nyc": "^15.1.0",
59
+ "prebuildify": "^5.0.1",
60
+ "prebuildify-cross": "5.0.0",
61
+ "should": "~13.2.3"
62
+ },
63
+ "dependencies": {
64
+ "debug": "^4.3.4",
65
+ "napi-thread-safe-callback": "^0.0.6",
66
+ "node-addon-api": "^4.3.0",
67
+ "node-gyp-build": "^4.5.0"
68
+ },
69
+ "optionalDependencies": {
70
+ "@stoprocent/bluetooth-hci-socket": "^1.1.3",
71
+ "bplist-parser": "0.3.2",
72
+ "xpc-connect": "^3.0.0"
73
+ },
74
+ "publishConfig": {
75
+ "access": "public"
76
+ }
77
+ }
@@ -0,0 +1,174 @@
1
+ /* jshint mocha: true */
2
+
3
+ const should = require('should');
4
+
5
+ const Characteristic = require('../lib/characteristic');
6
+
7
+ describe('Characteristic', function () {
8
+ const mockUuid = 'mockuuid';
9
+ const mockProperties = ['property1', 'property2', 'property3'];
10
+ const mockSecure = ['secure1', 'secure2', 'secure3'];
11
+ const mockValue = Buffer.from('mock value');
12
+ const mockDescriptors = [{}, {}, {}];
13
+
14
+ const mockOnReadRequest = function () {};
15
+ const mockOnWriteRequest = function () {};
16
+ const mockOnSubscribe = function () {};
17
+ const mockOnUnsubscribe = function () {};
18
+ const mockOnNotify = function () {};
19
+ const mockOnIndicate = function () {};
20
+
21
+ const mockMaxValueSize = 20;
22
+ const mockUpdateValueCallback = function () {};
23
+
24
+ it('should create with uuid option', function () {
25
+ const characteristic = new Characteristic({
26
+ uuid: mockUuid
27
+ });
28
+
29
+ characteristic.uuid.should.equal(mockUuid);
30
+
31
+ Array.isArray(characteristic.properties).should.equal(true);
32
+ characteristic.properties.length.should.equal(0);
33
+
34
+ Array.isArray(characteristic.secure).should.equal(true);
35
+ characteristic.secure.length.should.equal(0);
36
+
37
+ should(characteristic.value).equal(null);
38
+
39
+ Array.isArray(characteristic.descriptors).should.equal(true);
40
+ characteristic.descriptors.length.should.equal(0);
41
+ });
42
+
43
+ it('should create with properties option', function () {
44
+ const characteristic = new Characteristic({
45
+ properties: mockProperties
46
+ });
47
+
48
+ characteristic.properties.should.equal(mockProperties);
49
+ });
50
+
51
+ it('should create with secure option', function () {
52
+ const characteristic = new Characteristic({
53
+ secure: mockSecure
54
+ });
55
+
56
+ characteristic.secure.should.equal(mockSecure);
57
+ });
58
+
59
+ it('should create with value option', function () {
60
+ const characteristic = new Characteristic({
61
+ properties: ['read'],
62
+ value: mockValue
63
+ });
64
+
65
+ characteristic.value.should.equal(mockValue);
66
+ });
67
+
68
+ it('should not create with value option and non-read properties', function () {
69
+ (function () {
70
+ // eslint-disable-next-line no-unused-vars
71
+ const characteristic = new Characteristic({
72
+ properties: ['write'],
73
+ value: mockValue
74
+ });
75
+ }).should.throw();
76
+ });
77
+
78
+ it('should create with descriptors option', function () {
79
+ const characteristic = new Characteristic({
80
+ descriptors: mockDescriptors
81
+ });
82
+
83
+ characteristic.descriptors.should.equal(mockDescriptors);
84
+ });
85
+
86
+ it('should create with onReadRequest option', function () {
87
+ const characteristic = new Characteristic({
88
+ onReadRequest: mockOnReadRequest
89
+ });
90
+
91
+ characteristic.onReadRequest.should.equal(mockOnReadRequest);
92
+ });
93
+
94
+ it('should create with onWriteRequest option', function () {
95
+ const characteristic = new Characteristic({
96
+ onWriteRequest: mockOnWriteRequest
97
+ });
98
+
99
+ characteristic.onWriteRequest.should.equal(mockOnWriteRequest);
100
+ });
101
+
102
+ it('should create with onSubscribe option', function () {
103
+ const characteristic = new Characteristic({
104
+ onSubscribe: mockOnSubscribe
105
+ });
106
+
107
+ characteristic.onSubscribe.should.equal(mockOnSubscribe);
108
+ });
109
+
110
+ it('should create with onUnsubscribe option', function () {
111
+ const characteristic = new Characteristic({
112
+ onUnsubscribe: mockOnUnsubscribe
113
+ });
114
+
115
+ characteristic.onUnsubscribe.should.equal(mockOnUnsubscribe);
116
+ });
117
+
118
+ it('should create with onNotify option', function () {
119
+ const characteristic = new Characteristic({
120
+ onNotify: mockOnNotify
121
+ });
122
+
123
+ characteristic.onNotify.should.equal(mockOnNotify);
124
+ });
125
+
126
+ it('should create with onIndicate option', function () {
127
+ const characteristic = new Characteristic({
128
+ onIndicate: mockOnIndicate
129
+ });
130
+
131
+ characteristic.onIndicate.should.equal(mockOnIndicate);
132
+ });
133
+
134
+ it('should toString', function () {
135
+ const characteristic = new Characteristic({
136
+ uuid: mockUuid
137
+ });
138
+
139
+ characteristic.toString().should.equal('{"uuid":"mockuuid","properties":[],"secure":[],"value":null,"descriptors":[]}');
140
+ });
141
+
142
+ it('should handle read request', function (done) {
143
+ const characteristic = new Characteristic({});
144
+
145
+ characteristic.emit('readRequest', 0, function (result, data) {
146
+ result.should.equal(0x0e);
147
+ should(data).equal(null);
148
+
149
+ done();
150
+ });
151
+ });
152
+
153
+ it('should handle write request', function (done) {
154
+ const characteristic = new Characteristic({});
155
+
156
+ characteristic.emit('writeRequest', Buffer.alloc(0), 0, false, function (result) {
157
+ result.should.equal(0x0e);
158
+
159
+ done();
160
+ });
161
+ });
162
+
163
+ it('should handle unsubscribe', function () {
164
+ const characteristic = new Characteristic({});
165
+
166
+ characteristic.maxValueSize = mockMaxValueSize;
167
+ characteristic.updateValueCallback = mockUpdateValueCallback;
168
+
169
+ characteristic.emit('unsubscribe');
170
+
171
+ should(characteristic.maxValueSize).equal(null);
172
+ should(characteristic.updateValueCallback).equal(null);
173
+ });
174
+ });
@@ -0,0 +1,46 @@
1
+ /* jshint mocha: true */
2
+ const Descriptor = require('../lib/descriptor');
3
+
4
+ describe('Descriptor', function () {
5
+ const mockUuid = 'mockuuid';
6
+ const mockValue = Buffer.from('mock value');
7
+
8
+ it('should create with uuid option', function () {
9
+ const descriptor = new Descriptor({
10
+ uuid: mockUuid
11
+ });
12
+
13
+ descriptor.uuid.should.equal(mockUuid);
14
+
15
+ Buffer.isBuffer(descriptor.value).should.equal(true);
16
+ descriptor.value.length.should.equal(0);
17
+ });
18
+
19
+ it('should create with value option', function () {
20
+ const descriptor = new Descriptor({
21
+ value: mockValue
22
+ });
23
+
24
+ descriptor.value.should.equal(mockValue);
25
+ });
26
+
27
+ describe('toString', function () {
28
+ it('should hex buffer value', function () {
29
+ const descriptor = new Descriptor({
30
+ uuid: mockUuid,
31
+ value: mockValue
32
+ });
33
+
34
+ descriptor.toString().should.equal('{"uuid":"mockuuid","value":"6d6f636b2076616c7565"}');
35
+ });
36
+
37
+ it('should leave non-buffer value alone', function () {
38
+ const descriptor = new Descriptor({
39
+ uuid: mockUuid,
40
+ value: 'mock value'
41
+ });
42
+
43
+ descriptor.toString().should.equal('{"uuid":"mockuuid","value":"mock value"}');
44
+ });
45
+ });
46
+ });
File without changes
@@ -0,0 +1,5 @@
1
+ const Bleno = require('./lib/bleno');
2
+
3
+ module.exports = function (bindings) {
4
+ return new Bleno(bindings);
5
+ };
@@ -0,0 +1,6 @@
1
+ module.exports = function (options) {
2
+ const Bleno = require('./lib/bleno');
3
+ const bindings = require('./lib/resolve-bindings')(options);
4
+
5
+ return new Bleno(bindings);
6
+ };