Skip to content

Commit dba49f5

Browse files
committed
feat: Platform Stats now loads ALL session data with async iteration
1 parent 917c67a commit dba49f5

5 files changed

Lines changed: 64 additions & 33 deletions

File tree

changelog.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@ Format based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
66

77
## [Unreleased]
88

9+
### Changed
10+
11+
- Platform Stats now loads ALL session data instead of last 1000 sessions
12+
- Changed publicPlatformStats query to use async iteration (streams data without memory limits)
13+
- Added total sessions and total tokens display in Platform Stats header
14+
- Same pattern used by publicMessageCount and publicMessageGrowth queries
15+
916
### Fixed
1017

1118
- Fixed Netlify build error: Stats.tsx was git-ignored causing module not found error

convex/analytics.ts

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -696,6 +696,7 @@ export const publicMessageGrowth = query({
696696

697697
// Public platform-wide stats for homepage leaderboard (no auth required)
698698
// Returns top models and top CLI sources sorted by usage
699+
// Uses async iteration to stream ALL sessions without hitting memory limits
699700
export const publicPlatformStats = query({
700701
args: {},
701702
returns: v.object({
@@ -713,28 +714,27 @@ export const publicPlatformStats = query({
713714
totalTokens: v.number(),
714715
}),
715716
),
717+
totalSessions: v.number(),
718+
totalTokens: v.number(),
716719
}),
717720
handler: async (ctx) => {
718-
// Fetch recent sessions for platform-wide stats (limit to 1000 to avoid timeout)
719-
const sessions = await ctx.db.query("sessions").order("desc").take(1000);
720-
721-
if (sessions.length === 0) {
722-
return {
723-
topModels: [],
724-
topSources: [],
725-
};
726-
}
727-
728-
// Aggregate by model
721+
// Aggregate by model (streams all sessions without loading into memory)
729722
const modelMap: Record<string, { totalTokens: number; sessions: number }> =
730723
{};
731724
// Aggregate by source (CLI tool)
732725
const sourceMap: Record<string, { sessions: number; totalTokens: number }> =
733726
{};
734727

735-
for (const s of sessions) {
728+
let totalSessions = 0;
729+
let totalTokens = 0;
730+
731+
// Stream through ALL sessions using async iteration (avoids 16MB read limit)
732+
for await (const s of ctx.db.query("sessions")) {
733+
totalSessions += 1;
734+
736735
// Safe token value (handle null/undefined)
737736
const tokens = s.totalTokens ?? 0;
737+
totalTokens += tokens;
738738

739739
// Model aggregation
740740
const model = s.model || "unknown";
@@ -753,6 +753,16 @@ export const publicPlatformStats = query({
753753
sourceMap[source].totalTokens += tokens;
754754
}
755755

756+
// Return empty arrays if no data
757+
if (totalSessions === 0) {
758+
return {
759+
topModels: [],
760+
topSources: [],
761+
totalSessions: 0,
762+
totalTokens: 0,
763+
};
764+
}
765+
756766
// Sort models by total tokens and take top 5
757767
const topModels = Object.entries(modelMap)
758768
.map(([model, stats]) => ({
@@ -776,6 +786,8 @@ export const publicPlatformStats = query({
776786
return {
777787
topModels,
778788
topSources,
789+
totalSessions,
790+
totalTokens,
779791
};
780792
},
781793
});

0 commit comments

Comments
 (0)