Loading start.sh +420 −59 Original line number Diff line number Diff line Loading @@ -206,7 +206,7 @@ if ! command -v caddy &> /dev/null; then fi # Set up the API endpoint for the web apps API_ENDPOINT=${CLOUDRON_APP_ORIGIN}/api API_ENDPOINT="${CLOUDRON_APP_ORIGIN}/api" echo "==> Setting API endpoint to $API_ENDPOINT" # Set environment variables for the web apps Loading @@ -216,99 +216,248 @@ export REACT_APP_ENTE_ENDPOINT=$API_ENDPOINT export VUE_APP_ENTE_ENDPOINT=$API_ENDPOINT echo "==> Set environment variables for web apps" # Create a very simple Caddy configuration mkdir -p /app/data/caddy # Create directory for direct modifications mkdir -p /app/data/scripts # Create a script that will directly define the ENTE_CONFIG global in window cat > /app/data/scripts/ente-config.js <<EOT // Direct configuration script - should be loaded before any app code window.ENTE_CONFIG = { API_URL: "${API_ENDPOINT}" }; console.log("Ente config loaded, API_URL =", window.ENTE_CONFIG.API_URL); EOT # Set up Caddy server echo "==> Setting up Caddy server for web apps" mkdir -p /app/data/caddy/public cat > /app/data/caddy/Caddyfile <<EOT { admin off auto_https off log { output file /app/data/caddy/caddy.log format console output file /app/data/caddy/caddy.log { roll_size 10MB roll_keep 10 } } servers { protocols h1 h2c } } :3080 { :8000 { log { output file /app/data/caddy/access.log format console output file /app/data/caddy/access.log { roll_size 10MB roll_keep 10 } } # Add security headers to enable WebAssembly and IndexedDB # Allow WebAssembly and IndexedDB header { # Security headers Strict-Transport-Security "max-age=31536000; includeSubDomains" X-Content-Type-Options "nosniff" X-Frame-Options "SAMEORIGIN" Referrer-Policy "strict-origin-when-cross-origin" # Content Security Policy that allows WebAssembly Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' 'wasm-unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' data:; connect-src 'self' ${CLOUDRON_APP_ORIGIN} https://*.${CLOUDRON_APP_DOMAIN}; worker-src 'self' blob:;" # CORS headers for API access Access-Control-Allow-Origin "*" Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" Access-Control-Allow-Headers "Content-Type, Authorization" Access-Control-Allow-Credentials "true" Cross-Origin-Embedder-Policy "credentialless" Cross-Origin-Opener-Policy "same-origin" Cross-Origin-Resource-Policy "cross-origin" } # Serve config scripts directly handle /config.js { root * /app/data/public file_server } # Serve debug script and page handle /debug.js { root * /app/data/public file_server } # Simple JavaScript file that defines the API endpoint handle /api-config.js { header Content-Type "application/javascript" respond "window.ENTE_CONFIG = { API_URL: '${API_ENDPOINT}' };" 200 handle /debug { root * /app/data/public rewrite * /debug.html file_server } # Photos app - root path # Health check response handle /health { respond "OK" 200 } # Serve our custom config-injected landing pages handle /photos-config { root * /app/data/public rewrite * /photos-config.html file_server } handle /accounts-config { root * /app/data/public rewrite * /accounts-config.html file_server } handle /auth-config { root * /app/data/public rewrite * /auth-config.html file_server } handle /cast-config { root * /app/data/public rewrite * /cast-config.html file_server } # Root handler - serve our custom index.html handle / { root * /app/data/public file_server } # Serve the photos web app with local config support handle /photos* { uri strip_prefix /photos uri replace /photos / root * /app/web/photos try_files {path} /index.html file_server } # Accounts app handle /accounts/* { uri strip_prefix /accounts # Serve the accounts web app handle /accounts* { uri replace /accounts / root * /app/web/accounts try_files {path} /index.html file_server } # Auth app handle /auth/* { uri strip_prefix /auth # Serve the auth web app handle /auth* { uri replace /auth / root * /app/web/auth try_files {path} /index.html file_server } # Cast app handle /cast/* { uri strip_prefix /cast # Serve the cast web app handle /cast* { uri replace /cast / root * /app/web/cast try_files {path} /index.html file_server } # API endpoints - proxy to Museum server handle /api/* { # Proxy API calls to the backend server handle /api* { reverse_proxy localhost:8080 } # Health check endpoint for Cloudron handle /healthcheck { respond "OK" 200 } EOT # Default to photos app handle { root * /app/web/photos try_files {path} /index.html file_server } echo "==> Caddy configuration created at /app/data/caddy/Caddyfile" # Create HTML transformer script to modify all index.html files on load mkdir -p /app/data/scripts cat > /app/data/scripts/insert-config.sh <<EOT #!/bin/bash # This script injects our configuration into all index.html files # List of web app directories WEB_APPS=("/app/web/photos" "/app/web/accounts" "/app/web/auth" "/app/web/cast") for app_dir in "\${WEB_APPS[@]}"; do if [ -f "\$app_dir/index.html" ]; then echo "Processing \$app_dir/index.html" # Create a writable copy cp "\$app_dir/index.html" "/app/data/temp.html" # Insert our config script right before the closing head tag sed -i 's|</head>|<script>window.ENTE_CONFIG = { API_URL: "${API_ENDPOINT}" };</script></head>|' "/app/data/temp.html" # Create a symlink from the modified file to the original # Only if the temp file was created and modified successfully if [ -f "/app/data/temp.html" ]; then mkdir -p "/app/data/transformed/\$(basename \$app_dir)" cp "/app/data/temp.html" "/app/data/transformed/\$(basename \$app_dir)/index.html" fi fi done echo "All index.html files processed" EOT chmod +x /app/data/scripts/insert-config.sh # Run the transformer script to create modified index.html files mkdir -p /app/data/transformed echo "==> Creating modified index.html files with injected configuration" /app/data/scripts/insert-config.sh # Create direct configuration files for different frameworks mkdir -p /app/data/public echo "==> Creating framework-specific configuration files" # Create a Next.js public runtime configuration cat > /app/data/public/env.js <<EOT // Next.js runtime configuration window.ENV = { NEXT_PUBLIC_ENTE_ENDPOINT: "${API_ENDPOINT}" }; window.process = window.process || {}; window.process.env = window.process.env || {}; window.process.env.NEXT_PUBLIC_ENTE_ENDPOINT = "${API_ENDPOINT}"; EOT # Create a simple JSON config cat > /app/data/public/config.json <<EOT { "API_URL": "${API_ENDPOINT}" } EOT echo "==> Caddy configuration created at /app/data/caddy/Caddyfile" # Create additional HTML files with the config directly embedded for app_name in "photos" "accounts" "auth" "cast"; do cat > "/app/data/public/${app_name}-config.html" <<EOT <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Loading ${app_name}</title> <script src="/debug.js"></script> <script> // Set the global configuration window.ENTE_CONFIG = { API_URL: "${API_ENDPOINT}" }; // Set Next.js environment variables window.process = window.process || {}; window.process.env = window.process.env || {}; window.process.env.NEXT_PUBLIC_ENTE_ENDPOINT = "${API_ENDPOINT}"; // Store in localStorage as a fallback mechanism localStorage.setItem('ENTE_CONFIG', JSON.stringify(window.ENTE_CONFIG)); localStorage.setItem('NEXT_PUBLIC_ENTE_ENDPOINT', "${API_ENDPOINT}"); // Log the configuration console.log("Ente ${app_name} config loaded:", window.ENTE_CONFIG); // Redirect to the main app after a brief delay setTimeout(function() { window.location.href = "/${app_name}/"; }, 100); </script> </head> <body> <h1>Loading ${app_name}...</h1> <p>If you are not redirected automatically, <a href="/${app_name}/">click here</a>.</p> <p><a href="/debug">Debug Information</a></p> </body> </html> EOT done echo "==> Created app-specific config loading pages with debug info" # Looking for Museum (Go server component) echo "==> Looking for Museum (Go server component)" Loading Loading @@ -813,3 +962,215 @@ echo "==> Caddy: PID $CADDY_PID" # Wait for child processes to exit wait $SERVER_PID wait $CADDY_PID # Create a special root index.html that loads the config and redirects cat > /app/data/public/index.html <<EOT <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Ente</title> <script src="/debug.js"></script> <script> // Define configuration globally window.ENTE_CONFIG = { API_URL: "${API_ENDPOINT}" }; // Set environment variables for Next.js apps window.process = window.process || {}; window.process.env = window.process.env || {}; window.process.env.NEXT_PUBLIC_ENTE_ENDPOINT = "${API_ENDPOINT}"; // Store in localStorage as a fallback mechanism localStorage.setItem('ENTE_CONFIG', JSON.stringify(window.ENTE_CONFIG)); localStorage.setItem('NEXT_PUBLIC_ENTE_ENDPOINT', "${API_ENDPOINT}"); // Redirect to photos app after a small delay to let the configuration load setTimeout(function() { window.location.href = "/photos/"; }, 100); </script> </head> <body> <h1>Loading Ente...</h1> <p>You will be redirected automatically.</p> <p><a href="/debug">Debug Information</a></p> </body> </html> EOT echo "==> Created special root index.html with configuration" # Create debug script for frontend mkdir -p /app/data/public mkdir -p /app/data/debug echo "==> Creating debug scripts" cat > /app/data/public/debug.js <<EOT // Debugging script for Ente (function() { console.log("Debug script loaded"); // Intercept URL constructor const originalURL = window.URL; window.URL = function(url, base) { console.log("URL constructor called with:", url, base); try { return new originalURL(url, base); } catch (e) { console.error("URL construction failed:", e.message); console.error("URL:", url); console.error("Base:", base); console.error("Stack:", e.stack); // Try to fix common issues if (url && !url.startsWith("http") && !url.startsWith("/")) { console.log("Attempting to fix relative URL by adding leading slash"); return new originalURL("/" + url, base); } throw e; } }; // Create debug overlay const debugDiv = document.createElement('div'); debugDiv.style.position = 'fixed'; debugDiv.style.bottom = '10px'; debugDiv.style.right = '10px'; debugDiv.style.backgroundColor = 'rgba(0,0,0,0.7)'; debugDiv.style.color = 'white'; debugDiv.style.padding = '10px'; debugDiv.style.borderRadius = '5px'; debugDiv.style.zIndex = '9999'; debugDiv.style.maxWidth = '400px'; debugDiv.style.maxHeight = '200px'; debugDiv.style.overflow = 'auto'; debugDiv.innerHTML = '<h3>Ente Debug Info</h3>'; // Add configuration info const configInfo = document.createElement('div'); configInfo.innerHTML = 'ENTE_CONFIG: ' + JSON.stringify(window.ENTE_CONFIG || {}) + '<br>' + 'process.env.NEXT_PUBLIC_ENTE_ENDPOINT: ' + (window.process?.env?.NEXT_PUBLIC_ENTE_ENDPOINT || 'undefined') + '<br>' + 'localStorage ENTE_CONFIG: ' + localStorage.getItem('ENTE_CONFIG') + '<br>' + 'localStorage NEXT_PUBLIC_ENTE_ENDPOINT: ' + localStorage.getItem('NEXT_PUBLIC_ENTE_ENDPOINT'); debugDiv.appendChild(configInfo); // Add toggle button const toggleButton = document.createElement('button'); toggleButton.innerText = 'Toggle Debug Info'; toggleButton.style.marginTop = '10px'; toggleButton.onclick = function() { configInfo.style.display = configInfo.style.display === 'none' ? 'block' : 'none'; }; debugDiv.appendChild(toggleButton); // Add to document when it's ready if (document.body) { document.body.appendChild(debugDiv); } else { window.addEventListener('DOMContentLoaded', function() { document.body.appendChild(debugDiv); }); } })(); EOT # Create debug info script that prints environment info cat > /app/data/debug/debug_env.js <<EOT #!/usr/bin/env node console.log('=== Ente Environment Debug ==='); console.log('CLOUDRON_APP_ORIGIN:', process.env.CLOUDRON_APP_ORIGIN); console.log('API_ENDPOINT:', process.env.API_ENDPOINT); console.log('NEXT_PUBLIC_ENTE_ENDPOINT:', process.env.NEXT_PUBLIC_ENTE_ENDPOINT); console.log('HOSTNAME:', process.env.HOSTNAME); console.log('==============================='); EOT chmod +x /app/data/debug/debug_env.js # Create debug info HTML cat > /app/data/public/debug.html <<EOT <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Ente Debug Info</title> <style> body { font-family: Arial, sans-serif; margin: 20px; } .debug-section { margin-bottom: 20px; padding: 10px; border: 1px solid #ccc; } h1 { color: #333; } pre { background-color: #f5f5f5; padding: 10px; border-radius: 5px; overflow-x: auto; } </style> </head> <body> <h1>Ente Debug Information</h1> <div class="debug-section"> <h2>Frontend Configuration</h2> <pre id="config-info">Loading...</pre> </div> <div class="debug-section"> <h2>URL Test</h2> <p>Testing URL construction with API endpoint:</p> <pre id="url-test">Running test...</pre> </div> <div class="debug-section"> <h2>API Health Check</h2> <pre id="api-health">Checking API health...</pre> </div> <script> // Define configuration globally window.ENTE_CONFIG = { API_URL: "${CLOUDRON_APP_ORIGIN}/api" }; // Set environment variables for Next.js apps window.process = window.process || {}; window.process.env = window.process.env || {}; window.process.env.NEXT_PUBLIC_ENTE_ENDPOINT = "${CLOUDRON_APP_ORIGIN}/api"; // Store in localStorage localStorage.setItem('ENTE_CONFIG', JSON.stringify(window.ENTE_CONFIG)); localStorage.setItem('NEXT_PUBLIC_ENTE_ENDPOINT', "${CLOUDRON_APP_ORIGIN}/api"); // Display configuration document.getElementById('config-info').textContent = 'window.ENTE_CONFIG = ' + JSON.stringify(window.ENTE_CONFIG, null, 2) + '\n' + 'window.process.env.NEXT_PUBLIC_ENTE_ENDPOINT = ' + window.process.env.NEXT_PUBLIC_ENTE_ENDPOINT + '\n' + 'localStorage[\'ENTE_CONFIG\'] = ' + localStorage.getItem('ENTE_CONFIG') + '\n' + 'localStorage[\'NEXT_PUBLIC_ENTE_ENDPOINT\'] = ' + localStorage.getItem('NEXT_PUBLIC_ENTE_ENDPOINT'); // Test URL construction try { const apiUrl = window.ENTE_CONFIG.API_URL; const testUrl = new URL('/users/ott', apiUrl); document.getElementById('url-test').textContent = 'API URL: ' + apiUrl + '\n' + 'Test URL (/users/ott): ' + testUrl.toString() + '\n' + 'Result: SUCCESS'; } catch (e) { document.getElementById('url-test').textContent = 'Error: ' + e.message + '\n' + 'Stack: ' + e.stack; } // Test API health fetch('/api/health') .then(response => { if (response.ok) return response.text(); throw new Error('API returned status: ' + response.status); }) .then(data => { document.getElementById('api-health').textContent = 'API health check: OK\nResponse: ' + data; }) .catch(err => { document.getElementById('api-health').textContent = 'API health check failed: ' + err.message; }); </script> </body> </html> EOT No newline at end of file Loading
start.sh +420 −59 Original line number Diff line number Diff line Loading @@ -206,7 +206,7 @@ if ! command -v caddy &> /dev/null; then fi # Set up the API endpoint for the web apps API_ENDPOINT=${CLOUDRON_APP_ORIGIN}/api API_ENDPOINT="${CLOUDRON_APP_ORIGIN}/api" echo "==> Setting API endpoint to $API_ENDPOINT" # Set environment variables for the web apps Loading @@ -216,99 +216,248 @@ export REACT_APP_ENTE_ENDPOINT=$API_ENDPOINT export VUE_APP_ENTE_ENDPOINT=$API_ENDPOINT echo "==> Set environment variables for web apps" # Create a very simple Caddy configuration mkdir -p /app/data/caddy # Create directory for direct modifications mkdir -p /app/data/scripts # Create a script that will directly define the ENTE_CONFIG global in window cat > /app/data/scripts/ente-config.js <<EOT // Direct configuration script - should be loaded before any app code window.ENTE_CONFIG = { API_URL: "${API_ENDPOINT}" }; console.log("Ente config loaded, API_URL =", window.ENTE_CONFIG.API_URL); EOT # Set up Caddy server echo "==> Setting up Caddy server for web apps" mkdir -p /app/data/caddy/public cat > /app/data/caddy/Caddyfile <<EOT { admin off auto_https off log { output file /app/data/caddy/caddy.log format console output file /app/data/caddy/caddy.log { roll_size 10MB roll_keep 10 } } servers { protocols h1 h2c } } :3080 { :8000 { log { output file /app/data/caddy/access.log format console output file /app/data/caddy/access.log { roll_size 10MB roll_keep 10 } } # Add security headers to enable WebAssembly and IndexedDB # Allow WebAssembly and IndexedDB header { # Security headers Strict-Transport-Security "max-age=31536000; includeSubDomains" X-Content-Type-Options "nosniff" X-Frame-Options "SAMEORIGIN" Referrer-Policy "strict-origin-when-cross-origin" # Content Security Policy that allows WebAssembly Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' 'wasm-unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' data:; connect-src 'self' ${CLOUDRON_APP_ORIGIN} https://*.${CLOUDRON_APP_DOMAIN}; worker-src 'self' blob:;" # CORS headers for API access Access-Control-Allow-Origin "*" Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" Access-Control-Allow-Headers "Content-Type, Authorization" Access-Control-Allow-Credentials "true" Cross-Origin-Embedder-Policy "credentialless" Cross-Origin-Opener-Policy "same-origin" Cross-Origin-Resource-Policy "cross-origin" } # Serve config scripts directly handle /config.js { root * /app/data/public file_server } # Serve debug script and page handle /debug.js { root * /app/data/public file_server } # Simple JavaScript file that defines the API endpoint handle /api-config.js { header Content-Type "application/javascript" respond "window.ENTE_CONFIG = { API_URL: '${API_ENDPOINT}' };" 200 handle /debug { root * /app/data/public rewrite * /debug.html file_server } # Photos app - root path # Health check response handle /health { respond "OK" 200 } # Serve our custom config-injected landing pages handle /photos-config { root * /app/data/public rewrite * /photos-config.html file_server } handle /accounts-config { root * /app/data/public rewrite * /accounts-config.html file_server } handle /auth-config { root * /app/data/public rewrite * /auth-config.html file_server } handle /cast-config { root * /app/data/public rewrite * /cast-config.html file_server } # Root handler - serve our custom index.html handle / { root * /app/data/public file_server } # Serve the photos web app with local config support handle /photos* { uri strip_prefix /photos uri replace /photos / root * /app/web/photos try_files {path} /index.html file_server } # Accounts app handle /accounts/* { uri strip_prefix /accounts # Serve the accounts web app handle /accounts* { uri replace /accounts / root * /app/web/accounts try_files {path} /index.html file_server } # Auth app handle /auth/* { uri strip_prefix /auth # Serve the auth web app handle /auth* { uri replace /auth / root * /app/web/auth try_files {path} /index.html file_server } # Cast app handle /cast/* { uri strip_prefix /cast # Serve the cast web app handle /cast* { uri replace /cast / root * /app/web/cast try_files {path} /index.html file_server } # API endpoints - proxy to Museum server handle /api/* { # Proxy API calls to the backend server handle /api* { reverse_proxy localhost:8080 } # Health check endpoint for Cloudron handle /healthcheck { respond "OK" 200 } EOT # Default to photos app handle { root * /app/web/photos try_files {path} /index.html file_server } echo "==> Caddy configuration created at /app/data/caddy/Caddyfile" # Create HTML transformer script to modify all index.html files on load mkdir -p /app/data/scripts cat > /app/data/scripts/insert-config.sh <<EOT #!/bin/bash # This script injects our configuration into all index.html files # List of web app directories WEB_APPS=("/app/web/photos" "/app/web/accounts" "/app/web/auth" "/app/web/cast") for app_dir in "\${WEB_APPS[@]}"; do if [ -f "\$app_dir/index.html" ]; then echo "Processing \$app_dir/index.html" # Create a writable copy cp "\$app_dir/index.html" "/app/data/temp.html" # Insert our config script right before the closing head tag sed -i 's|</head>|<script>window.ENTE_CONFIG = { API_URL: "${API_ENDPOINT}" };</script></head>|' "/app/data/temp.html" # Create a symlink from the modified file to the original # Only if the temp file was created and modified successfully if [ -f "/app/data/temp.html" ]; then mkdir -p "/app/data/transformed/\$(basename \$app_dir)" cp "/app/data/temp.html" "/app/data/transformed/\$(basename \$app_dir)/index.html" fi fi done echo "All index.html files processed" EOT chmod +x /app/data/scripts/insert-config.sh # Run the transformer script to create modified index.html files mkdir -p /app/data/transformed echo "==> Creating modified index.html files with injected configuration" /app/data/scripts/insert-config.sh # Create direct configuration files for different frameworks mkdir -p /app/data/public echo "==> Creating framework-specific configuration files" # Create a Next.js public runtime configuration cat > /app/data/public/env.js <<EOT // Next.js runtime configuration window.ENV = { NEXT_PUBLIC_ENTE_ENDPOINT: "${API_ENDPOINT}" }; window.process = window.process || {}; window.process.env = window.process.env || {}; window.process.env.NEXT_PUBLIC_ENTE_ENDPOINT = "${API_ENDPOINT}"; EOT # Create a simple JSON config cat > /app/data/public/config.json <<EOT { "API_URL": "${API_ENDPOINT}" } EOT echo "==> Caddy configuration created at /app/data/caddy/Caddyfile" # Create additional HTML files with the config directly embedded for app_name in "photos" "accounts" "auth" "cast"; do cat > "/app/data/public/${app_name}-config.html" <<EOT <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Loading ${app_name}</title> <script src="/debug.js"></script> <script> // Set the global configuration window.ENTE_CONFIG = { API_URL: "${API_ENDPOINT}" }; // Set Next.js environment variables window.process = window.process || {}; window.process.env = window.process.env || {}; window.process.env.NEXT_PUBLIC_ENTE_ENDPOINT = "${API_ENDPOINT}"; // Store in localStorage as a fallback mechanism localStorage.setItem('ENTE_CONFIG', JSON.stringify(window.ENTE_CONFIG)); localStorage.setItem('NEXT_PUBLIC_ENTE_ENDPOINT', "${API_ENDPOINT}"); // Log the configuration console.log("Ente ${app_name} config loaded:", window.ENTE_CONFIG); // Redirect to the main app after a brief delay setTimeout(function() { window.location.href = "/${app_name}/"; }, 100); </script> </head> <body> <h1>Loading ${app_name}...</h1> <p>If you are not redirected automatically, <a href="/${app_name}/">click here</a>.</p> <p><a href="/debug">Debug Information</a></p> </body> </html> EOT done echo "==> Created app-specific config loading pages with debug info" # Looking for Museum (Go server component) echo "==> Looking for Museum (Go server component)" Loading Loading @@ -813,3 +962,215 @@ echo "==> Caddy: PID $CADDY_PID" # Wait for child processes to exit wait $SERVER_PID wait $CADDY_PID # Create a special root index.html that loads the config and redirects cat > /app/data/public/index.html <<EOT <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Ente</title> <script src="/debug.js"></script> <script> // Define configuration globally window.ENTE_CONFIG = { API_URL: "${API_ENDPOINT}" }; // Set environment variables for Next.js apps window.process = window.process || {}; window.process.env = window.process.env || {}; window.process.env.NEXT_PUBLIC_ENTE_ENDPOINT = "${API_ENDPOINT}"; // Store in localStorage as a fallback mechanism localStorage.setItem('ENTE_CONFIG', JSON.stringify(window.ENTE_CONFIG)); localStorage.setItem('NEXT_PUBLIC_ENTE_ENDPOINT', "${API_ENDPOINT}"); // Redirect to photos app after a small delay to let the configuration load setTimeout(function() { window.location.href = "/photos/"; }, 100); </script> </head> <body> <h1>Loading Ente...</h1> <p>You will be redirected automatically.</p> <p><a href="/debug">Debug Information</a></p> </body> </html> EOT echo "==> Created special root index.html with configuration" # Create debug script for frontend mkdir -p /app/data/public mkdir -p /app/data/debug echo "==> Creating debug scripts" cat > /app/data/public/debug.js <<EOT // Debugging script for Ente (function() { console.log("Debug script loaded"); // Intercept URL constructor const originalURL = window.URL; window.URL = function(url, base) { console.log("URL constructor called with:", url, base); try { return new originalURL(url, base); } catch (e) { console.error("URL construction failed:", e.message); console.error("URL:", url); console.error("Base:", base); console.error("Stack:", e.stack); // Try to fix common issues if (url && !url.startsWith("http") && !url.startsWith("/")) { console.log("Attempting to fix relative URL by adding leading slash"); return new originalURL("/" + url, base); } throw e; } }; // Create debug overlay const debugDiv = document.createElement('div'); debugDiv.style.position = 'fixed'; debugDiv.style.bottom = '10px'; debugDiv.style.right = '10px'; debugDiv.style.backgroundColor = 'rgba(0,0,0,0.7)'; debugDiv.style.color = 'white'; debugDiv.style.padding = '10px'; debugDiv.style.borderRadius = '5px'; debugDiv.style.zIndex = '9999'; debugDiv.style.maxWidth = '400px'; debugDiv.style.maxHeight = '200px'; debugDiv.style.overflow = 'auto'; debugDiv.innerHTML = '<h3>Ente Debug Info</h3>'; // Add configuration info const configInfo = document.createElement('div'); configInfo.innerHTML = 'ENTE_CONFIG: ' + JSON.stringify(window.ENTE_CONFIG || {}) + '<br>' + 'process.env.NEXT_PUBLIC_ENTE_ENDPOINT: ' + (window.process?.env?.NEXT_PUBLIC_ENTE_ENDPOINT || 'undefined') + '<br>' + 'localStorage ENTE_CONFIG: ' + localStorage.getItem('ENTE_CONFIG') + '<br>' + 'localStorage NEXT_PUBLIC_ENTE_ENDPOINT: ' + localStorage.getItem('NEXT_PUBLIC_ENTE_ENDPOINT'); debugDiv.appendChild(configInfo); // Add toggle button const toggleButton = document.createElement('button'); toggleButton.innerText = 'Toggle Debug Info'; toggleButton.style.marginTop = '10px'; toggleButton.onclick = function() { configInfo.style.display = configInfo.style.display === 'none' ? 'block' : 'none'; }; debugDiv.appendChild(toggleButton); // Add to document when it's ready if (document.body) { document.body.appendChild(debugDiv); } else { window.addEventListener('DOMContentLoaded', function() { document.body.appendChild(debugDiv); }); } })(); EOT # Create debug info script that prints environment info cat > /app/data/debug/debug_env.js <<EOT #!/usr/bin/env node console.log('=== Ente Environment Debug ==='); console.log('CLOUDRON_APP_ORIGIN:', process.env.CLOUDRON_APP_ORIGIN); console.log('API_ENDPOINT:', process.env.API_ENDPOINT); console.log('NEXT_PUBLIC_ENTE_ENDPOINT:', process.env.NEXT_PUBLIC_ENTE_ENDPOINT); console.log('HOSTNAME:', process.env.HOSTNAME); console.log('==============================='); EOT chmod +x /app/data/debug/debug_env.js # Create debug info HTML cat > /app/data/public/debug.html <<EOT <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Ente Debug Info</title> <style> body { font-family: Arial, sans-serif; margin: 20px; } .debug-section { margin-bottom: 20px; padding: 10px; border: 1px solid #ccc; } h1 { color: #333; } pre { background-color: #f5f5f5; padding: 10px; border-radius: 5px; overflow-x: auto; } </style> </head> <body> <h1>Ente Debug Information</h1> <div class="debug-section"> <h2>Frontend Configuration</h2> <pre id="config-info">Loading...</pre> </div> <div class="debug-section"> <h2>URL Test</h2> <p>Testing URL construction with API endpoint:</p> <pre id="url-test">Running test...</pre> </div> <div class="debug-section"> <h2>API Health Check</h2> <pre id="api-health">Checking API health...</pre> </div> <script> // Define configuration globally window.ENTE_CONFIG = { API_URL: "${CLOUDRON_APP_ORIGIN}/api" }; // Set environment variables for Next.js apps window.process = window.process || {}; window.process.env = window.process.env || {}; window.process.env.NEXT_PUBLIC_ENTE_ENDPOINT = "${CLOUDRON_APP_ORIGIN}/api"; // Store in localStorage localStorage.setItem('ENTE_CONFIG', JSON.stringify(window.ENTE_CONFIG)); localStorage.setItem('NEXT_PUBLIC_ENTE_ENDPOINT', "${CLOUDRON_APP_ORIGIN}/api"); // Display configuration document.getElementById('config-info').textContent = 'window.ENTE_CONFIG = ' + JSON.stringify(window.ENTE_CONFIG, null, 2) + '\n' + 'window.process.env.NEXT_PUBLIC_ENTE_ENDPOINT = ' + window.process.env.NEXT_PUBLIC_ENTE_ENDPOINT + '\n' + 'localStorage[\'ENTE_CONFIG\'] = ' + localStorage.getItem('ENTE_CONFIG') + '\n' + 'localStorage[\'NEXT_PUBLIC_ENTE_ENDPOINT\'] = ' + localStorage.getItem('NEXT_PUBLIC_ENTE_ENDPOINT'); // Test URL construction try { const apiUrl = window.ENTE_CONFIG.API_URL; const testUrl = new URL('/users/ott', apiUrl); document.getElementById('url-test').textContent = 'API URL: ' + apiUrl + '\n' + 'Test URL (/users/ott): ' + testUrl.toString() + '\n' + 'Result: SUCCESS'; } catch (e) { document.getElementById('url-test').textContent = 'Error: ' + e.message + '\n' + 'Stack: ' + e.stack; } // Test API health fetch('/api/health') .then(response => { if (response.ok) return response.text(); throw new Error('API returned status: ' + response.status); }) .then(data => { document.getElementById('api-health').textContent = 'API health check: OK\nResponse: ' + data; }) .catch(err => { document.getElementById('api-health').textContent = 'API health check failed: ' + err.message; }); </script> </body> </html> EOT No newline at end of file