diff --git a/crates/appview/src/routes.rs b/crates/appview/src/routes.rs index b1a46da..d14154a 100644 --- a/crates/appview/src/routes.rs +++ b/crates/appview/src/routes.rs @@ -355,13 +355,24 @@ async fn resolve_profile( }; let Some(target_did) = target_did else { - return Err(( - StatusCode::NOT_FOUND, - Json(json!({ - "error": "NotFound", - "message": "no DID or handle provided, or no posts for that handle", - })), - )); + // No posts indexed for this handle yet — typical for + // local-PDS users whose posts haven't been ingested into + // the Jetstream yet (and the AppView indexes only ingested + // posts, never queries upstream PDSs for handle→DID + // resolution). Instead of bubbling a 404 to the UI which + // then shows an error toast instead of an empty profile, + // synthesise a profile row with the requested handle and + // zero counts. The `did` is left empty; the UI's + // `displayHandle()` falls back to the handle and the + // "copy did" button just copies an empty string. + let display = handle_clean.unwrap_or_default(); + return Ok(Json(ProfileResponse { + did: String::new(), + handle: display, + posts: Vec::new(), + followers: 0, + following: 0, + })); }; // Fetch the user's most recent posts (newest first). We return up to