archy/neode-ui/src/views/appSession/appSessionConfig.ts
Dorian b0656b068f fix: 60s timeout on image pull, gitea port 3001, wireguard first-boot
Image pulls now timeout after 60s and fall through to dynamic registry
fallback instead of hanging forever when primary is unreachable.
Gitea external port corrected to 3001. WireGuard key generation
added to first-boot for fresh installs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 10:00:06 -04:00

177 lines
5.9 KiB
TypeScript

/** 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<string, number> = {
'bitcoin-knots': 8334,
'bitcoin-ui': 8334,
'electrumx': 50002,
'electrs': 50002,
'archy-electrs-ui': 50002,
'mempool-electrs': 50002,
'btcpay-server': 23000,
'lnd': 8081,
'archy-lnd-ui': 8081,
'mempool': 4080,
'mempool-web': 4080,
'archy-mempool-web': 4080,
'homeassistant': 8123,
'grafana': 3000,
'searxng': 8888,
'ollama': 11434,
'onlyoffice': 8044,
'penpot': 9001,
'nextcloud': 8085,
'vaultwarden': 8082,
'jellyfin': 8096,
'photoprism': 2342,
'immich': 2283,
'immich_server': 2283,
'filebrowser': 8083,
'nginx-proxy-manager': 8181,
'portainer': 9000,
'uptime-kuma': 3001,
'fedimint': 8175,
'fedimintd': 8175,
'fedimint-gateway': 8176,
'nostr-rs-relay': 18081,
'nostr-vpn': 8201,
'fips': 8202,
'routstr': 8200,
'indeedhub': 7778,
'botfights': 9100,
'gitea': 3001,
'dwn': 3100,
'endurain': 8080,
}
/** Apps that need nginx proxy for iframe embedding.
* IndeedHub loads via /app/indeedhub/ proxy for nostr-provider.js injection
* from the container's internal nginx so iframe works on all servers. */
export const PROXY_APPS: Record<string, string> = {}
/** Nginx proxy paths -- used on HTTPS to avoid mixed content (HTTPS parent + HTTP port iframe).
* On HTTP, direct port access is used instead (faster, no proxy). */
export const HTTPS_PROXY_PATHS: Record<string, string> = {
'bitcoin-knots': '/app/bitcoin-ui/',
'bitcoin-ui': '/app/bitcoin-ui/',
'lnd': '/app/lnd/',
'electrumx': '/app/electrs/',
'electrs': '/app/electrs/',
'mempool-electrs': '/app/electrs/',
'mempool': '/app/mempool/',
'mempool-web': '/app/mempool/',
'archy-mempool-web': '/app/mempool/',
'fedimint': '/app/fedimint/',
'fedimintd': '/app/fedimint/',
'fedimint-gateway': '/app/fedimint-gateway/',
'jellyfin': '/app/jellyfin/',
'searxng': '/app/searxng/',
'filebrowser': '/app/filebrowser/',
'ollama': '/app/ollama/',
'onlyoffice': '/app/onlyoffice/',
'immich': '/app/immich/',
'immich_server': '/app/immich/',
'portainer': '/app/portainer/',
'nginx-proxy-manager': '/app/nginx-proxy-manager/',
'uptime-kuma': '/app/uptime-kuma/',
'homeassistant': '/app/homeassistant/',
'vaultwarden': '/app/vaultwarden/',
'photoprism': '/app/photoprism/',
'endurain': '/app/endurain/',
'dwn': '/app/dwn/',
'btcpay-server': '/app/btcpay/',
'nextcloud': '/app/nextcloud/',
'penpot': '/app/penpot/',
'grafana': '/app/grafana/',
'indeedhub': '/app/indeedhub/',
'botfights': '/app/botfights/',
'gitea': '/app/gitea/',
'routstr': '/app/routstr/',
'nostr-vpn': '/app/nostr-vpn/',
'fips': '/app/fips/',
}
/** External HTTPS apps -- always loaded directly */
export const EXTERNAL_URLS: Record<string, string> = {
'nwnn': 'https://nwnn.l484.com',
'484-kitchen': 'https://484.kitchen',
'call-the-operator': 'https://cta.tx1138.com',
'syntropy-institute': 'https://syntropy.institute',
't-zero': 'https://teeminuszero.net',
'nostrudel': 'https://nostrudel.ninja',
'tailscale': 'https://login.tailscale.com/admin/machines',
}
export const APP_TITLES: Record<string, string> = {
'bitcoin-knots': 'Bitcoin', 'btcpay-server': 'BTCPay Server', 'indeedhub': 'Indeehub',
'botfights': 'BotFights', 'gitea': 'Gitea', '484-kitchen': '484 Kitchen', 'arch-presentation': 'Presentation',
'nostr-vpn': 'Nostr VPN', 'fips': 'FIPS', 'routstr': 'Routstr',
'homeassistant': 'Home Assistant', 'uptime-kuma': 'Uptime Kuma',
'nginx-proxy-manager': 'Nginx Proxy Manager', 'nostr-rs-relay': 'Nostr Relay',
'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',
'penpot',
'portainer',
'onlyoffice',
'nginx-proxy-manager',
'tailscale',
'routstr',
])
/** Sites known to block iframes -- skip the timeout and go straight to fallback */
export const IFRAME_BLOCKED_APPS = new Set<string>([])
/** Resolve the app URL given its ID and current route query */
export function resolveAppUrl(id: string, routeQueryPath?: string): string {
// External HTTPS apps
const ext = EXTERNAL_URLS[id]
if (ext) return ext
// Apps that need nginx proxy (nostr-provider.js injection for NIP-07)
const proxyPath = PROXY_APPS[id]
if (proxyPath) return `${window.location.origin}${proxyPath}`
// IndeedHub: direct port access (nostr-provider.js baked into container image)
if (id === 'indeedhub') {
const port = APP_PORTS[id]
if (port) {
let base = `${window.location.protocol}//${window.location.hostname}:${port}`
if (routeQueryPath) base += routeQueryPath
return base
}
}
// HTTPS: use nginx proxy to avoid mixed content
if (window.location.protocol === 'https:') {
const httpsProxy = HTTPS_PROXY_PATHS[id]
if (httpsProxy) return `${window.location.origin}${httpsProxy}`
}
// HTTP: direct port access (iframes break with proxy paths due to root-relative assets)
const port = APP_PORTS[id]
if (!port) return ''
let base = `http://${window.location.hostname}:${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())
}