IKHSAN
EN Read in EnglishID

snapme

Publik
Branch
master
Commit terakhir
130fdb828 Oktober 2026

next.config.ts

Buka raw
import type { NextConfig } from "next";

/* ARCHITECTURE §8: header keamanan. Kamera dibatasi ke origin sendiri, halaman
   strip tidak mengirim referrer dan tidak diindeks, dan halaman itu tidak boleh
   dibingkai situs lain. M9 memasang CSP penuh: seluruh halaman dan rutenya
   memakai satu kebijakan yang sama, termasuk `frame-ancestors 'none'` yang
   sebelumnya hanya dipasang di `/s` dan `/r`. */

/* Semua aset dan permintaan snapme berasal dari origin sendiri: fon di-host
   sendiri, wasm dan model MediaPipe di-host sendiri, dan tidak ada unggahan
   ke layanan luar, jadi CSP tidak punya host luar yang perlu diizinkan. */

/* Alasan tiap direktif (rinciannya di docs/DECISIONS.md, M9):

   - `script-src 'unsafe-inline'`: skrip bootstrap App Router ditulis inline dan
     tanpa nonce. Nonce memaksa render dinamis di setiap permintaan, yang
     bertabrakan dengan `cacheComponents` dan target LCP Welcome (PRD §8).
   - `script-src 'wasm-unsafe-eval'`: Gesture Snap menjalankan model MediaPipe
     yang di-host sendiri (ARCHITECTURE §6, §8).
   - `'unsafe-eval'` hanya di pengembangan, karena React memakainya untuk
     menyusun ulang jejak galat di peramban; produksi tidak butuh itu.
   - `img-src`/`media-src` `blob:` dan `data:`: pratinjau dan ekspor lewat
     kanvas (`toDataURL`), bingkai klip sebagai ImageBitmap, dan hasil
     MediaRecorder sebagai URL blob.
   - `connect-src` `blob:` dan `data:`: konversi hasil ekspor jadi Blob lewat
     `fetch(dataUrl)`, tanpa jaringan keluar.
   - `worker-src 'self' blob:`: MediaPipe membuat worker dari berkasnya sendiri
     dan dari blob.
   - `font-src 'self' data:`: fon di-host sendiri lewat next/font.
   - `object-src 'none'`, `base-uri 'self'`, `form-action 'self'`,
     `frame-ancestors 'none'`: pagar dasar tanpa pemakaian yang sah di produk
     ini. */
const CSP = [
  "default-src 'self'",
  `script-src 'self' 'unsafe-inline' 'wasm-unsafe-eval'${
    process.env.NODE_ENV === "development" ? " 'unsafe-eval'" : ""
  }`,
  "style-src 'self' 'unsafe-inline'",
  `img-src 'self' blob: data:`,
  `media-src 'self' blob: data:`,
  `connect-src 'self' blob: data:`,
  "font-src 'self' data:",
  "worker-src 'self' blob:",
  "object-src 'none'",
  "base-uri 'self'",
  "form-action 'self'",
  "frame-ancestors 'none'",
].join("; ");

const SECURITY_HEADERS = [
  { key: "Content-Security-Policy", value: CSP },
  { key: "Permissions-Policy", value: "camera=(self)" },
  { key: "X-Content-Type-Options", value: "nosniff" },
  { key: "Referrer-Policy", value: "strict-origin-when-cross-origin" },
];

const PRIVATE_HEADERS = [
  { key: "Referrer-Policy", value: "no-referrer" },
  { key: "X-Robots-Tag", value: "noindex" },
];

const nextConfig: NextConfig = {
  /* config options here */
  /* M10: `cacheComponents`, `partialPrefetching`, dan `htmlLimitedBots`
     DILEPAS. Ketiganya semula dipakai untuk PPR dan status 404 yang benar di
     `/s/[id]` dan `/r/[id]`, tetapi mesin Cache Components menolak berjalan
     stabil di bawah permintaan bersamaan: `CacheSignal` melempar
     "Cannot perform I/O on behalf of a different request" (penanda waktu yang
     dibuat di konteks permintaan lain) dan server menjawab 500 untuk semua
     permintaan berikutnya. Tanpa PPR, kedua halaman itu dirender dinamis dan
     `notFound()` tetap menjawab 404 sungguhan. Rinciannya di
     `docs/DECISIONS.md` M10. */
  turbopack: {
    rules: {
      "*.css": {
        loaders: ["@tailwindcss/turbopack"],
        as: "*.css",
      },
    },
  },
  async headers() {
    return [
      { source: "/:path*", headers: SECURITY_HEADERS },
      /* `/r/[id]` milik M8; aturannya sudah dipasang sekarang supaya halaman
         estafet tidak pernah bocor referrer saat dibangun. CSP-nya sudah
         ikut dari baris pertama. */
      { source: "/s/:path*", headers: PRIVATE_HEADERS },
      { source: "/r/:path*", headers: PRIVATE_HEADERS },
    ];
  },
};

export default nextConfig;
byte
3.957
baris
94
Jenis
ts
Commit terakhir
28 Oktober 2026