import { Inter } from "next/font/google"; import "./globals.css"; import { ThemeProvider } from "@/shared/components/ThemeProvider"; import { NextIntlClientProvider } from "next-intl"; import { getMessages, getLocale, getTranslations } from "next-intl/server"; import { RTL_LOCALES } from "@/i18n/config"; import { normalizeComplianceEventTypes } from "@/i18n/request"; import { getSettings } from "@/lib/db/settings"; import type { Viewport } from "next"; import { PwaRegister } from "@/shared/components/PwaRegister"; import { LocaleAutoDetect } from "@/shared/components/LocaleAutoDetect"; import { BasePathNetworkProvider } from "@/shared/components/BasePathNetworkProvider"; const inter = Inter({ subsets: ["latin"], variable: "--font-inter", }); export const viewport: Viewport = { themeColor: "#0b0f1a", viewportFit: "cover", }; export async function generateMetadata() { const settings = await getSettings(); const instanceName = settings?.instanceName || "OmniRoute"; const customFaviconUrl = settings?.customFaviconUrl || settings?.customFaviconBase64; return { title: `${instanceName} — AI Gateway for Multi-Provider LLMs`, description: "OmniRoute is an AI gateway for multi-provider LLMs. One endpoint for all your AI providers.", manifest: "/manifest.webmanifest", applicationName: instanceName, appleWebApp: { capable: true, title: instanceName, statusBarStyle: "black-translucent", }, other: { "mobile-web-app-capable": "yes", }, icons: { icon: customFaviconUrl ? "/api/settings/favicon" : [ { url: "/favicon.ico", sizes: "any" }, { url: "/favicon.svg", type: "image/svg+xml" }, { url: "/icon-512.png", type: "image/png", sizes: "512x512" }, ], apple: [{ url: "/apple-touch-icon.png", sizes: "180x180", type: "image/png" }], }, }; } export default async function RootLayout({ children }) { const locale = await getLocale(); const t = await getTranslations("sidebar"); const messages = normalizeComplianceEventTypes((await getMessages()) as Record); const isRtl = RTL_LOCALES.includes(locale as (typeof RTL_LOCALES)[number]); return ( {/* Pre-hydration cleanup: browser extensions (Bitdefender's bis_skin_checked, Grammarly's data-gr-ext-installed, LanguageTool's data-lt-installed, etc.) inject attributes into the DOM after SSR but before React hydrates, causing hydration mismatch warnings in dev. Strip them synchronously and observe for late injections; the observer auto-disconnects after 5s (well past typical hydration). */}