@parkingboss/api
Version:
The Parking Boss API
120 lines (119 loc) • 3.99 kB
JavaScript
import { buildLoginUrl } from "./urls";
import { loadUser, setUser, unsetUser, jwtUser } from "./loadUser";
export function session(settings) {
settings.user = loadUser();
const user = userStore(settings);
const validUser = validUserStore(user);
return Object.assign({
user,
validUser,
isLoggedIn: () => isLoggedIn(settings),
logIn: (email, password) => email && password ? logIn(settings, user.set, email, password) : logIn(settings, user.set),
renew: (password) => renew(settings, user.set, password),
requestPasswordReset: (email) => requestPasswordReset(settings, email),
logOut: () => logOut(user.set),
});
}
function userStore(settings) {
const subscribers = new Set();
function notifyUserChanged(user) {
subscribers.forEach((fn) => fn(user));
}
function subscribe(fn) {
fn(settings.user);
subscribers.add(fn);
return () => subscribers.delete(fn);
}
return {
subscribe,
set(user) {
settings.user = user;
if (user) {
setUser(user);
}
else {
unsetUser();
}
notifyUserChanged(user);
},
};
}
function validUserStore(user) {
return {
subscribe(fn) {
let timeout = null;
const unsub = user.subscribe((currentUser) => {
if (timeout != null) {
clearTimeout(timeout);
timeout = null;
}
if (isValidUser(currentUser)) {
fn(currentUser);
const msToExpiry = +currentUser.expires - Date.now();
timeout = setTimeout(() => {
fn(null);
timeout = null;
}, msToExpiry);
}
else {
fn(null);
}
});
return () => {
if (timeout != null) {
clearTimeout(timeout);
}
unsub();
};
},
};
}
async function logIn(settings, setUser, email, password) {
if (email && password) {
const url = new URL(settings.apiBase + "/auth/tokens");
url.searchParams.set("lifetime", "P7D");
url.searchParams.set("email", email);
url.searchParams.set("ts", new Date().toISOString());
const body = new FormData();
body.set("email", email);
body.set("password", password);
const result = await self.fetch(url.toString(), { method: "POST", body });
const responseBody = await result.json();
if (result.ok) {
setUser(jwtUser(responseBody));
return responseBody;
}
return responseBody;
}
const loginParams = { clientId: settings.client };
if (settings.user?.email) {
loginParams.email = settings.user.email;
}
window.location.href = buildLoginUrl(loginParams);
}
async function requestPasswordReset(settings, email) {
if (!email)
throw new Error("Email must be provided.");
const url = new URL(settings.apiBase + "/auth/tokens/email");
url.searchParams.set("ts", new Date().toISOString());
const body = new FormData();
body.set("email", email);
const result = await self.fetch(url.toString(), { method: "POST", body });
const responseBody = await result.json();
return responseBody;
}
function isLoggedIn(settings) {
return isValidUser(settings.user);
}
function isValidUser(user) {
return !!(user && (!user.expires || user.expires > new Date()));
}
async function logOut(setUser) {
setUser(null);
}
function renew(settings, setUser, password) {
if (!settings.user?.email) {
throw new Error("Use logIn. Cannot log in without current user data.");
}
return logIn(settings, setUser, settings.user.email, password);
}