2026-04-23 20:52:43 +03:00
|
|
|
import type { ListResponse } from './types';
|
2026-04-23 20:35:46 +03:00
|
|
|
|
2026-04-23 21:45:40 +03:00
|
|
|
/*
|
2026-04-23 20:35:46 +03:00
|
|
|
* Native fetch wrapper for PocketBase API requests.
|
|
|
|
|
*/
|
2026-04-23 21:45:40 +03:00
|
|
|
|
|
|
|
|
const PB_URL =
|
|
|
|
|
process.env.NEXT_PUBLIC_PB_URL ||
|
|
|
|
|
(process.env.NODE_ENV === 'production'
|
|
|
|
|
? (() => {
|
|
|
|
|
throw new Error('NEXT_PUBLIC_PB_URL is not set');
|
|
|
|
|
})()
|
|
|
|
|
: 'http://127.0.0.1:8090');
|
2026-04-23 20:35:46 +03:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Options for PocketBase collection fetching.
|
|
|
|
|
*/
|
|
|
|
|
export type PBFetchOptions = {
|
|
|
|
|
/**
|
|
|
|
|
* Sorting criteria (e.g., "-created,order")
|
|
|
|
|
*/
|
2026-04-23 20:52:43 +03:00
|
|
|
sort?: string;
|
2026-04-23 20:35:46 +03:00
|
|
|
/**
|
|
|
|
|
* Filter query string
|
|
|
|
|
*/
|
2026-04-23 20:52:43 +03:00
|
|
|
filter?: string;
|
2026-04-23 20:35:46 +03:00
|
|
|
/**
|
|
|
|
|
* Fields to expand (e.g., "stack")
|
|
|
|
|
*/
|
2026-04-23 20:52:43 +03:00
|
|
|
expand?: string;
|
|
|
|
|
};
|
2026-04-23 20:35:46 +03:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Fetch a list of records from a PocketBase collection.
|
|
|
|
|
*/
|
2026-04-23 20:52:43 +03:00
|
|
|
export async function getCollection<T>(collection: string, options: PBFetchOptions = {}): Promise<ListResponse<T>> {
|
2026-04-23 21:45:40 +03:00
|
|
|
const { sort, filter, expand } = options;
|
2026-04-23 20:35:46 +03:00
|
|
|
|
2026-04-23 20:52:43 +03:00
|
|
|
const params = new URLSearchParams();
|
2026-04-23 21:45:40 +03:00
|
|
|
if (sort) {
|
|
|
|
|
params.set('sort', sort);
|
|
|
|
|
}
|
|
|
|
|
if (filter) {
|
|
|
|
|
params.set('filter', filter);
|
|
|
|
|
}
|
|
|
|
|
if (expand) {
|
|
|
|
|
params.set('expand', expand);
|
|
|
|
|
}
|
2026-04-23 20:35:46 +03:00
|
|
|
|
2026-04-23 20:52:43 +03:00
|
|
|
const url = `${PB_URL}/api/collections/${collection}/records?${params.toString()}`;
|
2026-04-23 20:35:46 +03:00
|
|
|
|
2026-04-23 21:45:40 +03:00
|
|
|
/* force-cache deduplicates identical fetches during the static build phase;
|
|
|
|
|
* it has no runtime effect in `output: 'export'` mode. */
|
|
|
|
|
const res = await fetch(url, { cache: 'force-cache' });
|
2026-04-23 20:35:46 +03:00
|
|
|
|
|
|
|
|
if (!res.ok) {
|
2026-04-23 21:45:40 +03:00
|
|
|
throw new Error(`PocketBase ${res.status} ${res.statusText} on collection "${collection}"`);
|
2026-04-23 20:35:46 +03:00
|
|
|
}
|
|
|
|
|
|
2026-04-23 20:52:43 +03:00
|
|
|
return res.json();
|
2026-04-23 20:35:46 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2026-04-23 21:45:40 +03:00
|
|
|
* Fetch the first record matching an optional filter from a PocketBase collection.
|
2026-04-23 20:35:46 +03:00
|
|
|
*/
|
2026-04-23 20:52:43 +03:00
|
|
|
export async function getFirstRecord<T>(collection: string, options: PBFetchOptions = {}): Promise<T | null> {
|
2026-04-23 21:45:40 +03:00
|
|
|
const data = await getCollection<T>(collection, options);
|
|
|
|
|
return data.items[0] ?? null;
|
2026-04-23 20:35:46 +03:00
|
|
|
}
|