astro-loader-pocketbase
Version:
A content loader for Astro that uses the PocketBase API
67 lines (61 loc) • 1.94 kB
text/typescript
import type { LiveDataEntry } from "astro";
import { LiveCollectionValidationError } from "astro/content/runtime";
import { z } from "astro/zod";
import type { PocketBaseEntry } from "../types/pocketbase-entry.type";
import type { ExperimentalPocketBaseLiveLoaderOptions } from "../types/pocketbase-loader-options.type";
/**
* Converts a PocketBase entry into a LiveDataEntry for Astro, extracting content and cache metadata.
*/
export function parseLiveEntry<TEntry extends PocketBaseEntry>(
entry: TEntry,
options: ExperimentalPocketBaseLiveLoaderOptions
): LiveDataEntry<TEntry> {
// Build a cache tag
const tag = `${options.collectionName}-${entry.id}`;
let lastModified: Date | undefined = undefined;
// If an updated field is provided and the entry has a valid date value,
// use it as the last modified date cache hint
if (options.updatedField && entry[options.updatedField]) {
const value = `${entry[options.updatedField]}`;
const date = z.coerce.date().safeParse(value);
if (!date.success) {
throw new LiveCollectionValidationError(
options.collectionName,
entry.id,
date.error
);
}
lastModified = date.data;
}
if (!options.contentFields) {
return {
id: entry.id,
data: entry,
cacheHint: {
tags: [tag],
lastModified
}
};
}
let content: string;
if (typeof options.contentFields === "string") {
// If a single content field is provided, use it directly
content = `${entry[options.contentFields]}`;
} else {
// If multiple content fields are provided, concatenate them with `<section>` tags
content = options.contentFields
.map((field) => `<section id="${field}">${entry[field]}</section>`)
.join("");
}
return {
id: entry.id,
data: entry,
rendered: {
html: content
},
cacheHint: {
tags: [tag],
lastModified
}
};
}