ronantakizawa/codereview-bench huggingface dataset:
Repository: benawad/dogehouse
File: kibbeh/src/ui/VerticalUserInfo.tsx (TypeScript)

Code before:
import { UserBadge } from "./UserBadge";
import { badge, Badges } from "./UserSummaryCard";
import { ContributorBadge, StaffBadge } from "../icons/badges";

interface VerticalUserInfoProps {
  user: UserWithFollowInfo;
}

export const VerticalUserInfo: React.FC<VerticalUserInfoProps> = ({ user }) => {
  const { t } = useTypeSafeTranslation();
  const badges: badge[] = [];
  if (user.staff) {
    badges.push({
      content: <StaffBadge />,
      variant: "primary",
      color: "white",
      title: t("components.userBadges.dhStaff"),
      naked: true,
    });
  }
  if (user.contributions > 0) {
    badges.push({
      content: <ContributorBadge contributions={user.contributions} />,
      variant: "primary",
      color: "white",
      title: t("components.userBadges.dhContributor"),
      naked: true,
    });
  }

  if (user.botOwnerId) {
    badges.push({
      content: t("pages.viewUser.bot"),
      variant: "primary",
      color: "white",
      title: t("pages.viewUser.bot"),
    });
  }

  if (user.followsYou) {
    badges.push({
      content: t("pages.viewUser.followsYou"),
      variant: "primary-700",
      color: "grey",
      title: t("pages.viewUser.followsYou"),
      classname: "ml-1",
    });
  }
  return (
    <>
      <HeaderController

Review comment (suggestion):
```suggestion
      title: `${t("components.userBadges.dhContributor")} (${user.contributions} ${t("pages.admin.contributions")})`,
```

Code after:
import { UserBadge } from "./UserBadge";
import { badge, Badges } from "./UserSummaryCard";
import { ContributorBadge, StaffBadge } from "../icons/badges";

interface VerticalUserInfoProps {
  user: UserWithFollowInfo;
}

export const VerticalUserInfo: React.FC<VerticalUserInfoProps> = ({ user }) => {
  const { t } = useTypeSafeTranslation();
  const badges: badge[] = [];
  if (user.staff) {
    badges.push({
      content: <StaffBadge />,
      variant: "primary",
      color: "white",
      title: t("components.userBadges.dhStaff"),
      naked: true,
    });
  }
  if (user.contributions > 0) {
    badges.push({
      content: <ContributorBadge contributions={user.contributions} />,
      variant: "primary",
      color: "white",
      title: `${t("components.userBadges.dhContributor")} (${user.contributions} ${t("pages.admin.contributions")})`,
      naked: true,
    });
  }

  if (user.botOwnerId) {
    badges.push({
      content: t("pages.viewUser.bot"),
      variant: "primary",
      color: "white",
      title: t("pages.viewUser.bot"),
    });
  }

  if (user.followsYou) {
    badges.push({
      content: t("pages.viewUser.followsYou"),
      variant: "primary-700",
      color: "grey",
      title: t("pages.viewUser.followsYou"),
      classname: "ml-1",
    });
  }
  return (
    <>
      <HeaderController
Repository: better-auth/better-auth
File: packages/better-auth/src/utils/url.ts (TypeScript)

Code before:
import { env } from "@better-auth/core/env";
import { BetterAuthError } from "@better-auth/core/error";

function checkHasPath(url: string): boolean {
	try {
		const parsedUrl = new URL(url);
		const pathname = parsedUrl.pathname.replace(/\/+$/, "") || "/";
		return pathname !== "/";
	} catch (error) {
		throw new BetterAuthError(
			`Invalid base URL: ${url}. Please provide a valid base URL.`,
		);
	}
}

function withPath(url: string, path = "/api/auth") {
	const hasPath = checkHasPath(url);
	if (hasPath) {
		return url;
	}

	const trimmedUrl = url.replace(/\/+$/, "");

	if (!path || path === "/") {
		return trimmedUrl;
	}

	path = path.startsWith("/") ? path : `/${path}`;
	return `${trimmedUrl}${path}`;
}

export function getBaseURL(
	url?: string,
	path?: string,
	request?: Request,
	loadEnv?: boolean,
) {
	if (url) {
		return withPath(url, path);
	}

	if (loadEnv !== false) {
		const fromEnv =
			env.BETTER_AUTH_URL ||

Review comment (suggestion):
Hello @dmmulroy! While it makes sense to validate that a protocol exists and it's not `ws:` (or `wss:`), this current check is problematic for Electron and Tauri applications, which rely on custom protocols to access localhost (e.g. `tauri://localhost`) and other use cases. I'll be patching it locally 'til it gets fixed.

Code after:
import { env } from "@better-auth/core/env";
import { BetterAuthError } from "@better-auth/core/error";

function checkHasPath(url: string): boolean {
	try {
		const parsedUrl = new URL(url);
		const pathname = parsedUrl.pathname.replace(/\/+$/, "") || "/";
		return pathname !== "/";
	} catch (error) {
		throw new BetterAuthError(
			`Invalid base URL: ${url}. Please provide a valid base URL.`,
		);
	}
}

function assertHasProtocol(url: string): void {
	try {
		const parsedUrl = new URL(url);
		if (parsedUrl.protocol !== "http:" && parsedUrl.protocol !== "https:") {
			throw new BetterAuthError(
				`Invalid base URL: ${url}. URL must include 'http://' or 'https://'`,
			);
		}
	} catch (error) {
		if (error instanceof BetterAuthError) {
			throw error;
		}
		throw new BetterAuthError(
			`Invalid base URL: ${url}. Please provide a valid base URL.`,
			String(error),
		);
	}
}

function withPath(url: string, path = "/api/auth") {
	assertHasProtocol(url);

	const hasPath = checkHasPath(url);
	if (hasPath) {
		return url;
	}

	const trimmedUrl = url.replace(/\/+$/, "");
Repository: better-auth/better-auth
File: packages/better-auth/src/plugins/anonymous/index.ts (TypeScript)

Code before:
											required: ["message"],
										},
									},
								},
								"500": {
									description: "Internal server error",
									content: {
										"application/json": {
											schema: {
												type: "object",
												properties: {
													message: {
														type: "string",
													},
												},
												required: ["message"],
											},
										},
									},
								},
							},
						},
					},
				},
				async (ctx) => {
					const session = ctx.context.session as typeof ctx.context.session & {
						user: { isAnonymous: boolean | null };
					};

					if (options?.disableDeleteAnonymousUser) {
						throw new APIError("BAD_REQUEST", {
							message: ANONYMOUS_ERROR_CODES.DELETE_ANONYMOUS_USER_DISABLED,
						});
					}

					if (!session.user.isAnonymous) {
						throw new APIError("FORBIDDEN", {
							message: ANONYMOUS_ERROR_CODES.USER_IS_NOT_ANONYMOUS,
						});
					}

					try {
						await ctx.context.internalAdapter.deleteUser(session.user.id);
					} catch (error) {
						ctx.context.logger.error("Failed to delete anonymous user", error);
						throw new APIError("INTERNAL_SERVER_ERROR", {
							message: ANONYMOUS_ERROR_CODES.FAILED_TO_DELETE_ANONYMOUS_USER,
						});
					}
					deleteSessionCookie(ctx);
					return ctx.json({ success: true });

Review comment (refactor):
define `AnonymousSession` or some kind of helper type

Code after:
									description: "Anonymous user deletion is disabled",
									content: {
										"application/json": {
											schema: {
												type: "object",
												properties: {
													message: {
														type: "string",
													},
												},
											},
											required: ["message"],
										},
									},
								},
								"500": {
									description: "Internal server error",
									content: {
										"application/json": {
											schema: {
												type: "object",
												properties: {
													message: {
														type: "string",
													},
												},
												required: ["message"],
											},
										},
									},
								},
							},
						},
					},
				},
				async (ctx) => {
					const session = ctx.context.session as AnonymousSession;

					if (options?.disableDeleteAnonymousUser) {
						throw APIError.from(
							"BAD_REQUEST",
							ANONYMOUS_ERROR_CODES.DELETE_ANONYMOUS_USER_DISABLED,
						);
					}

					if (!session.user.isAnonymous) {
						throw APIError.from(
							"FORBIDDEN",
							ANONYMOUS_ERROR_CODES.USER_IS_NOT_ANONYMOUS,
						);
					}
Repository: better-auth/better-auth
File: packages/scim/src/types.ts (TypeScript)

Code before:
export type SCIMName = {
	formatted?: string;
	givenName?: string;
	familyName?: string;
};

export type SCIMEmail = { value?: string; primary?: boolean };

export type SCIMOptions = {
	/**
	 * Default list of SCIM providers for testing
	 * These will take precedence over the database when present
	 */
	defaultSCIM?: {
		/**
		 * The provider id
		 */
		providerId: string;
		/**
		 * The scim token
		 */
		scimToken: string;
		/**
		 * Optional organization id
		 */
		organizationId?: string;
	}[];
	/**
	 * A callback that runs before a new SCIM token is generated.
	 * @returns
	 */
	beforeSCIMTokenGenerated?: ({
		user,
		member,
		scimToken,
	}: {
		user: User;
		member?: Member | null;
		scimToken: string;
	}) => Promise<void>;

	/**
	 * A callback that runs before a new SCIM token is generated
	 * @returns
	 */
	afterSCIMTokenGenerated?: ({
		user,
		member,
		scimProvider,
	}: {
		user: User;

Review comment (suggestion):
@claude Please use `Omit<SCIMProvider, 'id'>[]` type here

Code after:
export type SCIMName = {
	formatted?: string;
	givenName?: string;
	familyName?: string;
};

export type SCIMEmail = { value?: string; primary?: boolean };

export type SCIMOptions = {
	/**
	 * Default list of SCIM providers for testing
	 * These will take precedence over the database when present
	 */
	defaultSCIM?: Omit<SCIMProvider, "id">[];
	/**
	 * A callback that runs before a new SCIM token is generated.
	 * @returns
	 */
	beforeSCIMTokenGenerated?: ({
		user,
		member,
		scimToken,
	}: {
		user: User;
		member?: Member | null;
		scimToken: string;
	}) => Promise<void>;

	/**
	 * A callback that runs before a new SCIM token is generated
	 * @returns
	 */
	afterSCIMTokenGenerated?: ({
		user,
		member,
		scimProvider,
	}: {
		user: User;
		member?: Member | null;
		scimToken: string;
		scimProvider: SCIMProvider;
	}) => Promise<void>;
	/**
	 * Store the SCIM token in your database in a secure way
	 *
	 * @default "plain"
	 */
	storeSCIMToken?:
		| (
				| "hashed"
				| "plain"
Repository: better-auth/better-auth
File: packages/core/src/types/context.ts (TypeScript)

Code before:
		 * option or `options.advanced?.disableOriginCheck` option.
		 *
		 * @default false
		 */
		skipOriginCheck: boolean;
		/**
		 * This skips the CSRF check for all requests.
		 *
		 * This is inferred from the `options.advanced?.
		 * disableCSRFCheck` option.
		 *
		 * @default false
		 */
		skipCSRFCheck: boolean;
		/**
		 * Paths that should skip origin check validation.
		 * These are normalized paths (without basePath prefix).
		 * Useful for endpoints that receive POST requests from external
		 * sources like IdP callbacks.
		 *
		 * Paths support prefix matching - a path like "/sso/saml2/callback"
		 * will match "/sso/saml2/callback/provider-name".
		 *
		 * @example ["/sso/saml2/callback", "/sso/saml2/sp/acs"]
		 */
		skipOriginCheckForPaths: string[];
	};


Review comment (suggestion):
let's rename this to `skipOriginCheck: string[] | boolean` - if set to true mean it'll skip orgin check for eveyrhign we should big warning for this in the jsdoc and docs

Code after:
		rateLimit: {
			enabled: boolean;
			window: number;
			max: number;
			storage: "memory" | "database" | "secondary-storage";
		} & Omit<
			BetterAuthRateLimitOptions,
			"enabled" | "window" | "max" | "storage"
		>;
		adapter: DBAdapter<Options>;
		internalAdapter: InternalAdapter<Options>;
		createAuthCookie: CreateCookieGetterFn;
		secret: string;
		sessionConfig: {
			updateAge: number;
			expiresIn: number;
			freshAge: number;
			cookieRefreshCache:
				| false
				| {
						enabled: true;
						updateAge: number;
				  };
		};
		generateId: (options: {
			model: ModelNames;
			size?: number | undefined;
		}) => string | false;
		secondaryStorage: SecondaryStorage | undefined;
		password: {
			hash: (password: string) => Promise<string>;
			verify: (data: { password: string; hash: string }) => Promise<boolean>;
			config: {
				minPasswordLength: number;
				maxPasswordLength: number;
			};
			checkPassword: CheckPasswordFn<Options>;
		};
		tables: BetterAuthDBSchema;
		runMigrations: () => Promise<void>;
		publishTelemetry: (event: {
			type: string;
			anonymousId?: string | undefined;
			payload: Record<string, any>;
		}) => Promise<void>;
		/**
		 * Skip origin check for requests.
		 *
		 * - `true`: Skip for ALL requests (DANGEROUS - disables CSRF protection)
		 * - `string[]`: Skip only for specific paths (e.g., SAML callbacks)
		 * - `false`: Enable origin check (default)
Repository: better-auth/better-auth
File: packages/sso/src/saml.test.ts (TypeScript)

Code before:
		provisionUser: vi
			.fn()
			.mockImplementation(async ({ user, userInfo, token, provider }) => {
				return {
					id: "provisioned-user-id",
					email: userInfo.email,
					name: userInfo.name,
					attributes: userInfo.attributes,
				};
			}),
	};

	const auth = betterAuth({
		database: memory,
		baseURL: "http://localhost:3000",
		emailAndPassword: {
			enabled: true,
		},
		plugins: [sso(ssoOptions)],
	});

	const authClient = createAuthClient({
		baseURL: "http://localhost:3000",
		plugins: [bearer(), ssoClient()],
		fetchOptions: {
			customFetchImpl: async (
				url: string | URL | Request,
				init?: RequestInit,
			) => {
				return auth.handler(new Request(url, init));
			},
		},
	});

	const testUser = {
		email: "test@email.com",
		password: "password",
		name: "Test User",
	};

	beforeAll(async () => {
		await authClient.signUp.email({
			email: testUser.email,
			password: testUser.password,
			name: testUser.name,
		});
	});

	beforeEach(() => {
		data.user = [];
		data.session = [];

Review comment (security):
I think we don't need to declare types here? since `createAuthClient` should already do that

Code after:
	};

	const auth = betterAuth({
		database: memory,
		baseURL: "http://localhost:3000",
		emailAndPassword: {
			enabled: true,
		},
		plugins: [sso(ssoOptions)],
	});

	const authClient = createAuthClient({
		baseURL: "http://localhost:3000",
		plugins: [bearer(), ssoClient()],
		fetchOptions: {
			customFetchImpl: async (url, init) => {
				return auth.handler(new Request(url, init));
			},
		},
	});

	const testUser = {
		email: "test@email.com",
		password: "password",
		name: "Test User",
	};

	beforeAll(async () => {
		await authClient.signUp.email({
			email: testUser.email,
			password: testUser.password,
			name: testUser.name,
		});
	});

	beforeEach(() => {
		data.user = [];
		data.session = [];
		data.verification = [];
		data.account = [];
		data.ssoProvider = [];

		vi.clearAllMocks();
	});

	async function getAuthHeaders() {
		const headers = new Headers();
		await authClient.signUp.email({
			email: testUser.email,
			password: testUser.password,
			name: testUser.name,
Repository: better-auth/better-auth
File: packages/core/src/social-providers/github.ts (TypeScript)

Code before:
			const { body, headers: requestHeaders } = createAuthorizationCodeRequest({
				code,
				codeVerifier,
				redirectURI,
				options,
			});

			const { data, error } = await betterFetch<
				| { access_token: string; token_type: string; scope: string }
				| { error: string; error_description?: string; error_uri?: string }
			>(tokenEndpoint, {
				method: "POST",
				body: body,
				headers: requestHeaders,
			});

			if (error) {
				throw error;
			}

			if ("error" in data) {
				throw new Error(
					data.error_description || data.error || "Failed to exchange code",
				);
			}

			return getOAuth2Tokens(data);
		},
		refreshAccessToken: options.refreshAccessToken
			? options.refreshAccessToken
			: async (refreshToken) => {
					return refreshAccessToken({
						refreshToken,
						options: {
							clientId: options.clientId,
							clientKey: options.clientKey,
							clientSecret: options.clientSecret,
						},
						tokenEndpoint: "https://github.com/login/oauth/access_token",
					});
				},
		async getUserInfo(token) {
			if (options.getUserInfo) {
				return options.getUserInfo(token);
			}
			const { data: profile, error } = await betterFetch<GithubProfile>(
				"https://api.github.com/user",
				{
					headers: {
						"User-Agent": "better-auth",
						authorization: `Bearer ${token.accessToken}`,

Review comment (suggestion):
maybe we should log this to the server and just return null instead or something than throwing new Error

Code after:
		validateAuthorizationCode: async ({ code, codeVerifier, redirectURI }) => {
			const { body, headers: requestHeaders } = createAuthorizationCodeRequest({
				code,
				codeVerifier,
				redirectURI,
				options,
			});

			const { data, error } = await betterFetch<
				| { access_token: string; token_type: string; scope: string }
				| { error: string; error_description?: string; error_uri?: string }
			>(tokenEndpoint, {
				method: "POST",
				body: body,
				headers: requestHeaders,
			});

			if (error) {
				logger.error("GitHub OAuth token exchange failed:", error);
				return null;
			}

			if ("error" in data) {
				logger.error("GitHub OAuth token exchange failed:", data);
				return null;
			}

			return getOAuth2Tokens(data);
		},
		refreshAccessToken: options.refreshAccessToken
			? options.refreshAccessToken
			: async (refreshToken) => {
					return refreshAccessToken({
						refreshToken,
						options: {
							clientId: options.clientId,
							clientKey: options.clientKey,
							clientSecret: options.clientSecret,
						},
						tokenEndpoint: "https://github.com/login/oauth/access_token",
					});
				},
		async getUserInfo(token) {
			if (options.getUserInfo) {
				return options.getUserInfo(token);
			}
			const { data: profile, error } = await betterFetch<GithubProfile>(
				"https://api.github.com/user",
				{
					headers: {
						"User-Agent": "better-auth",
Repository: better-auth/better-auth
File: packages/core/src/types/context.ts (TypeScript)

Code before:
	} | null>;

	findSessions(
		sessionTokens: string[],
	): Promise<{ session: Session; user: User }[]>;

	updateSession(
		sessionToken: string,
		session: Partial<Session> & Record<string, any>,
	): Promise<Session | null>;

	deleteSession(token: string): Promise<void>;

	deleteAccounts(userId: string): Promise<void>;

	deleteAccount(accountId: string): Promise<void>;

	deleteSessions(userIdOrSessionTokens: string | string[]): Promise<void>;

	findOAuthUser(
		email: string,
		accountId: string,
		providerId: string,
	): Promise<{
		user: User;
		linkedAccount?: Account;
		accounts: Account[];
	} | null>;

	findUserByEmail(
		email: string,
		options?: { includeAccounts: boolean } | undefined,
	): Promise<{ user: User; accounts: Account[] } | null>;

	findUserById(userId: string): Promise<User | null>;

	linkAccount(
		account: Omit<Account, "id" | "createdAt" | "updatedAt"> & Partial<Account>,
	): Promise<Account>;

	// Record<string, any> is to take into account additional fields or plugin-added fields
	updateUser<T extends Record<string, any>>(
		userId: string,
		data: Partial<User> & Record<string, any>,
	): Promise<User & T>;

	updateUserByEmail<T extends Record<string, any>>(
		email: string,
		data: Partial<User & Record<string, any>>,
	): Promise<User & T>;


Review comment (suggestion):
@claude Please update the type to `Account | null` and fix the related code

Code after:
	} | null>;

	findSessions(
		sessionTokens: string[],
	): Promise<{ session: Session; user: User }[]>;

	updateSession(
		sessionToken: string,
		session: Partial<Session> & Record<string, any>,
	): Promise<Session | null>;

	deleteSession(token: string): Promise<void>;

	deleteAccounts(userId: string): Promise<void>;

	deleteAccount(accountId: string): Promise<void>;

	deleteSessions(userIdOrSessionTokens: string | string[]): Promise<void>;

	findOAuthUser(
		email: string,
		accountId: string,
		providerId: string,
	): Promise<{
		user: User;
		linkedAccount: Account | null;
		accounts: Account[];
	} | null>;

	findUserByEmail(
		email: string,
		options?: { includeAccounts: boolean } | undefined,
	): Promise<{ user: User; accounts: Account[] } | null>;

	findUserById(userId: string): Promise<User | null>;

	linkAccount(
		account: Omit<Account, "id" | "createdAt" | "updatedAt"> & Partial<Account>,
	): Promise<Account>;

	// Record<string, any> is to take into account additional fields or plugin-added fields
	updateUser<T extends Record<string, any>>(
		userId: string,
		data: Partial<User> & Record<string, any>,
	): Promise<User & T>;

	updateUserByEmail<T extends Record<string, any>>(
		email: string,
		data: Partial<User & Record<string, any>>,
	): Promise<User & T>;
Repository: better-auth/better-auth
File: packages/core/src/context/transaction.ts (TypeScript)

Code before:
import type { AsyncLocalStorage } from "node:async_hooks";
import { getAsyncLocalStorage } from "@better-auth/core/async_hooks";
import type { DBAdapter, DBTransactionAdapter } from "../db/adapter";
import { getBetterAuthGlobal } from "./global";

type HookContext = {
	adapter: DBTransactionAdapter;
	pendingHooks: Array<() => Promise<void>>;
};

const ensureAsyncStorage = async () => {
	const betterAuthGlobal = getBetterAuthGlobal();
	if (!betterAuthGlobal.context.adapterAsyncStorage) {
		const AsyncLocalStorage = await getAsyncLocalStorage();
		betterAuthGlobal.context.adapterAsyncStorage = new AsyncLocalStorage();
	}
	return betterAuthGlobal.context
		.adapterAsyncStorage as AsyncLocalStorage<HookContext>;
};

/**
 * This is for internal use only. Most users should use `getCurrentAdapter` instead.
 *
 * It is exposed for advanced use cases where you need direct access to the AsyncLocalStorage instance.
 */
export const getCurrentDBAdapterAsyncLocalStorage = async () => {
	return ensureAsyncStorage();
};

export const getCurrentAdapter = async (
	fallback: DBTransactionAdapter,
): Promise<DBTransactionAdapter> => {
	return ensureAsyncStorage()

Review comment (suggestion):
@claude 

Please use `(() => Promise<void>)[]` type instead

Code after:
import type { AsyncLocalStorage } from "node:async_hooks";
import { getAsyncLocalStorage } from "@better-auth/core/async_hooks";
import type { DBAdapter, DBTransactionAdapter } from "../db/adapter";
import { __getBetterAuthGlobal } from "./global";

type HookContext = {
	adapter: DBTransactionAdapter;
	pendingHooks: Array<() => Promise<void>>;
};

const ensureAsyncStorage = async () => {
	const betterAuthGlobal = __getBetterAuthGlobal();
	if (!betterAuthGlobal.context.adapterAsyncStorage) {
		const AsyncLocalStorage = await getAsyncLocalStorage();
		betterAuthGlobal.context.adapterAsyncStorage = new AsyncLocalStorage();
	}
	return betterAuthGlobal.context
		.adapterAsyncStorage as AsyncLocalStorage<HookContext>;
};

/**
 * This is for internal use only. Most users should use `getCurrentAdapter` instead.
 *
 * It is exposed for advanced use cases where you need direct access to the AsyncLocalStorage instance.
 */
export const getCurrentDBAdapterAsyncLocalStorage = async () => {
	return ensureAsyncStorage();
};

export const getCurrentAdapter = async (
	fallback: DBTransactionAdapter,
): Promise<DBTransactionAdapter> => {
	return ensureAsyncStorage()