"""Hub info endpoints — /v1/hub/*""" from fastapi import APIRouter, Depends from sqlalchemy.ext.asyncio import AsyncSession from meshbay_common import MNP_VERSION, MHP_VERSION from meshbay_hub import __version__, hub_settings from meshbay_hub.auth import hub_public_key_pem from meshbay_hub.db.engine import get_db, get_engine router = APIRouter(prefix="/v1/hub", tags=["hub"]) @router.get("/info") async def hub_info(db: AsyncSession = Depends(get_db)): engine = get_engine() return { "hub_version": __version__, "mnp_version": MNP_VERSION, "mhp_version": MHP_VERSION, "db_dialect": engine.dialect.name, # Instance policy the SPA needs before drawing the create-group form. # Unauthenticated on purpose: it is not a secret, and the form is # reachable before the group list loads. The hub enforces it regardless # of what any client does with this flag. "allow_public_groups": await hub_settings.public_groups_allowed(db), } @router.get("/pubkey") async def hub_pubkey(): """Hub Ed25519 public key PEM — cached by nodes on first contact.""" return {"pk_hub_pem": hub_public_key_pem().decode()} # What an installed client must be, to talk to this hub. # # Until a client ships, the SPA and the hub deploy together and are always in # sync: a /v1/ response shape changes and app.js is fixed in the same commit. # The moment the interface is installed rather than served, an old client meets # a new hub — for the first time in this project's life — and there is no way to # fix it from here. # # `minimum` refuses; `recommended` warns. Both are stated so a client can tell a # user "update to keep using this" before it becomes "this stopped working". # Raise `minimum` only for a change a client genuinely cannot survive, and # remember store review latency makes that expensive on Android. MIN_CLIENT_VERSION = "0.1.0" RECOMMENDED_CLIENT_VERSION = "0.1.0" @router.get("/version") async def hub_version(): """Version check endpoint for clients to detect updates.""" return { "hub": __version__, "mnp": MNP_VERSION, "mhp": MHP_VERSION, # A client compares its own version against these before doing anything # else. The browser SPA always matches the hub by construction and can # ignore them. "client": { "minimum": MIN_CLIENT_VERSION, "recommended": RECOMMENDED_CLIENT_VERSION, }, }