astro-integration-pocketbase
Version:
An Astro integration to support developers working with astro-loader-pocketbase.
1 lines • 20.5 kB
Source Map (JSON)
{"version":3,"file":"index.mjs","names":[],"sources":["../src/core/refresh-collections.ts","../src/types/pocketbase-api-response.type.ts","../src/utils/get-superuser-token.ts","../src/utils/push-to-map-array.ts","../src/utils/map-collections-to-watch.ts","../src/core/refresh-collections-realtime.ts","../src/pocketbase-integration.ts"],"sourcesContent":["import type { BaseIntegrationHooks } from \"astro\";\n\n/**\n * Listen for the refresh event of the toolbar.\n * When the event is triggered in the toolbar, refresh the content loaded by the PocketBase loader.\n */\nexport function handleRefreshCollections({\n toolbar,\n refreshContent,\n logger\n}: Parameters<BaseIntegrationHooks[\"astro:server:setup\"]>[0]): void {\n if (!refreshContent) {\n return;\n }\n\n logger.info(\"Setting up refresh listener for PocketBase integration\");\n\n // Listen for the refresh event of the toolbar\n toolbar.on(\n \"astro-integration-pocketbase:refresh\",\n // oxlint-disable-next-line strict-void-return\n async ({ force }: { force: boolean }) => {\n // Send a loading state to the toolbar\n toolbar.send(\"astro-integration-pocketbase:refresh\", {\n loading: true\n });\n\n // Refresh content loaded by the PocketBase loader\n logger.info(\n `Refreshing ${force ? \"all \" : \"\"}content loaded by PocketBase loader`\n );\n await refreshContent({\n loaders: [\"pocketbase-loader\"],\n context: {\n source: \"astro-integration-pocketbase\",\n force\n }\n });\n\n // Reset the loading state in the toolbar\n toolbar.send(\"astro-integration-pocketbase:refresh\", {\n loading: false\n });\n }\n );\n}\n","import { z } from \"astro/zod\";\n\n/**\n * The schema for a PocketBase error response.\n */\nexport const pocketBaseErrorResponse = z.object({\n /**\n * The error message returned by PocketBase.\n */\n message: z.string()\n});\n\n/**\n * The schema for a PocketBase login response.\n */\nexport const pocketBaseLoginResponse = z.object({\n /**\n * The authentication token returned by PocketBase.\n */\n token: z.string()\n});\n","import type { AstroIntegrationLogger } from \"astro\";\nimport {\n pocketBaseErrorResponse,\n pocketBaseLoginResponse\n} from \"../types/pocketbase-api-response.type\";\n\n/**\n * This function will get a superuser token from the given PocketBase instance.\n *\n * @param url URL of the PocketBase instance\n * @param superuserCredentials Credentials of the superuser\n *\n * @returns A superuser token to access all resources of the PocketBase instance.\n */\nexport async function getSuperuserToken(\n url: string,\n superuserCredentials: {\n email: string;\n password: string;\n },\n logger: AstroIntegrationLogger\n): Promise<string | undefined> {\n // Build the URL for the login endpoint\n const loginUrl = new URL(\n `api/collections/_superusers/auth-with-password`,\n url\n ).href;\n\n // Create a new FormData object to send the login data\n const loginData = new FormData();\n loginData.set(\"identity\", superuserCredentials.email);\n loginData.set(\"password\", superuserCredentials.password);\n\n // Send the login request to get a token\n const loginRequest = await fetch(loginUrl, {\n method: \"POST\",\n body: loginData\n });\n\n // If the login request was not successful, print the error message and return undefined\n if (!loginRequest.ok) {\n if (loginRequest.status === 429) {\n const info =\n \"A rate limit was hit while trying to authenticate with PocketBase. Consider using an `impersonateToken` as credentials to avoid this issue.\";\n logger.info(info);\n\n // Random wait between 3 (default rate limit interval) and 8 seconds\n const retryAfter = Math.random() * 5 + 3;\n // oxlint-disable-next-line promise/avoid-new\n await new Promise((resolve) => {\n setTimeout(resolve, retryAfter * 1000);\n });\n\n return getSuperuserToken(url, superuserCredentials, logger);\n }\n\n const errorResponse = pocketBaseErrorResponse.parse(\n await loginRequest.json()\n );\n const errorMessage = `The given email / password for ${url} was not correct. Astro can't generate type definitions automatically and may not have access to all resources.\\nReason: ${errorResponse.message}`;\n logger.error(errorMessage);\n return undefined;\n }\n\n // Return the token\n const response = pocketBaseLoginResponse.parse(await loginRequest.json());\n return response.token;\n}\n","/**\n * Adds a value to an array in a map. If the key does not exist, it will be created.\n */\nexport function pushToMapArray<TKey, TArray>(\n map: Map<TKey, Array<TArray>>,\n key: TKey,\n value: TArray\n): void {\n const array = map.get(key);\n if (array) {\n array.push(value);\n return;\n }\n\n map.set(key, [value]);\n}\n","import type { PocketBaseIntegrationOptions } from \"../types/pocketbase-integration-options.type\";\nimport { pushToMapArray } from \"./push-to-map-array\";\n\n/**\n * Create a map of remote collections to watch.\n * Each key in the map represents a remote collection to subscribe to.\n * The value is an array of local collections that should be refreshed when an entry in the remote collection changes.\n */\nexport function mapCollectionsToWatch(\n collectionsToWatch: PocketBaseIntegrationOptions[\"collectionsToWatch\"]\n): Map<string, Array<string>> | undefined {\n // Check if collections should be watched\n if (!collectionsToWatch) {\n return undefined;\n }\n\n // Check if collectionsToWatch is an array\n if (Array.isArray(collectionsToWatch)) {\n // Check if the array is empty\n if (collectionsToWatch.length === 0) {\n return undefined;\n }\n\n // Create a map where each collection is watched by itself\n return new Map(\n collectionsToWatch.map((collection) => [collection, [collection]])\n );\n }\n\n // Check if collectionsToWatch is an empty object\n if (Object.keys(collectionsToWatch).length === 0) {\n return undefined;\n }\n\n // Map collections to watch\n const collectionsMap = new Map<string, Array<string>>();\n for (const localCollection in collectionsToWatch) {\n const watch = collectionsToWatch[localCollection];\n if (!watch) {\n continue;\n }\n\n // Check if collection should be watched by itself\n if (watch === true) {\n pushToMapArray(collectionsMap, localCollection, localCollection);\n continue;\n }\n\n // Collection should be watched by multiple collections\n for (const remoteCollection of watch) {\n pushToMapArray(collectionsMap, remoteCollection, localCollection);\n }\n }\n\n return collectionsMap;\n}\n","import type { AstroIntegrationLogger, BaseIntegrationHooks } from \"astro\";\nimport { EventSource } from \"eventsource\";\nimport type { PocketBaseIntegrationOptions } from \"../types/pocketbase-integration-options.type\";\nimport { getSuperuserToken } from \"../utils/get-superuser-token\";\nimport { mapCollectionsToWatch } from \"../utils/map-collections-to-watch\";\n\nexport function refreshCollectionsRealtime(\n options: PocketBaseIntegrationOptions,\n {\n logger,\n refreshContent,\n toolbar\n }: Parameters<BaseIntegrationHooks[\"astro:server:setup\"]>[0]\n): EventSource | undefined {\n // Check if collections should be watched\n const collectionsMap = mapCollectionsToWatch(options.collectionsToWatch);\n if (!collectionsMap) {\n return undefined;\n }\n const remoteCollections = [...collectionsMap.keys()];\n\n // Check if content loader is used\n if (!refreshContent) {\n logger.warn(\n \"No content loader available, skipping subscription to PocketBase realtime API.\"\n );\n return undefined;\n }\n\n // Check if EventSource is available\n // oxlint-disable-next-line no-unnecessary-condition\n if (!EventSource) {\n logger.warn(\n \"EventSource is not available, skipping subscription to PocketBase realtime API.\\n\" +\n \"Please install the 'eventsource' package.\"\n );\n return undefined;\n }\n\n let refreshEnabled = true;\n // Enable or disable real-time updates via the toolbar\n toolbar.on(\"astro-integration-pocketbase:real-time\", (enabled: boolean) => {\n refreshEnabled = enabled;\n });\n\n const eventSourceUrl = new URL(\"api/realtime\", options.url).href;\n const eventSource = new EventSource(eventSourceUrl);\n let wasConnectedOnce = false;\n let isConnected = false;\n\n // Log potential errors\n // oxlint-disable-next-line prefer-await-to-callbacks\n eventSource.addEventListener(\"error\", (error) => {\n isConnected = false;\n\n // Wait for 5 seconds in case of a connection error\n setTimeout(() => {\n if (isConnected) {\n // Connection was automatically re-established, no need to log the error\n return;\n }\n\n logger.error(\n `Error while connecting to PocketBase realtime API: ${error.type}`\n );\n }, 5000);\n });\n\n // Add event listeners for all collections\n for (const collection of remoteCollections) {\n eventSource.addEventListener(\n `${collection}/*`,\n async (event: MessageEvent<string>) => {\n // Do not refresh if the refresh is disabled\n if (!refreshEnabled) {\n return;\n }\n\n // Refresh the content\n logger.info(`Received update for ${collection}. Refreshing content...`);\n await refreshContent({\n loaders: [\"pocketbase-loader\"],\n context: {\n source: \"astro-integration-pocketbase\",\n collection: collectionsMap.get(collection),\n // oxlint-disable-next-line @typescript-eslint/no-unsafe-assignment\n data: JSON.parse(event.data)\n }\n });\n }\n );\n }\n\n // Add event listener for the connection event\n eventSource.addEventListener(\n \"PB_CONNECT\",\n async (event: MessageEvent<void>) => {\n isConnected = await handleConnectEvent(\n event,\n remoteCollections,\n wasConnectedOnce,\n options,\n logger\n );\n if (isConnected) {\n wasConnectedOnce = true;\n }\n }\n );\n\n return eventSource;\n}\n\nasync function handleConnectEvent(\n event: MessageEvent<void>,\n remoteCollections: Array<string>,\n wasConnectedOnce: boolean,\n options: PocketBaseIntegrationOptions,\n logger: AstroIntegrationLogger\n): Promise<boolean> {\n // Extract the clientId\n const clientId = event.lastEventId;\n\n // Get the superuser token if credentials are available\n let superuserToken: string | undefined;\n if (options.superuserCredentials) {\n if (\"impersonateToken\" in options.superuserCredentials) {\n superuserToken = options.superuserCredentials.impersonateToken;\n } else {\n superuserToken = await getSuperuserToken(\n options.url,\n options.superuserCredentials,\n logger\n );\n }\n }\n\n // Subscribe to the PocketBase realtime API\n const subscriptionUrl = new URL(\"api/realtime\", options.url).href;\n const result = await fetch(subscriptionUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: superuserToken || \"\"\n },\n body: JSON.stringify({\n clientId,\n subscriptions: remoteCollections.map((collection) => `${collection}/*`)\n })\n });\n\n // Log the connection status\n if (!result.ok) {\n logger.error(\n `Error while subscribing to PocketBase realtime API: ${result.status}`\n );\n return false;\n }\n\n if (!wasConnectedOnce) {\n logger.info(\n `Subscribed to PocketBase realtime API. Waiting for updates on ${remoteCollections.join(\n \", \"\n )}.`\n );\n }\n\n return true;\n}\n","import { fileURLToPath } from \"node:url\";\nimport type { AstroIntegration } from \"astro\";\nimport type { EventSource } from \"eventsource\";\nimport { handleRefreshCollections, refreshCollectionsRealtime } from \"./core\";\nimport type { ToolbarOptions } from \"./toolbar/types/options\";\nimport type { PocketBaseIntegrationOptions } from \"./types/pocketbase-integration-options.type\";\n\nexport function pocketbaseIntegration(\n options: PocketBaseIntegrationOptions\n): AstroIntegration {\n let eventSource: EventSource | undefined = undefined;\n let initialSetupDone = false;\n\n return {\n name: \"pocketbase-integration\",\n hooks: {\n \"astro:config:setup\": ({\n addDevToolbarApp,\n addMiddleware,\n command\n }): void => {\n // This integration is only available in dev mode\n if (command !== \"dev\") {\n return;\n }\n\n // Setup Toolbar\n addDevToolbarApp({\n name: \"PocketBase\",\n id: `pocketbase-entry`,\n icon: `<svg role=\"img\" viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\"><title>PocketBase</title><path fill=\"currentColor\" d=\"M5.684 12a.632.632 0 0 1-.631-.632V4.421c0-.349.282-.632.631-.632h2.37c.46 0 .889.047 1.287.139.407.084.758.23 1.053.44.303.202.541.475.715.82.173.335.26.75.26 1.246 0 .479-.092.894-.273 1.247a2.373 2.373 0 0 1-.715.869 3.11 3.11 0 0 1-1.053.503c-.398.11-.823.164-1.273.164h-.46a.632.632 0 0 0-.632.632v1.52a.632.632 0 0 1-.632.631Zm1.279-4.888c0 .349.283.632.632.632h.343c1.04 0 1.56-.437 1.56-1.31 0-.428-.135-.73-.404-.907-.26-.176-.645-.264-1.156-.264h-.343a.632.632 0 0 0-.632.631Zm6.3 13.098a.632.632 0 0 1-.631-.631v-6.947a.63.63 0 0 1 .631-.632h2.203c.44 0 .845.034 1.216.1.38.06.708.169.984.328.276.16.492.37.647.63.164.26.246.587.246.982 0 .185-.03.37-.09.554a1.537 1.537 0 0 1-.26.516 1.857 1.857 0 0 1-1.076.7.031.031 0 0 0-.023.03c0 .015.01.028.025.03.591.111 1.04.32 1.346.626.311.31.466.743.466 1.297 0 .42-.082.78-.246 1.083a2.153 2.153 0 0 1-.685.755 3.4 3.4 0 0 1-1.036.441 5.477 5.477 0 0 1-1.268.139zm1.271-5.542c0 .349.283.631.632.631h.21c.465 0 .802-.088 1.009-.264.207-.176.31-.424.31-.743 0-.302-.107-.516-.323-.642-.207-.135-.535-.202-.984-.202h-.222a.632.632 0 0 0-.632.632Zm0 3.463c0 .349.283.631.632.631h.39c1.019 0 1.528-.369 1.528-1.108 0-.36-.125-.621-.376-.78-.241-.16-.625-.24-1.152-.24h-.39a.632.632 0 0 0-.632.632zM1.389 0C.629 0 0 .629 0 1.389V15.03a1.4 1.4 0 0 0 1.389 1.39H8.21a.632.632 0 0 0 .63-.632.632.632 0 0 0-.63-.63H1.389c-.078 0-.125-.05-.125-.128V1.39c0-.078.047-.125.125-.125H15.03c.078 0 .127.047.127.125v6.82a.632.632 0 0 0 .631.63.632.632 0 0 0 .633-.63V1.389A1.4 1.4 0 0 0 15.032 0ZM15.79 7.578a.632.632 0 0 0-.632.633.632.632 0 0 0 .631.63h6.822c.078 0 .125.05.125.128V22.61c0 .078-.047.125-.125.125H8.97c-.077 0-.127-.047-.127-.125v-6.82a.632.632 0 0 0-.631-.63.632.632 0 0 0-.633.63v6.822A1.4 1.4 0 0 0 8.968 24h13.643c.76 0 1.389-.629 1.389-1.389V8.97a1.4 1.4 0 0 0-1.389-1.39Z\"/></svg>`,\n entrypoint: fileURLToPath(new URL(\"./toolbar\", import.meta.url))\n });\n\n // Setup middleware\n addMiddleware({\n order: \"post\",\n entrypoint: fileURLToPath(new URL(\"./middleware\", import.meta.url))\n });\n },\n \"astro:server:setup\": (setupOptions): void => {\n if (!initialSetupDone) {\n // Listen for the refresh event of the toolbar\n handleRefreshCollections(setupOptions);\n }\n\n // Subscribe to PocketBase realtime API\n if (eventSource) {\n eventSource.close();\n eventSource = undefined;\n }\n eventSource = refreshCollectionsRealtime(options, setupOptions);\n\n // Send settings to the toolbar on initialization\n setupOptions.toolbar.onAppInitialized(\"pocketbase-entry\", () => {\n setupOptions.toolbar.send(\"astro-integration-pocketbase:settings\", {\n hasContentLoader: !!setupOptions.refreshContent,\n realtime: !!eventSource,\n baseUrl: options.url\n } satisfies ToolbarOptions);\n });\n\n initialSetupDone = true;\n },\n \"astro:server:done\": ({ logger }): void => {\n // Close the EventSource connection when the server is done\n if (eventSource) {\n logger.info(\"Closing EventSource connection\");\n eventSource.close();\n eventSource = undefined;\n }\n }\n }\n };\n}\n"],"mappings":"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"}