When only TOTP is enabled (today's production state for everyone),
auth-gate.js was falling through to the legacy TOTP overlay with no
visible path to the email provider. The email method was unreachable
from the UI even when configured. Fixed: append a small 'Or sign in
with email instead ->' link to the bottom of the TOTP card. Clicking
swaps the body to the email challenge form.
Why this matters even for the single-totp path: email is the
phone-friendly, no-app-required recovery path. Operator forgets their
TOTP secret at 2am, they can request a link without touching the
authenticator app. The link just wasn't reachable before.
Renders the link only when the methods response includes both totp
and email — preserves the truly-single-provider case unchanged.
New module status/js/auth-gate.js owns the Caddy ?auth=required flow.
On load it queries GET /api/v1/auth/login/methods to discover which
AuthProviders are configured. Three branches:
* 0 providers → legacy TOTP overlay (delegates to window._showTotpOverlay)
* 1 provider (totp only) → legacy TOTP overlay (delegates, no UI change)
* 2+ providers → provider selector with 'Sign in with …' buttons
Email provider challenge is a single email input + 'Send sign-in link'
button. POST to /api/v1/auth/login/email/initiate. On success the UI
shows 'check the server logs' message if deliveredVia == 'dev-console'
(production hosts without SMTP fall back gracefully) or 'check your
inbox' when SMTP is configured.
TOTP button just calls window.location.reload() — simplest path because
totp-auth.js wires the 6-digit input handlers at module-load time, and
a reload re-runs all IIFEs with the original markup. Same behavior as
the legacy single-provider path.
Coordination with totp-auth.js: auth-gate.js sets window.__dc_049_handled
= true at IIFE entry. totp-auth.js's top-level ?auth=required check
reads that flag and skips its own UI when set — eliminates the flicker
in multi-provider installs. Single-provider installs still work because
the legacy code path is unchanged (auth-gate delegates to it).
Bundle order in build.js: auth-gate.js BEFORE totp-auth.js so the flag
is set in time.
Webpack-style bundle markers verified offline: __dc_049_handled,
auth-gate-email-input, provider-btn, _showAuthGate, totp_redirect all
present in dist/core.js (now 20 files, 248KB raw / 153KB min). New SW
cache hash dashcaddy-shell-680e230383 (was 743f9c17b0).