1<!doctype html> 2<html lang="en"> 3 <head> 4 <meta charset="UTF-8" /> 5 <link rel="icon" href="/_genesis/assets/favicon" /> 6 <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 7 <title>Enter Travel Planner - The App</title> 8 9
9<script> 10 // Pre-React error catch-all. Handles two scenarios: 11 // 1. React never mounts (syntax error, import crash) â spinner is still in #root 12 // 2. React mounted, crashed without ErrorBoundary, and unmounted â #root is empty 13 (function() { 14 var esc = function(s) { return String(s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>'); }; 15 var errorHtml = function(msg) { 16 return '<div style="position:fixed;inset:0;background:#000;padding:2rem;font-family:system-ui,sans-serif;color:#fff;overflow:auto">' + 17 '<div style="max-width:600px;margin:0 auto">' + 18 '<h2 style="margin:0 0 0.5rem;font-size:1.25rem">Something went wrong</h2>' + 19 '<p style="color:#999;margin:0 0 1rem;font-size:0.95rem">The app failed to load. Try refreshing the page.</p>' + 20 '<pre style="background:#1a1a1a;padding:1rem;border-radius:8px;overflow:auto;font-size:0.8rem;color:#f87171;margin:0;white-space:pre-wrap;word-break:break-word">' + 21 esc(msg) + '</pre></div></div>'; 22 }; 23 var reported = false; 24 function reportError(code, msg, stack) { 25 if (reported) return; 26 reported = true; 27 try { 28 var logger = window.__TASKADE_APP_LIFECYCLE_LOGGER__; 29 if (typeof logger?.log === 'function') { logger.log({ level: 'error', message: 'Runtime Error', data: { code: code, message: msg, stack: stack || '' } }); } 30 } catch (e) { /* Swallow â never block the fallback error UI */ } 31 } 32 function showError(code, msg, stack) { 33 reportError(code, msg, stack); 34 var root = document.getElementById('root'); 35 if (!root) return; 36 var spinner = root.querySelector('.genesis__spinner-container'); 37 if (spinner) { 38 // Scenario 1: React never mounted â replace spinner 39 spinner.outerHTML = errorHtml(msg); 40 } else if (!root.childElementCount) { 41 // Scenario 2: React crashed and unmounted â #root is empty 42 root.innerHTML = errorHtml(msg); 43 } 44 // Otherwise React is running fine â don't interfere 45 } 46 window.addEventListener('error', function(e) { 47 var msg = e.message || String(e.error) || 'Unknown error'; 48 var stack = e.error && e.error.stack ? e.error.stack : (e.filename ? e.filename + ':' + e.lineno + ':' + e.colno : ''); 49 showError('error.runtime_error', msg, stack); 50 }); 51 window.addEventListener('unhandledrejection', function(e) { 52 var msg = e.reason ? String(e.reason) : 'Unhandled promise rejection'; 53 var stack = e.reason && e.reason.stack ? e.reason.stack : ''; 54 showError('error.unhandled_promise', msg, stack); 55 }); 56 })(); 57 </script>
57 58 <style> 59 /* Genesis spinner styles */ 60 .genesis__spinner-container { 61 position: fixed; 62 inset: 0; 63 background: #000000; 64 display: flex; 65 align-items: center; 66 justify-content: center; 67 z-index: 9999; 68 } 69 70 .genesis__spinner-ring { 71 width: 20px; 72 height: 20px; 73 border: 1.5px solid transparent; 74 border-top: 1.5px solid rgba(255, 255, 255, 0.6); 75 border-radius: 50%; 76 animation: genesis__spin 1s linear infinite; 77 } 78 79 @keyframes genesis__spin { 80 0% { transform: rotate(0deg); } 81 100% { transform: rotate(360deg); } 82 } 83 84 /* Respect reduced motion preferences */ 85 @media (prefers-reduced-motion: reduce) { 86 .genesis__spinner-ring { 87 animation: none; 88 border-top-color: rgba(255, 255, 255, 0.9); 89 } 90 } 91 </style> 92
92<script type="module" src="/assets/main-3ASXOLRQ.js"></script>
92 93<link rel="stylesheet" href="/assets/main-EYRHGIOQ.css" /> 94 <meta charset="utf-8" /><meta name="language" content="en-US" /><meta name="robots" content="noindex,nofollow" /><meta name="author" content="Enter Travel Planner" /><link rel="icon" sizes="32x32" href="/_genesis/assets/favicon" /><link rel="apple-touch-icon" sizes="180x180" href="/_genesis/assets/favicon" /><meta name="theme-color" content="" media="(prefers-color-scheme: light)" /><meta name="theme-color" content="" media="(prefers-color-scheme: dark)" /><meta name="title" content="Enter Travel Planner - The App" /><meta property="og:title" content="Enter Travel Planner - The App" /><meta name="twitter:title" content="Enter Travel Planner - The App" /><meta name="description" content="Software para para el gerenciamiento de una Agencia de Viajes receptiva." /><meta property="og:description" content="Software para para el gerenciamiento de una Agencia de Viajes receptiva." /><meta name="twitter:description" content="Software para para el gerenciamiento de una Agencia de Viajes receptiva." /><meta property="og:type" content="website" /><meta property="og:url" content="https://crea-una-app-como-esta-httpsgcogeminishare1d35119d6029-y6xec3vt.taskade.app" /><meta property="og:site_name" content="Enter Travel Planner" /><meta property="og:image" content="https://crea-una-app-como-esta-httpsgcogeminishare1d35119d6029-y6xec3vt.taskade.app/_internal/screenshot" /><meta property="og:image:alt" content="Enter Travel Planner - The App - Software para para el gerenciamiento de una Agencia de Viajes receptiva...." /><meta property="og:locale" content="en_US" /><meta name="twitter:card" content="summary_large_image" /><meta name="twitter:site" content="@ddddd" /><meta name="twitter:creator" content="@ddddd" /><meta name="twitter:image" content="https://crea-una-app-como-esta-httpsgcogeminishare1d35119d6029-y6xec3vt.taskade.app/_internal/screenshot" /><meta name="twitter:image:alt" content="Enter Travel Planner - The App - Software para para el gerenciamiento de una Agencia de Viajes receptiva...." /><meta name="format-detection" content="telephone=no" /><meta name="mobile-web-app-capable" content="yes" /><meta name="apple-mobile-web-app-capable" content="yes" /><meta name="apple-mobile-web-app-status-bar-style" content="default" /><meta name="apple-mobile-web-app-title" content="Enter Travel Planner - The App" /><meta name="application-name" content="Enter Travel Planner" /><link rel="canonical" href="https://crea-una-app-como-esta-httpsgcogeminishare1d35119d6029-y6xec3vt.taskade.app" />
94<script type="application/ld+json"> 95 { 96 "@context": "https://schema.org", 97 "@type": "WebSite", 98 "name": "Enter Travel Planner", 99 "alternateName": "Enter Travel Planner - The App", 100 "description": "Software para para el gerenciamiento de una Agencia de Viajes receptiva.", 101 "image": "https://crea-una-app-como-esta-httpsgcogeminishare1d35119d6029-y6xec3vt.taskade.app/_internal/screenshot", 102 "url": "https://crea-una-app-como-esta-httpsgcogeminishare1d35119d6029-y6xec3vt.taskade.app", 103 "author": { 104 "@type": "Organization", 105 "name": "Enter Travel Planner" 106 }, 107 "publisher": { 108 "@type": "Organization", 109 "name": "Enter Travel Planner", 110 "url": "https://crea-una-app-como-esta-httpsgcogeminishare1d35119d6029-y6xec3vt.taskade.app", 111 "logo": { 112 "@type": "ImageObject", 113 "url": "https://crea-una-app-como-esta-httpsgcogeminishare1d35119d6029-y6xec3vt.taskade.app/_internal/screenshot" 114 } 115 } 116 } 117</script>
117<script defer src="/_genesis/vendor/flock.min.js" data-proxy-url="/_genesis/api/events" data-tenant-id="luy6vta3ms0kubw4:default" data-domain="crea-una-app-como-esta-httpsgcogeminishare1d35119d6029-y6xec3vt.taskade.app"></script>
117<script defer src="/_genesis/vendor/scroll-guard.js"></script>
117</head> 118 <body>
118<script> 119 (function() { 120 if (window.__genesisErrorCatchAll) return; 121 window.__genesisErrorCatchAll = true; 122 var esc = function(s) { return String(s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>'); }; 123 var errorHtml = function(msg, id) { 124 return '<div style="position:fixed;inset:0;background:#000;padding:2rem;font-family:system-ui,sans-serif;color:#fff;overflow:auto">' + 125 '<div style="max-width:600px;margin:0 auto">' + 126 '<h2 style="margin:0 0 0.5rem;font-size:1.25rem">Something went wrong</h2>' + 127 '<p style="color:#999;margin:0 0 1rem;font-size:0.95rem">The app failed to load. Try refreshing the page.</p>' + 128 '<pre style="background:#1a1a1a;padding:1rem;border-radius:8px;overflow:auto;font-size:0.8rem;color:#f87171;margin:0;white-space:pre-wrap;word-break:break-word">' + 129 esc(msg) + '<\/pre>' + 130 '<p style="color:#666;margin:1rem 0 0;font-size:0.75rem">Error ID: <code>' + esc(id) + '<\/code><\/p>' + 131 '<\/div><\/div>'; 132 }; 133 var reported = false; 134 var errorId = null; 135 function getErrorId() { 136 if (errorId != null) return errorId; 137 try { 138 if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') { errorId = crypto.randomUUID().replace(/-/g, ''); return errorId; } 139 } catch (e) { /* Fall through to the time+random id below */ } 140 errorId = Date.now().toString(36) + Math.random().toString(36).slice(2, 12); 141 return errorId; 142 } 143 function reportError(code, msg, stack) { 144 if (reported) return; 145 reported = true; 146 try { 147 var logger = window.__TASKADE_APP_LIFECYCLE_LOGGER__; 148 if (typeof logger?.log === 'function') { 149 logger.log({ level: 'error', message: 'Runtime Error', data: { code: code, message: msg, stack: stack || '' } }); 150 return; 151 } 152 // Published: no logger, so beacon to the Taskade gateway instead of 153 // dropping the crash on the floor (#27626). Relative path â the 154 // Director proxy injects the gateway token server-side. Once per page 155 // session (the latch above) so a crash loop cannot flood the sink. 156 fetch('/api/taskade/telemetry/errors', { 157 method: 'POST', 158 headers: { 'Content-Type': 'application/json' }, 159 body: JSON.stringify({ 160 errorId: getErrorId(), 161 code: code, 162 message: String(msg || 'Unknown error').slice(0, 4000), 163 stack: String(stack || '').slice(0, 20000), 164 path: location.pathname.slice(0, 1000),
165 userAgent: navigator.userAgent.slice(0, 512) 166 }), 167 keepalive: true 168 // Default same-origin credentials: a password-protected app gates 169 // /api/taskade/* on its signed access cookie, so omitting them 170 // would redirect the beacon to the password page. 171 }).catch(function() {}); 172 } catch (e) { /* Swallow â never block the fallback error UI */ } 173 } 174 function showError(code, msg, stack) { 175 var root = document.getElementById('root'); 176 if (!root) return; 177 var spinner = root.querySelector('.genesis__spinner-container'); 178 if (spinner) { 179 // Scenario 1: React never mounted â replace spinner 180 reportError('error.fatal', msg, stack); 181 spinner.outerHTML = errorHtml(msg, getErrorId()); 182 } else if (!root.childElementCount) { 183 // Scenario 2: React crashed and unmounted â #root is empty 184 reportError('error.fatal', msg, stack); 185 root.innerHTML = errorHtml(msg, getErrorId()); 186 } else { 187 // React is running fine â don't interfere with the DOM, 188 // but still report with the original code for diagnostics 189 reportError(code, msg, stack); 190 } 191 } 192 window.addEventListener('error', function(e) { 193 var msg = e.message || String(e.error) || 'Unknown error'; 194 var stack = e.error && e.error.stack ? e.error.stack : (e.filename ? e.filename + ':' + e.lineno + ':' + e.colno : ''); 195 showError('error.runtime_error', msg, stack); 196 }); 197 window.addEventListener('unhandledrejection', function(e) { 198 var msg = e.reason ? String(e.reason) : 'Unhandled promise rejection'; 199 var stack = e.reason && e.reason.stack ? e.reason.stack : ''; 200 showError('error.unhandled_promise', msg, stack); 201 }); 202 // A dead <img> degrades to a neutral placeholder instead of painting its 203 // raw alt string across the page (#27730) â the symptom half of the 204 // fabricated-hot-link fix, and the only half that helps an ALREADY 205 // published app, whose images can rot long after generation. 206 // 207 // Resource load errors do not bubble, so they reach window only in the 208 // CAPTURE phase. That is why neither handler above has ever seen one, and 209 // why this cannot disturb them: a broken image must never render the fatal 210 // error overlay or spend the once-per-session crash beacon. 211 // 212 // Swapping in a 1x1 transparent GIF is what actually stops the alt text â 213 // the element becomes a SUCCESSFUL load, so the browser has no broken image 214 // to caption, while the alt attribute stays for assistive tech. Layout is 215 // untouched: the app's own width/height/aspect classes still apply. The grey 216 // is translucent so it reads correctly on a light or a dark surface without 217 // this script having to know the app's theme. 218 var deadImagePixel = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'; 219 window.addEventListener('error', function(e) { 220 var el = e.target; 221 if (!el || el.tagName !== 'IMG') return; 222 // The swap fires a fresh load on the same element, so the latch is what 223 // keeps a failing data URI from looping. 224 if (el.getAttribute('data-genesis-image-fallback') !== null) return; 225 el.setAttribute('data-genesis-image-fallback', ''); 226 el.removeAttribute('srcset'); 227 el.src = deadImagePixel; 228 el.style.background = 'linear-gradient(135deg, rgba(127,127,127,0.16), rgba(127,127,127,0.28))'; 229 }, true); 230 231 // --------------------------------------------------------------- 232 // Dead env reads (advisory, NOT a failure) 233 // --------------------------------------------------------------- 234 // The bundle's import.meta.env / process.env shims are reporting 235 // Proxies (see genesisEnvBanner.ts). They are value-preserving: a 236 // missing key still reads undefined. This turns that read from invisible 237 // into observable, because a feature gated on one is permanently off and 238 // has no other symptom â the app builds, boots and looks healthy. 239 // 240 // Deliberately WARN, never error. The runtime cannot see whether a call 241 // site has a working fallback, so a correct 242 // VITE_API_BASE_URL || 'https://real' is reported too. Warn keeps it
243 // out of the "Fix with AI" popup set and out of FATAL_LIFECYCLE_CODES, 244 // both of which are error-level allowlists. 245 var deadEnvSeen = {}; 246 var deadEnvSent = 0; 247 // Its OWN budget and latch: sharing the 'reported' latch above would let 248 // an advisory notice spend the one crash report this page session gets. 249 var DEAD_ENV_MAX = 5; 250 function reportDeadEnv(source, key) { 251 try { 252 var signature = source + '.' + key; 253 if (deadEnvSeen[signature] || deadEnvSent >= DEAD_ENV_MAX) return; 254 deadEnvSeen[signature] = 1; 255 deadEnvSent++; 256 var msg = signature + ' is read but a Genesis build never defines it, so the value is ' + 257 'always undefined. If it gates a feature, that feature is permanently off. Route ' + 258 'secret-bearing calls through GenesisClient.proxy() with a secretAlias instead.'; 259 var logger = window.__TASKADE_APP_LIFECYCLE_LOGGER__; 260 if (typeof logger?.log === 'function') { 261 logger.log({ level: 'warn', message: 'Dead env read', data: { code: 'warn.dead_env', message: msg } }); 262 return; 263 } 264 fetch('/api/taskade/telemetry/errors', { 265 method: 'POST', 266 headers: { 267 'Content-Type': 'application/json', 268 // Lets the publish Worker pick the advisory rate-limit bucket 269 // without reading this body. Doing that at the edge means I/O 270 // of unbounded duration ahead of the limiter meant to bound it, 271 // which is the whole class of problem the header avoids. The 272 // origin still classifies from the validated body, so this is a 273 // bucket hint and never the record (#29164). 274 'X-Genesis-Telemetry-Code': 'warn.dead_env' 275 }, 276 body: JSON.stringify({ 277 errorId: 'de' + Date.now().toString(36) + Math.random().toString(36).slice(2, 8), 278 code: 'warn.dead_env', 279 message: msg.slice(0, 4000), 280 path: location.pathname.slice(0, 1000), 281 // The source and key as STRUCTURE, not only inside the prose. 282 // The gateway fingerprints on app + code alone, because this 283 // endpoint's token ships in the bundle and free text from it 284 // cannot be trusted; these two validated fields are how the 285 // key still reaches Sentry, as a tag. 286 // Sliced to the schema's bound like every other field here: the 287 // banner filters the key's SHAPE but not its length, and an 288 // over-long key would fail validation and lose the whole 289 // report rather than just the tag. 290 envSource: source, 291 envKey: String(key).slice(0, 64) 292 }), 293 keepalive: true 294 }).catch(function() {}); 295 } catch (e) { /* Swallow â advisory telemetry must never break an app */ } 296 } 297 window.__genesisReportDeadEnv = reportDeadEnv; 298 // Drain anything the bundle's banner queued. This script is a classic 299 // inline script and the bundle is a deferred module, so in practice the 300 // reporter wins the race; the queue is what makes that not a matter of 301 // luck (and covers an app whose HTML predates this script). 302 try { 303 var queued = window.__genesisDeadEnvQueue; 304 if (queued) { 305 window.__genesisDeadEnvQueue = []; 306 for (var qi = 0; qi < queued.length; qi++) reportDeadEnv(queued[qi][0], queued[qi][1]); 307 } 308 } catch (e) { /* Ignore. */ } 309 })(); 310</script>
310 311 <div id="root"> 312 <div class="genesis__spinner-container"> 313 <div class="genesis__spinner-ring"></div> 314 </div> 315 </div> 316
316<script type="module" src="https://static.cloudflareinsights.com/beacon.min.js/v31edd6df95cf4e85bb4c19e7a9bdbcba1788362987495" integrity="sha512-iIg7k2xntmwu6/uSb5tpc/hySgZc4eoL31yB29W6tJFo2akwjPWcEqnCEdJvGexCL0KEQwVYv5BlowfhVz26hg==" data-cf-beacon='{"version":"2024.11.0","token":"8d4254f20c524f6fbf6ecde0b2c89fb4","spa":2}' crossorigin="anonymous"></script>
316 317</body> 318</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.