// FirstAlert API client for OAuth and device polling // Implements token refresh, account/device fetch, and strong typing import { request } from 'undici' export interface ResideoDevice { id: string name: string deviceId: string globalDeviceType: string } export interface ResideoAccount { id: string firstName: string lastName: string contactEmail: string countryCode: string locale: string devices: ResideoDevice[] } export interface ResideoDeviceState { name: string deviceType: string isOnline: boolean deviceState: any } export class ResideoClient { private clientId = 'SRmiA7CaYi1JgivDZdzzoZu4X5VBogGt' private refreshToken: string private accessToken: string | null = null constructor(refreshToken: string) { this.refreshToken = refreshToken } async refreshAccessToken(): Promise { const body = JSON.stringify({ grant_type: 'refresh_token', refresh_token: this.refreshToken, client_id: this.clientId, }) const { body: resBody } = await request('https://login.firstalert.com/oauth/token', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body, }) const data = await resBody.json() as { access_token?: string } this.accessToken = data.access_token ?? '' if (!this.accessToken) { throw new Error('Failed to obtain access token from FirstAlert API') } return this.accessToken } async getAccessToken(): Promise { if (!this.accessToken) { await this.refreshAccessToken() } return this.accessToken! } async getAccount(): Promise { const token = await this.getAccessToken() const { body: resBody } = await request('https://api.firstalert.com/ris-public-api/api/v1/accounts', { method: 'GET', headers: { Authorization: `Bearer ${token}` }, }) const resp = await resBody.json() as { data: any } // Parse and flatten devices const data = resp.data const devices: ResideoDevice[] = [] for (const user of data.consumerUsers) { for (const loc of user.consumerAccount.locations) { for (const dev of loc.consumerDevices) { devices.push({ id: dev.id, name: dev.name, deviceId: dev.device.deviceId, globalDeviceType: dev.device.globalDeviceType, }) } } } return { id: data.id, firstName: data.firstName, lastName: data.lastName, contactEmail: data.contactEmail, countryCode: data.countryCode, locale: data.locale, devices, } } async getDeviceState(deviceId: string): Promise { const token = await this.getAccessToken() const { body: resBody } = await request(`https://api.firstalert.com/ris-public-api/api/v2/devices/smokeDetectors/${deviceId}/state`, { method: 'GET', headers: { Authorization: `Bearer ${token}` }, }) return await resBody.json() as ResideoDeviceState } }