@daveyplate/better-auth-persistent
Version:
Persistent session management for Better Auth
247 lines (233 loc) • 6.46 kB
JavaScript
'use strict';
var react$1 = require('@nanostores/react');
var react$2 = require('react');
var persistent = require('@nanostores/persistent');
var SuperJSON = require('superjson');
var nanostores = require('nanostores');
var plugins = require('better-auth/client/plugins');
var react = require('better-auth/react');
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
var SuperJSON__default = /*#__PURE__*/_interopDefault(SuperJSON);
// src/hooks/use-list-device-sessions.ts
// src/empty-result.ts
var emptyResult = {
data: null,
isPending: true,
isRefetching: false,
error: null,
refetch: async () => {
}
};
var $authClient = nanostores.atom(null);
// src/stores/device-sessions.ts
var $deviceSessions = persistent.persistentAtom(
"device-sessions",
{ ...emptyResult, isPending: false },
{
encode: SuperJSON__default.default.stringify,
decode: (value) => {
const parsed = SuperJSON__default.default.parse(value);
parsed.refetch = refetchDeviceSessions;
return parsed;
}
}
);
var refetchDeviceSessions = async () => {
const authClient2 = $authClient.get();
if (!authClient2) {
console.warn("$authClient not found");
return;
}
$deviceSessions.set({
...$deviceSessions.get(),
isRefetching: true
});
const result = await authClient2.multiSession.listDeviceSessions();
if (result.error) {
$deviceSessions.set({
...$deviceSessions.get(),
isRefetching: false,
isPending: false,
error: result.error
});
} else {
$deviceSessions.set({
...$deviceSessions.get(),
data: result.data,
isRefetching: false,
isPending: false,
error: null
});
}
};
function subscribe() {
return () => {
};
}
function useIsHydrated() {
return react$2.useSyncExternalStore(
subscribe,
() => true,
() => false
);
}
// src/hooks/use-list-device-sessions.ts
function useListDeviceSessions(_) {
const isHydrated = useIsHydrated();
const store = react$1.useStore($deviceSessions);
const result = react$2.useMemo(() => {
return isHydrated ? {
...store,
data: store.data
} : emptyResult;
}, [isHydrated, store]);
return result;
}
var $persistentSession = persistent.persistentAtom(
"session",
{ ...emptyResult, isPending: false },
{
encode: SuperJSON__default.default.stringify,
decode: (value) => {
const parsed = SuperJSON__default.default.parse(value);
parsed.refetch = refetchSession;
return parsed;
}
}
);
var refetchSession = async () => {
const authClient2 = $authClient.get();
if (!authClient2) {
console.warn("$authClient not found");
return;
}
$persistentSession.set({
...$persistentSession.get(),
isRefetching: true
});
const result = await authClient2.getSession();
if (result.error) {
$persistentSession.set({
...$persistentSession.get(),
isRefetching: false,
isPending: false,
error: result.error
});
} else {
$persistentSession.set({
...$persistentSession.get(),
optimistic: false,
data: result.data,
isRefetching: false,
isPending: false,
error: null
});
}
};
// src/init-persist-session.ts
function initPersistSession(authClient2) {
if ($authClient.get()) return;
$authClient.set(authClient2);
const sessionResult = $persistentSession.get();
if (!sessionResult.data) return;
sessionResult.refetch();
}
// src/hooks/use-session.ts
function useSession(authClient2) {
const isHydrated = useIsHydrated();
const store = react$1.useStore($persistentSession);
react$2.useEffect(() => {
if (authClient2) initPersistSession(authClient2);
}, [authClient2]);
const result = react$2.useMemo(() => {
return isHydrated ? {
...store,
data: store.data
} : emptyResult;
}, [isHydrated, store]);
return result;
}
// src/subscribe-device-sessions.ts
function subscribeDeviceSessions() {
const unsubscribe = $persistentSession.subscribe(
({ isPending, isRefetching, optimistic, data }) => {
if (isPending || isRefetching || optimistic) return;
const deviceSessions = $deviceSessions.get();
if (data) {
deviceSessions.refetch();
} else {
$deviceSessions.set({
...deviceSessions,
data: null,
isPending: false,
isRefetching: false,
error: null
});
}
}
);
const checkActiveSession = () => {
const persistentSession = $persistentSession.get();
if (!persistentSession.optimistic || !persistentSession.data) return;
const authClient2 = $authClient.get();
if (!authClient2) return;
authClient2.multiSession.setActive({
sessionToken: persistentSession.data.session.token
}).then((result) => {
if (result.error) return;
persistentSession.refetch();
});
};
checkActiveSession();
window.addEventListener("online", checkActiveSession);
return () => {
unsubscribe();
window.removeEventListener("online", checkActiveSession);
};
}
// src/hooks/use-subscribe-device-sessions.ts
function useSubscribeDeviceSessions() {
react$2.useEffect(() => {
return subscribeDeviceSessions();
}, []);
}
var authClient = react.createAuthClient({
plugins: [plugins.multiSessionClient()]
});
// src/set-active-session.ts
async function setActiveSession({
sessionToken
}) {
var _a;
const deviceSessions = $deviceSessions.get();
const session = (_a = deviceSessions.data) == null ? void 0 : _a.find(
(session2) => session2.session.token === sessionToken
);
if (!session)
throw {
error: {
message: "Invalid session token",
code: "INVALID_SESSION_TOKEN"
}
};
const persistentSession = $persistentSession.get();
$persistentSession.set({
...persistentSession,
optimistic: true,
data: session,
isPending: false,
isRefetching: false,
error: null
});
authClient.multiSession.setActive({ sessionToken }).then((result) => {
if (result.error) return;
persistentSession.refetch();
});
}
exports.$authClient = $authClient;
exports.$persistentSession = $persistentSession;
exports.setActiveSession = setActiveSession;
exports.subscribeDeviceSessions = subscribeDeviceSessions;
exports.useListDeviceSessions = useListDeviceSessions;
exports.useSession = useSession;
exports.useSubscribeDeviceSessions = useSubscribeDeviceSessions;