"""Standard API response envelope. All new endpoints should return via these helpers to produce a consistent ``{success, data, meta}`` shape that the frontend can depend on. Existing endpoints are NOT required to migrate — this is additive only. Usage:: from app.core.response import ok, created, paginated @router.get("/sync/progress") def get_progress(...): return ok({"events": []}) @router.post("/sync/progress") def post_progress(...): return created({"synced": True}, message="Progress recorded.") """ from __future__ import annotations from datetime import datetime, timezone from typing import Any def _now_iso() -> str: return datetime.now(timezone.utc).isoformat() def ok( data: Any, *, meta: dict[str, Any] | None = None, message: str | None = None, ) -> dict[str, Any]: """Return a 200 OK envelope. Shape:: {"success": true, "data": , "meta": {"timestamp": "...", ...}} """ m: dict[str, Any] = {"timestamp": _now_iso()} if meta: m.update(meta) if message: m["message"] = message return {"success": True, "data": data, "meta": m} def created( data: Any, *, meta: dict[str, Any] | None = None, message: str | None = None, ) -> dict[str, Any]: """Return a 201 Created envelope (same shape as ``ok``).""" return ok(data, meta=meta, message=message) def paginated( data: list[Any], *, total: int, page: int = 1, per_page: int = 20, extra_meta: dict[str, Any] | None = None, ) -> dict[str, Any]: """Return a paginated 200 OK envelope. Shape:: { "success": true, "data": [...], "meta": { "timestamp": "...", "total": 42, "page": 1, "per_page": 20, "pages": 3 } } """ pages = max(1, (total + per_page - 1) // per_page) meta: dict[str, Any] = { "timestamp": _now_iso(), "total": total, "page": page, "per_page": per_page, "pages": pages, } if extra_meta: meta.update(extra_meta) return {"success": True, "data": data, "meta": meta}