import os from typing import Dict, Any from supabase import create_client, Client import requests def _get_supabase_client() -> Client: url = os.getenv("SUPABASE_URL") key = os.getenv("SUPABASE_SERVICE_ROLE_KEY") or os.getenv("SUPABASE_ANON_KEY") if not url or not key: raise RuntimeError("Missing SUPABASE_URL or SUPABASE_*_KEY") return create_client(url, key) def fetch_user_from_supabase_token(jwt: str) -> Dict[str, Any] | None: # Validate JWT via auth endpoint supabase_url = os.getenv("SUPABASE_URL") if not supabase_url: return None resp = requests.get( f"{supabase_url}/auth/v1/user", headers={ "Authorization": f"Bearer {jwt}", "apikey": os.getenv("SUPABASE_ANON_KEY", ""), }, timeout=20, ) if resp.status_code != 200: return None return resp.json() def upload_bytes_to_supabase_storage( bucket: str, object_path: str, content_bytes: bytes, content_type: str = "application/octet-stream", ) -> str: client = _get_supabase_client() storage = client.storage.from_(bucket) storage.upload(object_path, content_bytes, { "contentType": content_type, "upsert": False, }) # Create public URL (assumes bucket is public or policy allows reads) # Handle both string or dict responses across library versions url_candidate = storage.get_public_url(object_path) if isinstance(url_candidate, dict): public_url = ( url_candidate.get("publicUrl") or url_candidate.get("public_url") or url_candidate.get("url") ) else: public_url = str(url_candidate) if not public_url: # Fallback construct (public bucket assumption) base = os.getenv("SUPABASE_URL", "").rstrip("/") public_url = f"{base}/storage/v1/object/public/{bucket}/{object_path}" return public_url def insert_slip_row(row: Dict[str, Any]) -> Dict[str, Any]: client = _get_supabase_client() response = client.table("slips").insert(row).select("*").execute() if not response.data: raise RuntimeError("Insert returned no data") return response.data[0]