UNPKG

millheat-js

Version:

Javascript client to ease the use of the Mill Open API V2

144 lines (139 loc) 3.99 kB
import fetch, { Headers } from 'node-fetch'; import { Agent } from 'https'; class Authenticator { constructor(credentials, apiURL, agent) { this.credentials = credentials; this.apiURL = apiURL; this.agent = agent; } status = { type: "initial" }; async authenticate() { let accessToken = await this.retrieveAccessToken(); return [["Authorization", `Bearer ${accessToken.idToken}`]]; } async retrieveAccessToken() { switch (this.status.type) { case "authenticating": return await this.status.result; case "authenticated": if (Date.now() < this.status.accessToken.expireTime) { return this.status.accessToken; } } let result = this.refresh(); this.status = { type: "authenticating", result }; try { let accessToken = await result; this.status = { type: "authenticated", accessToken }; return accessToken; } catch (error) { this.status = { type: "failed", error }; return Promise.reject(error); } } async refresh() { let response = await fetch(`${this.apiURL}/customer/auth/sign-in `, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ login: this.credentials.username, password: this.credentials.password }), agent: this.agent }); let payload = await response.json(); try { let parts = payload.idToken.split("."); let decoded = JSON.parse(Buffer.from(parts[1], "base64").toString()); return { ...payload, expireTime: Date.now() + decoded.exp - decoded.iat, refreshExpireTime: Date.now() + decoded.exp - decoded.iat }; } catch (error) { return Promise.reject(error); } } } async function execute(input, init, request, timeout) { const AbortController = globalThis.AbortController || (await import('abort-controller')).default; let cancelController = new AbortController(); let cancelTimeout = setTimeout(() => { cancelController.abort(); }, timeout); let headers = new Headers(init.headers); let requestInit = { ...init, body: request ? JSON.stringify(request) : void 0, method: request ? "POST" : "GET", signal: cancelController.signal, headers }; try { let response = await fetch(input, requestInit); if (response.status === 200) { let payload = await response.json(); return payload; } return Promise.reject(new Error("Unexpected error")); } catch (error) { return Promise.reject(error); } finally { clearTimeout(cancelTimeout); } } const apiUrl = "https://api.millnorwaycloud.com"; class MillheatAPI { options; agent = new Agent({ keepAlive: true }); constructor(credential, options = {}) { this.options = { timeout: 3e4, ...options }; this.credential = credential; this.authenticator = new Authenticator(credential, apiUrl, this.agent); } async api(input, init, request) { let headers = new Headers(init ? init.headers : void 0); let authenticationHeaders = await this.authenticator.authenticate(); for (let [key, value] of authenticationHeaders) { headers.append(key, value); } let requestInit = { ...init, agent: this.agent, headers }; return execute(input, requestInit, request, this.options.timeout); } async getHouses() { let response = await this.api( `${apiUrl}/houses`, {}, null ); return response; } async getDevicesForHouse(houseId) { let response = await this.api( `${apiUrl}/houses/${houseId}/devices`, {}, null ); return response; } async getIndependentDevicesForHouse(houseId) { let response = await this.api( `${apiUrl}/houses/${houseId}/devices/independent`, {}, null ); return response; } } export { MillheatAPI as Client }; //# sourceMappingURL=millheat-js.mjs.map