@neurosity/sdk 6.2.4 → 6.4.0-next.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 (40) hide show
  1. package/dist/browser/neurosity.iife.js +83 -17
  2. package/dist/browser/neurosity.js +7 -7
  3. package/dist/browser/neurosity.js.map +1 -1
  4. package/dist/cjs/Neurosity.d.ts +17 -1
  5. package/dist/cjs/Neurosity.js +26 -2
  6. package/dist/cjs/api/bluetooth/BluetoothClient.d.ts +3 -1
  7. package/dist/cjs/api/bluetooth/BluetoothClient.js +9 -5
  8. package/dist/cjs/api/bluetooth/BluetoothTransport.d.ts +2 -2
  9. package/dist/cjs/api/bluetooth/react-native/ReactNativeTransport.d.ts +3 -3
  10. package/dist/cjs/api/bluetooth/react-native/ReactNativeTransport.js +6 -4
  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 +3 -3
  14. package/dist/cjs/api/bluetooth/web/WebBluetoothTransport.js +8 -4
  15. package/dist/cjs/api/index.d.ts +3 -1
  16. package/dist/cjs/api/index.js +4 -0
  17. package/dist/cjs/types/deviceInfo.d.ts +2 -1
  18. package/dist/cjs/utils/oauth.js +1 -0
  19. package/dist/electron/index.js +7 -7
  20. package/dist/electron/index.js.map +1 -1
  21. package/dist/esm/Neurosity.d.ts +17 -1
  22. package/dist/esm/Neurosity.js +26 -2
  23. package/dist/esm/api/bluetooth/BluetoothClient.d.ts +3 -1
  24. package/dist/esm/api/bluetooth/BluetoothClient.js +10 -6
  25. package/dist/esm/api/bluetooth/BluetoothTransport.d.ts +2 -2
  26. package/dist/esm/api/bluetooth/react-native/ReactNativeTransport.d.ts +3 -3
  27. package/dist/esm/api/bluetooth/react-native/ReactNativeTransport.js +7 -5
  28. package/dist/esm/api/bluetooth/utils/osHasBluetoothSupport.d.ts +2 -2
  29. package/dist/esm/api/bluetooth/utils/osHasBluetoothSupport.js +4 -2
  30. package/dist/esm/api/bluetooth/web/WebBluetoothTransport.d.ts +3 -3
  31. package/dist/esm/api/bluetooth/web/WebBluetoothTransport.js +9 -5
  32. package/dist/esm/api/index.d.ts +3 -1
  33. package/dist/esm/api/index.js +4 -0
  34. package/dist/esm/neurosity.mjs +83 -17
  35. package/dist/esm/types/deviceInfo.d.ts +2 -1
  36. package/dist/esm/utils/oauth.js +1 -0
  37. package/dist/examples/neurosity.iife.js +83 -17
  38. package/dist/examples/neurosity.js +7 -7
  39. package/dist/examples/neurosity.mjs +83 -17
  40. package/package.json +1 -1
@@ -11,7 +11,7 @@ import { Calm } from "./types/calm";
11
11
  import { Focus } from "./types/focus";
12
12
  import { BrainwavesLabel, Epoch, PowerByBand, PSD } from "./types/brainwaves";
13
13
  import { Accelerometer } from "./types/accelerometer";
14
- import { DeviceInfo } from "./types/deviceInfo";
14
+ import { DeviceInfo, OSVersion } from "./types/deviceInfo";
15
15
  import { DeviceStatus } from "./types/status";
16
16
  import { Action } from "./types/actions";
17
17
  import { HapticEffects } from "./types/hapticEffects";
