mirror of
https://github.com/felipegcoutinho/openmonetis.git
synced 2026-05-09 19:01:47 +00:00
feat(logo): migrar token Logo.dev para runtime server-side
NEXT_PUBLIC_LOGO_DEV_TOKEN renomeado para LOGO_DEV_TOKEN — lido apenas em runtime no servidor. URL construída nos endpoints /api/logo/mapping e /api/logo/search; cliente nunca recebe o token. Novo server.ts com isLogoDevEnabled() e buildLogoDevUrl(). LogoDevProvider (Context) propaga flag `enabled` para Client Components. Build arg removido do Dockerfile e do workflow docker-publish.yml. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,9 +1,10 @@
|
||||
import { connection } from "next/server";
|
||||
import { fetchDashboardNavbarData } from "@/features/dashboard/navbar-queries";
|
||||
import { AppNavbar } from "@/shared/components/navigation/navbar/app-navbar";
|
||||
import { LogoDevProvider } from "@/shared/components/providers/logo-dev-provider";
|
||||
import { PrivacyProvider } from "@/shared/components/providers/privacy-provider";
|
||||
import { DotPattern } from "@/shared/components/ui/dot-pattern";
|
||||
import { getUserSession } from "@/shared/lib/auth/server";
|
||||
import { isLogoDevEnabled } from "@/shared/lib/logo/server";
|
||||
|
||||
export default async function DashboardLayout({
|
||||
children,
|
||||
@@ -13,33 +14,25 @@ export default async function DashboardLayout({
|
||||
await connection();
|
||||
const session = await getUserSession();
|
||||
const navbarData = await fetchDashboardNavbarData(session.user.id);
|
||||
const logoDevEnabled = isLogoDevEnabled();
|
||||
|
||||
return (
|
||||
<PrivacyProvider>
|
||||
<AppNavbar
|
||||
user={{ ...session.user, image: session.user.image ?? null }}
|
||||
pagadorAvatarUrl={navbarData.pagadorAvatarUrl}
|
||||
preLancamentosCount={navbarData.preLancamentosCount}
|
||||
notificationsSnapshot={navbarData.notificationsSnapshot}
|
||||
/>
|
||||
<div className="relative flex flex-1 flex-col pt-16">
|
||||
<div className="pointer-events-none absolute inset-x-0 top-0 h-32 overflow-hidden md:h-36">
|
||||
<DotPattern
|
||||
width={20}
|
||||
height={20}
|
||||
cx={1.25}
|
||||
cy={1.25}
|
||||
cr={1.25}
|
||||
className="text-primary/10 mask-[linear-gradient(to_bottom,black_0%,transparent_100%)]"
|
||||
/>
|
||||
<div className="absolute inset-0 bg-linear-to-b from-primary/6 to-transparent" />
|
||||
</div>
|
||||
<div className="@container/main flex flex-1 flex-col gap-2">
|
||||
<div className="flex flex-col gap-4 py-5 md:gap-6 w-full max-w-8xl mx-auto px-4 ">
|
||||
{children}
|
||||
<LogoDevProvider enabled={logoDevEnabled}>
|
||||
<PrivacyProvider>
|
||||
<AppNavbar
|
||||
user={{ ...session.user, image: session.user.image ?? null }}
|
||||
pagadorAvatarUrl={navbarData.pagadorAvatarUrl}
|
||||
preLancamentosCount={navbarData.preLancamentosCount}
|
||||
notificationsSnapshot={navbarData.notificationsSnapshot}
|
||||
/>
|
||||
<div className="relative flex flex-1 flex-col pt-16">
|
||||
<div className="@container/main flex flex-1 flex-col gap-2">
|
||||
<div className="flex flex-col gap-4 py-5 md:gap-6 w-full max-w-8xl mx-auto px-4 ">
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</PrivacyProvider>
|
||||
</PrivacyProvider>
|
||||
</LogoDevProvider>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,26 +1,29 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { getOptionalUserSession } from "@/shared/lib/auth/server";
|
||||
import { fetchEstablishmentLogoDomain } from "@/shared/lib/logo/establishment-logo-queries";
|
||||
import { buildLogoDevUrl } from "@/shared/lib/logo/server";
|
||||
|
||||
/**
|
||||
* GET /api/logo/mapping?name={name}
|
||||
*
|
||||
* Retorna o domínio Logo.dev salvo pelo usuário para um estabelecimento.
|
||||
* Usado pelo EstablishmentLogo para hidratar o domain salvo no banco.
|
||||
* Retorna o domínio Logo.dev salvo pelo usuário para um estabelecimento,
|
||||
* junto com a `logoUrl` final (construída server-side com o token). O
|
||||
* cliente usa `logoUrl` diretamente — sem precisar conhecer o token.
|
||||
*/
|
||||
export async function GET(request: Request) {
|
||||
const session = await getOptionalUserSession();
|
||||
if (!session) {
|
||||
return NextResponse.json({ domain: null }, { status: 200 });
|
||||
return NextResponse.json({ domain: null, logoUrl: null }, { status: 200 });
|
||||
}
|
||||
|
||||
const { searchParams } = new URL(request.url);
|
||||
const name = searchParams.get("name")?.trim();
|
||||
|
||||
if (!name) {
|
||||
return NextResponse.json({ domain: null }, { status: 200 });
|
||||
return NextResponse.json({ domain: null, logoUrl: null }, { status: 200 });
|
||||
}
|
||||
|
||||
const domain = await fetchEstablishmentLogoDomain(session.user.id, name);
|
||||
return NextResponse.json({ domain });
|
||||
const logoUrl = buildLogoDevUrl(domain);
|
||||
return NextResponse.json({ domain, logoUrl });
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { getOptionalUserSession } from "@/shared/lib/auth/server";
|
||||
import { buildLogoDevUrl } from "@/shared/lib/logo/server";
|
||||
|
||||
const LOGO_DEV_SEARCH_URL = "https://api.logo.dev/search";
|
||||
|
||||
@@ -8,6 +9,10 @@ interface LogoResult {
|
||||
domain: string;
|
||||
}
|
||||
|
||||
interface LogoResultWithUrl extends LogoResult {
|
||||
logoUrl: string | null;
|
||||
}
|
||||
|
||||
async function searchByStrategy(
|
||||
q: string,
|
||||
strategy: "match" | "typeahead",
|
||||
@@ -66,12 +71,14 @@ export async function GET(request: Request) {
|
||||
|
||||
// Mescla e deduplica por domain, mantendo ordem (match tem prioridade)
|
||||
const seen = new Set<string>();
|
||||
const merged: LogoResult[] = [];
|
||||
const merged: LogoResultWithUrl[] = [];
|
||||
|
||||
for (const result of [...matchResults, ...typeaheadResults]) {
|
||||
if (!seen.has(result.domain)) {
|
||||
seen.add(result.domain);
|
||||
merged.push(result);
|
||||
// logoUrl é construída server-side com o token — o cliente nunca
|
||||
// precisa conhecer LOGO_DEV_TOKEN para renderizar a imagem.
|
||||
merged.push({ ...result, logoUrl: buildLogoDevUrl(result.domain) });
|
||||
if (merged.length >= 20) break;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user