import PocketBase from "pocketbase"; // No fallback on purpose. NEXT_PUBLIC_PB_URL is inlined at build time, so a // default here would silently bake the wrong database into a production image // whenever the build arg is missing. Better to fail at startup than to serve // someone else's data. The Dockerfile checks for it before building too. export const PB_URL = process.env.NEXT_PUBLIC_PB_URL ?? ""; if (!PB_URL) { throw new Error( "NEXT_PUBLIC_PB_URL is not set. Set it in .env.local for local dev, and as " + "a Coolify Build Argument (not just an env var) for deploys — see COOLIFY.md.", ); } // Lazy singleton — the browser SDK auto-cancels in-flight requests when the // client is recreated, so we keep one instance for the whole browser session. let _pb: PocketBase | null = null; export function getPB(): PocketBase { if (!_pb) { _pb = new PocketBase(PB_URL); _pb.autoCancellation(false); // critical for SSR + parallel fetches } return _pb; } export async function isSuperuserLoggedIn(): Promise { const pb = getPB(); return pb.authStore.isValid && pb.authStore.record?.collectionName === "_superusers"; } // Server-only auth helper used by server components / route handlers. // Part 5.3: PocketBase 0.23+ renamed the admin collection to `_superusers`. // `pb.admins.authWithPassword()` is deprecated — use the collection endpoint instead. export async function serverAuth() { const pb = new PocketBase(PB_URL); pb.autoCancellation(false); const email = process.env.PB_ADMIN; const pass = process.env.PB_PASS; if (!email || !pass) return pb; if (pb.authStore.isValid) return pb; try { await pb.collection("_superusers").authWithPassword(email, pass); } catch { // ignore — read endpoints still work with superuser token-less for open rules } return pb; }