UNPKG

@mochabug/adapt-web

Version:

The client library to execute automations, without effort, in a browser environment

173 lines 6.47 kB
import { fromBinary, toJson } from "@bufbuild/protobuf"; import { timestampDate, ValueSchema } from "@bufbuild/protobuf/wkt"; import mqtt from "mqtt"; import { OutputSchema, SessionSchema, UrlSchema, } from "./genproto/mochabugapis/adapt/automations/v1/automations_pb.js"; const mqttUrl = "wss://adapt-dev.mochabugapis.com/mqtt"; const baseUrl = "https://adapt-dev.mochabugapis.com/v1/automations"; export async function startSession(req, token) { const headers = new Headers({ "Content-Type": "application/json", "Response-Type": "application/json", }); if (token) { headers.set("Authorization", `Bearer ${token}`); } const response = await fetch(`${baseUrl}/${req.automation.organization}/${req.automation.group}/${req.automation.automation}/start`, { method: "POST", body: JSON.stringify(req), headers, }); if (!response.ok) { throw new RestClientError(response); } return await response.json(); } export async function inheritSession(automation, sessionToken) { const response = await fetch(`${baseUrl}/${automation.organization}/${automation.group}/${automation.automation}/session/inherit`, { method: "POST", body: JSON.stringify(automation), headers: { "Content-Type": "application/json", "Response-Type": "application/json", Authorization: `Bearer ${sessionToken}`, }, }); if (!response.ok) { throw new RestClientError(response); } return await response.json(); } export async function getSession(automation, sessionToken) { const response = await fetch(`${baseUrl}/${automation.organization}/${automation.group}/${automation.automation}/session/status`, { method: "GET", headers: { "Response-Type": "application/json", Authorization: `Bearer ${sessionToken}`, }, }); if (!response.ok) { throw new RestClientError(response); } return await response.json(); } export async function readOutput(automation, sessionToken) { const response = await fetch(`${baseUrl}/${automation.organization}/${automation.group}/${automation.automation}/session/output`, { method: "GET", headers: { "Response-Type": "application/json", Authorization: `Bearer ${sessionToken}`, }, }); if (!response.ok) { throw new RestClientError(response); } return await response.json(); } export async function readUrls(automation, sessionToken) { const response = await fetch(`${baseUrl}/${automation.organization}/${automation.group}/${automation.automation}/session/urls`, { method: "GET", headers: { "Response-Type": "application/json", Authorization: `Bearer ${sessionToken}`, }, }); if (!response.ok) { throw new RestClientError(response); } return await response.json(); } export async function stopSession(automation, sessionToken) { const response = await fetch(`${baseUrl}/${automation.organization}/${automation.group}/${automation.automation}/session/stop`, { method: "DELETE", headers: { Authorization: `Bearer ${sessionToken}`, }, }); if (!response.ok) { throw new RestClientError(response); } } export class RestClientError extends Error { constructor(response) { super(`HTTP Error: ${response.status} ${response.statusText}`); this.name = "RestClientError"; this.status = response.status; this.statusText = response.statusText; this.response = response; } } export class MqttClient { constructor(clientId) { this.mqttClient = null; this.clientId = clientId; this.subscribe = this.subscribe.bind(this); this.unsubscribe = this.unsubscribe.bind(this); } async subscribe(opts) { this.unsubscribe(); this.mqttClient = await mqtt.connectAsync(mqttUrl, { transformWsUrl: (url, options) => { options.password = opts.sessionToken; return url; }, clientId: this.clientId, password: opts.sessionToken, username: this.clientId, clean: false, keepalive: 20, protocolVersion: 5, }); this.mqttClient.on("error", (err) => { console.error("MQTT error", err); }); this.mqttClient.on("message", (topic, _, packet) => { if (!(packet.payload instanceof Uint8Array)) { throw new Error("Payload is not a Uint8Array. The wireformat must be binary"); } if (topic.endsWith("session")) { opts.onSession?.(toJson(SessionSchema, fromBinary(SessionSchema, packet.payload))); } else if (topic.endsWith("url")) { opts.onUrl?.(toJson(UrlSchema, fromBinary(UrlSchema, packet.payload))); } else if (topic.endsWith("output")) { const output = fromBinary(OutputSchema, packet.payload); opts.onOutput?.({ vertex: output.vertex, data: Object.fromEntries(Object.entries(output.data).map(([k, v]) => [ k, toJson(ValueSchema, v), ])), created: timestampDate(output.created), }); } else { console.error("Unknown topic", topic); } }); const baseTopic = `org/${opts.automation.organization}/ag/${opts.automation.group}/aut/${opts.automation.automation}/session/${opts.session}`; const options = { qos: 1, nl: true, rh: 0, rap: false, }; const subs = []; if (opts.onSession) { subs.push(this.mqttClient.subscribeAsync(`${baseTopic}/session`, options)); } if (opts.onUrl) { subs.push(this.mqttClient.subscribeAsync(`${baseTopic}/url`, options)); } if (opts.onOutput) { subs.push(this.mqttClient.subscribeAsync(`${baseTopic}/output`, options)); } await Promise.all(subs); } async unsubscribe() { if (this.mqttClient) { await this.mqttClient.endAsync(true); } } } //# sourceMappingURL=index.js.map