github preston-peterson/aerodrome v3.4.27

latest releases: v3.4.136, v3.4.135, v3.4.134...
4 months ago

Critical regression from v3.4.25: every page that uses time formatting was silently broken. v3.4.25 added a window._aerodromeFirstRun injection block to _serve_template for the setup wizard's first-run trigger. That edit accidentally dropped the existing html.replace('</head>', timefmt_block + '</head>', 1) line that injected /static/timefmt.js into every served page. Result: across v3.4.25 and v3.4.26, no page actually loaded the shared time-formatter script. The functions formatTime, formatTimeFull, and formatDateTime — which are called from at least 14 sites across the Live, Stats, Aircraft, Status, Config, and search pages — were undefined window references on every load. The visible failure was the System Status page, which surfaces JavaScript errors in a red banner ("Failed to load status: formatTimeFull is not defined") and is therefore unmistakable. The less visible failures: row timestamps in the Live tab, the Stats "last fetch" timestamp, the test-notification result message in Config, and the recent-notifications log all threw ReferenceErrors at their respective call sites, with the failures masked by surrounding template-literal evaluation that left blank-or-stale content where a formatted time should be. The fix is a one-line restoration of the missing html.replace line, plus a parser-level check (the inline-JS extract + node --check pipeline) so a future edit that deletes a similar injection line gets caught at release time instead of at user-impact time. Anyone running v3.4.25 or v3.4.26 should upgrade to v3.4.27 — every page-level time display in those versions is wrong or missing.

  • Install-time LAN IP auto-detection is now resilient to the DHCP race. The _detect_lan_ip helper used by the ntfy installer (to write a phone-reachable base-url into server.yml at install time) was a one-shot UDP-socket trick that returned None on any exception, with a bare except Exception: swallowing the actual error. On freshly-bootstrapped boxes where the install ran within seconds of DHCP completing — typical for an auto-install flow that drops the user into the setup wizard immediately after bootstrap — the socket's connect() call could throw [Errno 101] Network is unreachable because the default route wasn't fully up yet. That fell through to the localhost fallback, persisted base_url: http://localhost:2586 to server.yml, and from that point on every visit to the wizard or the Notifications page showed the "LAN IP could not be auto-detected" warning with no way to fix it short of hand-editing the URL field. v3.4.27 rewrites detection in three layers: (1) retry with backoff — three attempts at 500ms intervals (1.5s worst case), which closes the typical DHCP race window without papering over genuinely no-network situations; (2) filter pathological results — the previous version had no defense against a kernel returning 0.0.0.0, 127.x.x.x (loopback), or 169.254.x.x (link-local autoconf), any of which would have been written into server.yml as if it were a real LAN address; (3) return the actual failure reason — _detect_lan_ip now returns a (ip, error_reason) tuple, and /api/ntfy/status exposes the detected_lan_ip_error field so the wizard's warning can show "auto-detection failed: [OSError: errno 101] Network is unreachable" instead of a generic "could not detect" message. The configuration file's comment also includes the failure reason, so a sysadmin reading server.yml directly can see what went wrong at install time. None of this changes the install-time fallback behavior on hosts where detection genuinely can't work (no default route, unusual networking) — the base-url still falls back to localhost in that case, just now with a usable diagnostic and a one-click fix once the network situation resolves.

  • One-click self-heal for installs that landed with base_url: localhost. The retry logic in the layer above only helps installs going forward. Installs that completed under the old code — with localhost baked into server.yml — still need a corrective action. v3.4.27 detects this situation (base_url is localhost AND a fresh re-detection now succeeds) and offers a "Use 192.168.88.198 as base URL" button directly in each localhost-warning surface: the setup wizard's step 4, the phone setup guide modal opened from the Notifications page, and the Notifications panel's main state row when ntfy is aerodrome_managed. The button hands off to the existing POST /api/ntfy/config endpoint (no new server surface needed; the manual Base-URL save flow has always supported this), which rewrites server.yml with the corrected URL and restarts ntfy. On success each surface refreshes its own view — the wizard re-renders step 4 with the new URLs and no warning, the phone setup modal closes and reopens to pick up the fresh state, the Notifications panel rebuilds from the updated /api/ntfy/status response. Internally the three surfaces share one helper (nfFixLocalhostBaseUrl(detectedIp, port, uiHooks)) so the button behavior can't drift between them — per the v3.4.23 retrospective on two-parallel-code-paths drift, the right structure for any cross-surface behavior is "one shared function, multiple call sites with their own glue" rather than "one canonical implementation plus copies." The detection retry from layer 1 also runs in this self-heal path, so a flaky live detection won't immediately lock the button out — it'll get up to 1.5 seconds of retries before declaring failure.

  • The bump-version.sh release pipeline now parses each template's inline JavaScript through node --check. Per-template rather than concatenated, so legitimate cross-template identifier reuse (let activeTab, etc.) doesn't false-positive. This catches syntax errors and reference-time-dead-zone bugs in inline JS that the existing Python AST and static name-resolution checks (both Python-only) can't see — including the class of bug from Lesson 4.16 (script-load-order interactions with deferred dependencies). The check is advisory at this release (skipped silently if node isn't installed; never fails the bump) and will be made required once it's validated across a release cycle without false positives. Worth being honest about what it does NOT catch: the specific v3.4.25 timefmt-injection regression that motivated this release isn't a parse error in any file. It's a deleted html.replace line in _serve_template that left a script reference unrendered. Detecting that class would require a server-side check that the rendered HTML actually contains <script src> tags for every external JS file the inline code calls into — a more invasive separate pass. This release ships the cheap parse check first; the rendered-output check is filed for a future release if the regression class recurs.

Don't miss a new aerodrome release

NewReleases is sending notifications on new releases.