mirror of
https://github.com/pocket-id/pocket-id.git
synced 2025-12-24 01:11:52 +03:00
118 lines
3.8 KiB
TypeScript
118 lines
3.8 KiB
TypeScript
type SkipCacheUntil = {
|
|
[key: string]: number;
|
|
};
|
|
|
|
type CachableImage = {
|
|
getUrl: (...props: any[]) => string;
|
|
bustCache: (...props: any[]) => void;
|
|
};
|
|
|
|
export const cachedApplicationLogo: CachableImage = {
|
|
getUrl: (light = true) => {
|
|
const url = new URL('/api/application-images/logo', window.location.origin);
|
|
if (!light) url.searchParams.set('light', 'false');
|
|
return getCachedImageUrl(url);
|
|
},
|
|
bustCache: (light = true) => {
|
|
const url = new URL('/api/application-images/logo', window.location.origin);
|
|
if (!light) url.searchParams.set('light', 'false');
|
|
bustImageCache(url);
|
|
}
|
|
};
|
|
|
|
export const cachedEmailLogo: CachableImage = {
|
|
getUrl: () => getCachedImageUrl(new URL('/api/application-images/email', window.location.origin)),
|
|
bustCache: () => bustImageCache(new URL('/api/application-images/email', window.location.origin))
|
|
};
|
|
|
|
export const cachedDefaultProfilePicture: CachableImage = {
|
|
getUrl: () =>
|
|
getCachedImageUrl(
|
|
new URL('/api/application-images/default-profile-picture', window.location.origin)
|
|
),
|
|
bustCache: () =>
|
|
bustImageCache(
|
|
new URL('/api/application-images/default-profile-picture', window.location.origin)
|
|
)
|
|
};
|
|
|
|
export const cachedBackgroundImage: CachableImage = {
|
|
getUrl: () =>
|
|
getCachedImageUrl(new URL('/api/application-images/background', window.location.origin)),
|
|
bustCache: () =>
|
|
bustImageCache(new URL('/api/application-images/background', window.location.origin))
|
|
};
|
|
|
|
export const cachedProfilePicture: CachableImage = {
|
|
getUrl: (userId: string) => {
|
|
const url = new URL(`/api/users/${userId}/profile-picture.png`, window.location.origin);
|
|
return getCachedImageUrl(url);
|
|
},
|
|
bustCache: (userId: string) => {
|
|
const url = new URL(`/api/users/${userId}/profile-picture.png`, window.location.origin);
|
|
bustImageCache(url);
|
|
}
|
|
};
|
|
|
|
export const cachedOidcClientLogo: CachableImage = {
|
|
getUrl: (clientId: string, light = true) => {
|
|
const url = new URL(`/api/oidc/clients/${clientId}/logo`, window.location.origin);
|
|
if (!light) url.searchParams.set('light', 'false');
|
|
return getCachedImageUrl(url);
|
|
},
|
|
bustCache: (clientId: string, light = true) => {
|
|
const url = new URL(`/api/oidc/clients/${clientId}/logo`, window.location.origin);
|
|
if (!light) url.searchParams.set('light', 'false');
|
|
bustImageCache(url);
|
|
}
|
|
};
|
|
|
|
function getCachedImageUrl(url: URL) {
|
|
const baseKey = normalizeUrlForKey(url);
|
|
const skipCacheUntil = getSkipCacheUntil(baseKey);
|
|
const skipCache = skipCacheUntil > Date.now();
|
|
|
|
const finalUrl = new URL(url.toString());
|
|
if (skipCache) {
|
|
finalUrl.searchParams.set('skip-cache', skipCacheUntil.toString());
|
|
}
|
|
|
|
return finalUrl.pathname + (finalUrl.search ? `?${finalUrl.searchParams.toString()}` : '');
|
|
}
|
|
|
|
function bustImageCache(url: URL) {
|
|
const key = normalizeUrlForKey(url);
|
|
const expiresAt = Date.now() + 1000 * 60 * 15;
|
|
|
|
const store: SkipCacheUntil = JSON.parse(localStorage.getItem('skip-cache-until') ?? '{}');
|
|
store[key] = expiresAt;
|
|
localStorage.setItem('skip-cache-until', JSON.stringify(store));
|
|
}
|
|
|
|
function getSkipCacheUntil(key: string): number {
|
|
const store: SkipCacheUntil = JSON.parse(localStorage.getItem('skip-cache-until') ?? '{}');
|
|
return store[key] ?? 0;
|
|
}
|
|
|
|
// Removes transient params and normalizes query order before hashing
|
|
function normalizeUrlForKey(url: URL) {
|
|
const u = new URL(url.toString());
|
|
u.searchParams.delete('skip-cache');
|
|
|
|
const sortedParams = new URLSearchParams(
|
|
[...u.searchParams.entries()].sort(([a], [b]) => a.localeCompare(b))
|
|
);
|
|
const normalized = u.pathname + (sortedParams.toString() ? `?${sortedParams.toString()}` : '');
|
|
return hashKey(normalized);
|
|
}
|
|
|
|
function hashKey(key: string): string {
|
|
let hash = 0;
|
|
for (let i = 0; i < key.length; i++) {
|
|
const char = key.charCodeAt(i);
|
|
hash = (hash << 5) - hash + char;
|
|
hash |= 0;
|
|
}
|
|
return Math.abs(hash).toString(36);
|
|
}
|