diff --git a/src/Neurosity.ts b/src/Neurosity.ts index cba1caf..cf51602 100644 --- a/src/Neurosity.ts +++ b/src/Neurosity.ts @@ -18,7 +18,7 @@ import { Focus } from "./types/focus"; import { getLabels } from "./utils/subscription"; import { BrainwavesLabel, Epoch, PowerByBand, PSD } from "./types/brainwaves"; import { Accelerometer } from "./types/accelerometer"; -import { DeviceInfo, OSVersion } from "./types/deviceInfo"; +import { DeviceInfo, DeviceSelector, OSVersion } from "./types/deviceInfo"; import { DeviceStatus, STATUS } from "./types/status"; import { Action } from "./types/actions"; import { HapticEffects } from "./types/hapticEffects"; @@ -526,7 +526,7 @@ export class Neurosity { * For more info, check out the "Device Selection" guide. */ public async selectDevice( - deviceSelector: (devices: DeviceInfo[]) => DeviceInfo + deviceSelector: DeviceSelector ): Promise { const [hasOAuthError, OAuthError] = validateOAuthScopeForFunctionName( this.cloudClient.userClaims, diff --git a/src/api/index.ts b/src/api/index.ts index 0bba9b7..f90b304 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -18,7 +18,7 @@ import { EmailAndPassword } from "../types/credentials"; import { ChangeSettings } from "../types/settings"; import { Subscription } from "../types/subscriptions"; import { DeviceStatus } from "../types/status"; -import { DeviceInfo, DeviceSelector, OSVersion } from "../types/deviceInfo"; +import { DeviceInfo, DeviceSelector, DeviceSelectorFunction, OSVersion } from "../types/deviceInfo"; import { UserClaims } from "../types/user"; import { OAuthRemoveResponse } from "../types/oauth"; import { Experiment } from "../types/experiment"; @@ -250,6 +250,72 @@ export class CloudClient implements Client { return !!selectedDevice; } + private async finalizeDeviceSelection(device: DeviceInfo): Promise { + const hasPermission = await this.firebaseUser.hasDevicePermission( + device.deviceId + ); + + if (!hasPermission) { + return Promise.reject(`Rejected device access due to permissions.`); + } + + this._selectedDevice.next(device); + + return device; + } + + /** + * Selects a device from the list of available devices based on a key-value pair of the device information. + * + * @template K The type of the key. + * @param {K} key The key to search for in the device information. + * @param {DeviceInfo[K]} value The value to match with the specified key. + * @returns {Promise} A promise that resolves to the selected device information. + * @throws {Error} If no devices are found for the user or if no device is found with the specified key-value pair. + */ + public async selectDeviceByKeyValue( + key: K, + value: DeviceInfo[K] + ): Promise { + const devices = await this.getDevices(); + if (!devices.length) { + throw new Error("No devices found for this user."); + } + + const selectedDevice = devices.find(device => JSON.stringify(device[key]) === JSON.stringify(value)); + if (!selectedDevice) { + throw new Error("Device not found with specified key-value pair."); + } + + return this.finalizeDeviceSelection(selectedDevice); + } + + /** + * Selects a device based on the provided device selector function. + * + * @param deviceSelector The device selector function used to select a device from the available devices. + * @returns A promise that resolves to the selected device information. + * @throws {Error} An error if no devices are found for the user or if the specified device is not found. + */ + public async selectDeviceBySelector( + deviceSelector: DeviceSelectorFunction + ): Promise { + const devices = await this.getDevices(); + if (!devices.length) { + throw new Error("No devices found for this user."); + } + + const selectedDevice = deviceSelector(devices); + if (!selectedDevice) { + throw new Error("Device not found with specified selector."); + } + + return this.finalizeDeviceSelection(selectedDevice); + } + + /** + * @deprecated Use `selectDeviceByKeyValue` or `selectDeviceBySelector` instead. + */ public async selectDevice( deviceSelector: DeviceSelector ): Promise { diff --git a/src/types/deviceInfo.ts b/src/types/deviceInfo.ts index d5af74c..6e91e75 100644 --- a/src/types/deviceInfo.ts +++ b/src/types/deviceInfo.ts @@ -16,6 +16,6 @@ export interface DeviceInfo { } type DeviceSelectorKeyValue = [string, string | number | string[]]; -type DeviceSelectorFunction = (devices: DeviceInfo[]) => DeviceInfo; +export type DeviceSelectorFunction = (devices: DeviceInfo[]) => DeviceInfo; export type DeviceSelector = DeviceSelectorKeyValue | DeviceSelectorFunction;