Browse Source

correct search page

Nostr-Signature: 2a93ec13a9ae177dfd3f4b59cfc7341e9a3a073367b43976ea161802efc76c44 573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc 7821315a6b3b5761c8938fd9b247db0f3344336fbf706b1fb5921ee5645b0f77298cb41a96cd5d1afa8e05c25eb7d64d69d42de585cdd016ad1425ca5b1f4772
main
Silberengel 2 weeks ago
parent
commit
45e7b8c6b3
  1. 1
      nostr/commit-signatures.jsonl
  2. 66
      src/routes/api/search/+server.ts
  3. 63
      src/routes/search/+page.svelte

1
nostr/commit-signatures.jsonl

@ -129,3 +129,4 @@
{"kind":1640,"pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","created_at":1772300935,"tags":[["author","Silberengel","silberengel7@protonmail.com"],["message","bug-fixes"]],"content":"Signed commit: bug-fixes","id":"3618c494d594408165ebf461e290676817ab6cc8b0b076ccc02b35a487ae8da1","sig":"d9106ce1318e703df1c366835be69c0cab12fba3a9be0fed944b17e55fd3b44f3fc9d45b32366d1d237452f099ab3b07f8ad6199660972ce571ec23ae264e873"} {"kind":1640,"pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","created_at":1772300935,"tags":[["author","Silberengel","silberengel7@protonmail.com"],["message","bug-fixes"]],"content":"Signed commit: bug-fixes","id":"3618c494d594408165ebf461e290676817ab6cc8b0b076ccc02b35a487ae8da1","sig":"d9106ce1318e703df1c366835be69c0cab12fba3a9be0fed944b17e55fd3b44f3fc9d45b32366d1d237452f099ab3b07f8ad6199660972ce571ec23ae264e873"}
{"kind":1640,"pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","created_at":1772302842,"tags":[["author","Silberengel","silberengel7@protonmail.com"],["message","bug-fixes"]],"content":"Signed commit: bug-fixes","id":"5c4b680a04363718d8de6aa05b824d30417221a9095be57bb9a7c2cf01c5af59","sig":"51ffa554e83a6a3c4ca97cffc7eca67e770ca822e43e9e78692bafcd63401c4df84e1fe030592e63982b509d3cfa8bfbd57c6b4257661b0f43adedef335c7575"} {"kind":1640,"pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","created_at":1772302842,"tags":[["author","Silberengel","silberengel7@protonmail.com"],["message","bug-fixes"]],"content":"Signed commit: bug-fixes","id":"5c4b680a04363718d8de6aa05b824d30417221a9095be57bb9a7c2cf01c5af59","sig":"51ffa554e83a6a3c4ca97cffc7eca67e770ca822e43e9e78692bafcd63401c4df84e1fe030592e63982b509d3cfa8bfbd57c6b4257661b0f43adedef335c7575"}
{"kind":1640,"pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","created_at":1772303976,"tags":[["author","Silberengel","silberengel7@protonmail.com"],["message","bug-fix"]],"content":"Signed commit: bug-fix","id":"a8e7a4f38f815abaa8cc807e43da842cc4715ff41e722ee6657cae57915b753e","sig":"9c427e839796099f8fdfc0dc4a6f4500ecb1835dbf62cf0b1d3dbe8f98c98a1bc7b28266cbc7a993a18f905ec6e57c610e10492c88e7f863319cefb2eab58fdc"} {"kind":1640,"pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","created_at":1772303976,"tags":[["author","Silberengel","silberengel7@protonmail.com"],["message","bug-fix"]],"content":"Signed commit: bug-fix","id":"a8e7a4f38f815abaa8cc807e43da842cc4715ff41e722ee6657cae57915b753e","sig":"9c427e839796099f8fdfc0dc4a6f4500ecb1835dbf62cf0b1d3dbe8f98c98a1bc7b28266cbc7a993a18f905ec6e57c610e10492c88e7f863319cefb2eab58fdc"}
{"kind":1640,"pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","created_at":1772305338,"tags":[["author","Silberengel","silberengel7@protonmail.com"],["message","allow forks"]],"content":"Signed commit: allow forks","id":"47f1aa9a47f4488a9babf752466bb2e4cb7974bd67aa827a4b70c57bac839750","sig":"3652f31ee120f894f7dbb04bb2e625dc2f97758b9fe99fa24aa0efe23872851aceb6f460d2c479bbfc9aa495b5c6d993b2ec7d65e21c90ee8ca6a9f23bfac498"}

