RJBULK-APP/lib/pocketbase.ts
SJCoetz 1efa979443 feat: initial setup of rj bulk supplies backoffice app
Adds complete initial codebase for the RJ Bulk Supplies fuel delivery backoffice:
- Authentication pages and protected route layouts
- Customer, supplier, fuel purchase, and delivery note management
- Custom reporting and customer statement sending tools
- Full UI component library and Tailwind styling
- Server actions, API routes, and PocketBase integration
- Development scripts and project configuration updates
- Updated README and package metadata
2026-07-19 20:38:16 +02:00

123 lines
3.9 KiB
TypeScript

import { cookies } from "next/headers";
import PocketBase from "pocketbase";
export const PB_URL =
process.env.POCKETBASE_URL ||
"http://pocketbase-zinlbpsext2ro0lgb2558vfy.169.239.180.130.sslip.io";
/**
* Plain fetch helper for RSC — avoids the PB SDK's auto-cancel wrapper.
*/
async function pbFetch(path: string, token?: string, init?: RequestInit) {
const res = await fetch(`${PB_URL}${path}`, {
...init,
headers: {
"Content-Type": "application/json",
...(token ? { Authorization: token } : {}),
...(init?.headers || {}),
},
cache: "no-store",
});
if (!res.ok) {
const text = await res.text();
throw new Error(`PB ${init?.method || "GET"} ${path} failed: ${res.status} ${text}`);
}
return res.json();
}
/**
* Get a PB client pre-loaded with the user's auth token from the cookie.
* Use this for actions/route handlers; for RSC use pbFetch() directly.
*/
export async function getServerPB() {
const cookieStore = await cookies();
const cookie = cookieStore.get("pb_auth");
const pb = new PocketBase(PB_URL);
if (cookie?.value) {
pb.authStore.save(cookie.value, null);
}
return pb;
}
/**
* Browser-side PB (realtime subscriptions, etc.)
*/
export function getBrowserPB() {
return new PocketBase(PB_URL);
}
/**
* PB record list response shape (subset we use).
*/
export interface PBList<T = any> {
items: T[];
page: number;
perPage: number;
totalItems: number;
totalPages: number;
}
/**
* Server-side PB helpers using plain fetch (RSC-safe).
*/
export async function pbList<T = any>(
collection: string,
opts: { page?: number; perPage?: number; filter?: string; sort?: string; fields?: string; expand?: string } = {},
token?: string,
): Promise<PBList<T>> {
const params = new URLSearchParams();
if (opts.page) params.set("page", String(opts.page));
if (opts.perPage) params.set("perPage", String(opts.perPage));
if (opts.filter) params.set("filter", opts.filter);
if (opts.sort) params.set("sort", opts.sort);
if (opts.fields) params.set("fields", opts.fields);
if (opts.expand) params.set("expand", opts.expand);
return pbFetch(`/api/collections/${collection}/records?${params}`, token);
}
/**
* Auto-paginated version of pbList. PB caps perPage at 1000 server-side,
* so for collections with >1000 records this is the only way to get them all.
* Loops server-side pagination until every page is consumed.
*/
export async function pbListAll<T = any>(
collection: string,
opts: { filter?: string; sort?: string; fields?: string; expand?: string; perPage?: number } = {},
token?: string,
): Promise<T[]> {
const perPage = opts.perPage ?? 1000;
const out: T[] = [];
let page = 1;
// Safety cap at 50 pages (50,000 records) — adjust if you have more
for (let i = 0; i < 50; i++) {
const res = await pbList<T>(collection, { ...opts, page, perPage }, token);
out.push(...res.items);
if (page >= res.totalPages) break;
page++;
}
return out;
}
export async function pbGet<T = any>(collection: string, id: string, expand?: string, token?: string): Promise<T> {
const params = new URLSearchParams();
if (expand) params.set("expand", expand);
return pbFetch(`/api/collections/${collection}/records/${id}?${params}`, token);
}
export async function pbCreate<T = any>(collection: string, body: any, token?: string): Promise<T> {
return pbFetch(`/api/collections/${collection}/records`, token, {
method: "POST",
body: JSON.stringify(body),
});
}
export async function pbUpdate<T = any>(collection: string, id: string, body: any, token?: string): Promise<T> {
return pbFetch(`/api/collections/${collection}/records/${id}`, token, {
method: "PATCH",
body: JSON.stringify(body),
});
}
export async function pbDelete(collection: string, id: string, token?: string): Promise<void> {
await pbFetch(`/api/collections/${collection}/records/${id}`, token, { method: "DELETE" });
}