112 lines
2.8 KiB
TypeScript
112 lines
2.8 KiB
TypeScript
import { createCache } from "../cache.ts";
|
|
import { MARKA_API_KEY } from "../env.ts";
|
|
import { getImage } from "../image.ts";
|
|
import { GenericResource } from "./schema.ts";
|
|
|
|
const url = `https://marka.max-richter.dev`;
|
|
//const url = "http://localhost:8080";
|
|
|
|
async function addImageToResource<T extends GenericResource>(
|
|
resource: GenericResource,
|
|
): Promise<T> {
|
|
const imageUrl = resource?.content?.image;
|
|
if (imageUrl) {
|
|
try {
|
|
const absoluteImageUrl = (imageUrl.startsWith("https://") ||
|
|
imageUrl.startsWith("http://"))
|
|
? imageUrl
|
|
: `${url}/${imageUrl}`;
|
|
const image = await getImage(absoluteImageUrl);
|
|
return { ...resource, image } as T;
|
|
} catch (e) {
|
|
console.log(`Failed to fetch image: ${imageUrl}`, e);
|
|
}
|
|
}
|
|
return resource as T;
|
|
}
|
|
|
|
type Resource = GenericResource & {
|
|
content: GenericResource["content"] & Array<GenericResource>;
|
|
};
|
|
|
|
const fetchCache = createCache<Resource>("marka");
|
|
const cacheLock = new Map<string, Promise<Resource>>();
|
|
async function cachedFetch(
|
|
url: string,
|
|
): Promise<Resource | undefined> {
|
|
if (fetchCache.has(url)) {
|
|
return fetchCache.get(url);
|
|
}
|
|
if (cacheLock.has(url)) {
|
|
return cacheLock.get(url);
|
|
}
|
|
const response = (async () => {
|
|
const response = await fetch(url);
|
|
const res = await response.json();
|
|
fetchCache.set(url, res);
|
|
return res;
|
|
})();
|
|
cacheLock.set(
|
|
url,
|
|
response,
|
|
);
|
|
const res = await response;
|
|
if (!res) {
|
|
cacheLock.delete(url);
|
|
}
|
|
return res;
|
|
}
|
|
|
|
export async function fetchResource<T extends Resource>(
|
|
resource: string,
|
|
): Promise<T | undefined> {
|
|
try {
|
|
const d = `${url}/resources/${resource}`;
|
|
const res = await cachedFetch(d);
|
|
if (!res) return;
|
|
return addImageToResource<T>(res);
|
|
} catch (_e) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
export async function listResources<T extends GenericResource>(
|
|
resource: string,
|
|
): Promise<T[]> {
|
|
try {
|
|
const d = `${url}/resources/${resource}`;
|
|
const list = await cachedFetch(d);
|
|
if (!list) return [];
|
|
return Promise.all(
|
|
list?.content
|
|
.filter((a) => a?.content?._type)
|
|
.map((res) => addImageToResource(res) as Promise<T>),
|
|
);
|
|
} catch (_e) {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
export async function createResource(
|
|
path: string,
|
|
content: string | object | ArrayBuffer,
|
|
) {
|
|
const isJson = typeof content === "object" &&
|
|
!(content instanceof ArrayBuffer);
|
|
const fetchUrl = `${url}/resources/${path}`;
|
|
const headers = new Headers();
|
|
headers.append("Content-Type", isJson ? "application/json" : "");
|
|
if (MARKA_API_KEY) {
|
|
headers.append("Authentication", MARKA_API_KEY);
|
|
}
|
|
const response = await fetch(fetchUrl, {
|
|
method: "POST",
|
|
headers,
|
|
body: isJson ? JSON.stringify(content) : content,
|
|
});
|
|
if (!response.ok) {
|
|
throw new Error(`Failed to create resource: ${response.status}`);
|
|
}
|
|
return response.json();
|
|
}
|