66
src/routes/api/search/+server.ts

@ -171,8 +171,18 @@ export const GET: RequestHandler = async (event) => {
const relayResult = await relayFetchPromise; const relayResult = await relayFetchPromise;
relayResults = relayResult.filtered; relayResults = relayResult.filtered;
allRelayRepos = relayResult.allRepos; allRelayRepos = relayResult.allRepos;
logger.debug({
filteredCount: relayResults.length,
allReposCount: allRelayRepos.length,
query: queryTrimmed.substring(0, 50)
}, 'Relay fetch completed successfully');
} catch (err) { } catch (err) {
logger.debug({ error: err }, 'Failed to get relay results'); logger.warn({
error: err instanceof Error ? err.message : String(err),
errorStack: err instanceof Error ? err.stack : undefined,
query: queryTrimmed.substring(0, 50),
cachedCount: cachedResults.length
}, 'Failed to get relay results - will return cached results if available');
} }
// Step 4 & 5: Deduplicate results (cached + relay) using deduplication keys // Step 4 & 5: Deduplicate results (cached + relay) using deduplication keys
@ -252,6 +262,54 @@ export const GET: RequestHandler = async (event) => {
}, 'Cache updated with filtered relay results (no unfiltered repos available)'); }, 'Cache updated with filtered relay results (no unfiltered repos available)');
} }
// If we have no results and cache was empty, try a simple fetch to populate cache
if (allResults.size === 0 && cachedRepos.length === 0 && allRelayRepos.length === 0) {
logger.info({ query: queryTrimmed.substring(0, 50) }, 'No results found and cache is empty - attempting simple relay fetch to populate cache');
try {
// Try a simple fetch of recent repo announcements to populate cache
const simpleFetch = nostrClient.fetchEvents([{
kinds: [KIND.REPO_ANNOUNCEMENT],
limit: 100
}]).catch(err => {
logger.debug({ error: err }, 'Simple cache population fetch failed');
return [] as NostrEvent[];
});
const simpleResults = await Promise.race([
simpleFetch,
new Promise<NostrEvent[]>((resolve) => {
setTimeout(() => {
logger.debug({ query: queryTrimmed.substring(0, 50) }, 'Simple cache population fetch timeout (5s)');
resolve([]);
}, 5000);
})
]);
if (simpleResults.length > 0) {
// Update cache with fetched repos
eventCache.set(cacheKey, simpleResults);
logger.info({
fetchedCount: simpleResults.length,
query: queryTrimmed.substring(0, 50)
}, 'Cache populated with simple fetch - filtering results');
// Filter the newly fetched repos
const newFiltered = filterRepos(simpleResults, queryTrimmed, queryLower, resolvedPubkey, decodedAddress);
// Add to allResults map
newFiltered.forEach(r => {
const key = getDeduplicationKey(r);
const existing = allResults.get(key);
if (!existing || r.created_at > existing.created_at) {
allResults.set(key, r);
}
});
}
} catch (err) {
logger.debug({ error: err, query: queryTrimmed.substring(0, 50) }, 'Simple cache population failed');
}
}
const mergedResults = Array.from(allResults.values()); const mergedResults = Array.from(allResults.values());
logger.debug({ logger.debug({
@ -367,7 +425,11 @@ export const GET: RequestHandler = async (event) => {
query: queryTrimmed.substring(0, 50), query: queryTrimmed.substring(0, 50),
resultCount: limitedResults.length, resultCount: limitedResults.length,
totalMatches: mergedResults.length, totalMatches: mergedResults.length,
fromCache cachedCount: cachedResults.length,
relayCount: relayResults.length,
fromCache,
hasCachedRepos: cachedRepos.length > 0,
hasRelayRepos: allRelayRepos.length > 0
}, 'Search completed'); }, 'Search completed');
return json({ return json({

63
src/routes/search/+page.svelte

@ -101,26 +101,53 @@
error = null; error = null;
results = null; // Reset results results = null; // Reset results
const searchQuery = query.trim();
const searchUrl = `/api/search?q=${encodeURIComponent(searchQuery)}`;
console.log('[Search] Starting search:', { query: searchQuery, url: searchUrl, hasUserPubkey: !!userPubkeyHex });
try { try {
const headers: Record<string, string> = {}; const headers: Record<string, string> = {};
if (userPubkeyHex) { if (userPubkeyHex) {
headers['X-User-Pubkey'] = userPubkeyHex; headers['X-User-Pubkey'] = userPubkeyHex;
} }
const response = await fetch(`/api/search?q=${encodeURIComponent(query.trim())}`, { console.log('[Search] Fetching:', { url: searchUrl, headers });
const response = await fetch(searchUrl, {
headers, headers,
signal: currentAbortController.signal signal: currentAbortController.signal
}); });
console.log('[Search] Response received:', {
status: response.status,
statusText: response.statusText,
ok: response.ok,
headers: Object.fromEntries(response.headers.entries())
});
// Check if request was aborted // Check if request was aborted
if (currentAbortController.signal.aborted) { if (currentAbortController.signal.aborted) {
console.log('[Search] Request was aborted');
return; return;
} }
if (response.ok) { if (response.ok) {
const data = await response.json(); const data = await response.json();
console.log('[Search] Response data:', {
query: data.query,
total: data.total,
reposCount: data.results?.repos?.length || 0,
fromCache: data.fromCache,
fullData: data
});
// Verify the response matches our current query (in case of race conditions) // Verify the response matches our current query (in case of race conditions)
if (data.query !== query.trim()) { if (data.query !== searchQuery) {
console.warn('[Search] Response query mismatch:', {
expected: searchQuery,
received: data.query
});
// Response is for a different query, ignore it // Response is for a different query, ignore it
return; return;
} }
@ -132,22 +159,50 @@
repos: Array.isArray(apiResults.repos) ? apiResults.repos : [], repos: Array.isArray(apiResults.repos) ? apiResults.repos : [],
total: typeof data.total === 'number' ? data.total : (apiResults.repos?.length || 0) total: typeof data.total === 'number' ? data.total : (apiResults.repos?.length || 0)
}; };
console.log('[Search] Search completed successfully:', {
resultCount: results.repos.length,
total: results.total
});
} else { } else {
const data = await response.json(); let errorData;
error = data.error || 'Search failed'; try {
errorData = await response.json();
} catch {
errorData = { error: `HTTP ${response.status}: ${response.statusText}` };
}
console.error('[Search] Search failed:', {
status: response.status,
statusText: response.statusText,
error: errorData.error || errorData,
fullError: errorData
});
error = errorData.error || 'Search failed';
results = null; // Clear results on error results = null; // Clear results on error
} }
} catch (err) { } catch (err) {
// Ignore abort errors // Ignore abort errors
if (err instanceof Error && err.name === 'AbortError') { if (err instanceof Error && err.name === 'AbortError') {
console.log('[Search] Request was aborted');
return; return;
} }
console.error('[Search] Search error:', {
error: err,
message: err instanceof Error ? err.message : String(err),
stack: err instanceof Error ? err.stack : undefined,
query: searchQuery
});
error = err instanceof Error ? err.message : 'Search failed'; error = err instanceof Error ? err.message : 'Search failed';
results = null; // Clear results on error results = null; // Clear results on error
} finally { } finally {
// Only update loading state if this is still the current search // Only update loading state if this is still the current search
if (currentAbortController === searchAbortController) { if (currentAbortController === searchAbortController) {
loading = false; loading = false;
console.log('[Search] Loading state set to false');
} }
} }
} }

Loading…
Cancel
Save