Validation: shared NaN-guarded Zod coercion helpers in schemas/common.ts replace the raw number|string transform idiom across every schema (the root-cause NaN bug class); emailOrEmpty + lenient isoDateString/timeString. Security: roles privilege-escalation closed; refresh-token family revocation on reuse; TOTP uses config params; read endpoints permission-guarded; received-invoices gross VAT on all paths; orders-pdf custom-items authz. Concurrency: $queryRaw SELECT...FOR UPDATE locks in ascending-id order (warehouse confirm/cancel, attendance lockUserRow); uniqueness checks moved into create transactions (TOCTOU -> 409); deterministic id tiebreak on second-precision timestamp ordering (plan resolveCell/resolveGrid, warehouse FIFO). Frontend: Rules-of-Hooks fixed across ~14 pages + PlanCellModal; UTC-date persisted fields; dashboard invalidation gaps; stale-closure confirm bugs. Tooling/tests: ESLint flat config (react-hooks/rules-of-hooks = error) + Prettier; tsconfig.test.json so tsc -b type-checks the tests; removed 3 dead deps; npm audit fix (8 -> 3). Suite 195 -> 247 (happy-path auth, FIFO oldest-first, flakiness fixes), isolated on app_test via .env.test with a hard-throw setup guard. Gates: tsc 0 | build 0 | vitest 247/247 | eslint 0 errors. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
79 lines
2.3 KiB
JavaScript
79 lines
2.3 KiB
JavaScript
import js from "@eslint/js";
|
|
import tseslint from "typescript-eslint";
|
|
import reactHooks from "eslint-plugin-react-hooks";
|
|
import reactRefresh from "eslint-plugin-react-refresh";
|
|
import globals from "globals";
|
|
import prettier from "eslint-config-prettier";
|
|
|
|
export default tseslint.config(
|
|
{
|
|
ignores: [
|
|
"dist/**",
|
|
"dist-client/**",
|
|
"node_modules/**",
|
|
"prisma/migrations/**",
|
|
"src/admin/bones/**",
|
|
"*.config.js",
|
|
"*.config.mjs",
|
|
"*.config.ts",
|
|
".claude/**",
|
|
],
|
|
},
|
|
js.configs.recommended,
|
|
...tseslint.configs.recommended,
|
|
{
|
|
// Server + shared code
|
|
files: ["src/**/*.{ts,tsx}", "scripts/**/*.ts", "prisma/seed.ts"],
|
|
languageOptions: {
|
|
globals: { ...globals.node, ...globals.browser },
|
|
},
|
|
rules: {
|
|
// TS already resolves identifiers — `no-undef` only false-positives on
|
|
// global types/ambient names in .ts files.
|
|
"no-undef": "off",
|
|
"@typescript-eslint/no-explicit-any": "warn",
|
|
"@typescript-eslint/no-unused-vars": [
|
|
"warn",
|
|
{ argsIgnorePattern: "^_", varsIgnorePattern: "^_" },
|
|
],
|
|
"@typescript-eslint/no-require-imports": "warn",
|
|
"no-empty": ["warn", { allowEmptyCatch: false }],
|
|
// Intentional control-character regexes (NUL/path-traversal guards,
|
|
// combining-marks stripping) — not a defect here.
|
|
"no-control-regex": "off",
|
|
// Stylistic / advisory — surface as warnings, don't fail the lint gate.
|
|
"no-useless-escape": "warn",
|
|
"no-useless-assignment": "warn",
|
|
"preserve-caught-error": "warn",
|
|
"prefer-const": "warn",
|
|
},
|
|
},
|
|
{
|
|
// Frontend React code
|
|
files: ["src/admin/**/*.{ts,tsx}", "src/**/*.tsx"],
|
|
plugins: {
|
|
"react-hooks": reactHooks,
|
|
"react-refresh": reactRefresh,
|
|
},
|
|
rules: {
|
|
"react-hooks/rules-of-hooks": "error",
|
|
"react-hooks/exhaustive-deps": "warn",
|
|
},
|
|
},
|
|
{
|
|
// Plain Node helper scripts (.js/.mjs/.cjs in scripts/)
|
|
files: ["scripts/**/*.{js,mjs,cjs}"],
|
|
languageOptions: { globals: { ...globals.node } },
|
|
rules: { "no-undef": "off" },
|
|
},
|
|
{
|
|
// Tests
|
|
files: ["src/__tests__/**/*.ts"],
|
|
languageOptions: { globals: { ...globals.node } },
|
|
rules: {
|
|
"@typescript-eslint/no-explicit-any": "off",
|
|
},
|
|
},
|
|
prettier,
|
|
);
|