UNPKG

wisdom-sdk

Version:

Core business logic and data access layer for prediction markets

210 lines (208 loc) 7.85 kB
import { getTopFromSortedSet, getScoresFromSortedSet, addToSortedSet, storeEntity, getEntity } from './chunk-FIJAO3BQ.js'; // src/user-stats-store.ts var userStatsStore = { // Helper to calculate user score consistently across the app calculateUserScore(stats) { const accuracyComponent = stats.totalPredictions >= 5 ? stats.accuracy : 0; const normalizedEarnings = stats.totalEarnings / 100; const volumeFactor = stats.totalPredictions > 0 ? Math.log10(stats.totalPredictions + 1) * 10 : 0; const consistencyFactor = stats.totalPredictions >= 10 ? accuracyComponent * Math.min(stats.totalPredictions / 20, 1.5) : accuracyComponent; return consistencyFactor * 0.4 + normalizedEarnings * 0.3 + Math.min(volumeFactor, 25) * 0.3; }, // Get user stats for a specific user async getUserStats(userId) { try { if (!userId) return null; const stats = await getEntity("USER_STATS", userId); return stats || null; } catch (error) { console.error(`Error getting user stats for ${userId}:`, error); return null; } }, // Update user stats when a prediction is made async updateStatsForNewPrediction(userId, prediction) { try { const currentStats = await this.getUserStats(userId) || { userId, totalPredictions: 0, correctPredictions: 0, accuracy: 0, totalAmount: 0, totalEarnings: 0, lastUpdated: (/* @__PURE__ */ new Date()).toISOString() }; const updatedStats = { ...currentStats, totalPredictions: currentStats.totalPredictions + 1, totalAmount: currentStats.totalAmount + prediction.amount, lastUpdated: (/* @__PURE__ */ new Date()).toISOString() }; updatedStats.accuracy = updatedStats.totalPredictions > 0 ? updatedStats.correctPredictions / updatedStats.totalPredictions * 100 : 0; await storeEntity("USER_STATS", userId, updatedStats); await this.updateLeaderboardEntries(updatedStats); return updatedStats; } catch (error) { console.error(`Error updating stats for user ${userId}:`, error); throw error; } }, // Update user stats when a prediction is resolved async updateStatsForResolvedPrediction(userId, prediction, isCorrect, earnings) { try { if (!userId || userId === "anonymous") { console.log("Skipping stats update for anonymous user"); return { userId, totalPredictions: 1, correctPredictions: isCorrect ? 1 : 0, accuracy: isCorrect ? 100 : 0, totalAmount: prediction?.amount || 0, totalEarnings: earnings, lastUpdated: (/* @__PURE__ */ new Date()).toISOString() }; } const currentStats = await this.getUserStats(userId); if (!currentStats) { console.log(`Creating new stats for user ${userId}`); const newStats = { userId, totalPredictions: 1, correctPredictions: isCorrect ? 1 : 0, accuracy: isCorrect ? 100 : 0, totalAmount: prediction?.amount || 0, totalEarnings: earnings, lastUpdated: (/* @__PURE__ */ new Date()).toISOString() }; await storeEntity("USER_STATS", userId, newStats); await this.updateLeaderboardEntries(newStats); return newStats; } const updatedStats = { ...currentStats, correctPredictions: isCorrect ? currentStats.correctPredictions + 1 : currentStats.correctPredictions, totalEarnings: currentStats.totalEarnings + earnings, lastUpdated: (/* @__PURE__ */ new Date()).toISOString() }; updatedStats.accuracy = updatedStats.totalPredictions > 0 ? updatedStats.correctPredictions / updatedStats.totalPredictions * 100 : 0; await storeEntity("USER_STATS", userId, updatedStats); await this.updateLeaderboardEntries(updatedStats); return updatedStats; } catch (error) { console.error(`Error updating stats for resolved prediction, user ${userId}:`, error); throw error; } }, // Update user's username (when available from auth provider) async updateUsername(userId, username) { try { const stats = await this.getUserStats(userId); if (!stats) return null; const updatedStats = { ...stats, username, lastUpdated: (/* @__PURE__ */ new Date()).toISOString() }; await storeEntity("USER_STATS", userId, updatedStats); await this.updateLeaderboardEntries(updatedStats); return updatedStats; } catch (error) { console.error(`Error updating username for user ${userId}:`, error); return null; } }, // Update leaderboard sorted sets for efficient querying async updateLeaderboardEntries(stats) { try { await addToSortedSet( "LEADERBOARD_EARNINGS", stats.userId, stats.totalEarnings ); const accuracyScore = stats.totalPredictions >= 5 ? stats.accuracy : 0; await addToSortedSet( "LEADERBOARD_ACCURACY", stats.userId, accuracyScore ); const compositeScore = this.calculateUserScore(stats); await addToSortedSet( "LEADERBOARD", stats.userId, compositeScore ); } catch (error) { console.error("Error updating leaderboard entries:", error); throw error; } }, // Get top leaderboard entries by earnings async getTopEarners(limit = 10) { try { const userIds = await getTopFromSortedSet("LEADERBOARD_EARNINGS", limit); const leaderboard = await this.getUserStatsForIds(userIds); const scoresMap = await getScoresFromSortedSet("LEADERBOARD_EARNINGS", userIds); return leaderboard.map((entry, index) => { return { ...entry, rank: index + 1, score: scoresMap[entry.userId] || this.calculateUserScore(entry) }; }); } catch (error) { console.error("Error getting top earners:", error); return []; } }, // Get top leaderboard entries by accuracy async getTopAccurate(limit = 10) { try { const userIds = await getTopFromSortedSet("LEADERBOARD_ACCURACY", limit); const leaderboard = await this.getUserStatsForIds(userIds); const scoresMap = await getScoresFromSortedSet("LEADERBOARD_ACCURACY", userIds); return leaderboard.map((entry, index) => { return { ...entry, rank: index + 1, score: scoresMap[entry.userId] || this.calculateUserScore(entry) }; }); } catch (error) { console.error("Error getting top accuracy:", error); return []; } }, // Get top leaderboard entries by combined score async getTopUsers(limit = 10) { try { const userIds = await getTopFromSortedSet("LEADERBOARD", limit); const leaderboard = await this.getUserStatsForIds(userIds); const scoresMap = await getScoresFromSortedSet("LEADERBOARD", userIds); return leaderboard.map((entry, index) => { return { ...entry, rank: index + 1, score: scoresMap[entry.userId] || this.calculateUserScore(entry) }; }); } catch (error) { console.error("Error getting leaderboard:", error); return []; } }, // Helper to get multiple user stats by IDs async getUserStatsForIds(userIds) { try { if (userIds.length === 0) return []; const statsPromises = userIds.map((id) => this.getUserStats(id)); const statsResults = await Promise.all(statsPromises); return statsResults.filter(Boolean); } catch (error) { console.error("Error getting user stats for IDs:", error); return []; } } }; export { userStatsStore }; //# sourceMappingURL=chunk-ZJ2UKXRV.js.map //# sourceMappingURL=chunk-ZJ2UKXRV.js.map