@neurosity/sdk
Version:
Neurosity SDK
308 lines (307 loc) • 12 kB
JavaScript
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { ReplaySubject, EMPTY } from "rxjs";
import { fromEventPattern, firstValueFrom } from "rxjs";
import { filter, shareReplay, share, switchMap } from "rxjs/operators";
import { FirebaseApp, FirebaseUser, FirebaseDevice } from "./firebase";
import { Timesync } from "../timesync";
import { SubscriptionManager } from "../subscriptions/SubscriptionManager";
import { heartbeatAwareStatus } from "../utils/heartbeat";
import { filterInternalKeys } from "../utils/filterInternalKeys";
export { credentialWithLink, createUser, SERVER_TIMESTAMP, __firebase } from "./firebase";
/**
* @hidden
*/
export class CloudClient {
constructor(options) {
/**
* @internal
*/
this._selectedDevice = new ReplaySubject(1);
this.options = options;
this.subscriptionManager = new SubscriptionManager();
this.firebaseApp = new FirebaseApp(options);
this.firebaseUser = new FirebaseUser(this.firebaseApp);
this._selectedDevice.next(undefined);
this.status$ = heartbeatAwareStatus(this.observeNamespace("status").pipe(share())).pipe(filterInternalKeys(), shareReplay(1));
this.osVersion$ = this.observeNamespace("info/osVersion").pipe(shareReplay(1));
this.firebaseUser.onAuthStateChanged().subscribe((user) => {
this.user = user;
});
this.firebaseUser.onUserClaimsChange().subscribe((userClaims) => {
this.userClaims = userClaims;
});
this.onDeviceChange().subscribe((device) => {
if (this.firebaseDevice) {
this.firebaseDevice.disconnect();
}
if (!device) {
return;
}
this.firebaseDevice = new FirebaseDevice({
deviceId: device.deviceId,
firebaseApp: this.firebaseApp,
dependencies: {
subscriptionManager: this.subscriptionManager
}
});
if (this.options.timesync) {
this.timesync = new Timesync({
status$: this.status(),
getTimesync: this.firebaseDevice.getTimesync.bind(this.firebaseDevice)
});
}
});
}
onDeviceChange() {
return this._selectedDevice
.asObservable()
.pipe(filter((value) => value !== undefined));
}
osVersion() {
return this.osVersion$;
}
// Automatically select device when user logs in
setAutoSelectedDevice() {
return __awaiter(this, void 0, void 0, function* () {
// Select based on `deviceId` passed
if (this.options.deviceId) {
return yield this.selectDevice((devices) => {
return devices.find((device) => device.deviceId === this.options.deviceId);
});
}
// Auto select first-claimed device
if (!this.options.deviceId && this.options.autoSelectDevice) {
return yield this.selectDevice((devices) => {
// Auto select first device
return devices[0];
});
}
return null;
});
}
get actions() {
return {
dispatch: (action) => {
return this.firebaseDevice.dispatchAction(action);
}
};
}
dispatchAction(action) {
return __awaiter(this, void 0, void 0, function* () {
return yield this.firebaseDevice.dispatchAction(action);
});
}
disconnect() {
return __awaiter(this, void 0, void 0, function* () {
return this.firebaseApp.disconnect();
});
}
getInfo() {
return __awaiter(this, void 0, void 0, function* () {
return yield this.firebaseDevice.getInfo();
});
}
login(credentials) {
return __awaiter(this, void 0, void 0, function* () {
if (this.user) {
return Promise.reject(`Already logged in.`);
}
const auth = yield this.firebaseUser.login(credentials);
const selectedDevice = yield this.setAutoSelectedDevice();
return Object.assign(Object.assign({}, auth), { selectedDevice });
});
}
logout() {
return __awaiter(this, void 0, void 0, function* () {
if (this.firebaseDevice) {
this.firebaseDevice.disconnect();
}
return yield this.firebaseUser.logout();
});
}
onAuthStateChanged() {
return this.firebaseUser.onAuthStateChanged().pipe(switchMap((user) => __awaiter(this, void 0, void 0, function* () {
if (!user) {
return null;
}
const selectedDevice = this.didSelectDevice()
? yield this.getSelectedDevice()
: yield this.setAutoSelectedDevice();
const userWithMetadata = Object.assign(user, {
selectedDevice
});
return userWithMetadata;
})));
}
getDevices() {
return this.firebaseUser.getDevices();
}
addDevice(deviceId) {
return this.firebaseUser.addDevice(deviceId);
}
removeDevice(deviceId) {
return __awaiter(this, void 0, void 0, function* () {
const [hasError, errorMessage] = yield this.firebaseUser
.removeDevice(deviceId)
.then(() => [false])
.catch((error) => [true, error]);
if (hasError) {
return Promise.reject(errorMessage);
}
const selectedDevice = yield this.getSelectedDevice();
if ((selectedDevice === null || selectedDevice === void 0 ? void 0 : selectedDevice.deviceId) === deviceId) {
this._selectedDevice.next(null);
}
});
}
transferDevice(options) {
return __awaiter(this, void 0, void 0, function* () {
const [hasError, error] = yield this.firebaseUser
.transferDevice(options)
.then(() => [false])
.catch((error) => [true, error]);
if (hasError) {
return Promise.reject(error);
}
const selectedDevice = yield this.getSelectedDevice();
if ((selectedDevice === null || selectedDevice === void 0 ? void 0 : selectedDevice.deviceId) === options.deviceId) {
this._selectedDevice.next(null);
}
});
}
onUserDevicesChange() {
return this.firebaseUser.onUserDevicesChange();
}
onUserClaimsChange() {
return this.firebaseUser.onUserClaimsChange();
}
didSelectDevice() {
return __awaiter(this, void 0, void 0, function* () {
const selectedDevice = yield this.getSelectedDevice();
return !!selectedDevice;
});
}
selectDevice(deviceSelector) {
return __awaiter(this, void 0, void 0, function* () {
const devices = yield this.getDevices();
if (!devices) {
return Promise.reject(`Did not find any devices for this user. Make sure your device is claimed by your Neurosity account.`);
}
const deviceTupleSelector = (devices) => devices.find((device) => {
if (!Array.isArray(deviceSelector)) {
return false;
}
const [deviceKey, deviceValue] = deviceSelector;
return (JSON.stringify(device === null || device === void 0 ? void 0 : device[deviceKey]) === JSON.stringify(deviceValue));
});
const device = typeof deviceSelector === "function"
? deviceSelector(devices)
: deviceTupleSelector(devices);
if (!device) {
return Promise.reject(`A device was not provided. Try returning a device from the devicesList provided in the callback.`);
}
const hasPermission = yield this.firebaseUser.hasDevicePermission(device.deviceId);
if (!hasPermission) {
return Promise.reject(`Rejected device access due to permissions.`);
}
this._selectedDevice.next(device);
return device;
});
}
getSelectedDevice() {
return __awaiter(this, void 0, void 0, function* () {
return yield firstValueFrom(this._selectedDevice);
});
}
status() {
return this.status$;
}
observeNamespace(namespace) {
const getNamespaceValues = () => fromEventPattern((handler) => this.firebaseDevice.onNamespace(namespace, handler), (handler) => this.firebaseDevice.offNamespace(namespace, handler));
return this.onDeviceChange().pipe(switchMap((selectedDevice) => {
return selectedDevice ? getNamespaceValues() : EMPTY;
}));
}
onceNamespace(namespace) {
return __awaiter(this, void 0, void 0, function* () {
return yield this.firebaseDevice.onceNamespace(namespace);
});
}
get metrics() {
return {
next: (metricName, metricValue) => {
this.firebaseDevice.nextMetric(metricName, metricValue);
},
on: (subscription, callback) => {
return this.firebaseDevice.onMetric(subscription, callback);
},
subscribe: (subscription) => {
const subscriptionCreated = this.firebaseDevice.subscribeToMetric(subscription);
this.subscriptionManager.add(subscriptionCreated);
return subscriptionCreated;
},
unsubscribe: (subscription, listener) => {
this.subscriptionManager.remove(subscription);
this.firebaseDevice.unsubscribeFromMetric(subscription);
this.firebaseDevice.removeMetricListener(subscription, listener);
}
};
}
createAccount(credentials) {
return this.firebaseUser.createAccount(credentials);
}
deleteAccount() {
return this.firebaseUser.deleteAccount();
}
createBluetoothToken() {
return this.firebaseDevice.createBluetoothToken();
}
createCustomToken() {
return this.firebaseUser.createCustomToken();
}
removeOAuthAccess() {
return this.firebaseUser.removeOAuthAccess();
}
onUserExperiments() {
return this.firebaseUser.onUserExperiments();
}
deleteUserExperiment(experimentId) {
return this.firebaseUser.deleteUserExperiment(experimentId);
}
get skills() {
return {
get: (bundleId) => __awaiter(this, void 0, void 0, function* () {
return this.firebaseDevice.getSkill(bundleId);
})
};
}
get timestamp() {
return this.options.timesync ? this.timesync.timestamp : Date.now();
}
getTimesyncOffset() {
return this.timesync.offset;
}
changeSettings(settings) {
return this.firebaseDevice.changeSettings(settings);
}
goOffline() {
this.firebaseApp.goOffline();
}
goOnline() {
this.firebaseApp.goOnline();
}
/**
* @internal
*/
__getApp() {
return this.firebaseApp.app;
}
}