export function json(content: unknown) { const headers = new Headers(); headers.append("Content-Type", "application/json"); return new Response(JSON.stringify(content), { headers, }); } export const isValidUrl = (urlString: string) => { try { return Boolean(new URL(urlString)); } catch (_e) { return false; } }; export const fixRenderedMarkdown = (content: string) => { return content.replace("***\n", "---") .replace("----------------", "---") .replace("\n---", "---") .replace(/^(date:[^'\n]*)'|'/gm, (match, p1, p2) => { if (p1) { // This is a line starting with date: followed by single quotes return p1.replace(/'/gm, ""); } else if (p2) { return ""; } else { // This is a line with single quotes, but not starting with date: return match; } }); }; export async function fetchStream(url: string, cb: (chunk: string) => void) { const response = await fetch(url); const reader = response?.body?.getReader(); if (reader) { while (true) { const { done, value } = await reader.read(); if (done) return; const data = new TextDecoder().decode(value); data .split("$") .filter((d) => d && d.length) .map((d) => cb(Array.isArray(d) ? d[0] : d)); } } } export function hashString(message: string) { let hash = 0; for (let i = 0; i < message.length; i++) { const char = message.charCodeAt(i); hash = ((hash << 5) - hash) + char; hash = hash & hash; // Convert to 32bit integer } return hash; } export const createStreamResponse = () => { let controller: ReadableStreamController; const body = new ReadableStream({ start(cont) { controller = cont; }, }); const response = new Response(body, { headers: { "content-type": "text/plain", "x-content-type-options": "nosniff", }, }); function cancel() { controller.close(); } function enqueue(chunk: string) { controller?.enqueue(new TextEncoder().encode("$" + chunk)); } return { response, cancel, enqueue, }; }; export type StreamResponse = ReturnType; export function debounce) => void>( this: ThisParameterType, fn: T, delay = 300, ) { let timer: ReturnType | undefined; return (...args: Parameters) => { clearTimeout(timer); timer = setTimeout(() => fn.apply(this, args), delay); }; } export function parseRating(rating: string | number) { if (typeof rating === "string") { return [...rating.matchAll(/⭐/)].length; } return rating; }