diff --git a/config.example.ts b/config.example.ts index d922e4d..513c8bc 100644 --- a/config.example.ts +++ b/config.example.ts @@ -3,24 +3,8 @@ import type { Config } from './src/types'; const config: Config = { server: { port: 3000, - // host: '0.0.0.0', // Uncomment to bind to all interfaces (default is localhost only) }, - // Dashboard configuration (optional) - // dashboard: { - // enabled: true, - // // Authentication options (choose one): - // auth: { - // // Option 1: Basic HTTP authentication - // type: 'basic', - // username: 'admin', - // password: 'changeme', - // // Option 2: Bearer token authentication - // // type: 'token', - // // token: 'your-secret-token-here', - // }, - // }, - repositories: [ // Leave empty to accept webhooks from any repo. // { owner: "myorg", repo: "myrepo" }, diff --git a/eslint.config.ts b/eslint.config.mjs similarity index 76% rename from eslint.config.ts rename to eslint.config.mjs index 4a51839..57ccfab 100644 --- a/eslint.config.ts +++ b/eslint.config.mjs @@ -2,9 +2,9 @@ import tseslint from '@typescript-eslint/eslint-plugin'; import tsparser from '@typescript-eslint/parser'; export default [ - { ignores: ['dist/**', 'node_modules/**', '**/*.d.ts'] }, { - files: ['src/**/*.ts', '**/*.js', 'config.example.ts', 'tsup.config.ts'], + files: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'], + ignores: ['dist/**', 'node_modules/**'], languageOptions: { ecmaVersion: 2022, sourceType: 'module', @@ -19,9 +19,8 @@ export default [ }, }, plugins: { - '@typescript-eslint': tseslint as unknown as Record, + '@typescript-eslint': tseslint, }, - rules: { ...tseslint.configs.recommended.rules, '@typescript-eslint/no-explicit-any': 'warn', diff --git a/prettier.config.ts b/prettier.config.mjs similarity index 75% rename from prettier.config.ts rename to prettier.config.mjs index 218a5fa..e218dce 100644 --- a/prettier.config.ts +++ b/prettier.config.mjs @@ -1,6 +1,4 @@ -import type { Config } from 'prettier'; - -const config: Config = { +export default { printWidth: 100, tabWidth: 2, useTabs: false, @@ -15,5 +13,3 @@ const config: Config = { endOfLine: 'lf', plugins: [], }; - -export default config; diff --git a/src/config.ts b/src/config.ts index e5896c0..5c6354f 100644 --- a/src/config.ts +++ b/src/config.ts @@ -97,10 +97,7 @@ export function loadConfig(): Config { ); } - const config = deepMerge( - defaults as unknown as Record, - fileConfig as unknown as Record - ) as unknown as Config; + const config = deepMerge(defaults, fileConfig); // Environment variable overrides if (process.env.PORT) { @@ -111,31 +108,6 @@ export function loadConfig(): Config { config.server.port = parsed; } - if (process.env.HOST) { - config.server.host = process.env.HOST; - } - - if (process.env.DASHBOARD_TOKEN) { - config.dashboard = { - ...(config.dashboard || { enabled: true }), - auth: { - type: 'token', - token: process.env.DASHBOARD_TOKEN, - }, - }; - } - - if (process.env.DASHBOARD_USERNAME && process.env.DASHBOARD_PASSWORD) { - config.dashboard = { - ...(config.dashboard || { enabled: true }), - auth: { - type: 'basic', - username: process.env.DASHBOARD_USERNAME, - password: process.env.DASHBOARD_PASSWORD, - }, - }; - } - const validLogLevels = ['debug', 'info', 'warn', 'error']; if (process.env.LOG_LEVEL) { if (!validLogLevels.includes(process.env.LOG_LEVEL)) { diff --git a/src/dashboard.ts b/src/dashboard.ts index db6f3e6..64cd5fc 100644 --- a/src/dashboard.ts +++ b/src/dashboard.ts @@ -9,43 +9,6 @@ export function createDashboardRouter(config: Config): express.Router { router.use(express.json()); - // Authentication middleware - if (config.dashboard?.auth) { - router.use((req, res, next) => { - const auth = config.dashboard!.auth!; - - if (auth.type === 'basic') { - const authHeader = req.headers.authorization; - if (!authHeader || !authHeader.startsWith('Basic ')) { - res.setHeader('WWW-Authenticate', 'Basic realm="Troutbot Dashboard"'); - res.status(401).json({ error: 'Authentication required' }); - return; - } - - const credentials = Buffer.from(authHeader.slice(6), 'base64').toString('utf8'); - const [username, password] = credentials.split(':'); - - if (username !== auth.username || password !== auth.password) { - res.setHeader('WWW-Authenticate', 'Basic realm="Troutbot Dashboard"'); - res.status(401).json({ error: 'Invalid credentials' }); - return; - } - } else if (auth.type === 'token') { - const authHeader = req.headers.authorization; - const token = req.query.token as string | undefined; - - const providedToken = authHeader?.startsWith('Bearer ') ? authHeader.slice(7) : token; - - if (!providedToken || providedToken !== auth.token) { - res.status(401).json({ error: 'Invalid or missing token' }); - return; - } - } - - next(); - }); - } - // API routes router.get('/api/status', (_req, res) => { const enabledBackends = Object.entries(config.engine.backends) @@ -78,9 +41,9 @@ export function createDashboardRouter(config: Config): express.Router { try { const partial = req.body as Partial; const merged = deepMerge( - config as unknown as Record, - partial as unknown as Record - ) as unknown as Config; + config as Record, + partial as Record + ) as Config; validate(merged); // Apply in-place @@ -92,7 +55,8 @@ export function createDashboardRouter(config: Config): express.Router { } }); - // Dashboard HTML + // --- Dashboard HTML --- + router.get('/dashboard', (_req, res) => { res.type('html').send(dashboardHTML()); }); diff --git a/src/index.ts b/src/index.ts index 1545763..2e24cbb 100644 --- a/src/index.ts +++ b/src/index.ts @@ -27,13 +27,12 @@ async function analyzeOne(target: string) { initLogger(config.logging); const logger = getLogger(); + initGitHub(process.env.GITHUB_TOKEN); if (!process.env.GITHUB_TOKEN) { logger.error('GITHUB_TOKEN is required for analyze mode'); process.exit(1); } - initGitHub(process.env.GITHUB_TOKEN); - const prData = await fetchPR(owner, repo, prNumber); if (!prData) { logger.error(`Could not fetch PR ${owner}/${repo}#${prNumber}`); @@ -109,9 +108,8 @@ function serve() { .filter(([, v]) => v.enabled) .map(([k]) => k); - const host = config.server.host || '127.0.0.1'; - const server = app.listen(port, host, async () => { - logger.info(`Troutbot listening on ${host}:${port}`); + const server = app.listen(port, async () => { + logger.info(`Troutbot listening on port ${port}`); logger.info(`Enabled backends: ${enabledBackends.join(', ')}`); // Watched repos @@ -142,8 +140,7 @@ function serve() { // Comment update mode logger.info(`Comment updates: ${config.response.allowUpdates ? 'enabled' : 'disabled'}`); - const displayHost = host === '0.0.0.0' ? 'localhost' : host; - logger.info(`Dashboard available at http://${displayHost}:${port}/dashboard`); + logger.info(`Dashboard available at http://localhost:${port}/dashboard`); // Start polling if enabled await startPolling(config); diff --git a/src/types.ts b/src/types.ts index 939a62e..ab07dff 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,6 +1,5 @@ export interface Config { server: ServerConfig; - dashboard?: DashboardConfig; repositories: RepoConfig[]; filters: FiltersConfig; engine: EngineConfig; @@ -17,22 +16,9 @@ export interface PollingConfig { export interface ServerConfig { port: number; - host?: string; rateLimit?: number; } -export interface DashboardConfig { - enabled: boolean; - auth?: DashboardAuthConfig; -} - -export interface DashboardAuthConfig { - type: 'basic' | 'token'; - username?: string; - password?: string; - token?: string; -} - export interface RepoConfig { owner: string; repo: string;