Added page caching

This commit is contained in:
DrMint 2024-06-29 12:54:04 +02:00
parent de9ad38835
commit cbbf0e5e3b
43 changed files with 567 additions and 382 deletions

View File

@ -1,6 +1,6 @@
{
"name": "v3.accords-library.com",
"version": "3.0.0-beta.6",
"version": "3.0.0-beta.7",
"scripts": {
"dev": "astro dev",
"start": "astro dev",

View File

@ -1,10 +1,16 @@
import { writeFileSync } from "fs";
import { payload } from "src/utils/payload";
import { PayloadSDK } from "src/shared/payload/payload-sdk";
const TRANSLATION_FOLDER = `${process.cwd()}/src/i18n`;
const payload = new PayloadSDK(
import.meta.env.PAYLOAD_API_URL,
import.meta.env.PAYLOAD_USER,
import.meta.env.PAYLOAD_PASSWORD
);
try {
const wordings = await payload.getWordings();
const { data: wordings } = await payload.getWordings();
const keys = wordings.map(({ name }) => name);
let result = "";

View File

@ -2,14 +2,16 @@ import type {
EndpointWebsiteConfig,
EndpointWording,
Language,
PayloadSDK,
} from "src/shared/payload/payload-sdk";
import { getLogger } from "src/utils/logger";
import { payload } from "src/utils/payload";
class ContextCache {
export class ContextCache {
private initialized = false;
private logger = getLogger("[ContextCache]");
constructor(private readonly payload: PayloadSDK) {}
locales: Language[] = [];
currencies: string[] = [];
wordings: EndpointWording[] = [];
@ -33,26 +35,22 @@ class ContextCache {
}
async refreshWordings() {
this.wordings = await payload.getWordings();
this.wordings = (await this.payload.getWordings()).data;
this.logger.log("Wordings refreshed");
}
async refreshCurrencies() {
contextCache.currencies = (await payload.getCurrencies()).map(({ id }) => id);
this.currencies = (await this.payload.getCurrencies()).data.map(({ id }) => id);
this.logger.log("Currencies refreshed");
}
async refreshLocales() {
contextCache.locales = await payload.getLanguages();
this.locales = (await this.payload.getLanguages()).data;
this.logger.log("Locales refreshed");
}
async refreshWebsiteConfig() {
contextCache.config = await payload.getConfig();
this.config = (await this.payload.getConfig()).data;
this.logger.log("WebsiteConfig refreshed");
}
}
const contextCache = new ContextCache();
await contextCache.init();
export { contextCache };

View File

@ -1,13 +1,18 @@
import type { PayloadSDK } from "src/shared/payload/payload-sdk";
import { getLogger } from "src/utils/logger";
import { payload } from "src/utils/payload";
class DataCache {
export class DataCache {
private readonly logger = getLogger("[DataCache]");
private initialized = false;
private readonly responseCache = new Map<string, any>();
private readonly idsCacheMap = new Map<string, Set<string>>();
constructor(
private readonly payload: PayloadSDK,
private readonly onInvalidate: (urls: string[]) => Promise<void>
) {}
async init() {
if (this.initialized) return;
@ -19,10 +24,10 @@ class DataCache {
}
private async precache() {
const { urls } = await payload.getAllSdkUrls();
for (const url of urls) {
const { data } = await this.payload.getAllSdkUrls();
for (const url of data.urls) {
try {
await payload.request(url);
await this.payload.request(url);
} catch {
this.logger.warn("Precaching failed for url", url);
}
@ -71,14 +76,13 @@ class DataCache {
this.responseCache.delete(url);
this.logger.log("Invalidated cache for", url);
try {
await payload.request(url);
await this.payload.request(url);
} catch (e) {
this.logger.log("Revalidation fails for", url);
}
}
this.onInvalidate([...urlsToInvalidate]);
this.logger.log("There are currently", this.responseCache.size, "responses in cache.");
}
}
export const dataCache = new DataCache();

View File

@ -1,11 +1,66 @@
import type { PayloadSDK } from "src/shared/payload/payload-sdk";
import { getLogger } from "src/utils/logger";
class PageCache {
export class PageCache {
private readonly logger = getLogger("[PageCache]");
private readonly cache = new Map<string, Response>();
private initialized = false;
private readonly responseCache = new Map<string, Response>();
private readonly invalidationMap = new Map<string, Set<string>>();
constructor(private readonly payload: PayloadSDK) {}
async init() {
if (this.initialized) return;
if (import.meta.env.ENABLE_PRECACHING === "true") {
await this.precacheAll();
}
this.initialized = true;
}
private async precacheAll() {
const { data: languages } = await this.payload.getLanguages();
const locales = languages.map(({ id }) => id);
await this.precache("/", locales);
await this.precache("/settings", locales);
await this.precache("/timeline", locales);
const { data: folders } = await this.payload.getFolderSlugs();
for (const slug of folders) {
await this.precache(`/folders/${slug}`, locales);
}
const { data: pages } = await this.payload.getPageSlugs();
for (const slug of pages) {
await this.precache(`/pages/${slug}`, locales);
}
const { data: collectibles } = await this.payload.getCollectibleSlugs();
for (const slug of collectibles) {
await this.precache(`/collectibles/${slug}`, locales);
}
this.logger.log("Precaching completed!", this.responseCache.size, "responses cached");
}
private async precache(pathname: string, locales: string[]) {
try {
await Promise.all(
locales.map((locale) => {
const url = `http://${import.meta.env.ASTRO_HOST}:${import.meta.env.ASTRO_PORT}/${locale}${pathname}`;
return fetch(url);
})
);
} catch (e) {
this.logger.warn("Precaching failed for page", pathname);
}
}
get(url: string): Response | undefined {
const cachedPage = this.cache.get(url);
const cachedPage = this.responseCache.get(url);
if (cachedPage) {
this.logger.log("Retrieved cached page for", url);
return cachedPage?.clone();
@ -13,10 +68,40 @@ class PageCache {
return;
}
set(url: string, response: Response) {
this.cache.set(url, response.clone());
set(url: string, response: Response, sdkCalls: string[]) {
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);
}
}
export const pageCache = new PageCache();
async invalidate(sdkUrls: string[]) {
const pagesToInvalidate = new Set<string>();
sdkUrls.forEach((url) => {
const pagesForThisSDKUrl = this.invalidationMap.get(url);
if (!pagesForThisSDKUrl) return;
this.invalidationMap.delete(url);
[...pagesForThisSDKUrl].forEach((page) => pagesToInvalidate.add(page));
});
for (const url of pagesToInvalidate) {
this.responseCache.delete(url);
this.logger.log("Invalidated cache for", url);
try {
await fetch(`http://${import.meta.env.ASTRO_HOST}:${import.meta.env.ASTRO_PORT}${url}`);
} catch (e) {
this.logger.log("Revalidation fails for", url);
}
}
this.logger.log("There are currently", this.responseCache.size, "responses in cache.");
}
}

20
src/cache/tokenCache.ts vendored Normal file
View File

@ -0,0 +1,20 @@
export class TokenCache {
private token: string | undefined;
private expiration: number | undefined;
get() {
if (!this.token) return undefined;
if (!this.expiration || this.expiration < Date.now()) {
console.log("[PayloadSDK] No token to be retrieved or the token expired");
return undefined;
}
return this.token;
}
set(newToken: string, newExpiration: number) {
this.token = newToken;
this.expiration = newExpiration * 1000;
const diffInMinutes = Math.floor((this.expiration - Date.now()) / 1000 / 60);
console.log("[PayloadSDK] New token set. TTL is", diffInMinutes, "minutes.");
}
}

View File

@ -2,7 +2,7 @@
import Html from "./components/Html.astro";
import Topbar from "./components/Topbar/Topbar.astro";
import Footer from "./components/Footer.astro";
import type { EndpointSource } from "src/shared/payload/payload-sdk";
import { getSDKEndpoint, type EndpointSource } from "src/shared/payload/payload-sdk";
import AppLayoutBackgroundImg from "./components/AppLayoutBackgroundImg.astro";
import type { ComponentProps } from "astro/types";
@ -15,6 +15,10 @@ 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,

View File

@ -7,7 +7,7 @@ import type {
EndpointPayloadImage,
EndpointVideo,
} from "src/shared/payload/payload-sdk";
import { contextCache } from "src/cache/contextCache";
import { contextCache } from "src/utils/payload";
import { PostProcessingTags } from "src/middleware/postProcessing";
interface Props {

View File

@ -2,7 +2,7 @@
import Button from "components/Button.astro";
import Tooltip from "components/Tooltip.astro";
import { getI18n } from "src/i18n/i18n";
import { contextCache } from "src/cache/contextCache";
import { contextCache } from "src/utils/payload";
import { formatCurrency } from "src/utils/currencies";
import {
PostProcessingTags,

View File

@ -2,7 +2,7 @@
import Button from "components/Button.astro";
import Tooltip from "components/Tooltip.astro";
import { getI18n } from "src/i18n/i18n";
import { contextCache } from "src/cache/contextCache";
import { contextCache } from "src/utils/payload";
import { formatLocale } from "src/utils/format";
interface Props {

1
src/env.d.ts vendored
View File

@ -5,5 +5,6 @@ declare namespace App {
interface Locals {
currentLocale: string;
notFound: boolean;
sdkCalls: Set<string>;
}
}

View File

@ -1,6 +1,6 @@
import type { WordingKey } from "src/i18n/wordings-keys";
import type { ChronologyEvent, EndpointSource } from "src/shared/payload/payload-sdk";
import { contextCache } from "src/cache/contextCache";
import { contextCache } from "src/utils/payload";
import { capitalize, formatInlineTitle } from "src/utils/format";
export const defaultLocale = "en";

View File

@ -8,8 +8,6 @@ import { requestTrackingMiddleware } from "src/middleware/requestTracking";
import { pageCachingMiddleware } from "src/middleware/pageCaching";
import { setAstroLocalsMiddleware } from "src/middleware/setAstroLocals";
export const onRequest = sequence(
// Possible redirect
actionsHandlingMiddleware,

View File

@ -1,7 +1,9 @@
import { defineMiddleware } from "astro:middleware";
import { pageCache } from "src/cache/pageCache";
import { pageCache } from "src/utils/payload";
export const pageCachingMiddleware = defineMiddleware(async ({ url, request }, next) => {
const blacklist = ["/en/api/hooks/collection-operation", "/en/api/on-startup"];
export const pageCachingMiddleware = defineMiddleware(async ({ url, request, locals }, next) => {
const pathname = url.pathname;
const cachedPage = pageCache.get(pathname);
@ -20,7 +22,10 @@ export const pageCachingMiddleware = defineMiddleware(async ({ url, request }, n
if (response.ok) {
response.headers.set("Last-Modified", new Date().toUTCString());
pageCache.set(pathname, response);
if (!blacklist.includes(pathname)) {
pageCache.set(pathname, response, [...locals.sdkCalls]);
}
}
return response;

View File

@ -53,8 +53,6 @@ export const postProcessingMiddleware = defineMiddleware(async ({ cookies, local
let html = await response.text();
const t0 = performance.now();
// HTML CLASS
const currentTheme = getCookieTheme(cookies) ?? "auto";
html = html.replace(
@ -102,7 +100,5 @@ export const postProcessingMiddleware = defineMiddleware(async ({ cookies, local
}
});
console.log("Post-processing:", performance.now() - t0, "ms");
return new Response(html, response);
});

View File

@ -3,5 +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();
return next();
});

View File

@ -1,6 +1,6 @@
import type { AstroCookies } from "astro";
import { z } from "astro:content";
import { contextCache } from "src/cache/contextCache";
import { contextCache } from "src/utils/payload";
import acceptLanguage from "accept-language";
export const getAbsoluteLocaleUrl = (locale: string, url: string) => `/${locale}${url}`;
@ -26,7 +26,7 @@ export const getCurrentLocale = (pathname: string): string | undefined => {
export const getBestAcceptedLanguage = (request: Request): string | undefined => {
const header = request.headers.get("Accept-Language");
if (!header) return;
if (!header || header === "*") return;
acceptLanguage.languages(contextCache.locales.map(({ id }) => id));

View File

@ -1,7 +1,7 @@
---
import LibraryCard from "./LibraryCard.astro";
import { getI18n } from "src/i18n/i18n";
import { contextCache } from "src/cache/contextCache";
import { contextCache } from "src/utils/payload";
const { getLocalizedUrl, getLocalizedMatch } = await getI18n(Astro.locals.currentLocale);
---

View File

@ -1,6 +1,5 @@
import type { APIRoute } from "astro";
import { contextCache } from "src/cache/contextCache";
import { dataCache } from "src/cache/dataCache";
import { contextCache, dataCache } from "src/utils/payload.ts";
import { Collections, type AfterOperationWebHookMessage } from "src/shared/payload/payload-sdk";
export const POST: APIRoute = async ({ request }) => {

View File

@ -1,7 +1,9 @@
import type { APIRoute } from "astro";
import { dataCache } from "src/cache/dataCache";
import { contextCache, dataCache, pageCache } from "src/utils/payload";
export const GET: APIRoute = async () => {
await contextCache.init();
await dataCache.init();
await pageCache.init();
return new Response(null, { status: 200, statusText: "Ok" });
};

View File

@ -24,8 +24,14 @@ interface Props {
const reqUrl = new URL(Astro.request.url);
const lang = Astro.props.lang ?? reqUrl.searchParams.get("lang")!;
const slug = Astro.props.slug ?? reqUrl.searchParams.get("slug")!;
const { translations, thumbnail, createdAt, updatedAt, updatedBy, attributes } =
Astro.props.page ?? (await payload.getPage(slug));
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;
})();
const { getLocalizedUrl, t, formatDate } = await getI18n(Astro.locals.currentLocale);
const { getLocalizedMatch } = await getI18n(lang);

View File

@ -12,17 +12,22 @@ import { payload } from "src/utils/payload";
export const partial = true;
interface Props {
lang: string;
event: EndpointChronologyEvent;
id: string;
index: number;
lang?: string;
event?: EndpointChronologyEvent;
id?: string;
index?: number;
}
const reqUrl = new URL(Astro.request.url);
const lang = Astro.props.lang ?? reqUrl.searchParams.get("lang")!;
const id = Astro.props.id ?? reqUrl.searchParams.get("id")!;
const index = Astro.props.index ?? parseInt(reqUrl.searchParams.get("index")!);
const event = Astro.props.event ?? (await payload.getChronologyEventByID(id));
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]!;
const { getLocalizedUrl } = await getI18n(Astro.locals.currentLocale);

View File

@ -13,10 +13,12 @@ import { fetchOr404 } from "src/utils/responses";
import { getFileIcon } from "src/utils/attributes";
const id = Astro.params.id!;
const audio = await fetchOr404(() => payload.getAudioByID(id));
if (audio instanceof Response) {
return audio;
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(
Astro.locals.currentLocale

View File

@ -13,12 +13,13 @@ const { getLocalizedUrl, getLocalizedMatch, t, formatDate } = await getI18n(
Astro.locals.currentLocale
);
const galleryImage = await fetchOr404(() => payload.getCollectibleGalleryImage(slug, index));
if (galleryImage instanceof Response) {
return galleryImage;
const response = await fetchOr404(() => payload.getCollectibleGalleryImage(slug, index));
if (response instanceof Response) {
return response;
}
Astro.locals.sdkCalls.add(response.endpointCalled);
const { parentPages, previousIndex, nextIndex, image } = response.data;
const { parentPages, previousIndex, nextIndex, image } = galleryImage;
const { filename, translations, createdAt, updatedAt, credits, attributes, mimeType } = image;
const { pretitle, title, subtitle, description, language } =

View File

@ -11,12 +11,13 @@ import RichText from "components/RichText/RichText.astro";
const slug = Astro.params.slug!;
const { getLocalizedMatch, getLocalizedUrl, t } = await getI18n(Astro.locals.currentLocale);
const gallery = await fetchOr404(() => payload.getCollectibleGallery(slug));
if (gallery instanceof Response) {
return gallery;
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, parentPages, images, thumbnail } = gallery;
const translation = getLocalizedMatch(translations);
---

View File

@ -26,10 +26,12 @@ const { getLocalizedMatch, getLocalizedUrl, t, formatDate } = await getI18n(
Astro.locals.currentLocale
);
const collectible = await fetchOr404(() => payload.getCollectible(slug));
if (collectible instanceof Response) {
return collectible;
const response = await fetchOr404(() => payload.getCollectible(slug));
if (response instanceof Response) {
return response;
}
Astro.locals.sdkCalls.add(response.endpointCalled);
const collectible = response.data;
const {
translations,

View File

@ -12,12 +12,13 @@ const { formatScanIndexShort, getLocalizedMatch, getLocalizedUrl } = await getI1
Astro.locals.currentLocale
);
const scanPage = await fetchOr404(() => payload.getCollectibleScanPage(slug, index));
if (scanPage instanceof Response) {
return scanPage;
const response = await fetchOr404(() => payload.getCollectibleScanPage(slug, index));
if (response instanceof Response) {
return response;
}
Astro.locals.sdkCalls.add(response.endpointCalled);
const { parentPages, previousIndex, nextIndex, image, translations } = response.data;
const { parentPages, previousIndex, nextIndex, image, translations } = scanPage;
const translation = getLocalizedMatch(translations);
---

View File

@ -12,12 +12,13 @@ import RichText from "components/RichText/RichText.astro";
const slug = Astro.params.slug!;
const { getLocalizedMatch, t } = await getI18n(Astro.locals.currentLocale);
const scans = await fetchOr404(() => payload.getCollectibleScans(slug));
if (scans instanceof Response) {
return scans;
const response = await fetchOr404(() => payload.getCollectibleScans(slug));
if (response instanceof Response) {
return response;
}
const { translations, credits, cover, pages, dustjacket, obi, parentPages, thumbnail } = scans;
Astro.locals.sdkCalls.add(response.endpointCalled);
const { translations, credits, cover, pages, dustjacket, obi, parentPages, thumbnail } =
response.data;
const translation = getLocalizedMatch(translations);

View File

@ -14,14 +14,11 @@ import { Icon } from "astro-icon/components";
import { sizesToSrcset } from "src/utils/img";
const id = Astro.params.id!;
const video = await fetchOr404(() => payload.getFileByID(id));
if (video instanceof Response) {
return video;
const response = await fetchOr404(() => payload.getFileByID(id));
if (response instanceof Response) {
return response;
}
const { getLocalizedMatch, t, formatFilesize, formatDate } = await getI18n(
Astro.locals.currentLocale
);
Astro.locals.sdkCalls.add(response.endpointCalled);
const {
translations,
attributes,
@ -33,7 +30,11 @@ const {
updatedAt,
createdAt,
thumbnail,
} = video;
} = response.data;
const { getLocalizedMatch, t, formatFilesize, formatDate } = await getI18n(
Astro.locals.currentLocale
);
const { pretitle, title, subtitle, description, language } =
translations.length > 0

View File

@ -18,36 +18,38 @@ import FilePreview from "components/Previews/FilePreview.astro";
const slug = Astro.params.slug!;
const folder = await fetchOr404(() => payload.getFolder(slug));
if (folder instanceof Response) {
return folder;
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 { getLocalizedMatch } = await getI18n(Astro.locals.currentLocale);
const meta = getLocalizedMatch(folder.translations);
const { language, title, description } = getLocalizedMatch(translations);
---
{/* ------------------------------------------- HTML ------------------------------------------- */}
<AppLayout
openGraph={{
title: meta.title,
description: meta.description && formatRichTextToString(meta.description),
title: title,
description: description && formatRichTextToString(description),
}}
parentPages={folder.parentPages}
parentPages={parentPages}
class="app">
<AppLayoutTitle title={meta.title} lang={meta.language} />
{meta.description && <RichText content={meta.description} context={{ lang: meta.language }} />}
<AppLayoutTitle title={title} lang={language} />
{description && <RichText content={description} context={{ lang: language }} />}
<div id="main" class:list={{ complex: folder.sections.type === "multiple" }}>
<div id="main" class:list={{ complex: sections.type === "multiple" }}>
{
folder.sections.type === "single" && folder.sections.subfolders.length > 0 ? (
<FoldersSection folders={folder.sections.subfolders} />
sections.type === "single" && sections.subfolders.length > 0 ? (
<FoldersSection folders={sections.subfolders} />
) : (
folder.sections.type === "multiple" &&
folder.sections.sections.length > 0 && (
sections.type === "multiple" &&
sections.sections.length > 0 && (
<div id="sections">
{folder.sections.sections.map(({ subfolders, translations }) => {
{sections.sections.map(({ subfolders, translations }) => {
const { language, name } = getLocalizedMatch(translations);
return <FoldersSection folders={subfolders} title={name} lang={language} />;
})}
@ -58,7 +60,7 @@ const meta = getLocalizedMatch(folder.translations);
<div id="files">
{
folder.files.map(({ relationTo, value }) => {
files.map(({ relationTo, value }) => {
switch (relationTo) {
case Collections.Collectibles:
return <CollectiblePreview collectible={value} />;

View File

@ -8,13 +8,15 @@ import { fetchOr404 } from "src/utils/responses";
import { getFileIcon } from "src/utils/attributes";
const id = Astro.params.id!;
const image = await fetchOr404(() => payload.getImageByID(id));
if (image instanceof Response) {
return image;
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, translations, attributes, credits, createdAt, updatedAt, mimeType } = image;
const { getLocalizedMatch, formatDate, t } = await getI18n(Astro.locals.currentLocale);
const { filename, translations, attributes, credits, createdAt, updatedAt, mimeType } = image;
const { pretitle, title, subtitle, description, language } =
translations.length > 0

View File

@ -3,7 +3,7 @@ import Button from "components/Button.astro";
import LibraryGrid from "./_components/LibraryGrid.astro";
import LinkCard from "./_components/LinkCard.astro";
import { getI18n } from "src/i18n/i18n";
import { contextCache } from "src/cache/contextCache";
import { contextCache } from "src/utils/payload";
import AppLayout from "components/AppLayout/AppLayout.astro";
import HomeTitle from "./_components/HomeTitle.astro";

View File

@ -8,11 +8,12 @@ import { fetchOr404 } from "src/utils/responses";
const slug = Astro.params.slug!;
const page = await fetchOr404(() => payload.getPage(slug));
if (page instanceof Response) {
return page;
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 { getLocalizedMatch } = await getI18n(Astro.locals.currentLocale);

View File

@ -12,15 +12,15 @@ import { fetchOr404 } from "src/utils/responses";
import { sizesToSrcset } from "src/utils/img";
const id = Astro.params.id!;
const recorder = await fetchOr404(() => payload.getRecorderByID(id));
if (recorder instanceof Response) {
return recorder;
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);
const { username, languages, avatar, translations } = recorder;
const { biography, language } =
translations.length > 0
? getLocalizedMatch(translations)

View File

@ -2,7 +2,7 @@
import AppLayout from "components/AppLayout/AppLayout.astro";
import AppLayoutTitle from "components/AppLayout/components/AppLayoutTitle.astro";
import { getI18n } from "src/i18n/i18n";
import { contextCache } from "src/cache/contextCache";
import { contextCache } from "src/utils/payload";
import { formatCurrency } from "src/utils/currencies";
import { formatLocale } from "src/utils/format";
import { prepareClassForSelectedCurrencyPostProcessing } from "src/middleware/postProcessing";

View File

@ -2,7 +2,7 @@
import type { EndpointChronologyEvent } from "src/shared/payload/payload-sdk";
import TimelineEvent from "./TimelineEvent.astro";
import { getI18n } from "src/i18n/i18n";
import { contextCache } from "src/cache/contextCache";
import { contextCache } from "src/utils/payload";
interface Props {
year: number;
@ -17,10 +17,6 @@ const eventsHaveDifferentDates = events.some(
);
const date = eventsHaveDifferentDates ? { year } : events[0]!.date;
const multiple = events.flatMap(({ events }) => events).length > 1;
if (year === 856) {
console.log({ eventsHaveDifferentDates, events: events.map(({ date }) => date) });
}
---
{/* ------------------------------------------- HTML ------------------------------------------- */}

View File

@ -6,10 +6,17 @@ import AppLayout from "components/AppLayout/AppLayout.astro";
import AppLayoutTitle from "components/AppLayout/components/AppLayoutTitle.astro";
import Card from "components/Card.astro";
import { getI18n } from "src/i18n/i18n";
import { contextCache } from "src/cache/contextCache";
import { contextCache } from "src/utils/payload";
import type { WordingKey } from "src/i18n/wordings-keys";
import { fetchOr404 } from "src/utils/responses";
const response = await fetchOr404(() => payload.getChronologyEvents());
if (response instanceof Response) {
return response;
}
Astro.locals.sdkCalls.add(response.endpointCalled);
const events = response.data;
const events = await payload.getChronologyEvents();
const groupedEvents = groupBy(events, (event) => event.date.year);
const { getLocalizedUrl, t, formatTimelineDate } = await getI18n(Astro.locals.currentLocale);
---

View File

@ -13,14 +13,12 @@ import { fetchOr404 } from "src/utils/responses";
import { getFileIcon } from "src/utils/attributes";
const id = Astro.params.id!;
const video = await fetchOr404(() => payload.getVideoByID(id));
if (video instanceof Response) {
return video;
const response = await fetchOr404(() => payload.getVideoByID(id));
if (response instanceof Response) {
return response;
}
const { getLocalizedMatch, t, formatFilesize, formatDate } = await getI18n(
Astro.locals.currentLocale
);
Astro.locals.sdkCalls.add(response.endpointCalled);
const video = response.data;
const {
translations,
attributes,
@ -34,6 +32,10 @@ const {
mimeType,
} = video;
const { getLocalizedMatch, t, formatFilesize, formatDate } = await getI18n(
Astro.locals.currentLocale
);
const { pretitle, title, subtitle, description, language } = getLocalizedMatch(translations);
const metaAttributes = [

View File

@ -1,4 +1,4 @@
import { contextCache } from "src/cache/contextCache";
import { contextCache } from "src/utils/payload";
const getUnlocalizedPathname = (pathname: string): string => {
for (const locale of contextCache.locales) {

View File

@ -1,177 +1,177 @@
{
"disclaimer": "Usage subject to terms: https://openexchangerates.org/terms",
"license": "https://openexchangerates.org/license",
"timestamp": 1719518400,
"timestamp": 1719604800,
"base": "USD",
"rates": {
"AED": 3.673,
"AFN": 70,
"ALL": 93.656243,
"AMD": 388.12,
"ANG": 1.803057,
"AFN": 71.063715,
"ALL": 93.708843,
"AMD": 388.16,
"ANG": 1.802366,
"AOA": 853.629,
"ARS": 911.0001,
"AUD": 1.504506,
"ARS": 911.483,
"AUD": 1.49888,
"AWG": 1.8025,
"AZN": 1.7,
"BAM": 1.827765,
"BAM": 1.828243,
"BBD": 2,
"BDT": 117.53659,
"BGN": 1.826865,
"BHD": 0.376928,
"BIF": 2882.5,
"BDT": 117.567308,
"BGN": 1.824066,
"BHD": 0.376918,
"BIF": 2877.015756,
"BMD": 1,
"BND": 1.357361,
"BOB": 6.912666,
"BRL": 5.5062,
"BND": 1.355347,
"BOB": 6.913636,
"BRL": 5.5903,
"BSD": 1,
"BTC": 0.000016286712,
"BTN": 83.510338,
"BWP": 13.649322,
"BYN": 3.274029,
"BZD": 2.016506,
"CAD": 1.36937,
"CDF": 2860,
"CHF": 0.898769,
"CLF": 0.034588,
"CLP": 954.24,
"CNH": 7.303225,
"CNY": 7.2683,
"COP": 4147.064273,
"CRC": 523.036765,
"BTC": 0.00001666854,
"BTN": 83.51892,
"BWP": 13.588017,
"BYN": 3.274442,
"BZD": 2.016789,
"CAD": 1.368179,
"CDF": 2843.605253,
"CHF": 0.898334,
"CLF": 0.034326,
"CLP": 947.15,
"CNH": 7.3002,
"CNY": 7.2677,
"COP": 4182.257769,
"CRC": 523.103268,
"CUC": 1,
"CUP": 25.75,
"CVE": 103.063904,
"CZK": 23.432,
"DJF": 177.5,
"DKK": 6.969109,
"DOP": 59.2,
"DZD": 134.481574,
"EGP": 48.0279,
"CVE": 103.074514,
"CZK": 23.392,
"DJF": 177.827972,
"DKK": 6.962786,
"DOP": 59.096817,
"DZD": 134.738656,
"EGP": 48.0286,
"ERN": 15,
"ETB": 57.750301,
"EUR": 0.934324,
"FJD": 2.24125,
"FKP": 0.791234,
"GBP": 0.791234,
"ETB": 57.758394,
"EUR": 0.933607,
"FJD": 2.2387,
"FKP": 0.791061,
"GBP": 0.791061,
"GEL": 2.8,
"GGP": 0.791234,
"GHS": 15.25,
"GIP": 0.791234,
"GGP": 0.791061,
"GHS": 15.25842,
"GIP": 0.791061,
"GMD": 67.775,
"GNF": 8595,
"GTQ": 7.773841,
"GYD": 209.310316,
"HKD": 7.808725,
"HNL": 24.762821,
"HRK": 7.039709,
"HTG": 132.614267,
"HUF": 370.35232,
"IDR": 16384.008966,
"ILS": 3.75783,
"IMP": 0.791234,
"INR": 83.466142,
"IQD": 1310.629281,
"GNF": 8612.182198,
"GTQ": 7.771251,
"GYD": 209.334678,
"HKD": 7.809383,
"HNL": 24.765136,
"HRK": 7.034895,
"HTG": 132.555762,
"HUF": 368.794829,
"IDR": 16351.422732,
"ILS": 3.76585,
"IMP": 0.791061,
"INR": 83.388488,
"IQD": 1310.765417,
"IRR": 42100,
"ISK": 139.14,
"JEP": 0.791234,
"JMD": 156.065666,
"ISK": 138.83,
"JEP": 0.791061,
"JMD": 156.080264,
"JOD": 0.7087,
"JPY": 160.819,
"KES": 129,
"KGS": 86.45,
"KHR": 4116,
"KMF": 460.04988,
"JPY": 160.8655,
"KES": 129.25,
"KGS": 86.4454,
"KHR": 4110.671159,
"KMF": 459.849919,
"KPW": 900,
"KRW": 1387.206613,
"KWD": 0.306775,
"KYD": 0.833746,
"KZT": 466.751615,
"LAK": 22077.44273,
"LBP": 89576.348385,
"LKR": 306.055904,
"LRD": 194.492735,
"LSL": 18.359053,
"LYD": 4.87349,
"MAD": 9.939151,
"MDL": 17.849263,
"MGA": 4476.966706,
"MKD": 57.476359,
"KRW": 1379.946543,
"KWD": 0.306773,
"KYD": 0.833423,
"KZT": 466.81538,
"LAK": 22075,
"LBP": 89600,
"LKR": 306.087327,
"LRD": 194.450023,
"LSL": 18.18,
"LYD": 4.875316,
"MAD": 9.940081,
"MDL": 17.830168,
"MGA": 4477.581302,
"MKD": 57.45758,
"MMK": 2481.91,
"MNT": 3450,
"MOP": 8.047221,
"MRU": 39.452362,
"MUR": 46.899999,
"MOP": 8.044281,
"MRU": 39.462689,
"MUR": 47.2,
"MVR": 15.405,
"MWK": 1734.657401,
"MXN": 18.41087,
"MYR": 4.7195,
"MZN": 63.850001,
"NAD": 18.359053,
"MWK": 1734.567667,
"MXN": 18.292389,
"MYR": 4.7175,
"MZN": 63.899991,
"NAD": 18.36094,
"NGN": 1515.9,
"NIO": 36.825702,
"NOK": 10.666237,
"NPR": 133.611854,
"NZD": 1.643791,
"OMR": 0.384955,
"NIO": 36.81119,
"NOK": 10.675842,
"NPR": 133.327095,
"NZD": 1.641672,
"OMR": 0.384947,
"PAB": 1,
"PEN": 3.823237,
"PGK": 3.904308,
"PHP": 58.639498,
"PKR": 278.503056,
"PLN": 4.029254,
"PYG": 7540.098869,
"QAR": 3.649042,
"RON": 4.6507,
"RSD": 109.379523,
"RUB": 84.998456,
"RWF": 1306.142519,
"SAR": 3.751634,
"PEN": 3.83492,
"PGK": 3.851055,
"PHP": 58.433004,
"PKR": 278.529263,
"PLN": 4.025131,
"PYG": 7540.873261,
"QAR": 3.647595,
"RON": 4.6472,
"RSD": 109.245,
"RUB": 85.744825,
"RWF": 1306.491928,
"SAR": 3.751727,
"SBD": 8.43942,
"SCR": 13.796937,
"SCR": 13.867107,
"SDG": 601,
"SEK": 10.62955,
"SGD": 1.358205,
"SHP": 0.791234,
"SEK": 10.596578,
"SGD": 1.35596,
"SHP": 0.791061,
"SLL": 20969.5,
"SOS": 571.751991,
"SRD": 30.623,
"SOS": 571.49784,
"SRD": 30.8385,
"SSP": 130.26,
"STD": 22281.8,
"STN": 22.899229,
"SVC": 8.754335,
"STN": 22.878594,
"SVC": 8.755235,
"SYP": 2512.53,
"SZL": 18.178413,
"THB": 36.7685,
"TJS": 10.65474,
"SZL": 18.183346,
"THB": 36.719,
"TJS": 10.656085,
"TMT": 3.51,
"TND": 3.136769,
"TOP": 2.36092,
"TRY": 32.836478,
"TTD": 6.7978,
"TWD": 32.560001,
"TZS": 2626.295328,
"UAH": 40.51595,
"UGX": 3711.539326,
"TND": 3.1465,
"TOP": 2.363716,
"TRY": 32.656998,
"TTD": 6.798721,
"TWD": 32.5085,
"TZS": 2635,
"UAH": 40.51974,
"UGX": 3712.013854,
"USD": 1,
"UYU": 39.578963,
"UZS": 12585.732694,
"VES": 36.35908,
"VND": 25455.008685,
"UYU": 39.446434,
"UZS": 12586.719022,
"VES": 36.390223,
"VND": 25455.011984,
"VUV": 118.722,
"WST": 2.8,
"XAF": 612.876514,
"XAG": 0.0345453,
"XAU": 0.00042988,
"XAF": 612.406173,
"XAG": 0.03435128,
"XAU": 0.00043009,
"XCD": 2.70255,
"XDR": 0.759718,
"XOF": 612.876514,
"XPD": 0.00108638,
"XPF": 111.494537,
"XPT": 0.00101314,
"XDR": 0.759476,
"XOF": 612.406173,
"XPD": 0.00104121,
"XPF": 111.408973,
"XPT": 0.00100687,
"YER": 250.399984,
"ZAR": 18.4643,
"ZMW": 25.735569,
"ZAR": 18.190651,
"ZMW": 25.739177,
"ZWL": 322
}
}

View File

@ -2082,30 +2082,17 @@ export type EndpointAllSDKUrls = {
// SDK
type GetPayloadSDKParams = {
apiURL: string;
email: string;
password: string;
tokenCache?: {
set: (token: string, expirationTimestamp: number) => void;
get: () => string | undefined;
};
responseCache?: {
set: (url: string, response: any) => void;
get: (url: string) => any | undefined;
};
};
const logResponse = (res: Response) => console.log(res.status, res.statusText, res.url);
export const getSDKEndpoint = {
getConfigEndpoint: () => `/globals/${Collections.WebsiteConfig}/config`,
getFolderEndpoint: (slug: string) => `/${Collections.Folders}/slug/${slug}`,
getFolderSlugsEndpoint: () => `/${Collections.Folders}/slugs`,
getLanguagesEndpoint: () => `/${Collections.Languages}/all`,
getCurrenciesEndpoint: () => `/${Collections.Currencies}/all`,
getWordingsEndpoint: () => `/${Collections.Wordings}/all`,
getPageEndpoint: (slug: string) => `/${Collections.Pages}/slug/${slug}`,
getPageSlugsEndpoint: () => `/${Collections.Pages}/slugs`,
getCollectibleEndpoint: (slug: string) => `/${Collections.Collectibles}/slug/${slug}`,
getCollectibleSlugsEndpoint: () => `/${Collections.Collectibles}/slugs`,
getCollectibleScansEndpoint: (slug: string) => `/${Collections.Collectibles}/slug/${slug}/scans`,
getCollectibleScanPageEndpoint: (slug: string, index: string) =>
`/${Collections.Collectibles}/slug/${slug}/scans/${index}`,
@ -2124,21 +2111,51 @@ export const getSDKEndpoint = {
getLoginEndpoint: () => `/${Collections.Recorders}/login`,
};
export const getPayloadSDK = ({
apiURL,
email,
password,
tokenCache,
responseCache,
}: GetPayloadSDKParams) => {
const refreshToken = async () => {
const loginUrl = `${apiURL}${getSDKEndpoint.getLoginEndpoint()}`;
type PayloadSDKResponse<T> = {
data: T;
endpointCalled: string;
};
type PayloadTokenCache = {
set: (token: string, expirationTimestamp: number) => void;
get: () => string | undefined;
};
type PayloadDataCache = {
set: (url: string, response: any) => void;
get: (url: string) => any | undefined;
};
export class PayloadSDK {
private tokenCache: PayloadTokenCache | undefined;
private dataCache: PayloadDataCache | undefined;
constructor(
private readonly apiURL: string,
private readonly email: string,
private readonly password: string
) {}
addTokenCache(tokenCache: PayloadTokenCache) {
this.tokenCache = tokenCache;
}
addDataCache(dataCache: PayloadDataCache) {
this.dataCache = dataCache;
}
private logResponse(res: Response) {
console.log(res.status, res.statusText, res.url);
}
private async refreshToken() {
const loginUrl = `${this.apiURL}${getSDKEndpoint.getLoginEndpoint()}`;
const loginResult = await fetch(loginUrl, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email, password }),
body: JSON.stringify({ email: this.email, password: this.password }),
});
logResponse(loginResult);
this.logResponse(loginResult);
if (loginResult.status !== 200) {
throw new Error("Unable to login");
@ -2148,77 +2165,104 @@ export const getPayloadSDK = ({
token: string;
exp: number;
};
tokenCache?.set(token, exp);
this.tokenCache?.set(token, exp);
return token;
};
}
const request = async (endpoint: string): Promise<any> => {
const cachedResponse = responseCache?.get(endpoint);
async request<T>(endpoint: string): Promise<PayloadSDKResponse<T>> {
const cachedResponse = this.dataCache?.get(endpoint);
if (cachedResponse) {
return cachedResponse;
}
const result = await fetch(`${apiURL}${endpoint}`, {
const result = await fetch(`${this.apiURL}${endpoint}`, {
headers: {
Authorization: `JWT ${tokenCache?.get() ?? (await refreshToken())}`,
Authorization: `JWT ${this.tokenCache?.get() ?? (await this.refreshToken())}`,
},
});
logResponse(result);
this.logResponse(result);
if (!result.ok) {
throw new Error("Unhandled fetch error");
}
const data = await result.json();
responseCache?.set(endpoint, data);
return data;
};
const response = { data: await result.json(), endpointCalled: endpoint };
this.dataCache?.set(endpoint, response);
return response;
}
return {
getConfig: async (): Promise<EndpointWebsiteConfig> =>
await request(getSDKEndpoint.getConfigEndpoint()),
getFolder: async (slug: string): Promise<EndpointFolder> =>
await request(getSDKEndpoint.getFolderEndpoint(slug)),
getLanguages: async (): Promise<Language[]> =>
await request(getSDKEndpoint.getLanguagesEndpoint()),
getCurrencies: async (): Promise<Currency[]> =>
await request(getSDKEndpoint.getCurrenciesEndpoint()),
getWordings: async (): Promise<EndpointWording[]> =>
await request(getSDKEndpoint.getWordingsEndpoint()),
getPage: async (slug: string): Promise<EndpointPage> =>
await request(getSDKEndpoint.getPageEndpoint(slug)),
getCollectible: async (slug: string): Promise<EndpointCollectible> =>
await request(getSDKEndpoint.getCollectibleEndpoint(slug)),
getCollectibleScans: async (slug: string): Promise<EndpointCollectibleScans> =>
await request(getSDKEndpoint.getCollectibleScansEndpoint(slug)),
getCollectibleScanPage: async (
async getConfig(): Promise<PayloadSDKResponse<EndpointWebsiteConfig>> {
return await this.request(getSDKEndpoint.getConfigEndpoint());
}
async getFolder(slug: string): Promise<PayloadSDKResponse<EndpointFolder>> {
return await this.request(getSDKEndpoint.getFolderEndpoint(slug));
}
async getFolderSlugs(): Promise<PayloadSDKResponse<string[]>> {
return await this.request(getSDKEndpoint.getFolderSlugsEndpoint());
}
async getLanguages(): Promise<PayloadSDKResponse<Language[]>> {
return await this.request(getSDKEndpoint.getLanguagesEndpoint());
}
async getCurrencies(): Promise<PayloadSDKResponse<Currency[]>> {
return await this.request(getSDKEndpoint.getCurrenciesEndpoint());
}
async getWordings(): Promise<PayloadSDKResponse<EndpointWording[]>> {
return await this.request(getSDKEndpoint.getWordingsEndpoint());
}
async getPage(slug: string): Promise<PayloadSDKResponse<EndpointPage>> {
return await this.request(getSDKEndpoint.getPageEndpoint(slug));
}
async getPageSlugs(): Promise<PayloadSDKResponse<string[]>> {
return await this.request(getSDKEndpoint.getPageSlugsEndpoint());
}
async getCollectible(slug: string): Promise<PayloadSDKResponse<EndpointCollectible>> {
return await this.request(getSDKEndpoint.getCollectibleEndpoint(slug));
}
async getCollectibleSlugs(): Promise<PayloadSDKResponse<string[]>> {
return await this.request(getSDKEndpoint.getCollectibleSlugsEndpoint());
}
async getCollectibleScans(slug: string): Promise<PayloadSDKResponse<EndpointCollectibleScans>> {
return await this.request(getSDKEndpoint.getCollectibleScansEndpoint(slug));
}
async getCollectibleScanPage(
slug: string,
index: string
): Promise<EndpointCollectibleScanPage> =>
await request(getSDKEndpoint.getCollectibleScanPageEndpoint(slug, index)),
getCollectibleGallery: async (slug: string): Promise<EndpointCollectibleGallery> =>
await request(getSDKEndpoint.getCollectibleGalleryEndpoint(slug)),
getCollectibleGalleryImage: async (
): Promise<PayloadSDKResponse<EndpointCollectibleScanPage>> {
return await this.request(getSDKEndpoint.getCollectibleScanPageEndpoint(slug, index));
}
async getCollectibleGallery(
slug: string
): Promise<PayloadSDKResponse<EndpointCollectibleGallery>> {
return await this.request(getSDKEndpoint.getCollectibleGalleryEndpoint(slug));
}
async getCollectibleGalleryImage(
slug: string,
index: string
): Promise<EndpointCollectibleGalleryImage> =>
await request(getSDKEndpoint.getCollectibleGalleryImageEndpoint(slug, index)),
getChronologyEvents: async (): Promise<EndpointChronologyEvent[]> =>
await request(getSDKEndpoint.getChronologyEventsEndpoint()),
getChronologyEventByID: async (id: string): Promise<EndpointChronologyEvent> =>
await request(getSDKEndpoint.getChronologyEventByIDEndpoint(id)),
getImageByID: async (id: string): Promise<EndpointImage> =>
await request(getSDKEndpoint.getImageByIDEndpoint(id)),
getAudioByID: async (id: string): Promise<EndpointAudio> =>
await request(getSDKEndpoint.getAudioByIDEndpoint(id)),
getVideoByID: async (id: string): Promise<EndpointVideo> =>
await request(getSDKEndpoint.getVideoByIDEndpoint(id)),
getFileByID: async (id: string): Promise<EndpointFile> =>
await request(getSDKEndpoint.getFileByIDEndpoint(id)),
getRecorderByID: async (id: string): Promise<EndpointRecorder> =>
await request(getSDKEndpoint.getRecorderByIDEndpoint(id)),
getAllSdkUrls: async (): Promise<EndpointAllSDKUrls> =>
await request(getSDKEndpoint.getAllSDKUrlsEndpoint()),
request: async (pathname: string): Promise<any> => await request(pathname),
};
};
): Promise<PayloadSDKResponse<EndpointCollectibleGalleryImage>> {
return await this.request(getSDKEndpoint.getCollectibleGalleryImageEndpoint(slug, index));
}
async getChronologyEvents(): Promise<PayloadSDKResponse<EndpointChronologyEvent[]>> {
return await this.request(getSDKEndpoint.getChronologyEventsEndpoint());
}
async getChronologyEventByID(id: string): Promise<PayloadSDKResponse<EndpointChronologyEvent>> {
return await this.request(getSDKEndpoint.getChronologyEventByIDEndpoint(id));
}
async getImageByID(id: string): Promise<PayloadSDKResponse<EndpointImage>> {
return await this.request(getSDKEndpoint.getImageByIDEndpoint(id));
}
async getAudioByID(id: string): Promise<PayloadSDKResponse<EndpointAudio>> {
return await this.request(getSDKEndpoint.getAudioByIDEndpoint(id));
}
async getVideoByID(id: string): Promise<PayloadSDKResponse<EndpointVideo>> {
return await this.request(getSDKEndpoint.getVideoByIDEndpoint(id));
}
async getFileByID(id: string): Promise<PayloadSDKResponse<EndpointFile>> {
return await this.request(getSDKEndpoint.getFileByIDEndpoint(id));
}
async getRecorderByID(id: string): Promise<PayloadSDKResponse<EndpointRecorder>> {
return await this.request(getSDKEndpoint.getRecorderByIDEndpoint(id));
}
async getAllSdkUrls(): Promise<PayloadSDKResponse<EndpointAllSDKUrls>> {
return await this.request(getSDKEndpoint.getAllSDKUrlsEndpoint());
}
}

View File

@ -6,7 +6,7 @@ import {
type RichTextContent,
type RichTextNode,
} from "src/shared/payload/payload-sdk";
import { contextCache } from "src/cache/contextCache";
import { contextCache } from "src/utils/payload";
export const formatLocale = (code: string): string =>
contextCache.locales.find(({ id }) => id === code)?.name ?? code;

View File

@ -1,28 +1,20 @@
import { dataCache } from "src/cache/dataCache";
import { getPayloadSDK } from "src/shared/payload/payload-sdk";
import { ContextCache } from "src/cache/contextCache";
import { DataCache } from "src/cache/dataCache";
import { PageCache } from "src/cache/pageCache";
import { TokenCache } from "src/cache/tokenCache";
import { PayloadSDK } from "src/shared/payload/payload-sdk";
let token: string | undefined = undefined;
let expiration: number | undefined = undefined;
const payload = new PayloadSDK(
import.meta.env.PAYLOAD_API_URL,
import.meta.env.PAYLOAD_USER,
import.meta.env.PAYLOAD_PASSWORD
);
export const payload = getPayloadSDK({
apiURL: import.meta.env.PAYLOAD_API_URL,
email: import.meta.env.PAYLOAD_USER,
password: import.meta.env.PAYLOAD_PASSWORD,
tokenCache: {
get: () => {
if (!token) return undefined;
if (!expiration || expiration < Date.now()) {
console.log("[PayloadSDK] No token to be retrieved or the token expired");
return undefined;
}
return token;
},
set: (newToken, newExpiration) => {
token = newToken;
expiration = newExpiration * 1000;
const diffInMinutes = Math.floor((expiration - Date.now()) / 1000 / 60);
console.log("[PayloadSDK] New token set. TTL is", diffInMinutes, "minutes.");
},
},
responseCache: dataCache,
});
const contextCache = new ContextCache(payload);
const pageCache = new PageCache(payload);
const dataCache = new DataCache(payload, (urls) => pageCache.invalidate(urls));
payload.addTokenCache(new TokenCache());
payload.addDataCache(dataCache);
export { payload, contextCache, pageCache, dataCache };