UNPKG

astro-integration-pocketbase

Version:

An Astro integration to support developers working with astro-loader-pocketbase.

141 lines (123 loc) 3.98 kB
import type { BaseIntegrationHooks } from "astro"; import { EventSource } from "eventsource"; import type { PocketBaseIntegrationOptions } from "../types/pocketbase-integration-options.type"; import { getSuperuserToken } from "../utils/get-superuser-token"; import { mapCollectionsToWatch } from "../utils/map-collections-to-watch"; export function refreshCollectionsRealtime( { url, superuserCredentials, collectionsToWatch }: PocketBaseIntegrationOptions, { logger, refreshContent, toolbar }: Parameters<BaseIntegrationHooks["astro:server:setup"]>[0] ): EventSource | undefined { // Check if collections should be watched const collectionsMap = mapCollectionsToWatch(collectionsToWatch); if (!collectionsMap) { return undefined; } const remoteCollections = [...collectionsMap.keys()]; // Check if content loader is used if (!refreshContent) { logger.warn( "No content loader available, skipping subscription to PocketBase realtime API." ); return undefined; } // Check if EventSource is available if (!EventSource) { logger.warn( "EventSource is not available, skipping subscription to PocketBase realtime API.\n" + "Please install the 'eventsource' package." ); return undefined; } let refreshEnabled = true; // Enable or disable real-time updates via the toolbar toolbar.on("astro-integration-pocketbase:real-time", (enabled: boolean) => { refreshEnabled = enabled; }); const eventSource = new EventSource(`${url}/api/realtime`); let wasConnectedOnce = false; let isConnected = false; // Log potential errors eventSource.onerror = (error): void => { isConnected = false; // Wait for 5 seconds in case of a connection error setTimeout(() => { if (isConnected) { // Connection was automatically re-established, no need to log the error return; } logger.error( `Error while connecting to PocketBase realtime API: ${error.type}` ); }, 5000); }; // Add event listeners for all collections for (const collection of remoteCollections) { eventSource.addEventListener(`${collection}/*`, async (event) => { // Do not refresh if the refresh is disabled if (!refreshEnabled) { return; } // Refresh the content logger.info(`Received update for ${collection}. Refreshing content...`); await refreshContent({ loaders: ["pocketbase-loader"], context: { source: "astro-integration-pocketbase", collection: collectionsMap.get(collection), data: JSON.parse(event.data) } }); }); } // Add event listener for the connection event eventSource.addEventListener("PB_CONNECT", async (event) => { // Extract the clientId const clientId = event.lastEventId; // Get the superuser token if credentials are available let superuserToken: string | undefined; if (superuserCredentials) { superuserToken = await getSuperuserToken( url, superuserCredentials, logger ); } // Subscribe to the PocketBase realtime API const result = await fetch(`${url}/api/realtime`, { method: "POST", headers: { "Content-Type": "application/json", Authorization: superuserToken || "" }, body: JSON.stringify({ clientId: clientId, subscriptions: remoteCollections.map((collection) => `${collection}/*`) }) }); // Log the connection status if (!result.ok) { logger.error( `Error while subscribing to PocketBase realtime API: ${result.status}` ); return; } if (!wasConnectedOnce) { wasConnectedOnce = true; logger.info( `Subscribed to PocketBase realtime API. Waiting for updates on ${remoteCollections.join( ", " )}.` ); } isConnected = true; }); return eventSource; }