UNPKG

better-auth

Version:

The most comprehensive authentication framework for TypeScript.

125 lines (124 loc) 3.62 kB
import { isJsonEqual, withEquality } from "./equality.mjs"; import { atom, onMount } from "nanostores"; //#region src/client/query.ts const isServer = () => typeof window === "undefined"; function isAuthQueryStateEqual(a, b) { return isJsonEqual(a.data, b.data) && a.error === b.error && a.isPending === b.isPending && a.isRefetching === b.isRefetching && a.refetch === b.refetch; } const useAuthQuery = (initializedAtom, path, $fetch, options) => { const value = atom({ data: null, error: null, isPending: true, isRefetching: false, refetch: (queryParams) => fn(queryParams) }); withEquality(value, isAuthQueryStateEqual); const fn = async (queryParams) => { return new Promise((resolve) => { const opts = typeof options === "function" ? options({ data: value.get().data, error: value.get().error, isPending: value.get().isPending }) : options; $fetch(path, { ...opts, query: { ...opts?.query, ...queryParams?.query }, async onSuccess(context) { const current = value.get(); const stableData = current.data != null && context.data != null && isJsonEqual(current.data, context.data) ? current.data : context.data; value.set({ data: stableData, error: null, isPending: false, isRefetching: false, refetch: value.value.refetch }); await opts?.onSuccess?.(context); }, async onError(context) { const { request } = context; const retryAttempts = typeof request.retry === "number" ? request.retry : request.retry?.attempts; const retryAttempt = request.retryAttempt || 0; if (retryAttempts && retryAttempt < retryAttempts) return; const isUnauthorized = context.error.status === 401; value.set({ error: context.error, data: isUnauthorized ? null : value.get().data, isPending: false, isRefetching: false, refetch: value.value.refetch }); await opts?.onError?.(context); }, async onRequest(context) { const currentValue = value.get(); value.set({ isPending: currentValue.data === null, data: currentValue.data, error: null, isRefetching: true, refetch: value.value.refetch }); await opts?.onRequest?.(context); } }).catch((error) => { value.set({ error, data: value.get().data, isPending: false, isRefetching: false, refetch: value.value.refetch }); }).finally(() => { resolve(void 0); }); }); }; initializedAtom = Array.isArray(initializedAtom) ? initializedAtom : [initializedAtom]; let isMountFetchPending = false; let isMounted = false; let shouldRefetchAfterPending = false; const fetchOnMount = () => { if (isMountFetchPending) { shouldRefetchAfterPending = true; return; } isMountFetchPending = true; fn().finally(() => { isMountFetchPending = false; const shouldRefetch = shouldRefetchAfterPending && isMounted; shouldRefetchAfterPending = false; if (shouldRefetch) fetchOnMount(); }); }; onMount(value, () => { if (isServer()) return; isMounted = true; let isInitialized = false; let timeoutId; const cleanups = initializedAtom.map((initAtom) => initAtom.listen(() => { if (isInitialized) fn(); else { isInitialized = true; clearTimeout(timeoutId); fetchOnMount(); } })); timeoutId = setTimeout(() => { isInitialized = true; fetchOnMount(); }, 0); return () => { isMounted = false; for (const cleanup of cleanups) cleanup(); clearTimeout(timeoutId); }; }); return value; }; //#endregion export { useAuthQuery };