refactor: replace all explicit any types with proper TypeScript types

Backend resolvers: typed enrichArticle/enrichVideo/enrichModel with DB
and $inferSelect types, SQL<unknown>[] for conditions arrays, proper
enum casts for status/role fields, $inferInsert for .set() updates,
typed raw SQL result rows in gamification, ReplyLike interface for
ctx.reply in auth. Frontend: typed catch blocks with Error/interface
casts, isActiveLink param, adminGetUser response, tags filter callback.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-07 19:25:04 +01:00
parent 8313664d70
commit e236ced12a
30 changed files with 392 additions and 375 deletions

View File

@@ -28,10 +28,12 @@ import {
lt,
gte,
arrayContains,
type SQL,
} from "drizzle-orm";
import { requireAdmin } from "../../lib/acl";
import type { DB } from "../../db/connection";
async function enrichVideo(db: any, video: any) {
async function enrichVideo(db: DB, video: typeof videos.$inferSelect) {
// Fetch models
const modelRows = await db
.select({
@@ -87,7 +89,7 @@ builder.queryField("videos", (t) =>
const pageSize = args.limit ?? 24;
const offset = args.offset ?? 0;
const conditions: any[] = [lte(videos.upload_date, new Date())];
const conditions: SQL<unknown>[] = [lte(videos.upload_date, new Date())];
if (!ctx.currentUser) conditions.push(eq(videos.premium, false));
if (args.featured !== null && args.featured !== undefined) {
conditions.push(eq(videos.featured, args.featured));
@@ -107,7 +109,7 @@ builder.queryField("videos", (t) =>
conditions.push(
inArray(
videos.id,
videoIds.map((v: any) => v.video_id),
videoIds.map((v) => v.video_id),
),
);
}
@@ -148,8 +150,8 @@ builder.queryField("videos", (t) =>
.leftJoin(files, eq(videos.movie, files.id))
.where(fullWhere),
]);
const videoList = rows.map((r: any) => r.v || r);
const items = await Promise.all(videoList.map((v: any) => enrichVideo(ctx.db, v)));
const videoList = rows.map((r) => r.v);
const items = await Promise.all(videoList.map((v) => enrichVideo(ctx.db, v)));
return { items, total: totalRows[0]?.total ?? 0 };
}
@@ -157,7 +159,7 @@ builder.queryField("videos", (t) =>
ctx.db.select().from(videos).where(where).orderBy(order).limit(pageSize).offset(offset),
ctx.db.select({ total: count() }).from(videos).where(where),
]);
const items = await Promise.all(rows.map((v: any) => enrichVideo(ctx.db, v)));
const items = await Promise.all(rows.map((v) => enrichVideo(ctx.db, v)));
return { items, total: totalRows[0]?.total ?? 0 };
},
}),
@@ -421,7 +423,7 @@ builder.queryField("analytics", (t) =>
};
}
const videoIds = modelVideoIds.map((v: any) => v.video_id);
const videoIds = modelVideoIds.map((v) => v.video_id);
const videoList = await ctx.db.select().from(videos).where(inArray(videos.id, videoIds));
const plays = await ctx.db
.select()
@@ -435,14 +437,14 @@ builder.queryField("analytics", (t) =>
const totalLikes = videoList.reduce((sum, v) => sum + (v.likes_count || 0), 0);
const totalPlays = videoList.reduce((sum, v) => sum + (v.plays_count || 0), 0);
const playsByDate = plays.reduce((acc: any, play) => {
const playsByDate = plays.reduce((acc: Record<string, number>, play) => {
const date = new Date(play.date_created).toISOString().split("T")[0];
if (!acc[date]) acc[date] = 0;
acc[date]++;
return acc;
}, {});
const likesByDate = likes.reduce((acc: any, like) => {
const likesByDate = likes.reduce((acc: Record<string, number>, like) => {
const date = new Date(like.date_created).toISOString().split("T")[0];
if (!acc[date]) acc[date] = 0;
acc[date]++;
@@ -499,7 +501,7 @@ builder.queryField("adminListVideos", (t) =>
const limit = args.limit ?? 50;
const offset = args.offset ?? 0;
const conditions: any[] = [];
const conditions: SQL<unknown>[] = [];
if (args.search) conditions.push(ilike(videos.title, `%${args.search}%`));
if (args.premium !== null && args.premium !== undefined)
conditions.push(eq(videos.premium, args.premium));
@@ -517,7 +519,7 @@ builder.queryField("adminListVideos", (t) =>
.offset(offset),
ctx.db.select({ total: count() }).from(videos).where(where),
]);
const items = await Promise.all(rows.map((v: any) => enrichVideo(ctx.db, v)));
const items = await Promise.all(rows.map((v) => enrichVideo(ctx.db, v)));
return { items, total: totalRows[0]?.total ?? 0 };
},
}),
@@ -590,7 +592,7 @@ builder.mutationField("updateVideo", (t) =>
const updated = await ctx.db
.update(videos)
.set(updates as any)
.set(updates as Partial<typeof videos.$inferInsert>)
.where(eq(videos.id, args.id))
.returning();
if (!updated[0]) return null;