Organized caching + groundwork for page caching
This commit is contained in:
parent
d9ef48d811
commit
2cacccae86
1
TODO.md
1
TODO.md
|
@ -10,7 +10,6 @@
|
|||
## Short term
|
||||
|
||||
- [Bugs] On android Chrome, the setting button in the header flashes for a few ms when the page is loading
|
||||
- [Feat] [caching] Use getURLs for precaching + precache everything
|
||||
- [Bugs] Make sure uploads name are slug-like and with an extension.
|
||||
- [Bugs] Nyupun can't upload subtitles files
|
||||
- [Bugs] https://v3.accords-library.com/en/collectibles/dod-original-soundtrack/scans obi is way too big
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
import type {
|
||||
EndpointWebsiteConfig,
|
||||
EndpointWording,
|
||||
Language,
|
||||
} from "src/shared/payload/payload-sdk";
|
||||
import { getLogger } from "src/utils/logger";
|
||||
import { payload } from "src/utils/payload";
|
||||
|
||||
class ContextCache {
|
||||
private initialized = false;
|
||||
private logger = getLogger("[ContextCache]");
|
||||
|
||||
locales: Language[] = [];
|
||||
currencies: string[] = [];
|
||||
wordings: EndpointWording[] = [];
|
||||
config: EndpointWebsiteConfig = {
|
||||
home: { folders: [] },
|
||||
timeline: { breaks: [], eras: [], eventCount: 0 },
|
||||
};
|
||||
|
||||
async init() {
|
||||
if (this.initialized) return;
|
||||
await this.refreshAll();
|
||||
this.initialized = true;
|
||||
this.logger.log("Init complete");
|
||||
}
|
||||
|
||||
private async refreshAll() {
|
||||
await this.refreshCurrencies();
|
||||
await this.refreshLocales();
|
||||
await this.refreshWebsiteConfig();
|
||||
await this.refreshWordings();
|
||||
}
|
||||
|
||||
async refreshWordings() {
|
||||
this.wordings = await payload.getWordings();
|
||||
this.logger.log("Wordings refreshed");
|
||||
}
|
||||
|
||||
async refreshCurrencies() {
|
||||
contextCache.currencies = (await payload.getCurrencies()).map(({ id }) => id);
|
||||
this.logger.log("Currencies refreshed");
|
||||
}
|
||||
|
||||
async refreshLocales() {
|
||||
contextCache.locales = await payload.getLanguages();
|
||||
this.logger.log("Locales refreshed");
|
||||
}
|
||||
|
||||
async refreshWebsiteConfig() {
|
||||
contextCache.config = await payload.getConfig();
|
||||
this.logger.log("WebsiteConfig refreshed");
|
||||
}
|
||||
}
|
||||
|
||||
const contextCache = new ContextCache();
|
||||
await contextCache.init();
|
||||
export { contextCache };
|
|
@ -0,0 +1,84 @@
|
|||
import { getLogger } from "src/utils/logger";
|
||||
import { payload } from "src/utils/payload";
|
||||
|
||||
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>>();
|
||||
|
||||
async init() {
|
||||
if (this.initialized) return;
|
||||
|
||||
if (import.meta.env.ENABLE_PRECACHING === "true") {
|
||||
await this.precache();
|
||||
}
|
||||
|
||||
this.initialized = true;
|
||||
}
|
||||
|
||||
private async precache() {
|
||||
const { urls } = await payload.getAllSdkUrls();
|
||||
for (const url of urls) {
|
||||
try {
|
||||
await payload.request(url);
|
||||
} catch {
|
||||
this.logger.warn("Precaching failed for url", url);
|
||||
}
|
||||
}
|
||||
this.logger.log("Precaching completed!", this.responseCache.size, "responses cached");
|
||||
}
|
||||
|
||||
get(url: string) {
|
||||
const cachedResponse = this.responseCache.get(url);
|
||||
if (cachedResponse) {
|
||||
this.logger.log("Retrieved cached response for", url);
|
||||
return structuredClone(cachedResponse);
|
||||
}
|
||||
}
|
||||
|
||||
set(url: string, response: any) {
|
||||
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.idsCacheMap.get(id);
|
||||
if (current) {
|
||||
current.add(url);
|
||||
} else {
|
||||
this.idsCacheMap.set(id, new Set([url]));
|
||||
}
|
||||
});
|
||||
|
||||
this.responseCache.set(url, response);
|
||||
this.logger.log("Cached response for", url);
|
||||
}
|
||||
|
||||
async invalidate(ids: string[], urls: string[]) {
|
||||
const urlsToInvalidate = new Set<string>(urls);
|
||||
|
||||
ids.forEach((id) => {
|
||||
const urlsForThisId = this.idsCacheMap.get(id);
|
||||
if (!urlsForThisId) return;
|
||||
this.idsCacheMap.delete(id);
|
||||
[...urlsForThisId].forEach((url) => urlsToInvalidate.add(url));
|
||||
});
|
||||
|
||||
for (const url of urlsToInvalidate) {
|
||||
this.responseCache.delete(url);
|
||||
this.logger.log("Invalidated cache for", url);
|
||||
try {
|
||||
await payload.request(url);
|
||||
} catch (e) {
|
||||
this.logger.log("Revalidation fails for", url);
|
||||
}
|
||||
}
|
||||
|
||||
this.logger.log("There are currently", this.responseCache.size, "responses in cache.");
|
||||
}
|
||||
}
|
||||
|
||||
export const dataCache = new DataCache();
|
|
@ -7,7 +7,7 @@ import type {
|
|||
EndpointPayloadImage,
|
||||
EndpointVideo,
|
||||
} from "src/shared/payload/payload-sdk";
|
||||
import { cache } from "src/utils/payload";
|
||||
import { contextCache } from "src/cache/contextCache";
|
||||
|
||||
interface Props {
|
||||
openGraph?:
|
||||
|
@ -28,7 +28,9 @@ const { openGraph = {} } = Astro.props;
|
|||
const { description = t("global.meta.description"), audio, video } = openGraph;
|
||||
|
||||
const thumbnail =
|
||||
openGraph.thumbnail?.openGraph ?? openGraph.thumbnail ?? cache.config.defaultOpenGraphImage;
|
||||
openGraph.thumbnail?.openGraph ??
|
||||
openGraph.thumbnail ??
|
||||
contextCache.config.defaultOpenGraphImage;
|
||||
|
||||
const title = openGraph.title
|
||||
? `${openGraph.title} – ${t("global.siteName")}`
|
||||
|
@ -38,8 +40,6 @@ const userAgent = Astro.request.headers.get("user-agent") ?? "";
|
|||
const parser = new UAParser(userAgent);
|
||||
const isIOS = parser.getOS().name === "iOS";
|
||||
|
||||
const { currentTheme } = Astro.locals;
|
||||
|
||||
/* Keep that separator here or else it breaks the HTML
|
||||
----------------------------------------------- HTML -------------------------------------------- */
|
||||
---
|
||||
|
@ -47,9 +47,7 @@ const { currentTheme } = Astro.locals;
|
|||
<html
|
||||
lang={currentLocale}
|
||||
class:list={{
|
||||
"manual-theme": currentTheme !== "auto",
|
||||
"light-theme": currentTheme === "light",
|
||||
"dark-theme": currentTheme === "dark",
|
||||
POST_PROCESS_HTML_CLASS: true,
|
||||
"texture-dots": !isIOS,
|
||||
"font-m": true,
|
||||
"debug-lang": false,
|
||||
|
@ -310,7 +308,7 @@ const { currentTheme } = Astro.locals;
|
|||
color: var(--color-base-1000);
|
||||
}
|
||||
|
||||
html:not(.manual-theme) {
|
||||
html:not(.light-theme, .dark-theme) {
|
||||
@media (prefers-color-scheme: light) {
|
||||
& .when-dark-theme {
|
||||
display: none !important;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
import Button from "components/Button.astro";
|
||||
import Tooltip from "components/Tooltip.astro";
|
||||
import { getI18n } from "src/i18n/i18n";
|
||||
import { cache } from "src/utils/payload";
|
||||
import { contextCache } from "src/cache/contextCache";
|
||||
import { formatCurrency } from "src/utils/currencies";
|
||||
|
||||
interface Props {
|
||||
|
@ -21,14 +21,13 @@ const { currentCurrency } = Astro.locals;
|
|||
<Tooltip trigger="click" {...otherProps.class ? otherProps : {}}>
|
||||
<div id="content" slot="tooltip-content">
|
||||
{
|
||||
cache.currencies.map((id) => (
|
||||
contextCache.currencies.map((id) => (
|
||||
<a
|
||||
class:list={{
|
||||
current: currentCurrency === id,
|
||||
"pressable-link": true,
|
||||
}}
|
||||
href={`?action-currency=${id}`}
|
||||
data-astro-prefetch="tap">
|
||||
href={`?action-currency=${id}`}>
|
||||
{`${id} (${formatCurrency(id)})`}
|
||||
</a>
|
||||
))
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
import Button from "components/Button.astro";
|
||||
import Tooltip from "components/Tooltip.astro";
|
||||
import { getI18n } from "src/i18n/i18n";
|
||||
import { cache } from "src/utils/payload";
|
||||
import { contextCache } from "src/cache/contextCache";
|
||||
import { formatLocale } from "src/utils/format";
|
||||
|
||||
interface Props {
|
||||
|
@ -21,11 +21,10 @@ const { t } = await getI18n(currentLocale);
|
|||
<Tooltip trigger="click" {...otherProps.class ? otherProps : {}}>
|
||||
<div id="content" slot="tooltip-content">
|
||||
{
|
||||
cache.locales.map(({ id }) => (
|
||||
contextCache.locales.map(({ id }) => (
|
||||
<a
|
||||
class:list={{ current: currentLocale === id, "pressable-link": true }}
|
||||
href={`?action-lang=${id}`}
|
||||
data-astro-prefetch="tap">
|
||||
href={`?action-lang=${id}`}>
|
||||
{formatLocale(id)}
|
||||
</a>
|
||||
))
|
||||
|
|
|
@ -3,7 +3,7 @@ import Button from "components/Button.astro";
|
|||
import Tooltip from "components/Tooltip.astro";
|
||||
import { getI18n } from "src/i18n/i18n";
|
||||
|
||||
const { currentLocale, currentTheme } = Astro.locals;
|
||||
const { currentLocale } = Astro.locals;
|
||||
const { t } = await getI18n(currentLocale);
|
||||
---
|
||||
|
||||
|
@ -11,19 +11,13 @@ const { t } = await getI18n(currentLocale);
|
|||
|
||||
<Tooltip trigger="click">
|
||||
<div id="content" slot="tooltip-content">
|
||||
<a
|
||||
class:list={{ current: currentTheme === "dark", "pressable-link": true }}
|
||||
href="?action-theme=dark">
|
||||
<a class="pressable-link underline-when-dark" href="?action-theme=dark">
|
||||
{t("global.theme.dark")}
|
||||
</a>
|
||||
<a
|
||||
class:list={{ current: currentTheme === "auto", "pressable-link": true }}
|
||||
href="?action-theme=auto">
|
||||
<a class="pressable-link underline-when-auto" href="?action-theme=auto">
|
||||
{t("global.theme.auto")}
|
||||
</a>
|
||||
<a
|
||||
class:list={{ current: currentTheme === "light", "pressable-link": true }}
|
||||
href="?action-theme=light">
|
||||
<a class="pressable-link underline-when-light" href="?action-theme=light">
|
||||
{t("global.theme.light")}
|
||||
</a>
|
||||
</div>
|
||||
|
@ -45,10 +39,12 @@ const { t } = await getI18n(currentLocale);
|
|||
#content {
|
||||
display: grid;
|
||||
gap: 0.5em;
|
||||
}
|
||||
|
||||
& > .current {
|
||||
color: var(--color-base-750);
|
||||
text-decoration: underline 0.08em var(--color-base-650);
|
||||
}
|
||||
:global(html.light-theme) a.underline-when-light,
|
||||
:global(html.dark-theme) a.underline-when-dark,
|
||||
:global(html:not(.light-theme, .dark-theme)) a.underline-when-auto {
|
||||
color: var(--color-base-750);
|
||||
text-decoration: underline 0.08em var(--color-base-650);
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
declare namespace App {
|
||||
interface Locals {
|
||||
currentLocale: string;
|
||||
currentTheme: "dark" | "auto" | "light";
|
||||
currentCurrency: string;
|
||||
notFound: boolean;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import type { WordingKey } from "src/i18n/wordings-keys";
|
||||
import type { ChronologyEvent, EndpointSource } from "src/shared/payload/payload-sdk";
|
||||
import { cache } from "src/utils/payload";
|
||||
import { contextCache } from "src/cache/contextCache";
|
||||
import { capitalize, formatInlineTitle } from "src/utils/format";
|
||||
|
||||
export const defaultLocale = "en";
|
||||
|
@ -113,7 +113,7 @@ export const getI18n = async (locale: string) => {
|
|||
options[0]!; // We will consider that there will always be at least one option.
|
||||
|
||||
const t = (key: WordingKey, values: Record<string, any> = {}): string => {
|
||||
const wording = cache.wordings.find(({ name }) => name === key);
|
||||
const wording = contextCache.wordings.find(({ name }) => name === key);
|
||||
const fallbackString = `«${key}»`;
|
||||
|
||||
if (!wording) {
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { defineMiddleware, sequence } from "astro:middleware";
|
||||
import { cache } from "src/utils/payload";
|
||||
import acceptLanguage from "accept-language";
|
||||
import type { AstroCookies } from "astro";
|
||||
import { z } from "astro:content";
|
||||
import { trackRequest, trackEvent } from "src/shared/analytics/analytics";
|
||||
import { defaultLocale } from "src/i18n/i18n";
|
||||
import { contextCache } from "src/cache/contextCache";
|
||||
|
||||
const ninetyDaysInSeconds = 60 * 60 * 24 * 90;
|
||||
|
||||
|
@ -141,20 +141,22 @@ const refreshCookiesMaxAge = defineMiddleware(async ({ cookies }, next) => {
|
|||
return response;
|
||||
});
|
||||
|
||||
const addContentLanguageResponseHeader = defineMiddleware(async ({ url }, next) => {
|
||||
const addCommonHeaders = defineMiddleware(async ({ url }, next) => {
|
||||
const currentLocale = getCurrentLocale(url.pathname);
|
||||
|
||||
const response = await next();
|
||||
if (response.status === 200 && currentLocale) {
|
||||
if (response.ok && currentLocale) {
|
||||
response.headers.set("Content-Language", currentLocale);
|
||||
}
|
||||
|
||||
response.headers.set("Vary", "Cookie");
|
||||
|
||||
return response;
|
||||
});
|
||||
|
||||
const provideLocalsToRequest = defineMiddleware(async ({ url, locals, cookies }, next) => {
|
||||
locals.currentLocale = getCurrentLocale(url.pathname) ?? "en";
|
||||
locals.currentCurrency = getCookieCurrency(cookies) ?? "USD";
|
||||
locals.currentTheme = getCookieTheme(cookies) ?? "auto";
|
||||
return next();
|
||||
});
|
||||
|
||||
|
@ -165,19 +167,40 @@ const analytics = defineMiddleware(async (context, next) => {
|
|||
return response;
|
||||
});
|
||||
|
||||
const postProcess = defineMiddleware(async ({ cookies }, next) => {
|
||||
const response = await next();
|
||||
if (!response.ok) {
|
||||
return response;
|
||||
}
|
||||
|
||||
let html = await response.text();
|
||||
|
||||
const currentTheme = getCookieTheme(cookies) ?? "auto";
|
||||
html = html.replace(
|
||||
"POST_PROCESS_HTML_CLASS",
|
||||
currentTheme === "dark" ? "dark-theme" : currentTheme === "light" ? "light-theme" : ""
|
||||
);
|
||||
return new Response(html, response);
|
||||
});
|
||||
|
||||
export const onRequest = sequence(
|
||||
addContentLanguageResponseHeader,
|
||||
// Possible redirect
|
||||
handleActionsSearchParams,
|
||||
refreshCookiesMaxAge,
|
||||
localeNegotiator,
|
||||
|
||||
addCommonHeaders,
|
||||
|
||||
// Get a response
|
||||
analytics,
|
||||
refreshCookiesMaxAge,
|
||||
provideLocalsToRequest,
|
||||
analytics
|
||||
postProcess
|
||||
);
|
||||
|
||||
/* LOCALE */
|
||||
|
||||
const getCurrentLocale = (pathname: string): string | undefined => {
|
||||
for (const locale of cache.locales) {
|
||||
for (const locale of contextCache.locales) {
|
||||
if (pathname.split("/")[1] === locale.id) {
|
||||
return locale.id;
|
||||
}
|
||||
|
@ -189,7 +212,7 @@ const getBestAcceptedLanguage = (request: Request): string | undefined => {
|
|||
const header = request.headers.get("Accept-Language");
|
||||
if (!header) return;
|
||||
|
||||
acceptLanguage.languages(cache.locales.map(({ id }) => id));
|
||||
acceptLanguage.languages(contextCache.locales.map(({ id }) => id));
|
||||
|
||||
return acceptLanguage.get(request.headers.get("Accept-Language")) ?? undefined;
|
||||
};
|
||||
|
@ -220,10 +243,12 @@ export const getCookieTheme = (cookies: AstroCookies): z.infer<typeof themeSchem
|
|||
};
|
||||
|
||||
export const isValidCurrency = (currency: string | null | undefined): currency is string =>
|
||||
currency !== null && currency != undefined && cache.currencies.includes(currency);
|
||||
currency !== null && currency != undefined && contextCache.currencies.includes(currency);
|
||||
|
||||
export const isValidLocale = (locale: string | null | undefined): locale is string =>
|
||||
locale !== null && locale != undefined && cache.locales.map(({ id }) => id).includes(locale);
|
||||
locale !== null &&
|
||||
locale != undefined &&
|
||||
contextCache.locales.map(({ id }) => id).includes(locale);
|
||||
|
||||
export const isValidTheme = (
|
||||
theme: string | null | undefined
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
import LibraryCard from "./LibraryCard.astro";
|
||||
import { getI18n } from "src/i18n/i18n";
|
||||
import { cache } from "src/utils/payload";
|
||||
import { contextCache } from "src/cache/contextCache";
|
||||
|
||||
const { getLocalizedUrl, getLocalizedMatch } = await getI18n(Astro.locals.currentLocale);
|
||||
---
|
||||
|
@ -9,7 +9,7 @@ const { getLocalizedUrl, getLocalizedMatch } = await getI18n(Astro.locals.curren
|
|||
{/* ------------------------------------------- HTML ------------------------------------------- */}
|
||||
|
||||
{
|
||||
cache.config.home.folders.map(({ slug, translations, darkThumbnail, lightThumbnail }) => (
|
||||
contextCache.config.home.folders.map(({ slug, translations, darkThumbnail, lightThumbnail }) => (
|
||||
<LibraryCard
|
||||
img={
|
||||
darkThumbnail && lightThumbnail ? { dark: darkThumbnail, light: lightThumbnail } : undefined
|
||||
|
|
|
@ -1,12 +1,7 @@
|
|||
import type { APIRoute } from "astro";
|
||||
import { contextCache } from "src/cache/contextCache";
|
||||
import { dataCache } from "src/cache/dataCache";
|
||||
import { Collections, type AfterOperationWebHookMessage } from "src/shared/payload/payload-sdk";
|
||||
import {
|
||||
invalidateDataCache,
|
||||
refreshCurrencies,
|
||||
refreshLocales,
|
||||
refreshWebsiteConfig,
|
||||
refreshWordings,
|
||||
} from "src/utils/payload";
|
||||
|
||||
export const POST: APIRoute = async ({ request }) => {
|
||||
const auth = request.headers.get("Authorization");
|
||||
|
@ -30,23 +25,23 @@ const handleWebHookMessage = async ({
|
|||
urls,
|
||||
id,
|
||||
}: AfterOperationWebHookMessage) => {
|
||||
await invalidateDataCache([...(id ? [id] : []), ...addedDependantIds], urls);
|
||||
await dataCache.invalidate([...(id ? [id] : []), ...addedDependantIds], urls);
|
||||
|
||||
switch (collection) {
|
||||
case Collections.Wordings:
|
||||
await refreshWordings();
|
||||
await contextCache.refreshWordings();
|
||||
break;
|
||||
|
||||
case Collections.Currencies:
|
||||
await refreshCurrencies();
|
||||
await contextCache.refreshCurrencies();
|
||||
break;
|
||||
|
||||
case Collections.Languages:
|
||||
await refreshLocales();
|
||||
await contextCache.refreshLocales();
|
||||
break;
|
||||
|
||||
case Collections.WebsiteConfig:
|
||||
await refreshWebsiteConfig();
|
||||
await contextCache.refreshWebsiteConfig();
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import type { APIRoute } from "astro";
|
||||
import { initPayload } from "src/utils/payload";
|
||||
import { dataCache } from "src/cache/dataCache";
|
||||
|
||||
export const GET: APIRoute = async () => {
|
||||
await initPayload();
|
||||
await dataCache.init();
|
||||
return new Response(null, { status: 200, statusText: "Ok" });
|
||||
};
|
||||
|
|
|
@ -9,7 +9,7 @@ interface Props {
|
|||
const { baseColors, theme } = Astro.props;
|
||||
---
|
||||
|
||||
<div id="container" class:list={[theme, "manual-theme"]}>
|
||||
<div id="container" class:list={theme}>
|
||||
<h4 class="font-xl">Base colors</h4>
|
||||
<div class="colors">
|
||||
{
|
||||
|
|
|
@ -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 { cache } from "src/utils/payload";
|
||||
import { contextCache } from "src/cache/contextCache";
|
||||
import AppLayout from "components/AppLayout/AppLayout.astro";
|
||||
import HomeTitle from "./_components/HomeTitle.astro";
|
||||
|
||||
|
@ -14,7 +14,7 @@ const { t, getLocalizedUrl } = await getI18n(Astro.locals.currentLocale);
|
|||
|
||||
<AppLayout
|
||||
openGraph={{ title: t("home.title") }}
|
||||
backgroundImage={cache.config.home.backgroundImage}
|
||||
backgroundImage={contextCache.config.home.backgroundImage}
|
||||
hideFooterLinks
|
||||
hideHomeButton
|
||||
class="app">
|
||||
|
@ -77,8 +77,8 @@ const { t, getLocalizedUrl } = await getI18n(Astro.locals.currentLocale);
|
|||
icon="material-symbols:calendar-month"
|
||||
title={t("footer.links.timeline.title")}
|
||||
subtitle={t("footer.links.timeline.subtitle", {
|
||||
eraCount: cache.config.timeline.eras.length,
|
||||
eventCount: cache.config.timeline.eventCount,
|
||||
eraCount: contextCache.config.timeline.eras.length,
|
||||
eventCount: contextCache.config.timeline.eventCount,
|
||||
})}
|
||||
href={getLocalizedUrl("/timeline")}
|
||||
/>
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
import AppLayout from "components/AppLayout/AppLayout.astro";
|
||||
import AppLayoutTitle from "components/AppLayout/components/AppLayoutTitle.astro";
|
||||
import { getI18n } from "src/i18n/i18n";
|
||||
import { cache } from "src/utils/payload";
|
||||
import { contextCache } from "src/cache/contextCache";
|
||||
import { formatCurrency } from "src/utils/currencies";
|
||||
import { formatLocale } from "src/utils/format";
|
||||
|
||||
const { currentLocale, currentTheme, currentCurrency } = Astro.locals;
|
||||
const { currentLocale, currentCurrency } = Astro.locals;
|
||||
const { t } = await getI18n(currentLocale);
|
||||
---
|
||||
|
||||
|
@ -20,11 +20,10 @@ const { t } = await getI18n(currentLocale);
|
|||
<h2>{t("settings.language.title")}</h2>
|
||||
<p>{t("settings.language.description")}</p><br />
|
||||
{
|
||||
cache.locales.map(({ id }) => (
|
||||
contextCache.locales.map(({ id }) => (
|
||||
<a
|
||||
class:list={{ current: currentLocale === id, "pressable-link": true }}
|
||||
href={`?action-lang=${id}`}
|
||||
data-astro-prefetch="tap">
|
||||
href={`?action-lang=${id}`}>
|
||||
{formatLocale(id)}
|
||||
</a>
|
||||
))
|
||||
|
@ -34,22 +33,13 @@ const { t } = await getI18n(currentLocale);
|
|||
<div class="section">
|
||||
<h2>{t("settings.theme.title")}</h2>
|
||||
<p>{t("settings.theme.description")}</p><br />
|
||||
<a
|
||||
class:list={{ current: currentTheme === "dark", "pressable-link": true }}
|
||||
href="?action-theme=dark"
|
||||
data-astro-prefetch="tap">
|
||||
<a class="pressable-link underline-when-dark" href="?action-theme=dark">
|
||||
{t("global.theme.dark")}
|
||||
</a>
|
||||
<a
|
||||
class:list={{ current: currentTheme === "auto", "pressable-link": true }}
|
||||
href="?action-theme=auto"
|
||||
data-astro-prefetch="tap">
|
||||
<a class="pressable-link underline-when-auto" href="?action-theme=auto">
|
||||
{t("global.theme.auto")}
|
||||
</a>
|
||||
<a
|
||||
class:list={{ current: currentTheme === "light", "pressable-link": true }}
|
||||
href="?action-theme=light"
|
||||
data-astro-prefetch="tap">
|
||||
<a class="pressable-link underline-when-light" href="?action-theme=light">
|
||||
{t("global.theme.light")}
|
||||
</a>
|
||||
</div>
|
||||
|
@ -58,11 +48,10 @@ const { t } = await getI18n(currentLocale);
|
|||
<h2>{t("settings.currency.title")}</h2>
|
||||
<p>{t("settings.currency.description")}</p><br />
|
||||
{
|
||||
cache.currencies.map((id) => (
|
||||
contextCache.currencies.map((id) => (
|
||||
<a
|
||||
class:list={{ current: currentCurrency === id, "pressable-link": true }}
|
||||
href={`?action-currency=${id}`}
|
||||
data-astro-prefetch="tap">
|
||||
href={`?action-currency=${id}`}>
|
||||
{`${id} (${formatCurrency(id)})`}
|
||||
</a>
|
||||
))
|
||||
|
@ -86,6 +75,13 @@ const { t } = await getI18n(currentLocale);
|
|||
}
|
||||
}
|
||||
|
||||
:global(html.light-theme) a.underline-when-light,
|
||||
:global(html.dark-theme) a.underline-when-dark,
|
||||
:global(html:not(.light-theme, .dark-theme)) a.underline-when-auto {
|
||||
color: var(--color-base-750);
|
||||
text-decoration: underline 0.08em var(--color-base-650);
|
||||
}
|
||||
|
||||
#main {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||
|
|
|
@ -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 { cache } from "src/utils/payload";
|
||||
import { contextCache } from "src/cache/contextCache";
|
||||
|
||||
interface Props {
|
||||
year: number;
|
||||
|
@ -25,7 +25,7 @@ if (year === 856) {
|
|||
|
||||
{/* ------------------------------------------- HTML ------------------------------------------- */}
|
||||
|
||||
{cache.config.timeline.breaks.includes(year) && <hr id={`hr-${year}`} />}
|
||||
{contextCache.config.timeline.breaks.includes(year) && <hr id={`hr-${year}`} />}
|
||||
|
||||
<div>
|
||||
<h2 class="font-2xl" class:list={{ multiple }} id={year.toString()}>
|
||||
|
|
|
@ -6,7 +6,7 @@ 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 { cache } from "src/utils/payload";
|
||||
import { contextCache } from "src/cache/contextCache";
|
||||
import type { WordingKey } from "src/i18n/wordings-keys";
|
||||
|
||||
const events = await payload.getChronologyEvents();
|
||||
|
@ -16,7 +16,7 @@ const { getLocalizedUrl, t, formatTimelineDate } = await getI18n(Astro.locals.cu
|
|||
|
||||
{/* ------------------------------------------- HTML ------------------------------------------- */}
|
||||
|
||||
<AppLayout backgroundImage={cache.config.timeline.backgroundImage} class="app">
|
||||
<AppLayout backgroundImage={contextCache.config.timeline.backgroundImage} class="app">
|
||||
<AppLayoutTitle title={t("timeline.title")} />
|
||||
<p class="prose" set:html={t("timeline.description")} />
|
||||
|
||||
|
@ -54,7 +54,7 @@ const { getLocalizedUrl, t, formatTimelineDate } = await getI18n(Astro.locals.cu
|
|||
<h3>{t("timeline.jumpTo")}</h3>
|
||||
|
||||
{
|
||||
cache.config.timeline.eras.map(({ name, startingYear, endingYear }) => (
|
||||
contextCache.config.timeline.eras.map(({ name, startingYear, endingYear }) => (
|
||||
<p
|
||||
set:html={t(name as WordingKey, {
|
||||
start: `<a href="#${startingYear}">${formatTimelineDate({ year: startingYear })}</a>`,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { cache } from "src/utils/payload";
|
||||
import { contextCache } from "src/cache/contextCache";
|
||||
|
||||
const getUnlocalizedPathname = (pathname: string): string => {
|
||||
for (const locale of cache.locales) {
|
||||
for (const locale of contextCache.locales) {
|
||||
if (pathname.startsWith(`/${locale.id}`)) {
|
||||
return pathname.substring(`/${locale.id}`.length) || "/";
|
||||
}
|
||||
|
@ -30,7 +30,6 @@ export const trackRequest = (request: Request, { clientAddress, locals }: TrackR
|
|||
attributes: {
|
||||
locale: locals.currentLocale,
|
||||
currency: locals.currentCurrency,
|
||||
theme: locals.currentTheme,
|
||||
},
|
||||
},
|
||||
request: {
|
||||
|
|
|
@ -1,177 +1,177 @@
|
|||
{
|
||||
"disclaimer": "Usage subject to terms: https://openexchangerates.org/terms",
|
||||
"license": "https://openexchangerates.org/license",
|
||||
"timestamp": 1719374401,
|
||||
"timestamp": 1719518400,
|
||||
"base": "USD",
|
||||
"rates": {
|
||||
"AED": 3.673,
|
||||
"AFN": 70.737389,
|
||||
"ALL": 93.591883,
|
||||
"AMD": 388.464511,
|
||||
"ANG": 1.804398,
|
||||
"AOA": 855.209667,
|
||||
"ARS": 909.2076,
|
||||
"AUD": 1.498775,
|
||||
"AFN": 70,
|
||||
"ALL": 93.656243,
|
||||
"AMD": 388.12,
|
||||
"ANG": 1.803057,
|
||||
"AOA": 853.629,
|
||||
"ARS": 911.0001,
|
||||
"AUD": 1.504506,
|
||||
"AWG": 1.8025,
|
||||
"AZN": 1.7,
|
||||
"BAM": 1.825905,
|
||||
"BAM": 1.827765,
|
||||
"BBD": 2,
|
||||
"BDT": 117.631657,
|
||||
"BGN": 1.8261,
|
||||
"BHD": 0.376925,
|
||||
"BIF": 2879.142593,
|
||||
"BDT": 117.53659,
|
||||
"BGN": 1.826865,
|
||||
"BHD": 0.376928,
|
||||
"BIF": 2882.5,
|
||||
"BMD": 1,
|
||||
"BND": 1.354432,
|
||||
"BOB": 6.917863,
|
||||
"BRL": 5.452199,
|
||||
"BND": 1.357361,
|
||||
"BOB": 6.912666,
|
||||
"BRL": 5.5062,
|
||||
"BSD": 1,
|
||||
"BTC": 0.000016147327,
|
||||
"BTN": 83.525391,
|
||||
"BWP": 13.566127,
|
||||
"BYN": 3.276229,
|
||||
"BZD": 2.017943,
|
||||
"CAD": 1.365775,
|
||||
"CDF": 2845.344278,
|
||||
"CHF": 0.895078,
|
||||
"CLF": 0.034108,
|
||||
"CLP": 943.396226,
|
||||
"CNH": 7.292088,
|
||||
"CNY": 7.2661,
|
||||
"COP": 4092.688822,
|
||||
"CRC": 524.018922,
|
||||
"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,
|
||||
"CUC": 1,
|
||||
"CUP": 25.75,
|
||||
"CVE": 102.941746,
|
||||
"CZK": 23.187699,
|
||||
"DJF": 178.249371,
|
||||
"DKK": 6.9642,
|
||||
"DOP": 59.114309,
|
||||
"DZD": 134.5516,
|
||||
"EGP": 48.377851,
|
||||
"CVE": 103.063904,
|
||||
"CZK": 23.432,
|
||||
"DJF": 177.5,
|
||||
"DKK": 6.969109,
|
||||
"DOP": 59.2,
|
||||
"DZD": 134.481574,
|
||||
"EGP": 48.0279,
|
||||
"ERN": 15,
|
||||
"ETB": 57.353303,
|
||||
"EUR": 0.933624,
|
||||
"FJD": 2.2362,
|
||||
"FKP": 0.788219,
|
||||
"GBP": 0.788219,
|
||||
"GEL": 2.81,
|
||||
"GGP": 0.788219,
|
||||
"GHS": 15.216498,
|
||||
"GIP": 0.788219,
|
||||
"GMD": 67.75,
|
||||
"GNF": 8617.038799,
|
||||
"GTQ": 7.774894,
|
||||
"GYD": 209.365764,
|
||||
"HKD": 7.809496,
|
||||
"HNL": 24.774423,
|
||||
"HRK": 7.034221,
|
||||
"HTG": 132.791853,
|
||||
"HUF": 369.47,
|
||||
"IDR": 16421.779805,
|
||||
"ILS": 3.74785,
|
||||
"IMP": 0.788219,
|
||||
"INR": 83.447347,
|
||||
"IQD": 1311.401658,
|
||||
"IRR": 42087.5,
|
||||
"ISK": 139.21,
|
||||
"JEP": 0.788219,
|
||||
"JMD": 156.444628,
|
||||
"ETB": 57.750301,
|
||||
"EUR": 0.934324,
|
||||
"FJD": 2.24125,
|
||||
"FKP": 0.791234,
|
||||
"GBP": 0.791234,
|
||||
"GEL": 2.8,
|
||||
"GGP": 0.791234,
|
||||
"GHS": 15.25,
|
||||
"GIP": 0.791234,
|
||||
"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,
|
||||
"IRR": 42100,
|
||||
"ISK": 139.14,
|
||||
"JEP": 0.791234,
|
||||
"JMD": 156.065666,
|
||||
"JOD": 0.7087,
|
||||
"JPY": 159.8375,
|
||||
"KES": 129.646953,
|
||||
"KGS": 86.5868,
|
||||
"KHR": 4119.876268,
|
||||
"KMF": 460.124977,
|
||||
"JPY": 160.819,
|
||||
"KES": 129,
|
||||
"KGS": 86.45,
|
||||
"KHR": 4116,
|
||||
"KMF": 460.04988,
|
||||
"KPW": 900,
|
||||
"KRW": 1390.097786,
|
||||
"KWD": 0.306622,
|
||||
"KYD": 0.834247,
|
||||
"KZT": 467.84526,
|
||||
"LAK": 22038.352227,
|
||||
"LBP": 89647.700512,
|
||||
"LKR": 305.644882,
|
||||
"LRD": 194.349995,
|
||||
"LSL": 18.152071,
|
||||
"LYD": 4.855,
|
||||
"MAD": 9.950426,
|
||||
"MDL": 17.920244,
|
||||
"MGA": 4473.169164,
|
||||
"MKD": 57.439335,
|
||||
"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,
|
||||
"MMK": 2481.91,
|
||||
"MNT": 3450,
|
||||
"MOP": 8.051048,
|
||||
"MRU": 39.352282,
|
||||
"MUR": 46.929999,
|
||||
"MOP": 8.047221,
|
||||
"MRU": 39.452362,
|
||||
"MUR": 46.899999,
|
||||
"MVR": 15.405,
|
||||
"MWK": 1735.964257,
|
||||
"MXN": 18.104717,
|
||||
"MYR": 4.71,
|
||||
"MWK": 1734.657401,
|
||||
"MXN": 18.41087,
|
||||
"MYR": 4.7195,
|
||||
"MZN": 63.850001,
|
||||
"NAD": 18.152071,
|
||||
"NGN": 1518.12,
|
||||
"NIO": 36.848246,
|
||||
"NOK": 10.607752,
|
||||
"NPR": 133.640175,
|
||||
"NZD": 1.635653,
|
||||
"OMR": 0.384952,
|
||||
"NAD": 18.359053,
|
||||
"NGN": 1515.9,
|
||||
"NIO": 36.825702,
|
||||
"NOK": 10.666237,
|
||||
"NPR": 133.611854,
|
||||
"NZD": 1.643791,
|
||||
"OMR": 0.384955,
|
||||
"PAB": 1,
|
||||
"PEN": 3.815747,
|
||||
"PGK": 3.906082,
|
||||
"PHP": 58.837749,
|
||||
"PKR": 278.808073,
|
||||
"PLN": 4.011559,
|
||||
"PYG": 7549.795422,
|
||||
"QAR": 3.651064,
|
||||
"RON": 4.644,
|
||||
"RSD": 109.292759,
|
||||
"RUB": 87.502462,
|
||||
"RWF": 1326.548635,
|
||||
"SAR": 3.751926,
|
||||
"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,
|
||||
"SBD": 8.43942,
|
||||
"SCR": 13.861839,
|
||||
"SCR": 13.796937,
|
||||
"SDG": 601,
|
||||
"SEK": 10.509533,
|
||||
"SGD": 1.354893,
|
||||
"SHP": 0.788219,
|
||||
"SEK": 10.62955,
|
||||
"SGD": 1.358205,
|
||||
"SHP": 0.791234,
|
||||
"SLL": 20969.5,
|
||||
"SOS": 572.148966,
|
||||
"SRD": 31.0905,
|
||||
"SOS": 571.751991,
|
||||
"SRD": 30.623,
|
||||
"SSP": 130.26,
|
||||
"STD": 22281.8,
|
||||
"STN": 22.872934,
|
||||
"SVC": 8.759785,
|
||||
"STN": 22.899229,
|
||||
"SVC": 8.754335,
|
||||
"SYP": 2512.53,
|
||||
"SZL": 18.159157,
|
||||
"THB": 36.7755,
|
||||
"TJS": 10.696778,
|
||||
"SZL": 18.178413,
|
||||
"THB": 36.7685,
|
||||
"TJS": 10.65474,
|
||||
"TMT": 3.51,
|
||||
"TND": 3.133858,
|
||||
"TOP": 2.359259,
|
||||
"TRY": 33.0006,
|
||||
"TTD": 6.801133,
|
||||
"TWD": 32.533,
|
||||
"TZS": 2638.159,
|
||||
"UAH": 40.666635,
|
||||
"UGX": 3709.12772,
|
||||
"TND": 3.136769,
|
||||
"TOP": 2.36092,
|
||||
"TRY": 32.836478,
|
||||
"TTD": 6.7978,
|
||||
"TWD": 32.560001,
|
||||
"TZS": 2626.295328,
|
||||
"UAH": 40.51595,
|
||||
"UGX": 3711.539326,
|
||||
"USD": 1,
|
||||
"UYU": 39.322323,
|
||||
"UZS": 12613.6,
|
||||
"VES": 36.320372,
|
||||
"VND": 25461.48991,
|
||||
"UYU": 39.578963,
|
||||
"UZS": 12585.732694,
|
||||
"VES": 36.35908,
|
||||
"VND": 25455.008685,
|
||||
"VUV": 118.722,
|
||||
"WST": 2.8,
|
||||
"XAF": 612.41733,
|
||||
"XAG": 0.03457994,
|
||||
"XAU": 0.00043156,
|
||||
"XAF": 612.876514,
|
||||
"XAG": 0.0345453,
|
||||
"XAU": 0.00042988,
|
||||
"XCD": 2.70255,
|
||||
"XDR": 0.761402,
|
||||
"XOF": 612.41733,
|
||||
"XPD": 0.00107841,
|
||||
"XPF": 111.411003,
|
||||
"XPT": 0.00101239,
|
||||
"XDR": 0.759718,
|
||||
"XOF": 612.876514,
|
||||
"XPD": 0.00108638,
|
||||
"XPF": 111.494537,
|
||||
"XPT": 0.00101314,
|
||||
"YER": 250.399984,
|
||||
"ZAR": 18.227543,
|
||||
"ZMW": 25.80335,
|
||||
"ZAR": 18.4643,
|
||||
"ZMW": 25.735569,
|
||||
"ZWL": 322
|
||||
}
|
||||
}
|
|
@ -6,10 +6,10 @@ import {
|
|||
type RichTextContent,
|
||||
type RichTextNode,
|
||||
} from "src/shared/payload/payload-sdk";
|
||||
import { cache } from "src/utils/payload";
|
||||
import { contextCache } from "src/cache/contextCache";
|
||||
|
||||
export const formatLocale = (code: string): string =>
|
||||
cache.locales.find(({ id }) => id === code)?.name ?? code;
|
||||
contextCache.locales.find(({ id }) => id === code)?.name ?? code;
|
||||
|
||||
export const formatInlineTitle = ({
|
||||
pretitle,
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
export const getLogger = (prefix: string): Pick<Console, "log" | "error" | "warn" | "debug"> => ({
|
||||
debug: (...message) => console.debug(prefix, ...message),
|
||||
log: (...message) => console.log(prefix, ...message),
|
||||
warn: (...message) => console.warn(prefix, ...message),
|
||||
error: (...message) => console.error(prefix, ...message),
|
||||
});
|
|
@ -1,18 +1,9 @@
|
|||
import {
|
||||
type Language,
|
||||
type EndpointWording,
|
||||
type EndpointWebsiteConfig,
|
||||
} from "src/shared/payload/payload-sdk";
|
||||
import { dataCache } from "src/cache/dataCache";
|
||||
import { getPayloadSDK } from "src/shared/payload/payload-sdk";
|
||||
|
||||
let token: string | undefined = undefined;
|
||||
let expiration: number | undefined = undefined;
|
||||
|
||||
const responseCache = new Map<string, any>();
|
||||
const idsCacheMap = new Map<string, Set<string>>();
|
||||
|
||||
const isPrecachingEnabled = import.meta.env.ENABLE_PRECACHING === "true";
|
||||
|
||||
export const payload = getPayloadSDK({
|
||||
apiURL: import.meta.env.PAYLOAD_API_URL,
|
||||
email: import.meta.env.PAYLOAD_USER,
|
||||
|
@ -33,108 +24,5 @@ export const payload = getPayloadSDK({
|
|||
console.log("[PayloadSDK] New token set. TTL is", diffInMinutes, "minutes.");
|
||||
},
|
||||
},
|
||||
responseCache: {
|
||||
get: (url) => {
|
||||
const cachedResponse = responseCache.get(url);
|
||||
if (cachedResponse) {
|
||||
console.log("[ResponseCaching] Retrieved cache response for", url);
|
||||
return structuredClone(cachedResponse);
|
||||
}
|
||||
},
|
||||
set: (url, response) => {
|
||||
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 = idsCacheMap.get(id);
|
||||
if (current) {
|
||||
current.add(url);
|
||||
} else {
|
||||
idsCacheMap.set(id, new Set([url]));
|
||||
}
|
||||
});
|
||||
|
||||
console.log("[ResponseCaching] Caching response for", url);
|
||||
responseCache.set(url, response);
|
||||
},
|
||||
},
|
||||
responseCache: dataCache,
|
||||
});
|
||||
|
||||
export const invalidateDataCache = async (ids: string[], urls: string[]) => {
|
||||
const urlsToInvalidate = new Set<string>(urls);
|
||||
|
||||
ids.forEach((id) => {
|
||||
const urlsForThisId = idsCacheMap.get(id);
|
||||
if (!urlsForThisId) return;
|
||||
idsCacheMap.delete(id);
|
||||
[...urlsForThisId].forEach((url) => urlsToInvalidate.add(url));
|
||||
});
|
||||
|
||||
for (const url of urlsToInvalidate) {
|
||||
responseCache.delete(url);
|
||||
console.log("[ResponseCaching][Invalidation] Deleted cache for", url);
|
||||
try {
|
||||
await payload.request(url);
|
||||
} catch (e) {
|
||||
console.log("[ResponseCaching][Revalidation] Failure for", url);
|
||||
}
|
||||
}
|
||||
|
||||
console.log("[ResponseCaching] There are currently", responseCache.size, "responses in cache.");
|
||||
};
|
||||
|
||||
type Cache = {
|
||||
locales: Language[];
|
||||
currencies: string[];
|
||||
wordings: EndpointWording[];
|
||||
config: EndpointWebsiteConfig;
|
||||
};
|
||||
|
||||
const fetchNewData = async (): Promise<Cache> => ({
|
||||
locales: await payload.getLanguages(),
|
||||
currencies: (await payload.getCurrencies()).map(({ id }) => id),
|
||||
wordings: await payload.getWordings(),
|
||||
config: await payload.getConfig(),
|
||||
});
|
||||
|
||||
export let cache = await fetchNewData();
|
||||
|
||||
export const refreshWordings = async () => {
|
||||
cache.wordings = await payload.getWordings();
|
||||
};
|
||||
|
||||
export const refreshCurrencies = async () => {
|
||||
cache.currencies = (await payload.getCurrencies()).map(({ id }) => id);
|
||||
};
|
||||
|
||||
export const refreshLocales = async () => {
|
||||
cache.locales = await payload.getLanguages();
|
||||
};
|
||||
|
||||
export const refreshWebsiteConfig = async () => {
|
||||
cache.config = await payload.getConfig();
|
||||
};
|
||||
|
||||
let payloadInitialized = false;
|
||||
export const initPayload = async () => {
|
||||
if (!payloadInitialized) {
|
||||
if (!isPrecachingEnabled) {
|
||||
payloadInitialized = true;
|
||||
return;
|
||||
}
|
||||
|
||||
const { urls } = await payload.getAllSdkUrls();
|
||||
for (const url of urls) {
|
||||
try {
|
||||
await payload.request(url);
|
||||
} catch {
|
||||
console.warn("[ResponseCaching] Precaching failed for url", url);
|
||||
}
|
||||
}
|
||||
console.log("[ResponseCaching] Precaching completed!", responseCache.size, "responses cached");
|
||||
|
||||
payloadInitialized = true;
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue