/* * Contains all of the logic for interacting with JMAP * None of the dependencies should leak, in types or otherwise */ import * as base64 from "base-64"; import * as jmapclient from "jmap-client-ts"; import { FetchTransport } from "jmap-client-ts/lib/utils/fetch-transport"; import { IAccount, ISession } from "./types"; type Callback = () => void; export interface IAuth { email: string; password: string; } export interface ClientState { session: ISession | null; } export default class Client { // Get the currently active account account(accountId: string): IAccount | null { if (!(this.state.session && this.state.session.accounts)) return null; return this.state.session.accounts[accountId]; } // All objects which currently are listening for changes callbacks: Array = []; jclient: jmapclient.Client | null = null; state: ClientState = { session: null, }; onChange(f: Callback) { this.callbacks.push(f); } // Ensure that login happens. If this is called many times, only login once. ensureLogin(auth: IAuth) { if (this.jclient != null) return; this.doLogin(auth); } // Make the request to get system metadata doLogin(auth: IAuth) { const domain = auth.email.split("@")[1]; const well_known_url = "https://" + domain + "/.well-known/jmap"; const basic_auth = "Basic " + base64.encode(auth.email + ":" + auth.password); this.jclient = new jmapclient.Client({ accessToken: "fake token", httpHeaders: { Authorization: basic_auth }, sessionUrl: well_known_url, transport: new FetchTransport(fetch.bind(window)), }); this.jclient .fetchSession() .then(() => { this._onSession(); }) .catch((error) => console.error(error)); return; } mailboxList(accountId: string, ids: Array) { if (this.jclient == null) return; this.jclient .mailbox_get({ accountId: accountId, ids: null, }) .then((response) => { if (this.state.session == null) return; const account = this.state.session.accounts[response.accountId]; account.mailboxes = response.list; this._triggerChange(); }); } _triggerChange() { this.callbacks.forEach((c) => { c(); }); } _onSession() { console.log("Session received"); // For the type checker if (!this.jclient) return; const session = this.jclient.getSession(); this.state.session = { ...session, accounts: Object.fromEntries( Object.entries(session.accounts).map(([key, account]) => [ key, { ...account, id: key.toString(), mailboxes: [] }, ]), ), }; if (!this.state.session) return; this._triggerChange(); } }