1<!doctype html> 2<html lang="en"> 3 <head> 4 <meta charset="UTF-8" /> 5 <link rel="icon" type="image/svg+xml" href="/vite.svg" /> 6 <meta name="generator" content="Hostinger Horizons" /> 7 <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 8 <title></title> 9
9<script type="module" crossorigin src="/assets/index-BUOT8SZj.js"></script>
9 10 <link rel="stylesheet" crossorigin href="/assets/index-DOLzdebM.css"> 11
11<script type="module"> 12window.onerror = (message, source, lineno, colno, errorObj) => { 13 const errorDetails = errorObj ? JSON.stringify({ 14 name: errorObj.name, 15 message: errorObj.message, 16 stack: errorObj.stack, 17 source, 18 lineno, 19 colno, 20 }) : null; 21 22 window.parent.postMessage({ 23 type: 'horizons-runtime-error', 24 message, 25 error: errorDetails 26 }, '*'); 27}; 28</script>
28 29
29<script type="module"> 30const observer = new MutationObserver((mutations) => { 31 for (const mutation of mutations) { 32 for (const addedNode of mutation.addedNodes) { 33 if ( 34 addedNode.nodeType === Node.ELEMENT_NODE && 35 ( 36 addedNode.tagName?.toLowerCase() === 'vite-error-overlay' || 37 addedNode.classList?.contains('backdrop') 38 ) 39 ) { 40 handleViteOverlay(addedNode); 41 } 42 } 43 } 44}); 45 46observer.observe(document.documentElement, { 47 childList: true, 48 subtree: true 49}); 50 51function handleViteOverlay(node) { 52 if (!node.shadowRoot) { 53 return; 54 } 55 56 const backdrop = node.shadowRoot.querySelector('.backdrop'); 57 58 if (backdrop) { 59 const overlayHtml = backdrop.outerHTML; 60 const parser = new DOMParser(); 61 const doc = parser.parseFromString(overlayHtml, 'text/html'); 62 const messageBodyElement = doc.querySelector('.message-body'); 63 const fileElement = doc.querySelector('.file'); 64 const messageText = messageBodyElement ? messageBodyElement.textContent.trim() : ''; 65 const fileText = fileElement ? fileElement.textContent.trim() : ''; 66 const error = messageText + (fileText ? ' File:' + fileText : ''); 67 68 window.parent.postMessage({ 69 type: 'horizons-vite-error', 70 error, 71 }, '*'); 72 } 73} 74</script>
74 75
75<script type="module"> 76const originalConsoleError = console.error; 77const MATCH_LINE_COL_REGEX = /:(\d+):(\d+)\)?\s*$/; // regex to match the :lineNum:colNum 78const MATCH_AT_REGEX = /^\s*at\s+(?:async\s+)?(?:.*?\s+)?\(?/; // regex to remove the 'at' keyword and any 'async' or function name 79const MATCH_PATH_REGEX = /^\//; // regex to remove the leading slash 80 81function parseStackFrameLine(line) { 82 const lineColMatch = line.match(MATCH_LINE_COL_REGEX); 83 if (!lineColMatch) return null; 84 const [, lineNum, colNum] = lineColMatch; 85 const suffix = `:${lineNum}:${colNum}`; 86 const idx = line.lastIndexOf(suffix); 87 if (idx === -1) return null; 88 const before = line.substring(0, idx); 89 const path = before.replace(MATCH_AT_REGEX, '').trim(); 90 91 if (!path) return null; 92 93 try { 94 const pathname = new URL(path).pathname; 95 const filePath = pathname.replace(MATCH_PATH_REGEX, '') || pathname; 96 return `${filePath}:${lineNum}:${colNum}`; 97 } catch (e) { 98 const filePath = path.replace(MATCH_PATH_REGEX, '') || path; 99 return `${filePath}:${lineNum}:${colNum}`; 100 } 101} 102 103function getFilePathFromStack(stack, skipFrames = 0) { 104 if (!stack || typeof stack !== 'string') return null; 105 const lines = stack.split('\n').slice(1); 106 107 const frames = lines.map(line => parseStackFrameLine(line.replace(/\r$/, ''))).filter(Boolean); 108 109 return frames[skipFrames] ?? null; 110} 111 112function formatConsoleMessage(args, skipStackFrames = 1) { 113 let messageString = ''; 114 let filePath = null; 115 116 for (let i = 0; i < args.length; i++) { 117 const arg = args[i]; 118 if (arg instanceof Error) { 119 filePath = getFilePathFromStack(arg.stack, 0); 120 messageString = `${arg.name}: ${arg.message}`; 121 if (filePath) { 122 messageString = `${messageString} at ${filePath}`; 123 } 124 break; 125 } 126 } 127 128 if (!messageString) { 129 messageString = args.map(arg => typeof arg === 'object' ? JSON.stringify(arg) : String(arg)).join(' '); 130 const stack = new Error().stack; 131 filePath = getFilePathFromStack(stack, skipStackFrames); 132 if (filePath) { 133 messageString = `${messageString} at ${filePath}`; 134 } 135 } 136 137 return messageString; 138} 139 140console.error = function(...args) { 141 originalConsoleError.apply(console, args); 142 143 window.parent.postMessage({ 144 type: 'horizons-console-error', 145 error: formatConsoleMessage(args, 1) 146 }, '*'); 147}; 148 149const originalConsoleWarn = console.warn; 150 151console.warn = function(...args) { 152 originalConsoleWarn.apply(console, args); 153 154 window.parent.postMessage({ 155 type: 'horizons-console-warn', 156 warning: formatConsoleMessage(args, 1) 157 }, '*'); 158}; 159</script>
159 160
160<script type="module"> 161// Prevents authentication failures (PB returns 400) from crashing the app â use console.info, not console.error/PM2. 162// [urlPattern, bodyPattern] tuples; align with sandboxErrorUtils ERROR_BLACKLIST. 163const BENIGN_FETCH_ERRORS = [ 164 [/hcgi\/platform\/api\/collections\/.*auth-with-password.*/i, /Failed to authenticate/i], 165 [/hcgi\/api\//i, /Insufficient credits/i], 166]; 167 168function isBenignFetchError(url, body) { 169 return BENIGN_FETCH_ERRORS.some(([urlPattern, bodyPattern]) => 170 urlPattern.test(url) && (!bodyPattern || bodyPattern.test(body))); 171} 172 173const PLATFORM_URL_PATTERN = /hcgi\/platform\//i; 174const VALIDATION_CODE_TEXT_PATTERN = /validation_/; 175 176function hasValidationCode(value) { 177 if (value == null) { 178 return false; 179 } 180 if (typeof value === 'string') { 181 return value.startsWith('validation_'); 182 } 183 if (Array.isArray(value)) { 184 return value.some(hasValidationCode); 185 } 186 if (typeof value === 'object') { 187 return Object.values(value).some(hasValidationCode); 188 } 189 return false; 190} 191 192function isValidationFetchWarning(url, body) { 193 if (!PLATFORM_URL_PATTERN.test(url)) { 194 return false; 195 } 196 try { 197 return hasValidationCode(JSON.parse(body)); 198 } catch { 199 return VALIDATION_CODE_TEXT_PATTERN.test(body); 200 } 201} 202 203const originalFetch = window.fetch; 204 205window.fetch = function(...args) { 206 const url = args[0] instanceof Request ? args[0].url : args[0]; 207 208 // Skip WebSocket URLs 209 if (url.startsWith('ws:') || url.startsWith('wss:')) { 210 return originalFetch.apply(this, args); 211 } 212 213 return originalFetch.apply(this, args) 214 .then(async response => { 215 const contentType = response.headers.get('Content-Type') || ''; 216 217 // Exclude HTML document responses 218 const isDocumentResponse = 219 contentType.includes('text/html') || 220 contentType.includes('application/xhtml+xml'); 221 222 if (!response.ok && !isDocumentResponse) { 223 const responseClone = response.clone(); 224 const errorFromRes = await responseClone.text(); 225 const requestUrl = response.url; 226 const errorMessage = `Fetch error from ${requestUrl}: ${errorFromRes}`; 227 228 if (isBenignFetchError(requestUrl, errorFromRes)) { 229 console.info(errorMessage); 230 } else if (isValidationFetchWarning(requestUrl, errorFromRes)) { 231 console.warn(errorMessage); 232 } else { 233 console.error(errorMessage); 234 } 235 } 236 237 return response; 238 }) 239 .catch(error => { 240 if (!url.match(/.html?$/i)) { 241 // Cancelled in-flight fetch (e.g. preview reload) â not a server failure. 242 if (error?.name === 'AbortError') { 243 console.info(error); 244 } else { 245 console.error(error); 246 } 247 } 248 249 throw error; 250 }); 251}; 252</script>
252 253
253<script type="module"> 254if (window.navigation && window.self !== window.top) { 255 window.navigation.addEventListener('navigate', (event) => { 256 const url = event.destination.url; 257 258 try { 259 const destinationUrl = new URL(url); 260 const destinationOrigin = destinationUrl.origin; 261 const currentOrigin = window.location.origin; 262 263 if (destinationOrigin === currentOrigin) { 264 return; 265 } 266 } catch (error) { 267 return; 268 } 269 270 window.parent.postMessage({ 271 type: 'horizons-navigation-error', 272 url, 273 }, '*'); 274 }); 275} 276</script>
276 277 </head> 278 <body> 279 <div id="root"></div> 280 </body> 281</html>
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.