fix: resolve lint and typecheck errors in API routes and tests

- Remove unused imports (users, and) from api-tokens model
- Fix password_hash destructure lint error in user routes
- Fix apiErrorResponse mock pattern in all 12 test files (use instanceof)
- Remove stale eslint-disable directives from test files
- Add eslint override for tests (no-explicit-any, no-require-imports)
- Fix unused vars in settings and tokens tests
- Fix unused tokenB in integration test

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
fuomag9
2026-03-26 10:33:47 +01:00
parent 28f61082ce
commit d9806e84e6
17 changed files with 64 additions and 55 deletions

View File

@@ -3,7 +3,8 @@ import { requireApiUser, requireApiAdmin, apiErrorResponse, ApiAuthError } from
import { getUserById, updateUserProfile } from "@/src/lib/models/user";
function stripPasswordHash(user: Record<string, unknown>) {
const { password_hash, ...rest } = user;
const { password_hash: _, ...rest } = user;
void _;
return rest;
}

View File

@@ -3,7 +3,8 @@ import { requireApiAdmin, apiErrorResponse } from "@/src/lib/api-auth";
import { listUsers } from "@/src/lib/models/user";
function stripPasswordHash(user: Record<string, unknown>) {
const { password_hash, ...rest } = user;
const { password_hash: _, ...rest } = user;
void _;
return rest;
}

View File

@@ -19,4 +19,11 @@ export default [
'@next/next/no-img-element': 'off',
},
},
{
files: ['tests/**/*.{ts,tsx}'],
rules: {
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-require-imports': 'off',
},
},
];

View File

