@neurosity/sdk 6.3.0 → 6.4.0-next.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.
Files changed (36) hide show
  1. package/dist/browser/neurosity.iife.js +1550 -1536
  2. package/dist/browser/neurosity.js +15 -15
  3. package/dist/browser/neurosity.js.map +1 -1
  4. package/dist/cjs/Neurosity.d.ts +5 -0
  5. package/dist/cjs/Neurosity.js +20 -6
  6. package/dist/cjs/api/bluetooth/BluetoothClient.d.ts +2 -0
  7. package/dist/cjs/api/bluetooth/BluetoothClient.js +35 -30
  8. package/dist/cjs/api/bluetooth/BluetoothTransport.d.ts +2 -2
  9. package/dist/cjs/api/bluetooth/react-native/ReactNativeTransport.d.ts +2 -3
  10. package/dist/cjs/api/bluetooth/react-native/ReactNativeTransport.js +37 -45
  11. package/dist/cjs/api/bluetooth/utils/osHasBluetoothSupport.d.ts +2 -2
  12. package/dist/cjs/api/bluetooth/utils/osHasBluetoothSupport.js +4 -2
  13. package/dist/cjs/api/bluetooth/web/WebBluetoothTransport.d.ts +2 -3
  14. package/dist/cjs/api/bluetooth/web/WebBluetoothTransport.js +35 -41
  15. package/dist/cjs/api/index.d.ts +3 -1
  16. package/dist/cjs/api/index.js +4 -0
  17. package/dist/electron/index.js +10 -10
  18. package/dist/electron/index.js.map +1 -1
  19. package/dist/esm/Neurosity.d.ts +5 -0
  20. package/dist/esm/Neurosity.js +20 -6
  21. package/dist/esm/api/bluetooth/BluetoothClient.d.ts +2 -0
  22. package/dist/esm/api/bluetooth/BluetoothClient.js +36 -31
  23. package/dist/esm/api/bluetooth/BluetoothTransport.d.ts +2 -2
  24. package/dist/esm/api/bluetooth/react-native/ReactNativeTransport.d.ts +2 -3
  25. package/dist/esm/api/bluetooth/react-native/ReactNativeTransport.js +33 -41
  26. package/dist/esm/api/bluetooth/utils/osHasBluetoothSupport.d.ts +2 -2
  27. package/dist/esm/api/bluetooth/utils/osHasBluetoothSupport.js +4 -2
  28. package/dist/esm/api/bluetooth/web/WebBluetoothTransport.d.ts +2 -3
  29. package/dist/esm/api/bluetooth/web/WebBluetoothTransport.js +33 -39
  30. package/dist/esm/api/index.d.ts +3 -1
  31. package/dist/esm/api/index.js +4 -0
  32. package/dist/esm/neurosity.mjs +1550 -1536
  33. package/dist/examples/neurosity.iife.js +1550 -1536
  34. package/dist/examples/neurosity.js +15 -15
  35. package/dist/examples/neurosity.mjs +1550 -1536
  36. package/package.json +1 -1
