@paroicms/server
Version:
The ParoiCMS server
261 lines • 13.9 kB
JavaScript
import { getDocumentTypeByName } from "@paroicms/internal-anywhere-lib";
import { toAbsoluteUrl } from "@paroicms/internal-server-lib";
import { encodeLNodeId, } from "@paroicms/public-anywhere-lib";
import { type } from "arktype";
import { getSiteFieldValue } from "../admin-backend/fields/load-fields.queries.js";
import { getHandleOfSiteField } from "../common/media-handles.helpers.js";
import { toMSourceMedia, toTpSourceMedia } from "../common/medias/to-media-values.js";
import { makeCacheDependencyKey } from "../common/text-cache.js";
import { loadRoutingClusterFromNode } from "../connector/db-init/load-routing-cluster.queries.js";
import { truncExcerptToWord } from "../helpers/excerpt.helpers.js";
import { getNodeTypeLabel } from "../helpers/label-translator.helper.js";
import { createLiquidDrop, loadOrFromRenderingCache } from "../liquidjs-tools/liquidjs-drop.js";
import { getFeaturedImageOf } from "../rendered-site/helpers/medias.helpers.js";
import { getUrlOfDocument } from "../rendered-site/page-route/make-url.js";
import { getPublicBreadcrumb } from "./breadcrumb.queries.js";
import { getClusterNodeOf, toTpClusterPayload, toTpRoutingClusterNode, } from "./cluster-payloads.js";
import { createPartDrop } from "./create-part-drop.js";
import { loadExcerpt } from "./excerpt.queries.js";
import { loadPublicFieldValues } from "./field-values.js";
import { getParentDocument } from "./get-parent.queries.js";
import { getSiblingDocuments } from "./get-siblings.queries.js";
import { makeJsonLdPayload } from "./json-ld-payload.js";
import { loadDefaultImage } from "./load-default-image.js";
import { makeImageAvailable } from "./make-image-available.js";
import { countPartsOf, formatListOfPartValues, keyOfParentPartData, loadPartsOf, } from "./parts.queries.js";
import { loadTranslationsAsDrops } from "./translations.queries.js";
const StringOrUndefinedAT = type("string|undefined");
export function createDocPayloadDrop(renderingContext, docValuesOrFn, options) {
const { siteContext } = renderingContext;
const { documentId } = options;
return createLiquidDrop(renderingContext, async () => {
const docValues = typeof docValuesOrFn === "function" ? await docValuesOrFn() : docValuesOrFn;
const documentType = getDocumentTypeByName(siteContext.siteSchema, docValues.type);
if (docValues.nodeId !== documentId.nodeId || docValues.language !== documentId.language) {
throw new Error("Document ID mismatch");
}
const typeLabel = getNodeTypeLabel(siteContext.siteSchema, {
language: docValues.language,
typeName: docValues.type,
});
renderingContext.addDependencyKey(makeCacheDependencyKey({ documentId }));
const id = encodeLNodeId(docValues);
return {
renderingCacheKey: `doc:${id}:${options.fieldNames?.join(",") ?? "full"}`,
values: {
kind: options.kind ??
(documentType.documentKind === "routing" ? "routingDocument" : "regularDocument"),
get leafType() {
siteContext.logger.warn("'leafType' is deprecated, use 'type' instead");
return docValues.type;
},
get leafId() {
siteContext.logger.warn("'leafId' is deprecated, use 'nodeId' instead");
return docValues.nodeId;
},
id,
...docValues,
get lang() {
siteContext.logger.warn("'doc.lang' is deprecated, use 'doc.language' instead");
return docValues.language;
},
languageLabel: siteContext.siteSchema.languageLabels[docValues.language],
url: options.url ?? (() => loadUrlOfDocument(renderingContext, docValues)),
excerpt: () => loadExcerpt(siteContext, renderingContext.tracker, {
lNodeId: docValues,
fieldTypes: documentType.fields ?? [],
}),
list: createPartsDrop(renderingContext, docValues, documentType),
listSize: createPartCountDrop(renderingContext, docValues, documentType),
defaultImage: async () => {
const image = await loadDefaultImage(renderingContext, {
fieldTypes: documentType.fields,
nodeId: docValues.nodeId,
language: docValues.language,
});
return image ? toTpSourceMedia(renderingContext, image) : undefined;
},
defaultImageId: async () => {
siteContext.logger.warn("'defaultImageId' is deprecated, use 'defaultImage' instead");
const image = await loadDefaultImage(renderingContext, {
fieldTypes: documentType.fields,
nodeId: docValues.nodeId,
language: docValues.language,
});
return image?.id;
},
featuredImage: async () => {
const image = await getFeaturedImageOf(renderingContext, {
nodeId: docValues.nodeId,
documentType,
});
return image ? toTpSourceMedia(renderingContext, image) : undefined;
},
featuredImageId: async () => {
siteContext.logger.warn("'featuredImageId' is deprecated, use 'featuredImage' instead");
const image = await getFeaturedImageOf(renderingContext, {
nodeId: docValues.nodeId,
documentType,
});
return image?.id;
},
field: () => loadPublicFieldValues(renderingContext, {
typeName: docValues.type,
lNodeId: docValues,
fieldNames: options.fieldNames,
}),
fields: () => {
siteContext.logger.warn("'fields' is deprecated, use 'field' instead");
return loadPublicFieldValues(renderingContext, {
typeName: docValues.type,
lNodeId: docValues,
fieldNames: options.fieldNames,
});
},
translations: () => loadTranslationsAsDrops(renderingContext, docValues),
labeling: () => {
siteContext.logger.warn("'labeling' no longer exists, use a labeling field instead");
},
singleLabeling: () => {
siteContext.logger.warn("'singleLabeling' no longer exists, use a labeling field instead");
},
flaggedWith: () => {
siteContext.logger.warn("'flaggedWith' no longer exists, use a labeling field instead");
},
flaggedWithOne: () => {
siteContext.logger.warn("'flaggedWithOne' no longer exists, use a labeling field instead");
},
og: () => makeOgValuesPayload(renderingContext, documentType, docValues, options),
jsonLd: () => makeJsonLdPayload(renderingContext, documentType, docValues, options),
breadcrumb: () => getPublicBreadcrumb(renderingContext, docValues),
parent: () => getParentDocument(renderingContext, docValues),
siblings: () => getSiblingDocuments(renderingContext, docValues),
typeLabel: typeLabel,
urlQuery: options.urlQuery,
frontendAppPath: options.frontendAppPath,
routing: async () => {
if (documentType.documentKind !== "routing")
return;
const cluster = await loadRoutingClusterFromNode(siteContext, {
nodeId: docValues.nodeId,
typeName: docValues.type,
});
const clusterNode = getClusterNodeOf(cluster, docValues.nodeId);
if (!clusterNode)
throw new Error(`Node '${docValues.nodeId}' not found in cluster`);
return toTpRoutingClusterNode(renderingContext, clusterNode, docValues.language);
},
routingIds: async () => {
siteContext.logger.warn("'routingIds' is deprecated, use 'routing' instead");
if (documentType.documentKind !== "routing")
return;
const cluster = await loadRoutingClusterFromNode(siteContext, {
nodeId: docValues.nodeId,
typeName: docValues.type,
});
const clusterNode = getClusterNodeOf(cluster, docValues.nodeId);
if (!clusterNode)
throw new Error(`Node '${docValues.nodeId}' not found in cluster`);
return toTpRoutingClusterNode(renderingContext, clusterNode, docValues.language);
},
cluster: async () => {
const found = await loadRoutingClusterFromNode(siteContext, {
nodeId: docValues.nodeId,
typeName: docValues.type,
});
return toTpClusterPayload(renderingContext, docValues.language, found);
},
},
};
}, {
loadDescriptor: {
load: "one",
nodeKind: "document",
descriptorName: "id",
documentId,
},
});
}
function createPartsDrop(renderingContext, documentId, documentType) {
const { siteContext } = renderingContext;
return createLiquidDrop(renderingContext, {
renderingCacheKey: `partsOf:${encodeLNodeId(documentId)}`,
values: Object.fromEntries((documentType.lists ?? []).map((listType) => [
listType.listName,
async () => {
const byParent = await loadPartsOf(siteContext, renderingContext.tracker, documentId, listType);
const completedItems = byParent.get(keyOfParentPartData({ listName: listType.listName, parentNodeId: documentId.nodeId }));
if (!completedItems || completedItems.length === 0)
return;
const rawItems = formatListOfPartValues(siteContext, completedItems, listType);
return rawItems.map((item) => createPartDrop(renderingContext, item, { byParent }));
},
])),
});
}
function createPartCountDrop(renderingContext, documentId, documentType) {
const { siteContext } = renderingContext;
return createLiquidDrop(renderingContext, {
renderingCacheKey: `partCountersOf:${encodeLNodeId(documentId)}`,
values: Object.fromEntries((documentType.lists ?? []).map((listType) => [
listType.listName,
() => countPartsOf(siteContext, renderingContext.tracker, documentId, listType),
])),
});
}
async function loadUrlOfDocument(renderingContext, documentId) {
const { siteContext } = renderingContext;
const { url, dependencyKeys } = await getUrlOfDocument(siteContext, renderingContext.tracker, documentId, {
returnUrlDependencyKeys: true,
forPreview: renderingContext.isPreview,
});
renderingContext.addDependencyKey(...dependencyKeys);
return url;
}
async function makeOgValuesPayload(renderingContext, documentType, docValues, options) {
const { siteContext } = renderingContext;
const excerpt = await loadOrFromRenderingCache(renderingContext, `excerpt:${encodeLNodeId(docValues)}:full`, () => loadExcerpt(siteContext, renderingContext.tracker, {
lNodeId: docValues,
fieldTypes: documentType.fields ?? [],
}));
const url = options.url ??
(await loadOrFromRenderingCache(renderingContext, `url:${encodeLNodeId(docValues)}`, () => loadUrlOfDocument(renderingContext, docValues)));
const featuredImageId = await loadOrFromRenderingCache(renderingContext, `featuredImage:${encodeLNodeId(docValues)}`, async () => (await getFeaturedImageOf(renderingContext, {
nodeId: docValues.nodeId,
documentType,
}))?.id);
const siteTitle = await loadOrFromRenderingCache(renderingContext, `siteFields:${docValues.language}:title`, async () => {
const title = await getSiteFieldValue(siteContext, {
fieldName: "title",
language: docValues.language,
publishedOnly: true,
});
return StringOrUndefinedAT.assert(title);
});
const description = excerpt
? truncExcerptToWord(excerpt, 130)
: docValues.metaDescription
? truncExcerptToWord(docValues.metaDescription, 130)
: undefined;
const ogMedia = featuredImageId !== undefined
? await siteContext.mediaStorage.getMedia({ mediaId: featuredImageId })
: await siteContext.mediaStorage.getMedia({
handle: getHandleOfSiteField(siteContext, { fieldName: "ogImage" }),
});
const ogImage = ogMedia?.kind === "image"
? await makeImageAvailable(renderingContext, toMSourceMedia(siteContext, ogMedia), {
pixelRatio: 1,
resizeRule: "1200x630",
})
: undefined;
return {
url: toAbsoluteUrl(siteContext, url),
type: documentType.ogType,
image: ogImage,
title: documentType.typeName === "home" ? siteTitle : docValues.title,
siteName: siteTitle,
description,
locale: docValues.language,
};
}
//# sourceMappingURL=create-doc-drop.js.map