diff --git a/js/app/feedCoordinator.js b/js/app/feedCoordinator.js index 73138370..5281941d 100644 --- a/js/app/feedCoordinator.js +++ b/js/app/feedCoordinator.js @@ -1016,8 +1016,21 @@ export function createFeedCoordinator(deps) { const recommendationFeed = feedType === FEED_TYPES.FOR_YOU || feedType === FEED_TYPES.EXPLORE; + let exploreActivation = null; if (recommendationFeed && typeof this.ensureExploreDataService === "function") { - await this.ensureExploreDataService(); + // Recommendation indexes are an enhancement, not a prerequisite for + // showing cached videos. Activating the worker here used to leave a + // returning For You view stuck on its static loading markup whenever + // worker startup was slow or unavailable. + exploreActivation = Promise.resolve(this.ensureExploreDataService()).catch( + (error) => { + devLogger.warn( + `[Application] Recommendation data activation failed for ${feedType}:`, + error, + ); + return null; + }, + ); } else if (this.exploreDataService?.setActive) { this.exploreDataService.setActive(false); } @@ -1117,6 +1130,23 @@ export function createFeedCoordinator(deps) { if (this.videoListView) { this.videoListView.state.videosMap = this.videosMap; } + + // Re-score once the optional recommendation indexes are ready, but only + // if the user is still looking at this feed. The first render above is + // deliberately cache-first and must not wait for worker startup. + if (exploreActivation) { + void exploreActivation.then(() => { + if (!this.isFeedActive(feedType)) { + return; + } + return this.refreshFeed(feedType, { reason: "recommendation-data-ready" }); + }).catch((error) => { + devLogger.warn( + `[Application] Failed to refresh ${feedType} after recommendation data activation:`, + error, + ); + }); + } }, /** diff --git a/tests/app/feedCoordinator.test.mjs b/tests/app/feedCoordinator.test.mjs index be34d9fd..e8c989e1 100644 --- a/tests/app/feedCoordinator.test.mjs +++ b/tests/app/feedCoordinator.test.mjs @@ -85,3 +85,61 @@ test('createFeedCoordinator - loadForYouVideos', async (t) => { assert.strictEqual(app.videoSubscription, 'mock-subscription', 'Should update videoSubscription'); }); }); + +test("loadForYouVideos renders without waiting for recommendation worker activation", async () => { + let resolveActivation; + const activation = new Promise((resolve) => { + resolveActivation = resolve; + }); + let loadVideosStarted = false; + const mockDeps = { + devLogger: { log: mock.fn(), warn: mock.fn() }, + userLogger: { warn: mock.fn() }, + nostrClient: {}, + getSidebarLoadingMarkup: mock.fn(() => '