@neurosity/sdk 6.2.4 → 6.3.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.
- package/dist/browser/neurosity.iife.js +23 -0
- package/dist/browser/neurosity.js +2 -2
- package/dist/browser/neurosity.js.map +1 -1
- package/dist/cjs/Neurosity.d.ts +17 -1
- package/dist/cjs/Neurosity.js +22 -0
- package/dist/cjs/types/deviceInfo.d.ts +2 -1
- package/dist/cjs/utils/oauth.js +1 -0
- package/dist/electron/index.js +2 -2
- package/dist/electron/index.js.map +1 -1
- package/dist/esm/Neurosity.d.ts +17 -1
- package/dist/esm/Neurosity.js +22 -0
- package/dist/esm/neurosity.mjs +23 -0
- package/dist/esm/types/deviceInfo.d.ts +2 -1
- package/dist/esm/utils/oauth.js +1 -0
- package/dist/examples/neurosity.iife.js +23 -0
- package/dist/examples/neurosity.js +2 -2
- package/dist/examples/neurosity.mjs +23 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["api/firebase/config.ts","api/firebase/FirebaseApp.ts","api/firebase/FirebaseUser.ts","api/firebase/deviceStore.ts","api/firebase/FirebaseDevice.ts","api/firebase/index.ts","utils/whileOnline.ts","timesync/Timesync.ts","timesync/index.ts","subscriptions/SubscriptionManager.ts","types/status.ts","utils/heartbeat.ts","utils/filterInternalKeys.ts","api/index.ts","types/streaming.ts","utils/errors.ts","utils/subscription.ts","utils/platform.ts","utils/hapticEffects.ts","utils/oauth.ts","api/https/config.ts","api/https/utils.ts","api/https/createOAuthURL.ts","api/https/getOAuthToken.ts","utils/is-node.ts","utils/metrics.ts","api/bluetooth/web/isMaybeWebWorkerContext.ts","api/bluetooth/web/isWebBluetoothSupported.ts","api/bluetooth/utils/create6DigitPin.ts","api/bluetooth/utils/stitch.ts","api/bluetooth/types/index.ts","api/bluetooth/utils/encoding.ts","api/bluetooth/constants.ts","api/bluetooth/utils/osHasBluetoothSupport.ts","api/bluetooth/web/WebBluetoothTransport.ts","api/bluetooth/react-native/ReactNativeTransport.ts","utils/pipes.ts","api/bluetooth/utils/csvBufferToEpoch.ts","api/bluetooth/BluetoothClient.ts","api/bluetooth/index.ts","Neurosity.ts","index.ts"],"names":[],"mappings":"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","file":"index.js","sourceRoot":"../../src","sourcesContent":["export const config = {\n apiKey: \"AIzaSyB0TkZ83Fj0CIzn8AAmE-Osc92s3ER8hy8\",\n authDomain: \"neurosity-device.firebaseapp.com\",\n databaseURL: \"https://neurosity-device.firebaseio.com\",\n projectId: \"neurosity-device\",\n storageBucket: \"neurosity-device.appspot.com\",\n messagingSenderId: \"212595049674\"\n};\n","import firebase from \"firebase/app\";\nimport \"firebase/database\";\nimport \"firebase/auth\";\nimport \"firebase/functions\";\nimport \"firebase/firestore\";\n\nimport { config } from \"./config\";\nimport { SDKOptions } from \"../../types/options\";\n\nexport const SERVER_TIMESTAMP = firebase.database.ServerValue.TIMESTAMP;\n\n/**\n * @hidden\n */\nexport class FirebaseApp {\n protected standalone: boolean;\n public app: firebase.app.App;\n\n constructor(options: SDKOptions) {\n this.app = this.getApp(options.deviceId);\n this.standalone = this.app.name === options.deviceId;\n\n if (options.emulator) {\n this.connectEmulators(options);\n }\n }\n\n private getApp(deviceId?: string) {\n const moduleApps = firebase.apps;\n const browserApps =\n typeof window !== \"undefined\" &&\n \"firebase\" in window &&\n \"apps\" in window.firebase\n ? window[\"firebase\"][\"apps\"]\n : [];\n\n const neurosityApp = [...moduleApps, ...(browserApps as any[])].find(\n (app: any) =>\n app.name === \"[DEFAULT]\" &&\n app.options.databaseURL === config.databaseURL\n );\n\n if (neurosityApp) {\n return neurosityApp;\n }\n\n if (deviceId) {\n const neurosityAppName = deviceId;\n const neurosityApp = moduleApps.find(\n (app) => app.name === neurosityAppName\n );\n return neurosityApp\n ? neurosityApp\n : firebase.initializeApp(config, neurosityAppName);\n }\n\n return firebase.initializeApp(config);\n }\n\n connectEmulators(options: SDKOptions) {\n const {\n emulatorHost,\n emulatorAuthPort,\n emulatorDatabasePort,\n emulatorFunctionsPort,\n emulatorFirestorePort,\n emulatorOptions\n } = options;\n\n this.app.auth().useEmulator(`http://${emulatorHost}:${emulatorAuthPort}`);\n this.app\n .database()\n .useEmulator(emulatorHost, emulatorDatabasePort, emulatorOptions);\n this.app.functions().useEmulator(emulatorHost, emulatorFunctionsPort);\n this.app\n .firestore()\n .useEmulator(emulatorHost, emulatorFirestorePort, emulatorOptions);\n }\n\n goOnline() {\n this.app.database().goOnline();\n }\n\n goOffline() {\n this.app.database().goOffline();\n }\n\n public disconnect(): Promise<any> {\n if (this.standalone) {\n return this.app.delete();\n }\n return Promise.resolve();\n }\n}\n","import { Observable, fromEventPattern, from, EMPTY } from \"rxjs\";\nimport { map, switchMap } from \"rxjs/operators\";\nimport firebase from \"firebase/app\";\nimport { User } from \"@firebase/auth-types\";\n\nimport { FirebaseApp } from \"./FirebaseApp\";\nimport {\n Credentials,\n EmailAndPassword,\n CustomToken\n} from \"../../types/credentials\";\nimport { UserDevices, UserClaims } from \"../../types/user\";\nimport { DeviceInfo } from \"../../types/deviceInfo\";\nimport { OAuthRemoveResponse } from \"../../types/oauth\";\nimport { Experiment } from \"../../types/experiment\";\nimport { TransferDeviceOptions } from \"../../utils/transferDevice\";\n\nconst SERVER_TIMESTAMP = firebase.database.ServerValue.TIMESTAMP;\n\n/**\n * @hidden\n */\nexport const credentialWithLink: Function =\n firebase.auth.EmailAuthProvider.credentialWithLink;\n\n/**\n * @hidden\n */\nexport function createUser(...args) {\n return new (firebase as any).User(...args);\n}\n\n/**\n * @hidden\n */\nexport class FirebaseUser {\n public app: firebase.app.App;\n public user: User | null;\n\n constructor(firebaseApp: FirebaseApp) {\n this.app = firebaseApp.app;\n\n this.app.auth().onAuthStateChanged((user: User | null) => {\n this.user = user;\n });\n }\n\n public auth() {\n return this.app.auth();\n }\n\n async createAccount(credentials: EmailAndPassword) {\n const { email, password } = credentials;\n const [error, user] = await this.app\n .auth()\n .createUserWithEmailAndPassword(email, password)\n .then((user) => [null, user])\n .catch((error) => [error, null]);\n\n if (error) {\n return Promise.reject(error);\n }\n\n return user;\n }\n\n async deleteAccount() {\n const user = this.app.auth().currentUser;\n\n if (!user) {\n return Promise.reject(\n new Error(\n `You are trying to delete an account that is not authenticated. To delete an account, the account must have signed in recently.`\n )\n );\n }\n\n const [devicesError, devices] = await this.getDevices()\n .then((response) => [null, response])\n .catch((error) => [error, null]);\n\n if (devicesError) {\n return Promise.reject(devicesError);\n }\n\n if (devices.length) {\n const removeDeviceError = await Promise.all(\n devices.map((device) => this.removeDevice(device.deviceId))\n )\n .then(() => null)\n .catch((error) => error);\n\n if (removeDeviceError) {\n return Promise.reject(removeDeviceError);\n }\n }\n\n return user.delete();\n }\n\n onAuthStateChanged(): Observable<User | null> {\n return new Observable((subscriber) => {\n try {\n this.app.auth().onAuthStateChanged(\n (user: User | null) => {\n subscriber.next(user);\n },\n (error) => {\n subscriber.error(error);\n }\n );\n } catch (error) {\n subscriber.error(error);\n }\n });\n }\n\n onLogin(): Observable<User> {\n return new Observable((subscriber) => {\n const unsubscribe = this.app\n .auth()\n .onAuthStateChanged((user: User) => {\n if (!!user) {\n subscriber.next(user);\n subscriber.complete();\n }\n });\n return () => unsubscribe();\n });\n }\n\n login(credentials: Credentials) {\n if (\"customToken\" in credentials) {\n const { customToken } = credentials;\n return this.app.auth().signInWithCustomToken(customToken);\n }\n\n if (\"idToken\" in credentials && \"providerId\" in credentials) {\n const provider = new firebase.auth.OAuthProvider(\n credentials.providerId\n );\n const oAuthCredential = provider.credential(credentials.idToken);\n return this.app.auth().signInWithCredential(oAuthCredential);\n }\n\n if (\"email\" in credentials && \"password\" in credentials) {\n const { email, password } = credentials;\n return this.app\n .auth()\n .signInWithEmailAndPassword(email, password);\n }\n\n throw new Error(\n `Either {email,password}, {customToken}, or {idToken,providerId} is required`\n );\n }\n\n logout() {\n return this.app.auth().signOut();\n }\n\n public async createCustomToken(): Promise<CustomToken> {\n const [error, customToken] = await this.app\n .functions()\n .httpsCallable(\"createCustomToken\")()\n .then(({ data }) => [null, data])\n .catch((error) => [error, null]);\n\n if (error) {\n return Promise.reject(error);\n }\n\n return customToken;\n }\n\n public async removeOAuthAccess(): Promise<OAuthRemoveResponse> {\n const userId = this.user?.uid;\n\n if (!userId) {\n return Promise.reject(\n `OAuth access can only be removed while logged in via OAuth.`\n );\n }\n\n const [error, response] = await this.app\n .functions()\n .httpsCallable(\"removeAccessOAuthApp\")()\n .then(({ data }) => [null, data])\n .catch((error) => [error, null]);\n\n if (error) {\n return Promise.reject(error);\n }\n\n const logoutError = await this.logout()\n .then(() => false)\n .catch((error) => error);\n\n if (logoutError) {\n return Promise.reject(logoutError);\n }\n\n return response;\n }\n\n async getDevices() {\n const userId = this.user?.uid;\n\n if (!userId) {\n return Promise.reject(`Please login.`);\n }\n\n const snapshot = await this.app\n .database()\n .ref(this.getUserDevicesPath())\n .once(\"value\");\n\n const userDevices: UserDevices | null = snapshot.val();\n\n return this.userDevicesToDeviceInfoList(userDevices);\n }\n\n async addDevice(deviceId: string): Promise<void> {\n const userId = this.user?.uid;\n\n if (!userId) {\n return Promise.reject(`Please login.`);\n }\n\n const devices = await this.getDevices().catch((error) => {\n console.log(error);\n });\n\n const deviceAlreadyInAccount =\n devices &&\n devices.length &&\n devices.map(({ deviceId }) => deviceId).includes(deviceId);\n\n if (deviceAlreadyInAccount) {\n return Promise.reject(\n `The device is already added to this account.`\n );\n }\n\n const [isValid, invalidErrorMessage] = await this.isDeviceIdValid(\n deviceId\n )\n .then((isValid) => [isValid])\n .catch((error) => [false, error]);\n\n if (!isValid) {\n return Promise.reject(invalidErrorMessage);\n }\n\n const claimedByPath = this.getDeviceClaimedByPath(deviceId);\n const userDevicePath = this.getUserClaimedDevicePath(deviceId);\n\n const [hasError, errorMessage] = await this.app\n .database()\n .ref()\n .update({\n [claimedByPath]: userId,\n [userDevicePath]: {\n claimedOn: SERVER_TIMESTAMP\n }\n })\n .then(() => [false])\n .catch((error) => [true, error]);\n\n if (hasError) {\n return Promise.reject(errorMessage);\n }\n }\n\n async removeDevice(deviceId: string): Promise<void> {\n const userId = this.user?.uid;\n\n if (!userId) {\n return Promise.reject(`Please login.`);\n }\n\n const claimedByPath = this.getDeviceClaimedByPath(deviceId);\n const userDevicePath = this.getUserClaimedDevicePath(deviceId);\n\n const claimedByRef = this.app.database().ref(claimedByPath);\n const userDeviceRef = this.app.database().ref(userDevicePath);\n\n const [hasError, errorMessage] = await Promise.all([\n claimedByRef.remove(),\n userDeviceRef.remove()\n ])\n .then(() => [false])\n .catch((error) => [true, error]);\n\n if (hasError) {\n return Promise.reject(errorMessage);\n }\n }\n\n public async transferDevice(\n options: TransferDeviceOptions\n ): Promise<void> {\n const userId = this.user?.uid;\n\n if (!userId) {\n return Promise.reject(\n new Error(`transferDevice: auth is required.`)\n );\n }\n\n if (\n !(\"recipientsEmail\" in options) &&\n !(\"recipientsUserId\" in options)\n ) {\n return Promise.reject(\n new Error(\n `transferDevice: either 'recipientsEmail' or 'recipientsUserId' key is required.`\n )\n );\n }\n\n if (!options?.deviceId) {\n return Promise.reject(\n new Error(`transferDevice: a deviceId is required.`)\n );\n }\n\n const [error, response] = await this.app\n .functions()\n .httpsCallable(\"transferDeviceOwnership\")(options)\n .then(({ data }) => [null, data])\n .catch((error) => [error, null]);\n\n if (error) {\n return Promise.reject(error);\n }\n }\n\n async isDeviceIdValid(deviceId: string): Promise<boolean> {\n // hex string of 32 characters\n const hexRegEx = /[0-9A-Fa-f]{32}/g;\n if (\n !deviceId ||\n deviceId.length !== 32 ||\n !hexRegEx.test(deviceId)\n ) {\n return Promise.reject(\"The device id is incorrectly formatted.\");\n }\n\n const claimedByPath = this.getDeviceClaimedByPath(deviceId);\n const claimedByRef = this.app.database().ref(claimedByPath);\n\n const claimedBySnapshot = await claimedByRef\n .once(\"value\")\n .catch(() => null);\n\n if (!claimedBySnapshot || claimedBySnapshot.exists()) {\n return Promise.reject(\"The device has already been claimed.\");\n }\n\n return true;\n }\n\n onUserDevicesChange(): Observable<DeviceInfo[]> {\n return this.onAuthStateChanged().pipe(\n switchMap((user) => {\n if (!user) {\n return EMPTY;\n }\n\n const userDevicesPath = this.getUserDevicesPath();\n const userDevicesRef = this.app.database().ref(userDevicesPath);\n\n return fromEventPattern(\n (handler) => userDevicesRef.on(\"value\", handler),\n (handler) => userDevicesRef.off(\"value\", handler)\n ).pipe(\n map(([snapshot]: [firebase.database.DataSnapshot]) =>\n snapshot.val()\n ),\n switchMap((userDevices: UserDevices | null) => {\n return from(this.userDevicesToDeviceInfoList(userDevices));\n })\n );\n })\n );\n }\n\n onUserClaimsChange(): Observable<UserClaims> {\n return this.onAuthStateChanged().pipe(\n switchMap((user) => {\n if (!user) {\n return EMPTY;\n }\n\n const claimsUpdatedOnPath = this.getUserClaimsUpdatedOnPath();\n\n const claimsUpdatedOnRef = this.app\n .database()\n .ref(claimsUpdatedOnPath);\n\n return fromEventPattern(\n (handler) => claimsUpdatedOnRef.on(\"value\", handler),\n (handler) => claimsUpdatedOnRef.off(\"value\", handler)\n ).pipe(\n map(([snapshot]: [firebase.database.DataSnapshot]) =>\n snapshot.val()\n ),\n switchMap(() => {\n // Force refresh of auth id token\n return from(this.getIdToken(true)).pipe(\n switchMap(() => from(this.getClaims()))\n );\n })\n );\n })\n );\n }\n\n async getIdToken(forceRefresh = false): Promise<void> {\n const user = this.app.auth()?.currentUser;\n\n if (!user) {\n return Promise.reject(\n `getUserIdToken: unable to get currentUser`\n );\n }\n\n await user.getIdToken(forceRefresh).catch((error) => {\n console.error(error);\n });\n }\n\n getClaims(): Promise<UserClaims> {\n const user = this.app.auth()?.currentUser;\n\n if (!user) {\n return Promise.reject(`getUserClaims: unable to get currentUser`);\n }\n\n return user\n .getIdTokenResult()\n .then((token) => token.claims)\n .catch((error) => {\n console.error(error);\n return null;\n });\n }\n\n private async userDevicesToDeviceInfoList(\n userDevices: UserDevices | null\n ): Promise<DeviceInfo[]> {\n const devicesInfoSnapshots = Object.keys(userDevices ?? {}).map(\n (deviceId) =>\n this.app\n .database()\n .ref(this.getDeviceInfoPath(deviceId))\n .once(\"value\")\n );\n\n const devicesList: DeviceInfo[] = await Promise.all(\n devicesInfoSnapshots\n ).then((snapshots) => snapshots.map((snapshot) => snapshot.val()));\n\n const validDevices = devicesList.filter((device) => !!device);\n\n validDevices.sort((a, b) => {\n return (\n userDevices[a.deviceId].claimedOn -\n userDevices[b.deviceId].claimedOn\n );\n });\n\n return validDevices;\n }\n\n public async hasDevicePermission(deviceId: string): Promise<boolean> {\n const deviceInfoPath = this.getDeviceInfoPath(deviceId);\n\n const hasPermission = await this.app\n .database()\n .ref(deviceInfoPath)\n .once(\"value\")\n .then(() => true)\n .catch(() => false);\n\n return hasPermission;\n }\n\n private getDeviceClaimedByPath(deviceId: string): string {\n return `devices/${deviceId}/status/claimedBy`;\n }\n\n private getUserClaimedDevicePath(deviceId: string): string {\n const userId = this.user.uid;\n return `users/${userId}/devices/${deviceId}`;\n }\n\n private getUserDevicesPath(): string {\n const userId = this.user.uid;\n return `users/${userId}/devices`;\n }\n\n private getUserClaimsUpdatedOnPath(): string {\n const userId = this.user.uid;\n return `users/${userId}/claimsUpdatedOn`;\n }\n\n private getDeviceInfoPath(deviceId: string): string {\n return `devices/${deviceId}/info`;\n }\n\n onUserExperiments(): Observable<Experiment[]> {\n return this.onAuthStateChanged().pipe(\n switchMap((user) => {\n if (!user) {\n return EMPTY;\n }\n\n const userId = this.user.uid;\n\n const userExperimentsRef = this.app\n .database()\n .ref(\"experiments\")\n .orderByChild(\"userId\")\n .equalTo(userId)\n .limitToFirst(100);\n\n return fromEventPattern(\n (handler) => userExperimentsRef.on(\"value\", handler),\n (handler) => userExperimentsRef.off(\"value\", handler)\n ).pipe(\n map(([snapshot]: [firebase.database.DataSnapshot]) =>\n snapshot.val()\n ),\n // transform experiments map into sorted list\n map((experimentsMaps): Experiment[] => {\n return Object.entries(experimentsMaps ?? {})\n .map(([id, value]: any) => ({\n id: value?.id ?? id,\n ...value\n }))\n .sort(\n (a: any, b: any): any =>\n new Date(b?.timestamp).getTime() -\n new Date(a?.timestamp).getTime()\n );\n })\n );\n })\n );\n }\n\n async deleteUserExperiment(experimentId: string): Promise<void> {\n if (!experimentId) {\n return Promise.reject(\n `deleteUserExperiment: please provide an experiment id`\n );\n }\n\n const removeExperiment = (experimentId: string) => {\n return this.app\n .database()\n .ref(\"experiments\")\n .child(experimentId)\n .remove();\n };\n\n const removeRelations = (experimentId: string) => {\n return this.app.functions().httpsCallable(\"removeRelations\")({\n experimentId\n });\n };\n\n await Promise.all([\n removeExperiment(experimentId),\n removeRelations(experimentId)\n ]).catch(() => {});\n }\n}\n","import firebase from \"firebase/app\";\n\nconst SERVER_TIMESTAMP = firebase.database.ServerValue.TIMESTAMP;\n\nexport interface IDevice {\n info: any;\n status: any;\n subscriptions: any;\n metrics: any;\n}\n\n/**\n * @hidden\n */\nexport const createDeviceStore = (\n app,\n deviceId,\n subscriptionManager\n) => {\n const deviceRef = app.database().ref(`devices/${deviceId}`);\n const clientId = deviceRef.child(\"subscriptions\").push().key;\n const clientRef = deviceRef.child(`clients/${clientId}`);\n let listenersToRemove = [];\n\n const set = (namespace, payload) => {\n return deviceRef.child(namespace).set(payload);\n };\n\n const push = (namespace, payload) => {\n return deviceRef.child(namespace).push(payload);\n };\n\n const update = (namespace, payload) => {\n return deviceRef.child(namespace).update(payload);\n };\n\n const on = (eventType: any = \"value\", namespace, callback) => {\n const listener = deviceRef\n .child(namespace)\n .on(eventType, (snapshot) => {\n callback(snapshot.val(), snapshot);\n });\n\n listenersToRemove.push(() => {\n deviceRef.child(namespace).off(eventType, listener);\n });\n\n return listener;\n };\n\n const off = (namespace, eventType, listener?) => {\n if (listener) {\n deviceRef.child(namespace).off(eventType, listener);\n } else {\n deviceRef.child(namespace).off(eventType);\n }\n };\n\n const once = async (namespace, eventType = \"value\") => {\n const snapshot = await deviceRef.child(namespace).once(eventType);\n return snapshot.val();\n };\n\n const remove = (namespace) => {\n deviceRef.child(namespace).remove();\n };\n\n const bindListener = (\n eventType: string,\n namespace: string,\n callback: (res: any) => void,\n overrideResponse?: any\n ) => {\n on(eventType, namespace, (data) => {\n if (data !== null) {\n off(namespace, eventType);\n const response = overrideResponse ? overrideResponse : data;\n callback(response);\n }\n });\n };\n\n const lastOfChildValue = async (namespace, key, value) => {\n const snapshot = await deviceRef\n .child(namespace)\n .orderByChild(key)\n .equalTo(value)\n .limitToLast(1)\n .once(\"value\");\n const results = snapshot.val();\n const [match] = Object.values(results || {});\n return match || null;\n };\n\n // Add client connections and subscriptions to db and remove them when offline\n const connectedListener = app\n .database()\n .ref(\".info/connected\")\n .on(\"value\", (snapshot) => {\n if (!snapshot.val()) {\n return;\n }\n\n clientRef\n .onDisconnect()\n .remove()\n .then(() => {\n clientRef.set(SERVER_TIMESTAMP);\n\n // NOTION-115: Re-subscribe when internet connection is lost and regained\n update(\"subscriptions\", subscriptionManager.get()).then(\n () => {\n subscriptionManager.toList().forEach((subscription) => {\n const childPath = `subscriptions/${subscription.id}`;\n deviceRef.child(childPath).onDisconnect().remove();\n });\n }\n );\n });\n });\n\n listenersToRemove.push(() => {\n app\n .database()\n .ref(\".info/connected\")\n .off(\"value\", connectedListener);\n });\n\n return {\n set,\n once,\n update,\n lastOfChildValue,\n onNamespace: (namespace: string, callback: Function): Function => {\n return on(\"value\", namespace, (data: any) => {\n callback(data);\n });\n },\n offNamespace: (namespace: string, listener: Function): void => {\n off(namespace, \"value\", listener);\n },\n dispatchAction: async (action) => {\n const snapshot = await push(\"actions\", action);\n const actionId = snapshot.key;\n const actionPath = `actions/${actionId}`;\n\n snapshot.onDisconnect().remove();\n\n if (action.responseRequired) {\n const responseTimeout = action.responseTimeout || 600000; // defaults to 10 minutes\n const timeout = new Promise((_, reject) => {\n const id = setTimeout(() => {\n clearTimeout(id);\n snapshot.remove();\n reject(\n `Action response timed out in ${responseTimeout}ms.`\n );\n }, responseTimeout);\n });\n\n const response = new Promise((resolve) => {\n bindListener(\"value\", `${actionPath}/response`, resolve);\n });\n\n return Promise.race([response, timeout]);\n }\n\n return actionId;\n },\n nextMetric: async (\n metricName: string,\n metricValue: { [label: string]: any }\n ) => {\n set(`metrics/${metricName}`, metricValue);\n },\n onMetric: (subscription, callback: Function) => {\n const { atomic, metric, labels } = subscription;\n const child = atomic\n ? `metrics/${metric}`\n : `metrics/${metric}/${labels[0]}`;\n return on(\"value\", child, (data) => {\n if (data !== null) {\n callback(data);\n }\n });\n },\n subscribeToMetric: (subscription) => {\n const id = deviceRef.child(\"subscriptions\").push().key;\n const childPath = `subscriptions/${id}`;\n const subscriptionCreated = {\n id,\n clientId,\n ...subscription\n };\n set(childPath, subscriptionCreated);\n\n deviceRef.child(childPath).onDisconnect().remove();\n\n return subscriptionCreated;\n },\n unsubscribeFromMetric: (subscription) => {\n remove(`subscriptions/${subscription.id}`);\n },\n removeMetricListener(subscription, listener: Function) {\n const { atomic, metric, labels } = subscription;\n const child = atomic\n ? `metrics/${metric}`\n : `metrics/${metric}/${labels[0]}`;\n off(child, \"value\", listener);\n },\n disconnect() {\n clientRef.remove();\n listenersToRemove.forEach((removeListener) => {\n removeListener();\n });\n subscriptionManager\n .toList()\n .filter((subscription) => subscription.clientId === clientId)\n .forEach((subscription) => {\n const childPath = `subscriptions/${subscription.id}`;\n deviceRef.child(childPath).remove();\n });\n }\n };\n};\n","import firebase from \"firebase/app\";\n\nimport { FirebaseApp } from \"./FirebaseApp\";\nimport { createDeviceStore } from \"./deviceStore\";\nimport { SDKDependencies } from \"../../types/options\";\n\nconst SERVER_TIMESTAMP = firebase.database.ServerValue.TIMESTAMP;\n\ntype FirebaseDeviceOptions = {\n deviceId: string;\n firebaseApp: FirebaseApp;\n dependencies: SDKDependencies;\n};\n\n/**\n * @hidden\n */\nexport class FirebaseDevice {\n static serverType = \"firebase\";\n protected app: firebase.app.App;\n protected deviceStore;\n public deviceId: string;\n\n constructor({\n deviceId,\n firebaseApp,\n dependencies\n }: FirebaseDeviceOptions) {\n if (!deviceId) {\n throw new Error(`No Device ID provided.`);\n }\n\n this.deviceId = deviceId;\n this.app = firebaseApp.app;\n this.deviceStore = createDeviceStore(\n this.app,\n deviceId,\n dependencies.subscriptionManager\n );\n }\n\n public get timestamp(): any {\n return SERVER_TIMESTAMP;\n }\n\n public dispatchAction(action): Promise<any> {\n return this.deviceStore.dispatchAction(action);\n }\n\n public async getInfo(): Promise<any> {\n return await this.deviceStore.once(\"info\");\n }\n\n public onNamespace(namespace: string, callback: Function): Function {\n return this.deviceStore.onNamespace(namespace, callback);\n }\n\n public async onceNamespace(namespace: string): Promise<any> {\n return await this.deviceStore.once(namespace);\n }\n\n public offNamespace(namespace: string, listener: Function): void {\n this.deviceStore.offNamespace(namespace, listener);\n }\n\n public async getTimesync(): Promise<number> {\n const response = await this.dispatchAction({\n command: \"timesync\",\n action: \"get\",\n responseRequired: true,\n responseTimeout: 250\n });\n return response.timestamp;\n }\n\n /**\n * Pushes metric for each subscriptions in path:\n * /devices/:deviceId/metrics/:metricName\n */\n public nextMetric(\n metricName: string,\n metricValue: { [label: string]: any }\n ): void {\n this.deviceStore.nextMetric(metricName, metricValue);\n }\n\n /**\n * Listens for metrics in path:\n * /devices/:deviceId/metrics/:metricName\n */\n public onMetric(subscription, callback): Function {\n return this.deviceStore.onMetric(subscription, callback);\n }\n\n /**\n * Creates a new and unique subscription in path:\n * /devices/:deviceId/subscriptions/:subscriptionId\n * E.g. /devices/device1/subscriptions/subscription3\n *\n * @param subscription\n * @returns subscriptionId\n */\n public subscribeToMetric(subscription) {\n const subscriptionId = this.deviceStore.subscribeToMetric({\n ...subscription,\n serverType: FirebaseDevice.serverType // @deprecated\n });\n return subscriptionId;\n }\n\n /**\n * Removes subscription in path:\n * /devices/:deviceId/subscriptions/:subscriptionId\n *\n * @param subscription\n */\n public unsubscribeFromMetric(subscription): void {\n this.deviceStore.unsubscribeFromMetric(subscription);\n }\n\n /**\n * Removes metric listener\n * /devices/:deviceId/metric\n * or\n * /devices/:deviceId/metric/label\n *\n * @param subscription\n * @param listener\n */\n public removeMetricListener(subscription, listener: Function): void {\n this.deviceStore.removeMetricListener(subscription, listener);\n }\n\n public async changeSettings(settings): Promise<void> {\n return this.deviceStore.update(\"settings\", settings);\n }\n\n public async getSkill(bundleId): Promise<any> {\n return await this.deviceStore.lastOfChildValue(\n \"skills\",\n \"bundleId\",\n bundleId\n );\n }\n\n public async createBluetoothToken(): Promise<string> {\n const [error, token] = await this.app\n .functions()\n .httpsCallable(\"createBluetoothToken\")({\n deviceId: this.deviceId\n })\n .then(({ data }) => [null, data?.token])\n .catch((error) => [error, null]);\n\n if (error) {\n return Promise.reject(error?.message ?? error);\n }\n\n if (!token) {\n return Promise.reject(`Failed to create Bluetooth token.`);\n }\n\n return token;\n }\n\n public disconnect() {\n this.deviceStore.disconnect();\n }\n}\n","export * from \"./FirebaseApp\";\nexport * from \"./FirebaseUser\";\nexport * from \"./FirebaseDevice\";\n","import { pipe, of, EMPTY, Observable } from \"rxjs\";\nimport { mergeMap, withLatestFrom } from \"rxjs/operators\";\nimport { DeviceStatus } from \"../types/status\";\n\ntype Options = {\n status$: Observable<DeviceStatus>;\n allowWhileOnSleepMode: boolean;\n};\n\nexport function whileOnline({\n status$,\n allowWhileOnSleepMode\n}: Options) {\n return pipe(\n withLatestFrom(status$),\n mergeMap(([value, status]: [any, DeviceStatus]) =>\n shouldAllowMetrics(status, allowWhileOnSleepMode)\n ? of(value)\n : EMPTY\n )\n );\n}\n\nfunction shouldAllowMetrics(\n status: DeviceStatus,\n allowWhileOnSleepMode: boolean\n) {\n return (\n status.state === \"online\" &&\n (allowWhileOnSleepMode ? true : !status.sleepMode)\n );\n}\n","import { timer, pipe, range, Observable } from \"rxjs\";\nimport { map, concatWith, filter, take } from \"rxjs/operators\";\nimport { bufferCount, concatMap, switchMap } from \"rxjs/operators\";\nimport outliers from \"outliers\";\n\nimport { whileOnline } from \"../utils/whileOnline\";\nimport { DeviceStatus } from \"../types/status\";\n\ntype Options = {\n getTimesync: () => Promise<number>;\n status$: Observable<DeviceStatus>;\n bufferSize?: number;\n updateInterval?: number;\n};\n\nconst defaultOptions = {\n bufferSize: 100,\n updateInterval: 1 * 60 * 1000 // every minute\n};\n\nexport class Timesync {\n options: Options;\n _offset: number = 0;\n\n constructor(options: Options) {\n this.options = {\n ...defaultOptions,\n ...options\n };\n\n this.start();\n }\n\n public start(): void {\n const { bufferSize, updateInterval, status$ } = this.options;\n\n const burst$ = range(0, bufferSize);\n const timer$ = timer(updateInterval, updateInterval).pipe(\n map((i: number) => bufferSize + i),\n whileOnline({\n status$,\n allowWhileOnSleepMode: true\n })\n );\n\n const firstTimeDeviceIsOnline$ = status$.pipe(\n filter((status: DeviceStatus) => status.state === \"online\"),\n take(1)\n );\n\n firstTimeDeviceIsOnline$\n .pipe(\n switchMap(() => {\n return burst$.pipe(\n concatWith(timer$),\n this.toOffset(),\n bufferCount(bufferSize, 1),\n this.filterOutliers(),\n map((list: number[]) => this.average(list))\n );\n })\n )\n .subscribe((offset) => {\n this._offset = offset;\n });\n }\n\n filterOutliers() {\n return pipe(\n map((offsets: number[]): number[] => {\n return offsets.filter(outliers());\n })\n );\n }\n\n toOffset() {\n const { getTimesync } = this.options;\n return pipe(\n concatMap(async () => {\n const requestStartTime = Date.now();\n const [error, serverTime] = await getTimesync()\n .then((offset) => [null, offset])\n .catch((error) => [error]);\n\n if (error) {\n return 0;\n }\n\n const responseEndTime = Date.now();\n const oneWayDuration = (responseEndTime - requestStartTime) / 2;\n const offset = responseEndTime - oneWayDuration - serverTime;\n return offset;\n })\n );\n }\n\n private average(list: number[]): number {\n return Math.round(\n list.reduce((acc, number) => acc + number) / list.length\n );\n }\n\n public get offset(): number {\n return this._offset;\n }\n\n public get timestamp(): number {\n return Date.now() + this._offset;\n }\n}\n","export * from \"./Timesync\";\n","import { Subscription, Subscriptions } from \"../types/subscriptions\";\n\n/**\n * @hidden\n */\nexport class SubscriptionManager {\n private _subscriptions: Subscriptions = {};\n\n public get(): Subscriptions {\n return this._subscriptions;\n }\n\n public toList(): Subscription[] {\n return Object.values(this._subscriptions);\n }\n\n public add(subscription: Subscription): void {\n this._subscriptions[subscription.id] = subscription;\n }\n\n public remove(subscription: Subscription): void {\n if (!(subscription.id in this._subscriptions)) {\n return;\n }\n\n Reflect.deleteProperty(this._subscriptions, subscription.id);\n }\n}\n","/**\n * @hidden\n */\nexport enum STATUS {\n ONLINE = \"online\",\n OFFLINE = \"offline\",\n UPDATING = \"updating\",\n BOOTING = \"booting\",\n SHUTTING_OFF = \"shuttingOff\"\n}\n\n/**\n * @hidden\n */\nexport enum SLEEP_MODE_REASON {\n UPDATING = \"updating\",\n CHARGING = \"charging\"\n}\n\nexport interface DeviceStatus {\n battery: number;\n charging: boolean;\n state: STATUS;\n sleepMode: boolean;\n sleepModeReason: SLEEP_MODE_REASON | null;\n lastHeartbeat: number;\n ssid: string;\n}\n","import { combineLatest, Observable, timer } from \"rxjs\";\nimport { map, startWith, switchMap } from \"rxjs/operators\";\nimport { withLatestFrom, distinctUntilChanged } from \"rxjs/operators\";\nimport isEqual from \"fast-deep-equal\";\n\nimport { DeviceStatus, STATUS } from \"../types/status\";\n\nconst HEARTBEAT_UPDATE_INTERVAL = 30_000; // 30 seconds - set by the OS\nconst LOST_HEARTBEAT_AFTER = HEARTBEAT_UPDATE_INTERVAL * 2.5; // 75 seconds\n\nexport function heartbeatAwareStatus(\n status$: Observable<DeviceStatus>\n): Observable<DeviceStatus> {\n const lastLocalHeartbeat$: Observable<number> = status$.pipe(\n map(({ lastHeartbeat }) => lastHeartbeat),\n distinctUntilChanged(),\n map(() => Date.now())\n );\n\n const lostHeartbeat$: Observable<void> = lastLocalHeartbeat$.pipe(\n switchMap(() => timer(LOST_HEARTBEAT_AFTER)),\n map(() => null),\n startWith(null)\n );\n\n return combineLatest({\n status: status$,\n lostHeartbeat: lostHeartbeat$ // @important - do not remove, adeed for state synchronization, value not used\n }).pipe(\n withLatestFrom(lastLocalHeartbeat$),\n map(([{ status }, lastLocalHeartbeat]) => {\n if (!lastLocalHeartbeat) {\n return status;\n }\n\n const lostHeartbeat = deviceHasLostHeartbeat(status, lastLocalHeartbeat);\n\n return lostHeartbeat\n ? {\n ...status,\n state: STATUS.OFFLINE\n }\n : status;\n }),\n distinctUntilChanged((a, b) => isEqual(a, b))\n );\n}\n\nexport function deviceHasLostHeartbeat(\n status: DeviceStatus,\n lastLocalHeartbeat: number\n): boolean {\n if (!(\"lastHeartbeat\" in status)) {\n return false;\n }\n\n // We are converting the heartbeat to the local time because the previous\n // implementation that used the server timestamp had bug where SDK clients\n // running on hardware with drifted/out-of-sync clocks (cough cough Android)\n // would override the state to offline when the heartbeat was active.\n const lostHeartbeat = Date.now() - lastLocalHeartbeat > LOST_HEARTBEAT_AFTER;\n\n return lostHeartbeat;\n}\n","import { MonoTypeOperatorFunction, pipe } from \"rxjs\";\nimport { map } from \"rxjs/operators\";\nimport { DeviceStatus } from \"../types/status\";\n\nexport function filterInternalKeys(): MonoTypeOperatorFunction<DeviceStatus> {\n return pipe(\n map((status: DeviceStatus): DeviceStatus => {\n if (!status) {\n return status;\n }\n\n // remove internal properties that start with \"__\"\n const filteredStatus: any = Object.entries(status).reduce(\n (acc, [key, value]) => {\n if (!key.startsWith(\"__\")) {\n acc[key] = value;\n }\n return acc;\n },\n {}\n );\n\n return filteredStatus;\n })\n );\n}\n","import { Observable, ReplaySubject, EMPTY } from \"rxjs\";\nimport { fromEventPattern, firstValueFrom } from \"rxjs\";\nimport { filter, shareReplay, share, switchMap } from \"rxjs/operators\";\nimport { FirebaseApp, FirebaseUser, FirebaseDevice } from \"./firebase\";\nimport { Timesync } from \"../timesync\";\nimport { SubscriptionManager } from \"../subscriptions/SubscriptionManager\";\nimport { heartbeatAwareStatus } from \"../utils/heartbeat\";\nimport { filterInternalKeys } from \"../utils/filterInternalKeys\";\nimport { Client } from \"../types/client\";\nimport { Action, Actions } from \"../types/actions\";\nimport { Metrics } from \"../types/metrics\";\nimport { SDKOptions } from \"../types/options\";\nimport { SkillsClient, DeviceSkill } from \"../types/skill\";\nimport { Credentials, CustomToken } from \"../types/credentials\";\nimport { EmailAndPassword } from \"../types/credentials\";\nimport { ChangeSettings } from \"../types/settings\";\nimport { Subscription } from \"../types/subscriptions\";\nimport { DeviceStatus } from \"../types/status\";\nimport { DeviceInfo, DeviceSelector } from \"../types/deviceInfo\";\nimport { UserClaims } from \"../types/user\";\nimport { OAuthRemoveResponse } from \"../types/oauth\";\nimport { Experiment } from \"../types/experiment\";\nimport { TransferDeviceOptions } from \"../utils/transferDevice\";\n\nexport { credentialWithLink, createUser, SERVER_TIMESTAMP } from \"./firebase\";\n\n/**\n * @hidden\n */\nexport class CloudClient implements Client {\n public user;\n public userClaims;\n protected options: SDKOptions;\n protected firebaseApp: FirebaseApp;\n protected firebaseUser: FirebaseUser;\n protected firebaseDevice: FirebaseDevice;\n protected timesync: Timesync;\n protected subscriptionManager: SubscriptionManager;\n protected status$: Observable<DeviceStatus>;\n\n /**\n * @internal\n */\n private _selectedDevice = new ReplaySubject<DeviceInfo | null | undefined>(1);\n\n constructor(options: SDKOptions) {\n this.options = options;\n this.subscriptionManager = new SubscriptionManager();\n this.firebaseApp = new FirebaseApp(options);\n this.firebaseUser = new FirebaseUser(this.firebaseApp);\n\n this._selectedDevice.next(undefined);\n\n this.status$ = heartbeatAwareStatus(\n this.observeNamespace(\"status\").pipe(share())\n ).pipe(filterInternalKeys(), shareReplay(1));\n\n this.firebaseUser.onAuthStateChanged().subscribe((user) => {\n this.user = user;\n });\n\n this.firebaseUser.onUserClaimsChange().subscribe((userClaims) => {\n this.userClaims = userClaims;\n });\n\n this.onDeviceChange().subscribe((device) => {\n if (this.firebaseDevice) {\n this.firebaseDevice.disconnect();\n }\n\n if (!device) {\n return;\n }\n\n this.firebaseDevice = new FirebaseDevice({\n deviceId: device.deviceId,\n firebaseApp: this.firebaseApp,\n dependencies: {\n subscriptionManager: this.subscriptionManager\n }\n });\n\n if (this.options.timesync) {\n this.timesync = new Timesync({\n status$: this.status(),\n getTimesync: this.firebaseDevice.getTimesync.bind(this.firebaseDevice)\n });\n }\n });\n }\n\n public onDeviceChange(): Observable<DeviceInfo> {\n return this._selectedDevice\n .asObservable()\n .pipe(filter((value) => value !== undefined));\n }\n\n // Automatically select device when user logs in\n private async setAutoSelectedDevice(): Promise<DeviceInfo | null> {\n // Select based on `deviceId` passed\n if (this.options.deviceId) {\n return await this.selectDevice((devices) => {\n return devices.find(\n (device) => device.deviceId === this.options.deviceId\n );\n });\n }\n\n // Auto select first-claimed device\n if (!this.options.deviceId && this.options.autoSelectDevice) {\n return await this.selectDevice((devices) => {\n // Auto select first device\n return devices[0];\n });\n }\n\n return null;\n }\n\n public get actions(): Actions {\n return {\n dispatch: (action) => {\n return this.firebaseDevice.dispatchAction(action);\n }\n };\n }\n\n public async dispatchAction(action: Action): Promise<any> {\n return await this.firebaseDevice.dispatchAction(action);\n }\n\n public async disconnect(): Promise<any> {\n return this.firebaseApp.disconnect();\n }\n\n public async getInfo(): Promise<any> {\n return await this.firebaseDevice.getInfo();\n }\n\n public async login(credentials: Credentials): Promise<any> {\n if (this.user) {\n return Promise.reject(`Already logged in.`);\n }\n\n const auth = await this.firebaseUser.login(credentials);\n const selectedDevice = await this.setAutoSelectedDevice();\n\n return {\n ...auth,\n selectedDevice\n };\n }\n\n public async logout(): Promise<any> {\n if (this.firebaseDevice) {\n this.firebaseDevice.disconnect();\n }\n\n return await this.firebaseUser.logout();\n }\n\n public onAuthStateChanged() {\n return this.firebaseUser.onAuthStateChanged().pipe(\n switchMap(async (user) => {\n if (!user) {\n return null;\n }\n\n const selectedDevice = this.didSelectDevice()\n ? await this.getSelectedDevice()\n : await this.setAutoSelectedDevice();\n\n return {\n ...user,\n selectedDevice\n };\n })\n );\n }\n\n public getDevices() {\n return this.firebaseUser.getDevices();\n }\n\n public addDevice(deviceId: string): Promise<void> {\n return this.firebaseUser.addDevice(deviceId);\n }\n\n public async removeDevice(deviceId: string): Promise<void> {\n const [hasError, errorMessage] = await this.firebaseUser\n .removeDevice(deviceId)\n .then(() => [false])\n .catch((error) => [true, error]);\n\n if (hasError) {\n return Promise.reject(errorMessage);\n }\n\n const selectedDevice = await this.getSelectedDevice();\n\n if (selectedDevice?.deviceId === deviceId) {\n this._selectedDevice.next(null);\n }\n }\n\n public async transferDevice(options: TransferDeviceOptions): Promise<void> {\n const [hasError, error] = await this.firebaseUser\n .transferDevice(options)\n .then(() => [false])\n .catch((error) => [true, error]);\n\n if (hasError) {\n return Promise.reject(error);\n }\n\n const selectedDevice = await this.getSelectedDevice();\n\n if (selectedDevice?.deviceId === options.deviceId) {\n this._selectedDevice.next(null);\n }\n }\n\n public onUserDevicesChange(): Observable<DeviceInfo[]> {\n return this.firebaseUser.onUserDevicesChange();\n }\n\n public onUserClaimsChange(): Observable<UserClaims> {\n return this.firebaseUser.onUserClaimsChange();\n }\n\n public async didSelectDevice(): Promise<boolean> {\n const selectedDevice = await this.getSelectedDevice();\n return !!selectedDevice;\n }\n\n public async selectDevice(\n deviceSelector: DeviceSelector\n ): Promise<DeviceInfo> {\n const devices = await this.getDevices();\n\n if (!devices) {\n return Promise.reject(\n `Did not find any devices for this user. Make sure your device is claimed by your Neurosity account.`\n );\n }\n\n const deviceTupleSelector = (devices: DeviceInfo[]) =>\n devices.find((device) => {\n if (!Array.isArray(deviceSelector)) {\n return false;\n }\n\n const [deviceKey, deviceValue] = deviceSelector;\n return (\n JSON.stringify(device?.[deviceKey]) === JSON.stringify(deviceValue)\n );\n });\n\n const device =\n typeof deviceSelector === \"function\"\n ? deviceSelector(devices)\n : deviceTupleSelector(devices);\n\n if (!device) {\n return Promise.reject(\n `A device was not provided. Try returning a device from the devicesList provided in the callback.`\n );\n }\n\n const hasPermission = await this.firebaseUser.hasDevicePermission(\n device.deviceId\n );\n\n if (!hasPermission) {\n return Promise.reject(`Rejected device access due to permissions.`);\n }\n\n this._selectedDevice.next(device);\n\n return device;\n }\n\n public async getSelectedDevice(): Promise<DeviceInfo | null> {\n return await firstValueFrom(this._selectedDevice);\n }\n\n public status(): Observable<DeviceStatus> {\n return this.status$;\n }\n\n public observeNamespace(namespace: string): Observable<any> {\n const getNamespaceValues = () =>\n fromEventPattern(\n (handler) => this.firebaseDevice.onNamespace(namespace, handler),\n (handler) => this.firebaseDevice.offNamespace(namespace, handler)\n );\n\n return this.onDeviceChange().pipe(\n switchMap((selectedDevice) => {\n return selectedDevice ? getNamespaceValues() : EMPTY;\n })\n );\n }\n\n public async onceNamespace(namespace: string): Promise<any> {\n return await this.firebaseDevice.onceNamespace(namespace);\n }\n\n public get metrics(): Metrics {\n return {\n next: (metricName: string, metricValue: any): void => {\n this.firebaseDevice.nextMetric(metricName, metricValue);\n },\n on: (subscription: Subscription, callback: Function): Function => {\n return this.firebaseDevice.onMetric(subscription, callback);\n },\n subscribe: (subscription: Subscription): Subscription => {\n const subscriptionCreated =\n this.firebaseDevice.subscribeToMetric(subscription);\n this.subscriptionManager.add(subscriptionCreated);\n return subscriptionCreated;\n },\n unsubscribe: (subscription: Subscription, listener: Function): void => {\n this.subscriptionManager.remove(subscription);\n this.firebaseDevice.unsubscribeFromMetric(subscription);\n this.firebaseDevice.removeMetricListener(subscription, listener);\n }\n };\n }\n\n public createAccount(credentials: EmailAndPassword) {\n return this.firebaseUser.createAccount(credentials);\n }\n\n public deleteAccount() {\n return this.firebaseUser.deleteAccount();\n }\n\n public createBluetoothToken(): Promise<string> {\n return this.firebaseDevice.createBluetoothToken();\n }\n\n public createCustomToken(): Promise<CustomToken> {\n return this.firebaseUser.createCustomToken();\n }\n\n public removeOAuthAccess(): Promise<OAuthRemoveResponse> {\n return this.firebaseUser.removeOAuthAccess();\n }\n\n public onUserExperiments(): Observable<Experiment[]> {\n return this.firebaseUser.onUserExperiments();\n }\n\n public deleteUserExperiment(experimentId: string): Promise<void> {\n return this.firebaseUser.deleteUserExperiment(experimentId);\n }\n\n public get skills(): SkillsClient {\n return {\n get: async (bundleId: string): Promise<DeviceSkill> => {\n return this.firebaseDevice.getSkill(bundleId);\n }\n };\n }\n\n public get timestamp(): number {\n return this.options.timesync ? this.timesync.timestamp : Date.now();\n }\n\n public getTimesyncOffset(): number {\n return this.timesync.offset;\n }\n\n public changeSettings(settings: ChangeSettings): Promise<void> {\n return this.firebaseDevice.changeSettings(settings);\n }\n\n public goOffline() {\n this.firebaseApp.goOffline();\n }\n\n public goOnline() {\n this.firebaseApp.goOnline();\n }\n\n /**\n * @internal\n */\n public __getApp() {\n return this.firebaseApp.app;\n }\n}\n","/**\n * @hidden\n */\nexport enum STREAMING_TYPE {\n WIFI = \"wifi\",\n BLUETOOTH = \"bluetooth\"\n}\n\n/**\n * @hidden\n */\nexport enum STREAMING_MODE {\n WIFI_ONLY = \"wifi-only\",\n WIFI_WITH_BLUETOOTH_FALLBACK = \"wifi-with-bluetooth-fallback\",\n BLUETOOTH_WITH_WIFI_FALLBACK = \"bluetooth-with-wifi-fallback\"\n}\n","export const prefix = \"Neurosity SDK: \";\nexport const mustSelectDevice = new Error(\n `${prefix}A device must be selected. Make sure to call \"neurosity.selectDevice()\"`\n);\n\nexport const metricNotSupportedByModel = (\n metric: string,\n modelVersion: string\n) => {\n return new Error(\n `${prefix}${metric} not supported on model version ${modelVersion}. See docs.neurosity.co for more info.`\n );\n};\n\nexport const locationNotFound = (location: string, modelVersion: string) => {\n return new Error(\n `${prefix}${location} location not supported on model version ${modelVersion}. Check spelling or see docs.neurosity.co for more info.`\n );\n};\n\nexport const exceededMaxItems = (maxItems: number) => {\n return new Error(`${prefix}Maximum items in array is ${maxItems}`);\n};\n","import { metrics } from \"@neurosity/ipk\";\n\nimport * as errors from \"../utils/errors\";\nimport { SDKOptions } from \"../types/options\";\n\nexport const isMetric = (metric: string): boolean =>\n Object.keys(metrics).includes(metric);\n\nexport const getLabels = (metric: string): string[] =>\n Object.keys(metrics[metric]);\n\nexport const hasInvalidLabels = (metric: string, labels: string[]): boolean => {\n const validLabels = getLabels(metric);\n return !labels.every((label) => validLabels.includes(label));\n};\n\nexport const isMetricDisallowed = (\n metricName: string,\n options: SDKOptions\n): boolean =>\n \"skill\" in options &&\n \"metrics\" in options.skill &&\n !options.skill.metrics.includes(metricName);\n\nexport const validate = (\n metric: string,\n labels: string[],\n options: SDKOptions\n): Error | false => {\n const validLabels = getLabels(metric).join(\", \");\n\n if (!labels.length) {\n return new Error(\n `${errors.prefix}At least one label is required for ${metric} metric. Please add one of the following labels: ${validLabels}`\n );\n }\n\n if (isMetricDisallowed(metric, options)) {\n return new Error(\n `${errors.prefix}No permission to access the ${metric} metric. To access this metric, edit the skill's permissions`\n );\n }\n\n if (hasInvalidLabels(metric, labels)) {\n return new Error(\n `${errors.prefix}One ore more labels provided to ${metric} are invalid. The valid labels for ${metric} are ${validLabels}`\n );\n }\n\n return false;\n};\n","export const MODEL_VERSION_1 = \"1\";\nexport const MODEL_VERSION_2 = \"2\";\nexport const MODEL_VERSION_3 = \"3\";\n\nexport const FEATURE_HAPTICS = \"haptics\";\nexport const FEATURE_ACCEL = \"accel\";\n\nexport const HAPTIC_P7 = \"P7\";\nexport const HAPTIC_P8 = \"P8\";\n\nexport const platformFeaturesByModelVersion = {\n [MODEL_VERSION_1]: [],\n [MODEL_VERSION_2]: [FEATURE_HAPTICS, FEATURE_ACCEL],\n [MODEL_VERSION_3]: [FEATURE_HAPTICS, FEATURE_ACCEL]\n};\n\nexport const platformConfigByModelVersion = {\n [MODEL_VERSION_1]: {},\n [MODEL_VERSION_2]: {\n motorByMotorName: {\n [HAPTIC_P7]: [],\n [HAPTIC_P8]: []\n }\n },\n [MODEL_VERSION_3]: {\n motorByMotorName: {\n [HAPTIC_P7]: [],\n [HAPTIC_P8]: []\n }\n }\n};\n\nexport const supportsHaptics = (modelVersion: string): boolean => {\n const platformFeaturesForModel =\n platformFeaturesByModelVersion[modelVersion];\n return platformFeaturesForModel.includes(FEATURE_HAPTICS);\n};\n\nexport const supportsAccel = (modelVersion: string): boolean => {\n const platformFeaturesForModel =\n platformFeaturesByModelVersion[modelVersion];\n return platformFeaturesForModel.includes(FEATURE_ACCEL);\n};\n\nexport const getPlatformHapticMotors = (modelVersion: string) => {\n const platformConfigForModel =\n platformConfigByModelVersion[modelVersion];\n const platformMotorByMotorName =\n platformConfigForModel?.motorByMotorName ?? {};\n return { ...platformMotorByMotorName };\n};\n","// All 127ish codes here:\n/// https://cdn-learn.adafruit.com/downloads/pdf/adafruit-drv2605-haptic-controller-breakout.pdf\nexport const strongClick100 = \"strongClick100\";\nexport const strongClick60 = \"strongClick60\";\nexport const strongClick30 = \"strongClick30\";\nexport const sharpClick100 = \"sharpClick100\";\nexport const sharpClick60 = \"sharpClick60\";\nexport const sharpClick30 = \"sharpClick30\";\nexport const softBump100 = \"softBump100\";\nexport const softBump60 = \"softBump60\";\nexport const softBump30 = \"softBump30\";\nexport const doubleClick100 = \"doubleClick100\";\nexport const doubleClick60 = \"doubleClick60\";\nexport const tripleClick100 = \"tripleClick100\";\nexport const softFuzz60 = \"softFuzz60\";\nexport const strongBuzz100 = \"strongBuzz100\";\nexport const alert750ms = \"alert750ms\";\nexport const alert1000ms = \"alert1000ms\";\nexport const strongClick1_100 = \"strongClick1_100\";\nexport const strongClick2_80 = \"strongClick2_80\";\nexport const strongClick3_60 = \"strongClick3_60\";\nexport const strongClick4_30 = \"strongClick4_30\";\nexport const mediumClick1_100 = \"mediumClick1_100\";\nexport const mediumClick2_80 = \"mediumClick2_80\";\nexport const mediumClick3_60 = \"mediumClick3_60\";\nexport const sharpTick1_100 = \"sharpTick1_100\";\nexport const sharpTick2_80 = \"sharpTick2_80\";\nexport const sharpTick3_60 = \"sharpTick3_60\";\nexport const shortDoubleClickStrong1_100 =\n \"shortDoubleClickStrong1_100\";\nexport const shortDoubleClickStrong2_80 = \"shortDoubleClickStrong2_80\";\nexport const shortDoubleClickStrong3_60 = \"shortDoubleClickStrong3_60\";\nexport const shortDoubleClickStrong4_30 = \"shortDoubleClickStrong4_30\";\nexport const shortDoubleClickMedium1_100 =\n \"shortDoubleClickMedium1_100\";\nexport const shortDoubleClickMedium2_80 = \"shortDoubleClickMedium2_80\";\nexport const shortDoubleClickMedium3_60 = \"shortDoubleClickMedium3_60\";\nexport const shortDoubleSharpTick1_100 = \"shortDoubleSharpTick1_100\";\nexport const shortDoubleSharpTick2_80 = \"shortDoubleSharpTick2_80\";\nexport const shortDoubleSharpTick3_60 = \"shortDoubleSharpTick3_60\";\nexport const longDoubleSharpClickStrong1_100 =\n \"longDoubleSharpClickStrong1_100\";\nexport const longDoubleSharpClickStrong2_80 =\n \"longDoubleSharpClickStrong2_80\";\nexport const longDoubleSharpClickStrong3_60 =\n \"longDoubleSharpClickStrong3_60\";\nexport const longDoubleSharpClickStrong4_30 =\n \"longDoubleSharpClickStrong4_30\";\nexport const longDoubleSharpClickMedium1_100 =\n \"longDoubleSharpClickMedium1_100\";\nexport const longDoubleSharpClickMedium2_80 =\n \"longDoubleSharpClickMedium2_80\";\nexport const longDoubleSharpClickMedium3_60 =\n \"longDoubleSharpClickMedium3_60\";\nexport const longDoubleSharpTick1_100 = \"longDoubleSharpTick1_100\";\nexport const longDoubleSharpTick2_80 = \"longDoubleSharpTick2_80\";\nexport const longDoubleSharpTick3_60 = \"longDoubleSharpTick3_60\";\nexport const buzz1_100 = \"buzz1_100\";\nexport const buzz2_80 = \"buzz2_80\";\nexport const buzz3_60 = \"buzz3_60\";\nexport const buzz4_40 = \"buzz4_40\";\nexport const buzz5_20 = \"buzz5_20\";\nexport const pulsingStong1_100 = \"pulsingStong1_100\";\nexport const pulsingStong2_60 = \"pulsingStong2_60\";\nexport const pulsingMedium1_100 = \"pulsingMedium1_100\";\nexport const pulsingMedium2_60 = \"pulsingMedium2_60\";\nexport const pulsingSharp1_100 = \"pulsingSharp1_100\";\nexport const pulsingSharp2_60 = \"pulsingSharp2_60\";\nexport const transistionClick1_100 = \"transistionClick1_100\";\nexport const transistionClick2_80 = \"transistionClick2_80\";\nexport const transistionClick3_60 = \"transistionClick3_60\";\nexport const transistionClick4_40 = \"transistionClick4_40\";\nexport const transistionClick5_20 = \"transistionClick5_20\";\nexport const transistionClick6_10 = \"transistionClick6_10\";\nexport const transistionHum1_100 = \"transistionHum1_100\";\nexport const transistionHum2_80 = \"transistionHum2_80\";\nexport const transistionHum3_60 = \"transistionHum3_60\";\nexport const transistionHum4_40 = \"transistionHum4_40\";\nexport const transistionHum5_20 = \"transistionHum5_20\";\nexport const transistionHum6_10 = \"transistionHum6_10\";\nexport const transitionRampDownLongSmooth1_100_to_0 =\n \"transitionRampDownLongSmooth1_100_to_0\";\nexport const transitionRampDownLongSmooth2_100_to_0 =\n \"transitionRampDownLongSmooth2_100_to_0\";\nexport const transitionRampDownMediumSmooth1_100_to_0 =\n \"transitionRampDownMediumSmooth1_100_to_0\";\nexport const transitionRampDownMediumSmooth2_100_to_0 =\n \"transitionRampDownMediumSmooth2_100_to_0\";\nexport const transitionRampDownShortSmooth1_100_to_0 =\n \"transitionRampDownShortSmooth1_100_to_0\";\nexport const transitionRampDownShortSmooth2_100_to_0 =\n \"transitionRampDownShortSmooth2_100_to_0\";\nexport const transitionRampDownLongSharp1_100_to_0 =\n \"transitionRampDownLongSharp1_100_to_0\";\nexport const transitionRampDownLongSharp2_100_to_0 =\n \"transitionRampDownLongSharp2_100_to_0\";\nexport const transitionRampDownLongMedium1_100_to_0 =\n \"transitionRampDownLongMedium1_100_to_0\";\nexport const transitionRampDownLongMedium2_100_to_0 =\n \"transitionRampDownLongMedium2_100_to_0\";\nexport const transitionRampDownShortSharp1_100_to_0 =\n \"transitionRampDownShortSharp1_100_to_0\";\nexport const transitionRampDownShortSharp2_100_to_0 =\n \"transitionRampDownShortSharp2_100_to_0\";\nexport const transitionRampUpLongSmooth1_0_to_100 =\n \"transitionRampUpLongSmooth1_0_to_100\";\nexport const transitionRampUpLongSmooth2_0_to_100 =\n \"transitionRampUpLongSmooth2_0_to_100\";\nexport const transitionRampUpMediumSmooth1_0_to_100 =\n \"transitionRampUpMediumSmooth1_0_to_100\";\nexport const transitionRampUpMediumSmooth2_0_to_100 =\n \"transitionRampUpMediumSmooth2_0_to_100\";\nexport const transitionRampUpShortSmooth1_0_to_100 =\n \"transitionRampUpShortSmooth1_0_to_100\";\nexport const transitionRampUpShortSmooth2_0_to_100 =\n \"transitionRampUpShortSmooth2_0_to_100\";\nexport const transitionRampUpLongSharp1_0_to_100 =\n \"transitionRampUpLongSharp1_0_to_100\";\nexport const transitionRampUpLongSharp2_0_to_100 =\n \"transitionRampUpLongSharp2_0_to_100\";\nexport const transitionRampUpMediumSharp1_0_to_100 =\n \"transitionRampUpMediumSharp1_0_to_100\";\nexport const transitionRampUpMediumSharp2_0_to_100 =\n \"transitionRampUpMediumSharp2_0_to_100\";\nexport const transitionRampUpShortSharp1_0_to_100 =\n \"transitionRampUpShortSharp1_0_to_100\";\nexport const transitionRampUpShortSharp2_0_to_100 =\n \"transitionRampUpShortSharp2_0_to_100\";\nexport const transitionRampDownLongSmooth1_50_to_0 =\n \"transitionRampDownLongSmooth1_50_to_0\";\nexport const transitionRampDownLongSmooth2_50_to_0 =\n \"transitionRampDownLongSmooth2_50_to_0\";\nexport const transitionRampDownMediumSmooth1_50_to_0 =\n \"transitionRampDownMediumSmooth1_50_to_0\";\nexport const transitionRampDownMediumSmooth2_50_to_0 =\n \"transitionRampDownMediumSmooth2_50_to_0\";\nexport const transitionRampDownShortSmooth1_50_to_0 =\n \"transitionRampDownShortSmooth1_50_to_0\";\nexport const transitionRampDownShortSmooth2_50_to_0 =\n \"transitionRampDownShortSmooth2_50_to_0\";\nexport const transitionRampDownLongSharp1_50_to_0 =\n \"transitionRampDownLongSharp1_50_to_0\";\nexport const transitionRampDownLongSharp2_50_to_0 =\n \"transitionRampDownLongSharp2_50_to_0\";\nexport const transitionRampDownMediumSharp1_50_to_0 =\n \"transitionRampDownMediumSharp1_50_to_0\";\nexport const transitionRampDownMediumSharp2_50_to_0 =\n \"transitionRampDownMediumSharp2_50_to_0\";\nexport const transitionRampDownShortSharp1_50_to_0 =\n \"transitionRampDownShortSharp1_50_to_0\";\nexport const transitionRampDownShortSharp2_50_to_0 =\n \"transitionRampDownShortSharp2_50_to_0\";\nexport const transitionRampUpLongSmooth1_0_to_50 =\n \"transitionRampUpLongSmooth1_0_to_50\";\nexport const transitionRampUpLongSmooth2_0_to_50 =\n \"transitionRampUpLongSmooth2_0_to_50\";\nexport const transitionRampUpMediumSmooth1_0_to_50 =\n \"transitionRampUpMediumSmooth1_0_to_50\";\nexport const transitionRampUpMediumSmooth2_0_to_50 =\n \"transitionRampUpMediumSmooth2_0_to_50\";\nexport const transitionRampUpShortSmooth1_0_to_50 =\n \"transitionRampUpShortSmooth1_0_to_50\";\nexport const transitionRampUpShortSmooth2_0_to_50 =\n \"transitionRampUpShortSmooth2_0_to_50\";\nexport const transitionRampUpLongSharp1_0_to_50 =\n \"transitionRampUpLongSharp1_0_to_50\";\nexport const transitionRampUpLongSharp2_0_to_50 =\n \"transitionRampUpLongSharp2_0_to_50\";\nexport const transitionRampUpMediumSharp1_0_to_50 =\n \"transitionRampUpMediumSharp1_0_to_50\";\nexport const transitionRampUpMediumSharp2_0_to_50 =\n \"transitionRampUpMediumSharp2_0_to_50\";\nexport const transitionRampUpShortSharp1_0_to_50 =\n \"transitionRampUpShortSharp1_0_to_50\";\nexport const transitionRampUpShortSharp2_0_to_50 =\n \"transitionRampUpShortSharp2_0_to_50\";\nexport const longBuzzForProgrammaticStopping_100 =\n \"longBuzzForProgrammaticStopping_100\";\nexport const smoothHum1_50 = \"smoothHum1_50\";\nexport const smoothHum2_40 = \"smoothHum2_40\";\nexport const smoothHum3_30 = \"smoothHum3_30\";\nexport const smoothHum4_20 = \"smoothHum4_20\";\nexport const smoothHum5_10 = \"smoothHum5_10\";\n","import * as errors from \"../utils/errors\";\nimport { Action } from \"../types/actions\";\n\ntype OAuthClaims = {\n oauth?: true;\n authId?: string;\n scopes?: string;\n};\n\nconst scopeRequiredByAction = {\n \"marker/add\": \"write:brainwave-markers\",\n \"brainwaves/record\": \"write:brainwaves\",\n \"haptics/queue\": \"write:haptics\",\n \"training/record\": \"write:kinesis\",\n \"training/stop\": \"write:kinesis\",\n \"training/stopAll\": \"write:kinesis\",\n \"wifi/reset\": \"write:wifi-settings\"\n};\n\nconst scopeRequiredByFunctionName = {\n //metrics\n accelerometer: \"read:accelerometer\",\n brainwaves: \"read:brainwaves\",\n calm: \"read:calm\",\n focus: \"read:focus\",\n kinesis: \"read:kinesis\",\n predictions: \"read:kinesis\",\n signalQuality: \"read:signal-quality\",\n // end of metrics\n // device info\n getInfo: \"read:devices-info\",\n getSelectedDevice: \"read:devices-info\",\n selectDevice: \"read:devices-info\",\n onDeviceChange: \"read:devices-info\",\n onUserDevicesChange: \"read:devices-info\",\n // end device info\n settings: \"read:devices-settings\",\n changeSettings: \"write:devices-settings\",\n status: \"read:devices-status\",\n addDevice: \"write:devices-add\",\n removeDevice: \"write:devices-remove\",\n transferDevice: \"write:devices-remove\"\n};\n\nexport function validateOAuthScopeForAction(\n userClaims: OAuthClaims,\n action: Action\n): [boolean, Error | null] {\n const { oauth, scopes: scopesString } = userClaims ?? {};\n\n if (!oauth) {\n return [false, null];\n }\n\n const scopes = scopesString.split(\",\");\n\n const { command, action: actionName } = action;\n const requiredScope =\n scopeRequiredByAction[`${command}/${actionName}`];\n const hasRequireScopes = scopes.includes(requiredScope);\n\n if (hasRequireScopes) {\n return [false, null];\n }\n\n return [true, getScopeError(requiredScope)];\n}\n\nexport function validateOAuthScopeForFunctionName(\n userClaims: OAuthClaims,\n functionName: string\n): [boolean, Error | null] {\n const { oauth, scopes: scopesString } = userClaims ?? {};\n\n if (!oauth) {\n return [false, null];\n }\n\n const scopes = scopesString.split(\",\");\n\n const requiredScope = scopeRequiredByFunctionName[functionName];\n const hasRequireScopes = scopes.includes(requiredScope);\n\n if (hasRequireScopes) {\n return [false, null];\n }\n\n return [true, getScopeError(requiredScope)];\n}\n\nfunction getScopeError(...requiredScopes: string[]): Error {\n return new Error(\n `${\n errors.prefix\n }You are trying to access data with an OAuth token without access to the following scopes: ${requiredScopes.join(\n \", \"\n )}.`\n );\n}\n","export const prodFunctionsBaseUrl =\n \"https://us-central1-neurosity-device.cloudfunctions.net\";\n","import { prodFunctionsBaseUrl } from \"./config\";\nimport { SDKOptions } from \"../../types/options\";\n\nexport function getFunctionsBaseURL(sdkOptions: SDKOptions) {\n if (!sdkOptions.emulator) {\n return prodFunctionsBaseUrl;\n }\n\n const { emulatorHost, emulatorFunctionsPort } = sdkOptions;\n const emulatorFunctionsBaseUrl = `http://${emulatorHost}:${emulatorFunctionsPort}/neurosity-device/us-central1`;\n\n return emulatorFunctionsBaseUrl;\n}\n","import axios from \"axios\";\n\nimport { getFunctionsBaseURL } from \"./utils\";\nimport { SDKOptions } from \"../../types/options\";\nimport { OAuthConfig } from \"../../types/oauth\";\n\nexport function createOAuthURL(\n config: OAuthConfig,\n sdkOptions: SDKOptions\n): Promise<string> {\n const {\n clientId,\n clientSecret,\n responseType,\n redirectUri,\n scope,\n state\n } = config;\n\n const baseUrl = getFunctionsBaseURL(sdkOptions);\n\n return axios\n .get(`${baseUrl}/authorize/entry`, {\n params: {\n client_id: clientId,\n ...(clientSecret ? { client_secret: clientSecret } : {}),\n response_type: responseType,\n redirect_uri: redirectUri,\n scope: scope.join(\",\"),\n state: state,\n redirect: \"false\"\n }\n })\n .then((response) => `${baseUrl}${response.data.url}`);\n}\n","import axios from \"axios\";\n\nimport { getFunctionsBaseURL } from \"./utils\";\nimport { SDKOptions } from \"../../types/options\";\nimport { OAuthQuery, OAuthQueryResult } from \"../../types/oauth\";\n\nexport async function getOAuthToken(\n query: OAuthQuery,\n sdkOptions: SDKOptions\n): Promise<OAuthQueryResult> {\n const baseUrl = getFunctionsBaseURL(sdkOptions);\n\n // Get refresh token\n const refreshResponse = await axios.post(\n `${baseUrl}/getOAuthRefreshToken`,\n query\n );\n\n const refreshToken = refreshResponse.data;\n\n return axios\n .post(`${baseUrl}/token`, {\n grant_type: \"refresh_token\",\n refresh_token: refreshToken.data,\n client_id: query.clientId,\n client_secret: query.clientSecret\n })\n .then((response) => JSON.parse(response.data)[\"access_token\"]);\n}\n","export function isNode() {\n return (\n typeof process !== \"undefined\" &&\n process.versions != null &&\n process.versions.node != null\n );\n}\n","import { Observable, throwError, EMPTY } from \"rxjs\";\nimport { switchMap } from \"rxjs/operators\";\n\nimport { whileOnline } from \"./whileOnline\";\nimport { validate } from \"./subscription\";\nimport { PendingSubscription, Subscription } from \"../types/subscriptions\";\nimport { DeviceInfo } from \"../types/deviceInfo\";\n\n/**\n * @internal\n */\nexport function getCloudMetric(\n dependencies,\n subscription: PendingSubscription\n): Observable<any> {\n const { options, cloudClient, onDeviceChange, status } = dependencies;\n\n const { metric, labels, atomic } = subscription;\n\n const metricError = validate(metric, labels, options);\n if (metricError) {\n return throwError(() => metricError);\n }\n\n const metric$ = new Observable((observer) => {\n const subscriptions: Subscription[] = atomic\n ? [\n cloudClient.metrics.subscribe({\n metric: metric,\n labels: labels,\n atomic: atomic\n })\n ]\n : labels.map((label) => {\n return cloudClient.metrics.subscribe({\n metric: metric,\n labels: [label],\n atomic: atomic\n });\n });\n\n const subscriptionWithListeners = subscriptions.map((subscription) => ({\n subscription,\n listener: cloudClient.metrics.on(subscription, (...data: any) => {\n observer.next(...data);\n })\n }));\n\n return () => {\n subscriptionWithListeners.forEach(({ subscription, listener }) => {\n cloudClient.metrics.unsubscribe(subscription, listener);\n });\n };\n });\n\n return onDeviceChange().pipe(\n switchMap((device: DeviceInfo) => {\n if (!device) {\n return EMPTY;\n }\n\n return metric$.pipe(\n whileOnline({\n status$: status(),\n allowWhileOnSleepMode: false\n })\n );\n })\n );\n}\n","const self: any = this;\n\nexport const isMaybeWebWorkerContext = (): boolean => {\n return self && self?.document === undefined;\n};\n","import { isMaybeWebWorkerContext } from \"./isMaybeWebWorkerContext\";\n\nexport function isWebBluetoothSupported() {\n return (\n typeof window !== \"undefined\" &&\n window?.navigator?.bluetooth &&\n !isMaybeWebWorkerContext()\n );\n}\n","// Creates a number of 6 digits and ensures the first digit will never be 0\nexport function create6DigitPin(): number {\n return Math.floor(100000 + Math.random() * 900000);\n}\n","import { pipe } from \"rxjs\";\nimport { map, scan, filter } from \"rxjs/operators\";\n\ntype StitchChunkOptions = {\n delimiter: string;\n};\n\nexport function stitchChunks({ delimiter }: StitchChunkOptions) {\n return pipe(\n scan(\n (\n [remainder]: [string, string],\n currentBuffer: string\n ): [string, string] => {\n const nextBuffer = remainder + currentBuffer;\n\n if (!nextBuffer.includes(delimiter)) {\n return [nextBuffer, \"\"];\n }\n\n if (nextBuffer.endsWith(delimiter)) {\n return [\"\", nextBuffer];\n }\n\n const remainderStart = nextBuffer.lastIndexOf(delimiter);\n const remainderIndex = remainderStart + delimiter.length;\n const nextPacket = nextBuffer.slice(0, remainderIndex);\n const nextRemainder = nextBuffer.slice(remainderIndex);\n\n return [nextRemainder, nextPacket];\n },\n [\"\", \"\"]\n ),\n map(([, nextPacket]: string[]): string =>\n nextPacket.slice(0, -delimiter.length)\n ),\n filter((nextPacket: string): boolean => !!nextPacket.length)\n );\n}\n","/**\n * @hidden\n */\nexport type ActionOptions = {\n characteristicName: string;\n action: any;\n};\n\n/**\n * @hidden\n */\nexport type SubscribeOptions = {\n characteristicName: string;\n manageNotifications?: boolean;\n};\n\n/**\n * @hidden\n */\nexport enum BLUETOOTH_CONNECTION {\n SCANNING = \"scanning\",\n CONNECTED = \"connected\",\n CONNECTING = \"connecting\",\n DISCONNECTING = \"disconnecting\",\n DISCONNECTED = \"disconnected\"\n}\n\n/**\n * @hidden\n */\nexport enum TRANSPORT_TYPE {\n WEB = \"web\",\n REACT_NATIVE = \"reactNative\"\n}\n","import { TRANSPORT_TYPE } from \"../types\";\n\nconst encoder = new TextEncoder();\nconst decoder = new TextDecoder(\"utf-8\");\n\nexport function encode(\n transportType: TRANSPORT_TYPE,\n data: string\n): Uint8Array | number[] {\n if (transportType === TRANSPORT_TYPE.REACT_NATIVE) {\n // React Native expects a plain array of numbers and not a Uint8Array\n return [...encoder.encode(data)];\n }\n\n return encoder.encode(data);\n}\n\nexport function decode(\n transportType: TRANSPORT_TYPE,\n data: Uint8Array | number[]\n): string {\n if (transportType === TRANSPORT_TYPE.REACT_NATIVE) {\n // React Native outpouts a plain array of numbers and not a Uint8Array\n return decoder.decode(new Uint8Array(data as number[]));\n }\n\n return decoder.decode(data as Uint8Array);\n}\n","import { BLUETOOTH_CHARACTERISTICS } from \"@neurosity/ipk\";\n\nexport const ANDROID_MAX_MTU: number = 512;\nexport const REACT_NATIVE_MAX_BYTE_SIZE: number = 512; // the default is 20\n\nexport const DEFAULT_ACTION_RESPONSE_TIMEOUT: number = 1000 * 60; // 1 minute\n\n// Reverse BLUETOOTH_CHARACTERISTICS key/values for easy lookup\nexport const CHARACTERISTIC_UUIDS_TO_NAMES = Object.fromEntries(\n Object.entries(BLUETOOTH_CHARACTERISTICS).map((entries) => entries.reverse())\n);\n","import semverGte from \"semver/functions/gte\";\n\nimport { DeviceInfo } from \"../../../types/deviceInfo\";\n\nexport function osHasBluetoothSupport(selectedDevice: DeviceInfo) {\n if (!selectedDevice) {\n return false;\n }\n\n // Only the Crown supports Bluetooth\n const isCrown = Number(selectedDevice.modelVersion) >= 3;\n if (!isCrown) {\n return false;\n }\n\n const isEmulator = !!selectedDevice?.emulator;\n if (isEmulator) {\n return false;\n }\n\n return semverGte(selectedDevice.osVersion, \"16.0.0\");\n}\n","import { BLUETOOTH_PRIMARY_SERVICE_UUID_HEX } from \"@neurosity/ipk\";\nimport { BLUETOOTH_CHUNK_DELIMITER } from \"@neurosity/ipk\";\nimport { BLUETOOTH_DEVICE_NAME_PREFIXES } from \"@neurosity/ipk\";\nimport { BLUETOOTH_COMPANY_IDENTIFIER_HEX } from \"@neurosity/ipk\";\nimport { BehaviorSubject, defer, merge, of, ReplaySubject, timer } from \"rxjs\";\nimport { fromEventPattern, Observable, EMPTY, NEVER } from \"rxjs\";\nimport { switchMap, map, filter, tap } from \"rxjs/operators\";\nimport { shareReplay, distinctUntilChanged } from \"rxjs/operators\";\nimport { take, share } from \"rxjs/operators\";\n\nimport { BluetoothTransport } from \"../BluetoothTransport\";\nimport { isWebBluetoothSupported } from \"./isWebBluetoothSupported\";\nimport { create6DigitPin } from \"../utils/create6DigitPin\";\nimport { stitchChunks } from \"../utils/stitch\";\nimport { encode, decode } from \"../utils/encoding\";\nimport { ActionOptions, SubscribeOptions } from \"../types\";\nimport { TRANSPORT_TYPE, BLUETOOTH_CONNECTION } from \"../types\";\nimport { DEFAULT_ACTION_RESPONSE_TIMEOUT } from \"../constants\";\nimport { CHARACTERISTIC_UUIDS_TO_NAMES } from \"../constants\";\nimport { DeviceInfo } from \"../../../types/deviceInfo\";\nimport { osHasBluetoothSupport } from \"../utils/osHasBluetoothSupport\";\n\ntype Options = {\n autoConnect?: boolean;\n};\n\nconst defaultOptions: Options = {\n autoConnect: true\n};\n\nexport class WebBluetoothTransport implements BluetoothTransport {\n type: TRANSPORT_TYPE = TRANSPORT_TYPE.WEB;\n options: Options;\n device: BluetoothDevice;\n server: BluetoothRemoteGATTServer;\n service: BluetoothRemoteGATTService;\n characteristicsByName: {\n [name: string]: BluetoothRemoteGATTCharacteristic;\n } = {};\n\n connection$ = new BehaviorSubject<BLUETOOTH_CONNECTION>(\n BLUETOOTH_CONNECTION.DISCONNECTED\n );\n pendingActions$ = new BehaviorSubject<any[]>([]);\n logs$ = new ReplaySubject<string>(10);\n onDisconnected$: Observable<void> = this._onDisconnected().pipe(share());\n connectionStream$: Observable<BLUETOOTH_CONNECTION> = this.connection$\n .asObservable()\n .pipe(\n filter((connection) => !!connection),\n distinctUntilChanged(),\n shareReplay(1)\n );\n\n _isAutoConnectEnabled$ = new ReplaySubject<boolean>(1);\n\n constructor(options: Options = {}) {\n this.options = { ...defaultOptions, ...options };\n\n if (!isWebBluetoothSupported()) {\n const errorMessage = \"Web Bluetooth is not supported\";\n this.addLog(errorMessage);\n throw new Error(errorMessage);\n }\n\n this._isAutoConnectEnabled$.subscribe((autoConnect) => {\n this.addLog(`Auto connect: ${autoConnect ? \"enabled\" : \"disabled\"}`);\n });\n\n this._isAutoConnectEnabled$.next(this.options.autoConnect);\n\n this.connection$.asObservable().subscribe((connection) => {\n this.addLog(`connection status is ${connection}`);\n });\n\n this.onDisconnected$.subscribe(() => {\n this.connection$.next(BLUETOOTH_CONNECTION.DISCONNECTED);\n });\n }\n\n async _getPairedDevices(): Promise<BluetoothDevice[]> {\n return await navigator.bluetooth.getDevices();\n }\n\n _autoConnect(selectedDevice$: Observable<DeviceInfo>): Observable<void> {\n return this._isAutoConnectEnabled$.pipe(\n switchMap((isAutoConnectEnabled) =>\n isAutoConnectEnabled\n ? merge(\n selectedDevice$,\n this.onDisconnected$.pipe(switchMap(() => selectedDevice$))\n )\n : NEVER\n ),\n switchMap((selectedDevice) =>\n osHasBluetoothSupport(selectedDevice) ? of(selectedDevice) : EMPTY\n ),\n switchMap(async (selectedDevice) => {\n const { deviceNickname } = selectedDevice;\n\n if (this.isConnected()) {\n this.addLog(\n `Auto connect: ${deviceNickname} is already connected. Skipping auto connect.`\n );\n return;\n }\n\n const [devicesError, devices] = await this._getPairedDevices()\n .then((devices) => [null, devices])\n .catch((error) => [error, null]);\n\n if (devicesError) {\n throw new Error(\n `failed to get devices: ${devicesError?.message ?? devicesError}`\n );\n }\n\n this.addLog(\n `Auto connect: found ${devices.length} devices ${devices\n .map(({ name }) => name)\n .join(\", \")}`\n );\n\n // @important - Using `findLast` instead of `find` because somehow the browser\n // is finding multiple peripherals with the same name\n const device = devices.findLast(\n (device: BluetoothDevice) => device.name === deviceNickname\n );\n\n if (!device) {\n throw new Error(\n `couldn't find selected device in the list of paired devices.`\n );\n }\n\n this.addLog(\n `Auto connect: ${deviceNickname} was detected and previously paired`\n );\n\n return device;\n }),\n tap(() => {\n this.connection$.next(BLUETOOTH_CONNECTION.SCANNING);\n }),\n switchMap((device: BluetoothDevice) => onAdvertisementReceived(device)),\n switchMap(async (advertisement) => {\n this.addLog(`Advertisement received for ${advertisement.device.name}`);\n return await this.getServerServiceAndCharacteristics(\n advertisement.device\n );\n })\n );\n }\n\n enableAutoConnect(autoConnect: boolean): void {\n this._isAutoConnectEnabled$.next(autoConnect);\n }\n\n addLog(log: string) {\n this.logs$.next(log);\n }\n\n isConnected() {\n const connection = this.connection$.getValue();\n return connection === BLUETOOTH_CONNECTION.CONNECTED;\n }\n\n connection(): Observable<BLUETOOTH_CONNECTION> {\n return this.connectionStream$;\n }\n\n async connect(deviceNickname?: string): Promise<void> {\n try {\n // requires user gesture\n const device: BluetoothDevice = await this.requestDevice(deviceNickname);\n\n await this.getServerServiceAndCharacteristics(device);\n } catch (error) {\n return Promise.reject(error);\n }\n }\n\n async requestDevice(deviceNickname?: string): Promise<BluetoothDevice> {\n try {\n this.addLog(\"Requesting Bluetooth Device...\");\n\n const prefixes = BLUETOOTH_DEVICE_NAME_PREFIXES.map((namePrefix) => ({\n namePrefix\n }));\n\n // Ability to only show selectedDevice if provided\n const filters = deviceNickname\n ? [\n {\n name: deviceNickname\n }\n ]\n : prefixes;\n\n const device = await window.navigator.bluetooth.requestDevice({\n filters: [\n ...filters,\n {\n manufacturerData: [\n {\n companyIdentifier: BLUETOOTH_COMPANY_IDENTIFIER_HEX\n }\n ]\n }\n ],\n optionalServices: [BLUETOOTH_PRIMARY_SERVICE_UUID_HEX]\n });\n\n return device;\n } catch (error) {\n return Promise.reject(error);\n }\n }\n\n async getServerServiceAndCharacteristics(device: BluetoothDevice) {\n try {\n this.device = device;\n\n const isConnecting =\n this.connection$.getValue() === BLUETOOTH_CONNECTION.CONNECTING;\n if (!isConnecting) {\n this.connection$.next(BLUETOOTH_CONNECTION.CONNECTING);\n }\n\n this.server = await device.gatt.connect();\n\n this.addLog(`Getting service...`);\n this.service = await this.server.getPrimaryService(\n BLUETOOTH_PRIMARY_SERVICE_UUID_HEX\n );\n this.addLog(\n `Got service ${this.service.uuid}, getting characteristics...`\n );\n\n const characteristicsList = await this.service.getCharacteristics();\n\n this.addLog(`Got characteristics`);\n\n this.characteristicsByName = Object.fromEntries(\n characteristicsList.map((characteristic) => [\n CHARACTERISTIC_UUIDS_TO_NAMES[characteristic.uuid],\n characteristic\n ])\n );\n\n this.connection$.next(BLUETOOTH_CONNECTION.CONNECTED);\n } catch (error) {\n return Promise.reject(error);\n }\n }\n\n _onDisconnected(): Observable<any> {\n return this.connection$\n .asObservable()\n .pipe(\n switchMap((connection) =>\n connection === BLUETOOTH_CONNECTION.CONNECTED\n ? fromDOMEvent(this.device, \"gattserverdisconnected\")\n : NEVER\n )\n );\n }\n\n async disconnect(): Promise<void> {\n const isDeviceConnected = this?.device?.gatt?.connected;\n if (isDeviceConnected) {\n this.device.gatt.disconnect();\n }\n }\n\n /**\n *\n * Bluetooth GATT attributes, services, characteristics, etc. are invalidated\n * when a device disconnects. This means your code should always retrieve\n * (through getPrimaryService(s), getCharacteristic(s), etc.) these attributes\n * after reconnecting.\n */\n async getCharacteristicByName(\n characteristicName: string\n ): Promise<BluetoothRemoteGATTCharacteristic> {\n return this.characteristicsByName?.[characteristicName];\n }\n\n subscribeToCharacteristic({\n characteristicName,\n manageNotifications = true\n }: SubscribeOptions): Observable<any> {\n const data$ = defer(() =>\n this.getCharacteristicByName(characteristicName)\n ).pipe(\n switchMap(async (characteristic: BluetoothRemoteGATTCharacteristic) => {\n if (this.isConnected() && manageNotifications) {\n try {\n await characteristic.startNotifications();\n this.addLog(\n `Started notifications for ${characteristicName} characteristic`\n );\n } catch (error) {\n this.addLog(\n `Attemped to stop notifications for ${characteristicName} characteristic: ${\n error?.message ?? error\n }`\n );\n }\n }\n\n return characteristic;\n }),\n switchMap((characteristic: BluetoothRemoteGATTCharacteristic) => {\n return fromDOMEvent(\n characteristic,\n \"characteristicvaluechanged\",\n async () => {\n if (this.isConnected() && manageNotifications) {\n try {\n await characteristic.stopNotifications();\n this.addLog(\n `Stopped notifications for ${characteristicName} characteristic`\n );\n } catch (error) {\n this.addLog(\n `Attemped to stop notifications for ${characteristicName} characteristic: ${\n error?.message ?? error\n }`\n );\n }\n }\n }\n );\n }),\n map((event: any): string => {\n const buffer: Uint8Array = event.target.value;\n const decoded = decode(this.type, buffer);\n\n this.addLog(\n `Received chunk with buffer size of ${buffer.byteLength} and decoded size ${decoded.length} for ${characteristicName} characteristic: \\n${decoded}`\n );\n\n return decoded;\n }),\n stitchChunks({ delimiter: BLUETOOTH_CHUNK_DELIMITER }),\n map((payload: any) => {\n try {\n return JSON.parse(payload);\n } catch (error) {\n this.addLog(\n `Failed to parse JSON for ${characteristicName} characteristic. Falling back to unparsed string. ${\n error?.message ?? error\n }`\n );\n\n return payload;\n }\n })\n // when streaming at ultra-low latency, the logs will slow down rendering\n // tap((data) => {\n // this.addLog(\n // `Received data for ${characteristicName} characteristic: \\n${JSON.stringify(\n // data,\n // null,\n // 2\n // )}`\n // );\n // })\n );\n\n return this.connection$.pipe(\n switchMap((connection) =>\n connection === BLUETOOTH_CONNECTION.CONNECTED ? data$ : NEVER\n )\n );\n }\n\n async readCharacteristic(\n characteristicName: string,\n parse: boolean = false\n ): Promise<any> {\n try {\n this.addLog(`Reading characteristic: ${characteristicName}`);\n\n const characteristic: BluetoothRemoteGATTCharacteristic =\n await this.getCharacteristicByName(characteristicName);\n\n if (!characteristic) {\n this.addLog(`Did not fund ${characteristicName} characteristic`);\n\n return Promise.reject(\n `Did not find characteristic by the name: ${characteristicName}`\n );\n }\n\n const value: unknown = await characteristic.readValue();\n const uint8Array = value as Uint8Array;\n const decodedValue: string = decode(this.type, uint8Array);\n const data = parse ? JSON.parse(decodedValue) : decodedValue;\n\n this.addLog(\n `Received read data from ${characteristicName} characteristic: \\n${data}`\n );\n\n return data;\n } catch (error) {\n return Promise.reject(`Error reading characteristic: ${error.message}`);\n }\n }\n\n async writeCharacteristic(\n characteristicName: string,\n data: string\n ): Promise<void> {\n this.addLog(`Writing characteristic: ${characteristicName}`);\n\n const characteristic: BluetoothRemoteGATTCharacteristic =\n await this.getCharacteristicByName(characteristicName);\n\n if (!characteristic) {\n this.addLog(`Did not fund ${characteristicName} characteristic`);\n\n return Promise.reject(\n `Did not find characteristic by the name: ${characteristicName}`\n );\n }\n\n const encoded = encode(this.type, data);\n\n await characteristic.writeValueWithResponse(encoded as Uint8Array);\n }\n\n _addPendingAction(actionId: number): void {\n const actions = this.pendingActions$.getValue();\n this.pendingActions$.next([...actions, actionId]);\n }\n\n _removePendingAction(actionId: number): void {\n const actions = this.pendingActions$.getValue();\n this.pendingActions$.next(\n actions.filter((id: number): boolean => id !== actionId)\n );\n }\n\n async _autoToggleActionNotifications(\n selectedDevice$: Observable<DeviceInfo>\n ): Promise<void> {\n let actionsCharacteristic: BluetoothRemoteGATTCharacteristic;\n let started: boolean = false;\n\n const sideEffects$ = this.connection$.asObservable().pipe(\n switchMap((connection) =>\n connection === BLUETOOTH_CONNECTION.CONNECTED\n ? defer(() => this.getCharacteristicByName(\"actions\")).pipe(\n switchMap((characteristic: BluetoothRemoteGATTCharacteristic) => {\n actionsCharacteristic = characteristic;\n return this.pendingActions$;\n })\n )\n : NEVER\n ),\n tap(async (pendingActions: string[]) => {\n const hasPendingActions = !!pendingActions.length;\n\n if (hasPendingActions && !started) {\n started = true;\n try {\n await actionsCharacteristic.startNotifications();\n this.addLog(`Started notifications for [actions] characteristic`);\n } catch (error) {\n this.addLog(\n `Attemped to start notifications for [actions] characteristic: ${\n error?.message ?? error\n }`\n );\n }\n }\n\n if (!hasPendingActions && started) {\n started = false;\n try {\n await actionsCharacteristic.stopNotifications();\n this.addLog(`Stopped notifications for actions characteristic`);\n } catch (error) {\n this.addLog(\n `Attemped to stop notifications for [actions] characteristic: ${\n error?.message ?? error\n }`\n );\n }\n }\n })\n );\n\n selectedDevice$\n .pipe(\n switchMap((selectedDevice: DeviceInfo) =>\n !osHasBluetoothSupport(selectedDevice) ? EMPTY : sideEffects$\n )\n )\n .subscribe();\n }\n\n async dispatchAction({\n characteristicName,\n action\n }: ActionOptions): Promise<any> {\n const {\n responseRequired = false,\n responseTimeout = DEFAULT_ACTION_RESPONSE_TIMEOUT\n } = action;\n\n return new Promise(async (resolve, reject) => {\n const characteristic: BluetoothRemoteGATTCharacteristic | void =\n await this.getCharacteristicByName(characteristicName).catch(() => {\n reject(\n `Did not find characteristic by the name: ${characteristicName}`\n );\n });\n\n if (!characteristic) {\n return;\n }\n\n const actionId: number = create6DigitPin(); // use to later identify and filter response\n const payload = JSON.stringify({ actionId, ...action }); // add the response id to the action\n\n this.addLog(`Dispatched action with id ${actionId}`);\n\n if (responseRequired && responseTimeout) {\n this._addPendingAction(actionId);\n\n const timeout = timer(responseTimeout).subscribe(() => {\n this._removePendingAction(actionId);\n reject(\n `Action with id ${actionId} timed out after ${responseTimeout}ms`\n );\n });\n\n // listen for a response before writing\n this.subscribeToCharacteristic({\n characteristicName,\n manageNotifications: false\n })\n .pipe(\n filter((response: any) => response?.actionId === actionId),\n take(1)\n )\n .subscribe((response) => {\n timeout.unsubscribe();\n this._removePendingAction(actionId);\n resolve(response);\n });\n\n // register action by writing\n this.writeCharacteristic(characteristicName, payload).catch((error) => {\n this._removePendingAction(actionId);\n reject(error.message);\n });\n } else {\n this.writeCharacteristic(characteristicName, payload)\n .then(() => {\n resolve(null);\n })\n .catch((error) => {\n reject(error.message);\n });\n }\n });\n }\n}\n\nfunction fromDOMEvent(\n target: any,\n eventName: any,\n beforeRemove?: () => Promise<void>\n): Observable<any> {\n return fromEventPattern(\n (addHandler) => {\n target.addEventListener(eventName, addHandler);\n },\n async (removeHandler) => {\n if (beforeRemove) {\n await beforeRemove();\n }\n\n target.removeEventListener(eventName, removeHandler);\n }\n );\n}\n\nfunction onAdvertisementReceived(\n device: BluetoothDevice | any\n): Observable<BluetoothAdvertisingEvent> {\n return new Observable((subscriber) => {\n const abortController = new AbortController();\n const { signal } = abortController;\n\n const listener = device.addEventListener(\n \"advertisementreceived\",\n (advertisement: BluetoothAdvertisingEvent) => {\n abortController.abort();\n subscriber.next(advertisement);\n subscriber.complete();\n },\n {\n once: true\n }\n );\n\n try {\n device.watchAdvertisements({ signal });\n } catch (error) {\n subscriber.error(error);\n }\n\n return () => {\n abortController.abort();\n device.removeEventListener(\"advertisementreceived\", listener);\n };\n });\n}\n","import { BLUETOOTH_PRIMARY_SERVICE_UUID_STRING } from \"@neurosity/ipk\";\nimport { BLUETOOTH_CHUNK_DELIMITER } from \"@neurosity/ipk\";\nimport { BLUETOOTH_DEVICE_NAME_PREFIXES } from \"@neurosity/ipk\";\nimport { BehaviorSubject, defer, merge, of, ReplaySubject, timer } from \"rxjs\";\nimport { fromEventPattern, Observable, NEVER, EMPTY } from \"rxjs\";\nimport { switchMap, map, filter, takeUntil, tap } from \"rxjs/operators\";\nimport { shareReplay, distinctUntilChanged, finalize } from \"rxjs/operators\";\nimport { take, share, scan, distinct } from \"rxjs/operators\";\n\nimport { BluetoothTransport } from \"../BluetoothTransport\";\nimport { create6DigitPin } from \"../utils/create6DigitPin\";\nimport { stitchChunks } from \"../utils/stitch\";\nimport { encode, decode } from \"../utils/encoding\";\nimport { ActionOptions, SubscribeOptions } from \"../types\";\nimport { TRANSPORT_TYPE, BLUETOOTH_CONNECTION } from \"../types\";\nimport { BleManager } from \"./types/BleManagerTypes\";\nimport { Peripheral, PeripheralInfo } from \"./types/BleManagerTypes\";\nimport { NativeEventEmitter } from \"./types/ReactNativeTypes\";\nimport { PlatformOSType } from \"./types/ReactNativeTypes\";\nimport { DEFAULT_ACTION_RESPONSE_TIMEOUT } from \"../constants\";\nimport { CHARACTERISTIC_UUIDS_TO_NAMES } from \"../constants\";\nimport { ANDROID_MAX_MTU } from \"../constants\";\nimport { REACT_NATIVE_MAX_BYTE_SIZE } from \"../constants\";\nimport { DeviceInfo } from \"../../../types/deviceInfo\";\nimport { osHasBluetoothSupport } from \"../utils/osHasBluetoothSupport\";\n\ntype Characteristic = {\n characteristicUUID: string;\n serviceUUID: string;\n peripheralId: string;\n};\n\ntype CharacteristicsByName = {\n [name: string]: Characteristic;\n};\n\ntype Options = {\n BleManager: BleManager;\n bleManagerEmitter: NativeEventEmitter;\n platform: PlatformOSType;\n autoConnect?: boolean;\n};\n\ntype BleManagerEvents = {\n stopScan$: Observable<void>;\n discoverPeripheral$: Observable<Peripheral>;\n connectPeripheral$: Observable<void>;\n disconnectPeripheral$: Observable<void>;\n didUpdateValueForCharacteristic$: Observable<any>;\n didUpdateState$: Observable<any>;\n};\n\nconst defaultOptions: Pick<Options, \"autoConnect\"> = {\n autoConnect: true\n};\n\nexport class ReactNativeTransport implements BluetoothTransport {\n type: TRANSPORT_TYPE = TRANSPORT_TYPE.REACT_NATIVE;\n options: Options;\n BleManager: BleManager;\n bleManagerEmitter: NativeEventEmitter;\n platform: PlatformOSType;\n bleEvents: BleManagerEvents;\n\n device: Peripheral;\n characteristicsByName: CharacteristicsByName = {};\n\n connection$ = new BehaviorSubject<BLUETOOTH_CONNECTION>(\n BLUETOOTH_CONNECTION.DISCONNECTED\n );\n pendingActions$ = new BehaviorSubject<any[]>([]);\n logs$ = new ReplaySubject<string>(10);\n onDisconnected$: Observable<void>;\n connectionStream$: Observable<BLUETOOTH_CONNECTION> = this.connection$\n .asObservable()\n .pipe(\n filter((connection) => !!connection),\n distinctUntilChanged(),\n shareReplay(1)\n );\n\n _isAutoConnectEnabled$ = new ReplaySubject<boolean>(1);\n\n constructor(options: Options) {\n if (!options) {\n const errorMessage = \"React Native transport: missing options.\";\n this.addLog(errorMessage);\n throw new Error(errorMessage);\n }\n\n this.options = { ...defaultOptions, ...options };\n\n const { BleManager, bleManagerEmitter, platform, autoConnect } =\n this.options;\n\n if (!BleManager) {\n const errorMessage = \"React Native option: BleManager not provided.\";\n this.addLog(errorMessage);\n throw new Error(errorMessage);\n }\n\n if (!bleManagerEmitter) {\n const errorMessage =\n \"React Native option: bleManagerEmitter not provided.\";\n this.addLog(errorMessage);\n throw new Error(errorMessage);\n }\n\n if (!platform) {\n const errorMessage = \"React Native option: platform not provided.\";\n this.addLog(errorMessage);\n throw new Error(errorMessage);\n }\n\n this.BleManager = BleManager;\n this.bleManagerEmitter = bleManagerEmitter;\n this.platform = platform;\n\n this._isAutoConnectEnabled$.next(autoConnect);\n\n this._isAutoConnectEnabled$.subscribe((autoConnect) => {\n this.addLog(`Auto connect: ${autoConnect ? \"enabled\" : \"disabled\"}`);\n });\n\n // We create a single listener per event type to\n // avoid missing events when multiple listeners are attached.\n this.bleEvents = {\n stopScan$: this._fromEvent(\"BleManagerStopScan\"),\n discoverPeripheral$: this._fromEvent(\"BleManagerDiscoverPeripheral\"),\n connectPeripheral$: this._fromEvent(\"BleManagerConnectPeripheral\"),\n disconnectPeripheral$: this._fromEvent(\"BleManagerDisconnectPeripheral\"),\n didUpdateValueForCharacteristic$: this._fromEvent(\n \"BleManagerDidUpdateValueForCharacteristic\"\n ),\n didUpdateState$: this._fromEvent(\"BleManagerDidUpdateState\")\n };\n\n this.onDisconnected$ = this.bleEvents.disconnectPeripheral$.pipe(share());\n\n // Initializes the module. This can only be called once.\n this.BleManager.start({ showAlert: false })\n .then(() => {\n this.addLog(`BleManger started`);\n })\n .catch((error) => {\n this.addLog(`BleManger failed to start. ${error?.message ?? error}`);\n });\n\n this.connection$.asObservable().subscribe((connection) => {\n this.addLog(`connection status is ${connection}`);\n });\n\n this.onDisconnected$.subscribe(() => {\n this.connection$.next(BLUETOOTH_CONNECTION.DISCONNECTED);\n });\n }\n\n addLog(log: string) {\n this.logs$.next(log);\n }\n\n isConnected() {\n const connection = this.connection$.getValue();\n return connection === BLUETOOTH_CONNECTION.CONNECTED;\n }\n\n _autoConnect(selectedDevice$: Observable<DeviceInfo>): Observable<void> {\n const selectedDeviceAfterDisconnect$ = this.onDisconnected$.pipe(\n switchMap(() => selectedDevice$)\n );\n\n return this._isAutoConnectEnabled$.pipe(\n switchMap((isAutoConnectEnabled) =>\n isAutoConnectEnabled\n ? merge(selectedDevice$, selectedDeviceAfterDisconnect$)\n : NEVER\n ),\n switchMap((selectedDevice) =>\n !osHasBluetoothSupport(selectedDevice)\n ? NEVER\n : this.scan().pipe(\n switchMap((peripherals: Peripheral[]) => {\n const peripheralMatch = peripherals.find(\n (peripheral) =>\n peripheral.name === selectedDevice?.deviceNickname\n );\n\n return peripheralMatch ? of(peripheralMatch) : NEVER;\n }),\n distinct((peripheral: Peripheral) => peripheral.id),\n take(1)\n )\n ),\n switchMap(async (peripheral) => {\n return await this.connect(peripheral);\n })\n );\n }\n\n enableAutoConnect(autoConnect: boolean): void {\n this._isAutoConnectEnabled$.next(autoConnect);\n }\n\n connection(): Observable<BLUETOOTH_CONNECTION> {\n return this.connectionStream$;\n }\n\n _fromEvent(eventName: string): Observable<any> {\n return fromEventPattern(\n (addHandler) => {\n this.bleManagerEmitter.addListener(eventName, addHandler);\n },\n () => {\n this.bleManagerEmitter.removeAllListeners(eventName);\n }\n ).pipe(\n // @important: we need to share the subscription\n // to avoid missing events\n share()\n );\n }\n\n scan(options?: {\n seconds?: number;\n once?: boolean;\n skipConnectionUpdate?: boolean;\n }): Observable<Peripheral[]> {\n const RESCAN_INTERVAL = 10_000; // 10 seconds\n const seconds = options?.seconds ?? RESCAN_INTERVAL / 1000;\n const once = options?.once ?? false;\n // If we are already connected to a peripheral and start scanning,\n // be default, it will set the connection status to SCANNING and not\n // update it back if no device is connected to\n const skipConnectionUpdate = options?.skipConnectionUpdate ?? false;\n const serviceUUIDs = [BLUETOOTH_PRIMARY_SERVICE_UUID_STRING];\n const allowDuplicates = true;\n const scanOptions = {};\n\n const scanOnce$ = new Observable((subscriber) => {\n try {\n this.BleManager.scan(\n serviceUUIDs,\n seconds,\n allowDuplicates,\n scanOptions\n ).then(() => {\n this.addLog(`BleManger scanning ${once ? \"once\" : \"indefintely\"}`);\n subscriber.next();\n });\n } catch (error) {\n this.addLog(\n `BleManger scanning ${once ? \"once\" : \"indefintely\"} failed. ${\n error?.message ?? error\n }`\n );\n subscriber.error(error);\n }\n\n return () => {\n this.BleManager.stopScan();\n };\n });\n\n const scan$ = once\n ? scanOnce$\n : timer(0, RESCAN_INTERVAL).pipe(switchMap(() => scanOnce$));\n\n const peripherals$ = scan$.pipe(\n tap(() => {\n if (!skipConnectionUpdate) {\n this.connection$.next(BLUETOOTH_CONNECTION.SCANNING);\n }\n }),\n takeUntil(this.onDisconnected$),\n switchMap(() => this.bleEvents.discoverPeripheral$),\n // Filter out devices that are not Neurosity devices\n filter((peripheral: Peripheral) => {\n const peripheralName: string =\n peripheral?.advertising?.localName ?? peripheral.name ?? \"\";\n\n if (!peripheralName) {\n return false;\n }\n\n const startsWithPrefix =\n BLUETOOTH_DEVICE_NAME_PREFIXES.findIndex((prefix) =>\n peripheralName.startsWith(prefix)\n ) !== -1;\n\n return startsWithPrefix;\n }),\n scan((acc, peripheral): { [name: string]: Peripheral } => {\n // normalized peripheral name for backwards compatibility\n // Neurosity OS v15 doesn't have peripheral.name as deviceNickname\n // it only has peripheral.advertising.localName as deviceNickname\n // and OS v16 has both as deviceNickname\n const peripheralName: string =\n peripheral?.advertising?.localName ?? peripheral.name ?? \"\";\n\n const manufactureDataString = decode(\n this.type,\n peripheral?.advertising?.manufacturerData?.bytes ?? []\n )?.slice?.(2); // First 2 bytes are reserved for the Neurosity company code\n\n return {\n ...acc,\n [peripheral.id]: {\n ...peripheral,\n name: peripheralName,\n manufactureDataString\n }\n };\n }, {}),\n distinctUntilChanged((a, b) => JSON.stringify(a) === JSON.stringify(b)),\n map((peripheralMap): Peripheral[] => Object.values(peripheralMap)),\n share()\n );\n\n return peripherals$;\n }\n\n async connect(peripheral: Peripheral): Promise<void> {\n return new Promise(async (resolve, reject) => {\n try {\n if (!peripheral) {\n this.addLog(\"Peripheral not found\");\n return;\n }\n\n this.connection$.next(BLUETOOTH_CONNECTION.CONNECTING);\n\n await this.BleManager.connect(peripheral.id);\n\n this.addLog(`Getting service...`);\n\n const peripheralInfo: PeripheralInfo =\n await this.BleManager.retrieveServices(peripheral.id, [\n BLUETOOTH_PRIMARY_SERVICE_UUID_STRING\n ]);\n\n if (!peripheralInfo) {\n this.addLog(\"Could not retreive services\");\n reject(new Error(`Could not retreive services`));\n return;\n }\n\n this.addLog(\n `Got service ${BLUETOOTH_PRIMARY_SERVICE_UUID_STRING}, getting characteristics...`\n );\n\n this.device = peripheral;\n\n this.characteristicsByName = Object.fromEntries(\n peripheralInfo.characteristics.map((characteristic: any) => [\n CHARACTERISTIC_UUIDS_TO_NAMES[\n characteristic.characteristic.toLowerCase() // react native uses uppercase\n ],\n {\n characteristicUUID: characteristic.characteristic,\n serviceUUID: characteristic.service,\n peripheralId: peripheral.id\n }\n ])\n );\n\n this.addLog(`Got characteristics.`);\n\n if (this.platform === \"android\") {\n await this.BleManager.requestMTU(peripheral.id, ANDROID_MAX_MTU)\n .then((updatedMTU) => {\n this.addLog(\n `Successfully updated Android MTU to ${updatedMTU} bytes. Requested MTU: ${ANDROID_MAX_MTU} bytes.`\n );\n })\n .catch((error) => {\n this.addLog(\n `Failed to set Android MTU of ${ANDROID_MAX_MTU} bytes. Error: ${error}`\n );\n });\n }\n\n this.addLog(`Successfully connected to peripheral ${peripheral.id}`);\n\n this.connection$.next(BLUETOOTH_CONNECTION.CONNECTED);\n\n resolve();\n } catch (error) {\n reject(error);\n }\n });\n }\n\n async disconnect(): Promise<void> {\n try {\n if (this.isConnected() && this?.device?.id) {\n await this.BleManager.disconnect(this.device.id);\n }\n } catch (error) {\n return Promise.reject(error);\n }\n }\n\n getCharacteristicByName(characteristicName: string): Characteristic {\n if (!(characteristicName in this.characteristicsByName)) {\n throw new Error(\n `Characteristic by name ${characteristicName} is not found`\n );\n }\n\n return this.characteristicsByName?.[characteristicName];\n }\n\n subscribeToCharacteristic({\n characteristicName,\n manageNotifications = true\n }: SubscribeOptions): Observable<any> {\n const getData = ({\n peripheralId,\n serviceUUID,\n characteristicUUID\n }: Characteristic) =>\n defer(async () => {\n if (manageNotifications) {\n try {\n await this.BleManager.startNotification(\n peripheralId,\n serviceUUID,\n characteristicUUID\n );\n\n this.addLog(\n `Started notifications for ${characteristicName} characteristic`\n );\n } catch (error) {\n this.addLog(\n `Attemped to stop notifications for ${characteristicName} characteristic: ${\n error?.message ?? error\n }`\n );\n }\n }\n }).pipe(\n switchMap(() => this.bleEvents.didUpdateValueForCharacteristic$),\n finalize(async () => {\n if (manageNotifications) {\n try {\n await this.BleManager.stopNotification(\n peripheralId,\n serviceUUID,\n characteristicUUID\n );\n this.addLog(\n `Stopped notifications for ${characteristicName} characteristic`\n );\n } catch (error) {\n this.addLog(\n `Attemped to stop notifications for ${characteristicName} characteristic: ${\n error?.message ?? error\n }`\n );\n }\n }\n }),\n filter(({ characteristic }) => characteristic === characteristicUUID),\n map(({ value }: { value: number[]; characteristic: string }): string =>\n decode(this.type, value)\n ),\n stitchChunks({ delimiter: BLUETOOTH_CHUNK_DELIMITER }),\n map((payload: any) => {\n try {\n return JSON.parse(payload);\n } catch (error) {\n this.addLog(\n `Failed to parse JSON for ${characteristicName} characteristic. Falling back to unparsed string. ${\n error?.message ?? error\n }`\n );\n\n return payload;\n }\n })\n );\n\n return this.connection$.pipe(\n switchMap((connection) =>\n connection === BLUETOOTH_CONNECTION.CONNECTED\n ? getData(this.getCharacteristicByName(characteristicName))\n : NEVER\n )\n );\n }\n\n async readCharacteristic(\n characteristicName: string,\n parse: boolean = false\n ): Promise<any> {\n this.addLog(`Reading characteristic: ${characteristicName}`);\n\n const { peripheralId, serviceUUID, characteristicUUID } =\n this.getCharacteristicByName(characteristicName);\n\n if (!characteristicUUID) {\n return Promise.reject(\n new Error(`Did not find characteristic matching ${characteristicName}`)\n );\n }\n\n try {\n const value = await this.BleManager.read(\n peripheralId,\n serviceUUID,\n characteristicUUID\n );\n\n const decodedValue = decode(this.type, value);\n const data = parse ? JSON.parse(decodedValue) : decodedValue;\n\n this.addLog(\n `Received read data from ${characteristicName} characteristic: \\n${data}`\n );\n\n return data;\n } catch (error) {\n return Promise.reject(\n new Error(\n `readCharacteristic ${characteristicName} error. ${\n error?.message ?? error\n }`\n )\n );\n }\n }\n\n async writeCharacteristic(\n characteristicName: string,\n data: string\n ): Promise<void> {\n this.addLog(`Writing characteristic: ${characteristicName}`);\n\n const { peripheralId, serviceUUID, characteristicUUID } =\n this.getCharacteristicByName(characteristicName);\n\n if (!characteristicUUID) {\n return Promise.reject(\n new Error(`Did not find characteristic matching ${characteristicName}`)\n );\n }\n\n const encoded = encode(this.type, data);\n\n await this.BleManager.write(\n peripheralId,\n serviceUUID,\n characteristicUUID,\n encoded,\n REACT_NATIVE_MAX_BYTE_SIZE\n );\n }\n\n _addPendingAction(actionId: number): void {\n const actions = this.pendingActions$.getValue();\n this.pendingActions$.next([...actions, actionId]);\n }\n\n _removePendingAction(actionId: number): void {\n const actions = this.pendingActions$.getValue();\n this.pendingActions$.next(\n actions.filter((id: number): boolean => id !== actionId)\n );\n }\n\n async _autoToggleActionNotifications(\n selectedDevice$: Observable<DeviceInfo>\n ): Promise<void> {\n let started: boolean = false;\n\n const sideEffects$ = this.connection$.asObservable().pipe(\n switchMap((connection) =>\n connection === BLUETOOTH_CONNECTION.CONNECTED\n ? this.pendingActions$\n : NEVER\n ),\n tap(async (pendingActions: string[]) => {\n const { peripheralId, serviceUUID, characteristicUUID } =\n this.getCharacteristicByName(\"actions\");\n\n const hasPendingActions = !!pendingActions.length;\n\n if (hasPendingActions && !started) {\n started = true;\n try {\n await this.BleManager.startNotification(\n peripheralId,\n serviceUUID,\n characteristicUUID\n );\n this.addLog(`Started notifications for [actions] characteristic`);\n } catch (error) {\n this.addLog(\n `Attemped to start notifications for [actions] characteristic: ${\n error?.message ?? error\n }`\n );\n }\n }\n\n if (!hasPendingActions && started) {\n started = false;\n try {\n await this.BleManager.stopNotification(\n peripheralId,\n serviceUUID,\n characteristicUUID\n );\n this.addLog(`Stopped notifications for actions characteristic`);\n } catch (error) {\n this.addLog(\n `Attemped to stop notifications for [actions] characteristic: ${\n error?.message ?? error\n }`\n );\n }\n }\n })\n );\n\n selectedDevice$\n .pipe(\n switchMap((selectedDevice: DeviceInfo) =>\n !osHasBluetoothSupport(selectedDevice) ? EMPTY : sideEffects$\n )\n )\n .subscribe();\n }\n\n async dispatchAction({\n characteristicName,\n action\n }: ActionOptions): Promise<any> {\n const {\n responseRequired = false,\n responseTimeout = DEFAULT_ACTION_RESPONSE_TIMEOUT\n } = action;\n\n return new Promise(async (resolve, reject) => {\n const actionId: number = create6DigitPin(); // use to later identify and filter response\n const payload = JSON.stringify({ actionId, ...action }); // add the response id to the action\n\n this.addLog(`Dispatched action with id ${actionId}`);\n\n if (responseRequired && responseTimeout) {\n this._addPendingAction(actionId);\n\n const timeout = timer(responseTimeout).subscribe(() => {\n this._removePendingAction(actionId);\n reject(\n new Error(\n `Action with id ${actionId} timed out after ${responseTimeout}ms`\n )\n );\n });\n\n // listen for a response before writing\n this.subscribeToCharacteristic({\n characteristicName,\n manageNotifications: false\n })\n .pipe(\n filter((response: any) => response?.actionId === actionId),\n take(1)\n )\n .subscribe((response) => {\n timeout.unsubscribe();\n this._removePendingAction(actionId);\n resolve(response);\n });\n\n // register action by writing\n this.writeCharacteristic(characteristicName, payload).catch((error) => {\n this._removePendingAction(actionId);\n reject(error);\n });\n } else {\n this.writeCharacteristic(characteristicName, payload)\n .then(() => {\n resolve(null);\n })\n .catch((error) => {\n reject(error);\n });\n }\n });\n }\n}\n","import { pipe } from \"rxjs\";\nimport { bufferCount, scan, filter, map } from \"rxjs/operators\";\n\nimport { Sample } from \"../types/sample\";\n\nconst defaultDataProp = \"data\";\nconst defaultSamplingRate = 256;\n\nconst isObject = (object) =>\n object instanceof Object && object === Object(object);\nconst isFunction = (object) => typeof object === \"function\";\n\nconst patch = (sample: Sample) => (info: any) => ({\n ...sample,\n info: {\n ...(sample?.info ?? {}),\n ...(info || {})\n }\n});\n\n/**\n * Annotates stream with user-defined metadata\n * @method addInfo\n * @example eeg$.pipe(addinfo({ samplingRate: 256, channelNames: [\"Af7\", \"Fp1\", \"Fp2\", \"Af8\"] })\n * @param {Object} info Info to be added to the EEG stream. Relevant info may include: `samplingRate` and `channelNames`\n * @returns {Observable<Sample|Epoch|PSD>}\n */\nexport const addInfo = (infoValue: any) =>\n pipe(\n map((sample: any) => {\n if (\n !isObject(sample) ||\n (!isObject(infoValue) && !isFunction(infoValue))\n ) {\n return sample;\n }\n const info: any = isFunction(infoValue) ? infoValue(sample) : infoValue;\n return patch(sample)(info);\n })\n );\n\n/**\n * Get a 2D data array organized by channel from an array of Samples. Credit to Ken from Seattle's elegant transposition\n * http://www.codesuck.com/2012/02/transpose-javascript-array-in-one-line.html\n * @method groupByChannel\n * @param {Array<Sample>} samplesBuffer Array of Samples to be grouped\n * @param {string} [dataProp] Name of the key associated with EEG data\n * @returns {Array<Array<number>>}\n */\n\nconst groupByChannel = (samplesBuffer, dataProp = defaultDataProp) =>\n samplesBuffer[0][dataProp].map((_, channelIndex) =>\n samplesBuffer.map((sample) => sample[dataProp][channelIndex])\n );\n\n/**\n * Takes an array or RxJS buffer of EEG Samples and returns an Epoch.\n * @method bufferToEpoch\n * @example eeg$.pipe(bufferTime(1000), bufferToEpoch({ samplingRate: 256 }))\n *\n * @param {Object} options - Data structure options\n * @param {number} [options.samplingRate] Sampling rate\n * @param {string} [options.dataProp='data'] Name of the key associated with eeg data\n *\n * @returns {Observable<Epoch>}\n */\nexport const bufferToEpoch = ({\n samplingRate = defaultSamplingRate,\n dataProp = defaultDataProp\n} = {}) =>\n pipe(\n map((samplesArray) => ({\n [dataProp]: groupByChannel(samplesArray, dataProp),\n info: {\n ...(samplesArray[0] && samplesArray[0].info\n ? samplesArray[0].info\n : {}),\n startTime: samplesArray[0].timestamp,\n samplingRate:\n samplesArray[0].info && samplesArray[0].info.samplingRate\n ? samplesArray[0].info.samplingRate\n : samplingRate\n }\n }))\n );\n\n/**\n * Converts a stream of individual Samples of EEG data into a stream of Epochs of a given duration emitted at specified interval. This operator functions similarly to a circular buffer internally and allows overlapping Epochs of data to be emitted (e.g. emitting the last one second of data every 100ms).\n * @method epoch\n * @example eeg$.pipe(epoch({ duration: 1024, interval: 100, samplingRate: 256 }))\n * @param {Object} options - Epoching options\n * @param {number} [options.duration=256] Number of samples to include in each epoch\n * @param {number} [options.interval=100] Time (ms) between emitted Epochs\n * @param {number} [options.samplingRate=256] Sampling rate\n * @param {string} [options.dataProp='data'] Name of the key associated with eeg data\n * @returns {Observable} Epoch\n */\nexport const epoch = ({\n duration,\n interval,\n samplingRate,\n dataProp = defaultDataProp\n}) =>\n pipe(\n bufferCount(interval),\n scan((acc, val) =>\n acc.concat(val).slice(acc.length < duration ? 0 : -duration)\n ),\n filter((samplesArray) => samplesArray.length === duration),\n bufferToEpoch({ samplingRate, dataProp })\n );\n","import { pipe, from, Observable, UnaryFunction } from \"rxjs\";\nimport { mergeMap, map } from \"rxjs/operators\";\n\nimport { epoch, addInfo } from \"../../../utils/pipes\";\nimport { Sample, CSVSample } from \"../../../types/sample\";\nimport { Epoch } from \"../../../types/epoch\";\nimport { DeviceInfo } from \"../../../types/deviceInfo\";\n\nconst EPOCH_BUFFER_SIZE = 16;\nconst SAMPLING_RATE_FALLBACK = 256; // Crown's sampling rate\n\n/**\n * @hidden\n */\nexport function csvBufferToEpoch(\n deviceInfo: DeviceInfo\n): UnaryFunction<Observable<Epoch>, any> {\n if (!deviceInfo?.samplingRate) {\n console.warn(\n `Didn't receive a sampling rate, defaulting to ${SAMPLING_RATE_FALLBACK}`\n );\n }\n\n return pipe(\n csvBufferToSamples(),\n epoch({\n duration: EPOCH_BUFFER_SIZE,\n interval: EPOCH_BUFFER_SIZE,\n samplingRate: deviceInfo?.samplingRate ?? SAMPLING_RATE_FALLBACK\n }),\n addInfo({\n channelNames: deviceInfo.channelNames,\n samplingRate: deviceInfo.samplingRate\n })\n );\n}\n\n/**\n * @hidden\n */\nexport function csvBufferToSamples(): UnaryFunction<any, any> {\n return pipe(\n mergeMap((samples: CSVSample[]): Observable<CSVSample> => from(samples)),\n map(\n ([timestamp, marker, ...data]: CSVSample): Sample => ({\n timestamp,\n data\n })\n )\n );\n}\n","import { defer, Observable, firstValueFrom, timer } from \"rxjs\";\nimport { ReplaySubject, EMPTY } from \"rxjs\";\nimport { switchMap, share, tap } from \"rxjs/operators\";\nimport { distinctUntilChanged } from \"rxjs/operators\";\n\nimport { WebBluetoothTransport } from \"./web/WebBluetoothTransport\";\nimport { ReactNativeTransport } from \"./react-native/ReactNativeTransport\";\nimport { csvBufferToEpoch } from \"./utils/csvBufferToEpoch\";\nimport { DeviceInfo } from \"../../types/deviceInfo\";\nimport { Action } from \"../../types/actions\";\nimport { Epoch } from \"../../types/epoch\";\nimport { BLUETOOTH_CONNECTION } from \"./types\";\nimport { DeviceNicknameOrPeripheral } from \"./BluetoothTransport\";\nimport { Peripheral } from \"./react-native/types/BleManagerTypes\";\nimport { osHasBluetoothSupport } from \"./utils/osHasBluetoothSupport\";\n\nexport type BluetoothTransport = WebBluetoothTransport | ReactNativeTransport;\n\ntype IsAuthenticated = boolean;\ntype ExpiresIn = number;\ntype IsAuthenticatedResponse = [IsAuthenticated, ExpiresIn];\n\ntype CreateBluetoothToken = () => Promise<string>;\n\ntype Options = {\n transport: BluetoothTransport;\n selectedDevice$: Observable<DeviceInfo>;\n createBluetoothToken: CreateBluetoothToken;\n};\n\nexport class BluetoothClient {\n transport: BluetoothTransport;\n deviceInfo: DeviceInfo;\n selectedDevice$ = new ReplaySubject<DeviceInfo>(1);\n isAuthenticated$ = new ReplaySubject<IsAuthenticated>(1);\n\n _focus$: Observable<any>;\n _calm$: Observable<any>;\n _accelerometer$: Observable<any>;\n _brainwavesRaw$: Observable<any>;\n _brainwavesRawUnfiltered$: Observable<any>;\n _brainwavesPSD$: Observable<any>;\n _brainwavesPowerByBand$: Observable<any>;\n _signalQuality$: Observable<any>;\n _status$: Observable<any>;\n _settings$: Observable<any>;\n _wifiNearbyNetworks$: Observable<any>;\n _wifiConnections$: Observable<any>;\n\n constructor(options: Options) {\n const { transport, selectedDevice$, createBluetoothToken } = options ?? {};\n\n if (!transport) {\n throw new Error(`No bluetooth transport provided.`);\n }\n\n this.transport = transport;\n\n // Pass events to the internal selectedDevice$ if selectedDevice$ is passed via options\n if (selectedDevice$) {\n selectedDevice$.subscribe(this.selectedDevice$);\n }\n\n // Auto Connect\n this.transport._autoConnect(this.selectedDevice$).subscribe({\n error: (error: Error) => {\n this.transport.addLog(\n `Auto connect: error -> ${error?.message ?? error}`\n );\n }\n });\n\n // Auto authentication\n if (typeof createBluetoothToken === \"function\") {\n this.transport.addLog(\"Auto authentication enabled\");\n this._autoAuthenticate(createBluetoothToken).subscribe();\n } else {\n this.transport.addLog(\"Auto authentication not enabled\");\n }\n\n // Auto manage action notifications\n this.transport._autoToggleActionNotifications(this.selectedDevice$);\n\n // Multicast metrics (share)\n this._focus$ = this._subscribeWhileAuthenticated(\"focus\");\n this._calm$ = this._subscribeWhileAuthenticated(\"calm\");\n this._accelerometer$ = this._subscribeWhileAuthenticated(\"accelerometer\");\n this._brainwavesRaw$ = this._subscribeWhileAuthenticated(\"raw\");\n this._brainwavesRawUnfiltered$ =\n this._subscribeWhileAuthenticated(\"rawUnfiltered\");\n this._brainwavesPSD$ = this._subscribeWhileAuthenticated(\"psd\");\n this._brainwavesPowerByBand$ =\n this._subscribeWhileAuthenticated(\"powerByBand\");\n this._signalQuality$ = this._subscribeWhileAuthenticated(\"signalQuality\");\n this._status$ = this._subscribeWhileAuthenticated(\"status\");\n this._settings$ = this._subscribeWhileAuthenticated(\"settings\");\n this._wifiNearbyNetworks$ =\n this._subscribeWhileAuthenticated(\"wifiNearbyNetworks\");\n this._wifiConnections$ =\n this._subscribeWhileAuthenticated(\"wifiConnections\");\n }\n\n _autoAuthenticate(createBluetoothToken: CreateBluetoothToken) {\n const REAUTHENTICATE_INTERVAL = 3600000; // 1 hour\n const reauthenticateInterval$ = timer(0, REAUTHENTICATE_INTERVAL).pipe(\n tap(() => {\n this.transport.addLog(`Auto authentication in progress...`);\n })\n );\n\n return this.selectedDevice$.pipe(\n switchMap((selectedDevice) =>\n !osHasBluetoothSupport(selectedDevice)\n ? EMPTY\n : this.connection().pipe(\n switchMap((connection) =>\n connection === BLUETOOTH_CONNECTION.CONNECTED\n ? reauthenticateInterval$\n : EMPTY\n ),\n switchMap(async () => await this.isAuthenticated()),\n tap(async ([isAuthenticated]) => {\n if (!isAuthenticated) {\n const token = await createBluetoothToken();\n await this.authenticate(token);\n } else {\n this.transport.addLog(`Already authenticated`);\n }\n })\n )\n )\n );\n }\n\n enableAutoConnect(autoConnect: boolean): void {\n this.transport.enableAutoConnect(autoConnect);\n }\n\n async _hasBluetoothSupport(): Promise<boolean> {\n const selectedDevice = await firstValueFrom(this.selectedDevice$);\n return osHasBluetoothSupport(selectedDevice);\n }\n\n async authenticate(token: string): Promise<IsAuthenticatedResponse> {\n const hasBluetoothSupport = await this._hasBluetoothSupport();\n if (!hasBluetoothSupport) {\n const errorMessage = `authenticate method: The OS version does not support Bluetooth.`;\n this.transport.addLog(errorMessage);\n return Promise.reject(errorMessage);\n }\n\n await this.transport.writeCharacteristic(\"auth\", token);\n\n const isAuthenticatedResponse = await this.isAuthenticated();\n\n const [isAuthenticated] = isAuthenticatedResponse;\n\n this.transport.addLog(\n `Authentication ${isAuthenticated ? \"succeeded\" : \"failed\"}`\n );\n\n this.isAuthenticated$.next(isAuthenticated);\n\n return isAuthenticatedResponse;\n }\n\n async isAuthenticated(): Promise<IsAuthenticatedResponse> {\n const [isAuthenticated, expiresIn] =\n await this.transport.readCharacteristic(\"auth\", true);\n\n this.isAuthenticated$.next(isAuthenticated);\n\n return [isAuthenticated, expiresIn];\n }\n\n // Method for React Native only\n scan(options?) {\n if (this.transport instanceof ReactNativeTransport) {\n return this.transport.scan(options);\n }\n\n if (this.transport instanceof WebBluetoothTransport) {\n throw new Error(\n `scan method is compatibly with the React Native transport only`\n );\n }\n\n throw new Error(`unknown transport`);\n }\n\n // Argument for React Native only\n connect(deviceNicknameORPeripheral?: DeviceNicknameOrPeripheral) {\n if (this.transport instanceof ReactNativeTransport) {\n return this.transport.connect(deviceNicknameORPeripheral as Peripheral);\n }\n\n if (this.transport instanceof WebBluetoothTransport) {\n return deviceNicknameORPeripheral\n ? this.transport.connect(deviceNicknameORPeripheral as string)\n : this.transport.connect();\n }\n }\n\n disconnect() {\n return this.transport.disconnect();\n }\n\n connection() {\n return this.transport.connection();\n }\n\n logs() {\n return this.transport.logs$.asObservable();\n }\n\n async getDeviceId(): Promise<string> {\n // This is a public characteristic and does not require authentication\n return this.transport.readCharacteristic(\"deviceId\");\n }\n\n async _withAuthentication<T>(getter: () => Promise<T>): Promise<T> {\n // First check if the OS supports Bluetooth before checking if the device is authenticated\n const hasBluetoothSupport = await this._hasBluetoothSupport();\n if (!hasBluetoothSupport) {\n const errorMessage = `The OS version does not support Bluetooth.`;\n this.transport.addLog(errorMessage);\n return Promise.reject(errorMessage);\n }\n\n const isAuthenticated = await firstValueFrom(this.isAuthenticated$);\n if (!isAuthenticated) {\n const errorMessage = `Authentication required.`;\n this.transport.addLog(errorMessage);\n return Promise.reject(errorMessage);\n }\n\n return await getter();\n }\n\n _subscribeWhileAuthenticated(characteristicName: string): Observable<any> {\n return this.selectedDevice$.pipe(\n switchMap((selectedDevice) =>\n !osHasBluetoothSupport(selectedDevice)\n ? EMPTY\n : this.isAuthenticated$.pipe(\n distinctUntilChanged(),\n switchMap((isAuthenticated) =>\n isAuthenticated\n ? this.transport.subscribeToCharacteristic({\n characteristicName\n })\n : EMPTY\n )\n )\n ),\n share()\n );\n }\n\n focus() {\n return this._focus$;\n }\n\n calm() {\n return this._calm$;\n }\n\n accelerometer() {\n return this._accelerometer$;\n }\n\n brainwaves(label: string): Observable<Epoch | any> {\n switch (label) {\n default:\n case \"raw\":\n return defer(() => this.getInfo()).pipe(\n switchMap((deviceInfo: DeviceInfo) =>\n this._brainwavesRaw$.pipe(csvBufferToEpoch(deviceInfo))\n )\n );\n\n case \"rawUnfiltered\":\n return defer(() => this.getInfo()).pipe(\n switchMap((deviceInfo: DeviceInfo) =>\n this._brainwavesRawUnfiltered$.pipe(csvBufferToEpoch(deviceInfo))\n )\n );\n\n case \"psd\":\n return this._brainwavesPSD$;\n\n case \"powerByBand\":\n return this._brainwavesPowerByBand$;\n }\n }\n\n signalQuality() {\n return this._signalQuality$;\n }\n\n async addMarker(label: string): Promise<void> {\n await this.dispatchAction({\n action: \"marker\",\n command: \"add\",\n message: {\n timestamp: Date.now(),\n label\n }\n });\n }\n\n async getInfo(): Promise<DeviceInfo> {\n return await this._withAuthentication(() =>\n firstValueFrom(\n this.transport.subscribeToCharacteristic({\n characteristicName: \"deviceInfo\"\n })\n )\n );\n }\n\n status() {\n return this._status$;\n }\n\n async dispatchAction(action: Action): Promise<any> {\n return await this._withAuthentication(() =>\n this.transport.dispatchAction({\n characteristicName: \"actions\",\n action\n })\n );\n }\n\n settings() {\n return this._settings$;\n }\n\n haptics(effects) {\n const metric = \"haptics\";\n\n return this.dispatchAction({\n action: metric,\n command: \"queue\",\n responseRequired: true,\n responseTimeout: 4000,\n // @TODO: implement validation logic as per SDK\n message: { effects }\n });\n }\n\n get wifi() {\n return {\n nearbyNetworks: (): Observable<any> => this._wifiNearbyNetworks$,\n\n connections: (): Observable<any> => this._wifiConnections$,\n\n connect: (ssid: string, password?: string) => {\n if (!ssid) {\n return Promise.reject(`Missing ssid`);\n }\n\n return this.dispatchAction({\n action: \"wifi\",\n command: \"connect\",\n responseRequired: true,\n responseTimeout: 1000 * 60 * 2, // 2 minutes\n message: {\n ssid,\n password: password ?? null\n }\n });\n },\n\n forgetConnection: (ssid: string): Promise<any> => {\n if (!ssid) {\n return Promise.reject(`Missing ssid`);\n }\n\n return this.dispatchAction({\n action: \"wifi\",\n command: \"forget-connection\",\n responseRequired: true,\n responseTimeout: 1000 * 15, // 15 seconds\n message: {\n ssid\n }\n });\n },\n\n reset: () => {\n return this.dispatchAction({\n action: \"wifi\",\n command: \"reset\",\n responseRequired: true,\n responseTimeout: 1000 * 30, // 30 seconds\n message: {\n // without this, the action will resolve as soon as the\n // action is received by the OS\n respondOnSuccess: true\n }\n });\n },\n\n speedTest: () => {\n return this.dispatchAction({\n action: \"wifi\",\n command: \"speed-test\",\n responseRequired: true,\n responseTimeout: 1000 * 60 * 1 // 1 minute\n });\n }\n };\n }\n}\n","export * from \"./BluetoothClient\";\nexport * from \"./web/WebBluetoothTransport\";\nexport * from \"./react-native/ReactNativeTransport\";\nexport * from \"./utils/osHasBluetoothSupport\";\nexport * from \"./types/index\";\n","import { combineLatest, Observable, of, throwError } from \"rxjs\";\nimport { ReplaySubject, firstValueFrom, EMPTY } from \"rxjs\";\nimport { distinctUntilChanged, map, switchMap } from \"rxjs/operators\";\nimport isEqual from \"fast-deep-equal\";\nimport { CloudClient, createUser } from \"./api/index\";\nimport { credentialWithLink, SERVER_TIMESTAMP } from \"./api/index\";\nimport { SDKOptions } from \"./types/options\";\nimport { STREAMING_MODE, STREAMING_TYPE } from \"./types/streaming\";\nimport { Training } from \"./types/training\";\nimport { Credentials, EmailAndPassword } from \"./types/credentials\";\nimport { CustomToken } from \"./types/credentials\";\nimport { Settings, ChangeSettings } from \"./types/settings\";\nimport { SignalQuality } from \"./types/signalQuality\";\nimport { Kinesis } from \"./types/kinesis\";\nimport { Calm } from \"./types/calm\";\nimport { Focus } from \"./types/focus\";\nimport { getLabels } from \"./utils/subscription\";\nimport { BrainwavesLabel, Epoch, PowerByBand, PSD } from \"./types/brainwaves\";\nimport { Accelerometer } from \"./types/accelerometer\";\nimport { DeviceInfo } from \"./types/deviceInfo\";\nimport { DeviceStatus, STATUS } from \"./types/status\";\nimport { Action } from \"./types/actions\";\nimport { HapticEffects } from \"./types/hapticEffects\";\nimport * as errors from \"./utils/errors\";\nimport * as platform from \"./utils/platform\";\nimport * as hapticEffects from \"./utils/hapticEffects\";\nimport { validateOAuthScopeForFunctionName } from \"./utils/oauth\";\nimport { validateOAuthScopeForAction } from \"./utils/oauth\";\nimport { createOAuthURL } from \"./api/https/createOAuthURL\";\nimport { getOAuthToken } from \"./api/https/getOAuthToken\";\nimport { OAuthConfig, OAuthQuery } from \"./types/oauth\";\nimport { OAuthQueryResult, OAuthRemoveResponse } from \"./types/oauth\";\nimport { UserClaims } from \"./types/user\";\nimport { isNode } from \"./utils/is-node\";\nimport { getCloudMetric } from \"./utils/metrics\";\nimport { Experiment } from \"./types/experiment\";\nimport { TransferDeviceOptions } from \"./utils/transferDevice\";\nimport { BluetoothClient, osHasBluetoothSupport } from \"./api/bluetooth\";\nimport { BLUETOOTH_CONNECTION } from \"./api/bluetooth/types\";\n\nconst defaultOptions = {\n timesync: false,\n autoSelectDevice: true,\n streamingMode: STREAMING_MODE.WIFI_ONLY,\n emulator: false,\n emulatorHost: \"localhost\",\n emulatorAuthPort: 9099,\n emulatorDatabasePort: 9000,\n emulatorFunctionsPort: 5001,\n emulatorFirestorePort: 8080,\n emulatorOptions: {}\n};\n\n/**\n * import StreamingModes from \"@site/src/components/StreamingModes\";\n *\n * Example\n * ```typescript\n * import { Neurosity } from \"@neurosity/sdk\";\n *\n * const neurosity = new Neurosity();\n * ```\n */\nexport class Neurosity {\n /**\n * @hidden\n */\n protected options: SDKOptions;\n\n /**\n * @hidden\n */\n protected cloudClient: CloudClient;\n\n /**\n * @hidden\n */\n protected bluetoothClient: BluetoothClient;\n\n /**\n * @hidden\n */\n protected isMissingBluetoothTransport: boolean;\n\n /**\n * @hidden\n */\n private streamingMode$ = new ReplaySubject<STREAMING_MODE>(1);\n\n /**\n *\n * @hidden\n */\n static credentialWithLink = credentialWithLink;\n\n /**\n *\n * @hidden\n */\n static createUser = createUser;\n\n /**\n *\n * @hidden\n */\n static SERVER_TIMESTAMP = SERVER_TIMESTAMP;\n\n /**\n * Creates new instance of the Neurosity SDK\n * \n * ```typescript\n * const neurosity = new Neurosity();\n * ```\n\n * @param options\n */\n constructor(options: SDKOptions = {}) {\n const { streamingMode, bluetoothTransport } = options;\n\n this.options = Object.freeze({\n ...defaultOptions,\n ...options\n });\n\n this.cloudClient = new CloudClient(this.options);\n\n if (!!bluetoothTransport) {\n this.bluetoothClient = new BluetoothClient({\n selectedDevice$: this.onDeviceChange(),\n createBluetoothToken: this.createBluetoothToken.bind(this),\n transport: bluetoothTransport\n });\n }\n\n this._initStreamingMode(streamingMode, !!bluetoothTransport);\n }\n\n /**\n *\n * @hidden\n */\n _initStreamingMode(\n streamingMode: STREAMING_MODE,\n hasBluetoothTransport: boolean\n ): void {\n const streamingModeFeaturesBluetooth = [\n STREAMING_MODE.BLUETOOTH_WITH_WIFI_FALLBACK,\n STREAMING_MODE.WIFI_WITH_BLUETOOTH_FALLBACK\n ].includes(streamingMode);\n\n const isInvalidStreamingMode =\n !Object.values(STREAMING_MODE).includes(streamingMode);\n\n const isMissingBluetoothTransport =\n streamingModeFeaturesBluetooth && !hasBluetoothTransport;\n\n this.isMissingBluetoothTransport = isMissingBluetoothTransport;\n\n const shouldDefaultToCloud =\n !streamingMode || isInvalidStreamingMode || isMissingBluetoothTransport;\n\n // Default to backwards compatible cloud streaming mode if:\n // 1. No streaming mode is provided\n // 2. An invalid streaming mode is provided\n // 3. A streaming mode containing bluetooth is provided, but without a bluetooth transport\n if (shouldDefaultToCloud) {\n this.streamingMode$.next(STREAMING_MODE.WIFI_ONLY);\n } else {\n this.streamingMode$.next(streamingMode);\n }\n }\n\n /**\n * Subscribe to the device's streaming state changes and the current strategy\n *\n * Streams the current mode of streaming (wifi or bluetooth).\n *\n * ```typescript\n * neurosity.streamingState().subscribe((streamingState) => {\n * console.log(streamingState);\n * // { streamingMode: \"wifi-only\", activeMode: \"wifi\", connected: true }\n * });\n * ```\n */\n public streamingState(): Observable<{\n connected: boolean;\n activeMode: STREAMING_TYPE;\n streamingMode: STREAMING_MODE;\n }> {\n const isWifiOnline = (state: STATUS) =>\n [STATUS.ONLINE, STATUS.UPDATING].includes(state);\n\n return this.streamingMode$.pipe(\n switchMap((streamingMode: STREAMING_MODE) => {\n return this.onDeviceChange().pipe(\n switchMap((selectDevice) => {\n if (!selectDevice) {\n return EMPTY;\n }\n\n const isUnableToUseBluetooth =\n this.isMissingBluetoothTransport ||\n !osHasBluetoothSupport(selectDevice);\n\n if (isUnableToUseBluetooth) {\n return this.cloudClient.status().pipe(\n map(({ state }) => ({\n connected: isWifiOnline(state),\n streamingMode,\n activeMode: STREAMING_TYPE.WIFI\n }))\n );\n }\n\n return combineLatest({\n wifiStatus: this.cloudClient.status(),\n bluetoothConnection: !!this?.bluetoothClient\n ? this.bluetoothClient.connection()\n : of(BLUETOOTH_CONNECTION.DISCONNECTED)\n }).pipe(\n map(({ wifiStatus, bluetoothConnection }) => {\n const isBluetoothConnected =\n bluetoothConnection === BLUETOOTH_CONNECTION.CONNECTED;\n\n switch (streamingMode) {\n default:\n case STREAMING_MODE.WIFI_ONLY:\n return {\n connected: isWifiOnline(wifiStatus.state),\n streamingMode,\n activeMode: STREAMING_TYPE.WIFI\n };\n\n case STREAMING_MODE.WIFI_WITH_BLUETOOTH_FALLBACK:\n return {\n connected:\n isWifiOnline(wifiStatus.state) || !isBluetoothConnected\n ? isWifiOnline(wifiStatus.state)\n : isBluetoothConnected,\n streamingMode,\n activeMode:\n isWifiOnline(wifiStatus.state) || !isBluetoothConnected\n ? STREAMING_TYPE.WIFI\n : STREAMING_TYPE.BLUETOOTH\n };\n\n case STREAMING_MODE.BLUETOOTH_WITH_WIFI_FALLBACK:\n return {\n connected: isBluetoothConnected\n ? true\n : isWifiOnline(wifiStatus.state),\n streamingMode,\n activeMode: isBluetoothConnected\n ? STREAMING_TYPE.BLUETOOTH\n : STREAMING_TYPE.WIFI\n };\n }\n }),\n distinctUntilChanged((a, b) => isEqual(a, b))\n );\n })\n );\n })\n );\n }\n\n /**\n *\n * @hidden\n */\n _withStreamingModeObservable<T>(streams: {\n wifi: () => Observable<T>;\n bluetooth: () => Observable<T>;\n }): Observable<any> {\n const { wifi, bluetooth } = streams;\n\n return this.streamingState().pipe(\n switchMap(({ activeMode }) => {\n switch (activeMode) {\n case STREAMING_TYPE.WIFI:\n return wifi();\n\n case STREAMING_TYPE.BLUETOOTH:\n return bluetooth();\n\n default:\n return wifi();\n }\n })\n );\n }\n\n /**\n *\n * @hidden\n */\n async _withStreamingModePromise<T>(promises: {\n wifi: () => Promise<T>;\n bluetooth: () => Promise<T>;\n }): Promise<T> {\n const { wifi, bluetooth } = promises;\n\n const { activeMode } = await firstValueFrom(this.streamingState());\n\n switch (activeMode) {\n case STREAMING_TYPE.WIFI:\n return await wifi();\n\n case STREAMING_TYPE.BLUETOOTH:\n return await bluetooth();\n\n default:\n return await wifi();\n }\n }\n\n /**\n *\n * @hidden\n */\n get bluetooth() {\n return this?.bluetoothClient;\n }\n\n /**\n *\n * @hidden\n */\n private _getCloudMetricDependencies() {\n return {\n options: this.options,\n cloudClient: this.cloudClient,\n onDeviceChange: this.onDeviceChange.bind(this),\n status: this.status.bind(this)\n };\n }\n\n /**\n * Starts user session\n *\n * ```typescript\n * await neurosity.login({\n * email: \"...\",\n * password: \"...\"\n * });\n * ```\n *\n * @param credentials\n */\n public async login(credentials: Credentials): Promise<void> {\n return await this.cloudClient.login(credentials);\n }\n\n /**\n * Ends user session\n *\n * ```typescript\n * await neurosity.logout();\n * // session has ended\n * ```\n *\n */\n public async logout(): Promise<void> {\n return await this.cloudClient.logout();\n }\n\n /**\n * @internal\n * Not user facing.\n */\n public __getApp() {\n return this.cloudClient.__getApp();\n }\n\n /**\n * Subscribe to auth state changes\n *\n * Streams the state of the auth session. If user has logged in, the user object will be set. When logged out, the user object will be null.\n *\n * ```typescript\n * neurosity.onAuthStateChanged().subscribe((user) => {\n * console.log(user);\n * });\n * ```\n */\n public onAuthStateChanged(): Observable<any> {\n return this.cloudClient.onAuthStateChanged();\n }\n\n /**\n * @internal\n * Not user facing yet\n */\n public addDevice(deviceId: string): Promise<void> {\n const [hasOAuthError, OAuthError] = validateOAuthScopeForFunctionName(\n this.cloudClient.userClaims,\n \"addDevice\"\n );\n\n if (hasOAuthError) {\n return Promise.reject(OAuthError);\n }\n\n return this.cloudClient.addDevice(deviceId);\n }\n\n /**\n * @internal\n * Not user facing yet\n */\n public removeDevice(deviceId: string): Promise<void> {\n const [hasOAuthError, OAuthError] = validateOAuthScopeForFunctionName(\n this.cloudClient.userClaims,\n \"removeDevice\"\n );\n\n if (hasOAuthError) {\n return Promise.reject(OAuthError);\n }\n\n return this.cloudClient.removeDevice(deviceId);\n }\n\n /**\n * @internal\n * Not user facing yet\n */\n public transferDevice(options: TransferDeviceOptions): Promise<void> {\n const [hasOAuthError, OAuthError] = validateOAuthScopeForFunctionName(\n this.cloudClient.userClaims,\n \"transferDevice\"\n );\n\n if (hasOAuthError) {\n return Promise.reject(OAuthError);\n }\n\n return this.cloudClient.transferDevice(options);\n }\n\n /**\n * @internal\n * Not user facing yet\n */\n public onUserDevicesChange(): Observable<DeviceInfo[]> {\n const [hasOAuthError, OAuthError] = validateOAuthScopeForFunctionName(\n this.cloudClient.userClaims,\n \"onUserDevicesChange\"\n );\n\n if (hasOAuthError) {\n return throwError(() => OAuthError);\n }\n\n return this.cloudClient.onUserDevicesChange();\n }\n\n /**\n * @internal\n * Not user facing yet\n */\n public onUserClaimsChange(): Observable<UserClaims> {\n return this.cloudClient.onUserClaimsChange();\n }\n\n /**\n * Get user devices\n *\n * Returns a list of devices claimed by the user authenticated.\n *\n * ```typescript\n * const devices = await neurosity.getDevices();\n * console.log(devices);\n * ```\n */\n public async getDevices(): Promise<DeviceInfo[]> {\n return await this.cloudClient.getDevices();\n }\n\n /**\n * Select Device\n *\n * Rarely necessary, but useful when the user owns multiple devices.\n *\n * A common use case for manually selecting a device is when you wish to build a device dropdown a user can select from, instead of collecting the Device Id from the user ahead of time.\n *\n * The 3 steps to manually selecting a device are:\n *\n * - Set `autoSelectDevice` to false when instantiating the `Neurosity` class.\n * - Authenticate with your Neurosity account to access your devices by calling the `neurosity.login(...)` function.\n * - Call the `neurosity.selectDevice(...)` function with a device selector function.\n *\n * ```typescript\n * const devices = await neurosity.selectDevice((devices) =>\n * devices.find((device) => device.deviceNickname === \"Crown-A1B\")\n * );\n *\n * console.log(devices);\n * ```\n *\n * > If you own multiple devices, and don't pass `autoSelectDevice`, then the first device on the list will be automatically selected.\n *\n * For more info, check out the \"Device Selection\" guide.\n */\n public async selectDevice(\n deviceSelector: (devices: DeviceInfo[]) => DeviceInfo\n ): Promise<DeviceInfo> {\n const [hasOAuthError, OAuthError] = validateOAuthScopeForFunctionName(\n this.cloudClient.userClaims,\n \"selectDevice\"\n );\n\n if (hasOAuthError) {\n return Promise.reject(OAuthError);\n }\n\n return await this.cloudClient.selectDevice(deviceSelector);\n }\n\n /**\n * Get selected device\n *\n * ```typescript\n * const selectedDevice = await neurosity.getSelectedDevice();\n * console.log(selectedDevice);\n * ```\n */\n\n public async getSelectedDevice(): Promise<DeviceInfo> {\n const [hasOAuthError, OAuthError] = validateOAuthScopeForFunctionName(\n this.cloudClient.userClaims,\n \"getSelectedDevice\"\n );\n\n if (hasOAuthError) {\n return Promise.reject(OAuthError);\n }\n\n return await this.cloudClient.getSelectedDevice();\n }\n\n /**\n * ```typescript\n * const info = await neurosity.getInfo();\n * ```\n */\n public async getInfo(): Promise<DeviceInfo> {\n if (!(await this.cloudClient.didSelectDevice())) {\n return Promise.reject(errors.mustSelectDevice);\n }\n\n const [hasOAuthError, OAuthError] = validateOAuthScopeForFunctionName(\n this.cloudClient.userClaims,\n \"getInfo\"\n );\n\n if (hasOAuthError) {\n return Promise.reject(OAuthError);\n }\n\n return await this._withStreamingModePromise({\n wifi: () => this.cloudClient.getInfo(),\n bluetooth: () => this.bluetoothClient.getInfo()\n });\n }\n\n /**\n * Observes selected device\n *\n * ```typescript\n * neurosity.onDeviceChange().subscribe(device => {\n * console.log(device);\n * });\n * ```\n */\n public onDeviceChange(): Observable<DeviceInfo> {\n const [hasOAuthError, OAuthError] = validateOAuthScopeForFunctionName(\n this.cloudClient.userClaims,\n \"onDeviceChange\"\n );\n\n if (hasOAuthError) {\n return throwError(() => OAuthError);\n }\n\n return this.cloudClient.onDeviceChange();\n }\n\n /**\n * <StreamingModes wifi={true} bluetooth={true} />\n *\n * Ends database connection\n *\n * ```typescript\n * await neurosity.disconnect();\n * ```\n */\n public async disconnect(): Promise<void> {\n return await this._withStreamingModePromise({\n wifi: () => this.cloudClient.disconnect(),\n bluetooth: () => this.bluetoothClient.disconnect()\n });\n }\n\n /**\n * <StreamingModes wifi={true} bluetooth={true} />\n *\n * @internal\n * Not user facing\n */\n private async dispatchAction(action: Action): Promise<Action> {\n if (!(await this.cloudClient.didSelectDevice())) {\n return Promise.reject(errors.mustSelectDevice);\n }\n\n const [hasOAuthError, OAuthError] = validateOAuthScopeForAction(\n this.cloudClient.userClaims,\n action\n );\n\n if (hasOAuthError) {\n return Promise.reject(OAuthError);\n }\n\n return await this._withStreamingModePromise({\n wifi: () => this.cloudClient.dispatchAction(action),\n bluetooth: () => this.bluetoothClient.dispatchAction(action)\n });\n }\n\n /**\n * <StreamingModes wifi={true} bluetooth={true} />\n *\n * Injects an EEG marker to data stream\n *\n * ```typescript\n * neurosity.addMarker(\"eyes-closed\");\n *\n * // later...\n *\n * neurosity.addMarker(\"eyes-open\");\n * ```\n *\n * @param label Name the label to inject\n */\n public async addMarker(label: string): Promise<Action> {\n if (!(await this.cloudClient.didSelectDevice())) {\n throw errors.mustSelectDevice;\n }\n\n if (!label) {\n throw new Error(`${errors.prefix}A label is required for addMarker`);\n }\n\n return await this._withStreamingModePromise({\n wifi: () =>\n this.cloudClient.dispatchAction({\n command: \"marker\",\n action: \"add\",\n message: {\n label,\n timestamp: this.cloudClient.timestamp\n }\n }),\n bluetooth: () => this.bluetoothClient.addMarker(label)\n });\n }\n\n /**\n * <StreamingModes wifi={true} bluetooth={true} />\n *\n * Queue haptic motor commands\n *\n * To queue haptic P7 only,\n * ```typescript\n * await neurosity.haptics({\n * P7: [\"tripleClick100\"]\n * });\n * ```\n *\n * To queue both motors at the same time\n * ```typescript\n * await neurosity.haptics({\n * P7: [neurosity.getHapticEffects().strongClick100],\n * P8: [neurosity.getHapticEffects().strongClick100]\n * });\n * ```\n *\n * You can queue different commands to the motors too\n * ```typescript\n * const effects = neurosity.getHapticEffects();\n * await neurosity.haptics({\n * P7: [effects.transitionRampUpLongSmooth1_0_to_100,\n * effects.transitionRampDownLongSmooth1_100_to_0],\n * P8: [effects.strongClick100]\n * });\n * ```\n *\n * @param effects Effects to queue. The key of the object passed should be the location of the motor\n * to queue. Each key can be an array of up to 7 commands. There is no haptic support for model\n * version 1, Notion DK1. The Haptic motor's location is positioned in reference to the 10-10 EEG\n * system used to label the channels of the Crown's EEG sensors. Notion 2 and Crown have haptics\n * at P7 and P8. A list of haptic commands can be found on ./utils/hapticCodes.ts - there\n * are about 127 of them!\n */\n public async haptics(effects: any): Promise<any> {\n const metric = \"haptics\";\n if (!(await this.cloudClient.didSelectDevice())) {\n return Promise.reject(errors.mustSelectDevice);\n }\n\n const modelVersion = (await this.getSelectedDevice())?.modelVersion;\n const supportsHaptics = platform.supportsHaptics(modelVersion);\n\n if (!supportsHaptics) {\n return Promise.reject(\n errors.metricNotSupportedByModel(metric, modelVersion)\n );\n }\n\n const newPlatformHapticRequest =\n platform.getPlatformHapticMotors(modelVersion);\n\n for (const key in effects) {\n if (!Object.keys(newPlatformHapticRequest).includes(key)) {\n return Promise.reject(errors.locationNotFound(key, modelVersion));\n }\n const singleMotorEffects: string[] = effects[key];\n const maxItems = 7;\n if (singleMotorEffects.length > maxItems) {\n return Promise.reject(errors.exceededMaxItems(maxItems));\n }\n newPlatformHapticRequest[key] = singleMotorEffects;\n }\n\n const payload = {\n command: metric,\n action: \"queue\",\n responseRequired: true,\n responseTimeout: 1000,\n message: { effects: newPlatformHapticRequest }\n };\n\n return await this._withStreamingModePromise({\n wifi: () => this.cloudClient.dispatchAction(payload),\n bluetooth: () => this.bluetoothClient.dispatchAction(payload)\n });\n }\n\n /**\n * ```typescript\n * const effects = neurosity.getHapticEffects();\n * ```\n */\n public getHapticEffects(): HapticEffects {\n return hapticEffects;\n }\n\n /**\n * <StreamingModes wifi={true} bluetooth={true} />\n *\n * Observes accelerometer data\n * Supported by the Crown and Notion 2 devices.\n *\n * ```typescript\n * neurosity.accelerometer().subscribe(accelerometer => {\n * console.log(accelerometer);\n * });\n *\n * // { acceleration: ..., inclination: ..., orientation: ..., pitch: ..., roll: ..., x: ..., y: ..., z: ... }\n * ```\n *\n * @returns Observable of accelerometer metric events\n */\n public accelerometer(): Observable<Accelerometer> {\n const metric = \"accelerometer\";\n\n const [hasOAuthError, OAuthError] = validateOAuthScopeForFunctionName(\n this.cloudClient.userClaims,\n metric\n );\n\n if (hasOAuthError) {\n return throwError(() => OAuthError);\n }\n\n return this.onDeviceChange().pipe(\n switchMap((selectedDevice: DeviceInfo | null) => {\n const modelVersion =\n selectedDevice?.modelVersion || platform.MODEL_VERSION_1;\n const supportsAccel = platform.supportsAccel(modelVersion);\n\n if (!supportsAccel) {\n return throwError(() =>\n errors.metricNotSupportedByModel(metric, modelVersion)\n );\n }\n\n return this._withStreamingModeObservable({\n wifi: () =>\n getCloudMetric(this._getCloudMetricDependencies(), {\n metric,\n labels: getLabels(metric),\n atomic: true\n }),\n bluetooth: () => this.bluetoothClient.accelerometer()\n });\n })\n );\n }\n\n /**\n * <StreamingModes wifi={true} bluetooth={true} />\n * \n * The `raw` brainwaves parameter emits epochs of 16 samples for Crown and 25 for Notion 1 and 2.\n *\n * Example\n * ```typescript\n * neurosity.brainwaves(\"raw\").subscribe(brainwaves => {\n * console.log(brainwaves);\n * });\n * ```\n *\n * Raw Unfiltered - The `rawUnfiltered` brainwaves parameter emits epochs of 16 samples for Crown and 25 for Notion 1 and 2. \n\n * Example\n * ```typescript\n * neurosity.brainwaves(\"rawUnfiltered\").subscribe(brainwaves => {\n * console.log(brainwaves);\n * });\n * ```\n *\n * Power By Band - The `powerByBand` brainwaves parameter emits epochs 4 times a second. Every frequency label (e.g. beta) contains an average power value per channel.\n * \n * Example\n * ```typescript\n * neurosity.brainwaves(\"powerByBand\").subscribe(brainwaves => {\n * console.log(brainwaves);\n * });\n * ```\n *\n * Power Spectral Density (PSD) - The `psd` brainwaves parameter emits epochs 4 times a second. Every frequency label (e.g. alpha) contains the computed FFT (Fast Fourier transform) value per channel (see the `psd` property), as well as the frequency ranges (see the `freqs` property).\n * \n * Example\n * ```typescript\n * neurosity.brainwaves(\"psd\").subscribe(brainwaves => {\n * console.log(brainwaves);\n * });\n * ```\n *\n * @param label Name of metric properties to filter by\n * @returns Observable of brainwaves metric events\n */\n public brainwaves(\n label: BrainwavesLabel\n ): Observable<Epoch | PowerByBand | PSD> {\n const [hasOAuthError, OAuthError] = validateOAuthScopeForFunctionName(\n this.cloudClient.userClaims,\n \"brainwaves\"\n );\n\n if (hasOAuthError) {\n return throwError(() => OAuthError);\n }\n\n return this._withStreamingModeObservable({\n wifi: () =>\n getCloudMetric(this._getCloudMetricDependencies(), {\n metric: \"brainwaves\",\n labels: label ? [label] : [],\n atomic: false\n }),\n // @TODO: doesn't support multiple labels, we should make the higher\n // order function only support one label\n bluetooth: () => this.bluetoothClient.brainwaves(label)\n });\n }\n\n /**\n * <StreamingModes wifi={true} bluetooth={true} />\n *\n * Example\n * ```typescript\n * neurosity.calm().subscribe(calm => {\n * console.log(calm.probability);\n * });\n *\n * // 0.45\n * // 0.47\n * // 0.53\n * // 0.51\n * // ...\n * ```\n *\n * @returns Observable of calm events - awareness/calm alias\n */\n public calm(): Observable<Calm> {\n const [hasOAuthError, OAuthError] = validateOAuthScopeForFunctionName(\n this.cloudClient.userClaims,\n \"calm\"\n );\n\n if (hasOAuthError) {\n return throwError(() => OAuthError);\n }\n\n return this._withStreamingModeObservable({\n wifi: () =>\n getCloudMetric(this._getCloudMetricDependencies(), {\n metric: \"awareness\",\n labels: [\"calm\"],\n atomic: false\n }),\n bluetooth: () => this.bluetoothClient.calm()\n });\n }\n\n /**\n * <StreamingModes wifi={true} bluetooth={true} />\n *\n * Observes signal quality data where each property is the name\n * of the channel and the value includes the standard deviation and\n * a status set by the device\n *\n * ```typescript\n * neurosity.signalQuality().subscribe(signalQuality => {\n * console.log(signalQuality);\n * });\n *\n * // { FC6: { standardDeviation: 3.5, status: \"good\" }, C3: {...}, ... }\n * ```\n *\n * @returns Observable of signalQuality metric events\n */\n public signalQuality(): Observable<SignalQuality> {\n const metric = \"signalQuality\";\n\n const [hasOAuthError, OAuthError] = validateOAuthScopeForFunctionName(\n this.cloudClient.userClaims,\n metric\n );\n\n if (hasOAuthError) {\n return throwError(() => OAuthError);\n }\n\n return this._withStreamingModeObservable({\n wifi: () =>\n getCloudMetric(this._getCloudMetricDependencies(), {\n metric,\n labels: getLabels(metric),\n atomic: true\n }),\n bluetooth: () => this.bluetoothClient.signalQuality()\n });\n }\n\n /**\n * <StreamingModes wifi={true} />\n *\n * Observes last state of `settings` and all subsequent `settings` changes\n *\n * ```typescript\n * neurosity.settings().subscribe(settings => {\n * console.log(settings.lsl);\n * });\n *\n * // true\n * // ...\n * ```\n *\n * @returns Observable of `settings` metric events\n */\n public settings(): Observable<Settings> {\n const [hasOAuthError, OAuthError] = validateOAuthScopeForFunctionName(\n this.cloudClient.userClaims,\n \"settings\"\n );\n\n if (hasOAuthError) {\n return throwError(() => OAuthError);\n }\n\n return this.cloudClient.observeNamespace(\"settings\");\n }\n\n /**\n * <StreamingModes wifi={true} bluetooth={true} />\n *\n * Example\n * ```typescript\n * neurosity.focus().subscribe(focus => {\n * console.log(focus.probability);\n * });\n *\n * // 0.56\n * // 0.46\n * // 0.31\n * // 0.39\n * // ...\n * ```\n *\n * @returns Observable of focus events - awareness/focus alias\n */\n public focus(): Observable<Focus> {\n const [hasOAuthError, OAuthError] = validateOAuthScopeForFunctionName(\n this.cloudClient.userClaims,\n \"focus\"\n );\n\n if (hasOAuthError) {\n return throwError(() => OAuthError);\n }\n\n return this._withStreamingModeObservable({\n wifi: () =>\n getCloudMetric(this._getCloudMetricDependencies(), {\n metric: \"awareness\",\n labels: [\"focus\"],\n atomic: false\n }),\n bluetooth: () => this.bluetoothClient.focus()\n });\n }\n\n /**\n * <StreamingModes wifi={true} />\n *\n * @param label Name of metric properties to filter by\n * @returns Observable of kinesis metric events\n */\n public kinesis(label: string): Observable<Kinesis> {\n const metric = \"kinesis\";\n\n const [hasOAuthError, OAuthError] = validateOAuthScopeForFunctionName(\n this.cloudClient.userClaims,\n metric\n );\n\n if (hasOAuthError) {\n return throwError(() => OAuthError);\n }\n\n return getCloudMetric(this._getCloudMetricDependencies(), {\n metric,\n labels: label ? [label] : [],\n atomic: false\n });\n }\n\n /**\n * <StreamingModes wifi={true} />\n *\n * @param label Name of metric properties to filter by\n * @returns Observable of predictions metric events\n */\n public predictions(label: string): Observable<any> {\n const metric = \"predictions\";\n\n const [hasOAuthError, OAuthError] = validateOAuthScopeForFunctionName(\n this.cloudClient.userClaims,\n metric\n );\n\n if (hasOAuthError) {\n return throwError(() => OAuthError);\n }\n\n return getCloudMetric(this._getCloudMetricDependencies(), {\n metric,\n labels: label ? [label] : [],\n atomic: false\n });\n }\n\n /**\n * <StreamingModes wifi={true} bluetooth={true} />\n *\n * Observes last state of `status` and all subsequent `status` changes\n *\n * ```typescript\n * neurosity.status().subscribe(status => {\n * console.log(status.state);\n * });\n *\n * // \"online\"\n * // ...\n * ```\n *\n * @returns Observable of `status` metric events\n */\n public status(): Observable<DeviceStatus> {\n const [hasOAuthError, OAuthError] = validateOAuthScopeForFunctionName(\n this.cloudClient.userClaims,\n \"status\"\n );\n\n if (hasOAuthError) {\n return throwError(() => OAuthError);\n }\n\n return this._withStreamingModeObservable({\n wifi: () => this.cloudClient.status(),\n bluetooth: () => this.bluetoothClient.status()\n });\n }\n\n /**\n * @internal\n * Not user facing yet\n *\n * <StreamingModes wifi={true} />\n *\n * Changes device settings programmatically. These settings can be\n * also changed from the developer console under device settings.\n *\n * Available settings [[ChangeSettings]]\n *\n * Example\n * ```typescript\n * neurosity.changeSettings({\n * lsl: true\n * });\n * ```\n */\n public async changeSettings(settings: ChangeSettings): Promise<void> {\n if (!(await this.cloudClient.didSelectDevice())) {\n return Promise.reject(errors.mustSelectDevice);\n }\n\n const [hasOAuthError, OAuthError] = validateOAuthScopeForFunctionName(\n this.cloudClient.userClaims,\n \"changeSettings\"\n );\n\n if (hasOAuthError) {\n return Promise.reject(OAuthError);\n }\n\n return await this.cloudClient.changeSettings(settings);\n }\n\n /**\n * <StreamingModes wifi={true} />\n *\n * ```typescript\n * neurosity.training.record({\n * metric: \"kinesis\",\n * label: \"push\"\n * });\n *\n * neurosity.training.stop({\n * metric: \"kinesis\",\n * label: \"push\"\n * });\n * ```\n *\n * @returns Training methods\n */\n public get training(): Training {\n return {\n /**\n * <StreamingModes wifi={true} />\n *\n * Records a training for a metric/label pair\n * @category Training\n */\n record: async (training) => {\n if (!(await this.cloudClient.didSelectDevice())) {\n throw errors.mustSelectDevice;\n }\n\n const userId =\n this.cloudClient.user && \"uid\" in this.cloudClient.user\n ? this.cloudClient.user.uid\n : null;\n const message = {\n fit: false,\n baseline: false,\n timestamp: this.cloudClient.timestamp,\n ...training,\n userId\n };\n\n await this.cloudClient.actions.dispatch({\n command: \"training\",\n action: \"record\",\n message\n });\n },\n /**\n * <StreamingModes wifi={true} />\n *\n * Stops the training for a metric/label pair\n * @category Training\n */\n stop: async (training) => {\n if (!(await this.cloudClient.didSelectDevice())) {\n throw errors.mustSelectDevice;\n }\n\n await this.cloudClient.actions.dispatch({\n command: \"training\",\n action: \"stop\",\n message: {\n ...training\n }\n });\n },\n /**\n * <StreamingModes wifi={true} />\n *\n * Stops all trainings\n * @category Training\n */\n stopAll: async () => {\n if (!(await this.cloudClient.didSelectDevice())) {\n throw errors.mustSelectDevice;\n }\n\n await this.cloudClient.actions.dispatch({\n command: \"training\",\n action: \"stopAll\",\n message: {}\n });\n }\n };\n }\n\n /**\n * @internal\n * Proof of Concept for disconnecting db\n */\n public goOffline(): void {\n this.cloudClient.goOffline();\n }\n\n /**\n * @internal\n * Proof of Concept for resuming db connection\n */\n public goOnline(): void {\n this.cloudClient.goOnline();\n }\n\n /**\n * @internal\n * Not user facing yet\n *\n * Creates user account and automatically signs in with same credentials\n *\n * @param emailAndPasswordObject\n * @returns user credential\n */\n public createAccount(credentials: EmailAndPassword) {\n return this.cloudClient.createAccount(credentials);\n }\n\n /**\n * @internal\n * Not user facing yet\n *\n * Removes all devices from an account and then deletes the account\n */\n public deleteAccount() {\n return this.cloudClient.deleteAccount();\n }\n\n /**\n * @internal\n * Not user facing\n *\n * Creates token (JWT) designed to authenticate and authorize Bluetooth clients/centrals.\n *\n * @returns token\n */\n public createBluetoothToken(): Promise<string> {\n return this.cloudClient.createBluetoothToken();\n }\n\n /**\n * @internal\n * Not user facing yet\n *\n * Creates custom token (JWT) to use to login with `{ customToken }`.\n *\n * @returns custom token\n */\n public createCustomToken(): Promise<CustomToken> {\n return this.cloudClient.createCustomToken();\n }\n\n /**\n * @internal\n * Not user facing yet\n *\n * Gets the offset between the device's clock and the client's clock\n * Requires option.timesync to be true\n *\n * @returns timesyncOffset\n */\n public getTimesyncOffset(): number {\n if (!this.options.timesync) {\n console.warn(`getTimesyncOffset() requires options.timesync to be true.`);\n }\n\n return this.options.timesync ? this.cloudClient.getTimesyncOffset() : 0;\n }\n\n /**\n * Create OAuth URL\n * 💡 OAuth requires developers to register their apps with Neurosity\n * [Read full OAuth guide](/docs/oauth)\n *\n * Creates client-specific OAuth URL. This is the first step of the OAuth workflow. Use this function to create a URL you can use to redirect users to the Neurosity sign-in page.\n * 💡 This function is designed to only run on the server side for security reasons, as it requires your client secret.\n *\n * ```typescript\n * const { Neurosity } = require(\"@neurosity/sdk\");\n *\n * const neurosity = new Neurosity({\n * autoSelectDevice: false\n * });\n *\n * exports.handler = async function (event) {\n * return neurosity\n * .createOAuthURL({\n * clientId: process.env.NEUROSITY_OAUTH_CLIENT_ID,\n * clientSecret: process.env.NEUROSITY_OAUTH_CLIENT_SECRET,\n * redirectUri: process.env.NEUROSITY_OAUTH_CLIENT_REDIRECT_URI,\n * responseType: \"token\",\n * state: Math.random().toString().split(\".\")[1],\n * scope: [\n * \"read:devices-info\",\n * \"read:devices-status\",\n * \"read:signal-quality\",\n * \"read:brainwaves\"\n * ]\n * })\n * .then((url) => ({\n * statusCode: 200,\n * body: JSON.stringify({ url })\n * }))\n * .catch((error) => ({\n * statusCode: 400,\n * body: JSON.stringify(error.response.data)\n * }));\n * };\n * ```\n * @returns custom token\n */\n public createOAuthURL(config: OAuthConfig): Promise<string> {\n if (!isNode) {\n return Promise.reject(\n new Error(\n `${errors.prefix}the createOAuthURL method must be used on the server side (node.js) for security reasons.`\n )\n );\n }\n\n return createOAuthURL(config, this.options);\n }\n\n /**\n * Get OAuth Token\n * 💡 OAuth requires developers to register their apps with Neurosity\n * [Read full OAuth guide](/docs/oauth)\n *\n * Gets client-specific OAuth token for a given userId.\n *\n * 💡 This function is designed to only run on the server side for security reasons, as it requires your client secret.\n * Here's an example of a cloud function that receives a `userId` via query params and loads the client id and client secret securely via environment variables.\n *\n *\n * ```typescript\n * const { Neurosity } = require(\"@neurosity/sdk\");\n *\n * const neurosity = new Neurosity({\n * autoSelectDevice: false\n * });\n *\n * exports.handler = async function (event) {\n * const userId = event.queryStringParameters?.userId;\n *\n * return neurosity\n * .getOAuthToken({\n * clientId: process.env.NEUROSITY_OAUTH_CLIENT_ID,\n * clientSecret: process.env.NEUROSITY_OAUTH_CLIENT_SECRET,\n * userId\n * })\n * .then((token) => ({\n * statusCode: 200,\n * body: JSON.stringify(token)\n * }))\n * .catch((error) => ({\n * statusCode: 200,\n * body: JSON.stringify(error.response.data)\n * }));\n * };\n * ```\n * @returns custom token\n */\n public getOAuthToken(query: OAuthQuery): Promise<OAuthQueryResult> {\n if (!isNode) {\n return Promise.reject(\n new Error(\n `${errors.prefix}the getOAuthToken method must be used on the server side (node.js) for security reasons.`\n )\n );\n }\n\n return getOAuthToken(query, this.options);\n }\n\n /**\n * Remove OAuth Access\n * 💡 OAuth requires developers to register their apps with Neurosity\n * [Read full OAuth guide](/docs/oauth)\n *\n * Removes client-specific OAuth token for a given userId. Requires SDK to be signed in with OAuth custom token.\n *\n * ```typescript\n * await neurosity.removeOAuthAccess().catch((error) => {\n * // handle error here...\n * });\n * ```\n * @returns custom token\n */\n public removeOAuthAccess(): Promise<OAuthRemoveResponse> {\n return this.cloudClient.removeOAuthAccess();\n }\n\n /**\n * <StreamingModes wifi={true} />\n *\n * Observes and returns a list of all Kinesis `experiments` and all subsequent experiment changes.\n * Here's an example of how to get a list of all Kinesis labels that have been trained:\n *\n * ```typescript\n *\n * const getUniqueLabels = (experiments) => {\n * const labels = experiments.flatMap((experiment) => experiment.labels);\n * // only return unique labels\n * return [...new Set(labels)];\n * }\n *\n * neurosity.onUserExperiments().subscribe((experiments) => {\n * console.log(experiments);\n * console.log(\"labels\", getUniqueLabels(experiments));\n * });\n *\n * // [{ id: '...', deviceId: '...', labels: [ 'drop' ], name: 'Lightgray cheetah', timestamp: 1577908381552, totalTrials: 16, userId: '...' }]\n * // [\"drop\", \"lift\", \"push\"]\n * ```\n *\n * @returns Observable of `experiments` events\n */\n public onUserExperiments(): Observable<Experiment[]> {\n return this.cloudClient.onUserExperiments();\n }\n\n /**\n * <StreamingModes wifi={true} />\n *\n * Deletes a specific experiment provided an experiment ID\n *\n * ```typescript\n * await neurosity.deleteUserExperiment(experiment.id);\n * ```\n *\n * @param experimentId The ID of the Experiment\n * @returns void\n */\n public deleteUserExperiment(experimentId: string): Promise<void> {\n return this.cloudClient.deleteUserExperiment(experimentId);\n }\n}\n\n/**\n * @hidden\n * Deprecated class kept for backwards compatibility purposes.\n */\nexport class Notion extends Neurosity {\n constructor(options: SDKOptions = {}) {\n super(options);\n console.log(\n `The Notion class is deprecated and will be removed in the next version of the SDK. Please use the Neurosity class instead. e.g. new Notion() => new Neurosity()`\n );\n }\n}\n","export * from \"./Neurosity\";\nexport * from \"./api/bluetooth\";\n"]}
|
|
1
|
+
{"version":3,"sources":["api/firebase/config.ts","api/firebase/FirebaseApp.ts","api/firebase/FirebaseUser.ts","api/firebase/deviceStore.ts","api/firebase/FirebaseDevice.ts","api/firebase/index.ts","utils/whileOnline.ts","timesync/Timesync.ts","timesync/index.ts","subscriptions/SubscriptionManager.ts","types/status.ts","utils/heartbeat.ts","utils/filterInternalKeys.ts","api/index.ts","types/streaming.ts","utils/errors.ts","utils/subscription.ts","utils/platform.ts","utils/hapticEffects.ts","utils/oauth.ts","api/https/config.ts","api/https/utils.ts","api/https/createOAuthURL.ts","api/https/getOAuthToken.ts","utils/is-node.ts","utils/metrics.ts","api/bluetooth/web/isMaybeWebWorkerContext.ts","api/bluetooth/web/isWebBluetoothSupported.ts","api/bluetooth/utils/create6DigitPin.ts","api/bluetooth/utils/stitch.ts","api/bluetooth/types/index.ts","api/bluetooth/utils/encoding.ts","api/bluetooth/constants.ts","api/bluetooth/utils/osHasBluetoothSupport.ts","api/bluetooth/web/WebBluetoothTransport.ts","api/bluetooth/react-native/ReactNativeTransport.ts","utils/pipes.ts","api/bluetooth/utils/csvBufferToEpoch.ts","api/bluetooth/BluetoothClient.ts","api/bluetooth/index.ts","Neurosity.ts","index.ts"],"names":[],"mappings":"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","file":"index.js","sourceRoot":"../../src","sourcesContent":["export const config = {\n apiKey: \"AIzaSyB0TkZ83Fj0CIzn8AAmE-Osc92s3ER8hy8\",\n authDomain: \"neurosity-device.firebaseapp.com\",\n databaseURL: \"https://neurosity-device.firebaseio.com\",\n projectId: \"neurosity-device\",\n storageBucket: \"neurosity-device.appspot.com\",\n messagingSenderId: \"212595049674\"\n};\n","import firebase from \"firebase/app\";\nimport \"firebase/database\";\nimport \"firebase/auth\";\nimport \"firebase/functions\";\nimport \"firebase/firestore\";\n\nimport { config } from \"./config\";\nimport { SDKOptions } from \"../../types/options\";\n\nexport const SERVER_TIMESTAMP = firebase.database.ServerValue.TIMESTAMP;\n\n/**\n * @hidden\n */\nexport class FirebaseApp {\n protected standalone: boolean;\n public app: firebase.app.App;\n\n constructor(options: SDKOptions) {\n this.app = this.getApp(options.deviceId);\n this.standalone = this.app.name === options.deviceId;\n\n if (options.emulator) {\n this.connectEmulators(options);\n }\n }\n\n private getApp(deviceId?: string) {\n const moduleApps = firebase.apps;\n const browserApps =\n typeof window !== \"undefined\" &&\n \"firebase\" in window &&\n \"apps\" in window.firebase\n ? window[\"firebase\"][\"apps\"]\n : [];\n\n const neurosityApp = [...moduleApps, ...(browserApps as any[])].find(\n (app: any) =>\n app.name === \"[DEFAULT]\" &&\n app.options.databaseURL === config.databaseURL\n );\n\n if (neurosityApp) {\n return neurosityApp;\n }\n\n if (deviceId) {\n const neurosityAppName = deviceId;\n const neurosityApp = moduleApps.find(\n (app) => app.name === neurosityAppName\n );\n return neurosityApp\n ? neurosityApp\n : firebase.initializeApp(config, neurosityAppName);\n }\n\n return firebase.initializeApp(config);\n }\n\n connectEmulators(options: SDKOptions) {\n const {\n emulatorHost,\n emulatorAuthPort,\n emulatorDatabasePort,\n emulatorFunctionsPort,\n emulatorFirestorePort,\n emulatorOptions\n } = options;\n\n this.app.auth().useEmulator(`http://${emulatorHost}:${emulatorAuthPort}`);\n this.app\n .database()\n .useEmulator(emulatorHost, emulatorDatabasePort, emulatorOptions);\n this.app.functions().useEmulator(emulatorHost, emulatorFunctionsPort);\n this.app\n .firestore()\n .useEmulator(emulatorHost, emulatorFirestorePort, emulatorOptions);\n }\n\n goOnline() {\n this.app.database().goOnline();\n }\n\n goOffline() {\n this.app.database().goOffline();\n }\n\n public disconnect(): Promise<any> {\n if (this.standalone) {\n return this.app.delete();\n }\n return Promise.resolve();\n }\n}\n","import { Observable, fromEventPattern, from, EMPTY } from \"rxjs\";\nimport { map, switchMap } from \"rxjs/operators\";\nimport firebase from \"firebase/app\";\nimport { User } from \"@firebase/auth-types\";\n\nimport { FirebaseApp } from \"./FirebaseApp\";\nimport {\n Credentials,\n EmailAndPassword,\n CustomToken\n} from \"../../types/credentials\";\nimport { UserDevices, UserClaims } from \"../../types/user\";\nimport { DeviceInfo } from \"../../types/deviceInfo\";\nimport { OAuthRemoveResponse } from \"../../types/oauth\";\nimport { Experiment } from \"../../types/experiment\";\nimport { TransferDeviceOptions } from \"../../utils/transferDevice\";\n\nconst SERVER_TIMESTAMP = firebase.database.ServerValue.TIMESTAMP;\n\n/**\n * @hidden\n */\nexport const credentialWithLink: Function =\n firebase.auth.EmailAuthProvider.credentialWithLink;\n\n/**\n * @hidden\n */\nexport function createUser(...args) {\n return new (firebase as any).User(...args);\n}\n\n/**\n * @hidden\n */\nexport class FirebaseUser {\n public app: firebase.app.App;\n public user: User | null;\n\n constructor(firebaseApp: FirebaseApp) {\n this.app = firebaseApp.app;\n\n this.app.auth().onAuthStateChanged((user: User | null) => {\n this.user = user;\n });\n }\n\n public auth() {\n return this.app.auth();\n }\n\n async createAccount(credentials: EmailAndPassword) {\n const { email, password } = credentials;\n const [error, user] = await this.app\n .auth()\n .createUserWithEmailAndPassword(email, password)\n .then((user) => [null, user])\n .catch((error) => [error, null]);\n\n if (error) {\n return Promise.reject(error);\n }\n\n return user;\n }\n\n async deleteAccount() {\n const user = this.app.auth().currentUser;\n\n if (!user) {\n return Promise.reject(\n new Error(\n `You are trying to delete an account that is not authenticated. To delete an account, the account must have signed in recently.`\n )\n );\n }\n\n const [devicesError, devices] = await this.getDevices()\n .then((response) => [null, response])\n .catch((error) => [error, null]);\n\n if (devicesError) {\n return Promise.reject(devicesError);\n }\n\n if (devices.length) {\n const removeDeviceError = await Promise.all(\n devices.map((device) => this.removeDevice(device.deviceId))\n )\n .then(() => null)\n .catch((error) => error);\n\n if (removeDeviceError) {\n return Promise.reject(removeDeviceError);\n }\n }\n\n return user.delete();\n }\n\n onAuthStateChanged(): Observable<User | null> {\n return new Observable((subscriber) => {\n try {\n this.app.auth().onAuthStateChanged(\n (user: User | null) => {\n subscriber.next(user);\n },\n (error) => {\n subscriber.error(error);\n }\n );\n } catch (error) {\n subscriber.error(error);\n }\n });\n }\n\n onLogin(): Observable<User> {\n return new Observable((subscriber) => {\n const unsubscribe = this.app\n .auth()\n .onAuthStateChanged((user: User) => {\n if (!!user) {\n subscriber.next(user);\n subscriber.complete();\n }\n });\n return () => unsubscribe();\n });\n }\n\n login(credentials: Credentials) {\n if (\"customToken\" in credentials) {\n const { customToken } = credentials;\n return this.app.auth().signInWithCustomToken(customToken);\n }\n\n if (\"idToken\" in credentials && \"providerId\" in credentials) {\n const provider = new firebase.auth.OAuthProvider(\n credentials.providerId\n );\n const oAuthCredential = provider.credential(credentials.idToken);\n return this.app.auth().signInWithCredential(oAuthCredential);\n }\n\n if (\"email\" in credentials && \"password\" in credentials) {\n const { email, password } = credentials;\n return this.app\n .auth()\n .signInWithEmailAndPassword(email, password);\n }\n\n throw new Error(\n `Either {email,password}, {customToken}, or {idToken,providerId} is required`\n );\n }\n\n logout() {\n return this.app.auth().signOut();\n }\n\n public async createCustomToken(): Promise<CustomToken> {\n const [error, customToken] = await this.app\n .functions()\n .httpsCallable(\"createCustomToken\")()\n .then(({ data }) => [null, data])\n .catch((error) => [error, null]);\n\n if (error) {\n return Promise.reject(error);\n }\n\n return customToken;\n }\n\n public async removeOAuthAccess(): Promise<OAuthRemoveResponse> {\n const userId = this.user?.uid;\n\n if (!userId) {\n return Promise.reject(\n `OAuth access can only be removed while logged in via OAuth.`\n );\n }\n\n const [error, response] = await this.app\n .functions()\n .httpsCallable(\"removeAccessOAuthApp\")()\n .then(({ data }) => [null, data])\n .catch((error) => [error, null]);\n\n if (error) {\n return Promise.reject(error);\n }\n\n const logoutError = await this.logout()\n .then(() => false)\n .catch((error) => error);\n\n if (logoutError) {\n return Promise.reject(logoutError);\n }\n\n return response;\n }\n\n async getDevices() {\n const userId = this.user?.uid;\n\n if (!userId) {\n return Promise.reject(`Please login.`);\n }\n\n const snapshot = await this.app\n .database()\n .ref(this.getUserDevicesPath())\n .once(\"value\");\n\n const userDevices: UserDevices | null = snapshot.val();\n\n return this.userDevicesToDeviceInfoList(userDevices);\n }\n\n async addDevice(deviceId: string): Promise<void> {\n const userId = this.user?.uid;\n\n if (!userId) {\n return Promise.reject(`Please login.`);\n }\n\n const devices = await this.getDevices().catch((error) => {\n console.log(error);\n });\n\n const deviceAlreadyInAccount =\n devices &&\n devices.length &&\n devices.map(({ deviceId }) => deviceId).includes(deviceId);\n\n if (deviceAlreadyInAccount) {\n return Promise.reject(\n `The device is already added to this account.`\n );\n }\n\n const [isValid, invalidErrorMessage] = await this.isDeviceIdValid(\n deviceId\n )\n .then((isValid) => [isValid])\n .catch((error) => [false, error]);\n\n if (!isValid) {\n return Promise.reject(invalidErrorMessage);\n }\n\n const claimedByPath = this.getDeviceClaimedByPath(deviceId);\n const userDevicePath = this.getUserClaimedDevicePath(deviceId);\n\n const [hasError, errorMessage] = await this.app\n .database()\n .ref()\n .update({\n [claimedByPath]: userId,\n [userDevicePath]: {\n claimedOn: SERVER_TIMESTAMP\n }\n })\n .then(() => [false])\n .catch((error) => [true, error]);\n\n if (hasError) {\n return Promise.reject(errorMessage);\n }\n }\n\n async removeDevice(deviceId: string): Promise<void> {\n const userId = this.user?.uid;\n\n if (!userId) {\n return Promise.reject(`Please login.`);\n }\n\n const claimedByPath = this.getDeviceClaimedByPath(deviceId);\n const userDevicePath = this.getUserClaimedDevicePath(deviceId);\n\n const claimedByRef = this.app.database().ref(claimedByPath);\n const userDeviceRef = this.app.database().ref(userDevicePath);\n\n const [hasError, errorMessage] = await Promise.all([\n claimedByRef.remove(),\n userDeviceRef.remove()\n ])\n .then(() => [false])\n .catch((error) => [true, error]);\n\n if (hasError) {\n return Promise.reject(errorMessage);\n }\n }\n\n public async transferDevice(\n options: TransferDeviceOptions\n ): Promise<void> {\n const userId = this.user?.uid;\n\n if (!userId) {\n return Promise.reject(\n new Error(`transferDevice: auth is required.`)\n );\n }\n\n if (\n !(\"recipientsEmail\" in options) &&\n !(\"recipientsUserId\" in options)\n ) {\n return Promise.reject(\n new Error(\n `transferDevice: either 'recipientsEmail' or 'recipientsUserId' key is required.`\n )\n );\n }\n\n if (!options?.deviceId) {\n return Promise.reject(\n new Error(`transferDevice: a deviceId is required.`)\n );\n }\n\n const [error, response] = await this.app\n .functions()\n .httpsCallable(\"transferDeviceOwnership\")(options)\n .then(({ data }) => [null, data])\n .catch((error) => [error, null]);\n\n if (error) {\n return Promise.reject(error);\n }\n }\n\n async isDeviceIdValid(deviceId: string): Promise<boolean> {\n // hex string of 32 characters\n const hexRegEx = /[0-9A-Fa-f]{32}/g;\n if (\n !deviceId ||\n deviceId.length !== 32 ||\n !hexRegEx.test(deviceId)\n ) {\n return Promise.reject(\"The device id is incorrectly formatted.\");\n }\n\n const claimedByPath = this.getDeviceClaimedByPath(deviceId);\n const claimedByRef = this.app.database().ref(claimedByPath);\n\n const claimedBySnapshot = await claimedByRef\n .once(\"value\")\n .catch(() => null);\n\n if (!claimedBySnapshot || claimedBySnapshot.exists()) {\n return Promise.reject(\"The device has already been claimed.\");\n }\n\n return true;\n }\n\n onUserDevicesChange(): Observable<DeviceInfo[]> {\n return this.onAuthStateChanged().pipe(\n switchMap((user) => {\n if (!user) {\n return EMPTY;\n }\n\n const userDevicesPath = this.getUserDevicesPath();\n const userDevicesRef = this.app.database().ref(userDevicesPath);\n\n return fromEventPattern(\n (handler) => userDevicesRef.on(\"value\", handler),\n (handler) => userDevicesRef.off(\"value\", handler)\n ).pipe(\n map(([snapshot]: [firebase.database.DataSnapshot]) =>\n snapshot.val()\n ),\n switchMap((userDevices: UserDevices | null) => {\n return from(this.userDevicesToDeviceInfoList(userDevices));\n })\n );\n })\n );\n }\n\n onUserClaimsChange(): Observable<UserClaims> {\n return this.onAuthStateChanged().pipe(\n switchMap((user) => {\n if (!user) {\n return EMPTY;\n }\n\n const claimsUpdatedOnPath = this.getUserClaimsUpdatedOnPath();\n\n const claimsUpdatedOnRef = this.app\n .database()\n .ref(claimsUpdatedOnPath);\n\n return fromEventPattern(\n (handler) => claimsUpdatedOnRef.on(\"value\", handler),\n (handler) => claimsUpdatedOnRef.off(\"value\", handler)\n ).pipe(\n map(([snapshot]: [firebase.database.DataSnapshot]) =>\n snapshot.val()\n ),\n switchMap(() => {\n // Force refresh of auth id token\n return from(this.getIdToken(true)).pipe(\n switchMap(() => from(this.getClaims()))\n );\n })\n );\n })\n );\n }\n\n async getIdToken(forceRefresh = false): Promise<void> {\n const user = this.app.auth()?.currentUser;\n\n if (!user) {\n return Promise.reject(\n `getUserIdToken: unable to get currentUser`\n );\n }\n\n await user.getIdToken(forceRefresh).catch((error) => {\n console.error(error);\n });\n }\n\n getClaims(): Promise<UserClaims> {\n const user = this.app.auth()?.currentUser;\n\n if (!user) {\n return Promise.reject(`getUserClaims: unable to get currentUser`);\n }\n\n return user\n .getIdTokenResult()\n .then((token) => token.claims)\n .catch((error) => {\n console.error(error);\n return null;\n });\n }\n\n private async userDevicesToDeviceInfoList(\n userDevices: UserDevices | null\n ): Promise<DeviceInfo[]> {\n const devicesInfoSnapshots = Object.keys(userDevices ?? {}).map(\n (deviceId) =>\n this.app\n .database()\n .ref(this.getDeviceInfoPath(deviceId))\n .once(\"value\")\n );\n\n const devicesList: DeviceInfo[] = await Promise.all(\n devicesInfoSnapshots\n ).then((snapshots) => snapshots.map((snapshot) => snapshot.val()));\n\n const validDevices = devicesList.filter((device) => !!device);\n\n validDevices.sort((a, b) => {\n return (\n userDevices[a.deviceId].claimedOn -\n userDevices[b.deviceId].claimedOn\n );\n });\n\n return validDevices;\n }\n\n public async hasDevicePermission(deviceId: string): Promise<boolean> {\n const deviceInfoPath = this.getDeviceInfoPath(deviceId);\n\n const hasPermission = await this.app\n .database()\n .ref(deviceInfoPath)\n .once(\"value\")\n .then(() => true)\n .catch(() => false);\n\n return hasPermission;\n }\n\n private getDeviceClaimedByPath(deviceId: string): string {\n return `devices/${deviceId}/status/claimedBy`;\n }\n\n private getUserClaimedDevicePath(deviceId: string): string {\n const userId = this.user.uid;\n return `users/${userId}/devices/${deviceId}`;\n }\n\n private getUserDevicesPath(): string {\n const userId = this.user.uid;\n return `users/${userId}/devices`;\n }\n\n private getUserClaimsUpdatedOnPath(): string {\n const userId = this.user.uid;\n return `users/${userId}/claimsUpdatedOn`;\n }\n\n private getDeviceInfoPath(deviceId: string): string {\n return `devices/${deviceId}/info`;\n }\n\n onUserExperiments(): Observable<Experiment[]> {\n return this.onAuthStateChanged().pipe(\n switchMap((user) => {\n if (!user) {\n return EMPTY;\n }\n\n const userId = this.user.uid;\n\n const userExperimentsRef = this.app\n .database()\n .ref(\"experiments\")\n .orderByChild(\"userId\")\n .equalTo(userId)\n .limitToFirst(100);\n\n return fromEventPattern(\n (handler) => userExperimentsRef.on(\"value\", handler),\n (handler) => userExperimentsRef.off(\"value\", handler)\n ).pipe(\n map(([snapshot]: [firebase.database.DataSnapshot]) =>\n snapshot.val()\n ),\n // transform experiments map into sorted list\n map((experimentsMaps): Experiment[] => {\n return Object.entries(experimentsMaps ?? {})\n .map(([id, value]: any) => ({\n id: value?.id ?? id,\n ...value\n }))\n .sort(\n (a: any, b: any): any =>\n new Date(b?.timestamp).getTime() -\n new Date(a?.timestamp).getTime()\n );\n })\n );\n })\n );\n }\n\n async deleteUserExperiment(experimentId: string): Promise<void> {\n if (!experimentId) {\n return Promise.reject(\n `deleteUserExperiment: please provide an experiment id`\n );\n }\n\n const removeExperiment = (experimentId: string) => {\n return this.app\n .database()\n .ref(\"experiments\")\n .child(experimentId)\n .remove();\n };\n\n const removeRelations = (experimentId: string) => {\n return this.app.functions().httpsCallable(\"removeRelations\")({\n experimentId\n });\n };\n\n await Promise.all([\n removeExperiment(experimentId),\n removeRelations(experimentId)\n ]).catch(() => {});\n }\n}\n","import firebase from \"firebase/app\";\n\nconst SERVER_TIMESTAMP = firebase.database.ServerValue.TIMESTAMP;\n\nexport interface IDevice {\n info: any;\n status: any;\n subscriptions: any;\n metrics: any;\n}\n\n/**\n * @hidden\n */\nexport const createDeviceStore = (\n app,\n deviceId,\n subscriptionManager\n) => {\n const deviceRef = app.database().ref(`devices/${deviceId}`);\n const clientId = deviceRef.child(\"subscriptions\").push().key;\n const clientRef = deviceRef.child(`clients/${clientId}`);\n let listenersToRemove = [];\n\n const set = (namespace, payload) => {\n return deviceRef.child(namespace).set(payload);\n };\n\n const push = (namespace, payload) => {\n return deviceRef.child(namespace).push(payload);\n };\n\n const update = (namespace, payload) => {\n return deviceRef.child(namespace).update(payload);\n };\n\n const on = (eventType: any = \"value\", namespace, callback) => {\n const listener = deviceRef\n .child(namespace)\n .on(eventType, (snapshot) => {\n callback(snapshot.val(), snapshot);\n });\n\n listenersToRemove.push(() => {\n deviceRef.child(namespace).off(eventType, listener);\n });\n\n return listener;\n };\n\n const off = (namespace, eventType, listener?) => {\n if (listener) {\n deviceRef.child(namespace).off(eventType, listener);\n } else {\n deviceRef.child(namespace).off(eventType);\n }\n };\n\n const once = async (namespace, eventType = \"value\") => {\n const snapshot = await deviceRef.child(namespace).once(eventType);\n return snapshot.val();\n };\n\n const remove = (namespace) => {\n deviceRef.child(namespace).remove();\n };\n\n const bindListener = (\n eventType: string,\n namespace: string,\n callback: (res: any) => void,\n overrideResponse?: any\n ) => {\n on(eventType, namespace, (data) => {\n if (data !== null) {\n off(namespace, eventType);\n const response = overrideResponse ? overrideResponse : data;\n callback(response);\n }\n });\n };\n\n const lastOfChildValue = async (namespace, key, value) => {\n const snapshot = await deviceRef\n .child(namespace)\n .orderByChild(key)\n .equalTo(value)\n .limitToLast(1)\n .once(\"value\");\n const results = snapshot.val();\n const [match] = Object.values(results || {});\n return match || null;\n };\n\n // Add client connections and subscriptions to db and remove them when offline\n const connectedListener = app\n .database()\n .ref(\".info/connected\")\n .on(\"value\", (snapshot) => {\n if (!snapshot.val()) {\n return;\n }\n\n clientRef\n .onDisconnect()\n .remove()\n .then(() => {\n clientRef.set(SERVER_TIMESTAMP);\n\n // NOTION-115: Re-subscribe when internet connection is lost and regained\n update(\"subscriptions\", subscriptionManager.get()).then(\n () => {\n subscriptionManager.toList().forEach((subscription) => {\n const childPath = `subscriptions/${subscription.id}`;\n deviceRef.child(childPath).onDisconnect().remove();\n });\n }\n );\n });\n });\n\n listenersToRemove.push(() => {\n app\n .database()\n .ref(\".info/connected\")\n .off(\"value\", connectedListener);\n });\n\n return {\n set,\n once,\n update,\n lastOfChildValue,\n onNamespace: (namespace: string, callback: Function): Function => {\n return on(\"value\", namespace, (data: any) => {\n callback(data);\n });\n },\n offNamespace: (namespace: string, listener: Function): void => {\n off(namespace, \"value\", listener);\n },\n dispatchAction: async (action) => {\n const snapshot = await push(\"actions\", action);\n const actionId = snapshot.key;\n const actionPath = `actions/${actionId}`;\n\n snapshot.onDisconnect().remove();\n\n if (action.responseRequired) {\n const responseTimeout = action.responseTimeout || 600000; // defaults to 10 minutes\n const timeout = new Promise((_, reject) => {\n const id = setTimeout(() => {\n clearTimeout(id);\n snapshot.remove();\n reject(\n `Action response timed out in ${responseTimeout}ms.`\n );\n }, responseTimeout);\n });\n\n const response = new Promise((resolve) => {\n bindListener(\"value\", `${actionPath}/response`, resolve);\n });\n\n return Promise.race([response, timeout]);\n }\n\n return actionId;\n },\n nextMetric: async (\n metricName: string,\n metricValue: { [label: string]: any }\n ) => {\n set(`metrics/${metricName}`, metricValue);\n },\n onMetric: (subscription, callback: Function) => {\n const { atomic, metric, labels } = subscription;\n const child = atomic\n ? `metrics/${metric}`\n : `metrics/${metric}/${labels[0]}`;\n return on(\"value\", child, (data) => {\n if (data !== null) {\n callback(data);\n }\n });\n },\n subscribeToMetric: (subscription) => {\n const id = deviceRef.child(\"subscriptions\").push().key;\n const childPath = `subscriptions/${id}`;\n const subscriptionCreated = {\n id,\n clientId,\n ...subscription\n };\n set(childPath, subscriptionCreated);\n\n deviceRef.child(childPath).onDisconnect().remove();\n\n return subscriptionCreated;\n },\n unsubscribeFromMetric: (subscription) => {\n remove(`subscriptions/${subscription.id}`);\n },\n removeMetricListener(subscription, listener: Function) {\n const { atomic, metric, labels } = subscription;\n const child = atomic\n ? `metrics/${metric}`\n : `metrics/${metric}/${labels[0]}`;\n off(child, \"value\", listener);\n },\n disconnect() {\n clientRef.remove();\n listenersToRemove.forEach((removeListener) => {\n removeListener();\n });\n subscriptionManager\n .toList()\n .filter((subscription) => subscription.clientId === clientId)\n .forEach((subscription) => {\n const childPath = `subscriptions/${subscription.id}`;\n deviceRef.child(childPath).remove();\n });\n }\n };\n};\n","import firebase from \"firebase/app\";\n\nimport { FirebaseApp } from \"./FirebaseApp\";\nimport { createDeviceStore } from \"./deviceStore\";\nimport { SDKDependencies } from \"../../types/options\";\n\nconst SERVER_TIMESTAMP = firebase.database.ServerValue.TIMESTAMP;\n\ntype FirebaseDeviceOptions = {\n deviceId: string;\n firebaseApp: FirebaseApp;\n dependencies: SDKDependencies;\n};\n\n/**\n * @hidden\n */\nexport class FirebaseDevice {\n static serverType = \"firebase\";\n protected app: firebase.app.App;\n protected deviceStore;\n public deviceId: string;\n\n constructor({\n deviceId,\n firebaseApp,\n dependencies\n }: FirebaseDeviceOptions) {\n if (!deviceId) {\n throw new Error(`No Device ID provided.`);\n }\n\n this.deviceId = deviceId;\n this.app = firebaseApp.app;\n this.deviceStore = createDeviceStore(\n this.app,\n deviceId,\n dependencies.subscriptionManager\n );\n }\n\n public get timestamp(): any {\n return SERVER_TIMESTAMP;\n }\n\n public dispatchAction(action): Promise<any> {\n return this.deviceStore.dispatchAction(action);\n }\n\n public async getInfo(): Promise<any> {\n return await this.deviceStore.once(\"info\");\n }\n\n public onNamespace(namespace: string, callback: Function): Function {\n return this.deviceStore.onNamespace(namespace, callback);\n }\n\n public async onceNamespace(namespace: string): Promise<any> {\n return await this.deviceStore.once(namespace);\n }\n\n public offNamespace(namespace: string, listener: Function): void {\n this.deviceStore.offNamespace(namespace, listener);\n }\n\n public async getTimesync(): Promise<number> {\n const response = await this.dispatchAction({\n command: \"timesync\",\n action: \"get\",\n responseRequired: true,\n responseTimeout: 250\n });\n return response.timestamp;\n }\n\n /**\n * Pushes metric for each subscriptions in path:\n * /devices/:deviceId/metrics/:metricName\n */\n public nextMetric(\n metricName: string,\n metricValue: { [label: string]: any }\n ): void {\n this.deviceStore.nextMetric(metricName, metricValue);\n }\n\n /**\n * Listens for metrics in path:\n * /devices/:deviceId/metrics/:metricName\n */\n public onMetric(subscription, callback): Function {\n return this.deviceStore.onMetric(subscription, callback);\n }\n\n /**\n * Creates a new and unique subscription in path:\n * /devices/:deviceId/subscriptions/:subscriptionId\n * E.g. /devices/device1/subscriptions/subscription3\n *\n * @param subscription\n * @returns subscriptionId\n */\n public subscribeToMetric(subscription) {\n const subscriptionId = this.deviceStore.subscribeToMetric({\n ...subscription,\n serverType: FirebaseDevice.serverType // @deprecated\n });\n return subscriptionId;\n }\n\n /**\n * Removes subscription in path:\n * /devices/:deviceId/subscriptions/:subscriptionId\n *\n * @param subscription\n */\n public unsubscribeFromMetric(subscription): void {\n this.deviceStore.unsubscribeFromMetric(subscription);\n }\n\n /**\n * Removes metric listener\n * /devices/:deviceId/metric\n * or\n * /devices/:deviceId/metric/label\n *\n * @param subscription\n * @param listener\n */\n public removeMetricListener(subscription, listener: Function): void {\n this.deviceStore.removeMetricListener(subscription, listener);\n }\n\n public async changeSettings(settings): Promise<void> {\n return this.deviceStore.update(\"settings\", settings);\n }\n\n public async getSkill(bundleId): Promise<any> {\n return await this.deviceStore.lastOfChildValue(\n \"skills\",\n \"bundleId\",\n bundleId\n );\n }\n\n public async createBluetoothToken(): Promise<string> {\n const [error, token] = await this.app\n .functions()\n .httpsCallable(\"createBluetoothToken\")({\n deviceId: this.deviceId\n })\n .then(({ data }) => [null, data?.token])\n .catch((error) => [error, null]);\n\n if (error) {\n return Promise.reject(error?.message ?? error);\n }\n\n if (!token) {\n return Promise.reject(`Failed to create Bluetooth token.`);\n }\n\n return token;\n }\n\n public disconnect() {\n this.deviceStore.disconnect();\n }\n}\n","export * from \"./FirebaseApp\";\nexport * from \"./FirebaseUser\";\nexport * from \"./FirebaseDevice\";\n","import { pipe, of, EMPTY, Observable } from \"rxjs\";\nimport { mergeMap, withLatestFrom } from \"rxjs/operators\";\nimport { DeviceStatus } from \"../types/status\";\n\ntype Options = {\n status$: Observable<DeviceStatus>;\n allowWhileOnSleepMode: boolean;\n};\n\nexport function whileOnline({\n status$,\n allowWhileOnSleepMode\n}: Options) {\n return pipe(\n withLatestFrom(status$),\n mergeMap(([value, status]: [any, DeviceStatus]) =>\n shouldAllowMetrics(status, allowWhileOnSleepMode)\n ? of(value)\n : EMPTY\n )\n );\n}\n\nfunction shouldAllowMetrics(\n status: DeviceStatus,\n allowWhileOnSleepMode: boolean\n) {\n return (\n status.state === \"online\" &&\n (allowWhileOnSleepMode ? true : !status.sleepMode)\n );\n}\n","import { timer, pipe, range, Observable } from \"rxjs\";\nimport { map, concatWith, filter, take } from \"rxjs/operators\";\nimport { bufferCount, concatMap, switchMap } from \"rxjs/operators\";\nimport outliers from \"outliers\";\n\nimport { whileOnline } from \"../utils/whileOnline\";\nimport { DeviceStatus } from \"../types/status\";\n\ntype Options = {\n getTimesync: () => Promise<number>;\n status$: Observable<DeviceStatus>;\n bufferSize?: number;\n updateInterval?: number;\n};\n\nconst defaultOptions = {\n bufferSize: 100,\n updateInterval: 1 * 60 * 1000 // every minute\n};\n\nexport class Timesync {\n options: Options;\n _offset: number = 0;\n\n constructor(options: Options) {\n this.options = {\n ...defaultOptions,\n ...options\n };\n\n this.start();\n }\n\n public start(): void {\n const { bufferSize, updateInterval, status$ } = this.options;\n\n const burst$ = range(0, bufferSize);\n const timer$ = timer(updateInterval, updateInterval).pipe(\n map((i: number) => bufferSize + i),\n whileOnline({\n status$,\n allowWhileOnSleepMode: true\n })\n );\n\n const firstTimeDeviceIsOnline$ = status$.pipe(\n filter((status: DeviceStatus) => status.state === \"online\"),\n take(1)\n );\n\n firstTimeDeviceIsOnline$\n .pipe(\n switchMap(() => {\n return burst$.pipe(\n concatWith(timer$),\n this.toOffset(),\n bufferCount(bufferSize, 1),\n this.filterOutliers(),\n map((list: number[]) => this.average(list))\n );\n })\n )\n .subscribe((offset) => {\n this._offset = offset;\n });\n }\n\n filterOutliers() {\n return pipe(\n map((offsets: number[]): number[] => {\n return offsets.filter(outliers());\n })\n );\n }\n\n toOffset() {\n const { getTimesync } = this.options;\n return pipe(\n concatMap(async () => {\n const requestStartTime = Date.now();\n const [error, serverTime] = await getTimesync()\n .then((offset) => [null, offset])\n .catch((error) => [error]);\n\n if (error) {\n return 0;\n }\n\n const responseEndTime = Date.now();\n const oneWayDuration = (responseEndTime - requestStartTime) / 2;\n const offset = responseEndTime - oneWayDuration - serverTime;\n return offset;\n })\n );\n }\n\n private average(list: number[]): number {\n return Math.round(\n list.reduce((acc, number) => acc + number) / list.length\n );\n }\n\n public get offset(): number {\n return this._offset;\n }\n\n public get timestamp(): number {\n return Date.now() + this._offset;\n }\n}\n","export * from \"./Timesync\";\n","import { Subscription, Subscriptions } from \"../types/subscriptions\";\n\n/**\n * @hidden\n */\nexport class SubscriptionManager {\n private _subscriptions: Subscriptions = {};\n\n public get(): Subscriptions {\n return this._subscriptions;\n }\n\n public toList(): Subscription[] {\n return Object.values(this._subscriptions);\n }\n\n public add(subscription: Subscription): void {\n this._subscriptions[subscription.id] = subscription;\n }\n\n public remove(subscription: Subscription): void {\n if (!(subscription.id in this._subscriptions)) {\n return;\n }\n\n Reflect.deleteProperty(this._subscriptions, subscription.id);\n }\n}\n","/**\n * @hidden\n */\nexport enum STATUS {\n ONLINE = \"online\",\n OFFLINE = \"offline\",\n UPDATING = \"updating\",\n BOOTING = \"booting\",\n SHUTTING_OFF = \"shuttingOff\"\n}\n\n/**\n * @hidden\n */\nexport enum SLEEP_MODE_REASON {\n UPDATING = \"updating\",\n CHARGING = \"charging\"\n}\n\nexport interface DeviceStatus {\n battery: number;\n charging: boolean;\n state: STATUS;\n sleepMode: boolean;\n sleepModeReason: SLEEP_MODE_REASON | null;\n lastHeartbeat: number;\n ssid: string;\n}\n","import { combineLatest, Observable, timer } from \"rxjs\";\nimport { map, startWith, switchMap } from \"rxjs/operators\";\nimport { withLatestFrom, distinctUntilChanged } from \"rxjs/operators\";\nimport isEqual from \"fast-deep-equal\";\n\nimport { DeviceStatus, STATUS } from \"../types/status\";\n\nconst HEARTBEAT_UPDATE_INTERVAL = 30_000; // 30 seconds - set by the OS\nconst LOST_HEARTBEAT_AFTER = HEARTBEAT_UPDATE_INTERVAL * 2.5; // 75 seconds\n\nexport function heartbeatAwareStatus(\n status$: Observable<DeviceStatus>\n): Observable<DeviceStatus> {\n const lastLocalHeartbeat$: Observable<number> = status$.pipe(\n map(({ lastHeartbeat }) => lastHeartbeat),\n distinctUntilChanged(),\n map(() => Date.now())\n );\n\n const lostHeartbeat$: Observable<void> = lastLocalHeartbeat$.pipe(\n switchMap(() => timer(LOST_HEARTBEAT_AFTER)),\n map(() => null),\n startWith(null)\n );\n\n return combineLatest({\n status: status$,\n lostHeartbeat: lostHeartbeat$ // @important - do not remove, adeed for state synchronization, value not used\n }).pipe(\n withLatestFrom(lastLocalHeartbeat$),\n map(([{ status }, lastLocalHeartbeat]) => {\n if (!lastLocalHeartbeat) {\n return status;\n }\n\n const lostHeartbeat = deviceHasLostHeartbeat(status, lastLocalHeartbeat);\n\n return lostHeartbeat\n ? {\n ...status,\n state: STATUS.OFFLINE\n }\n : status;\n }),\n distinctUntilChanged((a, b) => isEqual(a, b))\n );\n}\n\nexport function deviceHasLostHeartbeat(\n status: DeviceStatus,\n lastLocalHeartbeat: number\n): boolean {\n if (!(\"lastHeartbeat\" in status)) {\n return false;\n }\n\n // We are converting the heartbeat to the local time because the previous\n // implementation that used the server timestamp had bug where SDK clients\n // running on hardware with drifted/out-of-sync clocks (cough cough Android)\n // would override the state to offline when the heartbeat was active.\n const lostHeartbeat = Date.now() - lastLocalHeartbeat > LOST_HEARTBEAT_AFTER;\n\n return lostHeartbeat;\n}\n","import { MonoTypeOperatorFunction, pipe } from \"rxjs\";\nimport { map } from \"rxjs/operators\";\nimport { DeviceStatus } from \"../types/status\";\n\nexport function filterInternalKeys(): MonoTypeOperatorFunction<DeviceStatus> {\n return pipe(\n map((status: DeviceStatus): DeviceStatus => {\n if (!status) {\n return status;\n }\n\n // remove internal properties that start with \"__\"\n const filteredStatus: any = Object.entries(status).reduce(\n (acc, [key, value]) => {\n if (!key.startsWith(\"__\")) {\n acc[key] = value;\n }\n return acc;\n },\n {}\n );\n\n return filteredStatus;\n })\n );\n}\n","import { Observable, ReplaySubject, EMPTY } from \"rxjs\";\nimport { fromEventPattern, firstValueFrom } from \"rxjs\";\nimport { filter, shareReplay, share, switchMap } from \"rxjs/operators\";\nimport { FirebaseApp, FirebaseUser, FirebaseDevice } from \"./firebase\";\nimport { Timesync } from \"../timesync\";\nimport { SubscriptionManager } from \"../subscriptions/SubscriptionManager\";\nimport { heartbeatAwareStatus } from \"../utils/heartbeat\";\nimport { filterInternalKeys } from \"../utils/filterInternalKeys\";\nimport { Client } from \"../types/client\";\nimport { Action, Actions } from \"../types/actions\";\nimport { Metrics } from \"../types/metrics\";\nimport { SDKOptions } from \"../types/options\";\nimport { SkillsClient, DeviceSkill } from \"../types/skill\";\nimport { Credentials, CustomToken } from \"../types/credentials\";\nimport { EmailAndPassword } from \"../types/credentials\";\nimport { ChangeSettings } from \"../types/settings\";\nimport { Subscription } from \"../types/subscriptions\";\nimport { DeviceStatus } from \"../types/status\";\nimport { DeviceInfo, DeviceSelector } from \"../types/deviceInfo\";\nimport { UserClaims } from \"../types/user\";\nimport { OAuthRemoveResponse } from \"../types/oauth\";\nimport { Experiment } from \"../types/experiment\";\nimport { TransferDeviceOptions } from \"../utils/transferDevice\";\n\nexport { credentialWithLink, createUser, SERVER_TIMESTAMP } from \"./firebase\";\n\n/**\n * @hidden\n */\nexport class CloudClient implements Client {\n public user;\n public userClaims;\n protected options: SDKOptions;\n protected firebaseApp: FirebaseApp;\n protected firebaseUser: FirebaseUser;\n protected firebaseDevice: FirebaseDevice;\n protected timesync: Timesync;\n protected subscriptionManager: SubscriptionManager;\n protected status$: Observable<DeviceStatus>;\n\n /**\n * @internal\n */\n private _selectedDevice = new ReplaySubject<DeviceInfo | null | undefined>(1);\n\n constructor(options: SDKOptions) {\n this.options = options;\n this.subscriptionManager = new SubscriptionManager();\n this.firebaseApp = new FirebaseApp(options);\n this.firebaseUser = new FirebaseUser(this.firebaseApp);\n\n this._selectedDevice.next(undefined);\n\n this.status$ = heartbeatAwareStatus(\n this.observeNamespace(\"status\").pipe(share())\n ).pipe(filterInternalKeys(), shareReplay(1));\n\n this.firebaseUser.onAuthStateChanged().subscribe((user) => {\n this.user = user;\n });\n\n this.firebaseUser.onUserClaimsChange().subscribe((userClaims) => {\n this.userClaims = userClaims;\n });\n\n this.onDeviceChange().subscribe((device) => {\n if (this.firebaseDevice) {\n this.firebaseDevice.disconnect();\n }\n\n if (!device) {\n return;\n }\n\n this.firebaseDevice = new FirebaseDevice({\n deviceId: device.deviceId,\n firebaseApp: this.firebaseApp,\n dependencies: {\n subscriptionManager: this.subscriptionManager\n }\n });\n\n if (this.options.timesync) {\n this.timesync = new Timesync({\n status$: this.status(),\n getTimesync: this.firebaseDevice.getTimesync.bind(this.firebaseDevice)\n });\n }\n });\n }\n\n public onDeviceChange(): Observable<DeviceInfo> {\n return this._selectedDevice\n .asObservable()\n .pipe(filter((value) => value !== undefined));\n }\n\n // Automatically select device when user logs in\n private async setAutoSelectedDevice(): Promise<DeviceInfo | null> {\n // Select based on `deviceId` passed\n if (this.options.deviceId) {\n return await this.selectDevice((devices) => {\n return devices.find(\n (device) => device.deviceId === this.options.deviceId\n );\n });\n }\n\n // Auto select first-claimed device\n if (!this.options.deviceId && this.options.autoSelectDevice) {\n return await this.selectDevice((devices) => {\n // Auto select first device\n return devices[0];\n });\n }\n\n return null;\n }\n\n public get actions(): Actions {\n return {\n dispatch: (action) => {\n return this.firebaseDevice.dispatchAction(action);\n }\n };\n }\n\n public async dispatchAction(action: Action): Promise<any> {\n return await this.firebaseDevice.dispatchAction(action);\n }\n\n public async disconnect(): Promise<any> {\n return this.firebaseApp.disconnect();\n }\n\n public async getInfo(): Promise<any> {\n return await this.firebaseDevice.getInfo();\n }\n\n public async login(credentials: Credentials): Promise<any> {\n if (this.user) {\n return Promise.reject(`Already logged in.`);\n }\n\n const auth = await this.firebaseUser.login(credentials);\n const selectedDevice = await this.setAutoSelectedDevice();\n\n return {\n ...auth,\n selectedDevice\n };\n }\n\n public async logout(): Promise<any> {\n if (this.firebaseDevice) {\n this.firebaseDevice.disconnect();\n }\n\n return await this.firebaseUser.logout();\n }\n\n public onAuthStateChanged() {\n return this.firebaseUser.onAuthStateChanged().pipe(\n switchMap(async (user) => {\n if (!user) {\n return null;\n }\n\n const selectedDevice = this.didSelectDevice()\n ? await this.getSelectedDevice()\n : await this.setAutoSelectedDevice();\n\n return {\n ...user,\n selectedDevice\n };\n })\n );\n }\n\n public getDevices() {\n return this.firebaseUser.getDevices();\n }\n\n public addDevice(deviceId: string): Promise<void> {\n return this.firebaseUser.addDevice(deviceId);\n }\n\n public async removeDevice(deviceId: string): Promise<void> {\n const [hasError, errorMessage] = await this.firebaseUser\n .removeDevice(deviceId)\n .then(() => [false])\n .catch((error) => [true, error]);\n\n if (hasError) {\n return Promise.reject(errorMessage);\n }\n\n const selectedDevice = await this.getSelectedDevice();\n\n if (selectedDevice?.deviceId === deviceId) {\n this._selectedDevice.next(null);\n }\n }\n\n public async transferDevice(options: TransferDeviceOptions): Promise<void> {\n const [hasError, error] = await this.firebaseUser\n .transferDevice(options)\n .then(() => [false])\n .catch((error) => [true, error]);\n\n if (hasError) {\n return Promise.reject(error);\n }\n\n const selectedDevice = await this.getSelectedDevice();\n\n if (selectedDevice?.deviceId === options.deviceId) {\n this._selectedDevice.next(null);\n }\n }\n\n public onUserDevicesChange(): Observable<DeviceInfo[]> {\n return this.firebaseUser.onUserDevicesChange();\n }\n\n public onUserClaimsChange(): Observable<UserClaims> {\n return this.firebaseUser.onUserClaimsChange();\n }\n\n public async didSelectDevice(): Promise<boolean> {\n const selectedDevice = await this.getSelectedDevice();\n return !!selectedDevice;\n }\n\n public async selectDevice(\n deviceSelector: DeviceSelector\n ): Promise<DeviceInfo> {\n const devices = await this.getDevices();\n\n if (!devices) {\n return Promise.reject(\n `Did not find any devices for this user. Make sure your device is claimed by your Neurosity account.`\n );\n }\n\n const deviceTupleSelector = (devices: DeviceInfo[]) =>\n devices.find((device) => {\n if (!Array.isArray(deviceSelector)) {\n return false;\n }\n\n const [deviceKey, deviceValue] = deviceSelector;\n return (\n JSON.stringify(device?.[deviceKey]) === JSON.stringify(deviceValue)\n );\n });\n\n const device =\n typeof deviceSelector === \"function\"\n ? deviceSelector(devices)\n : deviceTupleSelector(devices);\n\n if (!device) {\n return Promise.reject(\n `A device was not provided. Try returning a device from the devicesList provided in the callback.`\n );\n }\n\n const hasPermission = await this.firebaseUser.hasDevicePermission(\n device.deviceId\n );\n\n if (!hasPermission) {\n return Promise.reject(`Rejected device access due to permissions.`);\n }\n\n this._selectedDevice.next(device);\n\n return device;\n }\n\n public async getSelectedDevice(): Promise<DeviceInfo | null> {\n return await firstValueFrom(this._selectedDevice);\n }\n\n public status(): Observable<DeviceStatus> {\n return this.status$;\n }\n\n public observeNamespace(namespace: string): Observable<any> {\n const getNamespaceValues = () =>\n fromEventPattern(\n (handler) => this.firebaseDevice.onNamespace(namespace, handler),\n (handler) => this.firebaseDevice.offNamespace(namespace, handler)\n );\n\n return this.onDeviceChange().pipe(\n switchMap((selectedDevice) => {\n return selectedDevice ? getNamespaceValues() : EMPTY;\n })\n );\n }\n\n public async onceNamespace(namespace: string): Promise<any> {\n return await this.firebaseDevice.onceNamespace(namespace);\n }\n\n public get metrics(): Metrics {\n return {\n next: (metricName: string, metricValue: any): void => {\n this.firebaseDevice.nextMetric(metricName, metricValue);\n },\n on: (subscription: Subscription, callback: Function): Function => {\n return this.firebaseDevice.onMetric(subscription, callback);\n },\n subscribe: (subscription: Subscription): Subscription => {\n const subscriptionCreated =\n this.firebaseDevice.subscribeToMetric(subscription);\n this.subscriptionManager.add(subscriptionCreated);\n return subscriptionCreated;\n },\n unsubscribe: (subscription: Subscription, listener: Function): void => {\n this.subscriptionManager.remove(subscription);\n this.firebaseDevice.unsubscribeFromMetric(subscription);\n this.firebaseDevice.removeMetricListener(subscription, listener);\n }\n };\n }\n\n public createAccount(credentials: EmailAndPassword) {\n return this.firebaseUser.createAccount(credentials);\n }\n\n public deleteAccount() {\n return this.firebaseUser.deleteAccount();\n }\n\n public createBluetoothToken(): Promise<string> {\n return this.firebaseDevice.createBluetoothToken();\n }\n\n public createCustomToken(): Promise<CustomToken> {\n return this.firebaseUser.createCustomToken();\n }\n\n public removeOAuthAccess(): Promise<OAuthRemoveResponse> {\n return this.firebaseUser.removeOAuthAccess();\n }\n\n public onUserExperiments(): Observable<Experiment[]> {\n return this.firebaseUser.onUserExperiments();\n }\n\n public deleteUserExperiment(experimentId: string): Promise<void> {\n return this.firebaseUser.deleteUserExperiment(experimentId);\n }\n\n public get skills(): SkillsClient {\n return {\n get: async (bundleId: string): Promise<DeviceSkill> => {\n return this.firebaseDevice.getSkill(bundleId);\n }\n };\n }\n\n public get timestamp(): number {\n return this.options.timesync ? this.timesync.timestamp : Date.now();\n }\n\n public getTimesyncOffset(): number {\n return this.timesync.offset;\n }\n\n public changeSettings(settings: ChangeSettings): Promise<void> {\n return this.firebaseDevice.changeSettings(settings);\n }\n\n public goOffline() {\n this.firebaseApp.goOffline();\n }\n\n public goOnline() {\n this.firebaseApp.goOnline();\n }\n\n /**\n * @internal\n */\n public __getApp() {\n return this.firebaseApp.app;\n }\n}\n","/**\n * @hidden\n */\nexport enum STREAMING_TYPE {\n WIFI = \"wifi\",\n BLUETOOTH = \"bluetooth\"\n}\n\n/**\n * @hidden\n */\nexport enum STREAMING_MODE {\n WIFI_ONLY = \"wifi-only\",\n WIFI_WITH_BLUETOOTH_FALLBACK = \"wifi-with-bluetooth-fallback\",\n BLUETOOTH_WITH_WIFI_FALLBACK = \"bluetooth-with-wifi-fallback\"\n}\n","export const prefix = \"Neurosity SDK: \";\nexport const mustSelectDevice = new Error(\n `${prefix}A device must be selected. Make sure to call \"neurosity.selectDevice()\"`\n);\n\nexport const metricNotSupportedByModel = (\n metric: string,\n modelVersion: string\n) => {\n return new Error(\n `${prefix}${metric} not supported on model version ${modelVersion}. See docs.neurosity.co for more info.`\n );\n};\n\nexport const locationNotFound = (location: string, modelVersion: string) => {\n return new Error(\n `${prefix}${location} location not supported on model version ${modelVersion}. Check spelling or see docs.neurosity.co for more info.`\n );\n};\n\nexport const exceededMaxItems = (maxItems: number) => {\n return new Error(`${prefix}Maximum items in array is ${maxItems}`);\n};\n","import { metrics } from \"@neurosity/ipk\";\n\nimport * as errors from \"../utils/errors\";\nimport { SDKOptions } from \"../types/options\";\n\nexport const isMetric = (metric: string): boolean =>\n Object.keys(metrics).includes(metric);\n\nexport const getLabels = (metric: string): string[] =>\n Object.keys(metrics[metric]);\n\nexport const hasInvalidLabels = (metric: string, labels: string[]): boolean => {\n const validLabels = getLabels(metric);\n return !labels.every((label) => validLabels.includes(label));\n};\n\nexport const isMetricDisallowed = (\n metricName: string,\n options: SDKOptions\n): boolean =>\n \"skill\" in options &&\n \"metrics\" in options.skill &&\n !options.skill.metrics.includes(metricName);\n\nexport const validate = (\n metric: string,\n labels: string[],\n options: SDKOptions\n): Error | false => {\n const validLabels = getLabels(metric).join(\", \");\n\n if (!labels.length) {\n return new Error(\n `${errors.prefix}At least one label is required for ${metric} metric. Please add one of the following labels: ${validLabels}`\n );\n }\n\n if (isMetricDisallowed(metric, options)) {\n return new Error(\n `${errors.prefix}No permission to access the ${metric} metric. To access this metric, edit the skill's permissions`\n );\n }\n\n if (hasInvalidLabels(metric, labels)) {\n return new Error(\n `${errors.prefix}One ore more labels provided to ${metric} are invalid. The valid labels for ${metric} are ${validLabels}`\n );\n }\n\n return false;\n};\n","export const MODEL_VERSION_1 = \"1\";\nexport const MODEL_VERSION_2 = \"2\";\nexport const MODEL_VERSION_3 = \"3\";\n\nexport const FEATURE_HAPTICS = \"haptics\";\nexport const FEATURE_ACCEL = \"accel\";\n\nexport const HAPTIC_P7 = \"P7\";\nexport const HAPTIC_P8 = \"P8\";\n\nexport const platformFeaturesByModelVersion = {\n [MODEL_VERSION_1]: [],\n [MODEL_VERSION_2]: [FEATURE_HAPTICS, FEATURE_ACCEL],\n [MODEL_VERSION_3]: [FEATURE_HAPTICS, FEATURE_ACCEL]\n};\n\nexport const platformConfigByModelVersion = {\n [MODEL_VERSION_1]: {},\n [MODEL_VERSION_2]: {\n motorByMotorName: {\n [HAPTIC_P7]: [],\n [HAPTIC_P8]: []\n }\n },\n [MODEL_VERSION_3]: {\n motorByMotorName: {\n [HAPTIC_P7]: [],\n [HAPTIC_P8]: []\n }\n }\n};\n\nexport const supportsHaptics = (modelVersion: string): boolean => {\n const platformFeaturesForModel =\n platformFeaturesByModelVersion[modelVersion];\n return platformFeaturesForModel.includes(FEATURE_HAPTICS);\n};\n\nexport const supportsAccel = (modelVersion: string): boolean => {\n const platformFeaturesForModel =\n platformFeaturesByModelVersion[modelVersion];\n return platformFeaturesForModel.includes(FEATURE_ACCEL);\n};\n\nexport const getPlatformHapticMotors = (modelVersion: string) => {\n const platformConfigForModel =\n platformConfigByModelVersion[modelVersion];\n const platformMotorByMotorName =\n platformConfigForModel?.motorByMotorName ?? {};\n return { ...platformMotorByMotorName };\n};\n","// All 127ish codes here:\n/// https://cdn-learn.adafruit.com/downloads/pdf/adafruit-drv2605-haptic-controller-breakout.pdf\nexport const strongClick100 = \"strongClick100\";\nexport const strongClick60 = \"strongClick60\";\nexport const strongClick30 = \"strongClick30\";\nexport const sharpClick100 = \"sharpClick100\";\nexport const sharpClick60 = \"sharpClick60\";\nexport const sharpClick30 = \"sharpClick30\";\nexport const softBump100 = \"softBump100\";\nexport const softBump60 = \"softBump60\";\nexport const softBump30 = \"softBump30\";\nexport const doubleClick100 = \"doubleClick100\";\nexport const doubleClick60 = \"doubleClick60\";\nexport const tripleClick100 = \"tripleClick100\";\nexport const softFuzz60 = \"softFuzz60\";\nexport const strongBuzz100 = \"strongBuzz100\";\nexport const alert750ms = \"alert750ms\";\nexport const alert1000ms = \"alert1000ms\";\nexport const strongClick1_100 = \"strongClick1_100\";\nexport const strongClick2_80 = \"strongClick2_80\";\nexport const strongClick3_60 = \"strongClick3_60\";\nexport const strongClick4_30 = \"strongClick4_30\";\nexport const mediumClick1_100 = \"mediumClick1_100\";\nexport const mediumClick2_80 = \"mediumClick2_80\";\nexport const mediumClick3_60 = \"mediumClick3_60\";\nexport const sharpTick1_100 = \"sharpTick1_100\";\nexport const sharpTick2_80 = \"sharpTick2_80\";\nexport const sharpTick3_60 = \"sharpTick3_60\";\nexport const shortDoubleClickStrong1_100 =\n \"shortDoubleClickStrong1_100\";\nexport const shortDoubleClickStrong2_80 = \"shortDoubleClickStrong2_80\";\nexport const shortDoubleClickStrong3_60 = \"shortDoubleClickStrong3_60\";\nexport const shortDoubleClickStrong4_30 = \"shortDoubleClickStrong4_30\";\nexport const shortDoubleClickMedium1_100 =\n \"shortDoubleClickMedium1_100\";\nexport const shortDoubleClickMedium2_80 = \"shortDoubleClickMedium2_80\";\nexport const shortDoubleClickMedium3_60 = \"shortDoubleClickMedium3_60\";\nexport const shortDoubleSharpTick1_100 = \"shortDoubleSharpTick1_100\";\nexport const shortDoubleSharpTick2_80 = \"shortDoubleSharpTick2_80\";\nexport const shortDoubleSharpTick3_60 = \"shortDoubleSharpTick3_60\";\nexport const longDoubleSharpClickStrong1_100 =\n \"longDoubleSharpClickStrong1_100\";\nexport const longDoubleSharpClickStrong2_80 =\n \"longDoubleSharpClickStrong2_80\";\nexport const longDoubleSharpClickStrong3_60 =\n \"longDoubleSharpClickStrong3_60\";\nexport const longDoubleSharpClickStrong4_30 =\n \"longDoubleSharpClickStrong4_30\";\nexport const longDoubleSharpClickMedium1_100 =\n \"longDoubleSharpClickMedium1_100\";\nexport const longDoubleSharpClickMedium2_80 =\n \"longDoubleSharpClickMedium2_80\";\nexport const longDoubleSharpClickMedium3_60 =\n \"longDoubleSharpClickMedium3_60\";\nexport const longDoubleSharpTick1_100 = \"longDoubleSharpTick1_100\";\nexport const longDoubleSharpTick2_80 = \"longDoubleSharpTick2_80\";\nexport const longDoubleSharpTick3_60 = \"longDoubleSharpTick3_60\";\nexport const buzz1_100 = \"buzz1_100\";\nexport const buzz2_80 = \"buzz2_80\";\nexport const buzz3_60 = \"buzz3_60\";\nexport const buzz4_40 = \"buzz4_40\";\nexport const buzz5_20 = \"buzz5_20\";\nexport const pulsingStong1_100 = \"pulsingStong1_100\";\nexport const pulsingStong2_60 = \"pulsingStong2_60\";\nexport const pulsingMedium1_100 = \"pulsingMedium1_100\";\nexport const pulsingMedium2_60 = \"pulsingMedium2_60\";\nexport const pulsingSharp1_100 = \"pulsingSharp1_100\";\nexport const pulsingSharp2_60 = \"pulsingSharp2_60\";\nexport const transistionClick1_100 = \"transistionClick1_100\";\nexport const transistionClick2_80 = \"transistionClick2_80\";\nexport const transistionClick3_60 = \"transistionClick3_60\";\nexport const transistionClick4_40 = \"transistionClick4_40\";\nexport const transistionClick5_20 = \"transistionClick5_20\";\nexport const transistionClick6_10 = \"transistionClick6_10\";\nexport const transistionHum1_100 = \"transistionHum1_100\";\nexport const transistionHum2_80 = \"transistionHum2_80\";\nexport const transistionHum3_60 = \"transistionHum3_60\";\nexport const transistionHum4_40 = \"transistionHum4_40\";\nexport const transistionHum5_20 = \"transistionHum5_20\";\nexport const transistionHum6_10 = \"transistionHum6_10\";\nexport const transitionRampDownLongSmooth1_100_to_0 =\n \"transitionRampDownLongSmooth1_100_to_0\";\nexport const transitionRampDownLongSmooth2_100_to_0 =\n \"transitionRampDownLongSmooth2_100_to_0\";\nexport const transitionRampDownMediumSmooth1_100_to_0 =\n \"transitionRampDownMediumSmooth1_100_to_0\";\nexport const transitionRampDownMediumSmooth2_100_to_0 =\n \"transitionRampDownMediumSmooth2_100_to_0\";\nexport const transitionRampDownShortSmooth1_100_to_0 =\n \"transitionRampDownShortSmooth1_100_to_0\";\nexport const transitionRampDownShortSmooth2_100_to_0 =\n \"transitionRampDownShortSmooth2_100_to_0\";\nexport const transitionRampDownLongSharp1_100_to_0 =\n \"transitionRampDownLongSharp1_100_to_0\";\nexport const transitionRampDownLongSharp2_100_to_0 =\n \"transitionRampDownLongSharp2_100_to_0\";\nexport const transitionRampDownLongMedium1_100_to_0 =\n \"transitionRampDownLongMedium1_100_to_0\";\nexport const transitionRampDownLongMedium2_100_to_0 =\n \"transitionRampDownLongMedium2_100_to_0\";\nexport const transitionRampDownShortSharp1_100_to_0 =\n \"transitionRampDownShortSharp1_100_to_0\";\nexport const transitionRampDownShortSharp2_100_to_0 =\n \"transitionRampDownShortSharp2_100_to_0\";\nexport const transitionRampUpLongSmooth1_0_to_100 =\n \"transitionRampUpLongSmooth1_0_to_100\";\nexport const transitionRampUpLongSmooth2_0_to_100 =\n \"transitionRampUpLongSmooth2_0_to_100\";\nexport const transitionRampUpMediumSmooth1_0_to_100 =\n \"transitionRampUpMediumSmooth1_0_to_100\";\nexport const transitionRampUpMediumSmooth2_0_to_100 =\n \"transitionRampUpMediumSmooth2_0_to_100\";\nexport const transitionRampUpShortSmooth1_0_to_100 =\n \"transitionRampUpShortSmooth1_0_to_100\";\nexport const transitionRampUpShortSmooth2_0_to_100 =\n \"transitionRampUpShortSmooth2_0_to_100\";\nexport const transitionRampUpLongSharp1_0_to_100 =\n \"transitionRampUpLongSharp1_0_to_100\";\nexport const transitionRampUpLongSharp2_0_to_100 =\n \"transitionRampUpLongSharp2_0_to_100\";\nexport const transitionRampUpMediumSharp1_0_to_100 =\n \"transitionRampUpMediumSharp1_0_to_100\";\nexport const transitionRampUpMediumSharp2_0_to_100 =\n \"transitionRampUpMediumSharp2_0_to_100\";\nexport const transitionRampUpShortSharp1_0_to_100 =\n \"transitionRampUpShortSharp1_0_to_100\";\nexport const transitionRampUpShortSharp2_0_to_100 =\n \"transitionRampUpShortSharp2_0_to_100\";\nexport const transitionRampDownLongSmooth1_50_to_0 =\n \"transitionRampDownLongSmooth1_50_to_0\";\nexport const transitionRampDownLongSmooth2_50_to_0 =\n \"transitionRampDownLongSmooth2_50_to_0\";\nexport const transitionRampDownMediumSmooth1_50_to_0 =\n \"transitionRampDownMediumSmooth1_50_to_0\";\nexport const transitionRampDownMediumSmooth2_50_to_0 =\n \"transitionRampDownMediumSmooth2_50_to_0\";\nexport const transitionRampDownShortSmooth1_50_to_0 =\n \"transitionRampDownShortSmooth1_50_to_0\";\nexport const transitionRampDownShortSmooth2_50_to_0 =\n \"transitionRampDownShortSmooth2_50_to_0\";\nexport const transitionRampDownLongSharp1_50_to_0 =\n \"transitionRampDownLongSharp1_50_to_0\";\nexport const transitionRampDownLongSharp2_50_to_0 =\n \"transitionRampDownLongSharp2_50_to_0\";\nexport const transitionRampDownMediumSharp1_50_to_0 =\n \"transitionRampDownMediumSharp1_50_to_0\";\nexport const transitionRampDownMediumSharp2_50_to_0 =\n \"transitionRampDownMediumSharp2_50_to_0\";\nexport const transitionRampDownShortSharp1_50_to_0 =\n \"transitionRampDownShortSharp1_50_to_0\";\nexport const transitionRampDownShortSharp2_50_to_0 =\n \"transitionRampDownShortSharp2_50_to_0\";\nexport const transitionRampUpLongSmooth1_0_to_50 =\n \"transitionRampUpLongSmooth1_0_to_50\";\nexport const transitionRampUpLongSmooth2_0_to_50 =\n \"transitionRampUpLongSmooth2_0_to_50\";\nexport const transitionRampUpMediumSmooth1_0_to_50 =\n \"transitionRampUpMediumSmooth1_0_to_50\";\nexport const transitionRampUpMediumSmooth2_0_to_50 =\n \"transitionRampUpMediumSmooth2_0_to_50\";\nexport const transitionRampUpShortSmooth1_0_to_50 =\n \"transitionRampUpShortSmooth1_0_to_50\";\nexport const transitionRampUpShortSmooth2_0_to_50 =\n \"transitionRampUpShortSmooth2_0_to_50\";\nexport const transitionRampUpLongSharp1_0_to_50 =\n \"transitionRampUpLongSharp1_0_to_50\";\nexport const transitionRampUpLongSharp2_0_to_50 =\n \"transitionRampUpLongSharp2_0_to_50\";\nexport const transitionRampUpMediumSharp1_0_to_50 =\n \"transitionRampUpMediumSharp1_0_to_50\";\nexport const transitionRampUpMediumSharp2_0_to_50 =\n \"transitionRampUpMediumSharp2_0_to_50\";\nexport const transitionRampUpShortSharp1_0_to_50 =\n \"transitionRampUpShortSharp1_0_to_50\";\nexport const transitionRampUpShortSharp2_0_to_50 =\n \"transitionRampUpShortSharp2_0_to_50\";\nexport const longBuzzForProgrammaticStopping_100 =\n \"longBuzzForProgrammaticStopping_100\";\nexport const smoothHum1_50 = \"smoothHum1_50\";\nexport const smoothHum2_40 = \"smoothHum2_40\";\nexport const smoothHum3_30 = \"smoothHum3_30\";\nexport const smoothHum4_20 = \"smoothHum4_20\";\nexport const smoothHum5_10 = \"smoothHum5_10\";\n","import * as errors from \"../utils/errors\";\nimport { Action } from \"../types/actions\";\n\ntype OAuthClaims = {\n oauth?: true;\n authId?: string;\n scopes?: string;\n};\n\nconst scopeRequiredByAction = {\n \"marker/add\": \"write:brainwave-markers\",\n \"brainwaves/record\": \"write:brainwaves\",\n \"haptics/queue\": \"write:haptics\",\n \"training/record\": \"write:kinesis\",\n \"training/stop\": \"write:kinesis\",\n \"training/stopAll\": \"write:kinesis\",\n \"wifi/reset\": \"write:wifi-settings\"\n};\n\nconst scopeRequiredByFunctionName = {\n //metrics\n accelerometer: \"read:accelerometer\",\n brainwaves: \"read:brainwaves\",\n calm: \"read:calm\",\n focus: \"read:focus\",\n kinesis: \"read:kinesis\",\n predictions: \"read:kinesis\",\n signalQuality: \"read:signal-quality\",\n // end of metrics\n // device info\n getInfo: \"read:devices-info\",\n getSelectedDevice: \"read:devices-info\",\n selectDevice: \"read:devices-info\",\n onDeviceChange: \"read:devices-info\",\n onUserDevicesChange: \"read:devices-info\",\n osVersion: \"read:devices-info\",\n // end device info\n settings: \"read:devices-settings\",\n changeSettings: \"write:devices-settings\",\n status: \"read:devices-status\",\n addDevice: \"write:devices-add\",\n removeDevice: \"write:devices-remove\",\n transferDevice: \"write:devices-remove\"\n};\n\nexport function validateOAuthScopeForAction(\n userClaims: OAuthClaims,\n action: Action\n): [boolean, Error | null] {\n const { oauth, scopes: scopesString } = userClaims ?? {};\n\n if (!oauth) {\n return [false, null];\n }\n\n const scopes = scopesString.split(\",\");\n\n const { command, action: actionName } = action;\n const requiredScope = scopeRequiredByAction[`${command}/${actionName}`];\n const hasRequireScopes = scopes.includes(requiredScope);\n\n if (hasRequireScopes) {\n return [false, null];\n }\n\n return [true, getScopeError(requiredScope)];\n}\n\nexport function validateOAuthScopeForFunctionName(\n userClaims: OAuthClaims,\n functionName: string\n): [boolean, Error | null] {\n const { oauth, scopes: scopesString } = userClaims ?? {};\n\n if (!oauth) {\n return [false, null];\n }\n\n const scopes = scopesString.split(\",\");\n\n const requiredScope = scopeRequiredByFunctionName[functionName];\n const hasRequireScopes = scopes.includes(requiredScope);\n\n if (hasRequireScopes) {\n return [false, null];\n }\n\n return [true, getScopeError(requiredScope)];\n}\n\nfunction getScopeError(...requiredScopes: string[]): Error {\n return new Error(\n `${\n errors.prefix\n }You are trying to access data with an OAuth token without access to the following scopes: ${requiredScopes.join(\n \", \"\n )}.`\n );\n}\n","export const prodFunctionsBaseUrl =\n \"https://us-central1-neurosity-device.cloudfunctions.net\";\n","import { prodFunctionsBaseUrl } from \"./config\";\nimport { SDKOptions } from \"../../types/options\";\n\nexport function getFunctionsBaseURL(sdkOptions: SDKOptions) {\n if (!sdkOptions.emulator) {\n return prodFunctionsBaseUrl;\n }\n\n const { emulatorHost, emulatorFunctionsPort } = sdkOptions;\n const emulatorFunctionsBaseUrl = `http://${emulatorHost}:${emulatorFunctionsPort}/neurosity-device/us-central1`;\n\n return emulatorFunctionsBaseUrl;\n}\n","import axios from \"axios\";\n\nimport { getFunctionsBaseURL } from \"./utils\";\nimport { SDKOptions } from \"../../types/options\";\nimport { OAuthConfig } from \"../../types/oauth\";\n\nexport function createOAuthURL(\n config: OAuthConfig,\n sdkOptions: SDKOptions\n): Promise<string> {\n const {\n clientId,\n clientSecret,\n responseType,\n redirectUri,\n scope,\n state\n } = config;\n\n const baseUrl = getFunctionsBaseURL(sdkOptions);\n\n return axios\n .get(`${baseUrl}/authorize/entry`, {\n params: {\n client_id: clientId,\n ...(clientSecret ? { client_secret: clientSecret } : {}),\n response_type: responseType,\n redirect_uri: redirectUri,\n scope: scope.join(\",\"),\n state: state,\n redirect: \"false\"\n }\n })\n .then((response) => `${baseUrl}${response.data.url}`);\n}\n","import axios from \"axios\";\n\nimport { getFunctionsBaseURL } from \"./utils\";\nimport { SDKOptions } from \"../../types/options\";\nimport { OAuthQuery, OAuthQueryResult } from \"../../types/oauth\";\n\nexport async function getOAuthToken(\n query: OAuthQuery,\n sdkOptions: SDKOptions\n): Promise<OAuthQueryResult> {\n const baseUrl = getFunctionsBaseURL(sdkOptions);\n\n // Get refresh token\n const refreshResponse = await axios.post(\n `${baseUrl}/getOAuthRefreshToken`,\n query\n );\n\n const refreshToken = refreshResponse.data;\n\n return axios\n .post(`${baseUrl}/token`, {\n grant_type: \"refresh_token\",\n refresh_token: refreshToken.data,\n client_id: query.clientId,\n client_secret: query.clientSecret\n })\n .then((response) => JSON.parse(response.data)[\"access_token\"]);\n}\n","export function isNode() {\n return (\n typeof process !== \"undefined\" &&\n process.versions != null &&\n process.versions.node != null\n );\n}\n","import { Observable, throwError, EMPTY } from \"rxjs\";\nimport { switchMap } from \"rxjs/operators\";\n\nimport { whileOnline } from \"./whileOnline\";\nimport { validate } from \"./subscription\";\nimport { PendingSubscription, Subscription } from \"../types/subscriptions\";\nimport { DeviceInfo } from \"../types/deviceInfo\";\n\n/**\n * @internal\n */\nexport function getCloudMetric(\n dependencies,\n subscription: PendingSubscription\n): Observable<any> {\n const { options, cloudClient, onDeviceChange, status } = dependencies;\n\n const { metric, labels, atomic } = subscription;\n\n const metricError = validate(metric, labels, options);\n if (metricError) {\n return throwError(() => metricError);\n }\n\n const metric$ = new Observable((observer) => {\n const subscriptions: Subscription[] = atomic\n ? [\n cloudClient.metrics.subscribe({\n metric: metric,\n labels: labels,\n atomic: atomic\n })\n ]\n : labels.map((label) => {\n return cloudClient.metrics.subscribe({\n metric: metric,\n labels: [label],\n atomic: atomic\n });\n });\n\n const subscriptionWithListeners = subscriptions.map((subscription) => ({\n subscription,\n listener: cloudClient.metrics.on(subscription, (...data: any) => {\n observer.next(...data);\n })\n }));\n\n return () => {\n subscriptionWithListeners.forEach(({ subscription, listener }) => {\n cloudClient.metrics.unsubscribe(subscription, listener);\n });\n };\n });\n\n return onDeviceChange().pipe(\n switchMap((device: DeviceInfo) => {\n if (!device) {\n return EMPTY;\n }\n\n return metric$.pipe(\n whileOnline({\n status$: status(),\n allowWhileOnSleepMode: false\n })\n );\n })\n );\n}\n","const self: any = this;\n\nexport const isMaybeWebWorkerContext = (): boolean => {\n return self && self?.document === undefined;\n};\n","import { isMaybeWebWorkerContext } from \"./isMaybeWebWorkerContext\";\n\nexport function isWebBluetoothSupported() {\n return (\n typeof window !== \"undefined\" &&\n window?.navigator?.bluetooth &&\n !isMaybeWebWorkerContext()\n );\n}\n","// Creates a number of 6 digits and ensures the first digit will never be 0\nexport function create6DigitPin(): number {\n return Math.floor(100000 + Math.random() * 900000);\n}\n","import { pipe } from \"rxjs\";\nimport { map, scan, filter } from \"rxjs/operators\";\n\ntype StitchChunkOptions = {\n delimiter: string;\n};\n\nexport function stitchChunks({ delimiter }: StitchChunkOptions) {\n return pipe(\n scan(\n (\n [remainder]: [string, string],\n currentBuffer: string\n ): [string, string] => {\n const nextBuffer = remainder + currentBuffer;\n\n if (!nextBuffer.includes(delimiter)) {\n return [nextBuffer, \"\"];\n }\n\n if (nextBuffer.endsWith(delimiter)) {\n return [\"\", nextBuffer];\n }\n\n const remainderStart = nextBuffer.lastIndexOf(delimiter);\n const remainderIndex = remainderStart + delimiter.length;\n const nextPacket = nextBuffer.slice(0, remainderIndex);\n const nextRemainder = nextBuffer.slice(remainderIndex);\n\n return [nextRemainder, nextPacket];\n },\n [\"\", \"\"]\n ),\n map(([, nextPacket]: string[]): string =>\n nextPacket.slice(0, -delimiter.length)\n ),\n filter((nextPacket: string): boolean => !!nextPacket.length)\n );\n}\n","/**\n * @hidden\n */\nexport type ActionOptions = {\n characteristicName: string;\n action: any;\n};\n\n/**\n * @hidden\n */\nexport type SubscribeOptions = {\n characteristicName: string;\n manageNotifications?: boolean;\n};\n\n/**\n * @hidden\n */\nexport enum BLUETOOTH_CONNECTION {\n SCANNING = \"scanning\",\n CONNECTED = \"connected\",\n CONNECTING = \"connecting\",\n DISCONNECTING = \"disconnecting\",\n DISCONNECTED = \"disconnected\"\n}\n\n/**\n * @hidden\n */\nexport enum TRANSPORT_TYPE {\n WEB = \"web\",\n REACT_NATIVE = \"reactNative\"\n}\n","import { TRANSPORT_TYPE } from \"../types\";\n\nconst encoder = new TextEncoder();\nconst decoder = new TextDecoder(\"utf-8\");\n\nexport function encode(\n transportType: TRANSPORT_TYPE,\n data: string\n): Uint8Array | number[] {\n if (transportType === TRANSPORT_TYPE.REACT_NATIVE) {\n // React Native expects a plain array of numbers and not a Uint8Array\n return [...encoder.encode(data)];\n }\n\n return encoder.encode(data);\n}\n\nexport function decode(\n transportType: TRANSPORT_TYPE,\n data: Uint8Array | number[]\n): string {\n if (transportType === TRANSPORT_TYPE.REACT_NATIVE) {\n // React Native outpouts a plain array of numbers and not a Uint8Array\n return decoder.decode(new Uint8Array(data as number[]));\n }\n\n return decoder.decode(data as Uint8Array);\n}\n","import { BLUETOOTH_CHARACTERISTICS } from \"@neurosity/ipk\";\n\nexport const ANDROID_MAX_MTU: number = 512;\nexport const REACT_NATIVE_MAX_BYTE_SIZE: number = 512; // the default is 20\n\nexport const DEFAULT_ACTION_RESPONSE_TIMEOUT: number = 1000 * 60; // 1 minute\n\n// Reverse BLUETOOTH_CHARACTERISTICS key/values for easy lookup\nexport const CHARACTERISTIC_UUIDS_TO_NAMES = Object.fromEntries(\n Object.entries(BLUETOOTH_CHARACTERISTICS).map((entries) => entries.reverse())\n);\n","import semverGte from \"semver/functions/gte\";\n\nimport { DeviceInfo } from \"../../../types/deviceInfo\";\n\nexport function osHasBluetoothSupport(selectedDevice: DeviceInfo) {\n if (!selectedDevice) {\n return false;\n }\n\n // Only the Crown supports Bluetooth\n const isCrown = Number(selectedDevice.modelVersion) >= 3;\n if (!isCrown) {\n return false;\n }\n\n const isEmulator = !!selectedDevice?.emulator;\n if (isEmulator) {\n return false;\n }\n\n return semverGte(selectedDevice.osVersion, \"16.0.0\");\n}\n","import { BLUETOOTH_PRIMARY_SERVICE_UUID_HEX } from \"@neurosity/ipk\";\nimport { BLUETOOTH_CHUNK_DELIMITER } from \"@neurosity/ipk\";\nimport { BLUETOOTH_DEVICE_NAME_PREFIXES } from \"@neurosity/ipk\";\nimport { BLUETOOTH_COMPANY_IDENTIFIER_HEX } from \"@neurosity/ipk\";\nimport { BehaviorSubject, defer, merge, of, ReplaySubject, timer } from \"rxjs\";\nimport { fromEventPattern, Observable, EMPTY, NEVER } from \"rxjs\";\nimport { switchMap, map, filter, tap } from \"rxjs/operators\";\nimport { shareReplay, distinctUntilChanged } from \"rxjs/operators\";\nimport { take, share } from \"rxjs/operators\";\n\nimport { BluetoothTransport } from \"../BluetoothTransport\";\nimport { isWebBluetoothSupported } from \"./isWebBluetoothSupported\";\nimport { create6DigitPin } from \"../utils/create6DigitPin\";\nimport { stitchChunks } from \"../utils/stitch\";\nimport { encode, decode } from \"../utils/encoding\";\nimport { ActionOptions, SubscribeOptions } from \"../types\";\nimport { TRANSPORT_TYPE, BLUETOOTH_CONNECTION } from \"../types\";\nimport { DEFAULT_ACTION_RESPONSE_TIMEOUT } from \"../constants\";\nimport { CHARACTERISTIC_UUIDS_TO_NAMES } from \"../constants\";\nimport { DeviceInfo } from \"../../../types/deviceInfo\";\nimport { osHasBluetoothSupport } from \"../utils/osHasBluetoothSupport\";\n\ntype Options = {\n autoConnect?: boolean;\n};\n\nconst defaultOptions: Options = {\n autoConnect: true\n};\n\nexport class WebBluetoothTransport implements BluetoothTransport {\n type: TRANSPORT_TYPE = TRANSPORT_TYPE.WEB;\n options: Options;\n device: BluetoothDevice;\n server: BluetoothRemoteGATTServer;\n service: BluetoothRemoteGATTService;\n characteristicsByName: {\n [name: string]: BluetoothRemoteGATTCharacteristic;\n } = {};\n\n connection$ = new BehaviorSubject<BLUETOOTH_CONNECTION>(\n BLUETOOTH_CONNECTION.DISCONNECTED\n );\n pendingActions$ = new BehaviorSubject<any[]>([]);\n logs$ = new ReplaySubject<string>(10);\n onDisconnected$: Observable<void> = this._onDisconnected().pipe(share());\n connectionStream$: Observable<BLUETOOTH_CONNECTION> = this.connection$\n .asObservable()\n .pipe(\n filter((connection) => !!connection),\n distinctUntilChanged(),\n shareReplay(1)\n );\n\n _isAutoConnectEnabled$ = new ReplaySubject<boolean>(1);\n\n constructor(options: Options = {}) {\n this.options = { ...defaultOptions, ...options };\n\n if (!isWebBluetoothSupported()) {\n const errorMessage = \"Web Bluetooth is not supported\";\n this.addLog(errorMessage);\n throw new Error(errorMessage);\n }\n\n this._isAutoConnectEnabled$.subscribe((autoConnect) => {\n this.addLog(`Auto connect: ${autoConnect ? \"enabled\" : \"disabled\"}`);\n });\n\n this._isAutoConnectEnabled$.next(this.options.autoConnect);\n\n this.connection$.asObservable().subscribe((connection) => {\n this.addLog(`connection status is ${connection}`);\n });\n\n this.onDisconnected$.subscribe(() => {\n this.connection$.next(BLUETOOTH_CONNECTION.DISCONNECTED);\n });\n }\n\n async _getPairedDevices(): Promise<BluetoothDevice[]> {\n return await navigator.bluetooth.getDevices();\n }\n\n _autoConnect(selectedDevice$: Observable<DeviceInfo>): Observable<void> {\n return this._isAutoConnectEnabled$.pipe(\n switchMap((isAutoConnectEnabled) =>\n isAutoConnectEnabled\n ? merge(\n selectedDevice$,\n this.onDisconnected$.pipe(switchMap(() => selectedDevice$))\n )\n : NEVER\n ),\n switchMap((selectedDevice) =>\n osHasBluetoothSupport(selectedDevice) ? of(selectedDevice) : EMPTY\n ),\n switchMap(async (selectedDevice) => {\n const { deviceNickname } = selectedDevice;\n\n if (this.isConnected()) {\n this.addLog(\n `Auto connect: ${deviceNickname} is already connected. Skipping auto connect.`\n );\n return;\n }\n\n const [devicesError, devices] = await this._getPairedDevices()\n .then((devices) => [null, devices])\n .catch((error) => [error, null]);\n\n if (devicesError) {\n throw new Error(\n `failed to get devices: ${devicesError?.message ?? devicesError}`\n );\n }\n\n this.addLog(\n `Auto connect: found ${devices.length} devices ${devices\n .map(({ name }) => name)\n .join(\", \")}`\n );\n\n // @important - Using `findLast` instead of `find` because somehow the browser\n // is finding multiple peripherals with the same name\n const device = devices.findLast(\n (device: BluetoothDevice) => device.name === deviceNickname\n );\n\n if (!device) {\n throw new Error(\n `couldn't find selected device in the list of paired devices.`\n );\n }\n\n this.addLog(\n `Auto connect: ${deviceNickname} was detected and previously paired`\n );\n\n return device;\n }),\n tap(() => {\n this.connection$.next(BLUETOOTH_CONNECTION.SCANNING);\n }),\n switchMap((device: BluetoothDevice) => onAdvertisementReceived(device)),\n switchMap(async (advertisement) => {\n this.addLog(`Advertisement received for ${advertisement.device.name}`);\n return await this.getServerServiceAndCharacteristics(\n advertisement.device\n );\n })\n );\n }\n\n enableAutoConnect(autoConnect: boolean): void {\n this._isAutoConnectEnabled$.next(autoConnect);\n }\n\n addLog(log: string) {\n this.logs$.next(log);\n }\n\n isConnected() {\n const connection = this.connection$.getValue();\n return connection === BLUETOOTH_CONNECTION.CONNECTED;\n }\n\n connection(): Observable<BLUETOOTH_CONNECTION> {\n return this.connectionStream$;\n }\n\n async connect(deviceNickname?: string): Promise<void> {\n try {\n // requires user gesture\n const device: BluetoothDevice = await this.requestDevice(deviceNickname);\n\n await this.getServerServiceAndCharacteristics(device);\n } catch (error) {\n return Promise.reject(error);\n }\n }\n\n async requestDevice(deviceNickname?: string): Promise<BluetoothDevice> {\n try {\n this.addLog(\"Requesting Bluetooth Device...\");\n\n const prefixes = BLUETOOTH_DEVICE_NAME_PREFIXES.map((namePrefix) => ({\n namePrefix\n }));\n\n // Ability to only show selectedDevice if provided\n const filters = deviceNickname\n ? [\n {\n name: deviceNickname\n }\n ]\n : prefixes;\n\n const device = await window.navigator.bluetooth.requestDevice({\n filters: [\n ...filters,\n {\n manufacturerData: [\n {\n companyIdentifier: BLUETOOTH_COMPANY_IDENTIFIER_HEX\n }\n ]\n }\n ],\n optionalServices: [BLUETOOTH_PRIMARY_SERVICE_UUID_HEX]\n });\n\n return device;\n } catch (error) {\n return Promise.reject(error);\n }\n }\n\n async getServerServiceAndCharacteristics(device: BluetoothDevice) {\n try {\n this.device = device;\n\n const isConnecting =\n this.connection$.getValue() === BLUETOOTH_CONNECTION.CONNECTING;\n if (!isConnecting) {\n this.connection$.next(BLUETOOTH_CONNECTION.CONNECTING);\n }\n\n this.server = await device.gatt.connect();\n\n this.addLog(`Getting service...`);\n this.service = await this.server.getPrimaryService(\n BLUETOOTH_PRIMARY_SERVICE_UUID_HEX\n );\n this.addLog(\n `Got service ${this.service.uuid}, getting characteristics...`\n );\n\n const characteristicsList = await this.service.getCharacteristics();\n\n this.addLog(`Got characteristics`);\n\n this.characteristicsByName = Object.fromEntries(\n characteristicsList.map((characteristic) => [\n CHARACTERISTIC_UUIDS_TO_NAMES[characteristic.uuid],\n characteristic\n ])\n );\n\n this.connection$.next(BLUETOOTH_CONNECTION.CONNECTED);\n } catch (error) {\n return Promise.reject(error);\n }\n }\n\n _onDisconnected(): Observable<any> {\n return this.connection$\n .asObservable()\n .pipe(\n switchMap((connection) =>\n connection === BLUETOOTH_CONNECTION.CONNECTED\n ? fromDOMEvent(this.device, \"gattserverdisconnected\")\n : NEVER\n )\n );\n }\n\n async disconnect(): Promise<void> {\n const isDeviceConnected = this?.device?.gatt?.connected;\n if (isDeviceConnected) {\n this.device.gatt.disconnect();\n }\n }\n\n /**\n *\n * Bluetooth GATT attributes, services, characteristics, etc. are invalidated\n * when a device disconnects. This means your code should always retrieve\n * (through getPrimaryService(s), getCharacteristic(s), etc.) these attributes\n * after reconnecting.\n */\n async getCharacteristicByName(\n characteristicName: string\n ): Promise<BluetoothRemoteGATTCharacteristic> {\n return this.characteristicsByName?.[characteristicName];\n }\n\n subscribeToCharacteristic({\n characteristicName,\n manageNotifications = true\n }: SubscribeOptions): Observable<any> {\n const data$ = defer(() =>\n this.getCharacteristicByName(characteristicName)\n ).pipe(\n switchMap(async (characteristic: BluetoothRemoteGATTCharacteristic) => {\n if (this.isConnected() && manageNotifications) {\n try {\n await characteristic.startNotifications();\n this.addLog(\n `Started notifications for ${characteristicName} characteristic`\n );\n } catch (error) {\n this.addLog(\n `Attemped to stop notifications for ${characteristicName} characteristic: ${\n error?.message ?? error\n }`\n );\n }\n }\n\n return characteristic;\n }),\n switchMap((characteristic: BluetoothRemoteGATTCharacteristic) => {\n return fromDOMEvent(\n characteristic,\n \"characteristicvaluechanged\",\n async () => {\n if (this.isConnected() && manageNotifications) {\n try {\n await characteristic.stopNotifications();\n this.addLog(\n `Stopped notifications for ${characteristicName} characteristic`\n );\n } catch (error) {\n this.addLog(\n `Attemped to stop notifications for ${characteristicName} characteristic: ${\n error?.message ?? error\n }`\n );\n }\n }\n }\n );\n }),\n map((event: any): string => {\n const buffer: Uint8Array = event.target.value;\n const decoded = decode(this.type, buffer);\n\n this.addLog(\n `Received chunk with buffer size of ${buffer.byteLength} and decoded size ${decoded.length} for ${characteristicName} characteristic: \\n${decoded}`\n );\n\n return decoded;\n }),\n stitchChunks({ delimiter: BLUETOOTH_CHUNK_DELIMITER }),\n map((payload: any) => {\n try {\n return JSON.parse(payload);\n } catch (error) {\n this.addLog(\n `Failed to parse JSON for ${characteristicName} characteristic. Falling back to unparsed string. ${\n error?.message ?? error\n }`\n );\n\n return payload;\n }\n })\n // when streaming at ultra-low latency, the logs will slow down rendering\n // tap((data) => {\n // this.addLog(\n // `Received data for ${characteristicName} characteristic: \\n${JSON.stringify(\n // data,\n // null,\n // 2\n // )}`\n // );\n // })\n );\n\n return this.connection$.pipe(\n switchMap((connection) =>\n connection === BLUETOOTH_CONNECTION.CONNECTED ? data$ : NEVER\n )\n );\n }\n\n async readCharacteristic(\n characteristicName: string,\n parse: boolean = false\n ): Promise<any> {\n try {\n this.addLog(`Reading characteristic: ${characteristicName}`);\n\n const characteristic: BluetoothRemoteGATTCharacteristic =\n await this.getCharacteristicByName(characteristicName);\n\n if (!characteristic) {\n this.addLog(`Did not fund ${characteristicName} characteristic`);\n\n return Promise.reject(\n `Did not find characteristic by the name: ${characteristicName}`\n );\n }\n\n const value: unknown = await characteristic.readValue();\n const uint8Array = value as Uint8Array;\n const decodedValue: string = decode(this.type, uint8Array);\n const data = parse ? JSON.parse(decodedValue) : decodedValue;\n\n this.addLog(\n `Received read data from ${characteristicName} characteristic: \\n${data}`\n );\n\n return data;\n } catch (error) {\n return Promise.reject(`Error reading characteristic: ${error.message}`);\n }\n }\n\n async writeCharacteristic(\n characteristicName: string,\n data: string\n ): Promise<void> {\n this.addLog(`Writing characteristic: ${characteristicName}`);\n\n const characteristic: BluetoothRemoteGATTCharacteristic =\n await this.getCharacteristicByName(characteristicName);\n\n if (!characteristic) {\n this.addLog(`Did not fund ${characteristicName} characteristic`);\n\n return Promise.reject(\n `Did not find characteristic by the name: ${characteristicName}`\n );\n }\n\n const encoded = encode(this.type, data);\n\n await characteristic.writeValueWithResponse(encoded as Uint8Array);\n }\n\n _addPendingAction(actionId: number): void {\n const actions = this.pendingActions$.getValue();\n this.pendingActions$.next([...actions, actionId]);\n }\n\n _removePendingAction(actionId: number): void {\n const actions = this.pendingActions$.getValue();\n this.pendingActions$.next(\n actions.filter((id: number): boolean => id !== actionId)\n );\n }\n\n async _autoToggleActionNotifications(\n selectedDevice$: Observable<DeviceInfo>\n ): Promise<void> {\n let actionsCharacteristic: BluetoothRemoteGATTCharacteristic;\n let started: boolean = false;\n\n const sideEffects$ = this.connection$.asObservable().pipe(\n switchMap((connection) =>\n connection === BLUETOOTH_CONNECTION.CONNECTED\n ? defer(() => this.getCharacteristicByName(\"actions\")).pipe(\n switchMap((characteristic: BluetoothRemoteGATTCharacteristic) => {\n actionsCharacteristic = characteristic;\n return this.pendingActions$;\n })\n )\n : NEVER\n ),\n tap(async (pendingActions: string[]) => {\n const hasPendingActions = !!pendingActions.length;\n\n if (hasPendingActions && !started) {\n started = true;\n try {\n await actionsCharacteristic.startNotifications();\n this.addLog(`Started notifications for [actions] characteristic`);\n } catch (error) {\n this.addLog(\n `Attemped to start notifications for [actions] characteristic: ${\n error?.message ?? error\n }`\n );\n }\n }\n\n if (!hasPendingActions && started) {\n started = false;\n try {\n await actionsCharacteristic.stopNotifications();\n this.addLog(`Stopped notifications for actions characteristic`);\n } catch (error) {\n this.addLog(\n `Attemped to stop notifications for [actions] characteristic: ${\n error?.message ?? error\n }`\n );\n }\n }\n })\n );\n\n selectedDevice$\n .pipe(\n switchMap((selectedDevice: DeviceInfo) =>\n !osHasBluetoothSupport(selectedDevice) ? EMPTY : sideEffects$\n )\n )\n .subscribe();\n }\n\n async dispatchAction({\n characteristicName,\n action\n }: ActionOptions): Promise<any> {\n const {\n responseRequired = false,\n responseTimeout = DEFAULT_ACTION_RESPONSE_TIMEOUT\n } = action;\n\n return new Promise(async (resolve, reject) => {\n const characteristic: BluetoothRemoteGATTCharacteristic | void =\n await this.getCharacteristicByName(characteristicName).catch(() => {\n reject(\n `Did not find characteristic by the name: ${characteristicName}`\n );\n });\n\n if (!characteristic) {\n return;\n }\n\n const actionId: number = create6DigitPin(); // use to later identify and filter response\n const payload = JSON.stringify({ actionId, ...action }); // add the response id to the action\n\n this.addLog(`Dispatched action with id ${actionId}`);\n\n if (responseRequired && responseTimeout) {\n this._addPendingAction(actionId);\n\n const timeout = timer(responseTimeout).subscribe(() => {\n this._removePendingAction(actionId);\n reject(\n `Action with id ${actionId} timed out after ${responseTimeout}ms`\n );\n });\n\n // listen for a response before writing\n this.subscribeToCharacteristic({\n characteristicName,\n manageNotifications: false\n })\n .pipe(\n filter((response: any) => response?.actionId === actionId),\n take(1)\n )\n .subscribe((response) => {\n timeout.unsubscribe();\n this._removePendingAction(actionId);\n resolve(response);\n });\n\n // register action by writing\n this.writeCharacteristic(characteristicName, payload).catch((error) => {\n this._removePendingAction(actionId);\n reject(error.message);\n });\n } else {\n this.writeCharacteristic(characteristicName, payload)\n .then(() => {\n resolve(null);\n })\n .catch((error) => {\n reject(error.message);\n });\n }\n });\n }\n}\n\nfunction fromDOMEvent(\n target: any,\n eventName: any,\n beforeRemove?: () => Promise<void>\n): Observable<any> {\n return fromEventPattern(\n (addHandler) => {\n target.addEventListener(eventName, addHandler);\n },\n async (removeHandler) => {\n if (beforeRemove) {\n await beforeRemove();\n }\n\n target.removeEventListener(eventName, removeHandler);\n }\n );\n}\n\nfunction onAdvertisementReceived(\n device: BluetoothDevice | any\n): Observable<BluetoothAdvertisingEvent> {\n return new Observable((subscriber) => {\n const abortController = new AbortController();\n const { signal } = abortController;\n\n const listener = device.addEventListener(\n \"advertisementreceived\",\n (advertisement: BluetoothAdvertisingEvent) => {\n abortController.abort();\n subscriber.next(advertisement);\n subscriber.complete();\n },\n {\n once: true\n }\n );\n\n try {\n device.watchAdvertisements({ signal });\n } catch (error) {\n subscriber.error(error);\n }\n\n return () => {\n abortController.abort();\n device.removeEventListener(\"advertisementreceived\", listener);\n };\n });\n}\n","import { BLUETOOTH_PRIMARY_SERVICE_UUID_STRING } from \"@neurosity/ipk\";\nimport { BLUETOOTH_CHUNK_DELIMITER } from \"@neurosity/ipk\";\nimport { BLUETOOTH_DEVICE_NAME_PREFIXES } from \"@neurosity/ipk\";\nimport { BehaviorSubject, defer, merge, of, ReplaySubject, timer } from \"rxjs\";\nimport { fromEventPattern, Observable, NEVER, EMPTY } from \"rxjs\";\nimport { switchMap, map, filter, takeUntil, tap } from \"rxjs/operators\";\nimport { shareReplay, distinctUntilChanged, finalize } from \"rxjs/operators\";\nimport { take, share, scan, distinct } from \"rxjs/operators\";\n\nimport { BluetoothTransport } from \"../BluetoothTransport\";\nimport { create6DigitPin } from \"../utils/create6DigitPin\";\nimport { stitchChunks } from \"../utils/stitch\";\nimport { encode, decode } from \"../utils/encoding\";\nimport { ActionOptions, SubscribeOptions } from \"../types\";\nimport { TRANSPORT_TYPE, BLUETOOTH_CONNECTION } from \"../types\";\nimport { BleManager } from \"./types/BleManagerTypes\";\nimport { Peripheral, PeripheralInfo } from \"./types/BleManagerTypes\";\nimport { NativeEventEmitter } from \"./types/ReactNativeTypes\";\nimport { PlatformOSType } from \"./types/ReactNativeTypes\";\nimport { DEFAULT_ACTION_RESPONSE_TIMEOUT } from \"../constants\";\nimport { CHARACTERISTIC_UUIDS_TO_NAMES } from \"../constants\";\nimport { ANDROID_MAX_MTU } from \"../constants\";\nimport { REACT_NATIVE_MAX_BYTE_SIZE } from \"../constants\";\nimport { DeviceInfo } from \"../../../types/deviceInfo\";\nimport { osHasBluetoothSupport } from \"../utils/osHasBluetoothSupport\";\n\ntype Characteristic = {\n characteristicUUID: string;\n serviceUUID: string;\n peripheralId: string;\n};\n\ntype CharacteristicsByName = {\n [name: string]: Characteristic;\n};\n\ntype Options = {\n BleManager: BleManager;\n bleManagerEmitter: NativeEventEmitter;\n platform: PlatformOSType;\n autoConnect?: boolean;\n};\n\ntype BleManagerEvents = {\n stopScan$: Observable<void>;\n discoverPeripheral$: Observable<Peripheral>;\n connectPeripheral$: Observable<void>;\n disconnectPeripheral$: Observable<void>;\n didUpdateValueForCharacteristic$: Observable<any>;\n didUpdateState$: Observable<any>;\n};\n\nconst defaultOptions: Pick<Options, \"autoConnect\"> = {\n autoConnect: true\n};\n\nexport class ReactNativeTransport implements BluetoothTransport {\n type: TRANSPORT_TYPE = TRANSPORT_TYPE.REACT_NATIVE;\n options: Options;\n BleManager: BleManager;\n bleManagerEmitter: NativeEventEmitter;\n platform: PlatformOSType;\n bleEvents: BleManagerEvents;\n\n device: Peripheral;\n characteristicsByName: CharacteristicsByName = {};\n\n connection$ = new BehaviorSubject<BLUETOOTH_CONNECTION>(\n BLUETOOTH_CONNECTION.DISCONNECTED\n );\n pendingActions$ = new BehaviorSubject<any[]>([]);\n logs$ = new ReplaySubject<string>(10);\n onDisconnected$: Observable<void>;\n connectionStream$: Observable<BLUETOOTH_CONNECTION> = this.connection$\n .asObservable()\n .pipe(\n filter((connection) => !!connection),\n distinctUntilChanged(),\n shareReplay(1)\n );\n\n _isAutoConnectEnabled$ = new ReplaySubject<boolean>(1);\n\n constructor(options: Options) {\n if (!options) {\n const errorMessage = \"React Native transport: missing options.\";\n this.addLog(errorMessage);\n throw new Error(errorMessage);\n }\n\n this.options = { ...defaultOptions, ...options };\n\n const { BleManager, bleManagerEmitter, platform, autoConnect } =\n this.options;\n\n if (!BleManager) {\n const errorMessage = \"React Native option: BleManager not provided.\";\n this.addLog(errorMessage);\n throw new Error(errorMessage);\n }\n\n if (!bleManagerEmitter) {\n const errorMessage =\n \"React Native option: bleManagerEmitter not provided.\";\n this.addLog(errorMessage);\n throw new Error(errorMessage);\n }\n\n if (!platform) {\n const errorMessage = \"React Native option: platform not provided.\";\n this.addLog(errorMessage);\n throw new Error(errorMessage);\n }\n\n this.BleManager = BleManager;\n this.bleManagerEmitter = bleManagerEmitter;\n this.platform = platform;\n\n this._isAutoConnectEnabled$.next(autoConnect);\n\n this._isAutoConnectEnabled$.subscribe((autoConnect) => {\n this.addLog(`Auto connect: ${autoConnect ? \"enabled\" : \"disabled\"}`);\n });\n\n // We create a single listener per event type to\n // avoid missing events when multiple listeners are attached.\n this.bleEvents = {\n stopScan$: this._fromEvent(\"BleManagerStopScan\"),\n discoverPeripheral$: this._fromEvent(\"BleManagerDiscoverPeripheral\"),\n connectPeripheral$: this._fromEvent(\"BleManagerConnectPeripheral\"),\n disconnectPeripheral$: this._fromEvent(\"BleManagerDisconnectPeripheral\"),\n didUpdateValueForCharacteristic$: this._fromEvent(\n \"BleManagerDidUpdateValueForCharacteristic\"\n ),\n didUpdateState$: this._fromEvent(\"BleManagerDidUpdateState\")\n };\n\n this.onDisconnected$ = this.bleEvents.disconnectPeripheral$.pipe(share());\n\n // Initializes the module. This can only be called once.\n this.BleManager.start({ showAlert: false })\n .then(() => {\n this.addLog(`BleManger started`);\n })\n .catch((error) => {\n this.addLog(`BleManger failed to start. ${error?.message ?? error}`);\n });\n\n this.connection$.asObservable().subscribe((connection) => {\n this.addLog(`connection status is ${connection}`);\n });\n\n this.onDisconnected$.subscribe(() => {\n this.connection$.next(BLUETOOTH_CONNECTION.DISCONNECTED);\n });\n }\n\n addLog(log: string) {\n this.logs$.next(log);\n }\n\n isConnected() {\n const connection = this.connection$.getValue();\n return connection === BLUETOOTH_CONNECTION.CONNECTED;\n }\n\n _autoConnect(selectedDevice$: Observable<DeviceInfo>): Observable<void> {\n const selectedDeviceAfterDisconnect$ = this.onDisconnected$.pipe(\n switchMap(() => selectedDevice$)\n );\n\n return this._isAutoConnectEnabled$.pipe(\n switchMap((isAutoConnectEnabled) =>\n isAutoConnectEnabled\n ? merge(selectedDevice$, selectedDeviceAfterDisconnect$)\n : NEVER\n ),\n switchMap((selectedDevice) =>\n !osHasBluetoothSupport(selectedDevice)\n ? NEVER\n : this.scan().pipe(\n switchMap((peripherals: Peripheral[]) => {\n const peripheralMatch = peripherals.find(\n (peripheral) =>\n peripheral.name === selectedDevice?.deviceNickname\n );\n\n return peripheralMatch ? of(peripheralMatch) : NEVER;\n }),\n distinct((peripheral: Peripheral) => peripheral.id),\n take(1)\n )\n ),\n switchMap(async (peripheral) => {\n return await this.connect(peripheral);\n })\n );\n }\n\n enableAutoConnect(autoConnect: boolean): void {\n this._isAutoConnectEnabled$.next(autoConnect);\n }\n\n connection(): Observable<BLUETOOTH_CONNECTION> {\n return this.connectionStream$;\n }\n\n _fromEvent(eventName: string): Observable<any> {\n return fromEventPattern(\n (addHandler) => {\n this.bleManagerEmitter.addListener(eventName, addHandler);\n },\n () => {\n this.bleManagerEmitter.removeAllListeners(eventName);\n }\n ).pipe(\n // @important: we need to share the subscription\n // to avoid missing events\n share()\n );\n }\n\n scan(options?: {\n seconds?: number;\n once?: boolean;\n skipConnectionUpdate?: boolean;\n }): Observable<Peripheral[]> {\n const RESCAN_INTERVAL = 10_000; // 10 seconds\n const seconds = options?.seconds ?? RESCAN_INTERVAL / 1000;\n const once = options?.once ?? false;\n // If we are already connected to a peripheral and start scanning,\n // be default, it will set the connection status to SCANNING and not\n // update it back if no device is connected to\n const skipConnectionUpdate = options?.skipConnectionUpdate ?? false;\n const serviceUUIDs = [BLUETOOTH_PRIMARY_SERVICE_UUID_STRING];\n const allowDuplicates = true;\n const scanOptions = {};\n\n const scanOnce$ = new Observable((subscriber) => {\n try {\n this.BleManager.scan(\n serviceUUIDs,\n seconds,\n allowDuplicates,\n scanOptions\n ).then(() => {\n this.addLog(`BleManger scanning ${once ? \"once\" : \"indefintely\"}`);\n subscriber.next();\n });\n } catch (error) {\n this.addLog(\n `BleManger scanning ${once ? \"once\" : \"indefintely\"} failed. ${\n error?.message ?? error\n }`\n );\n subscriber.error(error);\n }\n\n return () => {\n this.BleManager.stopScan();\n };\n });\n\n const scan$ = once\n ? scanOnce$\n : timer(0, RESCAN_INTERVAL).pipe(switchMap(() => scanOnce$));\n\n const peripherals$ = scan$.pipe(\n tap(() => {\n if (!skipConnectionUpdate) {\n this.connection$.next(BLUETOOTH_CONNECTION.SCANNING);\n }\n }),\n takeUntil(this.onDisconnected$),\n switchMap(() => this.bleEvents.discoverPeripheral$),\n // Filter out devices that are not Neurosity devices\n filter((peripheral: Peripheral) => {\n const peripheralName: string =\n peripheral?.advertising?.localName ?? peripheral.name ?? \"\";\n\n if (!peripheralName) {\n return false;\n }\n\n const startsWithPrefix =\n BLUETOOTH_DEVICE_NAME_PREFIXES.findIndex((prefix) =>\n peripheralName.startsWith(prefix)\n ) !== -1;\n\n return startsWithPrefix;\n }),\n scan((acc, peripheral): { [name: string]: Peripheral } => {\n // normalized peripheral name for backwards compatibility\n // Neurosity OS v15 doesn't have peripheral.name as deviceNickname\n // it only has peripheral.advertising.localName as deviceNickname\n // and OS v16 has both as deviceNickname\n const peripheralName: string =\n peripheral?.advertising?.localName ?? peripheral.name ?? \"\";\n\n const manufactureDataString = decode(\n this.type,\n peripheral?.advertising?.manufacturerData?.bytes ?? []\n )?.slice?.(2); // First 2 bytes are reserved for the Neurosity company code\n\n return {\n ...acc,\n [peripheral.id]: {\n ...peripheral,\n name: peripheralName,\n manufactureDataString\n }\n };\n }, {}),\n distinctUntilChanged((a, b) => JSON.stringify(a) === JSON.stringify(b)),\n map((peripheralMap): Peripheral[] => Object.values(peripheralMap)),\n share()\n );\n\n return peripherals$;\n }\n\n async connect(peripheral: Peripheral): Promise<void> {\n return new Promise(async (resolve, reject) => {\n try {\n if (!peripheral) {\n this.addLog(\"Peripheral not found\");\n return;\n }\n\n this.connection$.next(BLUETOOTH_CONNECTION.CONNECTING);\n\n await this.BleManager.connect(peripheral.id);\n\n this.addLog(`Getting service...`);\n\n const peripheralInfo: PeripheralInfo =\n await this.BleManager.retrieveServices(peripheral.id, [\n BLUETOOTH_PRIMARY_SERVICE_UUID_STRING\n ]);\n\n if (!peripheralInfo) {\n this.addLog(\"Could not retreive services\");\n reject(new Error(`Could not retreive services`));\n return;\n }\n\n this.addLog(\n `Got service ${BLUETOOTH_PRIMARY_SERVICE_UUID_STRING}, getting characteristics...`\n );\n\n this.device = peripheral;\n\n this.characteristicsByName = Object.fromEntries(\n peripheralInfo.characteristics.map((characteristic: any) => [\n CHARACTERISTIC_UUIDS_TO_NAMES[\n characteristic.characteristic.toLowerCase() // react native uses uppercase\n ],\n {\n characteristicUUID: characteristic.characteristic,\n serviceUUID: characteristic.service,\n peripheralId: peripheral.id\n }\n ])\n );\n\n this.addLog(`Got characteristics.`);\n\n if (this.platform === \"android\") {\n await this.BleManager.requestMTU(peripheral.id, ANDROID_MAX_MTU)\n .then((updatedMTU) => {\n this.addLog(\n `Successfully updated Android MTU to ${updatedMTU} bytes. Requested MTU: ${ANDROID_MAX_MTU} bytes.`\n );\n })\n .catch((error) => {\n this.addLog(\n `Failed to set Android MTU of ${ANDROID_MAX_MTU} bytes. Error: ${error}`\n );\n });\n }\n\n this.addLog(`Successfully connected to peripheral ${peripheral.id}`);\n\n this.connection$.next(BLUETOOTH_CONNECTION.CONNECTED);\n\n resolve();\n } catch (error) {\n reject(error);\n }\n });\n }\n\n async disconnect(): Promise<void> {\n try {\n if (this.isConnected() && this?.device?.id) {\n await this.BleManager.disconnect(this.device.id);\n }\n } catch (error) {\n return Promise.reject(error);\n }\n }\n\n getCharacteristicByName(characteristicName: string): Characteristic {\n if (!(characteristicName in this.characteristicsByName)) {\n throw new Error(\n `Characteristic by name ${characteristicName} is not found`\n );\n }\n\n return this.characteristicsByName?.[characteristicName];\n }\n\n subscribeToCharacteristic({\n characteristicName,\n manageNotifications = true\n }: SubscribeOptions): Observable<any> {\n const getData = ({\n peripheralId,\n serviceUUID,\n characteristicUUID\n }: Characteristic) =>\n defer(async () => {\n if (manageNotifications) {\n try {\n await this.BleManager.startNotification(\n peripheralId,\n serviceUUID,\n characteristicUUID\n );\n\n this.addLog(\n `Started notifications for ${characteristicName} characteristic`\n );\n } catch (error) {\n this.addLog(\n `Attemped to stop notifications for ${characteristicName} characteristic: ${\n error?.message ?? error\n }`\n );\n }\n }\n }).pipe(\n switchMap(() => this.bleEvents.didUpdateValueForCharacteristic$),\n finalize(async () => {\n if (manageNotifications) {\n try {\n await this.BleManager.stopNotification(\n peripheralId,\n serviceUUID,\n characteristicUUID\n );\n this.addLog(\n `Stopped notifications for ${characteristicName} characteristic`\n );\n } catch (error) {\n this.addLog(\n `Attemped to stop notifications for ${characteristicName} characteristic: ${\n error?.message ?? error\n }`\n );\n }\n }\n }),\n filter(({ characteristic }) => characteristic === characteristicUUID),\n map(({ value }: { value: number[]; characteristic: string }): string =>\n decode(this.type, value)\n ),\n stitchChunks({ delimiter: BLUETOOTH_CHUNK_DELIMITER }),\n map((payload: any) => {\n try {\n return JSON.parse(payload);\n } catch (error) {\n this.addLog(\n `Failed to parse JSON for ${characteristicName} characteristic. Falling back to unparsed string. ${\n error?.message ?? error\n }`\n );\n\n return payload;\n }\n })\n );\n\n return this.connection$.pipe(\n switchMap((connection) =>\n connection === BLUETOOTH_CONNECTION.CONNECTED\n ? getData(this.getCharacteristicByName(characteristicName))\n : NEVER\n )\n );\n }\n\n async readCharacteristic(\n characteristicName: string,\n parse: boolean = false\n ): Promise<any> {\n this.addLog(`Reading characteristic: ${characteristicName}`);\n\n const { peripheralId, serviceUUID, characteristicUUID } =\n this.getCharacteristicByName(characteristicName);\n\n if (!characteristicUUID) {\n return Promise.reject(\n new Error(`Did not find characteristic matching ${characteristicName}`)\n );\n }\n\n try {\n const value = await this.BleManager.read(\n peripheralId,\n serviceUUID,\n characteristicUUID\n );\n\n const decodedValue = decode(this.type, value);\n const data = parse ? JSON.parse(decodedValue) : decodedValue;\n\n this.addLog(\n `Received read data from ${characteristicName} characteristic: \\n${data}`\n );\n\n return data;\n } catch (error) {\n return Promise.reject(\n new Error(\n `readCharacteristic ${characteristicName} error. ${\n error?.message ?? error\n }`\n )\n );\n }\n }\n\n async writeCharacteristic(\n characteristicName: string,\n data: string\n ): Promise<void> {\n this.addLog(`Writing characteristic: ${characteristicName}`);\n\n const { peripheralId, serviceUUID, characteristicUUID } =\n this.getCharacteristicByName(characteristicName);\n\n if (!characteristicUUID) {\n return Promise.reject(\n new Error(`Did not find characteristic matching ${characteristicName}`)\n );\n }\n\n const encoded = encode(this.type, data);\n\n await this.BleManager.write(\n peripheralId,\n serviceUUID,\n characteristicUUID,\n encoded,\n REACT_NATIVE_MAX_BYTE_SIZE\n );\n }\n\n _addPendingAction(actionId: number): void {\n const actions = this.pendingActions$.getValue();\n this.pendingActions$.next([...actions, actionId]);\n }\n\n _removePendingAction(actionId: number): void {\n const actions = this.pendingActions$.getValue();\n this.pendingActions$.next(\n actions.filter((id: number): boolean => id !== actionId)\n );\n }\n\n async _autoToggleActionNotifications(\n selectedDevice$: Observable<DeviceInfo>\n ): Promise<void> {\n let started: boolean = false;\n\n const sideEffects$ = this.connection$.asObservable().pipe(\n switchMap((connection) =>\n connection === BLUETOOTH_CONNECTION.CONNECTED\n ? this.pendingActions$\n : NEVER\n ),\n tap(async (pendingActions: string[]) => {\n const { peripheralId, serviceUUID, characteristicUUID } =\n this.getCharacteristicByName(\"actions\");\n\n const hasPendingActions = !!pendingActions.length;\n\n if (hasPendingActions && !started) {\n started = true;\n try {\n await this.BleManager.startNotification(\n peripheralId,\n serviceUUID,\n characteristicUUID\n );\n this.addLog(`Started notifications for [actions] characteristic`);\n } catch (error) {\n this.addLog(\n `Attemped to start notifications for [actions] characteristic: ${\n error?.message ?? error\n }`\n );\n }\n }\n\n if (!hasPendingActions && started) {\n started = false;\n try {\n await this.BleManager.stopNotification(\n peripheralId,\n serviceUUID,\n characteristicUUID\n );\n this.addLog(`Stopped notifications for actions characteristic`);\n } catch (error) {\n this.addLog(\n `Attemped to stop notifications for [actions] characteristic: ${\n error?.message ?? error\n }`\n );\n }\n }\n })\n );\n\n selectedDevice$\n .pipe(\n switchMap((selectedDevice: DeviceInfo) =>\n !osHasBluetoothSupport(selectedDevice) ? EMPTY : sideEffects$\n )\n )\n .subscribe();\n }\n\n async dispatchAction({\n characteristicName,\n action\n }: ActionOptions): Promise<any> {\n const {\n responseRequired = false,\n responseTimeout = DEFAULT_ACTION_RESPONSE_TIMEOUT\n } = action;\n\n return new Promise(async (resolve, reject) => {\n const actionId: number = create6DigitPin(); // use to later identify and filter response\n const payload = JSON.stringify({ actionId, ...action }); // add the response id to the action\n\n this.addLog(`Dispatched action with id ${actionId}`);\n\n if (responseRequired && responseTimeout) {\n this._addPendingAction(actionId);\n\n const timeout = timer(responseTimeout).subscribe(() => {\n this._removePendingAction(actionId);\n reject(\n new Error(\n `Action with id ${actionId} timed out after ${responseTimeout}ms`\n )\n );\n });\n\n // listen for a response before writing\n this.subscribeToCharacteristic({\n characteristicName,\n manageNotifications: false\n })\n .pipe(\n filter((response: any) => response?.actionId === actionId),\n take(1)\n )\n .subscribe((response) => {\n timeout.unsubscribe();\n this._removePendingAction(actionId);\n resolve(response);\n });\n\n // register action by writing\n this.writeCharacteristic(characteristicName, payload).catch((error) => {\n this._removePendingAction(actionId);\n reject(error);\n });\n } else {\n this.writeCharacteristic(characteristicName, payload)\n .then(() => {\n resolve(null);\n })\n .catch((error) => {\n reject(error);\n });\n }\n });\n }\n}\n","import { pipe } from \"rxjs\";\nimport { bufferCount, scan, filter, map } from \"rxjs/operators\";\n\nimport { Sample } from \"../types/sample\";\n\nconst defaultDataProp = \"data\";\nconst defaultSamplingRate = 256;\n\nconst isObject = (object) =>\n object instanceof Object && object === Object(object);\nconst isFunction = (object) => typeof object === \"function\";\n\nconst patch = (sample: Sample) => (info: any) => ({\n ...sample,\n info: {\n ...(sample?.info ?? {}),\n ...(info || {})\n }\n});\n\n/**\n * Annotates stream with user-defined metadata\n * @method addInfo\n * @example eeg$.pipe(addinfo({ samplingRate: 256, channelNames: [\"Af7\", \"Fp1\", \"Fp2\", \"Af8\"] })\n * @param {Object} info Info to be added to the EEG stream. Relevant info may include: `samplingRate` and `channelNames`\n * @returns {Observable<Sample|Epoch|PSD>}\n */\nexport const addInfo = (infoValue: any) =>\n pipe(\n map((sample: any) => {\n if (\n !isObject(sample) ||\n (!isObject(infoValue) && !isFunction(infoValue))\n ) {\n return sample;\n }\n const info: any = isFunction(infoValue) ? infoValue(sample) : infoValue;\n return patch(sample)(info);\n })\n );\n\n/**\n * Get a 2D data array organized by channel from an array of Samples. Credit to Ken from Seattle's elegant transposition\n * http://www.codesuck.com/2012/02/transpose-javascript-array-in-one-line.html\n * @method groupByChannel\n * @param {Array<Sample>} samplesBuffer Array of Samples to be grouped\n * @param {string} [dataProp] Name of the key associated with EEG data\n * @returns {Array<Array<number>>}\n */\n\nconst groupByChannel = (samplesBuffer, dataProp = defaultDataProp) =>\n samplesBuffer[0][dataProp].map((_, channelIndex) =>\n samplesBuffer.map((sample) => sample[dataProp][channelIndex])\n );\n\n/**\n * Takes an array or RxJS buffer of EEG Samples and returns an Epoch.\n * @method bufferToEpoch\n * @example eeg$.pipe(bufferTime(1000), bufferToEpoch({ samplingRate: 256 }))\n *\n * @param {Object} options - Data structure options\n * @param {number} [options.samplingRate] Sampling rate\n * @param {string} [options.dataProp='data'] Name of the key associated with eeg data\n *\n * @returns {Observable<Epoch>}\n */\nexport const bufferToEpoch = ({\n samplingRate = defaultSamplingRate,\n dataProp = defaultDataProp\n} = {}) =>\n pipe(\n map((samplesArray) => ({\n [dataProp]: groupByChannel(samplesArray, dataProp),\n info: {\n ...(samplesArray[0] && samplesArray[0].info\n ? samplesArray[0].info\n : {}),\n startTime: samplesArray[0].timestamp,\n samplingRate:\n samplesArray[0].info && samplesArray[0].info.samplingRate\n ? samplesArray[0].info.samplingRate\n : samplingRate\n }\n }))\n );\n\n/**\n * Converts a stream of individual Samples of EEG data into a stream of Epochs of a given duration emitted at specified interval. This operator functions similarly to a circular buffer internally and allows overlapping Epochs of data to be emitted (e.g. emitting the last one second of data every 100ms).\n * @method epoch\n * @example eeg$.pipe(epoch({ duration: 1024, interval: 100, samplingRate: 256 }))\n * @param {Object} options - Epoching options\n * @param {number} [options.duration=256] Number of samples to include in each epoch\n * @param {number} [options.interval=100] Time (ms) between emitted Epochs\n * @param {number} [options.samplingRate=256] Sampling rate\n * @param {string} [options.dataProp='data'] Name of the key associated with eeg data\n * @returns {Observable} Epoch\n */\nexport const epoch = ({\n duration,\n interval,\n samplingRate,\n dataProp = defaultDataProp\n}) =>\n pipe(\n bufferCount(interval),\n scan((acc, val) =>\n acc.concat(val).slice(acc.length < duration ? 0 : -duration)\n ),\n filter((samplesArray) => samplesArray.length === duration),\n bufferToEpoch({ samplingRate, dataProp })\n );\n","import { pipe, from, Observable, UnaryFunction } from \"rxjs\";\nimport { mergeMap, map } from \"rxjs/operators\";\n\nimport { epoch, addInfo } from \"../../../utils/pipes\";\nimport { Sample, CSVSample } from \"../../../types/sample\";\nimport { Epoch } from \"../../../types/epoch\";\nimport { DeviceInfo } from \"../../../types/deviceInfo\";\n\nconst EPOCH_BUFFER_SIZE = 16;\nconst SAMPLING_RATE_FALLBACK = 256; // Crown's sampling rate\n\n/**\n * @hidden\n */\nexport function csvBufferToEpoch(\n deviceInfo: DeviceInfo\n): UnaryFunction<Observable<Epoch>, any> {\n if (!deviceInfo?.samplingRate) {\n console.warn(\n `Didn't receive a sampling rate, defaulting to ${SAMPLING_RATE_FALLBACK}`\n );\n }\n\n return pipe(\n csvBufferToSamples(),\n epoch({\n duration: EPOCH_BUFFER_SIZE,\n interval: EPOCH_BUFFER_SIZE,\n samplingRate: deviceInfo?.samplingRate ?? SAMPLING_RATE_FALLBACK\n }),\n addInfo({\n channelNames: deviceInfo.channelNames,\n samplingRate: deviceInfo.samplingRate\n })\n );\n}\n\n/**\n * @hidden\n */\nexport function csvBufferToSamples(): UnaryFunction<any, any> {\n return pipe(\n mergeMap((samples: CSVSample[]): Observable<CSVSample> => from(samples)),\n map(\n ([timestamp, marker, ...data]: CSVSample): Sample => ({\n timestamp,\n data\n })\n )\n );\n}\n","import { defer, Observable, firstValueFrom, timer } from \"rxjs\";\nimport { ReplaySubject, EMPTY } from \"rxjs\";\nimport { switchMap, share, tap } from \"rxjs/operators\";\nimport { distinctUntilChanged } from \"rxjs/operators\";\n\nimport { WebBluetoothTransport } from \"./web/WebBluetoothTransport\";\nimport { ReactNativeTransport } from \"./react-native/ReactNativeTransport\";\nimport { csvBufferToEpoch } from \"./utils/csvBufferToEpoch\";\nimport { DeviceInfo } from \"../../types/deviceInfo\";\nimport { Action } from \"../../types/actions\";\nimport { Epoch } from \"../../types/epoch\";\nimport { BLUETOOTH_CONNECTION } from \"./types\";\nimport { DeviceNicknameOrPeripheral } from \"./BluetoothTransport\";\nimport { Peripheral } from \"./react-native/types/BleManagerTypes\";\nimport { osHasBluetoothSupport } from \"./utils/osHasBluetoothSupport\";\n\nexport type BluetoothTransport = WebBluetoothTransport | ReactNativeTransport;\n\ntype IsAuthenticated = boolean;\ntype ExpiresIn = number;\ntype IsAuthenticatedResponse = [IsAuthenticated, ExpiresIn];\n\ntype CreateBluetoothToken = () => Promise<string>;\n\ntype Options = {\n transport: BluetoothTransport;\n selectedDevice$: Observable<DeviceInfo>;\n createBluetoothToken: CreateBluetoothToken;\n};\n\nexport class BluetoothClient {\n transport: BluetoothTransport;\n deviceInfo: DeviceInfo;\n selectedDevice$ = new ReplaySubject<DeviceInfo>(1);\n isAuthenticated$ = new ReplaySubject<IsAuthenticated>(1);\n\n _focus$: Observable<any>;\n _calm$: Observable<any>;\n _accelerometer$: Observable<any>;\n _brainwavesRaw$: Observable<any>;\n _brainwavesRawUnfiltered$: Observable<any>;\n _brainwavesPSD$: Observable<any>;\n _brainwavesPowerByBand$: Observable<any>;\n _signalQuality$: Observable<any>;\n _status$: Observable<any>;\n _settings$: Observable<any>;\n _wifiNearbyNetworks$: Observable<any>;\n _wifiConnections$: Observable<any>;\n\n constructor(options: Options) {\n const { transport, selectedDevice$, createBluetoothToken } = options ?? {};\n\n if (!transport) {\n throw new Error(`No bluetooth transport provided.`);\n }\n\n this.transport = transport;\n\n // Pass events to the internal selectedDevice$ if selectedDevice$ is passed via options\n if (selectedDevice$) {\n selectedDevice$.subscribe(this.selectedDevice$);\n }\n\n // Auto Connect\n this.transport._autoConnect(this.selectedDevice$).subscribe({\n error: (error: Error) => {\n this.transport.addLog(\n `Auto connect: error -> ${error?.message ?? error}`\n );\n }\n });\n\n // Auto authentication\n if (typeof createBluetoothToken === \"function\") {\n this.transport.addLog(\"Auto authentication enabled\");\n this._autoAuthenticate(createBluetoothToken).subscribe();\n } else {\n this.transport.addLog(\"Auto authentication not enabled\");\n }\n\n // Auto manage action notifications\n this.transport._autoToggleActionNotifications(this.selectedDevice$);\n\n // Multicast metrics (share)\n this._focus$ = this._subscribeWhileAuthenticated(\"focus\");\n this._calm$ = this._subscribeWhileAuthenticated(\"calm\");\n this._accelerometer$ = this._subscribeWhileAuthenticated(\"accelerometer\");\n this._brainwavesRaw$ = this._subscribeWhileAuthenticated(\"raw\");\n this._brainwavesRawUnfiltered$ =\n this._subscribeWhileAuthenticated(\"rawUnfiltered\");\n this._brainwavesPSD$ = this._subscribeWhileAuthenticated(\"psd\");\n this._brainwavesPowerByBand$ =\n this._subscribeWhileAuthenticated(\"powerByBand\");\n this._signalQuality$ = this._subscribeWhileAuthenticated(\"signalQuality\");\n this._status$ = this._subscribeWhileAuthenticated(\"status\");\n this._settings$ = this._subscribeWhileAuthenticated(\"settings\");\n this._wifiNearbyNetworks$ =\n this._subscribeWhileAuthenticated(\"wifiNearbyNetworks\");\n this._wifiConnections$ =\n this._subscribeWhileAuthenticated(\"wifiConnections\");\n }\n\n _autoAuthenticate(createBluetoothToken: CreateBluetoothToken) {\n const REAUTHENTICATE_INTERVAL = 3600000; // 1 hour\n const reauthenticateInterval$ = timer(0, REAUTHENTICATE_INTERVAL).pipe(\n tap(() => {\n this.transport.addLog(`Auto authentication in progress...`);\n })\n );\n\n return this.selectedDevice$.pipe(\n switchMap((selectedDevice) =>\n !osHasBluetoothSupport(selectedDevice)\n ? EMPTY\n : this.connection().pipe(\n switchMap((connection) =>\n connection === BLUETOOTH_CONNECTION.CONNECTED\n ? reauthenticateInterval$\n : EMPTY\n ),\n switchMap(async () => await this.isAuthenticated()),\n tap(async ([isAuthenticated]) => {\n if (!isAuthenticated) {\n const token = await createBluetoothToken();\n await this.authenticate(token);\n } else {\n this.transport.addLog(`Already authenticated`);\n }\n })\n )\n )\n );\n }\n\n enableAutoConnect(autoConnect: boolean): void {\n this.transport.enableAutoConnect(autoConnect);\n }\n\n async _hasBluetoothSupport(): Promise<boolean> {\n const selectedDevice = await firstValueFrom(this.selectedDevice$);\n return osHasBluetoothSupport(selectedDevice);\n }\n\n async authenticate(token: string): Promise<IsAuthenticatedResponse> {\n const hasBluetoothSupport = await this._hasBluetoothSupport();\n if (!hasBluetoothSupport) {\n const errorMessage = `authenticate method: The OS version does not support Bluetooth.`;\n this.transport.addLog(errorMessage);\n return Promise.reject(errorMessage);\n }\n\n await this.transport.writeCharacteristic(\"auth\", token);\n\n const isAuthenticatedResponse = await this.isAuthenticated();\n\n const [isAuthenticated] = isAuthenticatedResponse;\n\n this.transport.addLog(\n `Authentication ${isAuthenticated ? \"succeeded\" : \"failed\"}`\n );\n\n this.isAuthenticated$.next(isAuthenticated);\n\n return isAuthenticatedResponse;\n }\n\n async isAuthenticated(): Promise<IsAuthenticatedResponse> {\n const [isAuthenticated, expiresIn] =\n await this.transport.readCharacteristic(\"auth\", true);\n\n this.isAuthenticated$.next(isAuthenticated);\n\n return [isAuthenticated, expiresIn];\n }\n\n // Method for React Native only\n scan(options?) {\n if (this.transport instanceof ReactNativeTransport) {\n return this.transport.scan(options);\n }\n\n if (this.transport instanceof WebBluetoothTransport) {\n throw new Error(\n `scan method is compatibly with the React Native transport only`\n );\n }\n\n throw new Error(`unknown transport`);\n }\n\n // Argument for React Native only\n connect(deviceNicknameORPeripheral?: DeviceNicknameOrPeripheral) {\n if (this.transport instanceof ReactNativeTransport) {\n return this.transport.connect(deviceNicknameORPeripheral as Peripheral);\n }\n\n if (this.transport instanceof WebBluetoothTransport) {\n return deviceNicknameORPeripheral\n ? this.transport.connect(deviceNicknameORPeripheral as string)\n : this.transport.connect();\n }\n }\n\n disconnect() {\n return this.transport.disconnect();\n }\n\n connection() {\n return this.transport.connection();\n }\n\n logs() {\n return this.transport.logs$.asObservable();\n }\n\n async getDeviceId(): Promise<string> {\n // This is a public characteristic and does not require authentication\n return this.transport.readCharacteristic(\"deviceId\");\n }\n\n async _withAuthentication<T>(getter: () => Promise<T>): Promise<T> {\n // First check if the OS supports Bluetooth before checking if the device is authenticated\n const hasBluetoothSupport = await this._hasBluetoothSupport();\n if (!hasBluetoothSupport) {\n const errorMessage = `The OS version does not support Bluetooth.`;\n this.transport.addLog(errorMessage);\n return Promise.reject(errorMessage);\n }\n\n const isAuthenticated = await firstValueFrom(this.isAuthenticated$);\n if (!isAuthenticated) {\n const errorMessage = `Authentication required.`;\n this.transport.addLog(errorMessage);\n return Promise.reject(errorMessage);\n }\n\n return await getter();\n }\n\n _subscribeWhileAuthenticated(characteristicName: string): Observable<any> {\n return this.selectedDevice$.pipe(\n switchMap((selectedDevice) =>\n !osHasBluetoothSupport(selectedDevice)\n ? EMPTY\n : this.isAuthenticated$.pipe(\n distinctUntilChanged(),\n switchMap((isAuthenticated) =>\n isAuthenticated\n ? this.transport.subscribeToCharacteristic({\n characteristicName\n })\n : EMPTY\n )\n )\n ),\n share()\n );\n }\n\n focus() {\n return this._focus$;\n }\n\n calm() {\n return this._calm$;\n }\n\n accelerometer() {\n return this._accelerometer$;\n }\n\n brainwaves(label: string): Observable<Epoch | any> {\n switch (label) {\n default:\n case \"raw\":\n return defer(() => this.getInfo()).pipe(\n switchMap((deviceInfo: DeviceInfo) =>\n this._brainwavesRaw$.pipe(csvBufferToEpoch(deviceInfo))\n )\n );\n\n case \"rawUnfiltered\":\n return defer(() => this.getInfo()).pipe(\n switchMap((deviceInfo: DeviceInfo) =>\n this._brainwavesRawUnfiltered$.pipe(csvBufferToEpoch(deviceInfo))\n )\n );\n\n case \"psd\":\n return this._brainwavesPSD$;\n\n case \"powerByBand\":\n return this._brainwavesPowerByBand$;\n }\n }\n\n signalQuality() {\n return this._signalQuality$;\n }\n\n async addMarker(label: string): Promise<void> {\n await this.dispatchAction({\n action: \"marker\",\n command: \"add\",\n message: {\n timestamp: Date.now(),\n label\n }\n });\n }\n\n async getInfo(): Promise<DeviceInfo> {\n return await this._withAuthentication(() =>\n firstValueFrom(\n this.transport.subscribeToCharacteristic({\n characteristicName: \"deviceInfo\"\n })\n )\n );\n }\n\n status() {\n return this._status$;\n }\n\n async dispatchAction(action: Action): Promise<any> {\n return await this._withAuthentication(() =>\n this.transport.dispatchAction({\n characteristicName: \"actions\",\n action\n })\n );\n }\n\n settings() {\n return this._settings$;\n }\n\n haptics(effects) {\n const metric = \"haptics\";\n\n return this.dispatchAction({\n action: metric,\n command: \"queue\",\n responseRequired: true,\n responseTimeout: 4000,\n // @TODO: implement validation logic as per SDK\n message: { effects }\n });\n }\n\n get wifi() {\n return {\n nearbyNetworks: (): Observable<any> => this._wifiNearbyNetworks$,\n\n connections: (): Observable<any> => this._wifiConnections$,\n\n connect: (ssid: string, password?: string) => {\n if (!ssid) {\n return Promise.reject(`Missing ssid`);\n }\n\n return this.dispatchAction({\n action: \"wifi\",\n command: \"connect\",\n responseRequired: true,\n responseTimeout: 1000 * 60 * 2, // 2 minutes\n message: {\n ssid,\n password: password ?? null\n }\n });\n },\n\n forgetConnection: (ssid: string): Promise<any> => {\n if (!ssid) {\n return Promise.reject(`Missing ssid`);\n }\n\n return this.dispatchAction({\n action: \"wifi\",\n command: \"forget-connection\",\n responseRequired: true,\n responseTimeout: 1000 * 15, // 15 seconds\n message: {\n ssid\n }\n });\n },\n\n reset: () => {\n return this.dispatchAction({\n action: \"wifi\",\n command: \"reset\",\n responseRequired: true,\n responseTimeout: 1000 * 30, // 30 seconds\n message: {\n // without this, the action will resolve as soon as the\n // action is received by the OS\n respondOnSuccess: true\n }\n });\n },\n\n speedTest: () => {\n return this.dispatchAction({\n action: \"wifi\",\n command: \"speed-test\",\n responseRequired: true,\n responseTimeout: 1000 * 60 * 1 // 1 minute\n });\n }\n };\n }\n}\n","export * from \"./BluetoothClient\";\nexport * from \"./web/WebBluetoothTransport\";\nexport * from \"./react-native/ReactNativeTransport\";\nexport * from \"./utils/osHasBluetoothSupport\";\nexport * from \"./types/index\";\n","import { combineLatest, Observable, of, throwError } from \"rxjs\";\nimport { ReplaySubject, firstValueFrom, EMPTY } from \"rxjs\";\nimport { distinctUntilChanged, map, switchMap } from \"rxjs/operators\";\nimport isEqual from \"fast-deep-equal\";\nimport { CloudClient, createUser } from \"./api/index\";\nimport { credentialWithLink, SERVER_TIMESTAMP } from \"./api/index\";\nimport { SDKOptions } from \"./types/options\";\nimport { STREAMING_MODE, STREAMING_TYPE } from \"./types/streaming\";\nimport { Training } from \"./types/training\";\nimport { Credentials, EmailAndPassword } from \"./types/credentials\";\nimport { CustomToken } from \"./types/credentials\";\nimport { Settings, ChangeSettings } from \"./types/settings\";\nimport { SignalQuality } from \"./types/signalQuality\";\nimport { Kinesis } from \"./types/kinesis\";\nimport { Calm } from \"./types/calm\";\nimport { Focus } from \"./types/focus\";\nimport { getLabels } from \"./utils/subscription\";\nimport { BrainwavesLabel, Epoch, PowerByBand, PSD } from \"./types/brainwaves\";\nimport { Accelerometer } from \"./types/accelerometer\";\nimport { DeviceInfo, OSVersion } from \"./types/deviceInfo\";\nimport { DeviceStatus, STATUS } from \"./types/status\";\nimport { Action } from \"./types/actions\";\nimport { HapticEffects } from \"./types/hapticEffects\";\nimport * as errors from \"./utils/errors\";\nimport * as platform from \"./utils/platform\";\nimport * as hapticEffects from \"./utils/hapticEffects\";\nimport { validateOAuthScopeForFunctionName } from \"./utils/oauth\";\nimport { validateOAuthScopeForAction } from \"./utils/oauth\";\nimport { createOAuthURL } from \"./api/https/createOAuthURL\";\nimport { getOAuthToken } from \"./api/https/getOAuthToken\";\nimport { OAuthConfig, OAuthQuery } from \"./types/oauth\";\nimport { OAuthQueryResult, OAuthRemoveResponse } from \"./types/oauth\";\nimport { UserClaims } from \"./types/user\";\nimport { isNode } from \"./utils/is-node\";\nimport { getCloudMetric } from \"./utils/metrics\";\nimport { Experiment } from \"./types/experiment\";\nimport { TransferDeviceOptions } from \"./utils/transferDevice\";\nimport { BluetoothClient, osHasBluetoothSupport } from \"./api/bluetooth\";\nimport { BLUETOOTH_CONNECTION } from \"./api/bluetooth/types\";\n\nconst defaultOptions = {\n timesync: false,\n autoSelectDevice: true,\n streamingMode: STREAMING_MODE.WIFI_ONLY,\n emulator: false,\n emulatorHost: \"localhost\",\n emulatorAuthPort: 9099,\n emulatorDatabasePort: 9000,\n emulatorFunctionsPort: 5001,\n emulatorFirestorePort: 8080,\n emulatorOptions: {}\n};\n\n/**\n * import StreamingModes from \"@site/src/components/StreamingModes\";\n *\n * Example\n * ```typescript\n * import { Neurosity } from \"@neurosity/sdk\";\n *\n * const neurosity = new Neurosity();\n * ```\n */\nexport class Neurosity {\n /**\n * @hidden\n */\n protected options: SDKOptions;\n\n /**\n * @hidden\n */\n protected cloudClient: CloudClient;\n\n /**\n * @hidden\n */\n protected bluetoothClient: BluetoothClient;\n\n /**\n * @hidden\n */\n protected isMissingBluetoothTransport: boolean;\n\n /**\n * @hidden\n */\n private streamingMode$ = new ReplaySubject<STREAMING_MODE>(1);\n\n /**\n *\n * @hidden\n */\n static credentialWithLink = credentialWithLink;\n\n /**\n *\n * @hidden\n */\n static createUser = createUser;\n\n /**\n *\n * @hidden\n */\n static SERVER_TIMESTAMP = SERVER_TIMESTAMP;\n\n /**\n * Creates new instance of the Neurosity SDK\n * \n * ```typescript\n * const neurosity = new Neurosity();\n * ```\n\n * @param options\n */\n constructor(options: SDKOptions = {}) {\n const { streamingMode, bluetoothTransport } = options;\n\n this.options = Object.freeze({\n ...defaultOptions,\n ...options\n });\n\n this.cloudClient = new CloudClient(this.options);\n\n if (!!bluetoothTransport) {\n this.bluetoothClient = new BluetoothClient({\n selectedDevice$: this.onDeviceChange(),\n createBluetoothToken: this.createBluetoothToken.bind(this),\n transport: bluetoothTransport\n });\n }\n\n this._initStreamingMode(streamingMode, !!bluetoothTransport);\n }\n\n /**\n *\n * @hidden\n */\n _initStreamingMode(\n streamingMode: STREAMING_MODE,\n hasBluetoothTransport: boolean\n ): void {\n const streamingModeFeaturesBluetooth = [\n STREAMING_MODE.BLUETOOTH_WITH_WIFI_FALLBACK,\n STREAMING_MODE.WIFI_WITH_BLUETOOTH_FALLBACK\n ].includes(streamingMode);\n\n const isInvalidStreamingMode =\n !Object.values(STREAMING_MODE).includes(streamingMode);\n\n const isMissingBluetoothTransport =\n streamingModeFeaturesBluetooth && !hasBluetoothTransport;\n\n this.isMissingBluetoothTransport = isMissingBluetoothTransport;\n\n const shouldDefaultToCloud =\n !streamingMode || isInvalidStreamingMode || isMissingBluetoothTransport;\n\n // Default to backwards compatible cloud streaming mode if:\n // 1. No streaming mode is provided\n // 2. An invalid streaming mode is provided\n // 3. A streaming mode containing bluetooth is provided, but without a bluetooth transport\n if (shouldDefaultToCloud) {\n this.streamingMode$.next(STREAMING_MODE.WIFI_ONLY);\n } else {\n this.streamingMode$.next(streamingMode);\n }\n }\n\n /**\n * Subscribe to the device's streaming state changes and the current strategy\n *\n * Streams the current mode of streaming (wifi or bluetooth).\n *\n * ```typescript\n * neurosity.streamingState().subscribe((streamingState) => {\n * console.log(streamingState);\n * // { streamingMode: \"wifi-only\", activeMode: \"wifi\", connected: true }\n * });\n * ```\n */\n public streamingState(): Observable<{\n connected: boolean;\n activeMode: STREAMING_TYPE;\n streamingMode: STREAMING_MODE;\n }> {\n const isWifiOnline = (state: STATUS) =>\n [STATUS.ONLINE, STATUS.UPDATING].includes(state);\n\n return this.streamingMode$.pipe(\n switchMap((streamingMode: STREAMING_MODE) => {\n return this.onDeviceChange().pipe(\n switchMap((selectDevice) => {\n if (!selectDevice) {\n return EMPTY;\n }\n\n const isUnableToUseBluetooth =\n this.isMissingBluetoothTransport ||\n !osHasBluetoothSupport(selectDevice);\n\n if (isUnableToUseBluetooth) {\n return this.cloudClient.status().pipe(\n map(({ state }) => ({\n connected: isWifiOnline(state),\n streamingMode,\n activeMode: STREAMING_TYPE.WIFI\n }))\n );\n }\n\n return combineLatest({\n wifiStatus: this.cloudClient.status(),\n bluetoothConnection: !!this?.bluetoothClient\n ? this.bluetoothClient.connection()\n : of(BLUETOOTH_CONNECTION.DISCONNECTED)\n }).pipe(\n map(({ wifiStatus, bluetoothConnection }) => {\n const isBluetoothConnected =\n bluetoothConnection === BLUETOOTH_CONNECTION.CONNECTED;\n\n switch (streamingMode) {\n default:\n case STREAMING_MODE.WIFI_ONLY:\n return {\n connected: isWifiOnline(wifiStatus.state),\n streamingMode,\n activeMode: STREAMING_TYPE.WIFI\n };\n\n case STREAMING_MODE.WIFI_WITH_BLUETOOTH_FALLBACK:\n return {\n connected:\n isWifiOnline(wifiStatus.state) || !isBluetoothConnected\n ? isWifiOnline(wifiStatus.state)\n : isBluetoothConnected,\n streamingMode,\n activeMode:\n isWifiOnline(wifiStatus.state) || !isBluetoothConnected\n ? STREAMING_TYPE.WIFI\n : STREAMING_TYPE.BLUETOOTH\n };\n\n case STREAMING_MODE.BLUETOOTH_WITH_WIFI_FALLBACK:\n return {\n connected: isBluetoothConnected\n ? true\n : isWifiOnline(wifiStatus.state),\n streamingMode,\n activeMode: isBluetoothConnected\n ? STREAMING_TYPE.BLUETOOTH\n : STREAMING_TYPE.WIFI\n };\n }\n }),\n distinctUntilChanged((a, b) => isEqual(a, b))\n );\n })\n );\n })\n );\n }\n\n /**\n *\n * @hidden\n */\n _withStreamingModeObservable<T>(streams: {\n wifi: () => Observable<T>;\n bluetooth: () => Observable<T>;\n }): Observable<any> {\n const { wifi, bluetooth } = streams;\n\n return this.streamingState().pipe(\n switchMap(({ activeMode }) => {\n switch (activeMode) {\n case STREAMING_TYPE.WIFI:\n return wifi();\n\n case STREAMING_TYPE.BLUETOOTH:\n return bluetooth();\n\n default:\n return wifi();\n }\n })\n );\n }\n\n /**\n *\n * @hidden\n */\n async _withStreamingModePromise<T>(promises: {\n wifi: () => Promise<T>;\n bluetooth: () => Promise<T>;\n }): Promise<T> {\n const { wifi, bluetooth } = promises;\n\n const { activeMode } = await firstValueFrom(this.streamingState());\n\n switch (activeMode) {\n case STREAMING_TYPE.WIFI:\n return await wifi();\n\n case STREAMING_TYPE.BLUETOOTH:\n return await bluetooth();\n\n default:\n return await wifi();\n }\n }\n\n /**\n *\n * @hidden\n */\n get bluetooth() {\n return this?.bluetoothClient;\n }\n\n /**\n *\n * @hidden\n */\n private _getCloudMetricDependencies() {\n return {\n options: this.options,\n cloudClient: this.cloudClient,\n onDeviceChange: this.onDeviceChange.bind(this),\n status: this.status.bind(this)\n };\n }\n\n /**\n * Starts user session\n *\n * ```typescript\n * await neurosity.login({\n * email: \"...\",\n * password: \"...\"\n * });\n * ```\n *\n * @param credentials\n */\n public async login(credentials: Credentials): Promise<void> {\n return await this.cloudClient.login(credentials);\n }\n\n /**\n * Ends user session\n *\n * ```typescript\n * await neurosity.logout();\n * // session has ended\n * ```\n *\n */\n public async logout(): Promise<void> {\n return await this.cloudClient.logout();\n }\n\n /**\n * @internal\n * Not user facing.\n */\n public __getApp() {\n return this.cloudClient.__getApp();\n }\n\n /**\n * Subscribe to auth state changes\n *\n * Streams the state of the auth session. If user has logged in, the user object will be set. When logged out, the user object will be null.\n *\n * ```typescript\n * neurosity.onAuthStateChanged().subscribe((user) => {\n * console.log(user);\n * });\n * ```\n */\n public onAuthStateChanged(): Observable<any> {\n return this.cloudClient.onAuthStateChanged();\n }\n\n /**\n * @internal\n * Not user facing yet\n */\n public addDevice(deviceId: string): Promise<void> {\n const [hasOAuthError, OAuthError] = validateOAuthScopeForFunctionName(\n this.cloudClient.userClaims,\n \"addDevice\"\n );\n\n if (hasOAuthError) {\n return Promise.reject(OAuthError);\n }\n\n return this.cloudClient.addDevice(deviceId);\n }\n\n /**\n * @internal\n * Not user facing yet\n */\n public removeDevice(deviceId: string): Promise<void> {\n const [hasOAuthError, OAuthError] = validateOAuthScopeForFunctionName(\n this.cloudClient.userClaims,\n \"removeDevice\"\n );\n\n if (hasOAuthError) {\n return Promise.reject(OAuthError);\n }\n\n return this.cloudClient.removeDevice(deviceId);\n }\n\n /**\n * @internal\n * Not user facing yet\n */\n public transferDevice(options: TransferDeviceOptions): Promise<void> {\n const [hasOAuthError, OAuthError] = validateOAuthScopeForFunctionName(\n this.cloudClient.userClaims,\n \"transferDevice\"\n );\n\n if (hasOAuthError) {\n return Promise.reject(OAuthError);\n }\n\n return this.cloudClient.transferDevice(options);\n }\n\n /**\n * @internal\n * Not user facing yet\n */\n public onUserDevicesChange(): Observable<DeviceInfo[]> {\n const [hasOAuthError, OAuthError] = validateOAuthScopeForFunctionName(\n this.cloudClient.userClaims,\n \"onUserDevicesChange\"\n );\n\n if (hasOAuthError) {\n return throwError(() => OAuthError);\n }\n\n return this.cloudClient.onUserDevicesChange();\n }\n\n /**\n * @internal\n * Not user facing yet\n */\n public onUserClaimsChange(): Observable<UserClaims> {\n return this.cloudClient.onUserClaimsChange();\n }\n\n /**\n * Get user devices\n *\n * Returns a list of devices claimed by the user authenticated.\n *\n * ```typescript\n * const devices = await neurosity.getDevices();\n * console.log(devices);\n * ```\n */\n public async getDevices(): Promise<DeviceInfo[]> {\n return await this.cloudClient.getDevices();\n }\n\n /**\n * Select Device\n *\n * Rarely necessary, but useful when the user owns multiple devices.\n *\n * A common use case for manually selecting a device is when you wish to build a device dropdown a user can select from, instead of collecting the Device Id from the user ahead of time.\n *\n * The 3 steps to manually selecting a device are:\n *\n * - Set `autoSelectDevice` to false when instantiating the `Neurosity` class.\n * - Authenticate with your Neurosity account to access your devices by calling the `neurosity.login(...)` function.\n * - Call the `neurosity.selectDevice(...)` function with a device selector function.\n *\n * ```typescript\n * const devices = await neurosity.selectDevice((devices) =>\n * devices.find((device) => device.deviceNickname === \"Crown-A1B\")\n * );\n *\n * console.log(devices);\n * ```\n *\n * > If you own multiple devices, and don't pass `autoSelectDevice`, then the first device on the list will be automatically selected.\n *\n * For more info, check out the \"Device Selection\" guide.\n */\n public async selectDevice(\n deviceSelector: (devices: DeviceInfo[]) => DeviceInfo\n ): Promise<DeviceInfo> {\n const [hasOAuthError, OAuthError] = validateOAuthScopeForFunctionName(\n this.cloudClient.userClaims,\n \"selectDevice\"\n );\n\n if (hasOAuthError) {\n return Promise.reject(OAuthError);\n }\n\n return await this.cloudClient.selectDevice(deviceSelector);\n }\n\n /**\n * Get selected device\n *\n * ```typescript\n * const selectedDevice = await neurosity.getSelectedDevice();\n * console.log(selectedDevice);\n * ```\n */\n\n public async getSelectedDevice(): Promise<DeviceInfo> {\n const [hasOAuthError, OAuthError] = validateOAuthScopeForFunctionName(\n this.cloudClient.userClaims,\n \"getSelectedDevice\"\n );\n\n if (hasOAuthError) {\n return Promise.reject(OAuthError);\n }\n\n return await this.cloudClient.getSelectedDevice();\n }\n\n /**\n * ```typescript\n * const info = await neurosity.getInfo();\n * ```\n */\n public async getInfo(): Promise<DeviceInfo> {\n if (!(await this.cloudClient.didSelectDevice())) {\n return Promise.reject(errors.mustSelectDevice);\n }\n\n const [hasOAuthError, OAuthError] = validateOAuthScopeForFunctionName(\n this.cloudClient.userClaims,\n \"getInfo\"\n );\n\n if (hasOAuthError) {\n return Promise.reject(OAuthError);\n }\n\n return await this._withStreamingModePromise({\n wifi: () => this.cloudClient.getInfo(),\n bluetooth: () => this.bluetoothClient.getInfo()\n });\n }\n\n /**\n * Observes selected device\n *\n * ```typescript\n * neurosity.onDeviceChange().subscribe(device => {\n * console.log(device);\n * });\n * ```\n */\n public onDeviceChange(): Observable<DeviceInfo> {\n const [hasOAuthError, OAuthError] = validateOAuthScopeForFunctionName(\n this.cloudClient.userClaims,\n \"onDeviceChange\"\n );\n\n if (hasOAuthError) {\n return throwError(() => OAuthError);\n }\n\n return this.cloudClient.onDeviceChange();\n }\n\n /**\n * <StreamingModes wifi={true} bluetooth={true} />\n *\n * Ends database connection\n *\n * ```typescript\n * await neurosity.disconnect();\n * ```\n */\n public async disconnect(): Promise<void> {\n return await this._withStreamingModePromise({\n wifi: () => this.cloudClient.disconnect(),\n bluetooth: () => this.bluetoothClient.disconnect()\n });\n }\n\n /**\n * <StreamingModes wifi={true} bluetooth={true} />\n *\n * @internal\n * Not user facing\n */\n private async dispatchAction(action: Action): Promise<Action> {\n if (!(await this.cloudClient.didSelectDevice())) {\n return Promise.reject(errors.mustSelectDevice);\n }\n\n const [hasOAuthError, OAuthError] = validateOAuthScopeForAction(\n this.cloudClient.userClaims,\n action\n );\n\n if (hasOAuthError) {\n return Promise.reject(OAuthError);\n }\n\n return await this._withStreamingModePromise({\n wifi: () => this.cloudClient.dispatchAction(action),\n bluetooth: () => this.bluetoothClient.dispatchAction(action)\n });\n }\n\n /**\n * <StreamingModes wifi={true} bluetooth={true} />\n *\n * Injects an EEG marker to data stream\n *\n * ```typescript\n * neurosity.addMarker(\"eyes-closed\");\n *\n * // later...\n *\n * neurosity.addMarker(\"eyes-open\");\n * ```\n *\n * @param label Name the label to inject\n */\n public async addMarker(label: string): Promise<Action> {\n if (!(await this.cloudClient.didSelectDevice())) {\n throw errors.mustSelectDevice;\n }\n\n if (!label) {\n throw new Error(`${errors.prefix}A label is required for addMarker`);\n }\n\n return await this._withStreamingModePromise({\n wifi: () =>\n this.cloudClient.dispatchAction({\n command: \"marker\",\n action: \"add\",\n message: {\n label,\n timestamp: this.cloudClient.timestamp\n }\n }),\n bluetooth: () => this.bluetoothClient.addMarker(label)\n });\n }\n\n /**\n * <StreamingModes wifi={true} bluetooth={true} />\n *\n * Queue haptic motor commands\n *\n * To queue haptic P7 only,\n * ```typescript\n * await neurosity.haptics({\n * P7: [\"tripleClick100\"]\n * });\n * ```\n *\n * To queue both motors at the same time\n * ```typescript\n * await neurosity.haptics({\n * P7: [neurosity.getHapticEffects().strongClick100],\n * P8: [neurosity.getHapticEffects().strongClick100]\n * });\n * ```\n *\n * You can queue different commands to the motors too\n * ```typescript\n * const effects = neurosity.getHapticEffects();\n * await neurosity.haptics({\n * P7: [effects.transitionRampUpLongSmooth1_0_to_100,\n * effects.transitionRampDownLongSmooth1_100_to_0],\n * P8: [effects.strongClick100]\n * });\n * ```\n *\n * @param effects Effects to queue. The key of the object passed should be the location of the motor\n * to queue. Each key can be an array of up to 7 commands. There is no haptic support for model\n * version 1, Notion DK1. The Haptic motor's location is positioned in reference to the 10-10 EEG\n * system used to label the channels of the Crown's EEG sensors. Notion 2 and Crown have haptics\n * at P7 and P8. A list of haptic commands can be found on ./utils/hapticCodes.ts - there\n * are about 127 of them!\n */\n public async haptics(effects: any): Promise<any> {\n const metric = \"haptics\";\n if (!(await this.cloudClient.didSelectDevice())) {\n return Promise.reject(errors.mustSelectDevice);\n }\n\n const modelVersion = (await this.getSelectedDevice())?.modelVersion;\n const supportsHaptics = platform.supportsHaptics(modelVersion);\n\n if (!supportsHaptics) {\n return Promise.reject(\n errors.metricNotSupportedByModel(metric, modelVersion)\n );\n }\n\n const newPlatformHapticRequest =\n platform.getPlatformHapticMotors(modelVersion);\n\n for (const key in effects) {\n if (!Object.keys(newPlatformHapticRequest).includes(key)) {\n return Promise.reject(errors.locationNotFound(key, modelVersion));\n }\n const singleMotorEffects: string[] = effects[key];\n const maxItems = 7;\n if (singleMotorEffects.length > maxItems) {\n return Promise.reject(errors.exceededMaxItems(maxItems));\n }\n newPlatformHapticRequest[key] = singleMotorEffects;\n }\n\n const payload = {\n command: metric,\n action: \"queue\",\n responseRequired: true,\n responseTimeout: 1000,\n message: { effects: newPlatformHapticRequest }\n };\n\n return await this._withStreamingModePromise({\n wifi: () => this.cloudClient.dispatchAction(payload),\n bluetooth: () => this.bluetoothClient.dispatchAction(payload)\n });\n }\n\n /**\n * ```typescript\n * const effects = neurosity.getHapticEffects();\n * ```\n */\n public getHapticEffects(): HapticEffects {\n return hapticEffects;\n }\n\n /**\n * <StreamingModes wifi={true} bluetooth={true} />\n *\n * Observes accelerometer data\n * Supported by the Crown and Notion 2 devices.\n *\n * ```typescript\n * neurosity.accelerometer().subscribe(accelerometer => {\n * console.log(accelerometer);\n * });\n *\n * // { acceleration: ..., inclination: ..., orientation: ..., pitch: ..., roll: ..., x: ..., y: ..., z: ... }\n * ```\n *\n * @returns Observable of accelerometer metric events\n */\n public accelerometer(): Observable<Accelerometer> {\n const metric = \"accelerometer\";\n\n const [hasOAuthError, OAuthError] = validateOAuthScopeForFunctionName(\n this.cloudClient.userClaims,\n metric\n );\n\n if (hasOAuthError) {\n return throwError(() => OAuthError);\n }\n\n return this.onDeviceChange().pipe(\n switchMap((selectedDevice: DeviceInfo | null) => {\n const modelVersion =\n selectedDevice?.modelVersion || platform.MODEL_VERSION_1;\n const supportsAccel = platform.supportsAccel(modelVersion);\n\n if (!supportsAccel) {\n return throwError(() =>\n errors.metricNotSupportedByModel(metric, modelVersion)\n );\n }\n\n return this._withStreamingModeObservable({\n wifi: () =>\n getCloudMetric(this._getCloudMetricDependencies(), {\n metric,\n labels: getLabels(metric),\n atomic: true\n }),\n bluetooth: () => this.bluetoothClient.accelerometer()\n });\n })\n );\n }\n\n /**\n * <StreamingModes wifi={true} bluetooth={true} />\n * \n * The `raw` brainwaves parameter emits epochs of 16 samples for Crown and 25 for Notion 1 and 2.\n *\n * Example\n * ```typescript\n * neurosity.brainwaves(\"raw\").subscribe(brainwaves => {\n * console.log(brainwaves);\n * });\n * ```\n *\n * Raw Unfiltered - The `rawUnfiltered` brainwaves parameter emits epochs of 16 samples for Crown and 25 for Notion 1 and 2. \n\n * Example\n * ```typescript\n * neurosity.brainwaves(\"rawUnfiltered\").subscribe(brainwaves => {\n * console.log(brainwaves);\n * });\n * ```\n *\n * Power By Band - The `powerByBand` brainwaves parameter emits epochs 4 times a second. Every frequency label (e.g. beta) contains an average power value per channel.\n * \n * Example\n * ```typescript\n * neurosity.brainwaves(\"powerByBand\").subscribe(brainwaves => {\n * console.log(brainwaves);\n * });\n * ```\n *\n * Power Spectral Density (PSD) - The `psd` brainwaves parameter emits epochs 4 times a second. Every frequency label (e.g. alpha) contains the computed FFT (Fast Fourier transform) value per channel (see the `psd` property), as well as the frequency ranges (see the `freqs` property).\n * \n * Example\n * ```typescript\n * neurosity.brainwaves(\"psd\").subscribe(brainwaves => {\n * console.log(brainwaves);\n * });\n * ```\n *\n * @param label Name of metric properties to filter by\n * @returns Observable of brainwaves metric events\n */\n public brainwaves(\n label: BrainwavesLabel\n ): Observable<Epoch | PowerByBand | PSD> {\n const [hasOAuthError, OAuthError] = validateOAuthScopeForFunctionName(\n this.cloudClient.userClaims,\n \"brainwaves\"\n );\n\n if (hasOAuthError) {\n return throwError(() => OAuthError);\n }\n\n return this._withStreamingModeObservable({\n wifi: () =>\n getCloudMetric(this._getCloudMetricDependencies(), {\n metric: \"brainwaves\",\n labels: label ? [label] : [],\n atomic: false\n }),\n // @TODO: doesn't support multiple labels, we should make the higher\n // order function only support one label\n bluetooth: () => this.bluetoothClient.brainwaves(label)\n });\n }\n\n /**\n * <StreamingModes wifi={true} bluetooth={true} />\n *\n * Example\n * ```typescript\n * neurosity.calm().subscribe(calm => {\n * console.log(calm.probability);\n * });\n *\n * // 0.45\n * // 0.47\n * // 0.53\n * // 0.51\n * // ...\n * ```\n *\n * @returns Observable of calm events - awareness/calm alias\n */\n public calm(): Observable<Calm> {\n const [hasOAuthError, OAuthError] = validateOAuthScopeForFunctionName(\n this.cloudClient.userClaims,\n \"calm\"\n );\n\n if (hasOAuthError) {\n return throwError(() => OAuthError);\n }\n\n return this._withStreamingModeObservable({\n wifi: () =>\n getCloudMetric(this._getCloudMetricDependencies(), {\n metric: \"awareness\",\n labels: [\"calm\"],\n atomic: false\n }),\n bluetooth: () => this.bluetoothClient.calm()\n });\n }\n\n /**\n * <StreamingModes wifi={true} bluetooth={true} />\n *\n * Observes signal quality data where each property is the name\n * of the channel and the value includes the standard deviation and\n * a status set by the device\n *\n * ```typescript\n * neurosity.signalQuality().subscribe(signalQuality => {\n * console.log(signalQuality);\n * });\n *\n * // { FC6: { standardDeviation: 3.5, status: \"good\" }, C3: {...}, ... }\n * ```\n *\n * @returns Observable of signalQuality metric events\n */\n public signalQuality(): Observable<SignalQuality> {\n const metric = \"signalQuality\";\n\n const [hasOAuthError, OAuthError] = validateOAuthScopeForFunctionName(\n this.cloudClient.userClaims,\n metric\n );\n\n if (hasOAuthError) {\n return throwError(() => OAuthError);\n }\n\n return this._withStreamingModeObservable({\n wifi: () =>\n getCloudMetric(this._getCloudMetricDependencies(), {\n metric,\n labels: getLabels(metric),\n atomic: true\n }),\n bluetooth: () => this.bluetoothClient.signalQuality()\n });\n }\n\n /**\n * <StreamingModes wifi={true} />\n *\n * Observes last state of `settings` and all subsequent `settings` changes\n *\n * ```typescript\n * neurosity.settings().subscribe(settings => {\n * console.log(settings.lsl);\n * });\n *\n * // true\n * // ...\n * ```\n *\n * @returns Observable of `settings` metric events\n */\n public settings(): Observable<Settings> {\n const [hasOAuthError, OAuthError] = validateOAuthScopeForFunctionName(\n this.cloudClient.userClaims,\n \"settings\"\n );\n\n if (hasOAuthError) {\n return throwError(() => OAuthError);\n }\n\n return this.cloudClient.observeNamespace(\"settings\");\n }\n\n /**\n * <StreamingModes wifi={true} />\n *\n * Observes the current OS version and all subsequent version changes in real-time.\n *\n * ```typescript\n * neurosity.osVersion().subscribe((osVersion) => {\n * console.log(osVersion);\n * });\n *\n * // \"16.0.0\"\n * ```\n *\n * @returns Observable of `osVersion` events. e.g 16.0.0\n */\n public osVersion(): Observable<OSVersion> {\n const [hasOAuthError, OAuthError] = validateOAuthScopeForFunctionName(\n this.cloudClient.userClaims,\n \"osVersion\"\n );\n\n if (hasOAuthError) {\n return throwError(() => OAuthError);\n }\n\n return this.cloudClient.observeNamespace(\"info/osVersion\");\n }\n\n /**\n * <StreamingModes wifi={true} bluetooth={true} />\n *\n * Example\n * ```typescript\n * neurosity.focus().subscribe(focus => {\n * console.log(focus.probability);\n * });\n *\n * // 0.56\n * // 0.46\n * // 0.31\n * // 0.39\n * // ...\n * ```\n *\n * @returns Observable of focus events - awareness/focus alias\n */\n public focus(): Observable<Focus> {\n const [hasOAuthError, OAuthError] = validateOAuthScopeForFunctionName(\n this.cloudClient.userClaims,\n \"focus\"\n );\n\n if (hasOAuthError) {\n return throwError(() => OAuthError);\n }\n\n return this._withStreamingModeObservable({\n wifi: () =>\n getCloudMetric(this._getCloudMetricDependencies(), {\n metric: \"awareness\",\n labels: [\"focus\"],\n atomic: false\n }),\n bluetooth: () => this.bluetoothClient.focus()\n });\n }\n\n /**\n * <StreamingModes wifi={true} />\n *\n * @param label Name of metric properties to filter by\n * @returns Observable of kinesis metric events\n */\n public kinesis(label: string): Observable<Kinesis> {\n const metric = \"kinesis\";\n\n const [hasOAuthError, OAuthError] = validateOAuthScopeForFunctionName(\n this.cloudClient.userClaims,\n metric\n );\n\n if (hasOAuthError) {\n return throwError(() => OAuthError);\n }\n\n return getCloudMetric(this._getCloudMetricDependencies(), {\n metric,\n labels: label ? [label] : [],\n atomic: false\n });\n }\n\n /**\n * <StreamingModes wifi={true} />\n *\n * @param label Name of metric properties to filter by\n * @returns Observable of predictions metric events\n */\n public predictions(label: string): Observable<any> {\n const metric = \"predictions\";\n\n const [hasOAuthError, OAuthError] = validateOAuthScopeForFunctionName(\n this.cloudClient.userClaims,\n metric\n );\n\n if (hasOAuthError) {\n return throwError(() => OAuthError);\n }\n\n return getCloudMetric(this._getCloudMetricDependencies(), {\n metric,\n labels: label ? [label] : [],\n atomic: false\n });\n }\n\n /**\n * <StreamingModes wifi={true} bluetooth={true} />\n *\n * Observes last state of `status` and all subsequent `status` changes\n *\n * ```typescript\n * neurosity.status().subscribe(status => {\n * console.log(status.state);\n * });\n *\n * // \"online\"\n * // ...\n * ```\n *\n * @returns Observable of `status` metric events\n */\n public status(): Observable<DeviceStatus> {\n const [hasOAuthError, OAuthError] = validateOAuthScopeForFunctionName(\n this.cloudClient.userClaims,\n \"status\"\n );\n\n if (hasOAuthError) {\n return throwError(() => OAuthError);\n }\n\n return this._withStreamingModeObservable({\n wifi: () => this.cloudClient.status(),\n bluetooth: () => this.bluetoothClient.status()\n });\n }\n\n /**\n * @internal\n * Not user facing yet\n *\n * <StreamingModes wifi={true} />\n *\n * Changes device settings programmatically. These settings can be\n * also changed from the developer console under device settings.\n *\n * Available settings [[ChangeSettings]]\n *\n * Example\n * ```typescript\n * neurosity.changeSettings({\n * lsl: true\n * });\n * ```\n */\n public async changeSettings(settings: ChangeSettings): Promise<void> {\n if (!(await this.cloudClient.didSelectDevice())) {\n return Promise.reject(errors.mustSelectDevice);\n }\n\n const [hasOAuthError, OAuthError] = validateOAuthScopeForFunctionName(\n this.cloudClient.userClaims,\n \"changeSettings\"\n );\n\n if (hasOAuthError) {\n return Promise.reject(OAuthError);\n }\n\n return await this.cloudClient.changeSettings(settings);\n }\n\n /**\n * <StreamingModes wifi={true} />\n *\n * ```typescript\n * neurosity.training.record({\n * metric: \"kinesis\",\n * label: \"push\"\n * });\n *\n * neurosity.training.stop({\n * metric: \"kinesis\",\n * label: \"push\"\n * });\n * ```\n *\n * @returns Training methods\n */\n public get training(): Training {\n return {\n /**\n * <StreamingModes wifi={true} />\n *\n * Records a training for a metric/label pair\n * @category Training\n */\n record: async (training) => {\n if (!(await this.cloudClient.didSelectDevice())) {\n throw errors.mustSelectDevice;\n }\n\n const userId =\n this.cloudClient.user && \"uid\" in this.cloudClient.user\n ? this.cloudClient.user.uid\n : null;\n const message = {\n fit: false,\n baseline: false,\n timestamp: this.cloudClient.timestamp,\n ...training,\n userId\n };\n\n await this.cloudClient.actions.dispatch({\n command: \"training\",\n action: \"record\",\n message\n });\n },\n /**\n * <StreamingModes wifi={true} />\n *\n * Stops the training for a metric/label pair\n * @category Training\n */\n stop: async (training) => {\n if (!(await this.cloudClient.didSelectDevice())) {\n throw errors.mustSelectDevice;\n }\n\n await this.cloudClient.actions.dispatch({\n command: \"training\",\n action: \"stop\",\n message: {\n ...training\n }\n });\n },\n /**\n * <StreamingModes wifi={true} />\n *\n * Stops all trainings\n * @category Training\n */\n stopAll: async () => {\n if (!(await this.cloudClient.didSelectDevice())) {\n throw errors.mustSelectDevice;\n }\n\n await this.cloudClient.actions.dispatch({\n command: \"training\",\n action: \"stopAll\",\n message: {}\n });\n }\n };\n }\n\n /**\n * @internal\n * Proof of Concept for disconnecting db\n */\n public goOffline(): void {\n this.cloudClient.goOffline();\n }\n\n /**\n * @internal\n * Proof of Concept for resuming db connection\n */\n public goOnline(): void {\n this.cloudClient.goOnline();\n }\n\n /**\n * @internal\n * Not user facing yet\n *\n * Creates user account and automatically signs in with same credentials\n *\n * @param emailAndPasswordObject\n * @returns user credential\n */\n public createAccount(credentials: EmailAndPassword) {\n return this.cloudClient.createAccount(credentials);\n }\n\n /**\n * @internal\n * Not user facing yet\n *\n * Removes all devices from an account and then deletes the account\n */\n public deleteAccount() {\n return this.cloudClient.deleteAccount();\n }\n\n /**\n * @internal\n * Not user facing\n *\n * Creates token (JWT) designed to authenticate and authorize Bluetooth clients/centrals.\n *\n * @returns token\n */\n public createBluetoothToken(): Promise<string> {\n return this.cloudClient.createBluetoothToken();\n }\n\n /**\n * @internal\n * Not user facing yet\n *\n * Creates custom token (JWT) to use to login with `{ customToken }`.\n *\n * @returns custom token\n */\n public createCustomToken(): Promise<CustomToken> {\n return this.cloudClient.createCustomToken();\n }\n\n /**\n * @internal\n * Not user facing yet\n *\n * Gets the offset between the device's clock and the client's clock\n * Requires option.timesync to be true\n *\n * @returns timesyncOffset\n */\n public getTimesyncOffset(): number {\n if (!this.options.timesync) {\n console.warn(`getTimesyncOffset() requires options.timesync to be true.`);\n }\n\n return this.options.timesync ? this.cloudClient.getTimesyncOffset() : 0;\n }\n\n /**\n * Create OAuth URL\n * 💡 OAuth requires developers to register their apps with Neurosity\n * [Read full OAuth guide](/docs/oauth)\n *\n * Creates client-specific OAuth URL. This is the first step of the OAuth workflow. Use this function to create a URL you can use to redirect users to the Neurosity sign-in page.\n * 💡 This function is designed to only run on the server side for security reasons, as it requires your client secret.\n *\n * ```typescript\n * const { Neurosity } = require(\"@neurosity/sdk\");\n *\n * const neurosity = new Neurosity({\n * autoSelectDevice: false\n * });\n *\n * exports.handler = async function (event) {\n * return neurosity\n * .createOAuthURL({\n * clientId: process.env.NEUROSITY_OAUTH_CLIENT_ID,\n * clientSecret: process.env.NEUROSITY_OAUTH_CLIENT_SECRET,\n * redirectUri: process.env.NEUROSITY_OAUTH_CLIENT_REDIRECT_URI,\n * responseType: \"token\",\n * state: Math.random().toString().split(\".\")[1],\n * scope: [\n * \"read:devices-info\",\n * \"read:devices-status\",\n * \"read:signal-quality\",\n * \"read:brainwaves\"\n * ]\n * })\n * .then((url) => ({\n * statusCode: 200,\n * body: JSON.stringify({ url })\n * }))\n * .catch((error) => ({\n * statusCode: 400,\n * body: JSON.stringify(error.response.data)\n * }));\n * };\n * ```\n * @returns custom token\n */\n public createOAuthURL(config: OAuthConfig): Promise<string> {\n if (!isNode) {\n return Promise.reject(\n new Error(\n `${errors.prefix}the createOAuthURL method must be used on the server side (node.js) for security reasons.`\n )\n );\n }\n\n return createOAuthURL(config, this.options);\n }\n\n /**\n * Get OAuth Token\n * 💡 OAuth requires developers to register their apps with Neurosity\n * [Read full OAuth guide](/docs/oauth)\n *\n * Gets client-specific OAuth token for a given userId.\n *\n * 💡 This function is designed to only run on the server side for security reasons, as it requires your client secret.\n * Here's an example of a cloud function that receives a `userId` via query params and loads the client id and client secret securely via environment variables.\n *\n *\n * ```typescript\n * const { Neurosity } = require(\"@neurosity/sdk\");\n *\n * const neurosity = new Neurosity({\n * autoSelectDevice: false\n * });\n *\n * exports.handler = async function (event) {\n * const userId = event.queryStringParameters?.userId;\n *\n * return neurosity\n * .getOAuthToken({\n * clientId: process.env.NEUROSITY_OAUTH_CLIENT_ID,\n * clientSecret: process.env.NEUROSITY_OAUTH_CLIENT_SECRET,\n * userId\n * })\n * .then((token) => ({\n * statusCode: 200,\n * body: JSON.stringify(token)\n * }))\n * .catch((error) => ({\n * statusCode: 200,\n * body: JSON.stringify(error.response.data)\n * }));\n * };\n * ```\n * @returns custom token\n */\n public getOAuthToken(query: OAuthQuery): Promise<OAuthQueryResult> {\n if (!isNode) {\n return Promise.reject(\n new Error(\n `${errors.prefix}the getOAuthToken method must be used on the server side (node.js) for security reasons.`\n )\n );\n }\n\n return getOAuthToken(query, this.options);\n }\n\n /**\n * Remove OAuth Access\n * 💡 OAuth requires developers to register their apps with Neurosity\n * [Read full OAuth guide](/docs/oauth)\n *\n * Removes client-specific OAuth token for a given userId. Requires SDK to be signed in with OAuth custom token.\n *\n * ```typescript\n * await neurosity.removeOAuthAccess().catch((error) => {\n * // handle error here...\n * });\n * ```\n * @returns custom token\n */\n public removeOAuthAccess(): Promise<OAuthRemoveResponse> {\n return this.cloudClient.removeOAuthAccess();\n }\n\n /**\n * <StreamingModes wifi={true} />\n *\n * Observes and returns a list of all Kinesis `experiments` and all subsequent experiment changes.\n * Here's an example of how to get a list of all Kinesis labels that have been trained:\n *\n * ```typescript\n *\n * const getUniqueLabels = (experiments) => {\n * const labels = experiments.flatMap((experiment) => experiment.labels);\n * // only return unique labels\n * return [...new Set(labels)];\n * }\n *\n * neurosity.onUserExperiments().subscribe((experiments) => {\n * console.log(experiments);\n * console.log(\"labels\", getUniqueLabels(experiments));\n * });\n *\n * // [{ id: '...', deviceId: '...', labels: [ 'drop' ], name: 'Lightgray cheetah', timestamp: 1577908381552, totalTrials: 16, userId: '...' }]\n * // [\"drop\", \"lift\", \"push\"]\n * ```\n *\n * @returns Observable of `experiments` events\n */\n public onUserExperiments(): Observable<Experiment[]> {\n return this.cloudClient.onUserExperiments();\n }\n\n /**\n * <StreamingModes wifi={true} />\n *\n * Deletes a specific experiment provided an experiment ID\n *\n * ```typescript\n * await neurosity.deleteUserExperiment(experiment.id);\n * ```\n *\n * @param experimentId The ID of the Experiment\n * @returns void\n */\n public deleteUserExperiment(experimentId: string): Promise<void> {\n return this.cloudClient.deleteUserExperiment(experimentId);\n }\n}\n\n/**\n * @hidden\n * Deprecated class kept for backwards compatibility purposes.\n */\nexport class Notion extends Neurosity {\n constructor(options: SDKOptions = {}) {\n super(options);\n console.log(\n `The Notion class is deprecated and will be removed in the next version of the SDK. Please use the Neurosity class instead. e.g. new Notion() => new Neurosity()`\n );\n }\n}\n","export * from \"./Neurosity\";\nexport * from \"./api/bluetooth\";\n"]}
|