diff --git a/package.json b/package.json index 3b81ee2..bca4380 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/scripts/download-wording-keys.ts b/scripts/download-wording-keys.ts index c663a81..ac0f0ef 100644 --- a/scripts/download-wording-keys.ts +++ b/scripts/download-wording-keys.ts @@ -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 = ""; diff --git a/src/cache/contextCache.ts b/src/cache/contextCache.ts index 25ce04d..c74d861 100644 --- a/src/cache/contextCache.ts +++ b/src/cache/contextCache.ts @@ -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 }; diff --git a/src/cache/dataCache.ts b/src/cache/dataCache.ts index 6e2052d..354c7b6 100644 --- a/src/cache/dataCache.ts +++ b/src/cache/dataCache.ts @@ -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(); private readonly idsCacheMap = new Map>(); + constructor( + private readonly payload: PayloadSDK, + private readonly onInvalidate: (urls: string[]) => Promise + ) {} + 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(); diff --git a/src/cache/pageCache.ts b/src/cache/pageCache.ts index f527a14..3ee9da1 100644 --- a/src/cache/pageCache.ts +++ b/src/cache/pageCache.ts @@ -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(); + private initialized = false; + + private readonly responseCache = new Map(); + private readonly invalidationMap = new Map>(); + + 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(); + + 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."); + } +} diff --git a/src/cache/tokenCache.ts b/src/cache/tokenCache.ts new file mode 100644 index 0000000..d33051c --- /dev/null +++ b/src/cache/tokenCache.ts @@ -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."); + } +} diff --git a/src/components/AppLayout/AppLayout.astro b/src/components/AppLayout/AppLayout.astro index b888c68..3cb3318 100644 --- a/src/components/AppLayout/AppLayout.astro +++ b/src/components/AppLayout/AppLayout.astro @@ -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, diff --git a/src/components/AppLayout/components/Html.astro b/src/components/AppLayout/components/Html.astro index 6d537fc..0a4d93c 100644 --- a/src/components/AppLayout/components/Html.astro +++ b/src/components/AppLayout/components/Html.astro @@ -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 { diff --git a/src/components/AppLayout/components/Topbar/components/CurrencySelector.astro b/src/components/AppLayout/components/Topbar/components/CurrencySelector.astro index f4b8859..1591326 100644 --- a/src/components/AppLayout/components/Topbar/components/CurrencySelector.astro +++ b/src/components/AppLayout/components/Topbar/components/CurrencySelector.astro @@ -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, diff --git a/src/components/AppLayout/components/Topbar/components/LanguageSelector.astro b/src/components/AppLayout/components/Topbar/components/LanguageSelector.astro index 7df9894..3545e5a 100644 --- a/src/components/AppLayout/components/Topbar/components/LanguageSelector.astro +++ b/src/components/AppLayout/components/Topbar/components/LanguageSelector.astro @@ -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 { diff --git a/src/env.d.ts b/src/env.d.ts index 7f60c1b..94554b5 100644 --- a/src/env.d.ts +++ b/src/env.d.ts @@ -5,5 +5,6 @@ declare namespace App { interface Locals { currentLocale: string; notFound: boolean; + sdkCalls: Set; } } diff --git a/src/i18n/i18n.ts b/src/i18n/i18n.ts index 1c3c95d..aa31395 100644 --- a/src/i18n/i18n.ts +++ b/src/i18n/i18n.ts @@ -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"; diff --git a/src/middleware.ts b/src/middleware.ts index 821f5cb..c34df36 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -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, diff --git a/src/middleware/pageCaching.ts b/src/middleware/pageCaching.ts index 71c4af5..ce21bca 100644 --- a/src/middleware/pageCaching.ts +++ b/src/middleware/pageCaching.ts @@ -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; diff --git a/src/middleware/postProcessing.ts b/src/middleware/postProcessing.ts index 32f808c..e63ef43 100644 --- a/src/middleware/postProcessing.ts +++ b/src/middleware/postProcessing.ts @@ -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); }); diff --git a/src/middleware/setAstroLocals.ts b/src/middleware/setAstroLocals.ts index 5bc8ac4..b892e0c 100644 --- a/src/middleware/setAstroLocals.ts +++ b/src/middleware/setAstroLocals.ts @@ -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(); -}); \ No newline at end of file +}); diff --git a/src/middleware/utils.ts b/src/middleware/utils.ts index 377ebbd..e7bf44f 100644 --- a/src/middleware/utils.ts +++ b/src/middleware/utils.ts @@ -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)); diff --git a/src/pages/[locale]/_components/LibraryGrid.astro b/src/pages/[locale]/_components/LibraryGrid.astro index a7a6d3c..26126d9 100644 --- a/src/pages/[locale]/_components/LibraryGrid.astro +++ b/src/pages/[locale]/_components/LibraryGrid.astro @@ -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); --- diff --git a/src/pages/[locale]/api/hooks/collection-operation.ts b/src/pages/[locale]/api/hooks/collection-operation.ts index ed37239..6de6c8b 100644 --- a/src/pages/[locale]/api/hooks/collection-operation.ts +++ b/src/pages/[locale]/api/hooks/collection-operation.ts @@ -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 }) => { diff --git a/src/pages/[locale]/api/on-startup.ts b/src/pages/[locale]/api/on-startup.ts index 7cce4d3..f73c756 100644 --- a/src/pages/[locale]/api/on-startup.ts +++ b/src/pages/[locale]/api/on-startup.ts @@ -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" }); }; diff --git a/src/pages/[locale]/api/pages/partial.astro b/src/pages/[locale]/api/pages/partial.astro index 6d6c520..52c5dc2 100644 --- a/src/pages/[locale]/api/pages/partial.astro +++ b/src/pages/[locale]/api/pages/partial.astro @@ -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); diff --git a/src/pages/[locale]/api/timeline/partial.astro b/src/pages/[locale]/api/timeline/partial.astro index ae210a6..fc37181 100644 --- a/src/pages/[locale]/api/timeline/partial.astro +++ b/src/pages/[locale]/api/timeline/partial.astro @@ -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); diff --git a/src/pages/[locale]/audios/[id].astro b/src/pages/[locale]/audios/[id].astro index ed033ed..3172f0d 100644 --- a/src/pages/[locale]/audios/[id].astro +++ b/src/pages/[locale]/audios/[id].astro @@ -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 diff --git a/src/pages/[locale]/collectibles/[slug]/gallery/[index].astro b/src/pages/[locale]/collectibles/[slug]/gallery/[index].astro index b14b7d9..94dd168 100644 --- a/src/pages/[locale]/collectibles/[slug]/gallery/[index].astro +++ b/src/pages/[locale]/collectibles/[slug]/gallery/[index].astro @@ -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 } = diff --git a/src/pages/[locale]/collectibles/[slug]/gallery/index.astro b/src/pages/[locale]/collectibles/[slug]/gallery/index.astro index f85e08b..727be69 100644 --- a/src/pages/[locale]/collectibles/[slug]/gallery/index.astro +++ b/src/pages/[locale]/collectibles/[slug]/gallery/index.astro @@ -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); --- diff --git a/src/pages/[locale]/collectibles/[slug]/index.astro b/src/pages/[locale]/collectibles/[slug]/index.astro index 726609b..f403c11 100644 --- a/src/pages/[locale]/collectibles/[slug]/index.astro +++ b/src/pages/[locale]/collectibles/[slug]/index.astro @@ -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, diff --git a/src/pages/[locale]/collectibles/[slug]/scans/[index].astro b/src/pages/[locale]/collectibles/[slug]/scans/[index].astro index 949fc33..a941c30 100644 --- a/src/pages/[locale]/collectibles/[slug]/scans/[index].astro +++ b/src/pages/[locale]/collectibles/[slug]/scans/[index].astro @@ -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); --- diff --git a/src/pages/[locale]/collectibles/[slug]/scans/index.astro b/src/pages/[locale]/collectibles/[slug]/scans/index.astro index 0d7a9f6..e961797 100644 --- a/src/pages/[locale]/collectibles/[slug]/scans/index.astro +++ b/src/pages/[locale]/collectibles/[slug]/scans/index.astro @@ -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); diff --git a/src/pages/[locale]/files/[id].astro b/src/pages/[locale]/files/[id].astro index 9139831..e9c22da 100644 --- a/src/pages/[locale]/files/[id].astro +++ b/src/pages/[locale]/files/[id].astro @@ -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 diff --git a/src/pages/[locale]/folders/[slug].astro b/src/pages/[locale]/folders/[slug].astro index ec57bc0..ca5ca2e 100644 --- a/src/pages/[locale]/folders/[slug].astro +++ b/src/pages/[locale]/folders/[slug].astro @@ -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 ------------------------------------------- */} - - {meta.description && } + + {description && } -
+
{ - folder.sections.type === "single" && folder.sections.subfolders.length > 0 ? ( - + sections.type === "single" && sections.subfolders.length > 0 ? ( + ) : ( - folder.sections.type === "multiple" && - folder.sections.sections.length > 0 && ( + sections.type === "multiple" && + sections.sections.length > 0 && (
- {folder.sections.sections.map(({ subfolders, translations }) => { + {sections.sections.map(({ subfolders, translations }) => { const { language, name } = getLocalizedMatch(translations); return ; })} @@ -58,7 +60,7 @@ const meta = getLocalizedMatch(folder.translations);
{ - folder.files.map(({ relationTo, value }) => { + files.map(({ relationTo, value }) => { switch (relationTo) { case Collections.Collectibles: return ; diff --git a/src/pages/[locale]/images/[id].astro b/src/pages/[locale]/images/[id].astro index 2309f66..0aad715 100644 --- a/src/pages/[locale]/images/[id].astro +++ b/src/pages/[locale]/images/[id].astro @@ -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 diff --git a/src/pages/[locale]/index.astro b/src/pages/[locale]/index.astro index f9886de..f42eda2 100644 --- a/src/pages/[locale]/index.astro +++ b/src/pages/[locale]/index.astro @@ -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"; diff --git a/src/pages/[locale]/pages/[slug].astro b/src/pages/[locale]/pages/[slug].astro index 6266f5a..d86dfb1 100644 --- a/src/pages/[locale]/pages/[slug].astro +++ b/src/pages/[locale]/pages/[slug].astro @@ -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); diff --git a/src/pages/[locale]/recorders/[id].astro b/src/pages/[locale]/recorders/[id].astro index 41dfb10..3600792 100644 --- a/src/pages/[locale]/recorders/[id].astro +++ b/src/pages/[locale]/recorders/[id].astro @@ -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) diff --git a/src/pages/[locale]/settings/index.astro b/src/pages/[locale]/settings/index.astro index 250fe86..141a201 100644 --- a/src/pages/[locale]/settings/index.astro +++ b/src/pages/[locale]/settings/index.astro @@ -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"; diff --git a/src/pages/[locale]/timeline/_components/TimelineYear.astro b/src/pages/[locale]/timeline/_components/TimelineYear.astro index 968adc9..49ae785 100644 --- a/src/pages/[locale]/timeline/_components/TimelineYear.astro +++ b/src/pages/[locale]/timeline/_components/TimelineYear.astro @@ -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 ------------------------------------------- */} diff --git a/src/pages/[locale]/timeline/index.astro b/src/pages/[locale]/timeline/index.astro index 1d1a163..5701b62 100644 --- a/src/pages/[locale]/timeline/index.astro +++ b/src/pages/[locale]/timeline/index.astro @@ -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); --- diff --git a/src/pages/[locale]/videos/[id].astro b/src/pages/[locale]/videos/[id].astro index 415cb0d..6cdb6e7 100644 --- a/src/pages/[locale]/videos/[id].astro +++ b/src/pages/[locale]/videos/[id].astro @@ -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 = [ diff --git a/src/shared/analytics/analytics.ts b/src/shared/analytics/analytics.ts index 344ef87..9dac268 100644 --- a/src/shared/analytics/analytics.ts +++ b/src/shared/analytics/analytics.ts @@ -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) { diff --git a/src/shared/openExchange/rates.json b/src/shared/openExchange/rates.json index 7379078..8a6199d 100644 --- a/src/shared/openExchange/rates.json +++ b/src/shared/openExchange/rates.json @@ -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 } } \ No newline at end of file diff --git a/src/shared/payload/payload-sdk.ts b/src/shared/payload/payload-sdk.ts index 92672bc..1e76ba3 100644 --- a/src/shared/payload/payload-sdk.ts +++ b/src/shared/payload/payload-sdk.ts @@ -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 = { + 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 => { - const cachedResponse = responseCache?.get(endpoint); + async request(endpoint: string): Promise> { + 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 => - await request(getSDKEndpoint.getConfigEndpoint()), - getFolder: async (slug: string): Promise => - await request(getSDKEndpoint.getFolderEndpoint(slug)), - getLanguages: async (): Promise => - await request(getSDKEndpoint.getLanguagesEndpoint()), - getCurrencies: async (): Promise => - await request(getSDKEndpoint.getCurrenciesEndpoint()), - getWordings: async (): Promise => - await request(getSDKEndpoint.getWordingsEndpoint()), - getPage: async (slug: string): Promise => - await request(getSDKEndpoint.getPageEndpoint(slug)), - getCollectible: async (slug: string): Promise => - await request(getSDKEndpoint.getCollectibleEndpoint(slug)), - getCollectibleScans: async (slug: string): Promise => - await request(getSDKEndpoint.getCollectibleScansEndpoint(slug)), - getCollectibleScanPage: async ( - slug: string, - index: string - ): Promise => - await request(getSDKEndpoint.getCollectibleScanPageEndpoint(slug, index)), - getCollectibleGallery: async (slug: string): Promise => - await request(getSDKEndpoint.getCollectibleGalleryEndpoint(slug)), - getCollectibleGalleryImage: async ( - slug: string, - index: string - ): Promise => - await request(getSDKEndpoint.getCollectibleGalleryImageEndpoint(slug, index)), - getChronologyEvents: async (): Promise => - await request(getSDKEndpoint.getChronologyEventsEndpoint()), - getChronologyEventByID: async (id: string): Promise => - await request(getSDKEndpoint.getChronologyEventByIDEndpoint(id)), - getImageByID: async (id: string): Promise => - await request(getSDKEndpoint.getImageByIDEndpoint(id)), - getAudioByID: async (id: string): Promise => - await request(getSDKEndpoint.getAudioByIDEndpoint(id)), - getVideoByID: async (id: string): Promise => - await request(getSDKEndpoint.getVideoByIDEndpoint(id)), - getFileByID: async (id: string): Promise => - await request(getSDKEndpoint.getFileByIDEndpoint(id)), - getRecorderByID: async (id: string): Promise => - await request(getSDKEndpoint.getRecorderByIDEndpoint(id)), - getAllSdkUrls: async (): Promise => - await request(getSDKEndpoint.getAllSDKUrlsEndpoint()), - request: async (pathname: string): Promise => await request(pathname), - }; -}; + async getConfig(): Promise> { + return await this.request(getSDKEndpoint.getConfigEndpoint()); + } + async getFolder(slug: string): Promise> { + return await this.request(getSDKEndpoint.getFolderEndpoint(slug)); + } + async getFolderSlugs(): Promise> { + return await this.request(getSDKEndpoint.getFolderSlugsEndpoint()); + } + async getLanguages(): Promise> { + return await this.request(getSDKEndpoint.getLanguagesEndpoint()); + } + async getCurrencies(): Promise> { + return await this.request(getSDKEndpoint.getCurrenciesEndpoint()); + } + async getWordings(): Promise> { + return await this.request(getSDKEndpoint.getWordingsEndpoint()); + } + async getPage(slug: string): Promise> { + return await this.request(getSDKEndpoint.getPageEndpoint(slug)); + } + async getPageSlugs(): Promise> { + return await this.request(getSDKEndpoint.getPageSlugsEndpoint()); + } + async getCollectible(slug: string): Promise> { + return await this.request(getSDKEndpoint.getCollectibleEndpoint(slug)); + } + async getCollectibleSlugs(): Promise> { + return await this.request(getSDKEndpoint.getCollectibleSlugsEndpoint()); + } + async getCollectibleScans(slug: string): Promise> { + return await this.request(getSDKEndpoint.getCollectibleScansEndpoint(slug)); + } + async getCollectibleScanPage( + slug: string, + index: string + ): Promise> { + return await this.request(getSDKEndpoint.getCollectibleScanPageEndpoint(slug, index)); + } + async getCollectibleGallery( + slug: string + ): Promise> { + return await this.request(getSDKEndpoint.getCollectibleGalleryEndpoint(slug)); + } + async getCollectibleGalleryImage( + slug: string, + index: string + ): Promise> { + return await this.request(getSDKEndpoint.getCollectibleGalleryImageEndpoint(slug, index)); + } + async getChronologyEvents(): Promise> { + return await this.request(getSDKEndpoint.getChronologyEventsEndpoint()); + } + async getChronologyEventByID(id: string): Promise> { + return await this.request(getSDKEndpoint.getChronologyEventByIDEndpoint(id)); + } + async getImageByID(id: string): Promise> { + return await this.request(getSDKEndpoint.getImageByIDEndpoint(id)); + } + async getAudioByID(id: string): Promise> { + return await this.request(getSDKEndpoint.getAudioByIDEndpoint(id)); + } + async getVideoByID(id: string): Promise> { + return await this.request(getSDKEndpoint.getVideoByIDEndpoint(id)); + } + async getFileByID(id: string): Promise> { + return await this.request(getSDKEndpoint.getFileByIDEndpoint(id)); + } + async getRecorderByID(id: string): Promise> { + return await this.request(getSDKEndpoint.getRecorderByIDEndpoint(id)); + } + async getAllSdkUrls(): Promise> { + return await this.request(getSDKEndpoint.getAllSDKUrlsEndpoint()); + } +} diff --git a/src/utils/format.ts b/src/utils/format.ts index 3e77bcd..9ed396f 100644 --- a/src/utils/format.ts +++ b/src/utils/format.ts @@ -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; diff --git a/src/utils/payload.ts b/src/utils/payload.ts index acf7c07..a6cd2fe 100644 --- a/src/utils/payload.ts +++ b/src/utils/payload.ts @@ -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 };