108 lines
2.6 KiB
TypeScript
108 lines
2.6 KiB
TypeScript
|
/*
|
||
|
* 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<Callback> = [];
|
||
|
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<string>) {
|
||
|
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();
|
||
|
}
|
||
|
}
|