fix: resolve all biome lint errors and type issues
- Add file-level biome-ignore for noExplicitAny in prisma-facade.ts (intentional any for Prisma API compatibility surface) - Fix noNonNullAssertion errors in cached-db.ts (redis null-guard fixes) - Auto-fix formatting + organizeImports across modified files - 0 tsc errors, 0 biome errors, 583 tests passing
This commit is contained in:
1 parent
d1807ca814
commit
7f7971f578
7 files changed
+34
-37
No files matched your search
+1
-7
@@ -21,13 +21,7 @@ const securityHeaders = [
|
|||||||
|
|
||||||
const nextConfig: NextConfig = {
|
const nextConfig: NextConfig = {
|
||||||
turbopack: {},
|
turbopack: {},
|
||||||
serverExternalPackages: [
|
serverExternalPackages: ["mariadb", "lzma", "sharp", "pino", "pino-pretty"],
|
||||||
"mariadb",
|
|
||||||
"lzma",
|
|
||||||
"sharp",
|
|
||||||
"pino",
|
|
||||||
"pino-pretty",
|
|
||||||
],
|
|
||||||
|
|
||||||
// Enable React Compiler for automatic memoization
|
// Enable React Compiler for automatic memoization
|
||||||
reactCompiler: true,
|
reactCompiler: true,
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
import crypto from "node:crypto";
|
import crypto from "node:crypto";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { hashPassword } from "@/lib/auth/password";
|
|
||||||
import { invalidateLoginCache } from "@/lib/auth";
|
import { invalidateLoginCache } from "@/lib/auth";
|
||||||
|
import { hashPassword } from "@/lib/auth/password";
|
||||||
import { PERMS } from "@/lib/permissions";
|
import { PERMS } from "@/lib/permissions";
|
||||||
import { prisma } from "@/lib/prisma";
|
import { prisma } from "@/lib/prisma";
|
||||||
import { adminAction } from "@/lib/safe-action";
|
import { adminAction } from "@/lib/safe-action";
|
||||||
|
|||||||
@@ -12,15 +12,12 @@ export const dynamic = "force-dynamic";
|
|||||||
|
|
||||||
export async function GET(_req: Request) {
|
export async function GET(_req: Request) {
|
||||||
try {
|
try {
|
||||||
const users = await cached(
|
const users = await cached("online_users", 10_000, async () =>
|
||||||
"online_users",
|
prisma.user.findMany({
|
||||||
10_000,
|
where: { online: "1" },
|
||||||
async () =>
|
select: { username: true, look: true },
|
||||||
prisma.user.findMany({
|
take: 100,
|
||||||
where: { online: "1" },
|
}),
|
||||||
select: { username: true, look: true },
|
|
||||||
take: 100,
|
|
||||||
}),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return apiJson({ users });
|
return apiJson({ users });
|
||||||
|
|||||||
+2
-1
@@ -5,7 +5,8 @@
|
|||||||
@custom-variant dark (&:where(.dark, .dark *));
|
@custom-variant dark (&:where(.dark, .dark *));
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
--font-nunito: "Nunito", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
|
--font-nunito:
|
||||||
|
"Nunito", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
|
||||||
--font-pixel: "Pixelify Sans", monospace;
|
--font-pixel: "Pixelify Sans", monospace;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+6
-5
@@ -52,14 +52,15 @@ export default async function RootLayout({
|
|||||||
const nonce = (await headers()).get("x-nonce") ?? undefined;
|
const nonce = (await headers()).get("x-nonce") ?? undefined;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<html
|
<html lang={locale} className="app">
|
||||||
lang={locale}
|
|
||||||
className="app"
|
|
||||||
>
|
|
||||||
<head>
|
<head>
|
||||||
<meta name="theme-default-dark" content={String(defaultDark)} />
|
<meta name="theme-default-dark" content={String(defaultDark)} />
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="anonymous" />
|
<link
|
||||||
|
rel="preconnect"
|
||||||
|
href="https://fonts.gstatic.com"
|
||||||
|
crossOrigin="anonymous"
|
||||||
|
/>
|
||||||
<link
|
<link
|
||||||
rel="stylesheet"
|
rel="stylesheet"
|
||||||
href="https://fonts.googleapis.com/css2?family=Nunito:wght@400;600;700;800&display=swap"
|
href="https://fonts.googleapis.com/css2?family=Nunito:wght@400;600;700;800&display=swap"
|
||||||
|
|||||||
+3
-4
@@ -1,16 +1,15 @@
|
|||||||
|
import { sql } from "drizzle-orm";
|
||||||
import NextAuth from "next-auth";
|
import NextAuth from "next-auth";
|
||||||
import Credentials from "next-auth/providers/credentials";
|
import Credentials from "next-auth/providers/credentials";
|
||||||
import { sql } from "drizzle-orm";
|
|
||||||
import { env } from "@/env";
|
import { env } from "@/env";
|
||||||
import { getCachedJwtVersion } from "@/lib/auth/jwt-version-cache";
|
import { getCachedJwtVersion } from "@/lib/auth/jwt-version-cache";
|
||||||
import { cachedQuery } from "@/lib/cached-db";
|
|
||||||
import { invalidateKey } from "@/lib/cached-db";
|
|
||||||
import { LaravelEncrypter } from "@/lib/auth/laravel-encrypter";
|
import { LaravelEncrypter } from "@/lib/auth/laravel-encrypter";
|
||||||
import { checkLogin } from "@/lib/auth/password";
|
import { checkLogin } from "@/lib/auth/password";
|
||||||
import { verifyTotp } from "@/lib/auth/totp";
|
import { verifyTotp } from "@/lib/auth/totp";
|
||||||
|
import { cachedQuery, invalidateKey } from "@/lib/cached-db";
|
||||||
|
import { db } from "@/lib/db";
|
||||||
import { logger } from "@/lib/logger";
|
import { logger } from "@/lib/logger";
|
||||||
import { prisma } from "@/lib/prisma";
|
import { prisma } from "@/lib/prisma";
|
||||||
import { db } from "@/lib/db";
|
|
||||||
import { clientIp, rateLimit } from "@/lib/rate-limit";
|
import { clientIp, rateLimit } from "@/lib/rate-limit";
|
||||||
import { siteSettings } from "@/lib/services/site-settings";
|
import { siteSettings } from "@/lib/services/site-settings";
|
||||||
|
|
||||||
|
|||||||
+15
-10
@@ -1,7 +1,7 @@
|
|||||||
import "server-only";
|
import "server-only";
|
||||||
|
|
||||||
import { redis } from "@/lib/redis";
|
|
||||||
import { logger } from "@/lib/logger";
|
import { logger } from "@/lib/logger";
|
||||||
|
import { redis } from "@/lib/redis";
|
||||||
|
|
||||||
const DEFAULT_CACHE_TTL = 60;
|
const DEFAULT_CACHE_TTL = 60;
|
||||||
|
|
||||||
@@ -24,7 +24,10 @@ export async function cachedQuery<T>(
|
|||||||
return JSON.parse(cached) as T;
|
return JSON.parse(cached) as T;
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.warn("[cache] read failed, falling back to DB", { key: cacheKey, error: String(err) });
|
logger.warn("[cache] read failed, falling back to DB", {
|
||||||
|
key: cacheKey,
|
||||||
|
error: String(err),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await queryFn();
|
const result = await queryFn();
|
||||||
@@ -42,15 +45,17 @@ export async function cachedQuery<T>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Invalidate cache keys matching a glob pattern. */
|
/** Invalidate cache keys matching a glob pattern. */
|
||||||
export function invalidateCache(pattern: string): Promise<number> {
|
export async function invalidateCache(pattern: string): Promise<number> {
|
||||||
if (!isRedisAvailable()) return Promise.resolve(0);
|
if (!isRedisAvailable()) return 0;
|
||||||
return redis?.keys(pattern).then((keys) =>
|
const r = redis;
|
||||||
keys.length > 0 ? redis!.del(...keys) : 0,
|
if (!r) return 0;
|
||||||
) ?? Promise.resolve(0);
|
const keys = await r.keys(pattern);
|
||||||
|
return keys.length > 0 ? r.del(...keys) : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Invalidate a single cache key immediately. */
|
/** Invalidate a single cache key immediately. */
|
||||||
export function invalidateKey(key: string): Promise<number> {
|
export async function invalidateKey(key: string): Promise<number> {
|
||||||
if (!isRedisAvailable()) return Promise.resolve(0);
|
if (!isRedisAvailable()) return 0;
|
||||||
return redis!.del(key);
|
if (!redis) return 0;
|
||||||
|
return redis.del(key);
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user