diff --git a/js/feedEngine/sources.js b/js/feedEngine/sources.js index b8994fe7..bf7bf2a3 100644 --- a/js/feedEngine/sources.js +++ b/js/feedEngine/sources.js @@ -66,6 +66,7 @@ export function createSubscriptionAuthorsSource({ service } = {}) { const resolvedService = resolveService(service, nostrService); return async function subscriptionAuthorsSource(context = {}) { + context?.log?.("[subscriptions-source] START"); const runtimeAuthors = toArray( context?.runtime?.subscriptionAuthors || context?.runtime?.authors ).map(normalizeAuthor); @@ -88,6 +89,8 @@ export function createSubscriptionAuthorsSource({ service } = {}) { [...runtimeAuthors, ...configAuthors, ...hookAuthors].filter(Boolean) ); + context?.log?.(`[subscriptions-source] Resolved ${authors.size} authors.`); + if (!authors.size) { return []; } @@ -115,12 +118,16 @@ export function createSubscriptionAuthorsSource({ service } = {}) { let videos = []; try { if (hasTargetedLookup) { + context?.log?.("[subscriptions-source] Calling getActiveVideosByAuthors..."); videos = await Promise.resolve( resolvedService.getActiveVideosByAuthors(authorList, options) ); + context?.log?.(`[subscriptions-source] getActiveVideosByAuthors returned ${videos.length} videos.`); if (!videos.length && typeof resolvedService.fetchVideosByAuthors === "function") { + context?.log?.("[subscriptions-source] Cache empty. Calling fetchVideosByAuthors..."); const fetched = await resolvedService.fetchVideosByAuthors(authorList, options); + context?.log?.(`[subscriptions-source] fetchVideosByAuthors returned ${fetched ? fetched.length : 0} videos.`); if (Array.isArray(fetched) && fetched.length > 0) { videos = fetched; } diff --git a/js/nostr/toolkit.js b/js/nostr/toolkit.js index f3314803..829be9c8 100644 --- a/js/nostr/toolkit.js +++ b/js/nostr/toolkit.js @@ -581,6 +581,7 @@ export function shimLegacySimplePoolMethods(pool) { : 7000; timer = setTimeout(() => { + devLogger.warn(`[toolkit] pool.list timed out after ${timeoutMs}ms.`); timer = null; try { subscription.unsub?.(); diff --git a/js/services/nostrService.js b/js/services/nostrService.js index 5c420515..7a5ea3f0 100644 --- a/js/services/nostrService.js +++ b/js/services/nostrService.js @@ -157,6 +157,17 @@ function extractSnapshotPreview(message) { return sanitizeSnapshotPreview(selected || ""); } +function getActiveKey(video) { + if (video.videoRootId) { + return `ROOT:${video.videoRootId}`; + } + const dTag = video.tags?.find((t) => Array.isArray(t) && t[0] === "d"); + if (dTag && typeof dTag[1] === "string") { + return `${video.pubkey}:${dTag[1]}`; + } + return `LEGACY:${video.id}`; +} + function resolveDirectMessageRemotePubkey(message, actorPubkey = "") { const normalizedActor = normalizeHexPubkey(actorPubkey); @@ -1165,10 +1176,11 @@ export class NostrService { return []; } + this.log(`[nostrService] fetchVideosByAuthors START. Authors: ${authorList.length}`); + const requestedLimit = Number(options?.limit); const resolvedLimit = this.nostrClient.clampVideoRequestLimit( - requestedLimit, - DEFAULT_VIDEO_REQUEST_LIMIT + requestedLimit ); const filter = { @@ -1183,31 +1195,38 @@ export class NostrService { const invalidNotes = []; try { + this.log(`[nostrService] Querying ${this.nostrClient.relays.length} relays...`); await Promise.all( this.nostrClient.relays.map(async (url) => { - const events = await this.nostrClient.pool.list([url], [filter]); - for (const evt of events) { - if (evt && evt.id) { - this.nostrClient.rawEvents.set(evt.id, evt); - } - const vid = convertEventToVideo(evt); - if (vid.invalid) { - invalidNotes.push({ id: vid.id, reason: vid.reason }); - } else { - if ( - this.nostrClient && - typeof this.nostrClient.applyRootCreatedAt === "function" - ) { - this.nostrClient.applyRootCreatedAt(vid); + try { + this.log(`[nostrService] Querying relay: ${url}`); + const events = await this.nostrClient.pool.list([url], [filter]); + this.log(`[nostrService] Relay ${url} returned ${events.length} events.`); + for (const evt of events) { + if (evt && evt.id) { + this.nostrClient.rawEvents.set(evt.id, evt); } - const activeKey = getActiveKey(vid); - if (vid.deleted) { - this.recordTombstone(activeKey, vid.created_at); + const vid = convertEventToVideo(evt); + if (vid.invalid) { + invalidNotes.push({ id: vid.id, reason: vid.reason }); } else { - this.applyTombstoneGuard(vid); + if ( + this.nostrClient && + typeof this.nostrClient.applyRootCreatedAt === "function" + ) { + this.nostrClient.applyRootCreatedAt(vid); + } + const activeKey = getActiveKey(vid); + if (vid.deleted) { + this.nostrClient.recordTombstone(activeKey, vid.created_at); + } else { + this.nostrClient.applyTombstoneGuard(vid); + } + localAll.set(evt.id, vid); } - localAll.set(evt.id, vid); } + } catch (relayErr) { + this.log(`[nostrService] Relay ${url} failed:`, relayErr); } }) ); diff --git a/js/subscriptions.js b/js/subscriptions.js index 570c5343..b239274d 100644 --- a/js/subscriptions.js +++ b/js/subscriptions.js @@ -398,17 +398,20 @@ class SubscriptionsManager { } async ensureLoaded(actorHex) { + devLogger.log("[SubscriptionsManager] ensureLoaded start", actorHex); const normalizedActor = normalizeHexPubkey(actorHex) || actorHex; if (!normalizedActor) { return; } if (this.loaded && this.currentUserPubkey === normalizedActor) { + devLogger.log("[SubscriptionsManager] ensureLoaded already loaded"); return; } if (this.loadingPromise) { try { + devLogger.log("[SubscriptionsManager] ensureLoaded awaiting existing promise"); await this.loadingPromise; } catch (error) { throw error; @@ -431,6 +434,7 @@ class SubscriptionsManager { ) ), ]); + devLogger.log("[SubscriptionsManager] ensureLoaded success"); } catch (error) { userLogger.warn("[SubscriptionsManager] ensureLoaded timed out or failed:", error); } finally { @@ -870,7 +874,9 @@ class SubscriptionsManager { if (typeof nostrService?.awaitInitialLoad === "function") { try { + devLogger.log("[SubscriptionsManager] awaiting nostrService initial load..."); await nostrService.awaitInitialLoad(); + devLogger.log("[SubscriptionsManager] nostrService initial load done."); } catch (error) { devLogger.warn( "[SubscriptionsManager] Failed to await nostrService initial load:", @@ -906,7 +912,9 @@ class SubscriptionsManager { try { this.isRunningFeed = true; + devLogger.log("[SubscriptionsManager] Calling engine.run('subscriptions')..."); const result = await engine.run("subscriptions", runOptions); + devLogger.log("[SubscriptionsManager] engine.run complete. Items:", result?.items?.length); const videos = Array.isArray(result?.items) ? result.items.map((item) => item?.video).filter(Boolean)