'use client' import { useEffect } from 'react' const allowedHosts = new Set(['www.eversolo.com', 'eversolo.com']) const proxyPath = '/api/eversolo-paste-url' const pasteFetchCollectDelay = 300 const pasteFetchIdleReleaseDelay = 250 const pasteFetchRetryDelays = [0, 300, 800] const pasteFetchConcurrency = 4 const pasteFetchPatchVersion = 5 const bypassPathPrefixes = ['/admin', '/api', '/_next'] const assetPathPrefixes = ['/Attached/', '/Products/', '/Uploads/', '/controlapp/', '/files/', '/media/', '/videos/'] const assetExtensions = new Set([ '7z', 'aac', 'avi', 'bmp', 'css', 'csv', 'doc', 'docx', 'flac', 'gif', 'gz', 'htm', 'html', 'ico', 'jpeg', 'jpg', 'js', 'json', 'm4a', 'mov', 'mp3', 'mp4', 'pdf', 'png', 'rar', 'svg', 'tar', 'txt', 'wav', 'webm', 'webp', 'xls', 'xlsx', 'xml', 'zip', ]) type PatchedWindow = Window & { __eversoloPasteURLFetchPatchVersion?: number } type QueuedPasteFetch = { init?: RequestInit proxiedURL: string reject: (reason?: unknown) => void resolve: (response: Response) => void result?: PromiseSettledResult source?: QueuedPasteFetch } let activePasteFetches = 0 let pasteFetchCollectTimer: number | undefined let pasteFetchReleaseTimer: number | undefined const pasteFetchPendingQueue: QueuedPasteFetch[] = [] let pasteFetchSession: QueuedPasteFetch[] = [] function getFetchURL(input: RequestInfo | URL) { if (typeof input === 'string') return input if (input instanceof URL) return input.href return input.url } function getFetchMethod(input: RequestInfo | URL, init?: RequestInit) { if (init?.method) return init.method if (typeof input !== 'string' && !(input instanceof URL)) return input.method return undefined } function isBypassedURL(url: URL) { if (url.origin === window.location.origin) return true if (url.searchParams.has('_rsc')) return true return bypassPathPrefixes.some((prefix) => { return url.pathname === prefix || url.pathname.startsWith(`${prefix}/`) }) } function isAssetURL(url: URL) { if (assetPathPrefixes.some((prefix) => url.pathname.startsWith(prefix))) return true const extension = url.pathname.split('/').pop()?.split('.').pop()?.toLowerCase() return extension ? assetExtensions.has(extension) : false } function getProxiedPasteURL(input: RequestInfo | URL, init?: RequestInit) { const method = getFetchMethod(input, init) if (method && method.toUpperCase() !== 'GET' && method.toUpperCase() !== 'HEAD') { return null } try { const url = new URL(getFetchURL(input)) if (url.protocol !== 'https:' || !allowedHosts.has(url.hostname)) { return null } if (isBypassedURL(url) || !isAssetURL(url)) { return null } return `${proxyPath}?src=${encodeURIComponent(url.href)}` } catch { return null } } function wait(delay: number) { return new Promise((resolve) => { window.setTimeout(resolve, delay) }) } async function fetchWithRetry( originalFetch: typeof fetch, proxiedURL: string, init?: RequestInit, ) { let lastError: unknown for (const [index, delay] of pasteFetchRetryDelays.entries()) { if (delay > 0) { await wait(delay) } try { const response = await originalFetch(proxiedURL, { ...init, method: 'GET', }) if (response.ok || index === pasteFetchRetryDelays.length - 1) { return response } } catch (error) { lastError = error } } throw lastError } function releasePasteFetchSession() { if (activePasteFetches > 0 || pasteFetchPendingQueue.length > 0) return const session = pasteFetchSession pasteFetchSession = [] pasteFetchReleaseTimer = undefined session.forEach((item) => { const result = item.result ?? item.source?.result if (!result) return if (result.status === 'fulfilled') { item.resolve(result.value.clone()) } else { item.reject(result.reason) } }) } function schedulePasteFetchRelease() { if (activePasteFetches > 0 || pasteFetchPendingQueue.length > 0) return if (pasteFetchReleaseTimer) { window.clearTimeout(pasteFetchReleaseTimer) } pasteFetchReleaseTimer = window.setTimeout(() => { releasePasteFetchSession() }, pasteFetchIdleReleaseDelay) } function processPasteFetchQueue(originalFetch: typeof fetch) { pasteFetchCollectTimer = undefined while (activePasteFetches < pasteFetchConcurrency && pasteFetchPendingQueue.length > 0) { const item = pasteFetchPendingQueue.shift() if (!item) continue activePasteFetches += 1 fetchWithRetry(originalFetch, item.proxiedURL, item.init) .then((response) => { item.result = { status: 'fulfilled', value: response, } }) .catch((reason: unknown) => { item.result = { reason, status: 'rejected', } }) .finally(() => { activePasteFetches -= 1 processPasteFetchQueue(originalFetch) schedulePasteFetchRelease() }) } schedulePasteFetchRelease() } function enqueuePasteFetch(originalFetch: typeof fetch, proxiedURL: string, init?: RequestInit) { return new Promise((resolve, reject) => { if (pasteFetchReleaseTimer) { window.clearTimeout(pasteFetchReleaseTimer) pasteFetchReleaseTimer = undefined } const source = pasteFetchSession.find((pendingItem) => { return !pendingItem.source && pendingItem.proxiedURL === proxiedURL }) const item: QueuedPasteFetch = { init, proxiedURL, reject, resolve, source, } pasteFetchSession.push(item) if (source) { schedulePasteFetchRelease() return } pasteFetchPendingQueue.push(item) if (pasteFetchCollectTimer) { window.clearTimeout(pasteFetchCollectTimer) } pasteFetchCollectTimer = window.setTimeout(() => { processPasteFetchQueue(originalFetch) }, pasteFetchCollectDelay) }) } export function EversoloPasteURLFetchProvider({ children }: { children?: React.ReactNode }) { useEffect(() => { const patchedWindow = window as PatchedWindow if (patchedWindow.__eversoloPasteURLFetchPatchVersion === pasteFetchPatchVersion) return const originalFetch = window.fetch.bind(window) patchedWindow.__eversoloPasteURLFetchPatchVersion = pasteFetchPatchVersion window.fetch = (input, init) => { const proxiedPasteURL = getProxiedPasteURL(input, init) if (proxiedPasteURL) { return enqueuePasteFetch(originalFetch, proxiedPasteURL, init) } return originalFetch(input, init) } }, []) return children }