import type { NextConfig } from "next"; const nextConfig: NextConfig = { async redirects() { return [ { // La doc développeurs vit désormais sur developers.cordsuite.app. // Permanent (308) : les anciens liens et les moteurs de recherche suivent. source: "/docs/technique/api-v2", destination: "https://developers.cordsuite.app/api/drivecord", permanent: true, }, { source: "/docs/technique/applications", destination: "https://developers.cordsuite.app/auth", permanent: true, }, { source: "/docs/technique/sdk", destination: "https://developers.cordsuite.app/sdk", permanent: true, }, { // Lien d'invitation « vanity » : on communique drivecord.app/discord // partout, et il redirige vers l'invitation Discord réelle. Non // permanent (307) exprès : si l'invitation change un jour, il suffit // de modifier l'URL ci-dessous — aucun cache navigateur à purger. source: "/discord", destination: "https://discord.gg/drivecord", permanent: false, }, { // Lien vanity vers le dashboard DriveBot (hébergé séparément). Non // permanent (307) exprès pour pouvoir changer l'URL sans purge cache. source: "/drivebot", destination: "https://drivebot-dashboard.vercel.app/", permanent: false, }, { // Lien vanity vers le dépôt GitHub : on communique drivecord.app/github // et il redirige vers le dépôt réel. Non permanent (307) exprès pour // pouvoir changer d'organisation ou de nom de dépôt sans purge cache. source: "/github", destination: "https://github.com/LeVraiLunatix/drivecord", permanent: false, }, { // Lien vanity vers la page Patreon : on communique drivecord.app/patreon // et il redirige vers la vraie page. Non permanent (307) pour pouvoir // changer le slug sans purge cache. source: "/patreon", destination: "https://www.patreon.com/drivecord", permanent: false, }, ]; }, async headers() { return [ { // Consent / developer / login screens must never be framed (clickjacking of an "Authorize" button). source: "/:path(oauth|developers|login|settings)/:rest*", headers: [ { key: "Content-Security-Policy", value: "frame-ancestors 'none'" }, { key: "X-Frame-Options", value: "DENY" }, ], }, { // Baseline hardening for every response. 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=(), payment=()" }, { key: "Strict-Transport-Security", value: "max-age=31536000; includeSubDomains" }, ], }, { // The popup that mints an embed ticket is first-party only. source: "/embed/connect", headers: [ { key: "Content-Security-Policy", value: "frame-ancestors 'none'" }, { key: "X-Frame-Options", value: "DENY" }, ], }, { // Never cache HTML documents / API responses, so the in-app WebView // always loads the latest deploy on relaunch. Hashed static assets // under /_next/ are excluded and stay immutably cached. source: "/((?!_next/).*)", headers: [ { key: "Cache-Control", value: "no-store, must-revalidate" }, ], }, ]; }, }; export default nextConfig;