@@ -1,7 +1,7 @@
import { createHash, randomBytes } from "node:crypto";
import db, { nowIso, toIso } from "../db";
import { apiTokens, users } from "../db/schema";
import { eq, and } from "drizzle-orm";
import { apiTokens } from "../db/schema";
import { eq } from "drizzle-orm";
export type ApiToken = {
id: number;

View File

@@ -196,7 +196,7 @@ describe('api-tokens integration', () => {
const userB = await insertUser({ email: 'b@localhost', subject: 'b@localhost', role: 'user' });
const { token: tokenA } = await insertApiToken(userA.id, { name: 'A Token' });
const { token: tokenB } = await insertApiToken(userB.id, { name: 'B Token' });
await insertApiToken(userB.id, { name: 'B Token' });
// User B deletes only their own tokens
await db.delete(apiTokens).where(eq(apiTokens.createdBy, userB.id));

View File

@@ -19,11 +19,11 @@ vi.mock('@/src/lib/api-auth', () => {
requireApiAdmin: vi.fn().mockResolvedValue({ userId: 1, role: 'admin', authMethod: 'bearer' }),
requireApiUser: vi.fn().mockResolvedValue({ userId: 1, role: 'admin', authMethod: 'bearer' }),
apiErrorResponse: vi.fn((error: unknown) => {
const { NextResponse } = require('next/server');
if (error && typeof error === 'object' && 'status' in error) {
return NextResponse.json({ error: (error as Error).message }, { status: (error as any).status });
const { NextResponse: NR } = require('next/server');
if (error instanceof ApiAuthError) {
return NR.json({ error: error.message }, { status: error.status });
}
return NextResponse.json({ error: error instanceof Error ? error.message : 'Internal server error' }, { status: 500 });
return NR.json({ error: error instanceof Error ? error.message : 'Internal server error' }, { status: 500 });
}),
ApiAuthError,
};

View File

@@ -14,11 +14,11 @@ vi.mock('@/src/lib/api-auth', () => {
requireApiAdmin: vi.fn().mockResolvedValue({ userId: 1, role: 'admin', authMethod: 'bearer' }),
requireApiUser: vi.fn().mockResolvedValue({ userId: 1, role: 'admin', authMethod: 'bearer' }),
apiErrorResponse: vi.fn((error: unknown) => {
const { NextResponse } = require('next/server');
if (error && typeof error === 'object' && 'status' in error) {
return NextResponse.json({ error: (error as Error).message }, { status: (error as any).status });
const { NextResponse: NR } = require('next/server');
if (error instanceof ApiAuthError) {
return NR.json({ error: error.message }, { status: error.status });
}
return NextResponse.json({ error: error instanceof Error ? error.message : 'Internal server error' }, { status: 500 });
return NR.json({ error: error instanceof Error ? error.message : 'Internal server error' }, { status: 500 });
}),
ApiAuthError,
};

View File

@@ -17,11 +17,11 @@ vi.mock('@/src/lib/api-auth', () => {
requireApiAdmin: vi.fn().mockResolvedValue({ userId: 1, role: 'admin', authMethod: 'bearer' }),
requireApiUser: vi.fn().mockResolvedValue({ userId: 1, role: 'admin', authMethod: 'bearer' }),
apiErrorResponse: vi.fn((error: unknown) => {
const { NextResponse } = require('next/server');
if (error && typeof error === 'object' && 'status' in error) {
return NextResponse.json({ error: (error as Error).message }, { status: (error as any).status });
const { NextResponse: NR } = require('next/server');
if (error instanceof ApiAuthError) {
return NR.json({ error: error.message }, { status: error.status });
}
return NextResponse.json({ error: error instanceof Error ? error.message : 'Internal server error' }, { status: 500 });
return NR.json({ error: error instanceof Error ? error.message : 'Internal server error' }, { status: 500 });
}),
ApiAuthError,
};

View File

@@ -13,11 +13,11 @@ vi.mock('@/src/lib/api-auth', () => {
requireApiAdmin: vi.fn().mockResolvedValue({ userId: 1, role: 'admin', authMethod: 'bearer' }),
requireApiUser: vi.fn().mockResolvedValue({ userId: 1, role: 'admin', authMethod: 'bearer' }),
apiErrorResponse: vi.fn((error: unknown) => {
const { NextResponse } = require('next/server');
if (error && typeof error === 'object' && 'status' in error) {
return NextResponse.json({ error: (error as Error).message }, { status: (error as any).status });
const { NextResponse: NR } = require('next/server');
if (error instanceof ApiAuthError) {
return NR.json({ error: error.message }, { status: error.status });
}
return NextResponse.json({ error: error instanceof Error ? error.message : 'Internal server error' }, { status: 500 });
return NR.json({ error: error instanceof Error ? error.message : 'Internal server error' }, { status: 500 });
}),
ApiAuthError,
};

View File

@@ -17,11 +17,11 @@ vi.mock('@/src/lib/api-auth', () => {
requireApiAdmin: vi.fn().mockResolvedValue({ userId: 1, role: 'admin', authMethod: 'bearer' }),
requireApiUser: vi.fn().mockResolvedValue({ userId: 1, role: 'admin', authMethod: 'bearer' }),
apiErrorResponse: vi.fn((error: unknown) => {
const { NextResponse } = require('next/server');
if (error && typeof error === 'object' && 'status' in error) {
return NextResponse.json({ error: (error as Error).message }, { status: (error as any).status });
const { NextResponse: NR } = require('next/server');
if (error instanceof ApiAuthError) {
return NR.json({ error: error.message }, { status: error.status });
}
return NextResponse.json({ error: error instanceof Error ? error.message : 'Internal server error' }, { status: 500 });
return NR.json({ error: error instanceof Error ? error.message : 'Internal server error' }, { status: 500 });
}),
ApiAuthError,
};

View File

@@ -16,11 +16,11 @@ vi.mock('@/src/lib/api-auth', () => {
requireApiAdmin: vi.fn().mockResolvedValue({ userId: 1, role: 'admin', authMethod: 'bearer' }),
requireApiUser: vi.fn().mockResolvedValue({ userId: 1, role: 'admin', authMethod: 'bearer' }),
apiErrorResponse: vi.fn((error: unknown) => {
const { NextResponse } = require('next/server');
if (error && typeof error === 'object' && 'status' in error) {
return NextResponse.json({ error: (error as Error).message }, { status: (error as any).status });
const { NextResponse: NR } = require('next/server');
if (error instanceof ApiAuthError) {
return NR.json({ error: error.message }, { status: error.status });
}
return NextResponse.json({ error: error instanceof Error ? error.message : 'Internal server error' }, { status: 500 });
return NR.json({ error: error instanceof Error ? error.message : 'Internal server error' }, { status: 500 });
}),
ApiAuthError,
};

View File

@@ -19,11 +19,11 @@ vi.mock('@/src/lib/api-auth', () => {
requireApiAdmin: vi.fn().mockResolvedValue({ userId: 1, role: 'admin', authMethod: 'bearer' }),
requireApiUser: vi.fn().mockResolvedValue({ userId: 1, role: 'admin', authMethod: 'bearer' }),
apiErrorResponse: vi.fn((error: unknown) => {
const { NextResponse } = require('next/server');
if (error && typeof error === 'object' && 'status' in error) {
return NextResponse.json({ error: (error as Error).message }, { status: (error as any).status });
const { NextResponse: NR } = require('next/server');
if (error instanceof ApiAuthError) {
return NR.json({ error: error.message }, { status: error.status });
}
return NextResponse.json({ error: error instanceof Error ? error.message : 'Internal server error' }, { status: 500 });
return NR.json({ error: error instanceof Error ? error.message : 'Internal server error' }, { status: 500 });
}),
ApiAuthError,
};

View File

@@ -17,11 +17,11 @@ vi.mock('@/src/lib/api-auth', () => {
requireApiAdmin: vi.fn().mockResolvedValue({ userId: 1, role: 'admin', authMethod: 'bearer' }),
requireApiUser: vi.fn().mockResolvedValue({ userId: 1, role: 'admin', authMethod: 'bearer' }),
apiErrorResponse: vi.fn((error: unknown) => {
const { NextResponse } = require('next/server');
if (error && typeof error === 'object' && 'status' in error) {
return NextResponse.json({ error: (error as Error).message }, { status: (error as any).status });
const { NextResponse: NR } = require('next/server');
if (error instanceof ApiAuthError) {
return NR.json({ error: error.message }, { status: error.status });
}
return NextResponse.json({ error: error instanceof Error ? error.message : 'Internal server error' }, { status: 500 });
return NR.json({ error: error instanceof Error ? error.message : 'Internal server error' }, { status: 500 });
}),
ApiAuthError,
};

View File

@@ -17,11 +17,11 @@ vi.mock('@/src/lib/api-auth', () => {
requireApiAdmin: vi.fn().mockResolvedValue({ userId: 1, role: 'admin', authMethod: 'bearer' }),
requireApiUser: vi.fn().mockResolvedValue({ userId: 1, role: 'admin', authMethod: 'bearer' }),
apiErrorResponse: vi.fn((error: unknown) => {
const { NextResponse } = require('next/server');
if (error && typeof error === 'object' && 'status' in error) {
return NextResponse.json({ error: (error as Error).message }, { status: (error as any).status });
const { NextResponse: NR } = require('next/server');
if (error instanceof ApiAuthError) {
return NR.json({ error: error.message }, { status: error.status });
}
return NextResponse.json({ error: error instanceof Error ? error.message : 'Internal server error' }, { status: 500 });
return NR.json({ error: error instanceof Error ? error.message : 'Internal server error' }, { status: 500 });
}),
ApiAuthError,
};

View File

@@ -41,11 +41,11 @@ vi.mock('@/src/lib/api-auth', () => {
requireApiAdmin: vi.fn().mockResolvedValue({ userId: 1, role: 'admin', authMethod: 'bearer' }),
requireApiUser: vi.fn().mockResolvedValue({ userId: 1, role: 'admin', authMethod: 'bearer' }),
apiErrorResponse: vi.fn((error: unknown) => {
const { NextResponse } = require('next/server');
if (error && typeof error === 'object' && 'status' in error) {
return NextResponse.json({ error: (error as Error).message }, { status: (error as any).status });
const { NextResponse: NR } = require('next/server');
if (error instanceof ApiAuthError) {
return NR.json({ error: error.message }, { status: error.status });
}
return NextResponse.json({ error: error instanceof Error ? error.message : 'Internal server error' }, { status: 500 });
return NR.json({ error: error instanceof Error ? error.message : 'Internal server error' }, { status: 500 });
}),
ApiAuthError,
};
@@ -218,7 +218,7 @@ describe('PUT /api/v1/settings/[group]', () => {
const body = {};
const response = await PUT(createMockRequest({ method: 'PUT', body }), { params: Promise.resolve({ group: 'sync-token' }) });
const data = await response.json();
await response.json();
expect(response.status).toBe(200);
expect(mockSetSlaveMasterToken).toHaveBeenCalledWith(null);

View File

@@ -16,11 +16,11 @@ vi.mock('@/src/lib/api-auth', () => {
requireApiAdmin: vi.fn().mockResolvedValue({ userId: 1, role: 'admin', authMethod: 'bearer' }),
requireApiUser: vi.fn().mockResolvedValue({ userId: 1, role: 'admin', authMethod: 'bearer' }),
apiErrorResponse: vi.fn((error: unknown) => {
const { NextResponse } = require('next/server');
if (error && typeof error === 'object' && 'status' in error) {
return NextResponse.json({ error: (error as Error).message }, { status: (error as any).status });
const { NextResponse: NR } = require('next/server');
if (error instanceof ApiAuthError) {
return NR.json({ error: error.message }, { status: error.status });
}
return NextResponse.json({ error: error instanceof Error ? error.message : 'Internal server error' }, { status: 500 });
return NR.json({ error: error instanceof Error ? error.message : 'Internal server error' }, { status: 500 });
}),
ApiAuthError,
};
@@ -124,7 +124,7 @@ describe('POST /api/v1/tokens', () => {
mockCreateApiToken.mockResolvedValue(tokenResult as any);
const response = await POST(createMockRequest({ method: 'POST', body: { name: 'Expiring Token', expires_at: '2027-01-01' } }));
const data = await response.json();
await response.json();
expect(response.status).toBe(201);
expect(mockCreateApiToken).toHaveBeenCalledWith('Expiring Token', 1, '2027-01-01');

View File

@@ -15,11 +15,11 @@ vi.mock('@/src/lib/api-auth', () => {
requireApiAdmin: vi.fn().mockResolvedValue({ userId: 1, role: 'admin', authMethod: 'bearer' }),
requireApiUser: vi.fn().mockResolvedValue({ userId: 1, role: 'admin', authMethod: 'bearer' }),
apiErrorResponse: vi.fn((error: unknown) => {
const { NextResponse } = require('next/server');
if (error && typeof error === 'object' && 'status' in error) {
return NextResponse.json({ error: (error as Error).message }, { status: (error as any).status });
const { NextResponse: NR } = require('next/server');
if (error instanceof ApiAuthError) {
return NR.json({ error: error.message }, { status: error.status });
}
return NextResponse.json({ error: error instanceof Error ? error.message : 'Internal server error' }, { status: 500 });
return NR.json({ error: error instanceof Error ? error.message : 'Internal server error' }, { status: 500 });
}),
ApiAuthError,
};