-
Notifications
You must be signed in to change notification settings - Fork 31
feat: add user count API endpoint and refactor stats fetching logic: #241
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,26 +1,31 @@ | ||
| "use server" | ||
|
|
||
| import prisma from "@super/db" | ||
| async function safeFetchJson<T>(url: string, fallback: T): Promise<T> { | ||
| try { | ||
| const res = await fetch(url, { next: { revalidate: 3600 } }) | ||
|
Comment on lines
+3
to
+5
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🚀 Performance & Scalability | 🟠 Major | 🏗️ Heavy lift 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "== locate stats page and actions =="
fd -a 'page\.tsx$|index\.ts$' apps/web/modules/apps/web 2>/dev/null | sed 's#^\./##' | rg 'apps/web/app/\(pages\)/stats/page\.tsx|apps/web/modules/stats/actions/index\.ts' || true
echo
echo "== stats page outline/content =="
if [ -f 'apps/web/app/(pages)/stats/page.tsx' ]; then
wc -l 'apps/web/app/(pages)/stats/page.tsx'
cat -n 'apps/web/app/(pages)/stats/page.tsx' | sed -n '1,220p'
fi
echo
echo "== stats actions content =="
if [ -f 'apps/web/modules/stats/actions/index.ts' ]; then
wc -l 'apps/web/modules/stats/actions/index.ts'
cat -n 'apps/web/modules/stats/actions/index.ts' | sed -n '1,180p'
fiRepository: yashdev9274/supercli Length of output: 1840 🌐 Web query:
💡 Result: In the Next.js App Router, the interaction between individual Citations:
🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "== package versions =="
if [ -f package.json ]; then
node - <<'JS'
const fs = require('fs');
const p = JSON.parse(fs.readFileSync('package.json','utf8'));
console.log('root next:', p.dependencies?.next || p.devDependencies?.next);
console.log('root react:', p.dependencies?.react || p.devDependencies?.react);
for (const f of ['apps/web/package.json', 'apps/web/package-lock.json', 'package-lock.json']) {
if (fs.existsSync(f)) {
console.log('\nfile:', f);
const pkg = JSON.parse(fs.readFileSync(f,'utf8'));
if (pkg.dependencies?.next || pkg.devDependencies?.next) {
console.log('next:', pkg.dependencies?.next || pkg.devDependencies?.next);
}
}
}
JS
fi
echo
echo "== next config =="
fd -a 'next\.config\.(js|mjs|ts)$' apps/web . | sed 's#^\./##' | while read -r f; do
echo "--- $f"
wc -l "$f"
cat -n "$f" | sed -n '1,220p'
doneRepository: yashdev9274/supercli Length of output: 2817 🌐 Web query:
💡 Result: In Next.js 15, the dynamic configuration is a Route Segment Config option, not a setting defined in next.config.ts [1][2][3]. To force a page, layout, or route handler to be dynamically rendered at request time, you must export the dynamic constant directly from the route segment file (e.g., page.tsx, layout.tsx, or route.ts) [1][4]. Use the following syntax in your page or layout file: export const dynamic = 'force-dynamic'; When this is set, the route will be rendered for each user at request time [1][5]. This is functionally equivalent to setting every fetch request within that segment to { cache: 'no-store', next: { revalidate: 0 } } and setting the fetchCache option to 'force-no-store' [1]. Key points regarding this configuration: - Next.config.ts: This file is for global project-level configuration (e.g., experimental flags, redirects, headers) and does not control the dynamic rendering behavior of individual routes [2][3]. - Purpose: 'force-dynamic' is intended for routes that require request-time data, such as headers, cookies, or frequently changing server-side data [5]. - Alternatives: Using export const revalidate = 0 in your route segment provides an equivalent outcome, forcing the route to be dynamic [5][6]. - Next.js 15 behavior: Note that in Next.js 15, GET Route Handlers are not cached by default [2]. If you only need to ensure data freshness for specific fetches, you can use the { cache: 'no-store' } option on those individual fetch calls rather than forcing the entire route to be dynamic [1][6]. Citations:
Avoid forcing hourly stats revalidation into no-store.
🤖 Prompt for AI AgentsSource: MCP tools |
||
| return await res.json() | ||
| } catch { | ||
| return fallback | ||
| } | ||
| } | ||
|
Comment on lines
+3
to
+10
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "Locate target file and related files"
git ls-files | rg '(^|/)apps/web/modules/stats/actions/index\.ts$|package.json$|zod|tsconfig'
echo
echo "Target file outline"
ast-grep outline apps/web/modules/stats/actions/index.ts 2>/dev/null || true
echo
echo "Target file content"
cat -n apps/web/modules/stats/actions/index.ts
echo
echo "Search stats/json5/500/fetch usages"
rg -n "safeFetchJson|getStats|force-dynamic|fetch\(|json5|JSON\.parse|500|revalidate|localhost:3004" apps/web/modules/stats apps/web/features apps/web -g '*.ts' -g '*.tsx' | head -200Repository: yashdev9274/supercli Length of output: 15299 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "apps/web/package.json relevant deps"
node - <<'JS'
const fs = require('fs')
const p = JSON.parse(fs.readFileSync('apps/web/package.json', 'utf8'))
const deps = {...(p.dependencies||{}), ...(p.devDependencies||{})}
for (const [k,v] of Object.entries(deps)) {
if (/^(next|zod|json5)$/.test(k)) console.log(`${k}: ${v}`)
}
JS
echo
echo "Behavioral probe: fetch response handling and numeric coercion"
node - <<'JS'
class Response {
constructor(status, json, err) {
this.status = status
this._json = json
this._err = err
this.ok = status >= 200 && status < 300
}
async json() {
if (this._err) throw this._err
return this._json
}
}
async function currentSafeFetchJson(url, fallback) {
// Minimal JS equivalent of the current helper: no status check
const res = new Response(500, { error: "Internal Server Error" }, undefined)
try {
return await res.json()
} catch {
return fallback
}
}
for (const payload of [
{ status: 500, json: { downloads: "not a number" }, fallback: { downloads: 0 } },
{ status: 200, json: { downloads: NaN }, fallback: { downloads: 0 } },
{ status: 200, json: { downloads: null }, fallback: { downloads: 0 } },
{ status: "network error thrown", json: null, fallback: { downloads: 0 } },
]) {
let actualPayload
try {
actualPayload = payload.json
} catch (e) {
actualPayload = `THREW:${e.message}`
}
const fallbackReturn = typeof actualPayload === "object" && actualPayload !== null ? actualPayload : payload.fallback
const userStats = fallbackReturn
const computed = (userStats.downloads ? 1 : 0) + 6000
const arithmeticSafe = (userStats.downloads ?? 0) + 6000
console.log(JSON.stringify({
inputPayload: payload.json,
inputStatus: payload.status,
fallsthroughTo: fallbackReturn,
arithmeticUsingNullishCoalescing: arithmeticSafe,
arithmeticUsingTruthiness: computed,
}))
}
JSRepository: yashdev9274/supercli Length of output: 971 Enforce fallbacks for non-OK responses and invalid payload fields.
🤖 Prompt for AI AgentsSource: Coding guidelines |
||
|
|
||
| export async function getStats() { | ||
| try { | ||
| const [userCount, npmResponse, githubResponse] = await Promise.all([ | ||
| prisma.user.count(), | ||
| fetch("https://api.npmjs.org/downloads/point/last-month/supercode-cli").then( | ||
| (r) => r.json().catch(() => ({ downloads: 0 })), | ||
| ), | ||
| fetch("https://api.github.com/repos/yashdev9274/superCli").then((r) => | ||
| r.json().catch(() => ({ stargazers_count: 0 })), | ||
| ), | ||
| ]) | ||
| const serverUrl = process.env.TERMINAL_SERVER_URL || "http://localhost:3004" | ||
| const [userStats, npmResponse, githubResponse] = await Promise.all([ | ||
| safeFetchJson<{ count?: number }>(`${serverUrl}/api/data/users/count`, { count: 0 }), | ||
|
Comment on lines
+13
to
+15
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win Align the terminal-server URL fallback.
🤖 Prompt for AI Agents |
||
| safeFetchJson<{ downloads?: number }>( | ||
| "https://api.npmjs.org/downloads/point/last-month/supercode-cli", | ||
| { downloads: 0 }, | ||
| ), | ||
| safeFetchJson<{ stargazers_count?: number }>( | ||
| "https://api.github.com/repos/yashdev9274/superCli", | ||
| { stargazers_count: 0 }, | ||
| ), | ||
| ]) | ||
|
|
||
| return { | ||
| users: userCount + 100, | ||
| downloads: (npmResponse.downloads ?? 0) + 6000, | ||
| stars: githubResponse.stargazers_count ?? 0, | ||
| } | ||
| } catch (error) { | ||
| console.error("Error fetching stats:", error) | ||
| return { users: 0, downloads: 0, stars: 0 } | ||
| return { | ||
| users: (userStats.count ?? 0) + 100, | ||
| downloads: (npmResponse.downloads ?? 0) + 6000, | ||
| stars: githubResponse.stargazers_count ?? 0, | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
📐 Maintainability & Code Quality | 🟠 Major | 🏗️ Heavy lift
🧩 Analysis chain
🏁 Script executed:
Repository: yashdev9274/supercli
Length of output: 13398
Use
Bun.serve()for the new route.This handler is added via Express’s
app.get, butapps/supercode-cli/server/src/index.tsmatches the repository rule requiringBun.serve()with routes and WebSocket support instead of Express. Migrate this route with the server implementation or provide an explicit exemption.🤖 Prompt for AI Agents
Source: Coding guidelines