mega-plant/lib/pb.ts

49 lines
1.8 KiB
TypeScript
Raw Normal View History

import PocketBase from "pocketbase";
2026-09-12 10:05:43 +00:00
// 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<boolean> {
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;
}