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)
This commit is contained in:
2026-01-15 03:26:20 +01:00
parent 1fa424efb9
commit ff46da842f
7 changed files with 57 additions and 32 deletions

View File

@@ -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;
}
}

View File

@@ -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);

View File

@@ -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' });

View File

@@ -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' });
}

View File

@@ -350,7 +350,7 @@ async function performWebSearch(query: string, tavilyApiKey?: string): Promise<s
'Content-Type': 'application/json',
},
body: JSON.stringify({
api_key: apiKey,
api_key: tavilyApiKey,
query: query,
search_depth: 'basic',
include_answer: true,

View File

@@ -18,7 +18,7 @@ interface EmailOptions {
class EmailService {
private transporter: Transporter | null = null;
private isConfigured: boolean = false;
private _isConfigured: boolean = false;
constructor() {
this.initialize();
@@ -37,7 +37,7 @@ class EmailService {
if (!smtpHost || !smtpUser || !smtpPassword) {
logger.warn('SMTP not configured - email functionality will be disabled');
this.isConfigured = false;
this._isConfigured = false;
return;
}
@@ -52,11 +52,11 @@ class EmailService {
},
});
this.isConfigured = true;
this._isConfigured = true;
logger.info('Email service configured');
} catch (error) {
logger.error('Failed to initialize email service:', error);
this.isConfigured = false;
this._isConfigured = false;
}
}
@@ -64,7 +64,7 @@ class EmailService {
* Send an email
*/
async sendEmail(options: EmailOptions): Promise<boolean> {
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;
}
}

View File

@@ -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);
}