diff --git a/src/lib/feature/feeds/feed.svelte.ts b/src/lib/feature/feeds/feed.svelte.ts index 448591ef..af9a868c 100644 --- a/src/lib/feature/feeds/feed.svelte.ts +++ b/src/lib/feature/feeds/feed.svelte.ts @@ -93,6 +93,8 @@ export interface FeedTypes { postUri: string comments: GetCommentsParams preload?: CovesPostView + /** Poll briefly when the post isn't indexed yet (fresh-create redirect). */ + retryUnavailable?: boolean thread: { showContext?: boolean singleThread?: boolean diff --git a/src/routes/c/[handle=handle]/post/[rkey]/+page.ts b/src/routes/c/[handle=handle]/post/[rkey]/+page.ts index 119e2cce..4df154b6 100644 --- a/src/routes/c/[handle=handle]/post/[rkey]/+page.ts +++ b/src/routes/c/[handle=handle]/post/[rkey]/+page.ts @@ -68,9 +68,20 @@ export async function load({ params, url, fetch, route }) { const feedData = feed(route.id, async (p) => { // If we have a preloaded post from cache, use it. Otherwise fetch from API. - const result = + let result = p.preload ?? (await coves({ func: fetch }).getPost(p.postUri as AtUri)) + // A brand-new post can beat the AppView indexer here — the create flow + // redirects immediately after the record is written. When the navigation + // carries the fresh-post signal (`?uri=`), poll briefly instead of + // declaring the post unavailable. + if (!isHydratedPost(result) && p.retryUnavailable) { + for (let attempt = 0; attempt < 6 && !isHydratedPost(result); attempt++) { + await new Promise((resolve) => setTimeout(resolve, 500)) + result = await coves({ func: fetch }).getPost(p.postUri as AtUri) + } + } + // The batch endpoint returns a union: a hydrated post, or an unavailable // sentinel (deleted/unindexed/unresolvable/blocked). Surface the latter as // an "unavailable" state instead of throwing into the error page. We log @@ -124,6 +135,7 @@ export async function load({ params, url, fetch, route }) { limit: 50, }, preload: cachedPost, + retryUnavailable: url.searchParams.has('uri'), thread: { showContext, singleThread, focus }, }), )