UNPKG

astro-loader-pocketbase

Version:

A content loader for Astro that uses the PocketBase API

117 lines (102 loc) 3.7 kB
import type { LoaderContext } from "astro/loaders"; import type { PocketBaseLoaderOptions } from "../types/pocketbase-loader-options.type"; import { parseEntry } from "./parse-entry"; /** * Load (modified) entries from a PocketBase collection. * * @param options Options for the loader. * @param context Context of the loader. * @param superuserToken Superuser token to access all resources. * @param lastModified Date of the last fetch to only update changed entries. * * @returns `true` if the collection has an updated column, `false` otherwise. */ export async function loadEntries( options: PocketBaseLoaderOptions, context: LoaderContext, superuserToken: string | undefined, lastModified: string | undefined ): Promise<void> { // Build the URL for the collections endpoint const collectionUrl = new URL( `api/collections/${options.collectionName}/records`, options.url ).href; // Create the headers for the request to append the superuser token (if available) const collectionHeaders = new Headers(); if (superuserToken) { collectionHeaders.set("Authorization", superuserToken); } // Log the fetching of the entries context.logger.info( `Fetching${lastModified ? " modified" : ""} data${ lastModified ? ` starting at ${lastModified}` : "" }${superuserToken ? " as superuser" : ""}` ); // Prepare pagination variables let page = 0; let totalPages = 0; let entries = 0; // Fetch all (modified) entries do { // Build search parameters const searchParams = new URLSearchParams({ page: `${++page}`, perPage: "100" }); const filters = []; if (lastModified && options.updatedField) { // If `lastModified` is set, only fetch entries that have been modified since the last fetch filters.push(`(${options.updatedField}>"${lastModified}")`); // Sort by the updated field and id searchParams.set("sort", `-${options.updatedField},id`); } if (options.filter) { filters.push(`(${options.filter})`); } // Add filters to search parameters if (filters.length > 0) { searchParams.set("filter", filters.join("&&")); } // Fetch entries from the collection const collectionRequest = await fetch( `${collectionUrl}?${searchParams.toString()}`, { headers: collectionHeaders } ); // If the request was not successful, print the error message and return if (!collectionRequest.ok) { // If the collection is locked, an superuser token is required if (collectionRequest.status === 403) { throw new Error( `The collection is not accessible without superuser rights. Please provide superuser credentials in the config.` ); } // Get the reason for the error const reason = await collectionRequest .json() .then((data) => data.message); const errorMessage = `Fetching data failed with status code ${collectionRequest.status}.\nReason: ${reason}`; throw new Error(errorMessage); } // Get the data from the response const response = await collectionRequest.json(); // Parse and store the entries for (const entry of response.items) { await parseEntry(entry, context, options); } // Update the page and total pages page = response.page; totalPages = response.totalPages; entries += response.items.length; } while (page < totalPages); // Log the number of fetched entries if (lastModified) { context.logger.info( `Updated ${entries}/${context.store.keys().length} entries.` ); } else { context.logger.info(`Fetched ${entries} entries.`); } }