style: format code with prettier agian
Local Build and Deploy / deploy (push) Failing after 49s

This commit is contained in:
openhands committed 2026-07-13 21:41:52 +02:00
1 parent e6d7f2280b
commit 8efd032cc6
71 files changed
+6796 -3751

No files matched your search

+35 -13
View File
@@ -3,8 +3,23 @@ import { auth } from "@/lib/auth";
import { canAccess, getApiAdminContext } from "@/lib/permissions";
import { logAuthorizationEvent } from "@/lib/admin/authorization-events";
import { getRequestId, runWithStore, createStore, setContextUserId } from "./request-context";
import { NotFoundError, UnauthorizedError, ForbiddenError, ValidationError, RateLimitError, DatabaseError } from "./errors";
import type { ActionResult, ActionSuccess, ActionFailure, AppSession, AdminActionContext, IpAddress, RequestId } from "./types";
import {
NotFoundError,
UnauthorizedError,
ForbiddenError,
ValidationError,
RateLimitError,
DatabaseError,
} from "./errors";
import type {
ActionResult,
ActionSuccess,
ActionFailure,
AppSession,
AdminActionContext,
IpAddress,
RequestId,
} from "./types";
import { extractClientIpAsync } from "./security";
import { rateLimit } from "@/lib/rate-limit";
@@ -34,9 +49,7 @@ export function adminAction<TSchema extends z.ZodType | undefined = undefined>(
opts: AdminOpts<TSchema>,
handler: ActionHandler<TSchema>,
) {
return async (
input: TSchema extends z.ZodType ? z.input<TSchema> : void,
): Promise<ActionResult> => {
return async (input: TSchema extends z.ZodType ? z.input<TSchema> : void): Promise<ActionResult> => {
const ip = await extractClientIpAsync();
const store = createStore(ip);
@@ -83,7 +96,8 @@ export function adminAction<TSchema extends z.ZodType | undefined = undefined>(
requestId: getRequestId(),
ip,
...(opts.schema ? { data: data as z.infer<NonNullable<TSchema>> } : {}),
} as AdminActionContext & (TSchema extends z.ZodType ? { data: z.infer<TSchema> } : Record<string, never>);
} as AdminActionContext &
(TSchema extends z.ZodType ? { data: z.infer<TSchema> } : Record<string, never>);
return await handler(ctx);
} catch (error) {
@@ -102,11 +116,13 @@ interface AuthOpts<TSchema extends z.ZodType | undefined> {
export function authAction<TSchema extends z.ZodType | undefined = undefined>(
opts: AuthOpts<TSchema>,
handler: (ctx: { session: AppSession; requestId: RequestId; ip: IpAddress } & (TSchema extends z.ZodType ? { data: z.infer<TSchema> } : Record<string, never>)) => Promise<ActionResult>,
handler: (
ctx: { session: AppSession; requestId: RequestId; ip: IpAddress } & (TSchema extends z.ZodType
? { data: z.infer<TSchema> }
: Record<string, never>),
) => Promise<ActionResult>,
) {
return async (
input: TSchema extends z.ZodType ? z.input<TSchema> : void,
): Promise<ActionResult> => {
return async (input: TSchema extends z.ZodType ? z.input<TSchema> : void): Promise<ActionResult> => {
const ip = await extractClientIpAsync();
const store = createStore(ip);
@@ -136,7 +152,9 @@ export function authAction<TSchema extends z.ZodType | undefined = undefined>(
session: session as unknown as AppSession,
requestId: getRequestId(),
ip,
} as { session: AppSession; requestId: RequestId; ip: IpAddress } & (TSchema extends z.ZodType ? { data: z.infer<TSchema> } : Record<string, never>);
} as { session: AppSession; requestId: RequestId; ip: IpAddress } & (TSchema extends z.ZodType
? { data: z.infer<TSchema> }
: Record<string, never>);
if (opts.schema) {
(ctx as Record<string, unknown>).data = data as z.infer<NonNullable<TSchema>>;
@@ -171,12 +189,16 @@ export function handleActionError(error: unknown): ActionFailure {
}
if (
error instanceof Error &&
(error.constructor.name === "PrismaClientKnownRequestError" || error.name === "PrismaClientKnownRequestError") &&
(error.constructor.name === "PrismaClientKnownRequestError" ||
error.name === "PrismaClientKnownRequestError") &&
(error as Error & { code?: string }).code === "P2025"
) {
return fail("Not found");
}
console.error("[Action error]", error instanceof Error ? { message: error.message, name: error.name } : error);
console.error(
"[Action error]",
error instanceof Error ? { message: error.message, name: error.name } : error,
);
return fail("Internal server error");
}
+22 -4
View File
@@ -38,13 +38,23 @@ export class DbService {
this.client = new PrismaClient({
adapter,
log: env.NODE_ENV === "development" ? [{ emit: "event", level: "query" }, { emit: "event", level: "error" }] : [{ emit: "event", level: "error" }],
log:
env.NODE_ENV === "development"
? [
{ emit: "event", level: "query" },
{ emit: "event", level: "error" },
]
: [{ emit: "event", level: "error" }],
});
if (env.NODE_ENV === "development") {
this.client.$on("query" as never, (e: unknown) => {
const ev = e as { query: string; duration: number };
logger.debug("DB query", { query: ev.query.slice(0, 200), durationMs: ev.duration, requestId: getRequestId() });
logger.debug("DB query", {
query: ev.query.slice(0, 200),
durationMs: ev.duration,
requestId: getRequestId(),
});
});
}
@@ -74,7 +84,13 @@ export class DbService {
} catch (cause) {
const latencyMs = Math.round(performance.now() - start);
const message = cause instanceof Error ? cause.message : "Unknown database error";
this.healthCache = { ok: false, latencyMs, poolSize: env.DATABASE_POOL_SIZE, activeQueries: 0, error: message };
this.healthCache = {
ok: false,
latencyMs,
poolSize: env.DATABASE_POOL_SIZE,
activeQueries: 0,
error: message,
};
this.lastHealthCheck = now;
return this.healthCache;
}
@@ -89,7 +105,9 @@ export class DbService {
}
}
async transaction<T>(fn: (tx: Omit<PrismaClient, "$connect" | "$disconnect" | "$on" | "$use" | "$extends">) => Promise<T>): Promise<T> {
async transaction<T>(
fn: (tx: Omit<PrismaClient, "$connect" | "$disconnect" | "$on" | "$use" | "$extends">) => Promise<T>,
): Promise<T> {
try {
return await this.client.$transaction(fn);
} catch (cause) {
+3 -17
View File
@@ -1,15 +1,6 @@
export {
adminAction,
authAction,
actionOk,
actionError,
handleActionError,
} from "./action";
export { adminAction, authAction, actionOk, actionError, handleActionError } from "./action";
export {
DbService,
db,
} from "./database";
export { DbService, db } from "./database";
export {
safeRedirect,
@@ -44,12 +35,7 @@ export {
runWithStore,
} from "./request-context";
export {
chain,
withRequestContext,
protectAdminRoutes,
addSecurityHeaders,
} from "./middleware";
export { chain, withRequestContext, protectAdminRoutes, addSecurityHeaders } from "./middleware";
export {
username,
+3 -2
View File
@@ -53,8 +53,9 @@ export function protectAdminRoutes(req: NextRequest): NextResponse | null {
if (!pathname.startsWith("/admin")) return null;
const authToken = req.cookies.get("next-auth.session-token")?.value
?? req.cookies.get("__Secure-next-auth.session-token")?.value;
const authToken =
req.cookies.get("next-auth.session-token")?.value ??
req.cookies.get("__Secure-next-auth.session-token")?.value;
if (!authToken) {
const loginUrl = new URL("/login", req.url);
+1 -1
View File
@@ -35,7 +35,7 @@ export function getRequestStore(): RequestStore | null {
}
export function getRequestId(): RequestId {
return als.getStore()?.requestId ?? (generateRequestId());
return als.getStore()?.requestId ?? generateRequestId();
}
export function getClientIp(): IpAddress {
+28 -13
View File
@@ -9,15 +9,21 @@ const CSRF_BYTES = 32;
const CSRF_COOKIE = "__Host-csrf-token";
const CSRF_COOKIE_MAX_AGE = 86400; // 24h
const ALLOWED_HOSTS: ReadonlySet<string> = new Set([
env.APP_URL ? new URL(env.APP_URL).host : "",
"localhost",
"127.0.0.1",
].filter(Boolean));
const ALLOWED_HOSTS: ReadonlySet<string> = new Set(
[env.APP_URL ? new URL(env.APP_URL).host : "", "localhost", "127.0.0.1"].filter(Boolean),
);
const SAFE_REDIRECT_PATHS = new Set([
"/login", "/register", "/forgot", "/reset", "/verify",
"/banned", "/maintenance", "/", "/me", "/settings",
"/login",
"/register",
"/forgot",
"/reset",
"/verify",
"/banned",
"/maintenance",
"/",
"/me",
"/settings",
]);
function isSafePath(path: string): boolean {
@@ -42,7 +48,15 @@ export function redirectSafe(destination: string, fallback: string = "/"): never
redirect(safeRedirect(destination, fallback));
}
function csrfCookieOpts(): { name: string; value: string; httpOnly: boolean; secure: boolean; sameSite: "lax"; path: string; maxAge: number } {
function csrfCookieOpts(): {
name: string;
value: string;
httpOnly: boolean;
secure: boolean;
sameSite: "lax";
path: string;
maxAge: number;
} {
return {
name: CSRF_COOKIE,
value: crypto.randomBytes(CSRF_BYTES).toString("hex"),
@@ -106,7 +120,10 @@ export function canonicalizeFormValue(value: FormDataEntryValue | null, maxLen?:
return maxLen ? s.slice(0, maxLen) : s;
}
export function canonicalizeFormData(formData: FormData, fields: Record<string, number | undefined>): Record<string, string> {
export function canonicalizeFormData(
formData: FormData,
fields: Record<string, number | undefined>,
): Record<string, string> {
return Object.fromEntries(
Object.entries(fields).map(([key, maxLen]) => [key, canonicalizeFormValue(formData.get(key), maxLen)]),
);
@@ -115,13 +132,11 @@ export function canonicalizeFormData(formData: FormData, fields: Record<string,
export async function extractClientIpAsync(): Promise<IpAddress> {
try {
const h = await headers();
return (
h.get("x-real-client-ip") ??
return (h.get("x-real-client-ip") ??
h.get("cf-connecting-ip") ??
h.get("x-forwarded-for")?.split(",")[0]?.trim() ??
h.get("x-real-ip") ??
"0.0.0.0"
) as IpAddress;
"0.0.0.0") as IpAddress;
} catch {
return "0.0.0.0" as IpAddress;
}
+5 -20
View File
@@ -39,10 +39,7 @@ export const slug = z
.refine((v) => !v.startsWith("-") && !v.endsWith("-"), "Slug must not start or end with a hyphen")
.transform((v) => v.normalize("NFC"));
export const url = z
.string()
.url("Invalid URL")
.max(2048, "URL must be at most 2048 characters");
export const url = z.string().url("Invalid URL").max(2048, "URL must be at most 2048 characters");
export const look = z
.string()
@@ -50,25 +47,13 @@ export const look = z
.regex(/^[a-zA-Z0-9.\-_\s]+$/, "Invalid look format")
.optional();
export const positiveInt = z
.number()
.int("Must be a whole number")
.positive("Must be positive");
export const positiveInt = z.number().int("Must be a whole number").positive("Must be positive");
export const nonNegativeInt = z
.number()
.int("Must be a whole number")
.nonnegative("Must not be negative");
export const nonNegativeInt = z.number().int("Must be a whole number").nonnegative("Must not be negative");
export const bigIntString = z
.string()
.regex(/^\d+$/, "Must be a numeric string")
.transform(BigInt);
export const bigIntString = z.string().regex(/^\d+$/, "Must be a numeric string").transform(BigInt);
export const idParam = z
.string()
.regex(/^\d+$/, "ID must be numeric")
.transform(Number);
export const idParam = z.string().regex(/^\d+$/, "ID must be numeric").transform(Number);
export const pagination = z.object({
page: z.coerce.number().int().positive().default(1),