Ctrl K
ComunidadGuías…

eslint.config.mjs

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
import { FlatCompat } from "@eslint/eslintrc";
import { readFileSync } from "node:fs";
import { dirname } from "path";
import { fileURLToPath } from "url";

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

const compat = new FlatCompat({ baseDirectory: __dirname });

/**
 * Ce fichier est SYNCHRONISÉ vers le build self-host (mono-tenant), où le
 * client `prisma` est un PrismaClient ordinaire et où `$transaction` est
 * parfaitement légitime — 9 sites l'utilisent. Y appliquer la règle F5.1
 * ci-dessous rendrait `npm run lint` rouge chez tous les auto-hébergés.
 *
 * Plutôt qu'un jumeau d'overlay de plus à maintenir (et à voir diverger), on
 * détecte la présence du client ÉTENDU, seule raison d'être de la règle : le
 * marqueur `TenantAwarePrisma` n'existe que dans le `lib/prisma.ts` du SaaS.
 * Si un jour l'extension disparaît, la règle s'éteint d'elle-même — ce qui est
 * exactement le comportement voulu.
 */
const hasExtendedPrismaClient = (() => {
  try {
    return readFileSync(`${__dirname}/lib/prisma.ts`, "utf8").includes(
      "TenantAwarePrisma",
    );
  } catch {
    return false;
  }
})();

const eslintConfig = [
  ...compat.extends("next/core-web-vitals", "next/typescript"),
  {
    ignores: [
      ".next/**",
      "node_modules/**",
      "prisma/migrations/**",
      "next-env.d.ts",
    ],
  },
  ...(hasExtendedPrismaClient
    ? [
        {
          // F5.1 — `prisma.$transaction` sur le client étendu (lib/prisma.ts) n'ouvre
          // aucune transaction utile : l'extension redispatche chaque opération vers
          // un autre PrismaClient, qui les exécute en autocommit hors transaction.
          // Le type l'interdit déjà (le `$transaction` est retiré de
          // `TenantAwarePrisma`) ; cette règle n'existe que pour que le message soit
          // lisible plutôt qu'un « Property '$transaction' does not exist ».
          //
          // Portée : `app/**` et `lib/**`, les seuls endroits où le nom `prisma`
          // désigne le client étendu. Ailleurs il désigne un vrai client et
          // `$transaction` y est légitime : les `scripts/*.mjs` autonomes font leur
          // propre `new PrismaClient()`, et `scripts/public-overlay/**` est le jumeau
          // self-host mono-tenant. `basePrisma`, `adminPrisma` et
          // `getTenantPrisma(slug)` ne sont jamais visés — le sélecteur porte sur le
          // nom `prisma` seul. Le garde-fou qui couvre TOUT reste le type.
          files: ["app/**/*.{ts,tsx}", "lib/**/*.{ts,tsx}"],
          rules: {
            "no-restricted-syntax": [
              "error",
              {
                selector:
                  'MemberExpression[object.name="prisma"][property.name="$transaction"]',
                message:
                  "prisma.$transaction n'a AUCUNE atomicité (client étendu multi-tenant, cf. rapport-security.md §F5.1). Utiliser withTenantSchema(slug, (tx) => …) de lib/tenant.ts.",
              },
            ],
          },
        },
      ]
    : []),
];

export default eslintConfig;