Use backlinks and rework the caching system
This commit is contained in:
parent
f1b37a31a9
commit
7dd91f5847
|
@ -3,7 +3,8 @@ import type {
|
|||
EndpointWebsiteConfig,
|
||||
EndpointWording,
|
||||
} from "src/shared/payload/endpoint-types";
|
||||
import type { PayloadSDK } from "src/shared/payload/sdk";
|
||||
import { SDKEndpointNames, type PayloadSDK } from "src/shared/payload/sdk";
|
||||
import type { EndpointChange } from "src/shared/payload/webhooks";
|
||||
import { getLogger } from "src/utils/logger";
|
||||
|
||||
export class ContextCache {
|
||||
|
@ -35,24 +36,42 @@ export class ContextCache {
|
|||
await this.refreshWordings();
|
||||
}
|
||||
|
||||
async refreshWordings() {
|
||||
async invalidate(changes: EndpointChange[]) {
|
||||
for (const change of changes) {
|
||||
switch (change.type) {
|
||||
case SDKEndpointNames.getWordings:
|
||||
return await this.refreshWordings();
|
||||
|
||||
case SDKEndpointNames.getLanguages:
|
||||
return await this.refreshLocales();
|
||||
|
||||
case SDKEndpointNames.getCurrencies:
|
||||
return await this.refreshCurrencies();
|
||||
|
||||
case SDKEndpointNames.getWebsiteConfig:
|
||||
return await this.refreshWebsiteConfig();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async refreshWordings() {
|
||||
this.wordings = (await this.payload.getWordings()).data;
|
||||
this.logger.log("Wordings refreshed");
|
||||
}
|
||||
|
||||
async refreshCurrencies() {
|
||||
private async refreshCurrencies() {
|
||||
this.currencies = (await this.payload.getCurrencies()).data.map(({ id }) => id);
|
||||
this.logger.log("Currencies refreshed");
|
||||
}
|
||||
|
||||
async refreshLocales() {
|
||||
private async refreshLocales() {
|
||||
this.languages = (await this.payload.getLanguages()).data;
|
||||
this.locales = this.languages.filter(({ selectable }) => selectable).map(({ id }) => id);
|
||||
this.logger.log("Locales refreshed");
|
||||
}
|
||||
|
||||
async refreshWebsiteConfig() {
|
||||
this.config = (await this.payload.getConfig()).data;
|
||||
private async refreshWebsiteConfig() {
|
||||
this.config = (await this.payload.getWebsiteConfig()).data;
|
||||
this.logger.log("WebsiteConfig refreshed");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ import { getLogger } from "src/utils/logger";
|
|||
import { writeFile, mkdir, readFile } from "fs/promises";
|
||||
import { existsSync } from "fs";
|
||||
import type { PayloadSDK } from "src/shared/payload/sdk";
|
||||
import type { EndpointChange } from "src/shared/payload/webhooks";
|
||||
|
||||
const ON_DISK_ROOT = `.cache/dataCache`;
|
||||
const ON_DISK_RESPONSE_CACHE_FILE = `${ON_DISK_ROOT}/responseCache.json`;
|
||||
|
@ -11,14 +12,12 @@ export class DataCache {
|
|||
private initialized = false;
|
||||
|
||||
private readonly responseCache = new Map<string, any>();
|
||||
private readonly invalidationMap = new Map<string, Set<string>>();
|
||||
|
||||
private scheduleSaveTimeout: NodeJS.Timeout | undefined;
|
||||
|
||||
constructor(
|
||||
private readonly payload: PayloadSDK,
|
||||
private readonly uncachedPayload: PayloadSDK,
|
||||
private readonly onInvalidate: (urls: string[]) => Promise<void>
|
||||
private readonly uncachedPayload: PayloadSDK
|
||||
) {}
|
||||
|
||||
async init() {
|
||||
|
@ -32,8 +31,8 @@ export class DataCache {
|
|||
}
|
||||
|
||||
private async precache() {
|
||||
// Get all keys from CMS
|
||||
const allSDKUrls = (await this.uncachedPayload.getAllSdkUrls()).data.urls;
|
||||
// Get all documents from CMS
|
||||
const allDocs = (await this.uncachedPayload.getAll()).data;
|
||||
|
||||
// Load cache from disk if available
|
||||
if (existsSync(ON_DISK_RESPONSE_CACHE_FILE)) {
|
||||
|
@ -42,20 +41,20 @@ export class DataCache {
|
|||
const data = JSON.parse(buffer.toString()) as [string, any][];
|
||||
for (const [key, value] of data) {
|
||||
// Do not include cache where the key is no longer in the CMS
|
||||
if (!allSDKUrls.includes(key)) continue;
|
||||
if (!allDocs.find(({ url }) => url === key)) continue;
|
||||
this.set(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
const cacheSizeBeforePrecaching = this.responseCache.size;
|
||||
|
||||
for (const url of allSDKUrls) {
|
||||
for (const doc of allDocs) {
|
||||
// Do not precache response if already included in the loaded cache from disk
|
||||
if (this.responseCache.has(url)) continue;
|
||||
if (this.responseCache.has(doc.url)) continue;
|
||||
try {
|
||||
await this.payload.request(url);
|
||||
await this.payload.request(doc.url);
|
||||
} catch {
|
||||
this.logger.warn("Precaching failed for url", url);
|
||||
this.logger.warn("Precaching failed for url", doc.url);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -77,20 +76,6 @@ export class DataCache {
|
|||
|
||||
set(url: string, response: any) {
|
||||
if (import.meta.env.DATA_CACHING !== "true") return;
|
||||
const stringData = JSON.stringify(response);
|
||||
const regex = /[a-f0-9]{24}/g;
|
||||
const ids = [...stringData.matchAll(regex)].map((match) => match[0]);
|
||||
const uniqueIds = [...new Set(ids)];
|
||||
|
||||
uniqueIds.forEach((id) => {
|
||||
const current = this.invalidationMap.get(id);
|
||||
if (current) {
|
||||
current.add(url);
|
||||
} else {
|
||||
this.invalidationMap.set(id, new Set([url]));
|
||||
}
|
||||
});
|
||||
|
||||
this.responseCache.set(url, response);
|
||||
this.logger.log("Cached response for", url);
|
||||
if (this.initialized) {
|
||||
|
@ -98,18 +83,11 @@ export class DataCache {
|
|||
}
|
||||
}
|
||||
|
||||
async invalidate(ids: string[], urls: string[]) {
|
||||
async invalidate(changes: EndpointChange[]) {
|
||||
if (import.meta.env.DATA_CACHING !== "true") return;
|
||||
const urlsToInvalidate = new Set<string>(urls);
|
||||
|
||||
ids.forEach((id) => {
|
||||
const urlsForThisId = this.invalidationMap.get(id);
|
||||
if (!urlsForThisId) return;
|
||||
this.invalidationMap.delete(id);
|
||||
[...urlsForThisId].forEach((url) => urlsToInvalidate.add(url));
|
||||
});
|
||||
|
||||
for (const url of urlsToInvalidate) {
|
||||
const urls = changes.map(({ url }) => url);
|
||||
for (const url of urls) {
|
||||
this.responseCache.delete(url);
|
||||
this.logger.log("Invalidated cache for", url);
|
||||
try {
|
||||
|
@ -118,8 +96,6 @@ export class DataCache {
|
|||
this.logger.log("Revalidation fails for", url);
|
||||
}
|
||||
}
|
||||
|
||||
this.onInvalidate([...urlsToInvalidate]);
|
||||
this.logger.log("There are currently", this.responseCache.size, "responses in cache.");
|
||||
if (this.initialized) {
|
||||
this.scheduleSave();
|
||||
|
|
|
@ -6,22 +6,25 @@ import {
|
|||
serializeResponse,
|
||||
type SerializableResponse,
|
||||
} from "src/utils/responses";
|
||||
import type { PayloadSDK } from "src/shared/payload/sdk";
|
||||
import { SDKEndpointNames, type PayloadSDK } from "src/shared/payload/sdk";
|
||||
import type { EndpointChange } from "src/shared/payload/webhooks";
|
||||
import type { ContextCache } from "src/cache/contextCache";
|
||||
|
||||
const ON_DISK_ROOT = `.cache/pageCache`;
|
||||
const ON_DISK_RESPONSE_CACHE_FILE = `${ON_DISK_ROOT}/responseCache.json`;
|
||||
const ON_DISK_INVALIDATION_MAP_FILE = `${ON_DISK_ROOT}/invalidationMap.json`;
|
||||
|
||||
export class PageCache {
|
||||
private readonly logger = getLogger("[PageCache]");
|
||||
private initialized = false;
|
||||
|
||||
private responseCache = new Map<string, Response>();
|
||||
private invalidationMap = new Map<string, Set<string>>();
|
||||
|
||||
private scheduleSaveTimeout: NodeJS.Timeout | undefined;
|
||||
|
||||
constructor(private readonly uncachedPayload: PayloadSDK) {}
|
||||
constructor(
|
||||
private readonly uncachedPayload: PayloadSDK,
|
||||
private readonly contextCache: ContextCache
|
||||
) {}
|
||||
|
||||
async init() {
|
||||
if (this.initialized) return;
|
||||
|
@ -35,31 +38,16 @@ export class PageCache {
|
|||
|
||||
private async precache() {
|
||||
if (import.meta.env.DATA_CACHING !== "true") return;
|
||||
const { data: languages } = await this.uncachedPayload.getLanguages();
|
||||
const locales = languages.filter(({ selectable }) => selectable).map(({ id }) => id);
|
||||
|
||||
// Get all pages urls from CMS
|
||||
const allIds = (await this.uncachedPayload.getAllIds()).data;
|
||||
|
||||
const allPagesUrls = [
|
||||
"/",
|
||||
...allIds.audios.ids.map((id) => `/audios/${id}`),
|
||||
...allIds.collectibles.slugs.map((slug) => `/collectibles/${slug}`),
|
||||
...allIds.files.ids.map((id) => `/files/${id}`),
|
||||
...allIds.folders.slugs.map((slug) => `/folders/${slug}`),
|
||||
...allIds.images.ids.map((id) => `/images/${id}`),
|
||||
...allIds.pages.slugs.map((slug) => `/pages/${slug}`),
|
||||
...allIds.recorders.ids.map((id) => `/recorders/${id}`),
|
||||
"/settings",
|
||||
"/timeline",
|
||||
...allIds.videos.ids.map((id) => `/videos/${id}`),
|
||||
].flatMap((url) => locales.map((id) => `/${id}${url}`));
|
||||
const allDocs = (await this.uncachedPayload.getAll()).data;
|
||||
const allPageUrls = allDocs.flatMap((doc) => this.getUrlFromEndpointChange(doc));
|
||||
// TODO: Add static pages likes "/" and "/settings"
|
||||
|
||||
// Load cache from disk if available
|
||||
if (existsSync(ON_DISK_RESPONSE_CACHE_FILE) && existsSync(ON_DISK_INVALIDATION_MAP_FILE)) {
|
||||
if (existsSync(ON_DISK_RESPONSE_CACHE_FILE)) {
|
||||
this.logger.log("Loading cache from disk...");
|
||||
// Handle RESPONSE_CACHE_FILE
|
||||
{
|
||||
|
||||
const buffer = await readFile(ON_DISK_RESPONSE_CACHE_FILE);
|
||||
const data = JSON.parse(buffer.toString()) as [string, SerializableResponse][];
|
||||
let deserializedData = data.map<[string, Response]>(([key, value]) => [
|
||||
|
@ -68,26 +56,14 @@ export class PageCache {
|
|||
]);
|
||||
|
||||
// Do not include cache where the key is no longer in the CMS
|
||||
deserializedData = deserializedData.filter(([key]) => allPagesUrls.includes(key));
|
||||
deserializedData = deserializedData.filter(([key]) => allPageUrls.includes(key));
|
||||
|
||||
this.responseCache = new Map(deserializedData);
|
||||
}
|
||||
|
||||
// Handle INVALIDATION_MAP_FILE
|
||||
{
|
||||
const buffer = await readFile(ON_DISK_INVALIDATION_MAP_FILE);
|
||||
const data = JSON.parse(buffer.toString()) as [string, string[]][];
|
||||
const deserialize = data.map<[string, Set<string>]>(([key, value]) => [
|
||||
key,
|
||||
new Set(value),
|
||||
]);
|
||||
this.invalidationMap = new Map(deserialize);
|
||||
}
|
||||
}
|
||||
|
||||
const cacheSizeBeforePrecaching = this.responseCache.size;
|
||||
|
||||
for (const url of allPagesUrls) {
|
||||
for (const url of allPageUrls) {
|
||||
// Do not precache response if already included in the loaded cache from disk
|
||||
if (this.responseCache.has(url)) continue;
|
||||
try {
|
||||
|
@ -114,17 +90,8 @@ export class PageCache {
|
|||
return;
|
||||
}
|
||||
|
||||
set(url: string, response: Response, sdkCalls: string[]) {
|
||||
set(url: string, response: Response) {
|
||||
if (import.meta.env.PAGE_CACHING !== "true") return;
|
||||
sdkCalls.forEach((id) => {
|
||||
const current = this.invalidationMap.get(id);
|
||||
if (current) {
|
||||
current.add(url);
|
||||
} else {
|
||||
this.invalidationMap.set(id, new Set([url]));
|
||||
}
|
||||
});
|
||||
|
||||
this.responseCache.set(url, response.clone());
|
||||
this.logger.log("Cached response for", url);
|
||||
if (this.initialized) {
|
||||
|
@ -132,16 +99,70 @@ export class PageCache {
|
|||
}
|
||||
}
|
||||
|
||||
async invalidate(sdkUrls: string[]) {
|
||||
if (import.meta.env.PAGE_CACHING !== "true") return;
|
||||
const pagesToInvalidate = new Set<string>();
|
||||
private getUrlFromEndpointChange(change: EndpointChange): string[] {
|
||||
const getUnlocalizedUrl = (): string[] => {
|
||||
switch (change.type) {
|
||||
case SDKEndpointNames.getFolder:
|
||||
return [`/folders/${change.slug}`];
|
||||
|
||||
sdkUrls.forEach((url) => {
|
||||
const pagesForThisSDKUrl = this.invalidationMap.get(url);
|
||||
if (!pagesForThisSDKUrl) return;
|
||||
this.invalidationMap.delete(url);
|
||||
[...pagesForThisSDKUrl].forEach((page) => pagesToInvalidate.add(page));
|
||||
});
|
||||
case SDKEndpointNames.getCollectible:
|
||||
return [`/collectibles/${change.slug}`];
|
||||
|
||||
case SDKEndpointNames.getCollectibleGallery:
|
||||
return [`/collectibles/${change.slug}/gallery`];
|
||||
|
||||
case SDKEndpointNames.getCollectibleGalleryImage:
|
||||
return [`/collectibles/${change.slug}/gallery/${change.index}`];
|
||||
|
||||
case SDKEndpointNames.getCollectibleScans:
|
||||
return [`/collectibles/${change.slug}/scans`];
|
||||
|
||||
case SDKEndpointNames.getCollectibleScanPage:
|
||||
return [`/collectibles/${change.slug}/scans/${change.index}`];
|
||||
|
||||
case SDKEndpointNames.getPage:
|
||||
return [`/pages/${change.slug}`];
|
||||
|
||||
case SDKEndpointNames.getAudioByID:
|
||||
return [`/audios/${change.id}`];
|
||||
|
||||
case SDKEndpointNames.getImageByID:
|
||||
return [`/images/${change.id}`];
|
||||
|
||||
case SDKEndpointNames.getVideoByID:
|
||||
return [`/videos/${change.id}`];
|
||||
|
||||
case SDKEndpointNames.getFileByID:
|
||||
return [`/files/${change.id}`];
|
||||
|
||||
case SDKEndpointNames.getRecorderByID:
|
||||
return [`/recorders/${change.id}`];
|
||||
|
||||
case SDKEndpointNames.getChronologyEvents:
|
||||
case SDKEndpointNames.getChronologyEventByID:
|
||||
return [`/timeline`];
|
||||
|
||||
case SDKEndpointNames.getWebsiteConfig:
|
||||
case SDKEndpointNames.getLanguages:
|
||||
case SDKEndpointNames.getCurrencies:
|
||||
case SDKEndpointNames.getWordings:
|
||||
return [...this.responseCache.keys()];
|
||||
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
return getUnlocalizedUrl().flatMap((url) =>
|
||||
this.contextCache.locales.map((id) => `/${id}${url}`)
|
||||
);
|
||||
}
|
||||
|
||||
async invalidate(changes: EndpointChange[]) {
|
||||
if (import.meta.env.PAGE_CACHING !== "true") return;
|
||||
const pagesToInvalidate = new Set<string>(
|
||||
changes.flatMap((change) => this.getUrlFromEndpointChange(change))
|
||||
);
|
||||
|
||||
for (const url of pagesToInvalidate) {
|
||||
this.responseCache.delete(url);
|
||||
|
@ -181,13 +202,5 @@ export class PageCache {
|
|||
encoding: "utf-8",
|
||||
});
|
||||
this.logger.log("Saved", ON_DISK_RESPONSE_CACHE_FILE);
|
||||
|
||||
const serializedIdsCache = JSON.stringify(
|
||||
[...this.invalidationMap].map(([key, value]) => [key, [...value]])
|
||||
);
|
||||
await writeFile(ON_DISK_INVALIDATION_MAP_FILE, serializedIdsCache, {
|
||||
encoding: "utf-8",
|
||||
});
|
||||
this.logger.log("Saved", ON_DISK_INVALIDATION_MAP_FILE);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,12 +4,11 @@ import Topbar from "./components/Topbar/Topbar.astro";
|
|||
import Footer from "./components/Footer.astro";
|
||||
import AppLayoutBackgroundImg from "./components/AppLayoutBackgroundImg.astro";
|
||||
import type { ComponentProps } from "astro/types";
|
||||
import type { EndpointSource } from "src/shared/payload/endpoint-types";
|
||||
import { getSDKEndpoint } from "src/shared/payload/sdk";
|
||||
import type { EndpointRelation } from "src/shared/payload/endpoint-types";
|
||||
|
||||
interface Props {
|
||||
openGraph?: ComponentProps<typeof Html>["openGraph"];
|
||||
parentPages?: EndpointSource[];
|
||||
backlinks?: EndpointRelation[];
|
||||
backgroundImage?: ComponentProps<typeof AppLayoutBackgroundImg>["img"] | undefined;
|
||||
hideFooterLinks?: boolean;
|
||||
hideHomeButton?: boolean;
|
||||
|
@ -17,13 +16,9 @@ interface Props {
|
|||
class?: string | undefined;
|
||||
}
|
||||
|
||||
Astro.locals.sdkCalls.add(getSDKEndpoint.getCurrenciesEndpoint());
|
||||
Astro.locals.sdkCalls.add(getSDKEndpoint.getLanguagesEndpoint());
|
||||
Astro.locals.sdkCalls.add(getSDKEndpoint.getWordingsEndpoint());
|
||||
|
||||
const {
|
||||
openGraph,
|
||||
parentPages,
|
||||
backlinks,
|
||||
backgroundImage,
|
||||
hideFooterLinks = false,
|
||||
hideHomeButton = false,
|
||||
|
@ -38,7 +33,7 @@ const {
|
|||
{backgroundImage && <AppLayoutBackgroundImg img={backgroundImage} />}
|
||||
<header>
|
||||
<Topbar
|
||||
parentPages={parentPages}
|
||||
backlinks={backlinks}
|
||||
hideHomeButton={hideHomeButton}
|
||||
hideSearchButton={hideSearchButton}
|
||||
/>
|
||||
|
|
|
@ -6,15 +6,15 @@ import LanguageSelector from "./components/LanguageSelector.astro";
|
|||
import CurrencySelector from "./components/CurrencySelector.astro";
|
||||
import ParentPagesButton from "./components/ParentPagesButton.astro";
|
||||
import { getI18n } from "src/i18n/i18n";
|
||||
import type { EndpointSource } from "src/shared/payload/endpoint-types";
|
||||
import type { EndpointRelation } from "src/shared/payload/endpoint-types";
|
||||
|
||||
interface Props {
|
||||
parentPages?: EndpointSource[] | undefined;
|
||||
backlinks?: EndpointRelation[] | undefined;
|
||||
hideHomeButton?: boolean;
|
||||
hideSearchButton?: boolean;
|
||||
}
|
||||
|
||||
const { parentPages = [], hideHomeButton = false, hideSearchButton = false } = Astro.props;
|
||||
const { backlinks = [], hideHomeButton = false, hideSearchButton = false } = Astro.props;
|
||||
|
||||
const { t, getLocalizedUrl } = await getI18n(Astro.locals.currentLocale);
|
||||
---
|
||||
|
@ -23,14 +23,14 @@ const { t, getLocalizedUrl } = await getI18n(Astro.locals.currentLocale);
|
|||
|
||||
<nav id="topbar" class="when-no-print">
|
||||
{
|
||||
(!hideHomeButton || parentPages.length > 0) && (
|
||||
(!hideHomeButton || backlinks.length > 0) && (
|
||||
<div id="left" class="hide-scrollbar">
|
||||
<a href={getLocalizedUrl("/")} class="pressable-label">
|
||||
<Icon name="material-symbols:home" width={16} height={16} />
|
||||
<p>{t("home.title")}</p>
|
||||
</a>
|
||||
|
||||
{parentPages.length > 0 && <ParentPagesButton parentPages={parentPages} />}
|
||||
{backlinks.length > 0 && <ParentPagesButton backlinks={backlinks} />}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -3,14 +3,14 @@ import Tooltip from "components/Tooltip.astro";
|
|||
import { Icon } from "astro-icon/components";
|
||||
import { getI18n } from "src/i18n/i18n";
|
||||
import ReturnToButton from "./ReturnToButton.astro";
|
||||
import SourceRow from "components/SourceRow.astro";
|
||||
import type { EndpointSource } from "src/shared/payload/endpoint-types";
|
||||
import RelationRow from "components/RelationRow.astro";
|
||||
import type { EndpointRelation } from "src/shared/payload/endpoint-types";
|
||||
|
||||
interface Props {
|
||||
parentPages: EndpointSource[];
|
||||
backlinks: EndpointRelation[];
|
||||
}
|
||||
|
||||
const { parentPages } = Astro.props;
|
||||
const { backlinks } = Astro.props;
|
||||
|
||||
const { t } = await getI18n(Astro.locals.currentLocale);
|
||||
---
|
||||
|
@ -18,15 +18,15 @@ const { t } = await getI18n(Astro.locals.currentLocale);
|
|||
{/* ------------------------------------------- HTML ------------------------------------------- */}
|
||||
|
||||
{
|
||||
parentPages.length === 1 && parentPages[0] ? (
|
||||
<ReturnToButton parentPage={parentPages[0]} />
|
||||
backlinks.length === 1 && backlinks[0] ? (
|
||||
<ReturnToButton relation={backlinks[0]} />
|
||||
) : (
|
||||
<Tooltip trigger="click" class="when-js">
|
||||
<div id="tooltip-content" slot="tooltip-content">
|
||||
<p>{t("header.nav.parentPages.tooltip")}</p>
|
||||
<div>
|
||||
{parentPages.map((parentPage) => (
|
||||
<SourceRow source={parentPage} />
|
||||
{backlinks.map((relation) => (
|
||||
<RelationRow relation={relation} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -34,7 +34,7 @@ const { t } = await getI18n(Astro.locals.currentLocale);
|
|||
<Icon name="material-symbols:keyboard-return" />
|
||||
<p>
|
||||
{t("header.nav.parentPages.label", {
|
||||
count: parentPages.length,
|
||||
count: backlinks.length,
|
||||
})}
|
||||
</p>
|
||||
</button>
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
---
|
||||
import { Icon } from "astro-icon/components";
|
||||
import { getI18n } from "src/i18n/i18n";
|
||||
import type { EndpointSource } from "src/shared/payload/endpoint-types";
|
||||
import type { EndpointRelation } from "src/shared/payload/endpoint-types";
|
||||
|
||||
interface Props {
|
||||
parentPage: EndpointSource;
|
||||
relation: EndpointRelation;
|
||||
}
|
||||
|
||||
const { parentPage } = Astro.props;
|
||||
const { formatEndpointSource } = await getI18n(Astro.locals.currentLocale);
|
||||
const { relation } = Astro.props;
|
||||
const { formatEndpointRelation } = await getI18n(Astro.locals.currentLocale);
|
||||
|
||||
const {
|
||||
href,
|
||||
|
@ -17,7 +17,7 @@ const {
|
|||
target = undefined,
|
||||
rel = undefined,
|
||||
lang,
|
||||
} = formatEndpointSource(parentPage);
|
||||
} = formatEndpointRelation(relation);
|
||||
---
|
||||
|
||||
{/* ------------------------------------------- HTML ------------------------------------------- */}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
---
|
||||
import GenericPreview from "components/Previews/GenericPreview.astro";
|
||||
import { getI18n } from "src/i18n/i18n";
|
||||
import { Collections } from "src/shared/payload/constants";
|
||||
import type { EndpointFolder } from "src/shared/payload/endpoint-types";
|
||||
import type { Attribute } from "src/utils/attributes";
|
||||
|
||||
|
@ -11,7 +12,7 @@ interface Props {
|
|||
const { getLocalizedUrl, getLocalizedMatch, t } = await getI18n(Astro.locals.currentLocale);
|
||||
|
||||
const {
|
||||
folder: { translations, slug, files, sections, parentPages },
|
||||
folder: { translations, slug, files, sections, backlinks },
|
||||
} = Astro.props;
|
||||
|
||||
const { language, title } = getLocalizedMatch(translations);
|
||||
|
@ -32,9 +33,9 @@ const attributes: Attribute[] = [
|
|||
{
|
||||
icon: "material-symbols:keyboard-return",
|
||||
title: t("global.folders.attributes.parent"),
|
||||
values: parentPages.flatMap((parent) => {
|
||||
if (parent.type !== "folder") return [];
|
||||
const name = getLocalizedMatch(parent.folder.translations).title;
|
||||
values: backlinks.flatMap((link) => {
|
||||
if (link.type !== Collections.Folders) return [];
|
||||
const name = getLocalizedMatch(link.value.translations).title;
|
||||
return { name };
|
||||
}),
|
||||
},
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
---
|
||||
import { getI18n } from "src/i18n/i18n";
|
||||
import type { EndpointSource } from "src/shared/payload/endpoint-types";
|
||||
import type { EndpointRelation } from "src/shared/payload/endpoint-types";
|
||||
|
||||
interface Props {
|
||||
source: EndpointSource;
|
||||
relation: EndpointRelation;
|
||||
}
|
||||
|
||||
const { source } = Astro.props;
|
||||
const { formatEndpointSource } = await getI18n(Astro.locals.currentLocale);
|
||||
const { relation } = Astro.props;
|
||||
const { formatEndpointRelation } = await getI18n(Astro.locals.currentLocale);
|
||||
|
||||
const {
|
||||
href,
|
||||
|
@ -16,7 +16,7 @@ const {
|
|||
target = undefined,
|
||||
rel = undefined,
|
||||
lang,
|
||||
} = formatEndpointSource(source);
|
||||
} = formatEndpointRelation(relation);
|
||||
---
|
||||
|
||||
{/* ------------------------------------------- HTML ------------------------------------------- */}
|
|
@ -4,7 +4,6 @@
|
|||
declare namespace App {
|
||||
interface Locals {
|
||||
currentLocale: string;
|
||||
sdkCalls: Set<string>;
|
||||
pageCaching: boolean;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import type { WordingKey } from "src/i18n/wordings-keys";
|
||||
import { contextCache } from "src/services";
|
||||
import { capitalize, formatInlineTitle } from "src/utils/format";
|
||||
import type { EndpointChronologyEvent, EndpointSource } from "src/shared/payload/endpoint-types";
|
||||
import type { EndpointChronologyEvent, EndpointRelation } from "src/shared/payload/endpoint-types";
|
||||
import { Collections } from "src/shared/payload/constants";
|
||||
|
||||
export const defaultLocale = "en";
|
||||
|
||||
|
@ -236,8 +237,8 @@ export const getI18n = async (locale: string) => {
|
|||
}
|
||||
};
|
||||
|
||||
const formatEndpointSource = (
|
||||
source: EndpointSource
|
||||
const formatEndpointRelation = (
|
||||
relation: EndpointRelation
|
||||
): {
|
||||
href: string;
|
||||
typeLabel: string;
|
||||
|
@ -246,98 +247,84 @@ export const getI18n = async (locale: string) => {
|
|||
target?: string;
|
||||
rel?: string;
|
||||
} => {
|
||||
switch (source.type) {
|
||||
case "url": {
|
||||
switch (relation.type) {
|
||||
case "url":
|
||||
return {
|
||||
href: source.url,
|
||||
href: relation.url,
|
||||
typeLabel: t("global.sources.typeLabel.url"),
|
||||
label: source.label,
|
||||
label: relation.label,
|
||||
target: "_blank",
|
||||
rel: "noopener noreferrer",
|
||||
};
|
||||
}
|
||||
|
||||
case "collectible": {
|
||||
const rangeLabel = (() => {
|
||||
switch (source.range?.type) {
|
||||
case Collections.Collectibles: {
|
||||
const getRangeLabel = () => {
|
||||
switch (relation.range?.type) {
|
||||
case "timestamp":
|
||||
return t("global.sources.typeLabel.collectible.range.timestamp", {
|
||||
page: source.range.timestamp,
|
||||
page: relation.range.timestamp,
|
||||
});
|
||||
|
||||
case "page":
|
||||
return t("global.sources.typeLabel.collectible.range.page", {
|
||||
page: source.range.page,
|
||||
page: relation.range.page,
|
||||
});
|
||||
|
||||
case "custom":
|
||||
return t("global.sources.typeLabel.collectible.range.custom", {
|
||||
note: getLocalizedMatch(source.range.translations).note,
|
||||
note: getLocalizedMatch(relation.range.translations).note,
|
||||
});
|
||||
|
||||
case undefined:
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
})();
|
||||
};
|
||||
|
||||
const translation = getLocalizedMatch(source.collectible.translations);
|
||||
const translation = getLocalizedMatch(relation.value.translations);
|
||||
return {
|
||||
href: getLocalizedUrl(`/collectibles/${source.collectible.slug}`),
|
||||
href: getLocalizedUrl(`/collectibles/${relation.value.slug}`),
|
||||
typeLabel: t("global.sources.typeLabel.collectible"),
|
||||
label: formatInlineTitle(translation) + rangeLabel,
|
||||
label: formatInlineTitle(translation) + getRangeLabel(),
|
||||
lang: translation.language,
|
||||
};
|
||||
}
|
||||
|
||||
case "page": {
|
||||
const translation = getLocalizedMatch(source.page.translations);
|
||||
case Collections.Pages: {
|
||||
const translation = getLocalizedMatch(relation.value.translations);
|
||||
return {
|
||||
href: getLocalizedUrl(`/pages/${source.page.slug}`),
|
||||
href: getLocalizedUrl(`/pages/${relation.value.slug}`),
|
||||
typeLabel: t("global.sources.typeLabel.page"),
|
||||
label: formatInlineTitle(translation),
|
||||
lang: translation.language,
|
||||
};
|
||||
}
|
||||
|
||||
case "folder": {
|
||||
const translation = getLocalizedMatch(source.folder.translations);
|
||||
case Collections.Folders: {
|
||||
const translation = getLocalizedMatch(relation.value.translations);
|
||||
return {
|
||||
href: getLocalizedUrl(`/folders/${source.folder.slug}`),
|
||||
href: getLocalizedUrl(`/folders/${relation.value.slug}`),
|
||||
typeLabel: t("global.sources.typeLabel.folder"),
|
||||
label: formatInlineTitle(translation),
|
||||
lang: translation.language,
|
||||
};
|
||||
}
|
||||
|
||||
case "scans": {
|
||||
const translation = getLocalizedMatch(source.collectible.translations);
|
||||
return {
|
||||
href: getLocalizedUrl(`/collectibles/${source.collectible.slug}/scans`),
|
||||
typeLabel: t("global.sources.typeLabel.scans"),
|
||||
label: formatInlineTitle(translation),
|
||||
lang: translation.language,
|
||||
};
|
||||
}
|
||||
|
||||
case "gallery": {
|
||||
const translation = getLocalizedMatch(source.collectible.translations);
|
||||
return {
|
||||
href: getLocalizedUrl(`/collectibles/${source.collectible.slug}/gallery`),
|
||||
typeLabel: t("global.sources.typeLabel.gallery"),
|
||||
label: formatInlineTitle(translation),
|
||||
lang: translation.language,
|
||||
};
|
||||
}
|
||||
|
||||
default: {
|
||||
/* TODO: Handle other types of relations */
|
||||
case Collections.Audios:
|
||||
case Collections.ChronologyEvents:
|
||||
case Collections.Files:
|
||||
case Collections.Images:
|
||||
case Collections.Recorders:
|
||||
case Collections.Tags:
|
||||
case Collections.Videos:
|
||||
default:
|
||||
return {
|
||||
href: "/404",
|
||||
label: `Invalid type ${source["type"]}`,
|
||||
label: `Invalid type ${relation["type"]}`,
|
||||
typeLabel: "Error",
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
|
@ -353,7 +340,7 @@ export const getI18n = async (locale: string) => {
|
|||
formatMillimeters,
|
||||
formatNumber,
|
||||
formatTimelineDate,
|
||||
formatEndpointSource,
|
||||
formatEndpointRelation,
|
||||
formatScanIndexShort,
|
||||
formatFilesize,
|
||||
};
|
||||
|
|
|
@ -26,7 +26,7 @@ export const pageCachingMiddleware = defineMiddleware(async ({ url, request, loc
|
|||
response.headers.set("Last-Modified", new Date().toUTCString());
|
||||
|
||||
if (locals.pageCaching) {
|
||||
pageCache.set(pathname, response, [...locals.sdkCalls]);
|
||||
pageCache.set(pathname, response);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@ import { getCurrentLocale } from "src/middleware/utils";
|
|||
|
||||
export const setAstroLocalsMiddleware = defineMiddleware(async ({ url, locals }, next) => {
|
||||
locals.currentLocale = getCurrentLocale(url.pathname) ?? "en";
|
||||
locals.sdkCalls = new Set();
|
||||
locals.pageCaching = true;
|
||||
return next();
|
||||
});
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import type { APIRoute } from "astro";
|
||||
import { Collections } from "src/shared/payload/constants";
|
||||
import type { AfterOperationWebHookMessage } from "src/shared/payload/webhooks";
|
||||
import { contextCache, dataCache } from "src/services.ts";
|
||||
import { contextCache, dataCache, pageCache } from "src/services.ts";
|
||||
import type { EndpointChange } from "src/shared/payload/webhooks";
|
||||
|
||||
export const POST: APIRoute = async ({ request, locals }) => {
|
||||
locals.pageCaching = false;
|
||||
|
@ -11,38 +10,17 @@ export const POST: APIRoute = async ({ request, locals }) => {
|
|||
return new Response(null, { status: 403, statusText: "Forbidden" });
|
||||
}
|
||||
|
||||
const message = (await request.json()) as AfterOperationWebHookMessage;
|
||||
console.log("[Webhook] Received messages from CMS:", message);
|
||||
const changes = (await request.json()) as EndpointChange[];
|
||||
console.log("[Webhook] Received messages from CMS:", changes);
|
||||
|
||||
// Not awaiting on purpose to respond with a 202 and not block the CMS
|
||||
handleWebHookMessage(message);
|
||||
handleWebHookMessage(changes);
|
||||
|
||||
return new Response(null, { status: 202, statusText: "Accepted" });
|
||||
};
|
||||
|
||||
const handleWebHookMessage = async ({
|
||||
addedDependantIds,
|
||||
collection,
|
||||
urls,
|
||||
id,
|
||||
}: AfterOperationWebHookMessage) => {
|
||||
await dataCache.invalidate([...(id ? [id] : []), ...addedDependantIds], urls);
|
||||
|
||||
switch (collection) {
|
||||
case Collections.Wordings:
|
||||
await contextCache.refreshWordings();
|
||||
break;
|
||||
|
||||
case Collections.Currencies:
|
||||
await contextCache.refreshCurrencies();
|
||||
break;
|
||||
|
||||
case Collections.Languages:
|
||||
await contextCache.refreshLocales();
|
||||
break;
|
||||
|
||||
case Collections.WebsiteConfig:
|
||||
await contextCache.refreshWebsiteConfig();
|
||||
break;
|
||||
}
|
||||
const handleWebHookMessage = async (changes: EndpointChange[]) => {
|
||||
await dataCache.invalidate(changes);
|
||||
await contextCache.invalidate(changes);
|
||||
await pageCache.invalidate(changes);
|
||||
};
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import type { APIRoute } from "astro";
|
||||
import { dataCache, pageCache } from "src/services";
|
||||
import { contextCache, dataCache, pageCache } from "src/services";
|
||||
|
||||
export const GET: APIRoute = async ({ locals }) => {
|
||||
locals.pageCaching = false;
|
||||
|
||||
await contextCache.init();
|
||||
await dataCache.init();
|
||||
await pageCache.init();
|
||||
return new Response(null, { status: 200, statusText: "Ok" });
|
||||
|
|
|
@ -32,7 +32,6 @@ const { translations, thumbnail, createdAt, updatedAt, updatedBy, attributes } =
|
|||
await (async () => {
|
||||
if (Astro.props.page) return Astro.props.page;
|
||||
const response = await payload.getPage(slug);
|
||||
Astro.locals.sdkCalls.add(response.endpointCalled);
|
||||
return response.data;
|
||||
})();
|
||||
|
||||
|
|
|
@ -29,7 +29,6 @@ const index = Astro.props.index ?? parseInt(reqUrl.searchParams.get("index")!);
|
|||
const event = await (async () => {
|
||||
if (Astro.props.event) return Astro.props.event;
|
||||
const response = await payload.getChronologyEventByID(id);
|
||||
Astro.locals.sdkCalls.add(response.endpointCalled);
|
||||
return response.data;
|
||||
})();
|
||||
const { sources, translations } = event.events[index]!;
|
||||
|
|
|
@ -17,7 +17,6 @@ const response = await fetchOr404(() => payload.getAudioByID(id));
|
|||
if (response instanceof Response) {
|
||||
return response;
|
||||
}
|
||||
Astro.locals.sdkCalls.add(response.endpointCalled);
|
||||
const audio = response.data;
|
||||
|
||||
const { getLocalizedMatch, t, formatFilesize, formatDate } = await getI18n(
|
||||
|
@ -34,6 +33,7 @@ const {
|
|||
updatedAt,
|
||||
thumbnail,
|
||||
mimeType,
|
||||
backlinks,
|
||||
} = audio;
|
||||
|
||||
const { pretitle, title, subtitle, description, language } = getLocalizedMatch(translations);
|
||||
|
@ -73,6 +73,7 @@ const metaAttributes = [
|
|||
{/* ------------------------------------------- HTML ------------------------------------------- */}
|
||||
|
||||
<AppLayout
|
||||
backlinks={backlinks}
|
||||
openGraph={{
|
||||
title: formatInlineTitle({ pretitle, title, subtitle }),
|
||||
description: description && formatRichTextToString(description),
|
||||
|
|
|
@ -17,8 +17,7 @@ const response = await fetchOr404(() => payload.getCollectibleGalleryImage(slug,
|
|||
if (response instanceof Response) {
|
||||
return response;
|
||||
}
|
||||
Astro.locals.sdkCalls.add(response.endpointCalled);
|
||||
const { parentPages, previousIndex, nextIndex, image } = response.data;
|
||||
const { backlinks, previousIndex, nextIndex, image } = response.data;
|
||||
|
||||
const { filename, translations, createdAt, updatedAt, credits, attributes, mimeType } = image;
|
||||
|
||||
|
@ -67,7 +66,7 @@ const metaAttributes = [
|
|||
description: description && formatRichTextToString(description),
|
||||
thumbnail: image,
|
||||
}}
|
||||
parentPages={parentPages}>
|
||||
backlinks={backlinks}>
|
||||
<Lightbox
|
||||
image={image}
|
||||
pretitle={pretitle}
|
||||
|
|
|
@ -15,8 +15,7 @@ const response = await fetchOr404(() => payload.getCollectibleGallery(slug));
|
|||
if (response instanceof Response) {
|
||||
return response;
|
||||
}
|
||||
Astro.locals.sdkCalls.add(response.endpointCalled);
|
||||
const { translations, parentPages, images, thumbnail } = response.data;
|
||||
const { translations, backlinks, images, thumbnail } = response.data;
|
||||
|
||||
const translation = getLocalizedMatch(translations);
|
||||
---
|
||||
|
@ -29,7 +28,7 @@ const translation = getLocalizedMatch(translations);
|
|||
description: translation.description && formatRichTextToString(translation.description),
|
||||
thumbnail,
|
||||
}}
|
||||
parentPages={parentPages}
|
||||
backlinks={backlinks}
|
||||
class="app">
|
||||
<AppLayoutTitle
|
||||
title={translation.title}
|
||||
|
|
|
@ -30,7 +30,6 @@ const response = await fetchOr404(() => payload.getCollectible(slug));
|
|||
if (response instanceof Response) {
|
||||
return response;
|
||||
}
|
||||
Astro.locals.sdkCalls.add(response.endpointCalled);
|
||||
const collectible = response.data;
|
||||
|
||||
const {
|
||||
|
@ -47,7 +46,7 @@ const {
|
|||
scans,
|
||||
subitems,
|
||||
files,
|
||||
parentPages,
|
||||
backlinks,
|
||||
attributes,
|
||||
contents,
|
||||
createdAt,
|
||||
|
@ -128,7 +127,7 @@ if (languages.length > 0) {
|
|||
description: description && formatRichTextToString(description),
|
||||
thumbnail,
|
||||
}}
|
||||
parentPages={parentPages}
|
||||
backlinks={backlinks}
|
||||
backgroundImage={backgroundImage ?? thumbnail}>
|
||||
<AsideLayout reducedAsideWidth>
|
||||
<Fragment slot="header">
|
||||
|
|
|
@ -16,8 +16,7 @@ const response = await fetchOr404(() => payload.getCollectibleScanPage(slug, ind
|
|||
if (response instanceof Response) {
|
||||
return response;
|
||||
}
|
||||
Astro.locals.sdkCalls.add(response.endpointCalled);
|
||||
const { parentPages, previousIndex, nextIndex, image, translations } = response.data;
|
||||
const { backlinks, previousIndex, nextIndex, image, translations } = response.data;
|
||||
|
||||
const translation = getLocalizedMatch(translations);
|
||||
---
|
||||
|
@ -29,7 +28,7 @@ const translation = getLocalizedMatch(translations);
|
|||
title: `${formatInlineTitle(translation)} (${index})`,
|
||||
description: translation.description && formatRichTextToString(translation.description),
|
||||
}}
|
||||
parentPages={parentPages}>
|
||||
backlinks={backlinks}>
|
||||
<Lightbox
|
||||
image={image}
|
||||
title={formatScanIndexShort(index)}
|
||||
|
|
|
@ -16,8 +16,7 @@ const response = await fetchOr404(() => payload.getCollectibleScans(slug));
|
|||
if (response instanceof Response) {
|
||||
return response;
|
||||
}
|
||||
Astro.locals.sdkCalls.add(response.endpointCalled);
|
||||
const { translations, credits, cover, pages, dustjacket, obi, parentPages, thumbnail } =
|
||||
const { translations, credits, cover, pages, dustjacket, obi, backlinks, thumbnail } =
|
||||
response.data;
|
||||
|
||||
const translation = getLocalizedMatch(translations);
|
||||
|
@ -46,7 +45,7 @@ const hasOutsideObi = obi ? Object.keys(obi).some((value) => !value.includes("in
|
|||
description: translation.description && formatRichTextToString(translation.description),
|
||||
thumbnail,
|
||||
}}
|
||||
parentPages={parentPages}
|
||||
backlinks={backlinks}
|
||||
class="app">
|
||||
<AppLayoutTitle
|
||||
title={translation.title}
|
||||
|
|
|
@ -18,7 +18,6 @@ const response = await fetchOr404(() => payload.getFileByID(id));
|
|||
if (response instanceof Response) {
|
||||
return response;
|
||||
}
|
||||
Astro.locals.sdkCalls.add(response.endpointCalled);
|
||||
const {
|
||||
translations,
|
||||
attributes,
|
||||
|
@ -30,6 +29,7 @@ const {
|
|||
updatedAt,
|
||||
createdAt,
|
||||
thumbnail,
|
||||
backlinks,
|
||||
} = response.data;
|
||||
|
||||
const { getLocalizedMatch, t, formatFilesize, formatDate } = await getI18n(
|
||||
|
@ -84,6 +84,7 @@ const smallTitle = title === filename;
|
|||
{/* ------------------------------------------- HTML ------------------------------------------- */}
|
||||
|
||||
<AppLayout
|
||||
backlinks={backlinks}
|
||||
openGraph={{
|
||||
title: formatInlineTitle({ pretitle, title, subtitle }),
|
||||
description: description && formatRichTextToString(description),
|
||||
|
|
|
@ -22,8 +22,7 @@ const response = await fetchOr404(() => payload.getFolder(slug));
|
|||
if (response instanceof Response) {
|
||||
return response;
|
||||
}
|
||||
Astro.locals.sdkCalls.add(response.endpointCalled);
|
||||
const { files, parentPages, sections, translations } = response.data;
|
||||
const { files, backlinks, sections, translations } = response.data;
|
||||
|
||||
const { getLocalizedMatch } = await getI18n(Astro.locals.currentLocale);
|
||||
const { language, title, description } = getLocalizedMatch(translations);
|
||||
|
@ -36,7 +35,7 @@ const { language, title, description } = getLocalizedMatch(translations);
|
|||
title: title,
|
||||
description: description && formatRichTextToString(description),
|
||||
}}
|
||||
parentPages={parentPages}
|
||||
backlinks={backlinks}
|
||||
class="app">
|
||||
<AppLayoutTitle title={title} lang={language} />
|
||||
{description && <RichText content={description} context={{ lang: language }} />}
|
||||
|
|
|
@ -12,7 +12,6 @@ const response = await fetchOr404(() => payload.getImageByID(id));
|
|||
if (response instanceof Response) {
|
||||
return response;
|
||||
}
|
||||
Astro.locals.sdkCalls.add(response.endpointCalled);
|
||||
const image = response.data;
|
||||
const {
|
||||
filename,
|
||||
|
@ -25,6 +24,7 @@ const {
|
|||
filesize,
|
||||
width,
|
||||
height,
|
||||
backlinks,
|
||||
} = image;
|
||||
|
||||
const { getLocalizedMatch, formatDate, t, formatFilesize, formatNumber } = await getI18n(
|
||||
|
@ -83,6 +83,7 @@ const metaAttributes = [
|
|||
{/* ------------------------------------------- HTML ------------------------------------------- */}
|
||||
|
||||
<AppLayout
|
||||
backlinks={backlinks}
|
||||
openGraph={{
|
||||
title: formatInlineTitle({ pretitle, title, subtitle }),
|
||||
description: description && formatRichTextToString(description),
|
||||
|
|
|
@ -12,9 +12,8 @@ const response = await fetchOr404(() => payload.getPage(slug));
|
|||
if (response instanceof Response) {
|
||||
return response;
|
||||
}
|
||||
Astro.locals.sdkCalls.add(response.endpointCalled);
|
||||
const page = response.data;
|
||||
const { parentPages, thumbnail, translations, backgroundImage } = page;
|
||||
const { backlinks, thumbnail, translations, backgroundImage } = page;
|
||||
|
||||
const { getLocalizedMatch } = await getI18n(Astro.locals.currentLocale);
|
||||
const meta = getLocalizedMatch(translations);
|
||||
|
@ -28,7 +27,7 @@ const meta = getLocalizedMatch(translations);
|
|||
description: meta.summary && formatRichTextToString(meta.summary),
|
||||
thumbnail: thumbnail,
|
||||
}}
|
||||
parentPages={parentPages}
|
||||
backlinks={backlinks}
|
||||
backgroundImage={backgroundImage ?? thumbnail}>
|
||||
<Page slug={slug} lang={Astro.locals.currentLocale} page={page} />
|
||||
</AppLayout>
|
||||
|
|
|
@ -16,7 +16,6 @@ const response = await fetchOr404(() => payload.getRecorderByID(id));
|
|||
if (response instanceof Response) {
|
||||
return response;
|
||||
}
|
||||
Astro.locals.sdkCalls.add(response.endpointCalled);
|
||||
const { username, languages, avatar, translations } = response.data;
|
||||
|
||||
const { t, getLocalizedMatch, getLocalizedUrl } = await getI18n(Astro.locals.currentLocale);
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
---
|
||||
import { Icon } from "astro-icon/components";
|
||||
import SourceRow from "components/SourceRow.astro";
|
||||
import RelationRow from "components/RelationRow.astro";
|
||||
import Tooltip from "components/Tooltip.astro";
|
||||
import { getI18n } from "src/i18n/i18n";
|
||||
import type { EndpointSource } from "src/shared/payload/endpoint-types";
|
||||
import type { EndpointRelation } from "src/shared/payload/endpoint-types";
|
||||
|
||||
interface Props {
|
||||
sources: EndpointSource[];
|
||||
sources: EndpointRelation[];
|
||||
}
|
||||
|
||||
const { sources } = Astro.props;
|
||||
|
@ -26,7 +26,7 @@ const { t } = await getI18n(Astro.locals.currentLocale);
|
|||
<Tooltip trigger="click">
|
||||
<div id="tooltip-content" slot="tooltip-content">
|
||||
{sources.map((source) => (
|
||||
<SourceRow source={source} />
|
||||
<RelationRow relation={source} />
|
||||
))}
|
||||
</div>
|
||||
<button class="pressable-label">
|
||||
|
|
|
@ -14,7 +14,6 @@ const response = await fetchOr404(() => payload.getChronologyEvents());
|
|||
if (response instanceof Response) {
|
||||
return response;
|
||||
}
|
||||
Astro.locals.sdkCalls.add(response.endpointCalled);
|
||||
const events = response.data;
|
||||
|
||||
const groupedEvents = groupBy(events, (event) => event.date.year);
|
||||
|
|
|
@ -17,7 +17,6 @@ const response = await fetchOr404(() => payload.getVideoByID(id));
|
|||
if (response instanceof Response) {
|
||||
return response;
|
||||
}
|
||||
Astro.locals.sdkCalls.add(response.endpointCalled);
|
||||
const video = response.data;
|
||||
const {
|
||||
translations,
|
||||
|
@ -30,6 +29,7 @@ const {
|
|||
createdAt,
|
||||
thumbnail,
|
||||
mimeType,
|
||||
backlinks,
|
||||
} = video;
|
||||
|
||||
const { getLocalizedMatch, t, formatFilesize, formatDate } = await getI18n(
|
||||
|
@ -73,6 +73,7 @@ const metaAttributes = [
|
|||
{/* ------------------------------------------- HTML ------------------------------------------- */}
|
||||
|
||||
<AppLayout
|
||||
backlinks={backlinks}
|
||||
openGraph={{
|
||||
title: formatInlineTitle({ pretitle, title, subtitle }),
|
||||
description: description && formatRichTextToString(description),
|
||||
|
|
|
@ -22,6 +22,13 @@ export const analytics = import.meta.env.ANALYTICS_URL
|
|||
|
||||
const tokenCache = new TokenCache();
|
||||
|
||||
const uncachedPayload = new PayloadSDK(
|
||||
import.meta.env.PAYLOAD_API_URL,
|
||||
import.meta.env.PAYLOAD_USER,
|
||||
import.meta.env.PAYLOAD_PASSWORD
|
||||
);
|
||||
uncachedPayload.addTokenCache(tokenCache);
|
||||
|
||||
export const payload = new PayloadSDK(
|
||||
import.meta.env.PAYLOAD_API_URL,
|
||||
import.meta.env.PAYLOAD_USER,
|
||||
|
@ -29,19 +36,11 @@ export const payload = new PayloadSDK(
|
|||
);
|
||||
payload.addTokenCache(tokenCache);
|
||||
|
||||
const uncachedPayload = new PayloadSDK(
|
||||
import.meta.env.PAYLOAD_API_URL,
|
||||
import.meta.env.PAYLOAD_USER,
|
||||
import.meta.env.PAYLOAD_PASSWORD
|
||||
);
|
||||
uncachedPayload.addTokenCache(tokenCache);
|
||||
export const pageCache = new PageCache(uncachedPayload);
|
||||
|
||||
// Loading context cache first so that the server can still serve responses while precaching.
|
||||
export const contextCache = new ContextCache(payload);
|
||||
await contextCache.init();
|
||||
|
||||
export const dataCache = new DataCache(payload, uncachedPayload, (urls) =>
|
||||
pageCache.invalidate(urls)
|
||||
);
|
||||
export const dataCache = new DataCache(payload, uncachedPayload);
|
||||
payload.addDataCache(dataCache);
|
||||
|
||||
export const pageCache = new PageCache(uncachedPayload, contextCache);
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 47c990080173a2330f0c7a9837dac34dba4e0811
|
||||
Subproject commit caa79dee9eca5b9b6959e6f5a721245202423612
|
Loading…
Reference in New Issue