UNPKG

codalware-auth

Version:

Complete authentication system with enterprise security, attack protection, team workspaces, waitlist, billing, UI components, 2FA, and account recovery - production-ready in 5 minutes. Enhanced CLI with verification, rollback, and App Router scaffolding.

123 lines (101 loc) 3.35 kB
'use client'; import { useEffect, useMemo, useRef, useState } from 'react'; import { useI18n } from '../i18n'; import type { AuthPolicy } from '../types/auth'; type UseAuthPolicyOptions = { tenantDomain?: string; enabled?: boolean; debounce?: number; }; type UseAuthPolicyResponse = { policy: AuthPolicy | null; loading: boolean; error: string | null; tenant: string; refresh: () => void; }; const normaliseTenant = (value?: string) => value?.trim().toLowerCase() ?? ''; export const useAuthPolicy = (options: UseAuthPolicyOptions = {}): UseAuthPolicyResponse => { const { tenantDomain, enabled = true, debounce = 350 } = options; const [resolvedTenant, setResolvedTenant] = useState(''); const [requestedTenant, setRequestedTenant] = useState(() => normaliseTenant(tenantDomain)); const [policy, setPolicy] = useState<AuthPolicy | null>(null); const [loading, setLoading] = useState(false); const [error, setError] = useState<string | null>(null); const [refreshKey, setRefreshKey] = useState(0); const abortRef = useRef<AbortController | null>(null); const { t } = useI18n(); const normalisedTenant = useMemo(() => normaliseTenant(tenantDomain), [tenantDomain]); useEffect(() => { if (!enabled) { setRequestedTenant(''); return; } if (debounce <= 0) { setRequestedTenant(normalisedTenant); return; } const timer = setTimeout(() => { setRequestedTenant(normalisedTenant); }, debounce); return () => { clearTimeout(timer); }; }, [normalisedTenant, enabled, debounce]); useEffect(() => { if (!enabled) { abortRef.current?.abort(); setPolicy(null); setLoading(false); setError(null); return; } const controller = new AbortController(); abortRef.current?.abort(); abortRef.current = controller; const query = requestedTenant ? `?tenantDomain=${encodeURIComponent(requestedTenant)}` : ''; const fetchPolicy = async () => { setLoading(true); setError(null); try { const response = await fetch(`/api/auth/policy${query}`, { signal: controller.signal }); const json = await response.json(); if (!response.ok || !json?.success) { throw new Error(json?.error?.message || 'Policy request failed'); } if (!controller.signal.aborted) { setPolicy(json.data?.policy ?? null); setResolvedTenant(requestedTenant); } } catch (policyError) { if (controller.signal.aborted) return; console.warn('Unable to load auth policy', policyError); setPolicy(null); setError(t('errors.policyLoadFailed')); } finally { if (!controller.signal.aborted) { setLoading(false); } } }; fetchPolicy(); return () => { controller.abort(); }; }, [requestedTenant, enabled, refreshKey, t]); const refresh = () => { if (!enabled) { return; } setRefreshKey(current => current + 1); setRequestedTenant(normaliseTenant(tenantDomain)); }; return { policy, loading, error, tenant: resolvedTenant, refresh, }; }; export default useAuthPolicy;