next.config.ts
Rama main · réplica de lectura del repositorio original.
import type { NextConfig } from "next";
import { LEGACY_SETTINGS_REDIRECTS } from "./lib/settings/tabs";
const nextConfig: NextConfig = {
images: {
// 75 is next/image's default; 85 is the title page's full-bleed backdrop
// (components/title-hero.tsx), where 75 bands the long fades and shows
// blocks in dark skies at 2560px.
qualities: [75, 85],
remotePatterns: [
{
protocol: "https",
hostname: "image.tmdb.org",
pathname: "/t/p/**",
},
// TheTVDB's own artwork CDN — used as a poster/backdrop fallback when
// TMDb doesn't have one yet, for titles that have a TVDB API key
// connected.
{
protocol: "https",
hostname: "artworks.thetvdb.com",
},
],
},
// Settings' pages that moved when it was regrouped into tabs
// (lib/settings/tabs.ts): bookmarks and the apps' links still land.
async redirects() {
return LEGACY_SETTINGS_REDIRECTS.map((entry) => ({ ...entry, permanent: false }));
},
// Every /api/v1 route handler sets X-Marquee-API itself; this also covers
// the responses Next.js generates on its own for those paths (405 Method
// Not Allowed, automatic OPTIONS), so native clients can always tell a v1
// server's answer apart from something else on the same host.
async headers() {
return [
// Baseline hardening for every response. Framing is deliberately left
// alone: plenty of self-hosters embed Marquee in Organizr or Homarr,
// and a frame-ancestors rule would break that.
{
source: "/:path*",
headers: [
{ key: "X-Content-Type-Options", value: "nosniff" },
{ key: "Referrer-Policy", value: "strict-origin-when-cross-origin" },
{ key: "Permissions-Policy", value: "camera=(), microphone=(), geolocation=()" },
],
},
// The pages the Mac and Windows apps open for single sign-on: "Continue"
// there hands an app a session, so it's never shown inside someone
// else's frame (clickjacking). They're opened in the browser directly,
// never embedded, so this costs the Organizr/Homarr case nothing.
{
source: "/login/sso/:path*",
headers: [
{ key: "X-Frame-Options", value: "DENY" },
{ key: "Content-Security-Policy", value: "frame-ancestors 'none'" },
],
},
// The push service worker (public/sw.js): never cached, so a fix to
// it reaches every browser on its next visit, and scripts only from
// this site.
{
source: "/sw.js",
headers: [
{ key: "Content-Type", value: "application/javascript; charset=utf-8" },
{ key: "Cache-Control", value: "no-cache, no-store, must-revalidate" },
{ key: "Content-Security-Policy", value: "default-src 'self'; script-src 'self'" },
],
},
{ source: "/api/v1", headers: [{ key: "X-Marquee-API", value: "1" }] },
{ source: "/api/v1/:path*", headers: [{ key: "X-Marquee-API", value: "1" }] },
];
},
};
export default nextConfig;