aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-hub/src/meshbay_hub/app.py
diff options
context:
space:
mode:
authorChristophe Besson <cbesson@gmail.com>2026-08-09 04:39:34 +0200
committerChristophe Besson <cbesson@gmail.com>2026-08-09 04:39:34 +0200
commitfb91c4545c757711e1b5fd354ca4b311c89fd2c0 (patch)
treeeb1aee6cc0fb5fc020eed2763009dea5a32eb8ee /packages/meshbay-hub/src/meshbay_hub/app.py
parent77d76421829161df6b1ef628b4e6e051a2c3c2ee (diff)
downloadmeshbay-fb91c4545c757711e1b5fd354ca4b311c89fd2c0.tar.gz
feat(hub): add production hub — config, auth, API routers, tests
config.py: TOML + env var priority. auth.py: Argon2id passwords, JWT EdDSA with jti, refresh token hashed (blake3). Routers: hub (info/pubkey), users (register/login/refresh/pubkeys), nodes (announce/get), groups (create/gek-bundle/gek-retrieve). Rate limiting via slowapi. app.py factory with lifespan. All 40 tests pass (SQLite in-memory, no PostgreSQL required). Fix: remove tests/__init__.py to resolve namespace conflicts. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'packages/meshbay-hub/src/meshbay_hub/app.py')
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/app.py79
1 files changed, 58 insertions, 21 deletions
diff --git a/packages/meshbay-hub/src/meshbay_hub/app.py b/packages/meshbay-hub/src/meshbay_hub/app.py
index 3b9ee4f..c469a87 100644
--- a/packages/meshbay-hub/src/meshbay_hub/app.py
+++ b/packages/meshbay-hub/src/meshbay_hub/app.py
@@ -1,31 +1,68 @@
"""
-MeshBay Hub — FastAPI application.
+MeshBay Hub — FastAPI application factory.
-POC endpoints are implemented in this file (in-memory storage).
-Production implementation will use db/ with SQLAlchemy + PostgreSQL.
+Usage:
+ from meshbay_hub.app import create_app
+ from meshbay_hub.config import load_config
+
+ cfg = load_config()
+ app = create_app(cfg)
"""
+from contextlib import asynccontextmanager
+from pathlib import Path
+
from fastapi import FastAPI
+from slowapi import _rate_limit_exceeded_handler
+from slowapi.errors import RateLimitExceeded
+
from meshbay_hub import __version__
-from meshbay_common import MNP_VERSION, MHP_VERSION
+from meshbay_hub.auth import generate_hub_keypair, load_hub_keypair
+from meshbay_hub.config import HubConfig
+from meshbay_hub.db.engine import close_db, init_db
+from meshbay_hub.api.hub import router as hub_router
+from meshbay_hub.api.users import router as users_router, set_config as users_set_config
+from meshbay_hub.api.nodes import router as nodes_router
+from meshbay_hub.api.groups import router as groups_router
+from meshbay_hub.api.middleware import limiter
+
+
+def create_app(cfg: HubConfig | None = None) -> FastAPI:
+ from meshbay_hub.config import load_config
+ if cfg is None:
+ cfg = load_config()
+
+ @asynccontextmanager
+ async def lifespan(app: FastAPI):
+ # Startup
+ await init_db(cfg.db.url)
+
+ kp = cfg.identity.private_key_path
+ if not kp.exists():
+ generate_hub_keypair(kp)
+ load_hub_keypair(kp, cfg.identity.id)
+ users_set_config(cfg)
+
+ yield
+
+ # Shutdown
+ await close_db()
-app = FastAPI(
- title="MeshBay Hub",
- version=__version__,
- description="MeshBay identity authority and group registry",
-)
+ app = FastAPI(
+ title="MeshBay Hub",
+ version=__version__,
+ description="MeshBay identity authority and group registry",
+ lifespan=lifespan,
+ )
-# TODO: import and include routers from api/ submodules
-# from meshbay_hub.api import users, nodes, groups
-# app.include_router(users.router, prefix="/v1")
-# app.include_router(nodes.router, prefix="/v1")
-# app.include_router(groups.router, prefix="/v1")
+ # Rate limiting
+ app.state.limiter = limiter
+ app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)
+ # Routers
+ app.include_router(hub_router)
+ app.include_router(users_router)
+ app.include_router(nodes_router)
+ app.include_router(groups_router)
-@app.get("/v1/hub/info")
-async def hub_info() -> dict:
- return {
- "hub_id": "meshbay.org",
- "mnp_version": MNP_VERSION,
- "mhp_version": MHP_VERSION,
- }
+ return app