UNPKG

@convex-dev/better-auth

Version:
176 lines 6.29 kB
export function parseSetCookieHeader(header) { const cookieMap = new Map(); const cookies = header.split(", "); cookies.forEach((cookie) => { const [nameValue, ...attributes] = cookie.split("; "); const [name, value] = nameValue.split("="); const cookieObj = { value }; attributes.forEach((attr) => { const [attrName, attrValue] = attr.split("="); cookieObj[attrName.toLowerCase()] = attrValue; }); cookieMap.set(name, cookieObj); }); return cookieMap; } export function getSetCookie(header, prevCookie) { const parsed = parseSetCookieHeader(header); let toSetCookie = {}; parsed.forEach((cookie, key) => { const expiresAt = cookie["expires"]; const maxAge = cookie["max-age"]; const expires = expiresAt ? new Date(String(expiresAt)) : maxAge ? new Date(Date.now() + Number(maxAge) * 1000) : null; toSetCookie[key] = { value: cookie["value"], expires, }; }); if (prevCookie) { try { const prevCookieParsed = JSON.parse(prevCookie); toSetCookie = { ...prevCookieParsed, ...toSetCookie, }; } catch { // } } return JSON.stringify(toSetCookie); } export function getCookie(cookie) { let parsed = {}; try { parsed = JSON.parse(cookie); } catch { // noop } const toSend = Object.entries(parsed).reduce((acc, [key, value]) => { if (value.expires && value.expires < new Date()) { return acc; } return `${acc}; ${key}=${value.value}`; }, ""); return toSend; } export const crossDomainClient = (opts = {}) => { let store = null; const cookieName = `${opts?.storagePrefix || "better-auth"}_cookie`; const localCacheName = `${opts?.storagePrefix || "better-auth"}_session_data`; const storage = opts?.storage || (typeof window !== "undefined" ? localStorage : undefined); return { id: "cross-domain", $InferServerPlugin: {}, getActions(_, $store) { store = $store; return { /** * Get the stored cookie. * * You can use this to get the cookie stored in the device and use it in your fetch * requests. * * @example * ```ts * const cookie = client.getCookie(); * fetch("https://api.example.com", { * headers: { * cookie, * }, * }); */ getCookie: () => { const cookie = storage?.getItem(cookieName); return getCookie(cookie || "{}"); }, /** * Notify the session signal. * * This is used to trigger an update in useSession, generally when a new session * token is set. * * @example * ```ts * client.notifySessionSignal(); * ``` */ updateSession: () => { $store.notify("$sessionSignal"); }, /** * Get the stored session data. * * @example * ```ts * const sessionData = client.getSessionData(); * ``` */ getSessionData: () => { const sessionData = storage?.getItem(localCacheName); return sessionData ? JSON.parse(sessionData) : null; }, }; }, fetchPlugins: [ { id: "convex", name: "Convex", hooks: { async onSuccess(context) { if (!storage) { return; } const setCookie = context.response.headers.get("set-better-auth-cookie"); if (setCookie) { const prevCookie = await storage.getItem(cookieName); const toSetCookie = getSetCookie(setCookie || "", prevCookie ?? undefined); await storage.setItem(cookieName, toSetCookie); store?.notify("$sessionSignal"); } if (context.request.url.toString().includes("/get-session") && !opts?.disableCache) { const data = context.data; storage.setItem(localCacheName, JSON.stringify(data)); } }, }, async init(url, options) { if (!storage) { return { url, options: options, }; } options = options || {}; const storedCookie = storage.getItem(cookieName); const cookie = getCookie(storedCookie || "{}"); options.credentials = "omit"; options.headers = { ...options.headers, "Better-Auth-Cookie": cookie, }; if (url.includes("/sign-out")) { await storage.setItem(cookieName, "{}"); store?.atoms.session?.set({ data: null, error: null, isPending: false, }); storage.setItem(localCacheName, "{}"); } return { url, options: options, }; }, }, ], }; }; //# sourceMappingURL=client.js.map