import axios, {AxiosRequestConfig} from 'axios'; import {EventEmitter} from 'events'; export interface TokensObject { accessToken: string; refreshToken?: string; } export interface UserCredential { email: string; password: string; remember?: boolean; } export interface SignUpData { name: string; email: string; password: string; } interface User { id: number; name: string; email: string; } export interface FarmTicket { farmId: number; farmName: string; host: string; port: number; tlsPort: number; wssPort: number; username: string; password: string; } export class FloraCloud extends EventEmitter { apiUrl = "https://api.florafi.net" accessToken?: string refreshToken?: string // constructor() {} private async getAuthorizationConfig() { if (!this.accessToken) { if (this.refreshToken) { await this.refreshAccessToken() } else { throw new Error("Missing access token"); } } const headers = { Authorization: `Bearer ${this.accessToken}` } return headers } // auth async signUp(data: SignUpData, remember = false): Promise { const res = await axios.post(`${this.apiUrl}/users/sign-up`, data) this.accessToken = res.data.accessToken if (remember) { await this.createRefreshToken() } } async signIn(credential: UserCredential): Promise { const res = await axios.post(`${this.apiUrl}/auth/sign-in`, credential) if (!res.data.accessToken) throw new Error("Signin endpoint did not return accessToken"); this.accessToken = res.data.accessToken this.refreshToken = res.data.refreshToken this.emit("sign-in") return { accessToken: res.data.accessToken, refreshToken: res.data.refreshToken } } signOut(): void { this.accessToken = undefined this.refreshToken = undefined } async refreshAccessToken(): Promise { try { const res = await axios.post(`${this.apiUrl}/auth/refresh-access-token`, {refreshToken: this.refreshToken}) this.accessToken = res.data.accessToken if (!this.accessToken) throw new Error("Server did not return accessToken, wtf.") return {accessToken: this.accessToken} } catch (e) { console.log("refreshAccessToken error:", e) delete this.refreshToken throw e } } async createRefreshToken(): Promise<{refreshToken: string}> { const headers = await this.getAuthorizationConfig() const res = await axios.post(`${this.apiUrl}/auth/create-refresh-token`, null, {headers}) this.refreshToken = res.data.refreshToken return res.data } // low level rest async request(config: AxiosRequestConfig): Promise { if (typeof config.headers != "object") config.headers = {} config.headers = await this.getAuthorizationConfig() console.log("request", config) const res = await axios.request(config) return res } get(path: string): Promise { return this.request({ method: "GET", url: `${this.apiUrl}/${path}` }) } post(path: string, data: Record | null = null): Promise { return this.request({ method: "POST", url: `${this.apiUrl}/${path}`, data }) } // user async whoAmI(): Promise { const res = await this.get(`users/who-am-i`) return res.data } // farm async checkIn(): Promise { try { const res = await axios.get(`${this.apiUrl}/users/check-in`, {headers: await this.getAuthorizationConfig()}) this.emit("check-in", {tickets: res.data}) return res.data } catch (e) { console.log("Checkin error", e) // try to refresh token if (this.refreshToken) { console.log("Attepting to refresh access token") await this.refreshAccessToken() return this.checkIn() } else throw e } } }