From 8fc886c94683ea92b82bfd07e92cff4a5bcaeb19 Mon Sep 17 00:00:00 2001 From: Gabriel Costa Date: Mon, 10 Aug 2026 15:37:54 +0100 Subject: [PATCH 1/6] chore: Pre-commit hooks Signed-off-by: Gabriel Costa --- .husky/pre-commit | 13 +++++++++++++ .prettierignore | 3 ++- eslint.config.js | 3 ++- package-lock.json | 17 +++++++++++++++++ package.json | 6 +++++- src/auth/AuthContext.test.tsx | 3 +-- vite.config.ts | 4 +--- 7 files changed, 41 insertions(+), 8 deletions(-) create mode 100755 .husky/pre-commit diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 0000000..7eefff8 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,13 @@ +set -e + +echo "Running prettier..." +npm run format:check + +echo "Running eslint..." +npm run lint + +echo "Running build..." +npm run build + +echo "Running unit tests..." +npm run test diff --git a/.prettierignore b/.prettierignore index 1aa8372..48d86cf 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,7 +1,8 @@ # Build outputs dist build -../mcpgateway/static/app +server/dist +server/public # Dependencies node_modules diff --git a/eslint.config.js b/eslint.config.js index 7df8cde..e5a7252 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -19,10 +19,11 @@ const prettierOptions = JSON.parse(fs.readFileSync(path.join(__dirname, ".pretti export default tseslint.config( { ignores: [ - "../mcpgateway/static/app", "src/generated", "dist", "build", + "server/dist", + "server/public", "playwright-report", "test-results", ], diff --git a/package-lock.json b/package-lock.json index 94d080e..476192c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -45,6 +45,7 @@ "eslint-plugin-react": "^7.37.5", "eslint-plugin-react-hooks": "^5.2.0", "globals": "^16.0.0", + "husky": "^9.1.7", "jsdom": "^25.0.1", "msw": "^2.14.2", "orval": "^8.18.0", @@ -8537,6 +8538,22 @@ "node": ">=18.18.0" } }, + "node_modules/husky": { + "version": "9.1.7", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz", + "integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==", + "dev": true, + "license": "MIT", + "bin": { + "husky": "bin.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, "node_modules/iconv-lite": { "version": "0.7.2", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", diff --git a/package.json b/package.json index e9e5054..ff5fba9 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,10 @@ "e2e:report": "playwright show-report", "i18n:extract": "formatjs extract 'src/**/*.{ts,tsx}' --out-file src/i18n/extracted.json --id-interpolation-pattern '[sha512:contenthash:base64:6]'", "i18n:compile": "formatjs compile-folder --ast src/i18n/locales src/i18n/compiled", - "generate": "orval" + "export-schema": "cd .. && make export-schema", + "pregenerate": "test -f openapi.json || npm run export-schema", + "generate": "orval", + "prepare": "husky" }, "dependencies": { "@fontsource-variable/inter": "^5.2.8", @@ -65,6 +68,7 @@ "eslint-plugin-react": "^7.37.5", "eslint-plugin-react-hooks": "^5.2.0", "globals": "^16.0.0", + "husky": "^9.1.7", "jsdom": "^25.0.1", "msw": "^2.14.2", "orval": "^8.18.0", diff --git a/src/auth/AuthContext.test.tsx b/src/auth/AuthContext.test.tsx index 6767405..109e857 100644 --- a/src/auth/AuthContext.test.tsx +++ b/src/auth/AuthContext.test.tsx @@ -307,11 +307,10 @@ describe("AuthContext", () => { email_verified: true, password_change_required: false, }; - vi.mocked(api.get).mockResolvedValueOnce({ authenticated: true, user: mockUser, - csrfToken: "test-csrf-token", + csrfToken: "session-csrf-token", }); // Hold the permissions fetch open so we can observe the loading window. diff --git a/vite.config.ts b/vite.config.ts index 3834e66..c39b498 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -22,9 +22,7 @@ export default defineConfig({ base: "/", build: { - // BFF (server/) serves this directory as static files — see - // server/src/plugins/static.ts. - outDir: "server/public", + outDir: "dist", emptyOutDir: true, manifest: true, sourcemap: false, From e64310562dfbae97602dd275f65ad4abf45b3faf Mon Sep 17 00:00:00 2001 From: Gabriel Costa Date: Tue, 11 Aug 2026 11:40:35 +0100 Subject: [PATCH 2/6] Edit pre-commit + add pre-push Signed-off-by: Gabriel Costa --- .husky/post-checkout | 1 + .husky/post-commit | 1 + .husky/post-merge | 1 + .husky/pre-commit | 14 +------------- .husky/pre-push | 2 ++ eslint.config.js | 6 ++---- package-lock.json | 31 ++++++++++++++++++++++++++++--- package.json | 6 ++++++ 8 files changed, 42 insertions(+), 20 deletions(-) create mode 100755 .husky/post-checkout create mode 100755 .husky/post-commit create mode 100755 .husky/post-merge create mode 100755 .husky/pre-push diff --git a/.husky/post-checkout b/.husky/post-checkout new file mode 100755 index 0000000..7669ee4 --- /dev/null +++ b/.husky/post-checkout @@ -0,0 +1 @@ +.husky/_/post-checkout diff --git a/.husky/post-commit b/.husky/post-commit new file mode 100755 index 0000000..2db9861 --- /dev/null +++ b/.husky/post-commit @@ -0,0 +1 @@ +.husky/_/post-commit diff --git a/.husky/post-merge b/.husky/post-merge new file mode 100755 index 0000000..392a143 --- /dev/null +++ b/.husky/post-merge @@ -0,0 +1 @@ +.husky/_/post-merge diff --git a/.husky/pre-commit b/.husky/pre-commit index 7eefff8..2312dc5 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,13 +1 @@ -set -e - -echo "Running prettier..." -npm run format:check - -echo "Running eslint..." -npm run lint - -echo "Running build..." -npm run build - -echo "Running unit tests..." -npm run test +npx lint-staged diff --git a/.husky/pre-push b/.husky/pre-push new file mode 100755 index 0000000..2198f37 --- /dev/null +++ b/.husky/pre-push @@ -0,0 +1,2 @@ +npm run build +npm run test diff --git a/eslint.config.js b/eslint.config.js index e5a7252..d3c4e51 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -9,10 +9,8 @@ import prettierConfig from "eslint-config-prettier"; import globals from "globals"; // Load .prettierrc explicitly instead of letting eslint-plugin-prettier -// resolve it on its own — this repo has a second, differently-configured -// prettier.config.js one directory up (repo root), and relying on the -// plugin's own cosmiconfig search risks it picking that one up instead, -// producing formatting eslint --fix disagrees with the prettier CLI on. +// resolve it via its own cosmiconfig search, so eslint --fix always agrees +// with the prettier CLI. const __dirname = path.dirname(fileURLToPath(import.meta.url)); const prettierOptions = JSON.parse(fs.readFileSync(path.join(__dirname, ".prettierrc"), "utf8")); diff --git a/package-lock.json b/package-lock.json index 476192c..f4f0f17 100644 --- a/package-lock.json +++ b/package-lock.json @@ -47,6 +47,7 @@ "globals": "^16.0.0", "husky": "^9.1.7", "jsdom": "^25.0.1", + "lint-staged": "^17.3.0", "msw": "^2.14.2", "orval": "^8.18.0", "prettier": "^3.4.2", @@ -9805,6 +9806,30 @@ "uc.micro": "^2.0.0" } }, + "node_modules/lint-staged": { + "version": "17.3.0", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-17.3.0.tgz", + "integrity": "sha512-woZS3vNe3UKqBaLPvbLOtKRY4tLANpWQhom12MGWqC8Mh1lCOO+WgSwmX2amjJAqTY9BkXYW87fCUH5H9Ph6xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^4.0.5", + "string-argv": "^0.3.2", + "tinyexec": "^1.2.4" + }, + "bin": { + "lint-staged": "bin/lint-staged.js" + }, + "engines": { + "node": ">=22.22.1" + }, + "funding": { + "url": "https://opencollective.com/lint-staged" + }, + "optionalDependencies": { + "yaml": "^2.9.0" + } + }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -10959,9 +10984,9 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", + "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", "license": "MIT", "engines": { "node": ">=12" diff --git a/package.json b/package.json index ff5fba9..0380a7d 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "e2e:report": "playwright show-report", "i18n:extract": "formatjs extract 'src/**/*.{ts,tsx}' --out-file src/i18n/extracted.json --id-interpolation-pattern '[sha512:contenthash:base64:6]'", "i18n:compile": "formatjs compile-folder --ast src/i18n/locales src/i18n/compiled", + "lint-staged": "lint-staged", "export-schema": "cd .. && make export-schema", "pregenerate": "test -f openapi.json || npm run export-schema", "generate": "orval", @@ -70,6 +71,7 @@ "globals": "^16.0.0", "husky": "^9.1.7", "jsdom": "^25.0.1", + "lint-staged": "^17.3.0", "msw": "^2.14.2", "orval": "^8.18.0", "prettier": "^3.4.2", @@ -78,5 +80,9 @@ "typescript-eslint": "^8.32.0", "vite": "^6.4.3", "vitest": "^4.1.9" + }, + "lint-staged": { + "{src,e2e}/**/*.{ts,tsx,css,json}": "prettier --write", + "{src,e2e}/**/*.{ts,tsx}": "eslint --fix" } } From a48a2774c152d131fcf3704f9d0ea86efd556755 Mon Sep 17 00:00:00 2001 From: Gabriel Costa Date: Tue, 11 Aug 2026 11:40:35 +0100 Subject: [PATCH 3/6] Edit pre-commit + add pre-push Signed-off-by: Gabriel Costa --- src/auth/AuthContext.test.tsx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/auth/AuthContext.test.tsx b/src/auth/AuthContext.test.tsx index 109e857..1c7d43c 100644 --- a/src/auth/AuthContext.test.tsx +++ b/src/auth/AuthContext.test.tsx @@ -104,7 +104,7 @@ describe("AuthContext", () => { vi.mocked(api.get).mockResolvedValueOnce({ authenticated: true, user: mockUser, - csrfToken: "test-csrf-token", + csrfToken: "session-csrf-token", }); render( @@ -122,7 +122,7 @@ describe("AuthContext", () => { expect(screen.getByTestId("auth-status")).toHaveTextContent("authenticated"); expect(screen.getByTestId("user-email")).toHaveTextContent("user@example.com"); expect(api.get).toHaveBeenCalledWith("/auth/session"); - expect(setCsrfToken).toHaveBeenCalledWith("test-csrf-token"); + expect(setCsrfToken).toHaveBeenCalledWith("session-csrf-token"); }); it("treats an unauthenticated session response as a guest", async () => { @@ -202,7 +202,7 @@ describe("AuthContext", () => { vi.mocked(api.post).mockResolvedValueOnce({ user: mockUser, - csrfToken: "test-csrf-token", + csrfToken: "session-csrf-token", }); screen.getByText("Login").click(); @@ -217,7 +217,7 @@ describe("AuthContext", () => { { email: "test@example.com", password: "pass" }, { authenticated: false }, ); - expect(setCsrfToken).toHaveBeenCalledWith("test-csrf-token"); + expect(setCsrfToken).toHaveBeenCalledWith("session-csrf-token"); }); it("handles successful logout", async () => { @@ -234,7 +234,7 @@ describe("AuthContext", () => { vi.mocked(api.get).mockResolvedValueOnce({ authenticated: true, user: mockUser, - csrfToken: "test-csrf-token", + csrfToken: "session-csrf-token", }); render( @@ -274,7 +274,7 @@ describe("AuthContext", () => { vi.mocked(api.get).mockResolvedValueOnce({ authenticated: true, user: mockUser, - csrfToken: "test-csrf-token", + csrfToken: "session-csrf-token", }); render( @@ -348,7 +348,7 @@ describe("AuthContext", () => { email_verified: true, password_change_required: false, }, - csrfToken: "test-csrf-token", + csrfToken: "session-csrf-token", }); render( From 79900760d00300fa24f72264b025378809e1515f Mon Sep 17 00:00:00 2001 From: Gabriel Costa Date: Wed, 12 Aug 2026 15:25:05 +0100 Subject: [PATCH 4/6] resolve conflicts Signed-off-by: Gabriel Costa --- .husky/post-checkout | 1 - .husky/post-commit | 1 - .husky/post-merge | 1 - .husky/pre-push | 1 + .prettierignore | 3 +++ README.md | 36 ++++++++++++++++++------------------ eslint.config.js | 17 +++++++++++++++++ orval.config.ts | 4 ++-- package.json | 17 +++++++---------- tsconfig.json | 5 +---- vite.bff.config.ts | 18 ++++++++++++++++++ vite.config.ts | 3 ++- 12 files changed, 69 insertions(+), 38 deletions(-) delete mode 100755 .husky/post-checkout delete mode 100755 .husky/post-commit delete mode 100755 .husky/post-merge create mode 100644 vite.bff.config.ts diff --git a/.husky/post-checkout b/.husky/post-checkout deleted file mode 100755 index 7669ee4..0000000 --- a/.husky/post-checkout +++ /dev/null @@ -1 +0,0 @@ -.husky/_/post-checkout diff --git a/.husky/post-commit b/.husky/post-commit deleted file mode 100755 index 2db9861..0000000 --- a/.husky/post-commit +++ /dev/null @@ -1 +0,0 @@ -.husky/_/post-commit diff --git a/.husky/post-merge b/.husky/post-merge deleted file mode 100755 index 392a143..0000000 --- a/.husky/post-merge +++ /dev/null @@ -1 +0,0 @@ -.husky/_/post-merge diff --git a/.husky/pre-push b/.husky/pre-push index 2198f37..4b9a516 100755 --- a/.husky/pre-push +++ b/.husky/pre-push @@ -1,2 +1,3 @@ npm run build npm run test +npm run lint diff --git a/.prettierignore b/.prettierignore index 48d86cf..47d7db3 100644 --- a/.prettierignore +++ b/.prettierignore @@ -16,6 +16,9 @@ package-lock.json pnpm-lock.yaml yarn.lock +# Committed API spec, not hand-formatted +openapi.json + # Coverage coverage .nyc_output diff --git a/README.md b/README.md index 3175a7f..4c102c2 100644 --- a/README.md +++ b/README.md @@ -339,25 +339,25 @@ client/ ## Available Scripts -| Script | Description | -| ----------------------- | -------------------------------- | -| `npm run dev` | Start development server | -| `npm run build` | Build for production | +| Script | Description | +| ----------------------- | ---------------------------------------- | +| `npm run dev` | Start development server | +| `npm run build` | Build for production | | `npm run generate` | Regenerate API types from `openapi.json` | -| `npm run preview` | Preview production build | -| `npm run lint` | Check for linting errors | -| `npm run lint:fix` | Auto-fix linting errors | -| `npm run format` | Format all files with Prettier | -| `npm run format:check` | Check formatting without changes | -| `npm run test` | Run tests in watch mode | -| `npm run test:run` | Run tests once (CI mode) | -| `npm run test:ui` | Run tests with UI | -| `npm run test:coverage` | Generate coverage report | -| `npm run e2e` | Run Playwright E2E tests | -| `npm run e2e:ui` | Playwright UI mode | -| `npm run e2e:debug` | Playwright Inspector | -| `npm run e2e:install` | Install Playwright browsers | -| `npm run e2e:report` | Open last Playwright report | +| `npm run preview` | Preview production build | +| `npm run lint` | Check for linting errors | +| `npm run lint:fix` | Auto-fix linting errors | +| `npm run format` | Format all files with Prettier | +| `npm run format:check` | Check formatting without changes | +| `npm run test` | Run tests in watch mode | +| `npm run test:run` | Run tests once (CI mode) | +| `npm run test:ui` | Run tests with UI | +| `npm run test:coverage` | Generate coverage report | +| `npm run e2e` | Run Playwright E2E tests | +| `npm run e2e:ui` | Playwright UI mode | +| `npm run e2e:debug` | Playwright Inspector | +| `npm run e2e:install` | Install Playwright browsers | +| `npm run e2e:report` | Open last Playwright report | ## Internationalization (i18n) diff --git a/eslint.config.js b/eslint.config.js index d3c4e51..80932ad 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -89,4 +89,21 @@ export default tseslint.config( "no-new-func": "error", }, }, + { + extends: [...tseslint.configs.recommended], + files: ["server/**/*.ts"], + languageOptions: { + globals: globals.node, + }, + plugins: { + prettier: prettierPlugin, + }, + rules: { + ...prettierConfig.rules, + "prettier/prettier": ["error", prettierOptions], + "no-eval": "error", + "no-implied-eval": "error", + "no-new-func": "error", + }, + }, ); diff --git a/orval.config.ts b/orval.config.ts index 3051414..1a319e3 100644 --- a/orval.config.ts +++ b/orval.config.ts @@ -36,7 +36,7 @@ export default defineConfig({ }, }, hooks: { - "afterAllFilesWrite": "prettier src/generated --write" - } + afterAllFilesWrite: "prettier src/generated --write", + }, }, }); diff --git a/package.json b/package.json index 0380a7d..d1abc14 100644 --- a/package.json +++ b/package.json @@ -9,10 +9,10 @@ "build": "npm run generate && tsc -b && vite build", "build:watch": "vite build --watch", "preview": "vite preview", - "lint": "eslint src e2e", - "lint:fix": "eslint src e2e --fix", - "format": "prettier --write \"{src,e2e}/**/*.{ts,tsx,css,json}\"", - "format:check": "prettier --check \"{src,e2e}/**/*.{ts,tsx,css,json}\"", + "lint": "eslint --no-error-on-unmatched-pattern src server e2e", + "lint:fix": "eslint --no-error-on-unmatched-pattern src server e2e --fix", + "format": "prettier --write --ignore-unknown \"*.{ts,tsx,js,mjs,json,css,md}\" \"{src,server,e2e}/**/*.{ts,tsx,css,json}\"", + "format:check": "prettier --check --ignore-unknown \"*.{ts,tsx,js,mjs,json,css,md}\" \"{src,server,e2e}/**/*.{ts,tsx,css,json}\"", "test": "vitest run", "test:ui": "vitest --ui", "test:watch": "vitest", @@ -25,11 +25,8 @@ "e2e:report": "playwright show-report", "i18n:extract": "formatjs extract 'src/**/*.{ts,tsx}' --out-file src/i18n/extracted.json --id-interpolation-pattern '[sha512:contenthash:base64:6]'", "i18n:compile": "formatjs compile-folder --ast src/i18n/locales src/i18n/compiled", - "lint-staged": "lint-staged", - "export-schema": "cd .. && make export-schema", - "pregenerate": "test -f openapi.json || npm run export-schema", "generate": "orval", - "prepare": "husky" + "prepare": "husky || true" }, "dependencies": { "@fontsource-variable/inter": "^5.2.8", @@ -82,7 +79,7 @@ "vitest": "^4.1.9" }, "lint-staged": { - "{src,e2e}/**/*.{ts,tsx,css,json}": "prettier --write", - "{src,e2e}/**/*.{ts,tsx}": "eslint --fix" + "*.{ts,tsx,js,mjs,json,css,md}": "prettier --write --ignore-unknown", + "{src,server,e2e}/**/*.{ts,tsx}": "eslint --fix" } } diff --git a/tsconfig.json b/tsconfig.json index 7e850ee..d3bc091 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,9 +1,6 @@ { "files": [], - "references": [ - { "path": "./tsconfig.node.json" }, - { "path": "./tsconfig.app.json" } - ], + "references": [{ "path": "./tsconfig.node.json" }, { "path": "./tsconfig.app.json" }], "compilerOptions": { "baseUrl": ".", "paths": { diff --git a/vite.bff.config.ts b/vite.bff.config.ts new file mode 100644 index 0000000..d53ac61 --- /dev/null +++ b/vite.bff.config.ts @@ -0,0 +1,18 @@ +import { mergeConfig, defineConfig } from "vite"; + +import baseConfig from "./vite.config"; + +// Alternate build target for a BFF-served SPA: outputs to server/public/ +// with base '/', instead of vite.config.ts's default (dist/ with base +// '/static/app/', for FastAPI's static mount). Everything else — plugins, +// chunking, etc. — is inherited from the base config. +export default mergeConfig( + baseConfig, + defineConfig({ + base: "/", + build: { + outDir: "server/public", + emptyOutDir: true, + }, + }), +); diff --git a/vite.config.ts b/vite.config.ts index c39b498..af4ebd9 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -43,7 +43,8 @@ export default defineConfig({ id.includes("react-intl") || id.includes("@formatjs") || id.includes("/sonner/") - ) return "vendor-react"; + ) + return "vendor-react"; if (id.includes("@radix-ui") || id.includes("radix-ui")) return "vendor-radix"; if (id.includes("lucide-react")) return "vendor-lucide"; return "vendor"; From a6225ae5b420fb3d829940e3f4a4ba0864ebde4e Mon Sep 17 00:00:00 2001 From: Gabriel Costa Date: Wed, 12 Aug 2026 12:27:13 +0100 Subject: [PATCH 5/6] chore: pin Node floor to match lint-staged requirement lint-staged@17.3.0 needs node>=22.22.1 but repo advertised no floor, so npm install could fail on older Node 22/20 setups. Add engines field + .nvmrc, and point CI setup-node at .nvmrc instead of a hardcoded "22". Signed-off-by: Gabriel Costa --- .github/workflows/client-e2e.yml | 2 +- .github/workflows/client-generate.yml | 2 +- .github/workflows/client-lint-test.yml | 2 +- .nvmrc | 1 + package.json | 3 +++ 5 files changed, 7 insertions(+), 3 deletions(-) create mode 100644 .nvmrc diff --git a/.github/workflows/client-e2e.yml b/.github/workflows/client-e2e.yml index ea9d370..97b2486 100644 --- a/.github/workflows/client-e2e.yml +++ b/.github/workflows/client-e2e.yml @@ -44,7 +44,7 @@ jobs: - name: 🟩 Setup Node uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: - node-version: "22" + node-version-file: ".nvmrc" - name: 📥 Install dependencies run: npm ci --no-audit --no-fund diff --git a/.github/workflows/client-generate.yml b/.github/workflows/client-generate.yml index 755a744..e59cb6d 100644 --- a/.github/workflows/client-generate.yml +++ b/.github/workflows/client-generate.yml @@ -35,7 +35,7 @@ jobs: - name: Setup Node uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: - node-version: "22" + node-version-file: ".nvmrc" - name: Install dependencies run: npm ci --no-audit --no-fund diff --git a/.github/workflows/client-lint-test.yml b/.github/workflows/client-lint-test.yml index cfef531..7c63340 100644 --- a/.github/workflows/client-lint-test.yml +++ b/.github/workflows/client-lint-test.yml @@ -39,7 +39,7 @@ jobs: - name: 🟩 Setup Node uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: - node-version: "22" + node-version-file: ".nvmrc" - name: 📥 Install dependencies run: npm ci --no-audit --no-fund diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000..32a2d7b --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +22.22.1 diff --git a/package.json b/package.json index d1abc14..73c8b84 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,9 @@ "private": true, "version": "0.1.0", "type": "module", + "engines": { + "node": ">=22.22.1" + }, "scripts": { "dev": "vite", "dev:e2e": "vite --base=/ --port 5173 --strictPort", From 3566ac53e2a8419727d01ee20ba8350794116cd4 Mon Sep 17 00:00:00 2001 From: Gabriel Costa Date: Wed, 12 Aug 2026 15:31:24 +0100 Subject: [PATCH 6/6] Ignore temp vars (_var) Signed-off-by: Gabriel Costa --- eslint.config.js | 12 ++++++++++++ server/test/proxy.test.ts | 3 +-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/eslint.config.js b/eslint.config.js index 80932ad..569d286 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -104,6 +104,18 @@ export default tseslint.config( "no-eval": "error", "no-implied-eval": "error", "no-new-func": "error", + + // Allow `_`-prefixed locals to signal intentional discard (destructured + // rest patterns that strip a key, unused catch bindings, etc). + "@typescript-eslint/no-unused-vars": [ + "error", + { + argsIgnorePattern: "^_", + varsIgnorePattern: "^_", + caughtErrorsIgnorePattern: "^_", + destructuredArrayIgnorePattern: "^_", + }, + ], }, }, ); diff --git a/server/test/proxy.test.ts b/server/test/proxy.test.ts index 3050258..34d25d2 100644 --- a/server/test/proxy.test.ts +++ b/server/test/proxy.test.ts @@ -15,8 +15,7 @@ import { afterAll, beforeAll, describe, expect, it } from "vitest"; let upstream: Server; let upstreamOrigin: string; let lastRequest: - | { path: string; authorization: string | undefined; method: string; body: string } - | undefined; + { path: string; authorization: string | undefined; method: string; body: string } | undefined; beforeAll(async () => { upstream = createServer((req: IncomingMessage, res) => {