Compare commits
2 Commits
Author | SHA1 | Date |
---|---|---|
DrMint | c9c8160bfa | |
DrMint | 6c99de5bfb |
|
@ -13,7 +13,6 @@
|
||||||
"accept-language": "^3.0.18",
|
"accept-language": "^3.0.18",
|
||||||
"astro": "4.10.2",
|
"astro": "4.10.2",
|
||||||
"astro-icon": "^1.1.0",
|
"astro-icon": "^1.1.0",
|
||||||
"node-cache": "^5.1.2",
|
|
||||||
"tippy.js": "^6.3.7",
|
"tippy.js": "^6.3.7",
|
||||||
"ua-parser-js": "^1.0.38"
|
"ua-parser-js": "^1.0.38"
|
||||||
},
|
},
|
||||||
|
@ -4104,14 +4103,6 @@
|
||||||
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
|
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/clone": {
|
|
||||||
"version": "2.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
|
|
||||||
"integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/clsx": {
|
"node_modules/clsx": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
|
||||||
|
@ -6545,17 +6536,6 @@
|
||||||
"url": "https://opencollective.com/unified"
|
"url": "https://opencollective.com/unified"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/node-cache": {
|
|
||||||
"version": "5.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/node-cache/-/node-cache-5.1.2.tgz",
|
|
||||||
"integrity": "sha512-t1QzWwnk4sjLWaQAS8CHgOJ+RAfmHpxFWmc36IWTiWHQfs0w5JDMBS1b1ZxQteo0vVVuWJvIUKHDkkeK7vIGCg==",
|
|
||||||
"dependencies": {
|
|
||||||
"clone": "2.x"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 8.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/node-releases": {
|
"node_modules/node-releases": {
|
||||||
"version": "2.0.14",
|
"version": "2.0.14",
|
||||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz",
|
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "v3.accords-library.com",
|
"name": "v3.accords-library.com",
|
||||||
"version": "3.0.0-beta.3",
|
"version": "3.0.0-beta.4",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "astro dev",
|
"dev": "astro dev",
|
||||||
"start": "astro dev",
|
"start": "astro dev",
|
||||||
|
@ -24,7 +24,6 @@
|
||||||
"accept-language": "^3.0.18",
|
"accept-language": "^3.0.18",
|
||||||
"astro": "4.10.2",
|
"astro": "4.10.2",
|
||||||
"astro-icon": "^1.1.0",
|
"astro-icon": "^1.1.0",
|
||||||
"node-cache": "^5.1.2",
|
|
||||||
"tippy.js": "^6.3.7",
|
"tippy.js": "^6.3.7",
|
||||||
"ua-parser-js": "^1.0.38"
|
"ua-parser-js": "^1.0.38"
|
||||||
},
|
},
|
||||||
|
|
|
@ -151,6 +151,15 @@ const addContentLanguageResponseHeader = defineMiddleware(async ({ url }, next)
|
||||||
return response;
|
return response;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const addCacheControlHeaders = defineMiddleware(async (_, next) => {
|
||||||
|
const response = await next();
|
||||||
|
if (response.ok) {
|
||||||
|
response.headers.set("Cache-Control", "max-age=60, stale-while-revalidate=60");
|
||||||
|
response.headers.set("Vary", "Cookie")
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
});
|
||||||
|
|
||||||
const provideLocalsToRequest = defineMiddleware(async ({ url, locals, cookies }, next) => {
|
const provideLocalsToRequest = defineMiddleware(async ({ url, locals, cookies }, next) => {
|
||||||
locals.currentLocale = getCurrentLocale(url.pathname) ?? "en";
|
locals.currentLocale = getCurrentLocale(url.pathname) ?? "en";
|
||||||
locals.currentCurrency = getCookieCurrency(cookies) ?? "USD";
|
locals.currentCurrency = getCookieCurrency(cookies) ?? "USD";
|
||||||
|
@ -170,6 +179,7 @@ export const onRequest = sequence(
|
||||||
handleActionsSearchParams,
|
handleActionsSearchParams,
|
||||||
refreshCookiesMaxAge,
|
refreshCookiesMaxAge,
|
||||||
localeNegotiator,
|
localeNegotiator,
|
||||||
|
addCacheControlHeaders,
|
||||||
provideLocalsToRequest,
|
provideLocalsToRequest,
|
||||||
analytics
|
analytics
|
||||||
);
|
);
|
||||||
|
|
|
@ -25,7 +25,7 @@ const reqUrl = new URL(Astro.request.url);
|
||||||
const lang = Astro.props.lang ?? reqUrl.searchParams.get("lang")!;
|
const lang = Astro.props.lang ?? reqUrl.searchParams.get("lang")!;
|
||||||
const slug = Astro.props.slug ?? reqUrl.searchParams.get("slug")!;
|
const slug = Astro.props.slug ?? reqUrl.searchParams.get("slug")!;
|
||||||
const { translations, thumbnail, createdAt, updatedAt, updatedBy, attributes } =
|
const { translations, thumbnail, createdAt, updatedAt, updatedBy, attributes } =
|
||||||
Astro.props.page ?? (await payload.getPage(slug));
|
Astro.props.page ?? (await payload.getPage(slug)).data;
|
||||||
|
|
||||||
const { getLocalizedUrl, t, formatDate } = await getI18n(Astro.locals.currentLocale);
|
const { getLocalizedUrl, t, formatDate } = await getI18n(Astro.locals.currentLocale);
|
||||||
const { getLocalizedMatch } = await getI18n(lang);
|
const { getLocalizedMatch } = await getI18n(lang);
|
||||||
|
|
|
@ -12,7 +12,7 @@ import { formatInlineTitle, formatRichTextToString } from "src/utils/format";
|
||||||
import { fetchOr404 } from "src/utils/responses";
|
import { fetchOr404 } from "src/utils/responses";
|
||||||
|
|
||||||
const id = Astro.params.id!;
|
const id = Astro.params.id!;
|
||||||
const audio = await fetchOr404(() => payload.getAudioByID(id));
|
const audio = await fetchOr404(Astro, () => payload.getAudioByID(id));
|
||||||
if (audio instanceof Response) {
|
if (audio instanceof Response) {
|
||||||
return audio;
|
return audio;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ const { getLocalizedUrl, getLocalizedMatch, t, formatDate } = await getI18n(
|
||||||
Astro.locals.currentLocale
|
Astro.locals.currentLocale
|
||||||
);
|
);
|
||||||
|
|
||||||
const galleryImage = await fetchOr404(() => payload.getCollectibleGalleryImage(slug, index));
|
const galleryImage = await fetchOr404(Astro, () => payload.getCollectibleGalleryImage(slug, index));
|
||||||
if (galleryImage instanceof Response) {
|
if (galleryImage instanceof Response) {
|
||||||
return galleryImage;
|
return galleryImage;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ import RichText from "components/RichText/RichText.astro";
|
||||||
const slug = Astro.params.slug!;
|
const slug = Astro.params.slug!;
|
||||||
const { getLocalizedMatch, getLocalizedUrl, t } = await getI18n(Astro.locals.currentLocale);
|
const { getLocalizedMatch, getLocalizedUrl, t } = await getI18n(Astro.locals.currentLocale);
|
||||||
|
|
||||||
const gallery = await fetchOr404(() => payload.getCollectibleGallery(slug));
|
const gallery = await fetchOr404(Astro, () => payload.getCollectibleGallery(slug));
|
||||||
if (gallery instanceof Response) {
|
if (gallery instanceof Response) {
|
||||||
return gallery;
|
return gallery;
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ const { getLocalizedMatch, getLocalizedUrl, t, formatDate, formatPrice } = await
|
||||||
Astro.locals.currentLocale
|
Astro.locals.currentLocale
|
||||||
);
|
);
|
||||||
|
|
||||||
const collectible = await fetchOr404(() => payload.getCollectible(slug));
|
const collectible = await fetchOr404(Astro, () => payload.getCollectible(slug));
|
||||||
if (collectible instanceof Response) {
|
if (collectible instanceof Response) {
|
||||||
return collectible;
|
return collectible;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ const { formatScanIndexShort, getLocalizedMatch, getLocalizedUrl } = await getI1
|
||||||
Astro.locals.currentLocale
|
Astro.locals.currentLocale
|
||||||
);
|
);
|
||||||
|
|
||||||
const scanPage = await fetchOr404(() => payload.getCollectibleScanPage(slug, index));
|
const scanPage = await fetchOr404(Astro, () => payload.getCollectibleScanPage(slug, index));
|
||||||
if (scanPage instanceof Response) {
|
if (scanPage instanceof Response) {
|
||||||
return scanPage;
|
return scanPage;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ import RichText from "components/RichText/RichText.astro";
|
||||||
const slug = Astro.params.slug!;
|
const slug = Astro.params.slug!;
|
||||||
const { getLocalizedMatch, t } = await getI18n(Astro.locals.currentLocale);
|
const { getLocalizedMatch, t } = await getI18n(Astro.locals.currentLocale);
|
||||||
|
|
||||||
const scans = await fetchOr404(() => payload.getCollectibleScans(slug));
|
const scans = await fetchOr404(Astro, () => payload.getCollectibleScans(slug));
|
||||||
if (scans instanceof Response) {
|
if (scans instanceof Response) {
|
||||||
return scans;
|
return scans;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ import RichText from "components/RichText/RichText.astro";
|
||||||
|
|
||||||
const slug = Astro.params.slug!;
|
const slug = Astro.params.slug!;
|
||||||
|
|
||||||
const folder = await fetchOr404(() => payload.getFolder(slug));
|
const folder = await fetchOr404(Astro, () => payload.getFolder(slug));
|
||||||
if (folder instanceof Response) {
|
if (folder instanceof Response) {
|
||||||
return folder;
|
return folder;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ import { formatInlineTitle, formatRichTextToString } from "src/utils/format";
|
||||||
import { fetchOr404 } from "src/utils/responses";
|
import { fetchOr404 } from "src/utils/responses";
|
||||||
|
|
||||||
const id = Astro.params.id!;
|
const id = Astro.params.id!;
|
||||||
const image = await fetchOr404(() => payload.getImageByID(id));
|
const image = await fetchOr404(Astro, () => payload.getImageByID(id));
|
||||||
if (image instanceof Response) {
|
if (image instanceof Response) {
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ import { fetchOr404 } from "src/utils/responses";
|
||||||
|
|
||||||
const slug = Astro.params.slug!;
|
const slug = Astro.params.slug!;
|
||||||
|
|
||||||
const page = await fetchOr404(() => payload.getPage(slug));
|
const page = await fetchOr404(Astro, () => payload.getPage(slug));
|
||||||
if (page instanceof Response) {
|
if (page instanceof Response) {
|
||||||
return page;
|
return page;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ import { fetchOr404 } from "src/utils/responses";
|
||||||
import { sizesToSrcset } from "src/utils/img";
|
import { sizesToSrcset } from "src/utils/img";
|
||||||
|
|
||||||
const id = Astro.params.id!;
|
const id = Astro.params.id!;
|
||||||
const recorder = await fetchOr404(() => payload.getRecorderByID(id));
|
const recorder = await fetchOr404(Astro, () => payload.getRecorderByID(id));
|
||||||
if (recorder instanceof Response) {
|
if (recorder instanceof Response) {
|
||||||
return recorder;
|
return recorder;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,8 +8,13 @@ import Card from "components/Card.astro";
|
||||||
import { getI18n } from "src/i18n/i18n";
|
import { getI18n } from "src/i18n/i18n";
|
||||||
import { cache } from "src/utils/payload";
|
import { cache } from "src/utils/payload";
|
||||||
import type { WordingKey } from "src/i18n/wordings-keys";
|
import type { WordingKey } from "src/i18n/wordings-keys";
|
||||||
|
import { fetchOr404 } from "src/utils/responses";
|
||||||
|
|
||||||
|
const events = await fetchOr404(Astro, payload.getChronologyEvents);
|
||||||
|
if (events instanceof Response) {
|
||||||
|
return events;
|
||||||
|
}
|
||||||
|
|
||||||
const events = await payload.getChronologyEvents();
|
|
||||||
const groupedEvents = groupBy(events, (event) => event.date.year);
|
const groupedEvents = groupBy(events, (event) => event.date.year);
|
||||||
const { getLocalizedUrl, t, formatTimelineDate } = await getI18n(Astro.locals.currentLocale);
|
const { getLocalizedUrl, t, formatTimelineDate } = await getI18n(Astro.locals.currentLocale);
|
||||||
---
|
---
|
||||||
|
|
|
@ -12,7 +12,7 @@ import { formatInlineTitle, formatRichTextToString } from "src/utils/format";
|
||||||
import { fetchOr404 } from "src/utils/responses";
|
import { fetchOr404 } from "src/utils/responses";
|
||||||
|
|
||||||
const id = Astro.params.id!;
|
const id = Astro.params.id!;
|
||||||
const video = await fetchOr404(() => payload.getVideoByID(id));
|
const video = await fetchOr404(Astro, () => payload.getVideoByID(id));
|
||||||
if (video instanceof Response) {
|
if (video instanceof Response) {
|
||||||
return video;
|
return video;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,177 +1,177 @@
|
||||||
{
|
{
|
||||||
"disclaimer": "Usage subject to terms: https://openexchangerates.org/terms",
|
"disclaimer": "Usage subject to terms: https://openexchangerates.org/terms",
|
||||||
"license": "https://openexchangerates.org/license",
|
"license": "https://openexchangerates.org/license",
|
||||||
"timestamp": 1717740000,
|
"timestamp": 1718308800,
|
||||||
"base": "USD",
|
"base": "USD",
|
||||||
"rates": {
|
"rates": {
|
||||||
"AED": 3.673,
|
"AED": 3.67305,
|
||||||
"AFN": 70.453638,
|
"AFN": 70.500002,
|
||||||
"ALL": 91.912021,
|
"ALL": 92.875,
|
||||||
"AMD": 387.678915,
|
"AMD": 388.38664,
|
||||||
"ANG": 1.79986,
|
"ANG": 1.806289,
|
||||||
"AOA": 854.407667,
|
"AOA": 855,
|
||||||
"ARS": 898.5413,
|
"ARS": 902.25,
|
||||||
"AUD": 1.498617,
|
"AUD": 1.506865,
|
||||||
"AWG": 1.8,
|
"AWG": 1.8025,
|
||||||
"AZN": 1.7,
|
"AZN": 1.7,
|
||||||
"BAM": 1.795869,
|
"BAM": 1.815928,
|
||||||
"BBD": 2,
|
"BBD": 2,
|
||||||
"BDT": 117.294372,
|
"BDT": 117.778138,
|
||||||
"BGN": 1.79491,
|
"BGN": 1.821445,
|
||||||
"BHD": 0.376872,
|
"BHD": 0.376882,
|
||||||
"BIF": 2869.308172,
|
"BIF": 2879,
|
||||||
"BMD": 1,
|
"BMD": 1,
|
||||||
"BND": 1.345362,
|
"BND": 1.352522,
|
||||||
"BOB": 6.901365,
|
"BOB": 6.925559,
|
||||||
"BRL": 5.258701,
|
"BRL": 5.3671,
|
||||||
"BSD": 1,
|
"BSD": 1,
|
||||||
"BTC": 0.000014026029,
|
"BTC": 0.000015006774,
|
||||||
"BTN": 83.367902,
|
"BTN": 83.726029,
|
||||||
"BWP": 13.755584,
|
"BWP": 13.635836,
|
||||||
"BYN": 3.268278,
|
"BYN": 3.279777,
|
||||||
"BZD": 2.013085,
|
"BZD": 2.020138,
|
||||||
"CAD": 1.366955,
|
"CAD": 1.373867,
|
||||||
"CDF": 2822.733026,
|
"CDF": 2845,
|
||||||
"CHF": 0.89004,
|
"CHF": 0.893783,
|
||||||
"CLF": 0.032927,
|
"CLF": 0.033281,
|
||||||
"CLP": 908.55,
|
"CLP": 918.33,
|
||||||
"CNH": 7.255147,
|
"CNH": 7.270265,
|
||||||
"CNY": 7.2447,
|
"CNY": 7.2526,
|
||||||
"COP": 3927.880338,
|
"COP": 4064.333563,
|
||||||
"CRC": 527.874933,
|
"CRC": 528.390438,
|
||||||
"CUC": 1,
|
"CUC": 1,
|
||||||
"CUP": 25.75,
|
"CUP": 25.75,
|
||||||
"CVE": 101.249236,
|
"CVE": 103.1,
|
||||||
"CZK": 22.552099,
|
"CZK": 23.0107,
|
||||||
"DJF": 177.811501,
|
"DJF": 177,
|
||||||
"DKK": 6.849959,
|
"DKK": 6.9455,
|
||||||
"DOP": 59.242392,
|
"DOP": 59.4,
|
||||||
"DZD": 134.471532,
|
"DZD": 134.851507,
|
||||||
"EGP": 47.5129,
|
"EGP": 47.708,
|
||||||
"ERN": 15,
|
"ERN": 15,
|
||||||
"ETB": 57.42215,
|
"ETB": 57.5,
|
||||||
"EUR": 0.918217,
|
"EUR": 0.931055,
|
||||||
"FJD": 2.25895,
|
"FJD": 2.2337,
|
||||||
"FKP": 0.782189,
|
"FKP": 0.783387,
|
||||||
"GBP": 0.782189,
|
"GBP": 0.783387,
|
||||||
"GEL": 2.785,
|
"GEL": 2.86,
|
||||||
"GGP": 0.782189,
|
"GGP": 0.783387,
|
||||||
"GHS": 14.880927,
|
"GHS": 15.04,
|
||||||
"GIP": 0.782189,
|
"GIP": 0.783387,
|
||||||
"GMD": 67.775,
|
"GMD": 67.775,
|
||||||
"GNF": 8600.013522,
|
"GNF": 8605,
|
||||||
"GTQ": 7.76001,
|
"GTQ": 7.785371,
|
||||||
"GYD": 209.061081,
|
"GYD": 209.587622,
|
||||||
"HKD": 7.809645,
|
"HKD": 7.81073,
|
||||||
"HNL": 24.673005,
|
"HNL": 24.799999,
|
||||||
"HRK": 6.918151,
|
"HRK": 7.01418,
|
||||||
"HTG": 132.552876,
|
"HTG": 133.038665,
|
||||||
"HUF": 358.085123,
|
"HUF": 369.590851,
|
||||||
"IDR": 16216.760923,
|
"IDR": 16286.77334,
|
||||||
"ILS": 3.720825,
|
"ILS": 3.715655,
|
||||||
"IMP": 0.782189,
|
"IMP": 0.783387,
|
||||||
"INR": 83.458757,
|
"INR": 83.540593,
|
||||||
"IQD": 1308.290714,
|
"IQD": 1310,
|
||||||
"IRR": 42100,
|
"IRR": 42100,
|
||||||
"ISK": 137.46,
|
"ISK": 139.01,
|
||||||
"JEP": 0.782189,
|
"JEP": 0.783387,
|
||||||
"JMD": 155.295453,
|
"JMD": 156.002299,
|
||||||
"JOD": 0.7088,
|
"JOD": 0.7089,
|
||||||
"JPY": 155.5174,
|
"JPY": 157.063125,
|
||||||
"KES": 130,
|
"KES": 128.5,
|
||||||
"KGS": 87.3013,
|
"KGS": 87.1182,
|
||||||
"KHR": 4101.618815,
|
"KHR": 4119,
|
||||||
"KMF": 452.450119,
|
"KMF": 455.500241,
|
||||||
"KPW": 900,
|
"KPW": 900,
|
||||||
"KRW": 1367.937913,
|
"KRW": 1376.539507,
|
||||||
"KWD": 0.306384,
|
"KWD": 0.306419,
|
||||||
"KYD": 0.832281,
|
"KYD": 0.835233,
|
||||||
"KZT": 446.221602,
|
"KZT": 451.97877,
|
||||||
"LAK": 21498.895118,
|
"LAK": 21780,
|
||||||
"LBP": 89418.618549,
|
"LBP": 89550,
|
||||||
"LKR": 302.314319,
|
"LKR": 304.586904,
|
||||||
"LRD": 193.950039,
|
"LRD": 193.999927,
|
||||||
"LSL": 18.953322,
|
"LSL": 18.4,
|
||||||
"LYD": 4.829787,
|
"LYD": 4.85,
|
||||||
"MAD": 9.877784,
|
"MAD": 9.9465,
|
||||||
"MDL": 17.619678,
|
"MDL": 17.699209,
|
||||||
"MGA": 4467.052458,
|
"MGA": 4470,
|
||||||
"MKD": 56.57657,
|
"MKD": 57.263542,
|
||||||
"MMK": 2101.212378,
|
"MMK": 2201.379322,
|
||||||
"MNT": 3450,
|
"MNT": 3450,
|
||||||
"MOP": 8.033479,
|
"MOP": 8.063005,
|
||||||
"MRU": 39.126423,
|
"MRU": 39.45,
|
||||||
"MUR": 46.32,
|
"MUR": 46.637189,
|
||||||
"MVR": 15.4,
|
"MVR": 15.41,
|
||||||
"MWK": 1731.539932,
|
"MWK": 1733.5,
|
||||||
"MXN": 17.987572,
|
"MXN": 18.468878,
|
||||||
"MYR": 4.6955,
|
"MYR": 4.71875,
|
||||||
"MZN": 63.92499,
|
"MZN": 63.850001,
|
||||||
"NAD": 18.953497,
|
"NAD": 18.4,
|
||||||
"NGN": 1485.31,
|
"NGN": 1505,
|
||||||
"NIO": 36.764809,
|
"NIO": 36.8,
|
||||||
"NOK": 10.558218,
|
"NOK": 10.64482,
|
||||||
"NPR": 133.383523,
|
"NPR": 133.959461,
|
||||||
"NZD": 1.613954,
|
"NZD": 1.62071,
|
||||||
"OMR": 0.384963,
|
"OMR": 0.384946,
|
||||||
"PAB": 1,
|
"PAB": 1,
|
||||||
"PEN": 3.738103,
|
"PEN": 3.771,
|
||||||
"PGK": 3.887667,
|
"PGK": 3.904201,
|
||||||
"PHP": 58.519502,
|
"PHP": 58.6695,
|
||||||
"PKR": 278.529362,
|
"PKR": 278.575,
|
||||||
"PLN": 3.932408,
|
"PLN": 4.046857,
|
||||||
"PYG": 7514.698541,
|
"PYG": 7533.486837,
|
||||||
"QAR": 3.642917,
|
"QAR": 3.641,
|
||||||
"RON": 4.569,
|
"RON": 4.6339,
|
||||||
"RSD": 107.495,
|
"RSD": 108.997,
|
||||||
"RUB": 89.173363,
|
"RUB": 88.381576,
|
||||||
"RWF": 1298.427641,
|
"RWF": 1320,
|
||||||
"SAR": 3.750551,
|
"SAR": 3.751693,
|
||||||
"SBD": 8.482503,
|
"SBD": 8.457605,
|
||||||
"SCR": 13.845723,
|
"SCR": 13.855402,
|
||||||
"SDG": 586,
|
"SDG": 586,
|
||||||
"SEK": 10.38479,
|
"SEK": 10.472668,
|
||||||
"SGD": 1.34481,
|
"SGD": 1.3506,
|
||||||
"SHP": 0.782189,
|
"SHP": 0.783387,
|
||||||
"SLL": 20969.5,
|
"SLL": 20969.5,
|
||||||
"SOS": 570.753969,
|
"SOS": 571,
|
||||||
"SRD": 31.7645,
|
"SRD": 31.627,
|
||||||
"SSP": 130.26,
|
"SSP": 130.26,
|
||||||
"STD": 22281.8,
|
"STD": 22281.8,
|
||||||
"STN": 22.496155,
|
"STN": 22.9,
|
||||||
"SVC": 8.738769,
|
"SVC": 8.769202,
|
||||||
"SYP": 2512.53,
|
"SYP": 2512.53,
|
||||||
"SZL": 18.948934,
|
"SZL": 18.4,
|
||||||
"THB": 36.351667,
|
"THB": 36.78,
|
||||||
"TJS": 10.696062,
|
"TJS": 10.798706,
|
||||||
"TMT": 3.51,
|
"TMT": 3.5,
|
||||||
"TND": 3.10175,
|
"TND": 3.113,
|
||||||
"TOP": 2.352606,
|
"TOP": 2.354259,
|
||||||
"TRY": 32.310647,
|
"TRY": 32.291698,
|
||||||
"TTD": 6.757172,
|
"TTD": 6.811102,
|
||||||
"TWD": 32.282,
|
"TWD": 32.359801,
|
||||||
"TZS": 2615,
|
"TZS": 2621.947791,
|
||||||
"UAH": 40.094667,
|
"UAH": 40.510836,
|
||||||
"UGX": 3788.628608,
|
"UGX": 3738.089071,
|
||||||
"USD": 1,
|
"USD": 1,
|
||||||
"UYU": 38.896466,
|
"UYU": 39.198992,
|
||||||
"UZS": 12659.755435,
|
"UZS": 12635,
|
||||||
"VES": 36.442787,
|
"VES": 36.383822,
|
||||||
"VND": 25422.651993,
|
"VND": 25442.5,
|
||||||
"VUV": 118.722,
|
"VUV": 118.722,
|
||||||
"WST": 2.8,
|
"WST": 2.8,
|
||||||
"XAF": 602.310759,
|
"XAF": 610.732275,
|
||||||
"XAG": 0.03205488,
|
"XAG": 0.03455545,
|
||||||
"XAU": 0.0004209,
|
"XAU": 0.00043413,
|
||||||
"XCD": 2.70255,
|
"XCD": 2.70255,
|
||||||
"XDR": 0.75467,
|
"XDR": 0.760342,
|
||||||
"XOF": 602.310759,
|
"XOF": 610.732275,
|
||||||
"XPD": 0.00108737,
|
"XPD": 0.00113637,
|
||||||
"XPF": 109.572414,
|
"XPF": 111.104457,
|
||||||
"XPT": 0.00099467,
|
"XPT": 0.00105291,
|
||||||
"YER": 250.425029,
|
"YER": 250.350066,
|
||||||
"ZAR": 18.932716,
|
"ZAR": 18.430643,
|
||||||
"ZMW": 26.240618,
|
"ZMW": 26.433191,
|
||||||
"ZWL": 322
|
"ZWL": 322
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1953,17 +1953,30 @@ type GetPayloadSDKParams = {
|
||||||
apiURL: string;
|
apiURL: string;
|
||||||
email: string;
|
email: string;
|
||||||
password: string;
|
password: string;
|
||||||
cache: Cache;
|
tokenCache?: {
|
||||||
};
|
|
||||||
|
|
||||||
type Cache = {
|
|
||||||
set: (token: string, expirationTimestamp: number) => void;
|
set: (token: string, expirationTimestamp: number) => void;
|
||||||
get: () => string | undefined;
|
get: () => string | undefined;
|
||||||
};
|
};
|
||||||
|
responseCache?: {
|
||||||
|
set: (url: string, response: any) => void;
|
||||||
|
get: (url: string) => any | undefined;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export type PayloadResponse<T> = {
|
||||||
|
data: T;
|
||||||
|
timestamp: Date;
|
||||||
|
};
|
||||||
|
|
||||||
const logResponse = (res: Response) => console.log(res.status, res.statusText, res.url);
|
const logResponse = (res: Response) => console.log(res.status, res.statusText, res.url);
|
||||||
|
|
||||||
export const getPayloadSDK = ({ apiURL, email, password, cache }: GetPayloadSDKParams) => {
|
export const getPayloadSDK = ({
|
||||||
|
apiURL,
|
||||||
|
email,
|
||||||
|
password,
|
||||||
|
tokenCache,
|
||||||
|
responseCache,
|
||||||
|
}: GetPayloadSDKParams) => {
|
||||||
const refreshToken = async () => {
|
const refreshToken = async () => {
|
||||||
const loginUrl = payloadApiUrl(Collections.Recorders, "login");
|
const loginUrl = payloadApiUrl(Collections.Recorders, "login");
|
||||||
const loginResult = await fetch(loginUrl, {
|
const loginResult = await fetch(loginUrl, {
|
||||||
|
@ -1981,72 +1994,82 @@ export const getPayloadSDK = ({ apiURL, email, password, cache }: GetPayloadSDKP
|
||||||
token: string;
|
token: string;
|
||||||
exp: number;
|
exp: number;
|
||||||
};
|
};
|
||||||
cache.set(token, exp);
|
tokenCache?.set(token, exp);
|
||||||
return token;
|
return token;
|
||||||
};
|
};
|
||||||
|
|
||||||
const payloadApiUrl = (collection: Collections, endpoint?: string, isGlobal?: boolean): string =>
|
const payloadApiUrl = (collection: Collections, endpoint?: string, isGlobal?: boolean): string =>
|
||||||
`${apiURL}/${isGlobal === undefined ? "" : "globals/"}${collection}${endpoint === undefined ? "" : `/${endpoint}`}`;
|
`${apiURL}/${isGlobal === undefined ? "" : "globals/"}${collection}${endpoint === undefined ? "" : `/${endpoint}`}`;
|
||||||
|
|
||||||
const request = async (url: string): Promise<Response> => {
|
const request = async (url: string): Promise<PayloadResponse<any>> => {
|
||||||
|
const cachedResponse = responseCache?.get(url);
|
||||||
|
if (cachedResponse) {
|
||||||
|
return cachedResponse;
|
||||||
|
}
|
||||||
|
|
||||||
const result = await fetch(url, {
|
const result = await fetch(url, {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `JWT ${cache.get() ?? (await refreshToken())}`,
|
Authorization: `JWT ${tokenCache?.get() ?? (await refreshToken())}`,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
logResponse(result);
|
logResponse(result);
|
||||||
|
|
||||||
if (result.status !== 200) {
|
if (!result.ok) {
|
||||||
throw new Error("Unhandled fetch error");
|
throw new Error("Unhandled fetch error");
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
const data = { data: await result.json(), timestamp: new Date() };
|
||||||
|
|
||||||
|
responseCache?.set(url, data);
|
||||||
|
return data;
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
getConfig: async (): Promise<EndpointWebsiteConfig> =>
|
getConfig: async (): Promise<PayloadResponse<EndpointWebsiteConfig>> =>
|
||||||
await (await request(payloadApiUrl(Collections.WebsiteConfig, `config`, true))).json(),
|
await request(payloadApiUrl(Collections.WebsiteConfig, `config`, true)),
|
||||||
getFolder: async (slug: string): Promise<EndpointFolder> =>
|
getFolder: async (slug: string): Promise<PayloadResponse<EndpointFolder>> =>
|
||||||
await (await request(payloadApiUrl(Collections.Folders, `slug/${slug}`))).json(),
|
await request(payloadApiUrl(Collections.Folders, `slug/${slug}`)),
|
||||||
getLanguages: async (): Promise<Language[]> =>
|
getLanguages: async (): Promise<PayloadResponse<Language[]>> =>
|
||||||
await (await request(payloadApiUrl(Collections.Languages, `all`))).json(),
|
await request(payloadApiUrl(Collections.Languages, `all`)),
|
||||||
getCurrencies: async (): Promise<Currency[]> =>
|
getCurrencies: async (): Promise<PayloadResponse<Currency[]>> =>
|
||||||
await (await request(payloadApiUrl(Collections.Currencies, `all`))).json(),
|
await request(payloadApiUrl(Collections.Currencies, `all`)),
|
||||||
getWordings: async (): Promise<EndpointWording[]> =>
|
getWordings: async (): Promise<PayloadResponse<EndpointWording[]>> =>
|
||||||
await (await request(payloadApiUrl(Collections.Wordings, `all`))).json(),
|
await request(payloadApiUrl(Collections.Wordings, `all`)),
|
||||||
getPage: async (slug: string): Promise<EndpointPage> =>
|
getPage: async (slug: string): Promise<PayloadResponse<EndpointPage>> =>
|
||||||
await (await request(payloadApiUrl(Collections.Pages, `slug/${slug}`))).json(),
|
await request(payloadApiUrl(Collections.Pages, `slug/${slug}`)),
|
||||||
getCollectible: async (slug: string): Promise<EndpointCollectible> =>
|
getCollectible: async (slug: string): Promise<PayloadResponse<EndpointCollectible>> =>
|
||||||
await (await request(payloadApiUrl(Collections.Collectibles, `slug/${slug}`))).json(),
|
await request(payloadApiUrl(Collections.Collectibles, `slug/${slug}`)),
|
||||||
getCollectibleScans: async (slug: string): Promise<EndpointCollectibleScans> =>
|
getCollectibleScans: async (
|
||||||
await (await request(payloadApiUrl(Collections.Collectibles, `slug/${slug}/scans`))).json(),
|
slug: string
|
||||||
|
): Promise<PayloadResponse<EndpointCollectibleScans>> =>
|
||||||
|
await request(payloadApiUrl(Collections.Collectibles, `slug/${slug}/scans`)),
|
||||||
getCollectibleScanPage: async (
|
getCollectibleScanPage: async (
|
||||||
slug: string,
|
slug: string,
|
||||||
index: string
|
index: string
|
||||||
): Promise<EndpointCollectibleScanPage> =>
|
): Promise<PayloadResponse<EndpointCollectibleScanPage>> =>
|
||||||
await (
|
await request(payloadApiUrl(Collections.Collectibles, `slug/${slug}/scans/${index}`)),
|
||||||
await request(payloadApiUrl(Collections.Collectibles, `slug/${slug}/scans/${index}`))
|
getCollectibleGallery: async (
|
||||||
).json(),
|
slug: string
|
||||||
getCollectibleGallery: async (slug: string): Promise<EndpointCollectibleGallery> =>
|
): Promise<PayloadResponse<EndpointCollectibleGallery>> =>
|
||||||
await (await request(payloadApiUrl(Collections.Collectibles, `slug/${slug}/gallery`))).json(),
|
await request(payloadApiUrl(Collections.Collectibles, `slug/${slug}/gallery`)),
|
||||||
getCollectibleGalleryImage: async (
|
getCollectibleGalleryImage: async (
|
||||||
slug: string,
|
slug: string,
|
||||||
index: string
|
index: string
|
||||||
): Promise<EndpointCollectibleGalleryImage> =>
|
): Promise<PayloadResponse<EndpointCollectibleGalleryImage>> =>
|
||||||
await (
|
await request(payloadApiUrl(Collections.Collectibles, `slug/${slug}/gallery/${index}`)),
|
||||||
await request(payloadApiUrl(Collections.Collectibles, `slug/${slug}/gallery/${index}`))
|
getChronologyEvents: async (): Promise<PayloadResponse<EndpointChronologyEvent[]>> =>
|
||||||
).json(),
|
await request(payloadApiUrl(Collections.ChronologyEvents, `all`)),
|
||||||
getChronologyEvents: async (): Promise<EndpointChronologyEvent[]> =>
|
getChronologyEventByID: async (
|
||||||
await (await request(payloadApiUrl(Collections.ChronologyEvents, `all`))).json(),
|
id: string
|
||||||
getChronologyEventByID: async (id: string): Promise<EndpointChronologyEvent> =>
|
): Promise<PayloadResponse<EndpointChronologyEvent>> =>
|
||||||
await (await request(payloadApiUrl(Collections.ChronologyEvents, `id/${id}`))).json(),
|
await request(payloadApiUrl(Collections.ChronologyEvents, `id/${id}`)),
|
||||||
getImageByID: async (id: string): Promise<EndpointImage> =>
|
getImageByID: async (id: string): Promise<PayloadResponse<EndpointImage>> =>
|
||||||
await (await request(payloadApiUrl(Collections.Images, `id/${id}`))).json(),
|
await request(payloadApiUrl(Collections.Images, `id/${id}`)),
|
||||||
getAudioByID: async (id: string): Promise<EndpointAudio> =>
|
getAudioByID: async (id: string): Promise<PayloadResponse<EndpointAudio>> =>
|
||||||
await (await request(payloadApiUrl(Collections.Audios, `id/${id}`))).json(),
|
await request(payloadApiUrl(Collections.Audios, `id/${id}`)),
|
||||||
getVideoByID: async (id: string): Promise<EndpointVideo> =>
|
getVideoByID: async (id: string): Promise<PayloadResponse<EndpointVideo>> =>
|
||||||
await (await request(payloadApiUrl(Collections.Videos, `id/${id}`))).json(),
|
await request(payloadApiUrl(Collections.Videos, `id/${id}`)),
|
||||||
getRecorderByID: async (id: string): Promise<EndpointRecorder> =>
|
getRecorderByID: async (id: string): Promise<PayloadResponse<EndpointRecorder>> =>
|
||||||
await (await request(payloadApiUrl(Collections.Recorders, `id/${id}`))).json(),
|
await request(payloadApiUrl(Collections.Recorders, `id/${id}`)),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,39 +4,47 @@ import {
|
||||||
type EndpointWebsiteConfig,
|
type EndpointWebsiteConfig,
|
||||||
} from "src/shared/payload/payload-sdk";
|
} from "src/shared/payload/payload-sdk";
|
||||||
import { getPayloadSDK } from "src/shared/payload/payload-sdk";
|
import { getPayloadSDK } from "src/shared/payload/payload-sdk";
|
||||||
import NodeCache from "node-cache";
|
|
||||||
|
|
||||||
const REFRESH_FREQUENCY_IN_SEC = 60;
|
let token: string | undefined = undefined;
|
||||||
const nodeCache = new NodeCache({
|
let expiration: number | undefined = undefined;
|
||||||
checkperiod: REFRESH_FREQUENCY_IN_SEC,
|
|
||||||
deleteOnExpire: true,
|
const responseCache = new Map<string, any>();
|
||||||
forceString: true,
|
|
||||||
maxKeys: 1,
|
|
||||||
});
|
|
||||||
const TOKEN_KEY = "token";
|
|
||||||
|
|
||||||
export const payload = getPayloadSDK({
|
export const payload = getPayloadSDK({
|
||||||
apiURL: import.meta.env.PAYLOAD_API_URL,
|
apiURL: import.meta.env.PAYLOAD_API_URL,
|
||||||
email: import.meta.env.PAYLOAD_USER,
|
email: import.meta.env.PAYLOAD_USER,
|
||||||
password: import.meta.env.PAYLOAD_PASSWORD,
|
password: import.meta.env.PAYLOAD_PASSWORD,
|
||||||
cache: {
|
tokenCache: {
|
||||||
get: () => {
|
get: () => {
|
||||||
const cachedToken = nodeCache.get<string>(TOKEN_KEY);
|
if (!token) return undefined;
|
||||||
if (cachedToken !== undefined) {
|
if (!expiration || expiration < Date.now()) {
|
||||||
const cachedTokenTtl = nodeCache.getTtl(TOKEN_KEY) as number;
|
console.log("[PayloadSDK] No token to be retrieved or the token expired");
|
||||||
const diffInMinutes = Math.floor((cachedTokenTtl - Date.now()) / 1000 / 60);
|
|
||||||
console.log("Retrieved token from cache. TTL is", diffInMinutes, "minutes.");
|
|
||||||
return cachedToken;
|
|
||||||
}
|
|
||||||
console.log("No token to be retrieved or the token expired");
|
|
||||||
return undefined;
|
return undefined;
|
||||||
|
}
|
||||||
|
const diffInMinutes = Math.floor((expiration - Date.now()) / 1000 / 60);
|
||||||
|
console.log("[PayloadSDK] Retrieved token from cache. TTL is", diffInMinutes, "minutes.");
|
||||||
|
return token;
|
||||||
},
|
},
|
||||||
set: (token, exp) => {
|
set: (newToken, newExpiration) => {
|
||||||
const now = Math.floor(Date.now() / 1000);
|
token = newToken;
|
||||||
const ttl = Math.floor(exp - now - REFRESH_FREQUENCY_IN_SEC * 2);
|
expiration = newExpiration * 1000;
|
||||||
const ttlInMinutes = Math.floor(ttl / 60);
|
const diffInMinutes = Math.floor((expiration - Date.now()) / 1000 / 60);
|
||||||
console.log("Token was refreshed. TTL is", ttlInMinutes, "minutes.");
|
console.log("[PayloadSDK] New token set. TTL is", diffInMinutes, "minutes.");
|
||||||
nodeCache.set(TOKEN_KEY, token, ttl);
|
},
|
||||||
|
},
|
||||||
|
responseCache: {
|
||||||
|
get: (url) => {
|
||||||
|
const cachedResponse = responseCache.get(url);
|
||||||
|
if (!cachedResponse) {
|
||||||
|
console.log("[ResponseCaching] No cached response found for", url);
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
console.log("[ResponseCaching] Retrieved cache response for", url);
|
||||||
|
return cachedResponse;
|
||||||
|
},
|
||||||
|
set: (url, response) => {
|
||||||
|
console.log("[ResponseCaching] Caching response for", url);
|
||||||
|
responseCache.set(url, response);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -49,26 +57,26 @@ type Cache = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchNewData = async (): Promise<Cache> => ({
|
const fetchNewData = async (): Promise<Cache> => ({
|
||||||
locales: await payload.getLanguages(),
|
locales: (await payload.getLanguages()).data,
|
||||||
currencies: (await payload.getCurrencies()).map(({ id }) => id),
|
currencies: (await payload.getCurrencies()).data.map(({ id }) => id),
|
||||||
wordings: await payload.getWordings(),
|
wordings: (await payload.getWordings()).data,
|
||||||
config: await payload.getConfig(),
|
config: (await payload.getConfig()).data,
|
||||||
});
|
});
|
||||||
|
|
||||||
export let cache = await fetchNewData();
|
export let cache = await fetchNewData();
|
||||||
|
|
||||||
export const refreshWordings = async () => {
|
export const refreshWordings = async () => {
|
||||||
cache.wordings = await payload.getWordings();
|
cache.wordings = (await payload.getWordings()).data;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const refreshCurrencies = async () => {
|
export const refreshCurrencies = async () => {
|
||||||
cache.currencies = (await payload.getCurrencies()).map(({ id }) => id);
|
cache.currencies = (await payload.getCurrencies()).data.map(({ id }) => id);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const refreshLocales = async () => {
|
export const refreshLocales = async () => {
|
||||||
cache.locales = await payload.getLanguages();
|
cache.locales = (await payload.getLanguages()).data;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const refreshWebsiteConfig = async () => {
|
export const refreshWebsiteConfig = async () => {
|
||||||
cache.config = await payload.getConfig();
|
cache.config = (await payload.getConfig()).data;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,39 @@
|
||||||
export const fetchOr404 = async <T>(promise: () => Promise<T>): Promise<T | Response> => {
|
import type { PayloadResponse } from "src/shared/payload/payload-sdk";
|
||||||
|
|
||||||
|
export const fetchOr404 = async <T>(
|
||||||
|
{
|
||||||
|
request,
|
||||||
|
response,
|
||||||
|
}: {
|
||||||
|
request: Request;
|
||||||
|
response: {
|
||||||
|
headers: Headers;
|
||||||
|
};
|
||||||
|
},
|
||||||
|
promise: () => Promise<PayloadResponse<T>>
|
||||||
|
): Promise<T | Response> => {
|
||||||
try {
|
try {
|
||||||
return await promise();
|
const { data, timestamp } = await promise();
|
||||||
|
const lastModified = timestamp.toUTCString();
|
||||||
|
|
||||||
|
if (request.headers.get("If-Modified-Since") === lastModified) {
|
||||||
|
return new Response(null, {
|
||||||
|
status: 304,
|
||||||
|
statusText: "Not Modified",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// const userEtag = Astro.request.headers.get("If-None-Match");
|
||||||
|
// if (userEtag === collectible.etag) {
|
||||||
|
// return new Response(null, {
|
||||||
|
// status: 304,
|
||||||
|
// statusText: "Not Modified",
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
response.headers.set("Last-Modified", lastModified);
|
||||||
|
|
||||||
|
return data;
|
||||||
} catch {
|
} catch {
|
||||||
return new Response(null, {
|
return new Response(null, {
|
||||||
status: 404,
|
status: 404,
|
||||||
|
|
Loading…
Reference in New Issue