From ff46da842fc17b66192980bc22609486b96d5278 Mon Sep 17 00:00:00 2001 From: Bert Hausmans Date: Thu, 15 Jan 2026 03:26:20 +0100 Subject: [PATCH] Fix TypeScript compilation errors - Fix conflicting Request interface declarations (auth.ts vs authorization.ts) - Fix email field type issue in auth.ts (handle undefined) - Fix req.params type issues (string | string[] to string) in auth.ts, roles.ts, users.ts - Fix apiKey undefined issue in claude.ts (use tavilyApiKey) - Fix duplicate isConfigured identifier in emailService.ts (rename to _isConfigured) - Fix confluencePage property type issue in jiraAssetsClient.ts (add type assertion) --- backend/src/middleware/authorization.ts | 5 ++-- backend/src/routes/auth.ts | 8 ++++--- backend/src/routes/roles.ts | 21 +++++++++++------ backend/src/routes/users.ts | 30 ++++++++++++++++-------- backend/src/services/claude.ts | 2 +- backend/src/services/emailService.ts | 12 +++++----- backend/src/services/jiraAssetsClient.ts | 11 ++++++--- 7 files changed, 57 insertions(+), 32 deletions(-) diff --git a/backend/src/middleware/authorization.ts b/backend/src/middleware/authorization.ts index 33804b9..db41934 100644 --- a/backend/src/middleware/authorization.ts +++ b/backend/src/middleware/authorization.ts @@ -5,16 +5,17 @@ */ import { Request, Response, NextFunction } from 'express'; -import { authService, type SessionUser } from '../services/authService.js'; +import { authService, type SessionUser, type JiraUser } from '../services/authService.js'; import { roleService } from '../services/roleService.js'; import { logger } from '../services/logger.js'; // Extend Express Request to include user info +// Note: This matches the declaration in auth.ts declare global { namespace Express { interface Request { sessionId?: string; - user?: SessionUser; + user?: SessionUser | JiraUser; accessToken?: string; } } diff --git a/backend/src/routes/auth.ts b/backend/src/routes/auth.ts index 9f05de5..5249205 100644 --- a/backend/src/routes/auth.ts +++ b/backend/src/routes/auth.ts @@ -9,6 +9,7 @@ import { getAuthDatabase } from '../services/database/migrations.js'; const router = Router(); // Extend Express Request to include user info +// Note: This extends the declaration from authorization.ts declare global { namespace Express { interface Request { @@ -113,12 +114,13 @@ router.get('/me', async (req: Request, res: Response) => { let userData = session.user; if ('id' in session.user) { // Local user - ensure proper format + const email = session.user.email || session.user.emailAddress || ''; userData = { id: session.user.id, - email: session.user.email || session.user.emailAddress, + email: email, username: session.user.username, displayName: session.user.displayName, - emailAddress: session.user.email || session.user.emailAddress, + emailAddress: email, roles: session.user.roles || [], permissions: session.user.permissions || [], }; @@ -388,7 +390,7 @@ router.post('/verify-email', async (req: Request, res: Response) => { // Get invitation token info router.get('/invitation/:token', async (req: Request, res: Response) => { - const { token } = req.params; + const token = Array.isArray(req.params.token) ? req.params.token[0] : req.params.token; try { const user = await userService.validateInvitationToken(token); diff --git a/backend/src/routes/roles.ts b/backend/src/routes/roles.ts index d7b7832..d7ce942 100644 --- a/backend/src/routes/roles.ts +++ b/backend/src/routes/roles.ts @@ -37,7 +37,8 @@ router.get('/', async (req: Request, res: Response) => { // Get role by ID router.get('/:id', async (req: Request, res: Response) => { try { - const id = parseInt(req.params.id, 10); + const idParam = Array.isArray(req.params.id) ? req.params.id[0] : req.params.id; + const id = parseInt(idParam, 10); if (isNaN(id)) { return res.status(400).json({ error: 'Invalid role ID' }); } @@ -80,7 +81,8 @@ router.post('/', requireAuth, requireAdmin, async (req: Request, res: Response) // Update role (admin only) router.put('/:id', requireAuth, requireAdmin, async (req: Request, res: Response) => { try { - const id = parseInt(req.params.id, 10); + const idParam = Array.isArray(req.params.id) ? req.params.id[0] : req.params.id; + const id = parseInt(idParam, 10); if (isNaN(id)) { return res.status(400).json({ error: 'Invalid role ID' }); } @@ -99,7 +101,8 @@ router.put('/:id', requireAuth, requireAdmin, async (req: Request, res: Response // Delete role (admin only) router.delete('/:id', requireAuth, requireAdmin, async (req: Request, res: Response) => { try { - const id = parseInt(req.params.id, 10); + const idParam = Array.isArray(req.params.id) ? req.params.id[0] : req.params.id; + const id = parseInt(idParam, 10); if (isNaN(id)) { return res.status(400).json({ error: 'Invalid role ID' }); } @@ -120,7 +123,8 @@ router.delete('/:id', requireAuth, requireAdmin, async (req: Request, res: Respo // Get role permissions router.get('/:id/permissions', async (req: Request, res: Response) => { try { - const id = parseInt(req.params.id, 10); + const idParam = Array.isArray(req.params.id) ? req.params.id[0] : req.params.id; + const id = parseInt(idParam, 10); if (isNaN(id)) { return res.status(400).json({ error: 'Invalid role ID' }); } @@ -136,7 +140,8 @@ router.get('/:id/permissions', async (req: Request, res: Response) => { // Assign permission to role (admin only) router.post('/:id/permissions', requireAuth, requireAdmin, async (req: Request, res: Response) => { try { - const id = parseInt(req.params.id, 10); + const idParam = Array.isArray(req.params.id) ? req.params.id[0] : req.params.id; + const id = parseInt(idParam, 10); if (isNaN(id)) { return res.status(400).json({ error: 'Invalid role ID' }); } @@ -162,8 +167,10 @@ router.post('/:id/permissions', requireAuth, requireAdmin, async (req: Request, // Remove permission from role (admin only) router.delete('/:id/permissions/:permissionId', requireAuth, requireAdmin, async (req: Request, res: Response) => { try { - const roleId = parseInt(req.params.id, 10); - const permissionId = parseInt(req.params.permissionId, 10); + const roleIdParam = Array.isArray(req.params.id) ? req.params.id[0] : req.params.id; + const permissionIdParam = Array.isArray(req.params.permissionId) ? req.params.permissionId[0] : req.params.permissionId; + const roleId = parseInt(roleIdParam, 10); + const permissionId = parseInt(permissionIdParam, 10); if (isNaN(roleId) || isNaN(permissionId)) { return res.status(400).json({ error: 'Invalid role ID or permission ID' }); diff --git a/backend/src/routes/users.ts b/backend/src/routes/users.ts index 78c6473..6040f9b 100644 --- a/backend/src/routes/users.ts +++ b/backend/src/routes/users.ts @@ -42,7 +42,8 @@ router.get('/', async (req: Request, res: Response) => { // Get user by ID router.get('/:id', async (req: Request, res: Response) => { try { - const id = parseInt(req.params.id, 10); + const idParam = Array.isArray(req.params.id) ? req.params.id[0] : req.params.id; + const id = parseInt(idParam, 10); if (isNaN(id)) { return res.status(400).json({ error: 'Invalid user ID' }); } @@ -99,7 +100,8 @@ router.post('/', async (req: Request, res: Response) => { // Update user router.put('/:id', async (req: Request, res: Response) => { try { - const id = parseInt(req.params.id, 10); + const idParam = Array.isArray(req.params.id) ? req.params.id[0] : req.params.id; + const id = parseInt(idParam, 10); if (isNaN(id)) { return res.status(400).json({ error: 'Invalid user ID' }); } @@ -129,7 +131,8 @@ router.put('/:id', async (req: Request, res: Response) => { // Delete user router.delete('/:id', async (req: Request, res: Response) => { try { - const id = parseInt(req.params.id, 10); + const idParam = Array.isArray(req.params.id) ? req.params.id[0] : req.params.id; + const id = parseInt(idParam, 10); if (isNaN(id)) { return res.status(400).json({ error: 'Invalid user ID' }); } @@ -154,7 +157,8 @@ router.delete('/:id', async (req: Request, res: Response) => { // Send invitation email router.post('/:id/invite', async (req: Request, res: Response) => { try { - const id = parseInt(req.params.id, 10); + const idParam = Array.isArray(req.params.id) ? req.params.id[0] : req.params.id; + const id = parseInt(idParam, 10); if (isNaN(id)) { return res.status(400).json({ error: 'Invalid user ID' }); } @@ -174,7 +178,8 @@ router.post('/:id/invite', async (req: Request, res: Response) => { // Assign role to user router.post('/:id/roles', async (req: Request, res: Response) => { try { - const id = parseInt(req.params.id, 10); + const idParam = Array.isArray(req.params.id) ? req.params.id[0] : req.params.id; + const id = parseInt(idParam, 10); if (isNaN(id)) { return res.status(400).json({ error: 'Invalid user ID' }); } @@ -200,8 +205,10 @@ router.post('/:id/roles', async (req: Request, res: Response) => { // Remove role from user router.delete('/:id/roles/:roleId', async (req: Request, res: Response) => { try { - const userId = parseInt(req.params.id, 10); - const roleId = parseInt(req.params.roleId, 10); + const userIdParam = Array.isArray(req.params.id) ? req.params.id[0] : req.params.id; + const roleIdParam = Array.isArray(req.params.roleId) ? req.params.roleId[0] : req.params.roleId; + const userId = parseInt(userIdParam, 10); + const roleId = parseInt(roleIdParam, 10); if (isNaN(userId) || isNaN(roleId)) { return res.status(400).json({ error: 'Invalid user ID or role ID' }); @@ -231,7 +238,8 @@ router.delete('/:id/roles/:roleId', async (req: Request, res: Response) => { // Activate/deactivate user router.put('/:id/activate', async (req: Request, res: Response) => { try { - const id = parseInt(req.params.id, 10); + const idParam = Array.isArray(req.params.id) ? req.params.id[0] : req.params.id; + const id = parseInt(idParam, 10); if (isNaN(id)) { return res.status(400).json({ error: 'Invalid user ID' }); } @@ -257,7 +265,8 @@ router.put('/:id/activate', async (req: Request, res: Response) => { // Manually verify email address (admin action) router.put('/:id/verify-email', async (req: Request, res: Response) => { try { - const id = parseInt(req.params.id, 10); + const idParam = Array.isArray(req.params.id) ? req.params.id[0] : req.params.id; + const id = parseInt(idParam, 10); if (isNaN(id)) { return res.status(400).json({ error: 'Invalid user ID' }); } @@ -282,7 +291,8 @@ router.put('/:id/verify-email', async (req: Request, res: Response) => { // Set password for user (admin action) router.put('/:id/password', async (req: Request, res: Response) => { try { - const id = parseInt(req.params.id, 10); + const idParam = Array.isArray(req.params.id) ? req.params.id[0] : req.params.id; + const id = parseInt(idParam, 10); if (isNaN(id)) { return res.status(400).json({ error: 'Invalid user ID' }); } diff --git a/backend/src/services/claude.ts b/backend/src/services/claude.ts index 4fd0c96..ee49ab3 100644 --- a/backend/src/services/claude.ts +++ b/backend/src/services/claude.ts @@ -350,7 +350,7 @@ async function performWebSearch(query: string, tavilyApiKey?: string): Promise { - if (!this.isConfigured || !this.transporter) { + if (!this._isConfigured || !this.transporter) { logger.warn('Email service not configured - email not sent:', options.to); // In development, log the email content if (config.isDevelopment) { @@ -282,7 +282,7 @@ class EmailService { * Check if email service is configured */ isConfigured(): boolean { - return this.isConfigured; + return this._isConfigured; } } diff --git a/backend/src/services/jiraAssetsClient.ts b/backend/src/services/jiraAssetsClient.ts index 477d406..c2c7937 100644 --- a/backend/src/services/jiraAssetsClient.ts +++ b/backend/src/services/jiraAssetsClient.ts @@ -453,14 +453,19 @@ class JiraAssetsClient { // Generic Confluence field detection: check if any value has a confluencePage // This works for all Confluence fields regardless of their declared type (float, text, etc.) - const hasConfluencePage = values.some(v => v.confluencePage); + // Type assertion needed because confluencePage is not in the type definition but exists at runtime + type AttributeValueWithConfluence = typeof values[0] & { + confluencePage?: { url?: string }; + }; + const valuesWithConfluence = values as AttributeValueWithConfluence[]; + const hasConfluencePage = valuesWithConfluence.some(v => v.confluencePage); if (hasConfluencePage) { - const confluencePage = values[0]?.confluencePage; + const confluencePage = valuesWithConfluence[0]?.confluencePage; if (confluencePage?.url) { logger.info(`[Confluence Field Parse] Found Confluence URL for field "${attrDef.fieldName || 'unknown'}": ${confluencePage.url}`); // For multiple values, return array of URLs; for single, return the URL string if (attrDef.isMultiple) { - return values + return valuesWithConfluence .filter(v => v.confluencePage?.url) .map(v => v.confluencePage!.url); }