Merge pull request #1755 from PR0M3TH3AN/fix-nip07-login-and-list-sync-2738736650874322508

Fix NIP-07 Login Slowness and Prevent List Data Loss on Network Failure
This commit is contained in:
thePR0M3TH3AN authored and GitHub committed 2026-01-26 15:16:40 -05:00
commit de463a86f4
5 files changed
+57 -35

No files matched your search

+16 -23
View File
@@ -548,29 +548,22 @@ async function fetchLatestListEvent(filter, contextLabel = "admin-list") {
}
let events = [];
try {
if (pubkey) {
events = await nostrClient.fetchListIncrementally({
kind,
pubkey,
dTag,
relayUrls: relays
});
} else {
// Fallback for non-specific queries
const normalizedFilter = {
kinds: [kind],
limit: 50
};
if (dTag) normalizedFilter["#d"] = [dTag];
if (filter.authors) normalizedFilter.authors = filter.authors;
events = await nostrClient.pool.list(relays, [normalizedFilter]);
}
} catch (error) {
devLogger.warn(
`[adminListStore] Fetch failed for ${contextLabel}:`,
error,
);
if (pubkey) {
events = await nostrClient.fetchListIncrementally({
kind,
pubkey,
dTag,
relayUrls: relays
});
} else {
// Fallback for non-specific queries
const normalizedFilter = {
kinds: [kind],
limit: 50
};
if (dTag) normalizedFilter["#d"] = [dTag];
if (filter.authors) normalizedFilter.authors = filter.authors;
events = await nostrClient.pool.list(relays, [normalizedFilter]);
}
if (!events || !events.length) {
+21 -6
View File
@@ -3520,6 +3520,9 @@ export class NostrClient {
chunks.push(normalizedRelays.slice(i, i + concurrencyLimit));
}
let anySuccess = false;
const failures = [];
for (const chunk of chunks) {
const promises = chunk.map(async (relayUrl) => {
let lastSeen = this.getSyncLastSeen(
@@ -3587,7 +3590,7 @@ export class NostrClient {
this.updateSyncLastSeen(kind, normalizedPubkey, dTag, relayUrl, maxCreated);
}
return events;
return { events, ok: true };
} catch (error) {
// Fallback to full fetch if incremental failed or if relay error
if (!doFullFetch) {
@@ -3606,26 +3609,38 @@ export class NostrClient {
if (maxCreated > 0) {
this.updateSyncLastSeen(kind, normalizedPubkey, dTag, relayUrl, maxCreated);
}
return events || [];
return { events: events || [], ok: true };
} catch (fallbackError) {
devLogger.warn(`[fetchListIncrementally] Full fetch fallback failed for ${relayUrl}`, fallbackError);
return [];
return { error: fallbackError, ok: false };
}
} else {
devLogger.warn(`[fetchListIncrementally] Fetch failed for ${relayUrl}`, error);
return [];
return { error, ok: false };
}
}
});
const chunkResults = await Promise.all(promises);
for (const res of chunkResults) {
if (Array.isArray(res)) {
results.push(...res);
if (res.ok) {
anySuccess = true;
if (Array.isArray(res.events)) {
results.push(...res.events);
}
} else {
failures.push(res.error);
}
}
}
if (!anySuccess && normalizedRelays.length > 0) {
const error = new Error("All relays failed to fetch list.");
error.code = "fetch-failed";
error.failures = failures;
throw error;
}
// Deduplicate by ID
const uniqueEvents = new Map();
for (const ev of results) {
+11 -2
View File
@@ -270,12 +270,21 @@ export async function requestEnablePermissions(
let lastError = null;
for (const options of permissionVariants) {
// If specific permissions are requested (variants 1 & 2), fail fast (3s)
// to avoid hanging if the extension doesn't support the structured format.
// If we fall back to standard enable() (null), allow the full user interaction time.
const variantTimeoutOverrides = options
? {
timeoutMs: Math.min(NIP07_LOGIN_TIMEOUT_MS, getEnableVariantTimeoutMs()),
timeoutMs: 3000,
retryMultiplier: 1,
}
: { retryMultiplier: 1 };
: {
timeoutMs: Math.min(
NIP07_LOGIN_TIMEOUT_MS,
getEnableVariantTimeoutMs(),
),
retryMultiplier: 1,
};
try {
await runNip07WithRetry(
+8
View File
@@ -505,6 +505,14 @@ class HashtagPreferencesService {
}
if (!events.length) {
if (fetchError) {
userLogger.warn(
`${LOG_PREFIX} Failed to load hashtag preferences (keeping local state if any).`,
fetchError,
);
return;
}
// If we failed to fetch (network error) but already have data for this user,
// preserve the existing state instead of wiping it.
// If fetchListIncrementally returns empty, it means no new updates or full fetch yielded nothing.
+1 -4
View File
@@ -1096,10 +1096,7 @@ class UserBlockListManager {
} catch (error) {
userLogger.error("[UserBlockList] loadBlocks failed:", error);
applyBlockedPubkeys([], { source: "fast", reason: "load-error", error });
this.blockEventId = null;
this.blockEventCreatedAt = null;
userLogger.error("[UserBlockList] loadBlocks failed (keeping local state):", error);
emitStatus({ status: "error", error });
} finally {
this.loaded = true;