Menu
Public repository / 4f0b1d374fab4075f2b552b5f250bca5f28afee9
AkurAI-Mail / src/framework/api.js
Latest change 3af23b0e937520000e1aa43c7e2eb9de2675abd1 - OLI-248: webmail list and reader as framework islands on a signals store by Ólafur Búi Ólafsson
// api.js — the webmail API client (plain ESM). Mirrors the SvelteKit-era src/lib/api.ts:
// same-origin fetch, a 401 sends the browser to the IdP and never settles.
/**
* The IdP login route, returning to `returnTo` afterwards.
* @param {string} returnTo
*/
export function loginUrl(returnTo) {
return `/auth/login?return_to=${encodeURIComponent(returnTo)}`;
}
/**
* @typedef {(input: RequestInfo | URL, init?: RequestInit) => Promise<Response>} FetchLike
* @typedef {{ fetch?: FetchLike, navigate?: (url: string) => void, location?: { pathname: string } }} ApiOptions
*/
/**
* @param {ApiOptions} [options]
*/
export function createApi({ fetch: doFetch = (...args) => fetch(...args), navigate = (url) => { window.location.href = url; }, location = window.location } = {}) {
/**
* @param {string} path
* @param {RequestInit} [init]
* @returns {Promise<any>}
*/
async function api(path, init) {
const res = await doFetch(path, { credentials: "same-origin", ...init });
if (res.status === 401) {
navigate(loginUrl(location.pathname));
// The page is navigating away; never settle so callers do not render a half-loaded state.
return new Promise(() => {});
}
return res.json();
}
/**
* @param {string} path
* @param {unknown} body
*/
const post = (path, body) => api(path, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(body) });
return {
api,
post,
/** @param {Record<string, string>} params */
mailbox: (params) => doFetch(`/api/webmail?${new URLSearchParams(params)}`, { credentials: "same-origin" }),
/** @param {Record<string, unknown>} body */
webmail: (body) => doFetch("/api/webmail", { method: "POST", credentials: "same-origin", headers: { "content-type": "application/json" }, body: JSON.stringify(body) }),
};
}