This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

fix

+168 -9
+160
app/src/app/api/bluesky/feed-simple/route.ts
··· 1 + import { NextRequest, NextResponse } from 'next/server'; 2 + import { createClient } from '@supabase/supabase-js'; 3 + import { containsBannedWords, sanitizeText } from '@/lib/content-filter'; 4 + 5 + // Configure this route as dynamic to prevent any caching 6 + export const dynamic = 'force-dynamic'; 7 + 8 + // Define type for our database entry 9 + interface FlushingRecord { 10 + id: string | number; 11 + uri: string; 12 + cid: string; 13 + did: string; 14 + text: string; 15 + emoji: string; 16 + created_at: string; 17 + handle?: string; 18 + } 19 + 20 + // Type for the processed entry for the client 21 + interface ProcessedEntry { 22 + id: string | number; 23 + uri: string; 24 + cid: string; 25 + authorDid: string; 26 + authorHandle: string; 27 + text: string; 28 + emoji: string; 29 + createdAt: string; 30 + } 31 + 32 + // Constants 33 + const MAX_ENTRIES = 20; 34 + 35 + // Supabase client - using environment variables 36 + const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL || ''; 37 + const supabaseKey = process.env.SUPABASE_SERVICE_ROLE_KEY || ''; 38 + 39 + export async function GET(request: NextRequest) { 40 + // Debug log the incoming request 41 + console.log(`\n=== SIMPLE FEED REQUEST @ ${new Date().toISOString()} ===`); 42 + console.log(`URL: ${request.url}`); 43 + 44 + try { 45 + const url = new URL(request.url); 46 + const beforeCursor = url.searchParams.get('before'); 47 + 48 + console.log(`Request params: beforeCursor=${beforeCursor || 'none'}`); 49 + 50 + // If we don't have Supabase credentials, return an error 51 + if (!supabaseUrl || !supabaseKey) { 52 + console.error('Missing Supabase credentials'); 53 + return NextResponse.json( 54 + { error: 'Server configuration error' }, 55 + { status: 500 } 56 + ); 57 + } 58 + 59 + // Create Supabase client 60 + const supabase = createClient(supabaseUrl, supabaseKey); 61 + 62 + // Show highest ID in database for debugging 63 + const { data: maxIdResult } = await supabase 64 + .from('flushing_records') 65 + .select('id') 66 + .order('id', { ascending: false }) 67 + .limit(1); 68 + 69 + console.log('Highest ID in database:', maxIdResult?.[0]?.id || 'unknown'); 70 + 71 + let entries: FlushingRecord[] = []; 72 + 73 + if (beforeCursor) { 74 + // Pagination query: get entries older than the cursor 75 + console.log(`Fetching entries older than ID ${beforeCursor}`); 76 + 77 + const { data, error } = await supabase 78 + .from('flushing_records') 79 + .select('*') 80 + .lt('id', beforeCursor) 81 + .order('id', { ascending: false }) 82 + .limit(MAX_ENTRIES); 83 + 84 + if (error) { 85 + throw new Error(`Database query error: ${error.message}`); 86 + } 87 + 88 + entries = data || []; 89 + } else { 90 + // Main query: get the most recent entries 91 + console.log('Fetching latest entries'); 92 + 93 + // Standard query approach - simplest and most reliable 94 + const { data, error } = await supabase 95 + .from('flushing_records') 96 + .select('*') 97 + .order('id', { ascending: false }) 98 + .limit(MAX_ENTRIES); 99 + 100 + if (error) { 101 + throw new Error(`Database query error: ${error.message}`); 102 + } 103 + 104 + entries = data || []; 105 + } 106 + 107 + console.log(`Query returned ${entries.length} entries`); 108 + 109 + if (entries.length > 0) { 110 + console.log('Top 5 entries:'); 111 + for (let i = 0; i < Math.min(5, entries.length); i++) { 112 + const entry = entries[i]; 113 + console.log(` ${i+1}. ID: ${entry.id}, Handle: ${entry.handle || 'unknown'}, Text: "${entry.text.substring(0, 20)}..."`); 114 + } 115 + } else { 116 + console.warn('No entries found - this may indicate a database problem'); 117 + } 118 + 119 + // Process entries for the client 120 + const processedEntries = entries.map((entry) => { 121 + // Skip entries with banned content 122 + if (containsBannedWords(entry.text)) { 123 + return null; 124 + } 125 + 126 + // Use the handle from the database, or extract from DID as fallback 127 + const authorHandle = entry.handle || 128 + (entry.did.startsWith('did:plc:') ? 129 + `${entry.did.substring(8, 16)}...` : 130 + `${entry.did.substring(0, 8)}...`); 131 + 132 + // Return processed entry 133 + return { 134 + id: entry.id, 135 + uri: entry.uri, 136 + cid: entry.cid, 137 + authorDid: entry.did, 138 + authorHandle: authorHandle, 139 + text: sanitizeText(entry.text), 140 + emoji: entry.emoji, 141 + createdAt: entry.created_at 142 + } as ProcessedEntry; 143 + }); 144 + 145 + // Filter out null entries (those with banned content) 146 + const filteredEntries = processedEntries.filter((entry): entry is ProcessedEntry => entry !== null); 147 + 148 + // Return the processed entries 149 + return NextResponse.json({ 150 + entries: filteredEntries, 151 + source: 'simple-query' 152 + }); 153 + } catch (error: any) { 154 + console.error('Error in simple feed API:', error); 155 + return NextResponse.json( 156 + { error: 'Failed to fetch feed', message: error.message }, 157 + { status: 500 } 158 + ); 159 + } 160 + }
+8 -9
app/src/app/page.tsx
··· 189 189 createdAt: new Date().toISOString() 190 190 }; 191 191 192 - console.log('Adding temporary entry to feed:', tempEntry); 192 + console.log('Adding temporary entry to feed for immediate display:', tempEntry); 193 193 194 194 // Add the temporary entry to the top of the feed 195 195 setEntries(prevEntries => [tempEntry, ...prevEntries]); ··· 221 221 setLoading(true); 222 222 setError(null); 223 223 224 - // Use the new direct API endpoint that bypasses all caching 225 224 // Add a timestamp to ensure we bypass browser caching 226 225 const timestamp = Date.now(); 227 226 228 - // Use our new direct API endpoint which has a more reliable implementation 229 - const url = `/api/bluesky/feed-direct?_t=${timestamp}`; 227 + // Use our simple API endpoint for reliability 228 + const url = `/api/bluesky/feed-simple?_t=${timestamp}`; 230 229 231 230 console.log(`Fetching feed from ${url} at ${new Date().toISOString()}`); 232 231 ··· 304 303 console.log(`Loading older entries before ID ${oldestEntry.id}`); 305 304 306 305 // Use the oldest entry's ID as the cursor, plus add a unique timestamp 307 - // Use our direct API for more reliable pagination 308 - const url = `/api/bluesky/feed-direct?before=${oldestEntry.id}&_t=${Date.now()}`; 306 + // Use our simple API for reliable pagination 307 + const url = `/api/bluesky/feed-simple?before=${oldestEntry.id}&_t=${Date.now()}`; 309 308 310 309 const response = await fetch(url, { 311 310 cache: 'no-store', ··· 486 485 setLoading(true); 487 486 setError(null); 488 487 489 - // Use the direct API endpoint with a timestamp 488 + // Use the simple API endpoint with a timestamp 490 489 const timestamp = Date.now(); 491 - const url = `/api/bluesky/feed-direct?_t=${timestamp}`; 490 + const url = `/api/bluesky/feed-simple?_t=${timestamp}`; 492 491 console.log(`🔄 MANUAL REFRESH @ ${new Date().toISOString()}`); 493 - console.log(`Using direct API URL: ${url}`); 492 + console.log(`Using simple API URL: ${url}`); 494 493 495 494 // Use strong no-cache headers to ensure browsers don't use cached responses 496 495 const response = await fetch(url, {