-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
244 additions
and
51 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
import { NextApiRequest, NextApiResponse } from 'next'; | ||
import { TwitterClient } from './twitterAuth'; | ||
import { Tweet } from 'agent-twitter-client'; | ||
import { TRACKED_ACCOUNTS } from '@utils/trackedAccounts'; | ||
import { checkApiKey } from '@utils/checkApiKey'; | ||
|
||
export default async function handler( | ||
req: NextApiRequest, | ||
res: NextApiResponse | ||
) { | ||
// Initialize scraper outside request handler to reuse connection | ||
const client = TwitterClient.getInstance(); | ||
|
||
// Only allow GET requests | ||
if (req.method !== 'GET') { | ||
return res.status(405).json({ error: 'Method not allowed' }); | ||
} | ||
|
||
const apiKey = req.headers['x-api-key']; | ||
if (!apiKey) { | ||
return res.status(401).json({ error: 'API key is required' }); | ||
} | ||
|
||
try { | ||
if (!client.isReady()) { | ||
await client.initialize(); | ||
} | ||
|
||
const isValid = await checkApiKey(apiKey as string); | ||
if (!isValid) { | ||
return res.status(401).json({ error: 'Invalid API key' }); | ||
} | ||
|
||
// Fetch tweets from all tracked accounts | ||
const results = await Promise.allSettled( | ||
TRACKED_ACCOUNTS.map(async (username) => { | ||
try { | ||
const userTweets = await client.getUserTweets(username); | ||
const tweets: Tweet[] = []; | ||
for await (const tweet of userTweets) { | ||
tweets.push(tweet); | ||
} | ||
return { | ||
username, | ||
tweets | ||
}; | ||
} catch (error) { | ||
console.error(`Error fetching tweets for ${username}:`, error); | ||
return { | ||
username, | ||
tweets: [] | ||
}; | ||
} | ||
}) | ||
); | ||
|
||
// Filter out rejected promises and get fulfilled values | ||
const allTweets = results | ||
.filter((result): result is PromiseFulfilledResult<{username: string, tweets: Tweet[]}> => | ||
result.status === 'fulfilled' | ||
) | ||
.map(result => result.value); | ||
|
||
// Filter out empty results and sort by date | ||
const flattenedTweets = allTweets | ||
.flatMap(({ username, tweets }) => | ||
tweets.map((tweet: Tweet) => ({ | ||
...tweet, | ||
username | ||
})) | ||
); | ||
|
||
// Return the results | ||
return res.status(200).json({ | ||
success: true, | ||
data: flattenedTweets | ||
}); | ||
|
||
} catch (error) { | ||
console.error('Twitter fetch error:', error); | ||
return res.status(500).json({ | ||
success: false, | ||
error: 'Failed to fetch tweets' | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import { connectToDatabase } from "@pages/api/db/connectDB"; | ||
import { MongoClient } from "mongodb"; | ||
|
||
interface WalletDocument { | ||
apiKey: string; | ||
isPremium: boolean; | ||
} | ||
|
||
export const checkApiKey = async (apiKey: string): Promise<boolean> => { | ||
let mongoClient: MongoClient | null = null; | ||
|
||
try { | ||
// Validate API key format | ||
if (!apiKey || typeof apiKey !== 'string') { | ||
return false; | ||
} | ||
|
||
mongoClient = await connectToDatabase(); | ||
const db = mongoClient.db("walletAnalyzer"); | ||
|
||
// Check if API key exists and is valid | ||
const wallet = await db.collection<WalletDocument>('wallets').findOne({ | ||
apiKey: apiKey, | ||
isPremium: true // Ensure the wallet has premium status | ||
}); | ||
|
||
return !!wallet; | ||
} catch (error) { | ||
console.error('Error checking API key:', error); | ||
return false; | ||
} finally { | ||
// Always close the connection | ||
if (mongoClient) { | ||
await mongoClient.close(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
// List of accounts to track | ||
export const TRACKED_ACCOUNTS = [ | ||
'0xMert_', | ||
'blknoiz06', | ||
'DeeZe', | ||
'Loopifyyy', | ||
'0xMerp', | ||
'optimizoor', | ||
'DancingEddie_', | ||
'VitalikButerin', | ||
'notthreadguy', | ||
'aeyakovenko', | ||
'rajgokal', | ||
'zhusu', | ||
'vydamo_', | ||
'zachxbt', | ||
'metaversejoji', | ||
'casino616', | ||
'ShockedJS', | ||
'BastilleBtc', | ||
'spunosounds', | ||
'TheMisterFrog', | ||
'0xGroovy', | ||
'973Meech', | ||
'rektober', | ||
'frankdegods', | ||
'orangie', | ||
'imperooterxbt', | ||
'sabby_eth', | ||
'NokiTheTrader', | ||
'moneymaykah_', | ||
'rasmr_eth', | ||
'MustStopMurad', | ||
'staccoverflow', | ||
'mememe69696969', | ||
'dolonosolo', | ||
// 'based16z' | ||
]; |