"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const dotenv_1 = __importDefault(require("dotenv"));
const SERVICE_PORT_ENV_KEYS = [
    'PORT',
    'SMARTPERFETTO_BACKEND_PORT',
    'SMARTPERFETTO_FRONTEND_PORT',
    'SMARTPERFETTO_BACKEND_PUBLIC_PORT',
    'SMARTPERFETTO_BACKEND_PUBLIC_URL',
    'SMARTPERFETTO_BACKEND_URL',
    'FRONTEND_URL',
];
const lockedServiceEnv = process.env.SMARTPERFETTO_LOCK_SERVICE_PORTS === '1'
    ? Object.fromEntries(SERVICE_PORT_ENV_KEYS
        .filter((key) => process.env[key] !== undefined)
        .map((key) => [key, process.env[key]]))
    : null;
// Load environment variables FIRST before importing routes
dotenv_1.default.config(process.env.SMARTPERFETTO_ENV_FILE
    ? { path: process.env.SMARTPERFETTO_ENV_FILE, override: true }
    : { override: true });
if (lockedServiceEnv) {
    for (const [key, value] of Object.entries(lockedServiceEnv)) {
        process.env[key] = value;
    }
}
const epipeGuard_1 = require("./utils/epipeGuard");
const express_1 = __importDefault(require("express"));
const cors_1 = __importDefault(require("cors"));
const path_1 = __importDefault(require("path"));
// Import configuration
const config_1 = require("./config");
// Import routes (now after dotenv.config())
const sql_1 = __importDefault(require("./routes/sql"));
const simpleTraceRoutes_1 = __importDefault(require("./routes/simpleTraceRoutes"));
const perfettoLocalRoutes_1 = __importDefault(require("./routes/perfettoLocalRoutes"));
const sessionRoutes_1 = __importDefault(require("./routes/sessionRoutes"));
const perfettoSqlRoutes_1 = __importDefault(require("./routes/perfettoSqlRoutes"));
const exportRoutes_1 = __importDefault(require("./routes/exportRoutes"));
const templateAnalysisRoutes_1 = __importDefault(require("./routes/templateAnalysisRoutes"));
const skillRoutes_1 = __importDefault(require("./routes/skillRoutes"));
const skillAdminRoutes_1 = __importDefault(require("./routes/skillAdminRoutes"));
const strategyAdminRoutes_1 = __importDefault(require("./routes/strategyAdminRoutes"));
const reportRoutes_1 = __importDefault(require("./routes/reportRoutes"));
const agentRoutes_1 = __importDefault(require("./routes/agentRoutes"));
const providerRoutes_1 = __importDefault(require("./routes/providerRoutes"));
const flamegraphRoutes_1 = __importDefault(require("./routes/flamegraphRoutes"));
const criticalPathRoutes_1 = __importDefault(require("./routes/criticalPathRoutes"));
const baselineRoutes_1 = __importDefault(require("./routes/baselineRoutes"));
const ciGateRoutes_1 = __importDefault(require("./routes/ciGateRoutes"));
const memoryRoutes_1 = __importDefault(require("./routes/memoryRoutes"));
const caseRoutes_1 = __importDefault(require("./routes/caseRoutes"));
const ragAdminRoutes_1 = __importDefault(require("./routes/ragAdminRoutes"));
const enterpriseAuthRoutes_1 = __importDefault(require("./routes/enterpriseAuthRoutes"));
const enterpriseApiKeyRoutes_1 = __importDefault(require("./routes/enterpriseApiKeyRoutes"));
const enterpriseTenantRoutes_1 = __importDefault(require("./routes/enterpriseTenantRoutes"));
const enterpriseRuntimeDashboardRoutes_1 = __importDefault(require("./routes/enterpriseRuntimeDashboardRoutes"));
const analysisResultRoutes_1 = __importDefault(require("./routes/analysisResultRoutes"));
const workspaceWindowRoutes_1 = __importDefault(require("./routes/workspaceWindowRoutes"));
const comparisonRoutes_1 = __importDefault(require("./routes/comparisonRoutes"));
const traceProcessorProxyRoutes_1 = __importStar(require("./routes/traceProcessorProxyRoutes"));
const auth_1 = require("./middleware/auth");
const envCredentialSources_1 = require("./agentRuntime/envCredentialSources");
const runtimeHealth_1 = require("./agentRuntime/runtimeHealth");
const legacyApiTelemetry_1 = require("./services/legacyApiTelemetry");
const legacyAgentApi_1 = require("./middleware/legacyAgentApi");
const workspaceRouteContext_1 = require("./middleware/workspaceRouteContext");
// Import cleanup utilities
const workingTraceProcessor_1 = require("./services/workingTraceProcessor");
const portPool_1 = require("./services/portPool");
const analysisRunStore_1 = require("./services/analysisRunStore");
const app = (0, express_1.default)();
const PORT = config_1.serverConfig.port;
const NODE_ENV = config_1.serverConfig.nodeEnv;
const corsAllowedOrigins = new Set(config_1.serverConfig.corsOrigins.map((origin) => origin.replace(/\/+$/, '')));
const workspaceRouteContextMiddleware = [
    workspaceRouteContext_1.bindWorkspaceRouteContext,
    auth_1.authenticate,
    workspaceRouteContext_1.requireWorkspaceRouteContext,
];
function isCorsOriginAllowed(requestOrigin) {
    try {
        const url = new URL(requestOrigin);
        const normalized = `${url.protocol}//${url.host}`;
        return corsAllowedOrigins.has(normalized) || url.port === String(config_1.serverConfig.frontendPort);
    }
    catch {
        return false;
    }
}
// Middleware — dynamic CORS: allow configured origins and the active Perfetto frontend port.
app.use((0, cors_1.default)({
    origin: (requestOrigin, callback) => {
        // No Origin header (server-to-server, curl, etc.) → allow
        if (!requestOrigin)
            return callback(null, true);
        if (isCorsOriginAllowed(requestOrigin))
            return callback(null, true);
        callback(new Error(`CORS blocked: ${requestOrigin}`));
    },
    credentials: true,
}));
app.use(express_1.default.json({ limit: config_1.serverConfig.bodyLimit }));
app.use(express_1.default.urlencoded({ extended: true, limit: config_1.serverConfig.bodyLimit }));
// Health check endpoint
app.get('/health', (req, res) => {
    res.json((0, runtimeHealth_1.buildRuntimeHealthPayload)());
});
// Debug endpoint to check env vars
app.get('/debug', (req, res) => {
    const legacyUsage = (0, legacyApiTelemetry_1.getLegacyApiUsageSnapshot)(10);
    res.json({
        aiCredentialSources: (0, envCredentialSources_1.collectEnvCredentialSources)(process.env, 'health'),
        cwd: process.cwd(),
        legacyAgentApiUsage: legacyUsage,
    });
});
// API routes
app.use('/api/sql', sql_1.default);
app.use('/api/auth', enterpriseAuthRoutes_1.default);
app.use('/api/auth', enterpriseApiKeyRoutes_1.default);
app.use('/api/tenant', enterpriseTenantRoutes_1.default);
app.use('/api/workspaces/:workspaceId/traces', ...workspaceRouteContextMiddleware, simpleTraceRoutes_1.default);
app.use('/api/workspaces/:workspaceId/reports', ...workspaceRouteContextMiddleware, reportRoutes_1.default);
app.use('/api/workspaces/:workspaceId/agent', ...workspaceRouteContextMiddleware, agentRoutes_1.default);
app.use('/api/workspaces/:workspaceId/providers', ...workspaceRouteContextMiddleware, providerRoutes_1.default);
app.use('/api/workspaces/:workspaceId/analysis-results', ...workspaceRouteContextMiddleware, analysisResultRoutes_1.default);
app.use('/api/workspaces/:workspaceId/windows', ...workspaceRouteContextMiddleware, workspaceWindowRoutes_1.default);
app.use('/api/workspaces/:workspaceId/comparisons', ...workspaceRouteContextMiddleware, comparisonRoutes_1.default);
app.use('/api/traces', (0, legacyAgentApi_1.markLegacyApi)('/api/workspaces/:workspaceId/traces', 'Legacy trace API is deprecated. Migrate to workspace-scoped trace APIs'), simpleTraceRoutes_1.default);
app.use('/api/perfetto', perfettoLocalRoutes_1.default);
app.use('/api/sessions', sessionRoutes_1.default);
app.use('/api/perfetto-sql', perfettoSqlRoutes_1.default);
app.use('/api/export', exportRoutes_1.default);
app.use('/api/template-analysis', templateAnalysisRoutes_1.default);
app.use('/api/skills', skillRoutes_1.default);
app.use('/api/admin/runtime', enterpriseRuntimeDashboardRoutes_1.default);
app.use('/api/admin', skillAdminRoutes_1.default);
app.use('/api/admin', strategyAdminRoutes_1.default);
app.use('/api/reports', (0, legacyAgentApi_1.markLegacyApi)('/api/workspaces/:workspaceId/reports', 'Legacy report API is deprecated. Migrate to workspace-scoped report APIs'), reportRoutes_1.default);
app.use(legacyAgentApi_1.AGENT_API_V1_BASE, (0, legacyAgentApi_1.markLegacyApi)('/api/workspaces/:workspaceId/agent', 'Legacy agent API is deprecated. Migrate to workspace-scoped agent APIs'), agentRoutes_1.default);
app.use('/api/v1/providers', (0, legacyAgentApi_1.markLegacyApi)('/api/workspaces/:workspaceId/providers', 'Legacy provider API is deprecated. Migrate to workspace-scoped provider APIs'), providerRoutes_1.default);
app.use('/api/flamegraph', flamegraphRoutes_1.default);
app.use('/api/critical-path', criticalPathRoutes_1.default);
app.use('/api/baselines', baselineRoutes_1.default);
app.use('/api/ci', auth_1.authenticate, ciGateRoutes_1.default);
app.use('/api/tp', traceProcessorProxyRoutes_1.default);
app.use('/api/memory', memoryRoutes_1.default);
app.use('/api/cases', caseRoutes_1.default);
app.use('/api/rag', ragAdminRoutes_1.default);
app.use(legacyAgentApi_1.LEGACY_AGENT_API_BASE, legacyAgentApi_1.rejectLegacyAgentApi);
const assistantShellDir = path_1.default.resolve(__dirname, '../public/assistant-shell');
app.get('/assistant-shell', (_req, res) => {
    res.sendFile(path_1.default.join(assistantShellDir, 'index.html'));
});
app.use('/assistant-shell', express_1.default.static(assistantShellDir));
const adminControlPlaneDir = path_1.default.resolve(__dirname, '../public/admin-control-plane');
app.get('/admin-control-plane', (_req, res) => {
    res.sendFile(path_1.default.join(adminControlPlaneDir, 'index.html'));
});
app.use('/admin-control-plane', express_1.default.static(adminControlPlaneDir));
// Serve uploaded files in development
if (NODE_ENV === 'development') {
    app.use('/uploads', express_1.default.static(path_1.default.join(__dirname, '../uploads')));
}
// 404 handler
app.use((req, res) => {
    res.status(404).json({
        error: 'Route not found',
        message: `Cannot ${req.method} ${req.originalUrl}`,
    });
});
// Global error handler
app.use((err, req, res, next) => {
    console.error('Unhandled error:', err);
    res.status(err.status || 500).json({
        error: 'Internal server error',
        message: NODE_ENV === 'development' ? err.message : 'Something went wrong',
        ...(NODE_ENV === 'development' && { stack: err.stack }),
    });
});
// Initialize services
function recoverInterruptedEnterpriseRuns() {
    if (!(0, config_1.resolveFeatureConfig)().enterprise)
        return;
    try {
        const recovered = (0, analysisRunStore_1.failInterruptedAnalysisRunsOnStartup)();
        if (recovered.length > 0) {
            console.warn(`[EnterpriseRecovery] Marked ${recovered.length} interrupted analysis run(s) failed after backend startup`);
        }
    }
    catch (error) {
        console.warn('[EnterpriseRecovery] Failed to recover interrupted analysis runs:', error?.message || error);
    }
}
recoverInterruptedEnterpriseRuns();
// Kill orphan trace_processor processes from previous runs
(0, workingTraceProcessor_1.killOrphanProcessors)();
// Graceful shutdown handler
function gracefulShutdown(signal) {
    console.log(`\n📴 Received ${signal}, shutting down gracefully...`);
    // Cleanup all trace processors (this will also release ports)
    console.log('🧹 Cleaning up trace processors...');
    workingTraceProcessor_1.TraceProcessorFactory.cleanup();
    // Reset port pool
    console.log('🔌 Resetting port pool...');
    (0, portPool_1.resetPortPool)();
    console.log('✅ Cleanup complete, exiting...');
    process.exit(0);
}
// Register signal handlers
process.on('SIGTERM', () => gracefulShutdown('SIGTERM'));
process.on('SIGINT', () => gracefulShutdown('SIGINT'));
// EPIPE guard: prevent stdout/stderr/uncaughtException EPIPE from crashing the server.
// Non-EPIPE uncaught exceptions still trigger graceful shutdown.
(0, epipeGuard_1.installEpipeGuard)((error) => {
    console.error('❌ Uncaught Exception:', error);
    gracefulShutdown('uncaughtException');
});
process.on('unhandledRejection', (reason, promise) => {
    console.error('❌ Unhandled Rejection at:', promise, 'reason:', reason);
});
// Start server
const server = app.listen(PORT, () => {
    console.log(`🚀 Server running on port ${PORT}`);
    console.log(`📊 Environment: ${NODE_ENV}`);
    console.log(`🔗 API URL: http://localhost:${PORT}/api`);
    console.log(`❤️  Health check: http://localhost:${PORT}/health`);
    console.log(`📈 Stats: http://localhost:${PORT}/api/traces/stats`);
});
server.on('upgrade', (req, socket, head) => {
    if ((0, traceProcessorProxyRoutes_1.handleTraceProcessorProxyUpgrade)(req, socket, head))
        return;
    socket.destroy();
});
// Handle server close
server.on('close', () => {
    console.log('🔒 Server closed');
});
//# sourceMappingURL=index.js.map