Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/client-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/client-generate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/client-lint-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
npx lint-staged
3 changes: 3 additions & 0 deletions .husky/pre-push
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
npm run build
npm run test
npm run lint
1 change: 1 addition & 0 deletions .nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
22.22.1
6 changes: 5 additions & 1 deletion .prettierignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# Build outputs
dist
build
../mcpgateway/static/app
server/dist
server/public

# Dependencies
node_modules
Expand All @@ -15,6 +16,9 @@ package-lock.json
pnpm-lock.yaml
yarn.lock

# Committed API spec, not hand-formatted
openapi.json

# Coverage
coverage
.nyc_output
Expand Down
36 changes: 18 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
38 changes: 33 additions & 5 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,19 @@ 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"));

export default tseslint.config(
{
ignores: [
"../mcpgateway/static/app",
"src/generated",
"dist",
"build",
"server/dist",
"server/public",
"playwright-report",
"test-results",
],
Expand Down Expand Up @@ -90,4 +89,33 @@ 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",

// 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: "^_",
},
],
},
},
);
4 changes: 2 additions & 2 deletions orval.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export default defineConfig({
},
},
hooks: {
"afterAllFilesWrite": "prettier src/generated --write"
}
afterAllFilesWrite: "prettier src/generated --write",
},
},
});
48 changes: 45 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 15 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,19 @@
"private": true,
"version": "0.1.0",
"type": "module",
"engines": {
"node": ">=22.22.1"
},
"scripts": {
"dev": "vite",
"dev:e2e": "vite --base=/ --port 5173 --strictPort",
"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",
Expand All @@ -25,7 +28,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",
"generate": "orval"
"generate": "orval",
"prepare": "husky || true"
},
"dependencies": {
"@fontsource-variable/inter": "^5.2.8",
Expand Down Expand Up @@ -65,7 +69,9 @@
"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",
"lint-staged": "^17.3.0",
"msw": "^2.14.2",
"orval": "^8.18.0",
"prettier": "^3.4.2",
Expand All @@ -74,5 +80,9 @@
"typescript-eslint": "^8.32.0",
"vite": "^6.4.3",
"vitest": "^4.1.9"
},
"lint-staged": {
"*.{ts,tsx,js,mjs,json,css,md}": "prettier --write --ignore-unknown",
"{src,server,e2e}/**/*.{ts,tsx}": "eslint --fix"
}
}
3 changes: 1 addition & 2 deletions server/test/proxy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down
17 changes: 8 additions & 9 deletions src/auth/AuthContext.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ describe("AuthContext", () => {
vi.mocked(api.get).mockResolvedValueOnce({
authenticated: true,
user: mockUser,
csrfToken: "test-csrf-token",
csrfToken: "session-csrf-token",
});

render(
Expand All @@ -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 () => {
Expand Down Expand Up @@ -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();
Expand All @@ -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 () => {
Expand All @@ -234,7 +234,7 @@ describe("AuthContext", () => {
vi.mocked(api.get).mockResolvedValueOnce({
authenticated: true,
user: mockUser,
csrfToken: "test-csrf-token",
csrfToken: "session-csrf-token",
});

render(
Expand Down Expand Up @@ -274,7 +274,7 @@ describe("AuthContext", () => {
vi.mocked(api.get).mockResolvedValueOnce({
authenticated: true,
user: mockUser,
csrfToken: "test-csrf-token",
csrfToken: "session-csrf-token",
});

render(
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -349,7 +348,7 @@ describe("AuthContext", () => {
email_verified: true,
password_change_required: false,
},
csrfToken: "test-csrf-token",
csrfToken: "session-csrf-token",
});

render(
Expand Down
5 changes: 1 addition & 4 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -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": {
Expand Down
Loading
Loading