"""v1 vault sync-assist API — vault files are the source of truth.""" from __future__ import annotations from fastapi import APIRouter, Depends, File, HTTPException, UploadFile, status from fastapi.responses import Response from ..auth import get_current_user from .. import vault_store router = APIRouter() @router.get("/manifest") async def get_manifest(user_id: str = Depends(get_current_user)) -> dict: """List all files in the user's vault with size/mtime/sha256.""" return vault_store.build_manifest(user_id) @router.get("/files/{file_path:path}") async def download_file( file_path: str, user_id: str = Depends(get_current_user), ) -> Response: try: data = vault_store.read_file(user_id, file_path) except ValueError as exc: raise HTTPException(status.HTTP_400_BAD_REQUEST, detail=str(exc)) from exc except FileNotFoundError: raise HTTPException(status.HTTP_404_NOT_FOUND, detail="file not found") return Response( content=data, media_type="application/octet-stream", headers={"X-Vault-Path": file_path}, ) @router.put("/files/{file_path:path}") async def upload_file( file_path: str, upload: UploadFile = File(...), user_id: str = Depends(get_current_user), ) -> dict: try: data = await upload.read() entry = vault_store.write_file(user_id, file_path, data) except ValueError as exc: raise HTTPException(status.HTTP_400_BAD_REQUEST, detail=str(exc)) from exc return entry.to_dict() @router.delete("/files/{file_path:path}") async def remove_file( file_path: str, user_id: str = Depends(get_current_user), ) -> dict: try: vault_store.delete_file(user_id, file_path, tombstone=True) except ValueError as exc: raise HTTPException(status.HTTP_400_BAD_REQUEST, detail=str(exc)) from exc except FileNotFoundError: raise HTTPException(status.HTTP_404_NOT_FOUND, detail="file not found") return {"deleted": file_path, "tombstone": True}