Compare commits

...

5 Commits

5 changed files with 49 additions and 26 deletions

View File

@@ -556,9 +556,8 @@ import { initPostCards } from './js/post-interactions2.mjs';
const now = Math.floor(Date.now() / 1000);
const since = newestKnown > 0 ? Math.max(0, newestKnown - 30) : (now - 3600);
// Fire-and-forget: NDK.subscribe already calls trackUsers internally,
// but doing it explicitly avoids relying on internal timing.
void warmOutbox(authors).catch(() => {});
// NDK.subscribe already calls outboxTracker.trackUsers internally,
// so no explicit warmOutbox call is needed here.
subscribe(
{ kinds: [1], authors, since },
@@ -594,11 +593,8 @@ import { initPostCards } from './js/post-interactions2.mjs';
}
if (newAuthors.length > 0) {
try {
await warmOutbox(newAuthors);
} catch (e) {
console.warn('[feed.html] warmOutbox for new authors failed (non-blocking):', e?.message || e);
}
// NDK's fetchEvents/subscribe already calls outboxTracker.trackUsers
// internally for author-based filters, so no explicit warmOutbox needed.
try {
await fetchFeedWindow(newAuthors, { limit: INITIAL_POSTS_LOAD });
renderFeed();

View File

@@ -1038,7 +1038,7 @@ export async function getRelayData() {
pendingRequests.set(requestId, { resolve, reject });
// Set timeout
// Set timeout (15s — worker may be busy processing outbox/NDK events)
setTimeout(() => {
if (pendingRequests.has(requestId)) {
pendingRequests.delete(requestId);
@@ -1046,7 +1046,7 @@ export async function getRelayData() {
console.warn('[init-ndk] Get relay data timeout, returning empty array');
resolve([]);
}
}, 5000);
}, 15000);
ndkWorker.port.postMessage({
type: 'getRelayData',
@@ -1071,7 +1071,7 @@ export async function getRelayStats() {
pendingRequests.set(requestId, { resolve, reject });
// Set timeout
// Set timeout (15s — worker may be busy processing outbox/NDK events)
setTimeout(() => {
if (pendingRequests.has(requestId)) {
pendingRequests.delete(requestId);
@@ -1079,7 +1079,7 @@ export async function getRelayStats() {
console.warn('[init-ndk] Get relay stats timeout, returning empty object');
resolve({});
}
}, 5000);
}, 15000);
ndkWorker.port.postMessage({
type: 'getRelayStats',

View File

@@ -1,5 +1,5 @@
{
"VERSION": "v0.7.44",
"VERSION_NUMBER": "0.7.44",
"BUILD_DATE": "2026-06-26T13:54:18.538Z"
"VERSION": "v0.7.49",
"VERSION_NUMBER": "0.7.49",
"BUILD_DATE": "2026-06-26T14:27:42.415Z"
}

View File

@@ -6470,11 +6470,22 @@ async function handleGetDiscoveredRelays(requestId, port) {
try {
const trackerData = ndk?.outboxTracker?.data;
if (trackerData) {
// Debug: log what the LRU cache looks like
const trackerKeys = typeof trackerData.keys === 'function' ? Array.from(trackerData.keys()) :
(trackerData instanceof Map ? Array.from(trackerData.keys()) : []);
console.log('[Worker] getDiscoveredRelays: tracker has', trackerKeys.length, 'entries');
let pubkeysProcessed = 0;
let pubkeysWithWriteRelays = 0;
const collectForPubkey = (pubkey) => {
pubkeysProcessed++;
try {
const outboxItem = trackerData.get(pubkey);
const writeRelays = outboxItem?.writeRelays;
if (!writeRelays) return;
if (!outboxItem) return;
const writeRelays = outboxItem.writeRelays;
if (!writeRelays || writeRelays.size === 0) return;
pubkeysWithWriteRelays++;
for (const r of writeRelays) {
const rUrl = r?.url ? normalizeRelayUrl(r.url) : (typeof r === 'string' ? normalizeRelayUrl(r) : null);
if (!rUrl) continue;
@@ -6516,7 +6527,26 @@ async function handleGetDiscoveredRelays(requestId, port) {
for (const pubkey of trackerData.keys()) {
collectForPubkey(pubkey);
}
iterated = true;
}
// Strategy 4: try internal storage if LRU cache has it
if (!iterated) {
try {
// Some LRU caches store entries in an internal Map or object
const internal = trackerData._map || trackerData.cache || trackerData._cache;
if (internal instanceof Map) {
for (const [pubkey] of internal) {
collectForPubkey(pubkey);
}
iterated = true;
}
} catch (_) {}
}
console.log('[Worker] getDiscoveredRelays: processed', pubkeysProcessed, 'pubkeys,', pubkeysWithWriteRelays, 'with write relays, iterated:', iterated, ', relayServesPubkeys size:', relayServesPubkeys.size);
} else {
console.log('[Worker] getDiscoveredRelays: no outbox tracker data available');
}
} catch (err) {
console.warn('[Worker] getDiscoveredRelays: outbox tracker inversion failed:', err?.message || err);
@@ -6900,7 +6930,10 @@ self.onconnect = (event) => {
break;
case 'warmOutbox':
await handleWarmOutbox(requestId, pubkeys, port);
// Don't await — trackUsers involves network I/O to outbox pool
// relays and would block the entire message dispatch loop,
// starving getRelayData/getRelayStats messages.
void handleWarmOutbox(requestId, pubkeys, port);
break;
case 'setRelayEventLogging':

View File

@@ -1586,14 +1586,8 @@ const versionInfo = await getVersion();
// Refresh relay table every 5 seconds
setInterval(refreshRelayData, 5000);
// Refresh discovered relays (outbox) on a slower 15s interval,
// and only when the section is expanded, to avoid blocking the
// worker's message queue with LRU cache iteration on every 5s cycle.
setInterval(() => {
if (discoveredRelaysExpanded) {
void refreshDiscoveredRelays();
}
}, 15000);
// Discovered relays are fetched only on manual expand click — no
// auto-refresh interval, to avoid blocking the worker's message queue.
// Sync connection history toggle state from localStorage
connectionHistoryEnabled = localStorage.getItem('relayConnectionHistory') === 'true';