Ctrl K
ComunidadGuías…

eslint.config.js

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

Archivo original ↗Preguntar a KiBot
import js from '@eslint/js'
import tseslint from 'typescript-eslint'

export default tseslint.config(
  { ignores: ['**/dist/**', '**/node_modules/**', '**/*.tsbuildinfo'] },
  js.configs.recommended,
  tseslint.configs.recommended,
  {
    // Plain-JS tooling runs on Node. no-undef is off for .ts files by default,
    // because the compiler answers that question better.
    // Build and CI tooling, wherever it lives — the repository's scripts/, the
    // per-package ones a build step invokes, and the ones a workflow runs.
    files: [
      'scripts/**/*.{js,mjs,cjs}',
      'packages/*/scripts/**/*.{js,mjs,cjs}',
      '.github/scripts/**/*.{js,mjs,cjs}',
    ],
    languageOptions: {
      // Listed rather than pulled from a `globals` package: the list being
      // short is the point. A script here reaching for something not on it is
      // worth noticing, and `fetch` and `setTimeout` earned their place by the
      // release plan asking the registry what it already holds.
      globals: {
        console: 'readonly',
        process: 'readonly',
        URL: 'readonly',
        fetch: 'readonly',
        setTimeout: 'readonly',
        // Beside `setTimeout`, and it earned its place the same way: the seed
        // harness arms a deadline for the stub API's port and disarms it, and a
        // timer nobody clears keeps a check's process alive after it has
        // answered.
        clearTimeout: 'readonly',
        // Earned its place the same way: the WebAuthn end-to-end signs a token
        // with a secret it builds here, exactly as the suites do.
        TextEncoder: 'readonly',
        // For the *browser* side of a `page.evaluate`, which is lexically in
        // these files and runs somewhere else entirely. `sessionStorage` and
        // friends are reached through this rather than being listed, because
        // listing them would tell the linter a Node script may use them — and
        // one that did would fail at run time with the check green.
        globalThis: 'readonly',
      },
    },
  },
  {
    rules: {
      // The permission model reads better with explicit, narrow types than
      // with inferred ones; these two catch the drift that hides a widening.
      '@typescript-eslint/explicit-module-boundary-types': 'off',
      '@typescript-eslint/no-explicit-any': 'error',
    },
  },
  {
    // A bare `decodeURIComponent` over a captured path segment throws
    // `URIError` on a malformed escape (`/v1/documents/%ZZ` — WHATWG `URL`
    // leaves the invalid escape in `pathname` verbatim), which the error
    // boundary turns into a `500` and a spurious `error` audit row where the
    // answer is the `404` every unknown id gets. Twelve routes decoded one by
    // hand; they all go through `pathMatch` in `server.ts` now, and this is
    // what stops the thirteenth being written the old way. The one legitimate
    // reader outside it is `core/redis.ts`, decoding credentials out of a URL
    // an operator wrote — a URIError there is a configuration error at
    // startup, not a caller-reachable throw.
    files: ['packages/api/src/**/*.ts', 'packages/mcp/src/**/*.ts'],
    ignores: ['**/__tests__/**'],
    rules: {
      'no-restricted-syntax': [
        'error',
        {
          selector:
            "CallExpression[callee.name='decodeURIComponent']:not(FunctionDeclaration[id.name='pathMatch'] CallExpression)",
          message:
            'A malformed percent-escape throws URIError and becomes a 500. Route segments go through pathMatch (server.ts), which answers the 404 an unknown path gets.',
        },
      ],
    },
  },
)