TelegramPWA/src/util/cacheApi.ts
2022-05-31 20:58:35 +04:00

117 lines
3.0 KiB
TypeScript

// eslint-disable-next-line no-restricted-globals
const cacheApi = self.caches;
export enum Type {
Text,
Blob,
Json,
ArrayBuffer,
}
export async function fetch(
cacheName: string, key: string, type: Type, isHtmlAllowed = false,
) {
if (!cacheApi) {
return undefined;
}
try {
// To avoid the error "Request scheme 'webdocument' is unsupported"
const request = new Request(key.replace(/:/g, '_'));
const cache = await cacheApi.open(cacheName);
const response = await cache.match(request);
if (!response) {
return undefined;
}
const contentType = response.headers.get('Content-Type');
switch (type) {
case Type.Text:
return await response.text();
case Type.Blob: {
// Ignore deprecated data-uri avatars
if (key.startsWith('avatar') && contentType && contentType.startsWith('text')) {
return undefined;
}
const blob = await response.blob();
const shouldRecreate = !blob.type || (!isHtmlAllowed && blob.type.includes('html'));
// iOS Safari fails to preserve `type` in cache
let resolvedType = blob.type || contentType;
if (!(shouldRecreate && resolvedType)) {
return blob;
}
// Prevent HTML-in-video attacks (for files that were cached before fix)
if (!isHtmlAllowed) {
resolvedType = resolvedType.replace(/html/gi, '');
}
return new Blob([blob], { type: resolvedType });
}
case Type.Json:
return await response.json();
case Type.ArrayBuffer:
return await response.arrayBuffer();
default:
return undefined;
}
} catch (err) {
// eslint-disable-next-line no-console
console.warn(err);
return undefined;
}
}
export async function save(cacheName: string, key: string, data: AnyLiteral | Blob | ArrayBuffer | string) {
if (!cacheApi) {
return undefined;
}
try {
const cacheData = typeof data === 'string' || data instanceof Blob || data instanceof ArrayBuffer
? data
: JSON.stringify(data);
// To avoid the error "Request scheme 'webdocument' is unsupported"
const request = new Request(key.replace(/:/g, '_'));
const response = new Response(cacheData);
const cache = await cacheApi.open(cacheName);
return await cache.put(request, response);
} catch (err) {
// eslint-disable-next-line no-console
console.warn(err);
return undefined;
}
}
export async function remove(cacheName: string, key: string) {
try {
if (!cacheApi) {
return undefined;
}
const cache = await cacheApi.open(cacheName);
return await cache.delete(key);
} catch (err) {
// eslint-disable-next-line no-console
console.warn(err);
return undefined;
}
}
export async function clear(cacheName: string) {
try {
if (!cacheApi) {
return undefined;
}
return await cacheApi.delete(cacheName);
} catch (err) {
// eslint-disable-next-line no-console
console.warn(err);
return undefined;
}
}