@@ -80,6 +80,11 @@ export declare class Neurosity {
80
80
  * @hidden
81
81
  */
82
82
  _initStreamingMode(streamingMode: STREAMING_MODE, hasBluetoothTransport: boolean): void;
83
+ /**
84
+ *
85
+ * @hidden
86
+ */
87
+ _osHasBluetoothSupport(): Observable<any>;
83
88
  /**
84
89
  * Subscribe to the device's streaming state changes and the current strategy
85
90
  *
@@ -39,6 +39,7 @@ exports.Notion = exports.Neurosity = void 0;
39
39
  const rxjs_1 = require("rxjs");
40
40
  const rxjs_2 = require("rxjs");
41
41
  const operators_1 = require("rxjs/operators");
42
+ const operators_2 = require("rxjs/operators");
42
43
  const fast_deep_equal_1 = __importDefault(require("fast-deep-equal"));
43
44
  const index_1 = require("./api/index");
44
45
  const index_2 = require("./api/index");
@@ -99,6 +100,7 @@ class Neurosity {
99
100
  if (!!bluetoothTransport) {
100
101
  this.bluetoothClient = new bluetooth_1.BluetoothClient({
101
102
  selectedDevice$: this.onDeviceChange(),
103
+ osHasBluetoothSupport$: this._osHasBluetoothSupport(),
102
104
  createBluetoothToken: this.createBluetoothToken.bind(this),
103
105
  transport: bluetoothTransport
104
106
  });
@@ -129,6 +131,16 @@ class Neurosity {
129
131
  this.streamingMode$.next(streamingMode);
130
132
  }
131
133
  }
134
+ /**
135
+ *
136
+ * @hidden
137
+ */
138
+ _osHasBluetoothSupport() {
139
+ return (0, rxjs_1.combineLatest)({
140
+ selectedDevice: this.onDeviceChange(),
141
+ osVersion: this.osVersion().pipe((0, operators_1.startWith)(null))
142
+ }).pipe((0, operators_1.map)(({ selectedDevice, osVersion }) => (0, bluetooth_1.osHasBluetoothSupport)(selectedDevice, osVersion)));
143
+ }
132
144
  /**
133
145
  * Subscribe to the device's streaming state changes and the current strategy
134
146
  *
@@ -144,12 +156,14 @@ class Neurosity {
144
156
  streamingState() {
145
157
  const isWifiOnline = (state) => [status_1.STATUS.ONLINE, status_1.STATUS.UPDATING].includes(state);
146
158
  return this.streamingMode$.pipe((0, operators_1.switchMap)((streamingMode) => {
147
- return this.onDeviceChange().pipe((0, operators_1.switchMap)((selectDevice) => {
148
- if (!selectDevice) {
159
+ return (0, rxjs_1.combineLatest)({
160
+ selectedDevice: this.onDeviceChange(),
161
+ osHasBluetoothSupport: this._osHasBluetoothSupport()
162
+ }).pipe((0, operators_1.switchMap)(({ selectedDevice, osHasBluetoothSupport }) => {
163
+ if (!selectedDevice) {
149
164
  return rxjs_2.EMPTY;
150
165
  }
151
- const isUnableToUseBluetooth = this.isMissingBluetoothTransport ||
152
- !(0, bluetooth_1.osHasBluetoothSupport)(selectDevice);
166
+ const isUnableToUseBluetooth = this.isMissingBluetoothTransport || !osHasBluetoothSupport;
153
167
  if (isUnableToUseBluetooth) {
154
168
  return this.cloudClient.status().pipe((0, operators_1.map)(({ state }) => ({
155
169
  connected: isWifiOnline(state),
@@ -193,7 +207,7 @@ class Neurosity {
193
207
  : streaming_1.STREAMING_TYPE.WIFI
194
208
  };
195
209
  }
196
- }), (0, operators_1.distinctUntilChanged)((a, b) => (0, fast_deep_equal_1.default)(a, b)));
210
+ }), (0, operators_2.distinctUntilChanged)((a, b) => (0, fast_deep_equal_1.default)(a, b)));
197
211
  }));
198
212
  }));
199
213
  }
@@ -815,7 +829,7 @@ class Neurosity {
815
829
  if (hasOAuthError) {
816
830
  return (0, rxjs_1.throwError)(() => OAuthError);
817
831
  }
818
- return this.cloudClient.observeNamespace("info/osVersion");
832
+ return this.cloudClient.osVersion();
819
833
  }
820
834
  /**
821
835
  * <StreamingModes wifi={true} bluetooth={true} />
@@ -16,12 +16,14 @@ declare type CreateBluetoothToken = () => Promise<string>;
16
16
  declare type Options = {
17
17
  transport: BluetoothTransport;
18
18
  selectedDevice$: Observable<DeviceInfo>;
19
+ osHasBluetoothSupport$: Observable<boolean>;
19
20
  createBluetoothToken: CreateBluetoothToken;
20
21
  };
21
22
  export declare class BluetoothClient {
22
23
  transport: BluetoothTransport;
23
24
  deviceInfo: DeviceInfo;
24
25
  selectedDevice$: ReplaySubject<DeviceInfo>;
26
+ osHasBluetoothSupport$: ReplaySubject<boolean>;
25
27
  isAuthenticated$: ReplaySubject<boolean>;
26
28
  _focus$: Observable<any>;
27
29
  _calm$: Observable<any>;
@@ -13,17 +13,16 @@ exports.BluetoothClient = void 0;
13
13
  const rxjs_1 = require("rxjs");
14
14
  const rxjs_2 = require("rxjs");
15
15
  const operators_1 = require("rxjs/operators");
16
- const operators_2 = require("rxjs/operators");
17
16
  const WebBluetoothTransport_1 = require("./web/WebBluetoothTransport");
18
17
  const ReactNativeTransport_1 = require("./react-native/ReactNativeTransport");
19
18
  const csvBufferToEpoch_1 = require("./utils/csvBufferToEpoch");
20
19
  const types_1 = require("./types");
21
- const osHasBluetoothSupport_1 = require("./utils/osHasBluetoothSupport");
22
20
  class BluetoothClient {
23
21
  constructor(options) {
24
22
  this.selectedDevice$ = new rxjs_2.ReplaySubject(1);
23
+ this.osHasBluetoothSupport$ = new rxjs_2.ReplaySubject(1);
25
24
  this.isAuthenticated$ = new rxjs_2.ReplaySubject(1);
26
- const { transport, selectedDevice$, createBluetoothToken } = options !== null && options !== void 0 ? options : {};
25
+ const { transport, selectedDevice$, osHasBluetoothSupport$, createBluetoothToken } = options !== null && options !== void 0 ? options : {};
27
26
  if (!transport) {
28
27
  throw new Error(`No bluetooth transport provided.`);
29
28
  }
@@ -32,8 +31,15 @@ class BluetoothClient {
32
31
  if (selectedDevice$) {
33
32
  selectedDevice$.subscribe(this.selectedDevice$);
34
33
  }
35
- // Auto Connect
36
- this.transport._autoConnect(this.selectedDevice$).subscribe({
34
+ // Pass events to the internal osHasBluetoothSupport$ if osHasBluetoothSupport$ is passed via options
35
+ if (osHasBluetoothSupport$) {
36
+ osHasBluetoothSupport$.subscribe(this.osHasBluetoothSupport$);
37
+ }
38
+ this.osHasBluetoothSupport$
39
+ .pipe((0, operators_1.switchMap)((osHasBluetoothSupport) => osHasBluetoothSupport
40
+ ? this.transport._autoConnect(this.selectedDevice$)
41
+ : rxjs_2.EMPTY))
42
+ .subscribe({
37
43
  error: (error) => {
38
44
  var _a;
39
45
  this.transport.addLog(`Auto connect: error -> ${(_a = error === null || error === void 0 ? void 0 : error.message) !== null && _a !== void 0 ? _a : error}`);
@@ -48,7 +54,11 @@ class BluetoothClient {
48
54
  this.transport.addLog("Auto authentication not enabled");
49
55
  }
50
56
  // Auto manage action notifications
51
- this.transport._autoToggleActionNotifications(this.selectedDevice$);
57
+ this.osHasBluetoothSupport$
58
+ .pipe((0, operators_1.switchMap)((osHasBluetoothSupport) => osHasBluetoothSupport
59
+ ? this.transport._autoToggleActionNotifications()
60
+ : rxjs_2.EMPTY))
61
+ .subscribe();
52
62
  // Multicast metrics (share)
53
63
  this._focus$ = this._subscribeWhileAuthenticated("focus");
54
64
  this._calm$ = this._subscribeWhileAuthenticated("calm");
@@ -72,27 +82,24 @@ class BluetoothClient {
72
82
  const reauthenticateInterval$ = (0, rxjs_1.timer)(0, REAUTHENTICATE_INTERVAL).pipe((0, operators_1.tap)(() => {
73
83
  this.transport.addLog(`Auto authentication in progress...`);
74
84
  }));
75
- return this.selectedDevice$.pipe((0, operators_1.switchMap)((selectedDevice) => !(0, osHasBluetoothSupport_1.osHasBluetoothSupport)(selectedDevice)
76
- ? rxjs_2.EMPTY
77
- : this.connection().pipe((0, operators_1.switchMap)((connection) => connection === types_1.BLUETOOTH_CONNECTION.CONNECTED
78
- ? reauthenticateInterval$
79
- : rxjs_2.EMPTY), (0, operators_1.switchMap)(() => __awaiter(this, void 0, void 0, function* () { return yield this.isAuthenticated(); })), (0, operators_1.tap)(([isAuthenticated]) => __awaiter(this, void 0, void 0, function* () {
80
- if (!isAuthenticated) {
81
- const token = yield createBluetoothToken();
82
- yield this.authenticate(token);
83
- }
84
- else {
85
- this.transport.addLog(`Already authenticated`);
86
- }
87
- })))));
85
+ return this.osHasBluetoothSupport$.pipe((0, operators_1.switchMap)((osHasBluetoothSupport) => osHasBluetoothSupport ? this.connection() : rxjs_2.EMPTY), (0, operators_1.switchMap)((connection) => connection === types_1.BLUETOOTH_CONNECTION.CONNECTED
86
+ ? reauthenticateInterval$
87
+ : rxjs_2.EMPTY), (0, operators_1.switchMap)(() => __awaiter(this, void 0, void 0, function* () { return yield this.isAuthenticated(); })), (0, operators_1.tap)(([isAuthenticated]) => __awaiter(this, void 0, void 0, function* () {
88
+ if (!isAuthenticated) {
89
+ const token = yield createBluetoothToken();
90
+ yield this.authenticate(token);
91
+ }
92
+ else {
93
+ this.transport.addLog(`Already authenticated`);
94
+ }
95
+ })));
88
96
  }
89
97
  enableAutoConnect(autoConnect) {
90
98
  this.transport.enableAutoConnect(autoConnect);
91
99
  }
92
100
  _hasBluetoothSupport() {
93
101
  return __awaiter(this, void 0, void 0, function* () {
94
- const selectedDevice = yield (0, rxjs_1.firstValueFrom)(this.selectedDevice$);
95
- return (0, osHasBluetoothSupport_1.osHasBluetoothSupport)(selectedDevice);
102
+ return yield (0, rxjs_2.firstValueFrom)(this.osHasBluetoothSupport$);
96
103
  });
97
104
  }
98
105
  authenticate(token) {
@@ -163,7 +170,7 @@ class BluetoothClient {
163
170
  this.transport.addLog(errorMessage);
164
171
  return Promise.reject(errorMessage);
165
172
  }
166
- const isAuthenticated = yield (0, rxjs_1.firstValueFrom)(this.isAuthenticated$);
173
+ const isAuthenticated = yield (0, rxjs_2.firstValueFrom)(this.isAuthenticated$);
167
174
  if (!isAuthenticated) {
168
175
  const errorMessage = `Authentication required.`;
169
176
  this.transport.addLog(errorMessage);
@@ -173,13 +180,11 @@ class BluetoothClient {
173
180
  });
174
181
  }
175
182
  _subscribeWhileAuthenticated(characteristicName) {
176
- return this.selectedDevice$.pipe((0, operators_1.switchMap)((selectedDevice) => !(0, osHasBluetoothSupport_1.osHasBluetoothSupport)(selectedDevice)
177
- ? rxjs_2.EMPTY
178
- : this.isAuthenticated$.pipe((0, operators_2.distinctUntilChanged)(), (0, operators_1.switchMap)((isAuthenticated) => isAuthenticated
179
- ? this.transport.subscribeToCharacteristic({
180
- characteristicName
181
- })
182
- : rxjs_2.EMPTY))), (0, operators_1.share)());
183
+ return this.osHasBluetoothSupport$.pipe((0, operators_1.switchMap)((osHasBluetoothSupport) => osHasBluetoothSupport ? this.isAuthenticated$ : rxjs_2.EMPTY), (0, operators_1.distinctUntilChanged)(), (0, operators_1.switchMap)((isAuthenticated) => isAuthenticated
184
+ ? this.transport.subscribeToCharacteristic({
185
+ characteristicName
186
+ })
187
+ : rxjs_2.EMPTY), (0, operators_1.share)());
183
188
  }
184
189
  focus() {
185
190
  return this._focus$;
@@ -220,7 +225,7 @@ class BluetoothClient {
220
225
  }
221
226
  getInfo() {
222
227
  return __awaiter(this, void 0, void 0, function* () {
223
- return yield this._withAuthentication(() => (0, rxjs_1.firstValueFrom)(this.transport.subscribeToCharacteristic({
228
+ return yield this._withAuthentication(() => (0, rxjs_2.firstValueFrom)(this.transport.subscribeToCharacteristic({
224
229
  characteristicName: "deviceInfo"
225
230
  })));
226
231
  });
@@ -1,7 +1,7 @@
1
1
  import { Observable, Subject } from "rxjs";
2
2
  import { BLUETOOTH_CONNECTION, TRANSPORT_TYPE } from "./types";
3
3
  import { Action } from "../../types/actions";
4
- import { DeviceInfo } from "../../types/deviceInfo";
4
+ import { DeviceInfo, OSVersion } from "../../types/deviceInfo";
5
5
  import { Peripheral } from "./react-native/types/BleManagerTypes";
6
6
  export declare type DeviceNicknameOrPeripheral = string | Peripheral;
7
7
  /**
@@ -10,7 +10,7 @@ export declare type DeviceNicknameOrPeripheral = string | Peripheral;
10
10
  export interface BluetoothTransport {
11
11
  type: TRANSPORT_TYPE;
12
12
  connect(deviceNicknameORPeripheral?: DeviceNicknameOrPeripheral): Promise<void>;
13
- _autoConnect(selectedDevice$: Observable<DeviceInfo>): Observable<void>;
13
+ _autoConnect(selectedDevice$: Observable<DeviceInfo>, osVersion: Observable<OSVersion>): Observable<void>;
14
14
  disconnect(): Promise<void>;
15
15
  connection(): Observable<BLUETOOTH_CONNECTION>;
16
16
  requestDevice?(): any;
@@ -1,5 +1,4 @@
1
- import { BehaviorSubject, ReplaySubject } from "rxjs";
2
- import { Observable } from "rxjs";
1
+ import { Observable, BehaviorSubject, ReplaySubject } from "rxjs";
3
2
  import { BluetoothTransport } from "../BluetoothTransport";
4
3
  import { ActionOptions, SubscribeOptions } from "../types";
5
4
  import { TRANSPORT_TYPE, BLUETOOTH_CONNECTION } from "../types";
@@ -65,7 +64,7 @@ export declare class ReactNativeTransport implements BluetoothTransport {
65
64
  writeCharacteristic(characteristicName: string, data: string): Promise<void>;
66
65
  _addPendingAction(actionId: number): void;
67
66
  _removePendingAction(actionId: number): void;
68
- _autoToggleActionNotifications(selectedDevice$: Observable<DeviceInfo>): Promise<void>;
67
+ _autoToggleActionNotifications(): Observable<any>;
69
68
  dispatchAction({ characteristicName, action }: ActionOptions): Promise<any>;
70
69
  }
71
70
  export {};
@@ -26,7 +26,6 @@ const constants_1 = require("../constants");
26
26
  const constants_2 = require("../constants");
27
27
  const constants_3 = require("../constants");
28
28
  const constants_4 = require("../constants");
29
- const osHasBluetoothSupport_1 = require("../utils/osHasBluetoothSupport");
30
29
  const defaultOptions = {
31
30
  autoConnect: true
32
31
  };
@@ -107,13 +106,11 @@ class ReactNativeTransport {
107
106
  _autoConnect(selectedDevice$) {
108
107
  const selectedDeviceAfterDisconnect$ = this.onDisconnected$.pipe((0, operators_1.switchMap)(() => selectedDevice$));
109
108
  return this._isAutoConnectEnabled$.pipe((0, operators_1.switchMap)((isAutoConnectEnabled) => isAutoConnectEnabled
110
- ? (0, rxjs_1.merge)(selectedDevice$, selectedDeviceAfterDisconnect$)
111
- : rxjs_2.NEVER), (0, operators_1.switchMap)((selectedDevice) => !(0, osHasBluetoothSupport_1.osHasBluetoothSupport)(selectedDevice)
112
- ? rxjs_2.NEVER
113
- : this.scan().pipe((0, operators_1.switchMap)((peripherals) => {
114
- const peripheralMatch = peripherals.find((peripheral) => peripheral.name === (selectedDevice === null || selectedDevice === void 0 ? void 0 : selectedDevice.deviceNickname));
115
- return peripheralMatch ? (0, rxjs_1.of)(peripheralMatch) : rxjs_2.NEVER;
116
- }), (0, operators_3.distinct)((peripheral) => peripheral.id), (0, operators_3.take)(1))), (0, operators_1.switchMap)((peripheral) => __awaiter(this, void 0, void 0, function* () {
109
+ ? (0, rxjs_2.merge)(selectedDevice$, selectedDeviceAfterDisconnect$)
110
+ : rxjs_1.NEVER), (0, operators_1.switchMap)((selectedDevice) => this.scan().pipe((0, operators_1.switchMap)((peripherals) => {
111
+ const peripheralMatch = peripherals.find((peripheral) => peripheral.name === (selectedDevice === null || selectedDevice === void 0 ? void 0 : selectedDevice.deviceNickname));
112
+ return peripheralMatch ? (0, rxjs_2.of)(peripheralMatch) : rxjs_1.NEVER;
113
+ }), (0, operators_3.distinct)((peripheral) => peripheral.id), (0, operators_3.take)(1))), (0, operators_1.switchMap)((peripheral) => __awaiter(this, void 0, void 0, function* () {
117
114
  return yield this.connect(peripheral);
118
115
  })));
119
116
  }
@@ -145,7 +142,7 @@ class ReactNativeTransport {
145
142
  const serviceUUIDs = [ipk_1.BLUETOOTH_PRIMARY_SERVICE_UUID_STRING];
146
143
  const allowDuplicates = true;
147
144
  const scanOptions = {};
148
- const scanOnce$ = new rxjs_2.Observable((subscriber) => {
145
+ const scanOnce$ = new rxjs_1.Observable((subscriber) => {
149
146
  var _a;
150
147
  try {
151
148
  this.BleManager.scan(serviceUUIDs, seconds, allowDuplicates, scanOptions).then(() => {
@@ -163,7 +160,7 @@ class ReactNativeTransport {
163
160
  });
164
161
  const scan$ = once
165
162
  ? scanOnce$
166
- : (0, rxjs_1.timer)(0, RESCAN_INTERVAL).pipe((0, operators_1.switchMap)(() => scanOnce$));
163
+ : (0, rxjs_2.timer)(0, RESCAN_INTERVAL).pipe((0, operators_1.switchMap)(() => scanOnce$));
167
164
  const peripherals$ = scan$.pipe((0, operators_1.tap)(() => {
168
165
  if (!skipConnectionUpdate) {
169
166
  this.connection$.next(types_1.BLUETOOTH_CONNECTION.SCANNING);
@@ -261,7 +258,7 @@ class ReactNativeTransport {
261
258
  return (_a = this.characteristicsByName) === null || _a === void 0 ? void 0 : _a[characteristicName];
262
259
  }
263
260
  subscribeToCharacteristic({ characteristicName, manageNotifications = true }) {
264
- const getData = ({ peripheralId, serviceUUID, characteristicUUID }) => (0, rxjs_1.defer)(() => __awaiter(this, void 0, void 0, function* () {
261
+ const getData = ({ peripheralId, serviceUUID, characteristicUUID }) => (0, rxjs_2.defer)(() => __awaiter(this, void 0, void 0, function* () {
265
262
  var _a;
266
263
  if (manageNotifications) {
267
264
  try {
@@ -295,7 +292,7 @@ class ReactNativeTransport {
295
292
  }));
296
293
  return this.connection$.pipe((0, operators_1.switchMap)((connection) => connection === types_1.BLUETOOTH_CONNECTION.CONNECTED
297
294
  ? getData(this.getCharacteristicByName(characteristicName))
298
- : rxjs_2.NEVER));
295
+ : rxjs_1.NEVER));
299
296
  }
300
297
  readCharacteristic(characteristicName, parse = false) {
301
298
  var _a;
@@ -336,40 +333,35 @@ class ReactNativeTransport {
336
333
  const actions = this.pendingActions$.getValue();
337
334
  this.pendingActions$.next(actions.filter((id) => id !== actionId));
338
335
  }
339
- _autoToggleActionNotifications(selectedDevice$) {
340
- return __awaiter(this, void 0, void 0, function* () {
341
- let started = false;
342
- const sideEffects$ = this.connection$.asObservable().pipe((0, operators_1.switchMap)((connection) => connection === types_1.BLUETOOTH_CONNECTION.CONNECTED
343
- ? this.pendingActions$
344
- : rxjs_2.NEVER), (0, operators_1.tap)((pendingActions) => __awaiter(this, void 0, void 0, function* () {
345
- var _a, _b;
346
- const { peripheralId, serviceUUID, characteristicUUID } = this.getCharacteristicByName("actions");
347
- const hasPendingActions = !!pendingActions.length;
348
- if (hasPendingActions && !started) {
349
- started = true;
350
- try {
351
- yield this.BleManager.startNotification(peripheralId, serviceUUID, characteristicUUID);
352
- this.addLog(`Started notifications for [actions] characteristic`);
353
- }
354
- catch (error) {
355
- this.addLog(`Attemped to start notifications for [actions] characteristic: ${(_a = error === null || error === void 0 ? void 0 : error.message) !== null && _a !== void 0 ? _a : error}`);
356
- }
336
+ _autoToggleActionNotifications() {
337
+ let started = false;
338
+ return this.connection$.asObservable().pipe((0, operators_1.switchMap)((connection) => connection === types_1.BLUETOOTH_CONNECTION.CONNECTED
339
+ ? this.pendingActions$
340
+ : rxjs_1.NEVER), (0, operators_1.tap)((pendingActions) => __awaiter(this, void 0, void 0, function* () {
341
+ var _a, _b;
342
+ const { peripheralId, serviceUUID, characteristicUUID } = this.getCharacteristicByName("actions");
343
+ const hasPendingActions = !!pendingActions.length;
344
+ if (hasPendingActions && !started) {
345
+ started = true;
346
+ try {
347
+ yield this.BleManager.startNotification(peripheralId, serviceUUID, characteristicUUID);
348
+ this.addLog(`Started notifications for [actions] characteristic`);
357
349
  }
358
- if (!hasPendingActions && started) {
359
- started = false;
360
- try {
361
- yield this.BleManager.stopNotification(peripheralId, serviceUUID, characteristicUUID);
362
- this.addLog(`Stopped notifications for actions characteristic`);
363
- }
364
- catch (error) {
365
- this.addLog(`Attemped to stop notifications for [actions] characteristic: ${(_b = error === null || error === void 0 ? void 0 : error.message) !== null && _b !== void 0 ? _b : error}`);
366
- }
350
+ catch (error) {
351
+ this.addLog(`Attemped to start notifications for [actions] characteristic: ${(_a = error === null || error === void 0 ? void 0 : error.message) !== null && _a !== void 0 ? _a : error}`);
367
352
  }
368
- })));
369
- selectedDevice$
370
- .pipe((0, operators_1.switchMap)((selectedDevice) => !(0, osHasBluetoothSupport_1.osHasBluetoothSupport)(selectedDevice) ? rxjs_2.EMPTY : sideEffects$))
371
- .subscribe();
372
- });
353
+ }
354
+ if (!hasPendingActions && started) {
355
+ started = false;
356
+ try {
357
+ yield this.BleManager.stopNotification(peripheralId, serviceUUID, characteristicUUID);
358
+ this.addLog(`Stopped notifications for actions characteristic`);
359
+ }
360
+ catch (error) {
361
+ this.addLog(`Attemped to stop notifications for [actions] characteristic: ${(_b = error === null || error === void 0 ? void 0 : error.message) !== null && _b !== void 0 ? _b : error}`);
362
+ }
363
+ }
364
+ })));
373
365
  }
374
366
  dispatchAction({ characteristicName, action }) {
375
367
  return __awaiter(this, void 0, void 0, function* () {
@@ -380,7 +372,7 @@ class ReactNativeTransport {
380
372
  this.addLog(`Dispatched action with id ${actionId}`);
381
373
  if (responseRequired && responseTimeout) {
382
374
  this._addPendingAction(actionId);
383
- const timeout = (0, rxjs_1.timer)(responseTimeout).subscribe(() => {
375
+ const timeout = (0, rxjs_2.timer)(responseTimeout).subscribe(() => {
384
376
  this._removePendingAction(actionId);
385
377
  reject(new Error(`Action with id ${actionId} timed out after ${responseTimeout}ms`));
386
378
  });
@@ -1,2 +1,2 @@
1
- import { DeviceInfo } from "../../../types/deviceInfo";
2
- export declare function osHasBluetoothSupport(selectedDevice: DeviceInfo): any;
1
+ import { DeviceInfo, OSVersion } from "../../../types/deviceInfo";
2
+ export declare function osHasBluetoothSupport(selectedDevice: DeviceInfo, osVersion?: OSVersion): any;
@@ -5,7 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.osHasBluetoothSupport = void 0;
7
7
  const gte_1 = __importDefault(require("semver/functions/gte"));
8
- function osHasBluetoothSupport(selectedDevice) {
8
+ function osHasBluetoothSupport(selectedDevice, osVersion) {
9
9
  if (!selectedDevice) {
10
10
  return false;
11
11
  }
@@ -18,6 +18,8 @@ function osHasBluetoothSupport(selectedDevice) {
18
18
  if (isEmulator) {
19
19
  return false;
20
20
  }
21
- return (0, gte_1.default)(selectedDevice.osVersion, "16.0.0");
21
+ // `osVersion` is updated in real time,
22
+ // unlike accessing via `selectedDevice.osVersion`
23
+ return (0, gte_1.default)(osVersion !== null && osVersion !== void 0 ? osVersion : selectedDevice.osVersion, "16.0.0");
22
24
  }
23
25
  exports.osHasBluetoothSupport = osHasBluetoothSupport;
@@ -1,6 +1,5 @@
1
1
  /// <reference types="web-bluetooth" />
2
- import { BehaviorSubject, ReplaySubject } from "rxjs";
3
- import { Observable } from "rxjs";
2
+ import { Observable, BehaviorSubject, ReplaySubject } from "rxjs";
4
3
  import { BluetoothTransport } from "../BluetoothTransport";
5
4
  import { ActionOptions, SubscribeOptions } from "../types";
6
5
  import { TRANSPORT_TYPE, BLUETOOTH_CONNECTION } from "../types";
@@ -48,7 +47,7 @@ export declare class WebBluetoothTransport implements BluetoothTransport {
48
47
  writeCharacteristic(characteristicName: string, data: string): Promise<void>;
49
48
  _addPendingAction(actionId: number): void;
50
49
  _removePendingAction(actionId: number): void;
51
- _autoToggleActionNotifications(selectedDevice$: Observable<DeviceInfo>): Promise<void>;
50
+ _autoToggleActionNotifications(): Observable<any>;
52
51
  dispatchAction({ characteristicName, action }: ActionOptions): Promise<any>;
53
52
  }
54
53
  export {};
@@ -26,7 +26,6 @@ const encoding_1 = require("../utils/encoding");
26
26
  const types_1 = require("../types");
27
27
  const constants_1 = require("../constants");
28
28
  const constants_2 = require("../constants");
29
- const osHasBluetoothSupport_1 = require("../utils/osHasBluetoothSupport");
30
29
  const defaultOptions = {
31
30
  autoConnect: true
32
31
  };
@@ -66,8 +65,8 @@ class WebBluetoothTransport {
66
65
  }
67
66
  _autoConnect(selectedDevice$) {
68
67
  return this._isAutoConnectEnabled$.pipe((0, operators_1.switchMap)((isAutoConnectEnabled) => isAutoConnectEnabled
69
- ? (0, rxjs_1.merge)(selectedDevice$, this.onDisconnected$.pipe((0, operators_1.switchMap)(() => selectedDevice$)))
70
- : rxjs_2.NEVER), (0, operators_1.switchMap)((selectedDevice) => (0, osHasBluetoothSupport_1.osHasBluetoothSupport)(selectedDevice) ? (0, rxjs_1.of)(selectedDevice) : rxjs_2.EMPTY), (0, operators_1.switchMap)((selectedDevice) => __awaiter(this, void 0, void 0, function* () {
68
+ ? (0, rxjs_2.merge)(selectedDevice$, this.onDisconnected$.pipe((0, operators_1.switchMap)(() => selectedDevice$)))
69
+ : rxjs_2.NEVER), (0, operators_1.switchMap)((selectedDevice) => __awaiter(this, void 0, void 0, function* () {
71
70
  var _a;
72
71
  const { deviceNickname } = selectedDevice;
73
72
  if (this.isConnected()) {
@@ -213,7 +212,7 @@ class WebBluetoothTransport {
213
212
  });
214
213
  }
215
214
  subscribeToCharacteristic({ characteristicName, manageNotifications = true }) {
216
- const data$ = (0, rxjs_1.defer)(() => this.getCharacteristicByName(characteristicName)).pipe((0, operators_1.switchMap)((characteristic) => __awaiter(this, void 0, void 0, function* () {
215
+ const data$ = (0, rxjs_2.defer)(() => this.getCharacteristicByName(characteristicName)).pipe((0, operators_1.switchMap)((characteristic) => __awaiter(this, void 0, void 0, function* () {
217
216
  var _a;
218
217
  if (this.isConnected() && manageNotifications) {
219
218
  try {
@@ -307,43 +306,38 @@ class WebBluetoothTransport {
307
306
  const actions = this.pendingActions$.getValue();
308
307
  this.pendingActions$.next(actions.filter((id) => id !== actionId));
309
308
  }
310
- _autoToggleActionNotifications(selectedDevice$) {
311
- return __awaiter(this, void 0, void 0, function* () {
312
- let actionsCharacteristic;
313
- let started = false;
314
- const sideEffects$ = this.connection$.asObservable().pipe((0, operators_1.switchMap)((connection) => connection === types_1.BLUETOOTH_CONNECTION.CONNECTED
315
- ? (0, rxjs_1.defer)(() => this.getCharacteristicByName("actions")).pipe((0, operators_1.switchMap)((characteristic) => {
316
- actionsCharacteristic = characteristic;
317
- return this.pendingActions$;
318
- }))
319
- : rxjs_2.NEVER), (0, operators_1.tap)((pendingActions) => __awaiter(this, void 0, void 0, function* () {
320
- var _a, _b;
321
- const hasPendingActions = !!pendingActions.length;
322
- if (hasPendingActions && !started) {
323
- started = true;
324
- try {
325
- yield actionsCharacteristic.startNotifications();
326
- this.addLog(`Started notifications for [actions] characteristic`);
327
- }
328
- catch (error) {
329
- this.addLog(`Attemped to start notifications for [actions] characteristic: ${(_a = error === null || error === void 0 ? void 0 : error.message) !== null && _a !== void 0 ? _a : error}`);
330
- }
309
+ _autoToggleActionNotifications() {
310
+ let actionsCharacteristic;
311
+ let started = false;
312
+ return this.connection$.asObservable().pipe((0, operators_1.switchMap)((connection) => connection === types_1.BLUETOOTH_CONNECTION.CONNECTED
313
+ ? (0, rxjs_2.defer)(() => this.getCharacteristicByName("actions")).pipe((0, operators_1.switchMap)((characteristic) => {
314
+ actionsCharacteristic = characteristic;
315
+ return this.pendingActions$;
316
+ }))
317
+ : rxjs_2.NEVER), (0, operators_1.tap)((pendingActions) => __awaiter(this, void 0, void 0, function* () {
318
+ var _a, _b;
319
+ const hasPendingActions = !!pendingActions.length;
320
+ if (hasPendingActions && !started) {
321
+ started = true;
322
+ try {
323
+ yield actionsCharacteristic.startNotifications();
324
+ this.addLog(`Started notifications for [actions] characteristic`);
331
325
  }
332
- if (!hasPendingActions && started) {
333
- started = false;
334
- try {
335
- yield actionsCharacteristic.stopNotifications();
336
- this.addLog(`Stopped notifications for actions characteristic`);
337
- }
338
- catch (error) {
339
- this.addLog(`Attemped to stop notifications for [actions] characteristic: ${(_b = error === null || error === void 0 ? void 0 : error.message) !== null && _b !== void 0 ? _b : error}`);
340
- }
326
+ catch (error) {
327
+ this.addLog(`Attemped to start notifications for [actions] characteristic: ${(_a = error === null || error === void 0 ? void 0 : error.message) !== null && _a !== void 0 ? _a : error}`);
341
328
  }
342
- })));
343
- selectedDevice$
344
- .pipe((0, operators_1.switchMap)((selectedDevice) => !(0, osHasBluetoothSupport_1.osHasBluetoothSupport)(selectedDevice) ? rxjs_2.EMPTY : sideEffects$))
345
- .subscribe();
346
- });
329
+ }
330
+ if (!hasPendingActions && started) {
331
+ started = false;
332
+ try {
333
+ yield actionsCharacteristic.stopNotifications();
334
+ this.addLog(`Stopped notifications for actions characteristic`);
335
+ }
336
+ catch (error) {
337
+ this.addLog(`Attemped to stop notifications for [actions] characteristic: ${(_b = error === null || error === void 0 ? void 0 : error.message) !== null && _b !== void 0 ? _b : error}`);
338
+ }
339
+ }
340
+ })));
347
341
  }
348
342
  dispatchAction({ characteristicName, action }) {
349
343
  return __awaiter(this, void 0, void 0, function* () {
@@ -360,7 +354,7 @@ class WebBluetoothTransport {
360
354
  this.addLog(`Dispatched action with id ${actionId}`);
361
355
  if (responseRequired && responseTimeout) {
362
356
  this._addPendingAction(actionId);
363
- const timeout = (0, rxjs_1.timer)(responseTimeout).subscribe(() => {
357
+ const timeout = (0, rxjs_2.timer)(responseTimeout).subscribe(() => {
364
358
  this._removePendingAction(actionId);
365
359
  reject(`Action with id ${actionId} timed out after ${responseTimeout}ms`);
366
360
  });
@@ -406,7 +400,7 @@ function fromDOMEvent(target, eventName, beforeRemove) {
406
400
  }));
407
401
  }
408
402
  function onAdvertisementReceived(device) {
409
- return new rxjs_2.Observable((subscriber) => {
403
+ return new rxjs_1.Observable((subscriber) => {
410
404
  const abortController = new AbortController();
411
405
  const { signal } = abortController;
412
406
  const listener = device.addEventListener("advertisementreceived", (advertisement) => {
@@ -11,7 +11,7 @@ import { Credentials, CustomToken } from "../types/credentials";
11
11
  import { EmailAndPassword } from "../types/credentials";
12
12
  import { ChangeSettings } from "../types/settings";
13
13
  import { DeviceStatus } from "../types/status";
14
- import { DeviceInfo, DeviceSelector } from "../types/deviceInfo";
14
+ import { DeviceInfo, DeviceSelector, OSVersion } from "../types/deviceInfo";
15
15
  import { UserClaims } from "../types/user";
16
16
  import { OAuthRemoveResponse } from "../types/oauth";
17
17
  import { Experiment } from "../types/experiment";
@@ -30,8 +30,10 @@ export declare class CloudClient implements Client {
30
30
  protected timesync: Timesync;
31
31
  protected subscriptionManager: SubscriptionManager;
32
32
  protected status$: Observable<DeviceStatus>;
33
+ protected osVersion$: Observable<OSVersion>;
33
34
  constructor(options: SDKOptions);
34
35
  onDeviceChange(): Observable<DeviceInfo>;
36
+ osVersion(): Observable<OSVersion>;
35
37
  private setAutoSelectedDevice;
36
38
  get actions(): Actions;
37
39
  dispatchAction(action: Action): Promise<any>;
@@ -37,6 +37,7 @@ class CloudClient {
37
37
  this.firebaseUser = new firebase_1.FirebaseUser(this.firebaseApp);
38
38
  this._selectedDevice.next(undefined);
39
39
  this.status$ = (0, heartbeat_1.heartbeatAwareStatus)(this.observeNamespace("status").pipe((0, operators_1.share)())).pipe((0, filterInternalKeys_1.filterInternalKeys)(), (0, operators_1.shareReplay)(1));
40
+ this.osVersion$ = this.observeNamespace("info/osVersion").pipe((0, operators_1.shareReplay)(1));
40
41
  this.firebaseUser.onAuthStateChanged().subscribe((user) => {
41
42
  this.user = user;
42
43
  });
@@ -70,6 +71,9 @@ class CloudClient {
70
71
  .asObservable()
71
72
  .pipe((0, operators_1.filter)((value) => value !== undefined));
72
73
  }
74
+ osVersion() {
75
+ return this.osVersion$;
76
+ }
73
77
  // Automatically select device when user logs in
74
78
  setAutoSelectedDevice() {
75
79
  return __awaiter(this, void 0, void 0, function* () {