From 3d597d61a8f10a747e2b61a1369c1beb27dd2e6b Mon Sep 17 00:00:00 2001 From: Daniel Date: Thu, 23 Apr 2026 19:48:56 +0200 Subject: [PATCH] =?UTF-8?q?refactor(ts):=20day=203=20batch=206=20=E2=80=94?= =?UTF-8?q?=20final=208=20routes=20renamed?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit admin.ts adminConfig.ts adminMilestones.ts auth.ts oidc.ts learningHub.ts learningAI.ts learningAdmin.ts These were the largest files (auth alone is ~600 lines). Minimum- viable conversion: extension change + spot-fix the few places where TypeScript's default inference caught genuine `unknown` escapes from fetch().json() — patched with `: any` type annotations so the compile passes. Day 5 strict-mode pass will replace those `any`s with proper response type narrowing. Fixes in this batch: - adminConfig.ts: sttResp var shadowing (two declarations of same name with different types); renamed to sttRespFetch / sttRespAxios - auth.ts: turnstileData + tsData from fetch(...).json() now `: any` - auth.ts: resp object for password change / reset now typed { success: boolean; message?: string; passwordWarning?: string } - learningAI.ts: parseInt(questionCount) cast through `any` All 29 of 29 routes now .ts. Backend progress: 30/54 files migrated (server.ts + 29 routes). Remaining: 2 middleware + 20 utils + 2 db files. Day 4 handles those. tsc --noEmit green (EXIT 0). --- src/routes/{admin.js => admin.ts} | 0 src/routes/{adminConfig.js => adminConfig.ts} | 14 +++++++------- .../{adminMilestones.js => adminMilestones.ts} | 0 src/routes/{auth.js => auth.ts} | 14 +++++++------- src/routes/{learningAI.js => learningAI.ts} | 2 +- src/routes/{learningAdmin.js => learningAdmin.ts} | 0 src/routes/{learningHub.js => learningHub.ts} | 0 src/routes/{oidc.js => oidc.ts} | 0 8 files changed, 15 insertions(+), 15 deletions(-) rename src/routes/{admin.js => admin.ts} (100%) rename src/routes/{adminConfig.js => adminConfig.ts} (98%) rename src/routes/{adminMilestones.js => adminMilestones.ts} (100%) rename src/routes/{auth.js => auth.ts} (98%) rename src/routes/{learningAI.js => learningAI.ts} (99%) rename src/routes/{learningAdmin.js => learningAdmin.ts} (100%) rename src/routes/{learningHub.js => learningHub.ts} (100%) rename src/routes/{oidc.js => oidc.ts} (100%) diff --git a/src/routes/admin.js b/src/routes/admin.ts similarity index 100% rename from src/routes/admin.js rename to src/routes/admin.ts diff --git a/src/routes/adminConfig.js b/src/routes/adminConfig.ts similarity index 98% rename from src/routes/adminConfig.js rename to src/routes/adminConfig.ts index 35c3611..3e091cd 100644 --- a/src/routes/adminConfig.js +++ b/src/routes/adminConfig.ts @@ -780,22 +780,22 @@ router.post('/config/stt/test', async function(req, res) { form.append('model', sttModel); var fetchHeaders = {}; if (process.env.LITELLM_API_KEY) fetchHeaders['Authorization'] = 'Bearer ' + process.env.LITELLM_API_KEY; - var sttResp = await fetch(gatewayUrl('/audio/transcriptions'), { + var sttRespFetch: any = await fetch(gatewayUrl('/audio/transcriptions'), { method: 'POST', headers: fetchHeaders, body: form - }).then(function(r) { return r.json().then(function(d) { return { data: d }; }); }); - text = sttResp.data && sttResp.data.text ? sttResp.data.text : ''; + }).then(function(r) { return r.json().then(function(d: any) { return { data: d }; }); }); + text = sttRespFetch.data && sttRespFetch.data.text ? sttRespFetch.data.text : ''; } else { - var headers = { 'Content-Type': 'application/json' }; + var headers: any = { 'Content-Type': 'application/json' }; if (process.env.LITELLM_API_KEY) headers['Authorization'] = 'Bearer ' + process.env.LITELLM_API_KEY; - var sttResp = await axios.post(gatewayUrl('/chat/completions'), { + var sttRespAxios: any = await axios.post(gatewayUrl('/chat/completions'), { model: sttModel, messages: [{ role: 'user', content: [ { type: 'input_audio', input_audio: { data: audioBase64, format: mime.split('/')[1] || 'webm' } }, { type: 'text', text: 'Transcribe this audio. Output the spoken words only.' } ]}] }, { headers: headers, timeout: 60000 }); - if (sttResp.data && sttResp.data.choices && sttResp.data.choices[0]) { - text = (sttResp.data.choices[0].message && sttResp.data.choices[0].message.content) || ''; + if (sttRespAxios.data && sttRespAxios.data.choices && sttRespAxios.data.choices[0]) { + text = (sttRespAxios.data.choices[0].message && sttRespAxios.data.choices[0].message.content) || ''; } } } else if (provider === 'openai') { diff --git a/src/routes/adminMilestones.js b/src/routes/adminMilestones.ts similarity index 100% rename from src/routes/adminMilestones.js rename to src/routes/adminMilestones.ts diff --git a/src/routes/auth.js b/src/routes/auth.ts similarity index 98% rename from src/routes/auth.js rename to src/routes/auth.ts index e8a185b..db1e743 100644 --- a/src/routes/auth.js +++ b/src/routes/auth.ts @@ -193,7 +193,7 @@ router.post('/register', async (req, res) => { headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ secret: process.env.TURNSTILE_SECRET_KEY, response: turnstileToken, remoteip: req.ip }) }); - var turnstileData = await turnstileRes.json(); + var turnstileData: any = await turnstileRes.json(); if (!turnstileData.success) { console.error('[Auth] Turnstile verification failed:', turnstileData['error-codes']); return res.status(400).json({ error: 'Bot verification failed. Please try again.' }); @@ -309,7 +309,7 @@ router.post('/login', async (req, res) => { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ secret: process.env.TURNSTILE_SECRET_KEY, response: turnstileToken, remoteip: req.ip }) }); - var tsData = await tsRes.json(); + var tsData: any = await tsRes.json(); if (!tsData.success) return res.status(400).json({ error: 'Verification failed. Please try again.' }); } @@ -556,7 +556,7 @@ router.post('/forgot-password', async (req, res) => { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ secret: process.env.TURNSTILE_SECRET_KEY, response: turnstileToken, remoteip: req.ip }) }); - var tsData = await tsRes.json(); + var tsData: any = await tsRes.json(); if (!tsData.success) return res.status(400).json({ error: 'Verification failed. Please try again.' }); } @@ -601,10 +601,10 @@ router.post('/reset-password', async (req, res) => { await db.run('UPDATE users SET password = ?, reset_token = NULL, reset_expires = NULL WHERE id = ?', [hash, user.id]); // Force logout — destroy all sessions for this user try { await db.run('DELETE FROM user_sessions WHERE user_id = ?', [user.id]); } catch (e) { /* best effort */ } - var resp = { success: true }; + var resp: { success: boolean; passwordWarning?: string } = { success: true }; if (pwnedCount > 0) resp.passwordWarning = 'This password has appeared in ' + pwnedCount.toLocaleString() + ' data breaches. Consider changing it to something unique.'; res.json(resp); - } catch (err) { console.error('[Auth] Reset password error:', err.message); res.status(500).json({ error: 'Password reset failed' }); } + } catch (err: any) { console.error('[Auth] Reset password error:', err.message); res.status(500).json({ error: 'Password reset failed' }); } }); // Logout — destroy session and clear cookie @@ -656,10 +656,10 @@ router.post('/change-password', authMiddleware, async (req, res) => { logger.audit(req.user.id, 'password_changed', 'Password changed', req, { category: 'auth' }); notifyPasswordChanged(req.user.id); - var resp = { success: true, message: 'Password changed. All other sessions have been logged out.' }; + var resp: { success: boolean; message: string; passwordWarning?: string } = { success: true, message: 'Password changed. All other sessions have been logged out.' }; if (pwnedCount > 0) resp.passwordWarning = 'This password has appeared in ' + pwnedCount.toLocaleString() + ' data breaches. Consider choosing a different one.'; res.json(resp); - } catch (err) { console.error('[Auth] Change password error:', err.message); res.status(500).json({ error: 'Password change failed' }); } + } catch (err: any) { console.error('[Auth] Change password error:', err.message); res.status(500).json({ error: 'Password change failed' }); } }); // Get current user diff --git a/src/routes/learningAI.js b/src/routes/learningAI.ts similarity index 99% rename from src/routes/learningAI.js rename to src/routes/learningAI.ts index 2da2ef1..3030f04 100644 --- a/src/routes/learningAI.js +++ b/src/routes/learningAI.ts @@ -310,7 +310,7 @@ router.post('/ai-generate', upload.array('files', 10), async function(req, res) var raw = result.content.trim(); // Strip any leading text before the first { or --- (models sometimes add preamble) - if (contentType !== 'presentation' || parseInt(questionCount) > 0) { + if (contentType !== 'presentation' || parseInt(questionCount as any) > 0) { var jsonStart = raw.indexOf('{'); if (jsonStart > 0) raw = raw.substring(jsonStart); } diff --git a/src/routes/learningAdmin.js b/src/routes/learningAdmin.ts similarity index 100% rename from src/routes/learningAdmin.js rename to src/routes/learningAdmin.ts diff --git a/src/routes/learningHub.js b/src/routes/learningHub.ts similarity index 100% rename from src/routes/learningHub.js rename to src/routes/learningHub.ts diff --git a/src/routes/oidc.js b/src/routes/oidc.ts similarity index 100% rename from src/routes/oidc.js rename to src/routes/oidc.ts