fix(web): csp font violation, /pricing 401, residual login emoji
Some checks failed
CI / Lint (push) Has been cancelled
CI / Typecheck (push) Has been cancelled
CI / Broker tests (Postgres) (push) Has been cancelled
CI / Docker build (linux/amd64) (push) Has been cancelled

Three bugs caught via devtools on live site:

**1. CSP 'font-src 'self' data:' violation × 3 per landing load.**
BaseLayout was loading Geist + Geist_Mono via next/font/google. In
prod builds Next.js self-hosts those under /_next/static, but the
generated CSS still references `--font-sans: "Geist", …` which some
browsers resolve by re-requesting fonts.gstatic.com. Since we ship
Anthropic Sans/Serif/Mono self-hosted already (/fonts/*.woff2 via
@font-face in globals.css), the Geist dependency was pure overhead.

Removed `next/font/google` imports entirely. Added a `.cm-root`
class on <html> that remaps the Tailwind `--font-sans/--font-mono`
tokens to our `--cm-font-sans/--cm-font-mono` vars — so every
Tailwind `font-sans` / `font-mono` utility now resolves to Anthropic
families. No Google Fonts fetch, no CSP violation.

**2. /pricing 401 on public visit.**
`<Plan>` calls `useCustomer()` → `GET /api/billing/customer` which
needs auth. Unauthed visitor on /pricing → 401 in devtools + wasted
round trip. Gated `useCustomer` on `authClient.useSession()` —
query `enabled: !!session?.user`. Public visitors now skip the fetch
entirely; signed-in users still get their customer record.

**3. Residual "Welcome back! 👋" on /auth/login (both locales).**
Emoji sweep (e91fc80) missed the i18n translation files. Removed 👋
from en/auth.json + es/auth.json login header titles.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Alejandro Gutiérrez
2026-04-05 16:41:23 +01:00
parent 6acfc252b0
commit c3fa04dde8
5 changed files with 26 additions and 19 deletions

View File

@@ -154,3 +154,13 @@
:root { :root {
color-scheme: dark; color-scheme: dark;
} }
/* Override the Tailwind default --font-sans / --font-mono CSS vars
(which BaseLayout used to populate from next/font/google Geist).
We self-host Anthropic Sans/Serif/Mono now — no Google Fonts fetch,
no CSP font-src violation. */
.cm-root {
--font-sans: var(--cm-font-sans);
--font-mono: var(--cm-font-mono);
--font-serif: var(--cm-font-serif);
}

View File

@@ -1,5 +1,17 @@
import { useQuery } from "@tanstack/react-query"; import { useQuery } from "@tanstack/react-query";
import { authClient } from "~/lib/auth/client";
import { billing } from "~/modules/billing/lib/api"; import { billing } from "~/modules/billing/lib/api";
export const useCustomer = () => useQuery(billing.queries.customer.get); /**
* Fetches the current user's billing customer. Gated on session
* presence so unauthenticated public pages (landing, /pricing) don't
* fire a 401 just to render plan cards.
*/
export const useCustomer = () => {
const { data: session } = authClient.useSession();
return useQuery({
...billing.queries.customer.get,
enabled: !!session?.user,
});
};

View File

@@ -1,22 +1,7 @@
import { Geist_Mono, Geist } from "next/font/google";
import { cn } from "@turbostarter/ui"; import { cn } from "@turbostarter/ui";
import { appConfig } from "~/config/app"; import { appConfig } from "~/config/app";
const sans = Geist({
subsets: ["latin"],
display: "swap",
variable: "--font-sans",
});
const mono = Geist_Mono({
subsets: ["latin"],
display: "swap",
variable: "--font-mono",
weight: ["300", "400", "500"],
});
interface BaseLayoutProps { interface BaseLayoutProps {
readonly locale: string; readonly locale: string;
readonly children: React.ReactNode; readonly children: React.ReactNode;
@@ -24,7 +9,7 @@ interface BaseLayoutProps {
export const BaseLayout = ({ children, locale }: BaseLayoutProps) => { export const BaseLayout = ({ children, locale }: BaseLayoutProps) => {
return ( return (
<html lang={locale} className={cn(sans.variable, mono.variable)}> <html lang={locale} className={cn("cm-root")}>
<body <body
suppressHydrationWarning suppressHydrationWarning
className="bg-background text-foreground flex min-h-screen flex-col items-center justify-center font-sans antialiased" className="bg-background text-foreground flex min-h-screen flex-col items-center justify-center font-sans antialiased"

View File

@@ -224,7 +224,7 @@
"login": { "login": {
"title": "Login", "title": "Login",
"header": { "header": {
"title": "Welcome back! 👋", "title": "Welcome back",
"description": "Enter your data below to login to your account" "description": "Enter your data below to login to your account"
}, },
"magicLink": { "magicLink": {

View File

@@ -218,7 +218,7 @@
"login": { "login": {
"title": "Iniciar sesión", "title": "Iniciar sesión",
"header": { "header": {
"title": "¡Bienvenido de nuevo! 👋", "title": "Bienvenido de nuevo",
"description": "Ingresa tus datos abajo" "description": "Ingresa tus datos abajo"
}, },
"magicLink": { "magicLink": {