better-auth
Version:
The most comprehensive authentication framework for TypeScript.
132 lines (131 loc) • 4.02 kB
JavaScript
import { getGlobalBroadcastChannel } from "./broadcast-channel.mjs";
import { getGlobalFocusManager } from "./focus-manager.mjs";
import { getGlobalOnlineManager } from "./online-manager.mjs";
//#region src/client/session-refresh.ts
const now = () => Math.floor(Date.now() / 1e3);
/**
* Rate limit: don't refetch on focus if a session request was made within this many seconds
*/
const FOCUS_REFETCH_RATE_LIMIT_SECONDS = 5;
function createSessionRefreshManager(opts) {
const { fetchSession, shouldPollSession = () => true, sessionSignal, options = {} } = opts;
const refetchInterval = options.sessionOptions?.refetchInterval ?? 0;
const refetchOnWindowFocus = options.sessionOptions?.refetchOnWindowFocus ?? true;
const refetchWhenOffline = options.sessionOptions?.refetchWhenOffline ?? false;
const state = {
isInitialized: false,
lastSessionRequest: 0
};
const shouldRefetch = () => {
return refetchWhenOffline || getGlobalOnlineManager().isOnline;
};
const triggerRefetch = (event) => {
if (!shouldRefetch()) return;
if (event?.event === "storage") {
fetchSession();
return;
}
if (event?.event === "poll") {
state.lastSessionRequest = now();
fetchSession();
return;
}
if (event?.event === "visibilitychange") {
if (now() - state.lastSessionRequest < FOCUS_REFETCH_RATE_LIMIT_SECONDS) return;
state.lastSessionRequest = now();
fetchSession();
return;
}
fetchSession();
};
const broadcastSessionUpdate = (trigger) => {
getGlobalBroadcastChannel().post({
event: "session",
data: { trigger },
clientId: Math.random().toString(36).substring(7)
});
};
const setupPolling = () => {
if (refetchInterval && refetchInterval > 0) state.pollInterval = setInterval(() => {
if (shouldPollSession()) triggerRefetch({ event: "poll" });
}, refetchInterval * 1e3);
};
const setupBroadcast = () => {
state.unsubscribeBroadcast = getGlobalBroadcastChannel().subscribe(() => {
triggerRefetch({ event: "storage" });
});
};
const setupFocusRefetch = () => {
if (!refetchOnWindowFocus) return;
state.unsubscribeFocus = getGlobalFocusManager().subscribe(() => {
triggerRefetch({ event: "visibilitychange" });
});
};
const setupOnlineRefetch = () => {
state.unsubscribeOnline = getGlobalOnlineManager().subscribe((online) => {
if (online) triggerRefetch({ event: "visibilitychange" });
});
};
const setupSignalSubscription = () => {
state.unsubscribeSignal = sessionSignal.listen(() => {
fetchSession();
});
};
const init = () => {
if (state.isInitialized) return;
state.isInitialized = true;
setupPolling();
setupBroadcast();
setupFocusRefetch();
setupOnlineRefetch();
setupSignalSubscription();
state.cleanupBroadcastSetup = getGlobalBroadcastChannel().setup();
state.cleanupFocusSetup = getGlobalFocusManager().setup();
state.cleanupOnlineSetup = getGlobalOnlineManager().setup();
};
const cleanup = () => {
if (!state.isInitialized) return;
if (state.pollInterval) {
clearInterval(state.pollInterval);
state.pollInterval = void 0;
}
if (state.unsubscribeBroadcast) {
state.unsubscribeBroadcast();
state.unsubscribeBroadcast = void 0;
}
if (state.unsubscribeFocus) {
state.unsubscribeFocus();
state.unsubscribeFocus = void 0;
}
if (state.unsubscribeOnline) {
state.unsubscribeOnline();
state.unsubscribeOnline = void 0;
}
if (state.unsubscribeSignal) {
state.unsubscribeSignal();
state.unsubscribeSignal = void 0;
}
if (state.cleanupBroadcastSetup) {
state.cleanupBroadcastSetup();
state.cleanupBroadcastSetup = void 0;
}
if (state.cleanupFocusSetup) {
state.cleanupFocusSetup();
state.cleanupFocusSetup = void 0;
}
if (state.cleanupOnlineSetup) {
state.cleanupOnlineSetup();
state.cleanupOnlineSetup = void 0;
}
state.isInitialized = false;
state.lastSessionRequest = 0;
};
return {
init,
cleanup,
triggerRefetch,
broadcastSessionUpdate
};
}
//#endregion
export { createSessionRefreshManager };