full site update
This commit is contained in:
20
node_modules/astro/dist/content/loaders/errors.d.ts
generated
vendored
Normal file
20
node_modules/astro/dist/content/loaders/errors.d.ts
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
import type { ZodError } from 'zod';
|
||||
export declare class LiveCollectionError extends Error {
|
||||
readonly collection: string;
|
||||
readonly message: string;
|
||||
readonly cause?: Error | undefined;
|
||||
constructor(collection: string, message: string, cause?: Error | undefined);
|
||||
static is(error: unknown): error is LiveCollectionError;
|
||||
}
|
||||
export declare class LiveEntryNotFoundError extends LiveCollectionError {
|
||||
constructor(collection: string, entryFilter: string | Record<string, unknown>);
|
||||
static is(error: unknown): error is LiveEntryNotFoundError;
|
||||
}
|
||||
export declare class LiveCollectionValidationError extends LiveCollectionError {
|
||||
constructor(collection: string, entryId: string, error: ZodError);
|
||||
static is(error: unknown): error is LiveCollectionValidationError;
|
||||
}
|
||||
export declare class LiveCollectionCacheHintError extends LiveCollectionError {
|
||||
constructor(collection: string, entryId: string | undefined, error: ZodError);
|
||||
static is(error: unknown): error is LiveCollectionCacheHintError;
|
||||
}
|
67
node_modules/astro/dist/content/loaders/errors.js
generated
vendored
Normal file
67
node_modules/astro/dist/content/loaders/errors.js
generated
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
class LiveCollectionError extends Error {
|
||||
constructor(collection, message, cause) {
|
||||
super(message);
|
||||
this.collection = collection;
|
||||
this.message = message;
|
||||
this.cause = cause;
|
||||
this.name = "LiveCollectionError";
|
||||
if (cause?.stack) {
|
||||
this.stack = cause.stack;
|
||||
}
|
||||
}
|
||||
static is(error) {
|
||||
return error instanceof LiveCollectionError;
|
||||
}
|
||||
}
|
||||
class LiveEntryNotFoundError extends LiveCollectionError {
|
||||
constructor(collection, entryFilter) {
|
||||
super(
|
||||
collection,
|
||||
`Entry ${collection} \u2192 ${typeof entryFilter === "string" ? entryFilter : JSON.stringify(entryFilter)} was not found.`
|
||||
);
|
||||
this.name = "LiveEntryNotFoundError";
|
||||
}
|
||||
static is(error) {
|
||||
return error?.name === "LiveEntryNotFoundError";
|
||||
}
|
||||
}
|
||||
class LiveCollectionValidationError extends LiveCollectionError {
|
||||
constructor(collection, entryId, error) {
|
||||
super(
|
||||
collection,
|
||||
[
|
||||
`**${collection} \u2192 ${entryId}** data does not match the collection schema.
|
||||
`,
|
||||
...error.errors.map((zodError) => ` **${zodError.path.join(".")}**: ${zodError.message}`),
|
||||
""
|
||||
].join("\n")
|
||||
);
|
||||
this.name = "LiveCollectionValidationError";
|
||||
}
|
||||
static is(error) {
|
||||
return error?.name === "LiveCollectionValidationError";
|
||||
}
|
||||
}
|
||||
class LiveCollectionCacheHintError extends LiveCollectionError {
|
||||
constructor(collection, entryId, error) {
|
||||
super(
|
||||
collection,
|
||||
[
|
||||
`**${String(collection)}${entryId ? ` \u2192 ${String(entryId)}` : ""}** returned an invalid cache hint.
|
||||
`,
|
||||
...error.errors.map((zodError) => ` **${zodError.path.join(".")}**: ${zodError.message}`),
|
||||
""
|
||||
].join("\n")
|
||||
);
|
||||
this.name = "LiveCollectionCacheHintError";
|
||||
}
|
||||
static is(error) {
|
||||
return error?.name === "LiveCollectionCacheHintError";
|
||||
}
|
||||
}
|
||||
export {
|
||||
LiveCollectionCacheHintError,
|
||||
LiveCollectionError,
|
||||
LiveCollectionValidationError,
|
||||
LiveEntryNotFoundError
|
||||
};
|
12
node_modules/astro/dist/content/loaders/file.d.ts
generated
vendored
12
node_modules/astro/dist/content/loaders/file.d.ts
generated
vendored
@@ -1,7 +1,15 @@
|
||||
import type { Loader } from './types.js';
|
||||
interface FileOptions {
|
||||
/**
|
||||
* the parsing function to use for this data
|
||||
* @default JSON.parse or yaml.load, depending on the extension of the file
|
||||
* */
|
||||
parser?: (text: string) => Record<string, Record<string, unknown>> | Array<Record<string, unknown>>;
|
||||
}
|
||||
/**
|
||||
* Loads entries from a JSON file. The file must contain an array of objects that contain unique `id` fields, or an object with string keys.
|
||||
* @todo Add support for other file types, such as YAML, CSV etc.
|
||||
* @param fileName The path to the JSON file to load, relative to the content directory.
|
||||
* @param options Additional options for the file loader
|
||||
*/
|
||||
export declare function file(fileName: string): Loader;
|
||||
export declare function file(fileName: string, options?: FileOptions): Loader;
|
||||
export {};
|
||||
|
62
node_modules/astro/dist/content/loaders/file.js
generated
vendored
62
node_modules/astro/dist/content/loaders/file.js
generated
vendored
@@ -1,43 +1,72 @@
|
||||
import { promises as fs, existsSync } from "node:fs";
|
||||
import { existsSync, promises as fs } from "node:fs";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import yaml from "js-yaml";
|
||||
import toml from "smol-toml";
|
||||
import { FileGlobNotSupported, FileParserNotFound } from "../../core/errors/errors-data.js";
|
||||
import { AstroError } from "../../core/errors/index.js";
|
||||
import { posixRelative } from "../utils.js";
|
||||
function file(fileName) {
|
||||
function file(fileName, options) {
|
||||
if (fileName.includes("*")) {
|
||||
throw new Error("Glob patterns are not supported in `file` loader. Use `glob` loader instead.");
|
||||
throw new AstroError(FileGlobNotSupported);
|
||||
}
|
||||
let parse = null;
|
||||
const ext = fileName.split(".").at(-1);
|
||||
if (ext === "json") {
|
||||
parse = JSON.parse;
|
||||
} else if (ext === "yml" || ext === "yaml") {
|
||||
parse = (text) => yaml.load(text, {
|
||||
filename: fileName
|
||||
});
|
||||
} else if (ext === "toml") {
|
||||
parse = toml.parse;
|
||||
}
|
||||
if (options?.parser) parse = options.parser;
|
||||
if (parse === null) {
|
||||
throw new AstroError({
|
||||
...FileParserNotFound,
|
||||
message: FileParserNotFound.message(fileName)
|
||||
});
|
||||
}
|
||||
async function syncData(filePath, { logger, parseData, store, config }) {
|
||||
let json;
|
||||
let data;
|
||||
try {
|
||||
const data = await fs.readFile(filePath, "utf-8");
|
||||
json = JSON.parse(data);
|
||||
const contents = await fs.readFile(filePath, "utf-8");
|
||||
data = parse(contents);
|
||||
} catch (error) {
|
||||
logger.error(`Error reading data from ${fileName}`);
|
||||
logger.debug(error.message);
|
||||
return;
|
||||
}
|
||||
const normalizedFilePath = posixRelative(fileURLToPath(config.root), filePath);
|
||||
if (Array.isArray(json)) {
|
||||
if (json.length === 0) {
|
||||
if (Array.isArray(data)) {
|
||||
if (data.length === 0) {
|
||||
logger.warn(`No items found in ${fileName}`);
|
||||
}
|
||||
logger.debug(`Found ${json.length} item array in ${fileName}`);
|
||||
logger.debug(`Found ${data.length} item array in ${fileName}`);
|
||||
store.clear();
|
||||
for (const rawItem of json) {
|
||||
const idList = /* @__PURE__ */ new Set();
|
||||
for (const rawItem of data) {
|
||||
const id = (rawItem.id ?? rawItem.slug)?.toString();
|
||||
if (!id) {
|
||||
logger.error(`Item in ${fileName} is missing an id or slug field.`);
|
||||
continue;
|
||||
}
|
||||
const data = await parseData({ id, data: rawItem, filePath });
|
||||
store.set({ id, data, filePath: normalizedFilePath });
|
||||
if (idList.has(id)) {
|
||||
logger.warn(
|
||||
`Duplicate id "${id}" found in ${fileName}. Later items with the same id will overwrite earlier ones.`
|
||||
);
|
||||
}
|
||||
idList.add(id);
|
||||
const parsedData = await parseData({ id, data: rawItem, filePath });
|
||||
store.set({ id, data: parsedData, filePath: normalizedFilePath });
|
||||
}
|
||||
} else if (typeof json === "object") {
|
||||
const entries = Object.entries(json);
|
||||
} else if (typeof data === "object") {
|
||||
const entries = Object.entries(data);
|
||||
logger.debug(`Found object with ${entries.length} entries in ${fileName}`);
|
||||
store.clear();
|
||||
for (const [id, rawItem] of entries) {
|
||||
const data = await parseData({ id, data: rawItem, filePath });
|
||||
store.set({ id, data, filePath: normalizedFilePath });
|
||||
const parsedData = await parseData({ id, data: rawItem, filePath });
|
||||
store.set({ id, data: parsedData, filePath: normalizedFilePath });
|
||||
}
|
||||
} else {
|
||||
logger.error(`Invalid data in ${fileName}. Must be an array or object.`);
|
||||
@@ -55,6 +84,7 @@ function file(fileName) {
|
||||
}
|
||||
const filePath = fileURLToPath(url);
|
||||
await syncData(filePath, context);
|
||||
watcher?.add(filePath);
|
||||
watcher?.on("change", async (changedPath) => {
|
||||
if (changedPath === filePath) {
|
||||
logger.info(`Reloading data from ${fileName}`);
|
||||
|
12
node_modules/astro/dist/content/loaders/glob.d.ts
generated
vendored
12
node_modules/astro/dist/content/loaders/glob.d.ts
generated
vendored
@@ -1,5 +1,5 @@
|
||||
import type { Loader } from './types.js';
|
||||
export interface GenerateIdOptions {
|
||||
interface GenerateIdOptions {
|
||||
/** The path to the entry file, relative to the base directory. */
|
||||
entry: string;
|
||||
/** The base directory URL. */
|
||||
@@ -7,9 +7,9 @@ export interface GenerateIdOptions {
|
||||
/** The parsed, unvalidated data of the entry. */
|
||||
data: Record<string, unknown>;
|
||||
}
|
||||
export interface GlobOptions {
|
||||
interface GlobOptions {
|
||||
/** The glob pattern to match files, relative to the base directory */
|
||||
pattern: string;
|
||||
pattern: string | Array<string>;
|
||||
/** The base directory to resolve the glob pattern from. Relative to the root directory, or an absolute file URL. Defaults to `.` */
|
||||
base?: string | URL;
|
||||
/**
|
||||
@@ -23,3 +23,9 @@ export interface GlobOptions {
|
||||
* @param pattern A glob pattern to match files, relative to the content directory.
|
||||
*/
|
||||
export declare function glob(globOptions: GlobOptions): Loader;
|
||||
/** @private */
|
||||
export declare function glob(globOptions: GlobOptions & {
|
||||
/** @deprecated */
|
||||
_legacy?: true;
|
||||
}): Loader;
|
||||
export {};
|
||||
|
106
node_modules/astro/dist/content/loaders/glob.js
generated
vendored
106
node_modules/astro/dist/content/loaders/glob.js
generated
vendored
@@ -1,15 +1,16 @@
|
||||
import { promises as fs } from "node:fs";
|
||||
import { existsSync, promises as fs } from "node:fs";
|
||||
import { relative } from "node:path";
|
||||
import { fileURLToPath, pathToFileURL } from "node:url";
|
||||
import fastGlob from "fast-glob";
|
||||
import { bold, green } from "kleur/colors";
|
||||
import micromatch from "micromatch";
|
||||
import pLimit from "p-limit";
|
||||
import picomatch from "picomatch";
|
||||
import { glob as tinyglobby } from "tinyglobby";
|
||||
import { getContentEntryIdAndSlug, posixRelative } from "../utils.js";
|
||||
function generateIdDefault({ entry, base, data }) {
|
||||
if (data.slug) {
|
||||
return data.slug;
|
||||
}
|
||||
const entryURL = new URL(entry, base);
|
||||
const entryURL = new URL(encodeURI(entry), base);
|
||||
const { slug } = getContentEntryIdAndSlug({
|
||||
entry: entryURL,
|
||||
contentDir: base,
|
||||
@@ -17,13 +18,19 @@ function generateIdDefault({ entry, base, data }) {
|
||||
});
|
||||
return slug;
|
||||
}
|
||||
function checkPrefix(pattern, prefix) {
|
||||
if (Array.isArray(pattern)) {
|
||||
return pattern.some((p) => p.startsWith(prefix));
|
||||
}
|
||||
return pattern.startsWith(prefix);
|
||||
}
|
||||
function glob(globOptions) {
|
||||
if (globOptions.pattern.startsWith("../")) {
|
||||
if (checkPrefix(globOptions.pattern, "../")) {
|
||||
throw new Error(
|
||||
"Glob patterns cannot start with `../`. Set the `base` option to a parent directory instead."
|
||||
);
|
||||
}
|
||||
if (globOptions.pattern.startsWith("/")) {
|
||||
if (checkPrefix(globOptions.pattern, "/")) {
|
||||
throw new Error(
|
||||
"Glob patterns cannot start with `/`. Set the `base` option to a parent directory or use a relative path instead."
|
||||
);
|
||||
@@ -35,17 +42,19 @@ function glob(globOptions) {
|
||||
load: async ({ config, logger, watcher, parseData, store, generateDigest, entryTypes }) => {
|
||||
const renderFunctionByContentType = /* @__PURE__ */ new WeakMap();
|
||||
const untouchedEntries = new Set(store.keys());
|
||||
async function syncData(entry, base, entryType) {
|
||||
const isLegacy = globOptions._legacy;
|
||||
const emulateLegacyCollections = !config.legacy.collections;
|
||||
async function syncData(entry, base, entryType, oldId) {
|
||||
if (!entryType) {
|
||||
logger.warn(`No entry type found for ${entry}`);
|
||||
return;
|
||||
}
|
||||
const fileUrl = new URL(entry, base);
|
||||
const fileUrl = new URL(encodeURI(entry), base);
|
||||
const contents = await fs.readFile(fileUrl, "utf-8").catch((err) => {
|
||||
logger.error(`Error reading ${entry}: ${err.message}`);
|
||||
return;
|
||||
});
|
||||
if (!contents) {
|
||||
if (!contents && contents !== "") {
|
||||
logger.warn(`No contents found for ${entry}`);
|
||||
return;
|
||||
}
|
||||
@@ -54,10 +63,23 @@ function glob(globOptions) {
|
||||
fileUrl
|
||||
});
|
||||
const id = generateId({ entry, base, data });
|
||||
if (oldId && oldId !== id) {
|
||||
store.delete(oldId);
|
||||
}
|
||||
let legacyId;
|
||||
if (isLegacy) {
|
||||
const entryURL = new URL(encodeURI(entry), base);
|
||||
const legacyOptions = getContentEntryIdAndSlug({
|
||||
entry: entryURL,
|
||||
contentDir: base,
|
||||
collection: ""
|
||||
});
|
||||
legacyId = legacyOptions.id;
|
||||
}
|
||||
untouchedEntries.delete(id);
|
||||
const existingEntry = store.get(id);
|
||||
const digest = generateDigest(contents);
|
||||
const filePath = fileURLToPath(fileUrl);
|
||||
const filePath2 = fileURLToPath(fileUrl);
|
||||
if (existingEntry && existingEntry.digest === digest && existingEntry.filePath) {
|
||||
if (existingEntry.deferredRender) {
|
||||
store.addModuleImport(existingEntry.filePath);
|
||||
@@ -65,16 +87,21 @@ function glob(globOptions) {
|
||||
if (existingEntry.assetImports?.length) {
|
||||
store.addAssetImports(existingEntry.assetImports, existingEntry.filePath);
|
||||
}
|
||||
fileToIdMap.set(filePath, id);
|
||||
fileToIdMap.set(filePath2, id);
|
||||
return;
|
||||
}
|
||||
const relativePath = posixRelative(fileURLToPath(config.root), filePath);
|
||||
const relativePath2 = posixRelative(fileURLToPath(config.root), filePath2);
|
||||
const parsedData = await parseData({
|
||||
id,
|
||||
data,
|
||||
filePath
|
||||
filePath: filePath2
|
||||
});
|
||||
if (entryType.getRenderFunction) {
|
||||
if (isLegacy && data.layout) {
|
||||
logger.error(
|
||||
`The Markdown "layout" field is not supported in content collections in Astro 5. Ignoring layout for ${JSON.stringify(entry)}. Enable "legacy.collections" if you need to use the layout field.`
|
||||
);
|
||||
}
|
||||
let render = renderFunctionByContentType.get(entryType);
|
||||
if (!render) {
|
||||
render = await entryType.getRenderFunction(config);
|
||||
@@ -84,9 +111,9 @@ function glob(globOptions) {
|
||||
try {
|
||||
rendered = await render?.({
|
||||
id,
|
||||
data: parsedData,
|
||||
data,
|
||||
body,
|
||||
filePath,
|
||||
filePath: filePath2,
|
||||
digest
|
||||
});
|
||||
} catch (error) {
|
||||
@@ -96,32 +123,47 @@ function glob(globOptions) {
|
||||
id,
|
||||
data: parsedData,
|
||||
body,
|
||||
filePath: relativePath,
|
||||
filePath: relativePath2,
|
||||
digest,
|
||||
rendered,
|
||||
assetImports: rendered?.metadata?.imagePaths
|
||||
assetImports: rendered?.metadata?.imagePaths,
|
||||
legacyId
|
||||
});
|
||||
} else if ("contentModuleTypes" in entryType) {
|
||||
store.set({
|
||||
id,
|
||||
data: parsedData,
|
||||
body,
|
||||
filePath: relativePath,
|
||||
filePath: relativePath2,
|
||||
digest,
|
||||
deferredRender: true
|
||||
deferredRender: true,
|
||||
legacyId
|
||||
});
|
||||
} else {
|
||||
store.set({ id, data: parsedData, body, filePath: relativePath, digest });
|
||||
store.set({ id, data: parsedData, body, filePath: relativePath2, digest, legacyId });
|
||||
}
|
||||
fileToIdMap.set(filePath, id);
|
||||
fileToIdMap.set(filePath2, id);
|
||||
}
|
||||
const baseDir = globOptions.base ? new URL(globOptions.base, config.root) : config.root;
|
||||
if (!baseDir.pathname.endsWith("/")) {
|
||||
baseDir.pathname = `${baseDir.pathname}/`;
|
||||
}
|
||||
const files = await fastGlob(globOptions.pattern, {
|
||||
cwd: fileURLToPath(baseDir)
|
||||
const filePath = fileURLToPath(baseDir);
|
||||
const relativePath = relative(fileURLToPath(config.root), filePath);
|
||||
const exists = existsSync(baseDir);
|
||||
if (!exists) {
|
||||
logger.warn(`The base directory "${fileURLToPath(baseDir)}" does not exist.`);
|
||||
}
|
||||
const files = await tinyglobby(globOptions.pattern, {
|
||||
cwd: fileURLToPath(baseDir),
|
||||
expandDirectories: false
|
||||
});
|
||||
if (exists && files.length === 0) {
|
||||
logger.warn(
|
||||
`No files found matching "${globOptions.pattern}" in directory "${relativePath}"`
|
||||
);
|
||||
return;
|
||||
}
|
||||
function configForFile(file) {
|
||||
const ext = file.split(".").at(-1);
|
||||
if (!ext) {
|
||||
@@ -149,7 +191,7 @@ function glob(globOptions) {
|
||||
if (isConfigFile(entry)) {
|
||||
return;
|
||||
}
|
||||
if (isInContentDir(entry)) {
|
||||
if (!emulateLegacyCollections && isInContentDir(entry)) {
|
||||
skippedFiles.push(entry);
|
||||
return;
|
||||
}
|
||||
@@ -161,13 +203,16 @@ function glob(globOptions) {
|
||||
);
|
||||
const skipCount = skippedFiles.length;
|
||||
if (skipCount > 0) {
|
||||
logger.warn(`The glob() loader cannot be used for files in ${bold("src/content")}.`);
|
||||
const patternList = Array.isArray(globOptions.pattern) ? globOptions.pattern.join(", ") : globOptions.pattern;
|
||||
logger.warn(
|
||||
`The glob() loader cannot be used for files in ${bold("src/content")} when legacy mode is enabled.`
|
||||
);
|
||||
if (skipCount > 10) {
|
||||
logger.warn(
|
||||
`Skipped ${green(skippedFiles.length)} files that matched ${green(globOptions.pattern)}.`
|
||||
`Skipped ${green(skippedFiles.length)} files that matched ${green(patternList)}.`
|
||||
);
|
||||
} else {
|
||||
logger.warn(`Skipped the following files that matched ${green(globOptions.pattern)}:`);
|
||||
logger.warn(`Skipped the following files that matched ${green(patternList)}:`);
|
||||
skippedFiles.forEach((file) => logger.warn(`\u2022 ${green(file)}`));
|
||||
}
|
||||
}
|
||||
@@ -175,8 +220,8 @@ function glob(globOptions) {
|
||||
if (!watcher) {
|
||||
return;
|
||||
}
|
||||
const matcher = micromatch.makeRe(globOptions.pattern);
|
||||
const matchesGlob = (entry) => !entry.startsWith("../") && matcher.test(entry);
|
||||
watcher.add(filePath);
|
||||
const matchesGlob = (entry) => !entry.startsWith("../") && picomatch.isMatch(entry, globOptions.pattern);
|
||||
const basePath = fileURLToPath(baseDir);
|
||||
async function onChange(changedPath) {
|
||||
const entry = posixRelative(basePath, changedPath);
|
||||
@@ -185,7 +230,8 @@ function glob(globOptions) {
|
||||
}
|
||||
const entryType = configForFile(changedPath);
|
||||
const baseUrl = pathToFileURL(basePath);
|
||||
await syncData(entry, baseUrl, entryType);
|
||||
const oldId = fileToIdMap.get(changedPath);
|
||||
await syncData(entry, baseUrl, entryType, oldId);
|
||||
logger.info(`Reloaded data from ${green(entry)}`);
|
||||
}
|
||||
watcher.on("change", onChange);
|
||||
|
36
node_modules/astro/dist/content/loaders/types.d.ts
generated
vendored
36
node_modules/astro/dist/content/loaders/types.d.ts
generated
vendored
@@ -1,7 +1,11 @@
|
||||
import type { FSWatcher } from 'vite';
|
||||
import type { ZodSchema } from 'zod';
|
||||
import type { AstroConfig, AstroIntegrationLogger, ContentEntryType } from '../../@types/astro.js';
|
||||
import type { MetaStore, ScopedDataStore } from '../mutable-data-store.js';
|
||||
import type { AstroIntegrationLogger } from '../../core/logger/core.js';
|
||||
import type { AstroConfig } from '../../types/public/config.js';
|
||||
import type { LiveDataCollection, LiveDataEntry } from '../../types/public/content.js';
|
||||
import type { RenderedContent } from '../data-store.js';
|
||||
import type { DataStore, MetaStore } from '../mutable-data-store.js';
|
||||
export type { DataStore, MetaStore };
|
||||
export interface ParseDataOptions<TData extends Record<string, unknown>> {
|
||||
/** The ID of the entry. Unique per collection */
|
||||
id: string;
|
||||
@@ -13,8 +17,8 @@ export interface ParseDataOptions<TData extends Record<string, unknown>> {
|
||||
export interface LoaderContext {
|
||||
/** The unique name of the collection */
|
||||
collection: string;
|
||||
/** A database abstraction to store the actual data */
|
||||
store: ScopedDataStore;
|
||||
/** A database to store the actual data */
|
||||
store: DataStore;
|
||||
/** A simple KV store, designed for things like sync tokens */
|
||||
meta: MetaStore;
|
||||
logger: AstroIntegrationLogger;
|
||||
@@ -22,12 +26,14 @@ export interface LoaderContext {
|
||||
config: AstroConfig;
|
||||
/** Validates and parses the data according to the collection schema */
|
||||
parseData<TData extends Record<string, unknown>>(props: ParseDataOptions<TData>): Promise<TData>;
|
||||
/** Renders markdown content to HTML and metadata */
|
||||
renderMarkdown(content: string): Promise<RenderedContent>;
|
||||
/** Generates a non-cryptographic content digest. This can be used to check if the data has changed */
|
||||
generateDigest(data: Record<string, unknown> | string): string;
|
||||
/** When running in dev, this is a filesystem watcher that can be used to trigger updates */
|
||||
watcher?: FSWatcher;
|
||||
/** If the loader has been triggered by an integration, this may optionally contain extra data set by that integration */
|
||||
refreshContextData?: Record<string, unknown>;
|
||||
entryTypes: Map<string, ContentEntryType>;
|
||||
}
|
||||
export interface Loader {
|
||||
/** Unique name of the loader, e.g. the npm package name */
|
||||
@@ -37,3 +43,23 @@ export interface Loader {
|
||||
/** Optionally, define the schema of the data. Will be overridden by user-defined schema */
|
||||
schema?: ZodSchema | Promise<ZodSchema> | (() => ZodSchema | Promise<ZodSchema>);
|
||||
}
|
||||
export interface LoadEntryContext<TEntryFilter = never> {
|
||||
filter: TEntryFilter extends never ? {
|
||||
id: string;
|
||||
} : TEntryFilter;
|
||||
}
|
||||
export interface LoadCollectionContext<TCollectionFilter = unknown> {
|
||||
filter?: TCollectionFilter;
|
||||
}
|
||||
export interface LiveLoader<TData extends Record<string, any> = Record<string, unknown>, TEntryFilter extends Record<string, any> | never = never, TCollectionFilter extends Record<string, any> | never = never, TError extends Error = Error> {
|
||||
/** Unique name of the loader, e.g. the npm package name */
|
||||
name: string;
|
||||
/** Load a single entry */
|
||||
loadEntry: (context: LoadEntryContext<TEntryFilter>) => Promise<LiveDataEntry<TData> | undefined | {
|
||||
error: TError;
|
||||
}>;
|
||||
/** Load a collection of entries */
|
||||
loadCollection: (context: LoadCollectionContext<TCollectionFilter>) => Promise<LiveDataCollection<TData> | {
|
||||
error: TError;
|
||||
}>;
|
||||
}
|
||||
|
Reference in New Issue
Block a user