diff --git a/server.py b/server.py
index fa05444..9ea7e5c 100644
--- a/server.py
+++ b/server.py
@@ -537,7 +537,7 @@ def render_home_html(actor_id: Optional[str] = None) -> str:
@app.get("/", response_class=HTMLResponse)
async def root(request: Request):
"""Home page."""
- ctx = get_user_context_from_cookie(request)
+ ctx = await get_user_context_from_cookie(request)
actor_id = ctx.actor_id if ctx else None
return render_home_html(actor_id)
@@ -721,7 +721,7 @@ async def discard_run(run_id: str, ctx: UserContext = Depends(get_required_user_
@app.delete("/ui/runs/{run_id}/discard", response_class=HTMLResponse)
async def ui_discard_run(run_id: str, request: Request):
"""HTMX handler: discard a run. Only deletes outputs, preserves inputs."""
- ctx = get_user_context_from_cookie(request)
+ ctx = await get_user_context_from_cookie(request)
if not ctx:
return '
Login required
'
@@ -795,7 +795,7 @@ async def run_detail(run_id: str, request: Request):
await asyncio.to_thread(save_run, run)
if wants_html(request):
- ctx = get_user_context_from_cookie(request)
+ ctx = await get_user_context_from_cookie(request)
if not ctx:
content = 'Login via L2 to view run details.
'
return HTMLResponse(render_page("Login Required", content, None, active_tab="runs"), status_code=401)
@@ -1014,7 +1014,7 @@ async def run_detail(run_id: str, request: Request):
@app.get("/runs")
async def list_runs(request: Request, page: int = 1, limit: int = 20):
"""List runs. HTML for browsers (with infinite scroll), JSON for APIs (with pagination)."""
- ctx = get_user_context_from_cookie(request)
+ ctx = await get_user_context_from_cookie(request)
all_runs = await asyncio.to_thread(list_all_runs)
total = len(all_runs)
@@ -1206,7 +1206,7 @@ async def upload_recipe(file: UploadFile = File(...), ctx: UserContext = Depends
@app.get("/recipes")
async def list_recipes_api(request: Request, page: int = 1, limit: int = 20):
"""List recipes. HTML for browsers, JSON for APIs."""
- ctx = get_user_context_from_cookie(request)
+ ctx = await get_user_context_from_cookie(request)
all_recipes = await asyncio.to_thread(list_all_recipes)
@@ -1469,7 +1469,7 @@ def build_dag_from_recipe(yaml_config: dict, user_inputs: dict[str, str], recipe
@app.get("/recipe/{recipe_id}", response_class=HTMLResponse)
async def recipe_detail_page(recipe_id: str, request: Request):
"""Recipe detail page with run form."""
- ctx = get_user_context_from_cookie(request)
+ ctx = await get_user_context_from_cookie(request)
recipe = load_recipe(recipe_id)
if not recipe:
@@ -1550,7 +1550,7 @@ async def recipe_detail_page(recipe_id: str, request: Request):
@app.post("/ui/recipes/{recipe_id}/run", response_class=HTMLResponse)
async def ui_run_recipe(recipe_id: str, request: Request):
"""HTMX handler: run a recipe with form inputs."""
- ctx = get_user_context_from_cookie(request)
+ ctx = await get_user_context_from_cookie(request)
if not ctx:
return 'Login required
'
@@ -1620,7 +1620,7 @@ async def ui_run_recipe(recipe_id: str, request: Request):
@app.get("/ui/recipes-list", response_class=HTMLResponse)
async def ui_recipes_list(request: Request):
"""HTMX partial: list of recipes."""
- ctx = get_user_context_from_cookie(request)
+ ctx = await get_user_context_from_cookie(request)
if not ctx:
return 'Login via L2 to see recipes.
'
@@ -1671,7 +1671,7 @@ async def ui_recipes_list(request: Request):
@app.delete("/ui/recipes/{recipe_id}/discard", response_class=HTMLResponse)
async def ui_discard_recipe(recipe_id: str, request: Request):
"""HTMX handler: discard a recipe."""
- ctx = get_user_context_from_cookie(request)
+ ctx = await get_user_context_from_cookie(request)
if not ctx:
return 'Login required
'
@@ -1706,7 +1706,7 @@ async def get_cached(content_hash: str, request: Request):
accept = request.headers.get("accept", "")
logger.info(f"get_cached: {content_hash[:16]}... Accept={accept[:50]}")
- ctx = get_user_context_from_cookie(request)
+ ctx = await get_user_context_from_cookie(request)
cache_path = get_cache_path(content_hash)
if not cache_path:
@@ -1963,7 +1963,7 @@ async def cache_meta_form(content_hash: str, request: Request):
@app.get("/ui/cache/{content_hash}/meta-form", response_class=HTMLResponse)
async def ui_cache_meta_form(content_hash: str, request: Request):
"""HTMX partial: metadata editing form for a cached item."""
- ctx = get_user_context_from_cookie(request)
+ ctx = await get_user_context_from_cookie(request)
if not ctx:
return 'Login required to edit metadata
'
@@ -2136,7 +2136,7 @@ async def ui_cache_meta_form(content_hash: str, request: Request):
@app.patch("/ui/cache/{content_hash}/meta", response_class=HTMLResponse)
async def ui_update_cache_meta(content_hash: str, request: Request):
"""HTMX handler: update cache metadata from form."""
- ctx = get_user_context_from_cookie(request)
+ ctx = await get_user_context_from_cookie(request)
if not ctx:
return 'Login required
'
@@ -2183,7 +2183,7 @@ async def ui_update_cache_meta(content_hash: str, request: Request):
@app.post("/ui/cache/{content_hash}/publish", response_class=HTMLResponse)
async def ui_publish_cache(content_hash: str, request: Request):
"""HTMX handler: publish cache item to L2."""
- ctx = get_user_context_from_cookie(request)
+ ctx = await get_user_context_from_cookie(request)
if not ctx:
return 'Login required
'
@@ -2276,7 +2276,7 @@ async def ui_publish_cache(content_hash: str, request: Request):
@app.patch("/ui/cache/{content_hash}/republish", response_class=HTMLResponse)
async def ui_republish_cache(content_hash: str, request: Request):
"""HTMX handler: re-publish (update) cache item on L2."""
- ctx = get_user_context_from_cookie(request)
+ ctx = await get_user_context_from_cookie(request)
if not ctx:
return 'Login required
'
@@ -2360,7 +2360,7 @@ async def list_media(
tag: Optional[str] = None
):
"""List media items. HTML for browsers (with infinite scroll), JSON for APIs (with pagination)."""
- ctx = get_user_context_from_cookie(request)
+ ctx = await get_user_context_from_cookie(request)
if wants_html(request):
# Require login for HTML media view
@@ -2593,7 +2593,7 @@ async def discard_cache(content_hash: str, ctx: UserContext = Depends(get_requir
@app.delete("/ui/cache/{content_hash}/discard", response_class=HTMLResponse)
async def ui_discard_cache(content_hash: str, request: Request):
"""HTMX handler: discard a cached item."""
- ctx = get_user_context_from_cookie(request)
+ ctx = await get_user_context_from_cookie(request)
if not ctx:
return 'Login required
'
@@ -3174,7 +3174,7 @@ async def sync_with_l2(ctx: UserContext = Depends(get_required_user_context)):
@app.post("/ui/sync-l2", response_class=HTMLResponse)
async def ui_sync_with_l2(request: Request):
"""HTMX handler: sync with L2 server."""
- ctx = get_user_context_from_cookie(request)
+ ctx = await get_user_context_from_cookie(request)
if not ctx:
return 'Login required
'
@@ -3356,17 +3356,17 @@ def detect_media_type(cache_path: Path) -> str:
return "unknown"
-def get_user_context_from_cookie(request) -> Optional[UserContext]:
+async def get_user_context_from_cookie(request) -> Optional[UserContext]:
"""Get user context from auth cookie. Returns full context with actor_id and l2_server."""
token = request.cookies.get("auth_token")
if not token:
return None
- return get_verified_user_context(token)
+ return await get_verified_user_context(token)
-def get_user_from_cookie(request) -> Optional[str]:
+async def get_user_from_cookie(request) -> Optional[str]:
"""Get username from auth cookie (backwards compat - prefer get_user_context_from_cookie)."""
- ctx = get_user_context_from_cookie(request)
+ ctx = await get_user_context_from_cookie(request)
return ctx.username if ctx else None
@@ -3585,7 +3585,7 @@ async def ui_logout():
@app.post("/ui/publish-run/{run_id}", response_class=HTMLResponse)
async def ui_publish_run(run_id: str, request: Request, output_name: str = Form(...)):
"""Publish a run to L2 from the web UI."""
- ctx = get_user_context_from_cookie(request)
+ ctx = await get_user_context_from_cookie(request)
if not ctx:
return HTMLResponse('Not logged in
')
@@ -3654,7 +3654,7 @@ async def ui_publish_run(run_id: str, request: Request, output_name: str = Form(
@app.get("/ui/runs", response_class=HTMLResponse)
async def ui_runs(request: Request):
"""HTMX partial: list of runs."""
- ctx = get_user_context_from_cookie(request)
+ ctx = await get_user_context_from_cookie(request)
runs = list_all_runs()
# Require login to see runs
@@ -3754,7 +3754,7 @@ async def ui_media_list(
tag: Optional[str] = None
):
"""HTMX partial: list of media items with optional filtering."""
- ctx = get_user_context_from_cookie(request)
+ ctx = await get_user_context_from_cookie(request)
# Require login to see media
if not ctx: