/** Static configuration maps for app session routing and display */ export type DisplayMode = 'panel' | 'overlay' | 'fullscreen' export const DISPLAY_MODE_KEY = 'archipelago_app_display_mode' /** Container apps: direct port access (avoids root-relative asset breakage under /app/xxx/ proxy) */ export const APP_PORTS: Record = { 'bitcoin-knots': 8334, 'bitcoin-core': 8334, 'bitcoin-ui': 8334, 'electrumx': 50002, 'electrs': 50002, 'archy-electrs-ui': 50002, 'mempool-electrs': 50002, 'btcpay-server': 23000, 'saleor': 9010, 'lnd': 18083, 'archy-lnd-ui': 18083, 'mempool': 4080, 'mempool-web': 4080, 'archy-mempool-web': 4080, 'homeassistant': 8123, 'grafana': 3000, 'searxng': 8888, 'ollama': 11434, 'onlyoffice': 8044, 'nextcloud': 8085, 'vaultwarden': 8082, 'jellyfin': 8096, 'photoprism': 2342, 'immich': 2283, 'immich_server': 2283, 'filebrowser': 8083, 'nginx-proxy-manager': 8081, 'gitea': 3001, 'portainer': 9000, 'netbird': 8087, 'tailscale': 8240, 'uptime-kuma': 3002, 'fedimint': 8175, 'fedimintd': 8175, 'fedimint-gateway': 8176, 'indeedhub': 7778, 'botfights': 9100, 'dwn': 3100, 'endurain': 8080, } /** Apps that need nginx proxy for iframe embedding. * IndeeHub web UI is on 7778. Port 7777 is the Nostr relay. */ export const PROXY_APPS: Record = { 'gitea': '/app/gitea/', 'nginx-proxy-manager': '/app/nginx-proxy-manager/', 'uptime-kuma': '/app/uptime-kuma/', } /** App launches use direct ports. Do not route through /app/... path proxies. */ export const HTTPS_PROXY_PATHS: Record = { } /** External HTTPS apps -- always loaded directly */ export const EXTERNAL_URLS: Record = { 'nwnn': 'https://nwnn.l484.com', '484-kitchen': 'https://484.kitchen', 'call-the-operator': 'https://cta.tx1138.com', 'arch-presentation': 'https://present.l484.com', 'syntropy-institute': 'https://syntropy.institute', 't-zero': 'https://teeminuszero.net', 'nostrudel': 'https://nostrudel.ninja', } export const APP_TITLES: Record = { 'bitcoin-knots': 'Bitcoin Knots', 'bitcoin-core': 'Bitcoin Core', 'btcpay-server': 'BTCPay Server', 'saleor': 'Saleor', 'indeedhub': 'Indeehub', 'botfights': 'BotFights', 'gitea': 'Gitea', '484-kitchen': '484 Kitchen', 'arch-presentation': 'Presentation', 'homeassistant': 'Home Assistant', 'uptime-kuma': 'Uptime Kuma', 'nginx-proxy-manager': 'Nginx Proxy Manager', 'call-the-operator': 'Call The Operator', 'syntropy-institute': 'Syntropy Institute', 't-zero': 'T-Zero', 'nostrudel': 'noStrudel', } /** Apps that set X-Frame-Options and MUST open in a new tab (can't iframe) */ export const NEW_TAB_APPS = new Set([ 'btcpay-server', 'grafana', 'photoprism', 'homeassistant', 'vaultwarden', 'nextcloud', 'uptime-kuma', 'portainer', 'onlyoffice', 'nginx-proxy-manager', 'gitea', 'tailscale', ]) /** Sites known to block iframes -- skip the timeout and go straight to fallback */ export const IFRAME_BLOCKED_APPS = new Set([]) /** Resolve app URL using direct port mapping (source of truth) */ export function resolveAppUrl(id: string, routeQueryPath?: string, runtimeUrl?: string): string { // External HTTPS apps const ext = EXTERNAL_URLS[id] if (ext) return ext // Bitcoin UI is a host-network companion on :8334. Do not launch it via // /app/bitcoin-ui/: the static UI is built for root and renders a blank // shell when proxied under a path prefix on some nodes. if (id === 'bitcoin-knots' || id === 'bitcoin-core' || id === 'bitcoin-ui') { return 'http://' + window.location.hostname + ':8334' } // Local apps launch by host port. const port = APP_PORTS[id] if (!port) return '' let base = 'http://' + window.location.hostname + ':' + String(port) if (routeQueryPath) base += routeQueryPath return base } /** Resolve a human-readable title for an app */ export function resolveAppTitle(id: string): string { return APP_TITLES[id] || id.replace(/-/g, ' ').replace(/\b\w/g, c => c.toUpperCase()) }