@@ -404,6 +404,22 @@ export declare class Neurosity {
404
404
  * @returns Observable of `settings` metric events
405
405
  */
406
406
  settings(): Observable<Settings>;
407
+ /**
408
+ * <StreamingModes wifi={true} />
409
+ *
410
+ * Observes the current OS version and all subsequent version changes in real-time.
411
+ *
412
+ * ```typescript
413
+ * neurosity.osVersion().subscribe((osVersion) => {
414
+ * console.log(osVersion);
415
+ * });
416
+ *
417
+ * // "16.0.0"
418
+ * ```
419
+ *
420
+ * @returns Observable of `osVersion` events. e.g 16.0.0
421
+ */
422
+ osVersion(): Observable<OSVersion>;
407
423
  /**
408
424
  * <StreamingModes wifi={true} bluetooth={true} />
409
425
  *
@@ -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
+ osVersion$: this.osVersion(),
102
104
  createBluetoothToken: this.createBluetoothToken.bind(this),
103
105
  transport: bluetoothTransport
104
106
  });
@@ -144,12 +146,12 @@ class Neurosity {
144
146
  streamingState() {
145
147
  const isWifiOnline = (state) => [status_1.STATUS.ONLINE, status_1.STATUS.UPDATING].includes(state);
146
148
  return this.streamingMode$.pipe((0, operators_1.switchMap)((streamingMode) => {
147
- return this.onDeviceChange().pipe((0, operators_1.switchMap)((selectDevice) => {
149
+ return this.onDeviceChange().pipe((0, operators_2.combineLatestWith)(this.osVersion()), (0, operators_1.switchMap)(([selectDevice, osVersion]) => {
148
150
  if (!selectDevice) {
149
151
  return rxjs_2.EMPTY;
150
152
  }
151
153
  const isUnableToUseBluetooth = this.isMissingBluetoothTransport ||
152
- !(0, bluetooth_1.osHasBluetoothSupport)(selectDevice);
154
+ !(0, bluetooth_1.osHasBluetoothSupport)(selectDevice, osVersion);
153
155
  if (isUnableToUseBluetooth) {
154
156
  return this.cloudClient.status().pipe((0, operators_1.map)(({ state }) => ({
155
157
  connected: isWifiOnline(state),
@@ -795,6 +797,28 @@ class Neurosity {
795
797
  }
796
798
  return this.cloudClient.observeNamespace("settings");
797
799
  }
800
+ /**
801
+ * <StreamingModes wifi={true} />
802
+ *
803
+ * Observes the current OS version and all subsequent version changes in real-time.
804
+ *
805
+ * ```typescript
806
+ * neurosity.osVersion().subscribe((osVersion) => {
807
+ * console.log(osVersion);
808
+ * });
809
+ *
810
+ * // "16.0.0"
811
+ * ```
812
+ *
813
+ * @returns Observable of `osVersion` events. e.g 16.0.0
814
+ */
815
+ osVersion() {
816
+ const [hasOAuthError, OAuthError] = (0, oauth_1.validateOAuthScopeForFunctionName)(this.cloudClient.userClaims, "osVersion");
817
+ if (hasOAuthError) {
818
+ return (0, rxjs_1.throwError)(() => OAuthError);
819
+ }
820
+ return this.cloudClient.osVersion();
821
+ }
798
822
  /**
799
823
  * <StreamingModes wifi={true} bluetooth={true} />
800
824
  *
@@ -2,7 +2,7 @@ import { Observable } from "rxjs";
2
2
  import { ReplaySubject } from "rxjs";
3
3
  import { WebBluetoothTransport } from "./web/WebBluetoothTransport";
4
4
  import { ReactNativeTransport } from "./react-native/ReactNativeTransport";
5
- import { DeviceInfo } from "../../types/deviceInfo";
5
+ import { DeviceInfo, OSVersion } from "../../types/deviceInfo";
6
6
  import { Action } from "../../types/actions";
7
7
  import { Epoch } from "../../types/epoch";
8
8
  import { BLUETOOTH_CONNECTION } from "./types";
@@ -16,12 +16,14 @@ declare type CreateBluetoothToken = () => Promise<string>;
16
16
  declare type Options = {
17
17
  transport: BluetoothTransport;
18
18
  selectedDevice$: Observable<DeviceInfo>;
19
+ osVersion$: Observable<OSVersion>;
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
+ osVersion$: ReplaySubject<string>;
25
27
  isAuthenticated$: ReplaySubject<boolean>;
26
28
  _focus$: Observable<any>;
27
29
  _calm$: Observable<any>;
@@ -22,6 +22,7 @@ const osHasBluetoothSupport_1 = require("./utils/osHasBluetoothSupport");
22
22
  class BluetoothClient {
23
23
  constructor(options) {
24
24
  this.selectedDevice$ = new rxjs_2.ReplaySubject(1);
25
+ this.osVersion$ = new rxjs_2.ReplaySubject(1);
25
26
  this.isAuthenticated$ = new rxjs_2.ReplaySubject(1);
26
27
  const { transport, selectedDevice$, createBluetoothToken } = options !== null && options !== void 0 ? options : {};
27
28
  if (!transport) {
@@ -33,7 +34,9 @@ class BluetoothClient {
33
34
  selectedDevice$.subscribe(this.selectedDevice$);
34
35
  }
35
36
  // Auto Connect
36
- this.transport._autoConnect(this.selectedDevice$).subscribe({
37
+ this.transport
38
+ ._autoConnect(this.selectedDevice$, this.osVersion$)
39
+ .subscribe({
37
40
  error: (error) => {
38
41
  var _a;
39
42
  this.transport.addLog(`Auto connect: error -> ${(_a = error === null || error === void 0 ? void 0 : error.message) !== null && _a !== void 0 ? _a : error}`);
@@ -48,7 +51,7 @@ class BluetoothClient {
48
51
  this.transport.addLog("Auto authentication not enabled");
49
52
  }
50
53
  // Auto manage action notifications
51
- this.transport._autoToggleActionNotifications(this.selectedDevice$);
54
+ this.transport._autoToggleActionNotifications(this.selectedDevice$, this.osVersion$);
52
55
  // Multicast metrics (share)
53
56
  this._focus$ = this._subscribeWhileAuthenticated("focus");
54
57
  this._calm$ = this._subscribeWhileAuthenticated("calm");
@@ -72,7 +75,7 @@ class BluetoothClient {
72
75
  const reauthenticateInterval$ = (0, rxjs_1.timer)(0, REAUTHENTICATE_INTERVAL).pipe((0, operators_1.tap)(() => {
73
76
  this.transport.addLog(`Auto authentication in progress...`);
74
77
  }));
75
- return this.selectedDevice$.pipe((0, operators_1.switchMap)((selectedDevice) => !(0, osHasBluetoothSupport_1.osHasBluetoothSupport)(selectedDevice)
78
+ return this.selectedDevice$.pipe((0, operators_1.combineLatestWith)(this.osVersion$), (0, operators_1.switchMap)(([selectedDevice, osVersion]) => !(0, osHasBluetoothSupport_1.osHasBluetoothSupport)(selectedDevice, osVersion)
76
79
  ? rxjs_2.EMPTY
77
80
  : this.connection().pipe((0, operators_1.switchMap)((connection) => connection === types_1.BLUETOOTH_CONNECTION.CONNECTED
78
81
  ? reauthenticateInterval$
@@ -92,7 +95,8 @@ class BluetoothClient {
92
95
  _hasBluetoothSupport() {
93
96
  return __awaiter(this, void 0, void 0, function* () {
94
97
  const selectedDevice = yield (0, rxjs_1.firstValueFrom)(this.selectedDevice$);
95
- return (0, osHasBluetoothSupport_1.osHasBluetoothSupport)(selectedDevice);
98
+ const osVersion = yield (0, rxjs_1.firstValueFrom)(this.osVersion$);
99
+ return (0, osHasBluetoothSupport_1.osHasBluetoothSupport)(selectedDevice, osVersion);
96
100
  });
97
101
  }
98
102
  authenticate(token) {
@@ -173,7 +177,7 @@ class BluetoothClient {
173
177
  });
174
178
  }
175
179
  _subscribeWhileAuthenticated(characteristicName) {
176
- return this.selectedDevice$.pipe((0, operators_1.switchMap)((selectedDevice) => !(0, osHasBluetoothSupport_1.osHasBluetoothSupport)(selectedDevice)
180
+ return this.selectedDevice$.pipe((0, operators_1.combineLatestWith)(this.osVersion$), (0, operators_1.switchMap)(([selectedDevice, osVersion]) => !(0, osHasBluetoothSupport_1.osHasBluetoothSupport)(selectedDevice, osVersion)
177
181
  ? rxjs_2.EMPTY
178
182
  : this.isAuthenticated$.pipe((0, operators_2.distinctUntilChanged)(), (0, operators_1.switchMap)((isAuthenticated) => isAuthenticated
179
183
  ? this.transport.subscribeToCharacteristic({
@@ -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;
@@ -7,7 +7,7 @@ import { BleManager } from "./types/BleManagerTypes";
7
7
  import { Peripheral } from "./types/BleManagerTypes";
8
8
  import { NativeEventEmitter } from "./types/ReactNativeTypes";
9
9
  import { PlatformOSType } from "./types/ReactNativeTypes";
10
- import { DeviceInfo } from "../../../types/deviceInfo";
10
+ import { DeviceInfo, OSVersion } from "../../../types/deviceInfo";
11
11
  declare type Characteristic = {
12
12
  characteristicUUID: string;
13
13
  serviceUUID: string;
@@ -48,7 +48,7 @@ export declare class ReactNativeTransport implements BluetoothTransport {
48
48
  constructor(options: Options);
49
49
  addLog(log: string): void;
50
50
  isConnected(): boolean;
51
- _autoConnect(selectedDevice$: Observable<DeviceInfo>): Observable<void>;
51
+ _autoConnect(selectedDevice$: Observable<DeviceInfo>, osVersion$: Observable<OSVersion>): Observable<void>;
52
52
  enableAutoConnect(autoConnect: boolean): void;
53
53
  connection(): Observable<BLUETOOTH_CONNECTION>;
54
54
  _fromEvent(eventName: string): Observable<any>;
@@ -65,7 +65,7 @@ export declare class ReactNativeTransport implements BluetoothTransport {
65
65
  writeCharacteristic(characteristicName: string, data: string): Promise<void>;
66
66
  _addPendingAction(actionId: number): void;
67
67
  _removePendingAction(actionId: number): void;
68
- _autoToggleActionNotifications(selectedDevice$: Observable<DeviceInfo>): Promise<void>;
68
+ _autoToggleActionNotifications(selectedDevice$: Observable<DeviceInfo>, osVersion$: Observable<OSVersion>): Promise<void>;
69
69
  dispatchAction({ characteristicName, action }: ActionOptions): Promise<any>;
70
70
  }
71
71
  export {};
@@ -104,11 +104,11 @@ class ReactNativeTransport {
104
104
  const connection = this.connection$.getValue();
105
105
  return connection === types_1.BLUETOOTH_CONNECTION.CONNECTED;
106
106
  }
107
- _autoConnect(selectedDevice$) {
107
+ _autoConnect(selectedDevice$, osVersion$) {
108
108
  const selectedDeviceAfterDisconnect$ = this.onDisconnected$.pipe((0, operators_1.switchMap)(() => selectedDevice$));
109
109
  return this._isAutoConnectEnabled$.pipe((0, operators_1.switchMap)((isAutoConnectEnabled) => isAutoConnectEnabled
110
110
  ? (0, rxjs_1.merge)(selectedDevice$, selectedDeviceAfterDisconnect$)
111
- : rxjs_2.NEVER), (0, operators_1.switchMap)((selectedDevice) => !(0, osHasBluetoothSupport_1.osHasBluetoothSupport)(selectedDevice)
111
+ : rxjs_2.NEVER), (0, operators_3.combineLatestWith)(osVersion$), (0, operators_1.switchMap)(([selectedDevice, osVersion]) => !(0, osHasBluetoothSupport_1.osHasBluetoothSupport)(selectedDevice, osVersion)
112
112
  ? rxjs_2.NEVER
113
113
  : this.scan().pipe((0, operators_1.switchMap)((peripherals) => {
114
114
  const peripheralMatch = peripherals.find((peripheral) => peripheral.name === (selectedDevice === null || selectedDevice === void 0 ? void 0 : selectedDevice.deviceNickname));
@@ -336,7 +336,7 @@ class ReactNativeTransport {
336
336
  const actions = this.pendingActions$.getValue();
337
337
  this.pendingActions$.next(actions.filter((id) => id !== actionId));
338
338
  }
339
- _autoToggleActionNotifications(selectedDevice$) {
339
+ _autoToggleActionNotifications(selectedDevice$, osVersion$) {
340
340
  return __awaiter(this, void 0, void 0, function* () {
341
341
  let started = false;
342
342
  const sideEffects$ = this.connection$.asObservable().pipe((0, operators_1.switchMap)((connection) => connection === types_1.BLUETOOTH_CONNECTION.CONNECTED
@@ -367,7 +367,9 @@ class ReactNativeTransport {
367
367
  }
368
368
  })));
369
369
  selectedDevice$
370
- .pipe((0, operators_1.switchMap)((selectedDevice) => !(0, osHasBluetoothSupport_1.osHasBluetoothSupport)(selectedDevice) ? rxjs_2.EMPTY : sideEffects$))
370
+ .pipe((0, operators_3.combineLatestWith)(osVersion$), (0, operators_1.switchMap)(([selectedDevice, osVersion]) => !(0, osHasBluetoothSupport_1.osHasBluetoothSupport)(selectedDevice, osVersion)
371
+ ? rxjs_2.EMPTY
372
+ : sideEffects$))
371
373
  .subscribe();
372
374
  });
373
375
  }
@@ -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;
@@ -4,7 +4,7 @@ import { Observable } from "rxjs";
4
4
  import { BluetoothTransport } from "../BluetoothTransport";
5
5
  import { ActionOptions, SubscribeOptions } from "../types";
6
6
  import { TRANSPORT_TYPE, BLUETOOTH_CONNECTION } from "../types";
7
- import { DeviceInfo } from "../../../types/deviceInfo";
7
+ import { DeviceInfo, OSVersion } from "../../../types/deviceInfo";
8
8
  declare type Options = {
9
9
  autoConnect?: boolean;
10
10
  };
@@ -25,7 +25,7 @@ export declare class WebBluetoothTransport implements BluetoothTransport {
25
25
  _isAutoConnectEnabled$: ReplaySubject<boolean>;
26
26
  constructor(options?: Options);
27
27
  _getPairedDevices(): Promise<BluetoothDevice[]>;
28
- _autoConnect(selectedDevice$: Observable<DeviceInfo>): Observable<void>;
28
+ _autoConnect(selectedDevice$: Observable<DeviceInfo>, osVersion$: Observable<OSVersion>): Observable<void>;
29
29
  enableAutoConnect(autoConnect: boolean): void;
30
30
  addLog(log: string): void;
31
31
  isConnected(): boolean;
@@ -48,7 +48,7 @@ export declare class WebBluetoothTransport implements BluetoothTransport {
48
48
  writeCharacteristic(characteristicName: string, data: string): Promise<void>;
49
49
  _addPendingAction(actionId: number): void;
50
50
  _removePendingAction(actionId: number): void;
51
- _autoToggleActionNotifications(selectedDevice$: Observable<DeviceInfo>): Promise<void>;
51
+ _autoToggleActionNotifications(selectedDevice$: Observable<DeviceInfo>, osVersion$: Observable<OSVersion>): Promise<void>;
52
52
  dispatchAction({ characteristicName, action }: ActionOptions): Promise<any>;
53
53
  }
54
54
  export {};
@@ -64,10 +64,12 @@ class WebBluetoothTransport {
64
64
  return yield navigator.bluetooth.getDevices();
65
65
  });
66
66
  }
67
- _autoConnect(selectedDevice$) {
67
+ _autoConnect(selectedDevice$, osVersion$) {
68
68
  return this._isAutoConnectEnabled$.pipe((0, operators_1.switchMap)((isAutoConnectEnabled) => isAutoConnectEnabled
69
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* () {
70
+ : rxjs_2.NEVER), (0, operators_1.combineLatestWith)(osVersion$), (0, operators_1.switchMap)(([selectedDevice, osVersion]) => (0, osHasBluetoothSupport_1.osHasBluetoothSupport)(selectedDevice, osVersion)
71
+ ? (0, rxjs_1.of)(selectedDevice)
72
+ : rxjs_2.EMPTY), (0, operators_1.switchMap)((selectedDevice) => __awaiter(this, void 0, void 0, function* () {
71
73
  var _a;
72
74
  const { deviceNickname } = selectedDevice;
73
75
  if (this.isConnected()) {
@@ -307,7 +309,7 @@ class WebBluetoothTransport {
307
309
  const actions = this.pendingActions$.getValue();
308
310
  this.pendingActions$.next(actions.filter((id) => id !== actionId));
309
311
  }
310
- _autoToggleActionNotifications(selectedDevice$) {
312
+ _autoToggleActionNotifications(selectedDevice$, osVersion$) {
311
313
  return __awaiter(this, void 0, void 0, function* () {
312
314
  let actionsCharacteristic;
313
315
  let started = false;
@@ -341,7 +343,9 @@ class WebBluetoothTransport {
341
343
  }
342
344
  })));
343
345
  selectedDevice$
344
- .pipe((0, operators_1.switchMap)((selectedDevice) => !(0, osHasBluetoothSupport_1.osHasBluetoothSupport)(selectedDevice) ? rxjs_2.EMPTY : sideEffects$))
346
+ .pipe((0, operators_1.combineLatestWith)(osVersion$), (0, operators_1.switchMap)(([selectedDevice, osVersion]) => !(0, osHasBluetoothSupport_1.osHasBluetoothSupport)(selectedDevice, osVersion)
347
+ ? rxjs_2.EMPTY
348
+ : sideEffects$))
345
349
  .subscribe();
346
350
  });
347
351
  }
@@ -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* () {
@@ -1,3 +1,4 @@
1
+ export declare type OSVersion = string;
1
2
  export interface DeviceInfo {
2
3
  deviceId: string;
3
4
  deviceNickname: string;
@@ -8,7 +9,7 @@ export interface DeviceInfo {
8
9
  model: string;
9
10
  modelName: string;
10
11
  modelVersion: string;
11
- osVersion: string;
12
+ osVersion: OSVersion;
12
13
  apiVersion: string;
13
14
  emulator?: boolean;
14
15
  }
@@ -50,6 +50,7 @@ const scopeRequiredByFunctionName = {
50
50
  selectDevice: "read:devices-info",
51
51
  onDeviceChange: "read:devices-info",
52
52
  onUserDevicesChange: "read:devices-info",
53
+ osVersion: "read:devices-info",
53
54
  // end device info
54
55
  settings: "read:devices-settings",
55
56
  changeSettings: "write:devices-settings",