UNPKG

astro-pocketbase-loader

Version:

A content loader for Astro that uses the PocketBase API

110 lines (96 loc) 3.73 kB
import type { LoaderContext } from "astro/loaders"; import type { PocketBaseLoaderOptions } from "./types/pocketbase-loader-options.type"; import { parseEntry } from "./utils/parse-entry"; /** * Load (modified) entries from a PocketBase collection. * * @param options Options for the loader. * @param context Context of the loader. * @param adminToken Admin 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, adminToken: string | undefined, lastModified: string | undefined ): Promise<boolean> { // 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 admin token (if available) const collectionHeaders = new Headers(); if (adminToken) { collectionHeaders.set("Authorization", adminToken); } // Log the fetching of the entries context.logger.info( `Fetching${lastModified ? " modified" : ""} data for ${ context.collection } from ${collectionUrl}${ lastModified ? ` starting at ${lastModified}` : "" }${adminToken ? " with admin token" : ""}` ); // Prepare pagination variables let page = 0; let totalPages = 0; let entries = 0; let hasUpdatedColumn = !!lastModified; // Fetch all (modified) entries do { // Fetch entries from the collection // If `lastModified` is set, only fetch entries that have been modified since the last fetch const collectionRequest = await fetch( `${collectionUrl}?page=${++page}&perPage=100${ lastModified ? `&sort=-updated,id&filter=(updated>"${lastModified}")` : "" }`, { headers: collectionHeaders } ); // If the request was not successful, print the error message and return if (!collectionRequest.ok) { // If the collection is locked, an admin token is required if (collectionRequest.status === 403) { throw new Error( `The collection ${options.collectionName} is not accessible without an admin rights. Please provide an admin email and password in the config.` ); } // Get the reason for the error const reason = await collectionRequest .json() .then((data) => data.message); const errorMessage = `Fetching data from ${options.collectionName} 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.id, options.content); // Check if the entry has an `updated` column // This is used to enable the incremental fetching of entries if (!hasUpdatedColumn && "updated" in entry) { hasUpdatedColumn = true; } } // 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 context.logger.info( `Fetched ${entries}${lastModified ? " changed" : ""} entries for ${ context.collection }` ); // Return if the collection has an updated column return hasUpdatedColumn; }