"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.app = exports.HomebridgeIpcService = void 0;
const node_path_1 = require("node:path");
const node_process_1 = __importDefault(require("node:process"));
const helmet_1 = __importDefault(require("@fastify/helmet"));
const multipart_1 = __importDefault(require("@fastify/multipart"));
const common_1 = require("@nestjs/common");
const core_1 = require("@nestjs/core");
const platform_fastify_1 = require("@nestjs/platform-fastify");
const swagger_1 = require("@nestjs/swagger");
const bonjour_service_1 = require("bonjour-service");
const fs_extra_1 = require("fs-extra");
const app_module_1 = require("./app.module");
const config_service_1 = require("./core/config/config.service");
const config_startup_1 = require("./core/config/config.startup");
const logger_service_1 = require("./core/logger/logger.service");
const spa_html_service_1 = require("./core/spa/spa-html.service");
const spa_filter_1 = require("./core/spa/spa.filter");
require("./self-check");
require("./globalDefaults");
var homebridge_ipc_service_1 = require("./core/homebridge-ipc/homebridge-ipc.service");
Object.defineProperty(exports, "HomebridgeIpcService", { enumerable: true, get: function () { return homebridge_ipc_service_1.HomebridgeIpcService; } });
node_process_1.default.env.UIX_BASE_PATH = node_process_1.default.env.UIX_BASE_PATH_OVERRIDE || (0, node_path_1.resolve)(__dirname, '../');
async function bootstrap() {
    const startupConfig = await (0, config_startup_1.getStartupConfig)();
    const fAdapter = new platform_fastify_1.FastifyAdapter({
        https: startupConfig.httpsOptions,
        logger: startupConfig.debug || false,
    });
    fAdapter.register(multipart_1.default, {
        limits: {
            files: 1,
            fileSize: globalThis.backup.maxBackupSize,
        },
    });
    fAdapter.register(helmet_1.default, {
        hsts: false,
        frameguard: false,
        referrerPolicy: {
            policy: 'no-referrer',
        },
        crossOriginEmbedderPolicy: false,
        crossOriginOpenerPolicy: false,
        crossOriginResourcePolicy: false,
        contentSecurityPolicy: {
            directives: {
                defaultSrc: ['\'self\''],
                scriptSrc: ['\'self\'', '\'unsafe-inline\'', '\'unsafe-eval\''],
                styleSrc: ['\'self\'', '\'unsafe-inline\''],
                imgSrc: ['\'self\'', 'data:', 'https://raw.githubusercontent.com', 'https://user-images.githubusercontent.com'],
                connectSrc: ['\'self\'', 'https://openweathermap.org', 'https://api.openweathermap.org', (req) => {
                        return `wss://${req.headers.host} ws://${req.headers.host} ${startupConfig.cspWsOverride || ''}`;
                    }],
                frameSrc: ['\'self\'', 'data:', 'https://developers.homebridge.io'],
                scriptSrcAttr: null,
                fontSrc: null,
                objectSrc: null,
                frameAncestors: null,
                formAction: null,
                baseUri: null,
                upgradeInsecureRequests: null,
                blockAllMixedContent: null,
            },
        },
    });
    const app = await core_1.NestFactory.create(app_module_1.AppModule, fAdapter, {
        logger: startupConfig.debug ? new logger_service_1.Logger() : false,
        httpsOptions: startupConfig.httpsOptions,
    });
    const configService = app.get(config_service_1.ConfigService);
    const logger = app.get(logger_service_1.Logger);
    let realWebroot = startupConfig.webroot || '';
    try {
        await spa_html_service_1.SpaHtmlService.updateIndexHtml(startupConfig.webroot);
        node_process_1.default.env.UIX_ORIGINAL_WEBROOT = startupConfig.webroot;
        configService.setOriginalWebroot(startupConfig.webroot);
    }
    catch (error) {
        logger.warn(`Could not update index.html with webroot ${startupConfig.webroot}: ${error.message}`);
        realWebroot = '';
        node_process_1.default.env.UIX_ORIGINAL_WEBROOT = globalThis.webroot.errorCode;
        configService.setOriginalWebroot(globalThis.webroot.errorCode);
    }
    app.getHttpAdapter().get(realWebroot || '/', async (req, res) => {
        res.type('text/html');
        res.header('Cache-Control', 'no-cache, no-store, must-revalidate');
        res.header('Pragma', 'no-cache');
        res.header('Expires', '0');
        res.header('Origin-Agent-Cluster', '?1');
        res.send(await (0, fs_extra_1.readFile)((0, node_path_1.resolve)(node_process_1.default.env.UIX_BASE_PATH, 'public/index.html')));
    });
    app.useStaticAssets({
        root: (0, node_path_1.resolve)(node_process_1.default.env.UIX_BASE_PATH, 'public'),
        setHeaders(res) {
            res.setHeader('Cache-Control', 'public,max-age=31536000,immutable');
        },
        ...realWebroot ? { prefix: realWebroot } : {},
    });
    app.setGlobalPrefix(`${realWebroot || ''}/api`);
    app.enableCors({
        origin: ['http://localhost:8080', 'http://localhost:4200'],
        methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
    });
    app.useGlobalPipes(new common_1.ValidationPipe({
        whitelist: true,
        skipMissingProperties: true,
    }));
    const options = new swagger_1.DocumentBuilder()
        .setTitle('Homebridge UI API Reference')
        .setVersion(configService.package.version)
        .addBearerAuth({
        type: 'oauth2',
        flows: {
            password: {
                tokenUrl: '/api/auth/login',
                scopes: null,
            },
        },
    })
        .build();
    const document = swagger_1.SwaggerModule.createDocument(app, options);
    swagger_1.SwaggerModule.setup(`${realWebroot}/swagger`.replace(/^\//, ''), app, document);
    app.useGlobalFilters(new spa_filter_1.SpaFilter());
    logger.warn(`Homebridge UI v${configService.package.version} is listening on ${startupConfig.host} port ${configService.ui.port}.`);
    await app.listen(configService.ui.port, startupConfig.host);
    let bonjour = null;
    if (configService.ui.enableMdnsAdvertise) {
        try {
            bonjour = new bonjour_service_1.Bonjour();
            const serviceName = configService.homebridgeConfig?.bridge?.name
                ? configService.homebridgeConfig.bridge.name
                : 'Homebridge UI';
            const service = bonjour.publish({
                name: serviceName,
                type: 'http',
                port: configService.ui.port,
                host: startupConfig.host === '0.0.0.0' || startupConfig.host === '::' ? undefined : startupConfig.host,
                txt: {
                    path: realWebroot || '/',
                    version: configService.package.version,
                    https: startupConfig.httpsOptions ? 'true' : 'false',
                },
            });
            logger.log(`Homebridge UI HTTP service advertised via mDNS as "${service.name}" on port ${configService.ui.port}`);
        }
        catch (error) {
            logger.error('Failed to advertise mDNS service:', error);
        }
    }
    const cleanupBonjour = () => {
        if (bonjour) {
            try {
                logger.log('Shutting down mDNS service advertising...');
                bonjour.unpublishAll();
                bonjour.destroy();
                bonjour = null;
            }
            catch (error) {
                logger.error('Error during mDNS cleanup:', error);
            }
        }
    };
    const handleShutdown = (signal) => {
        logger.log(`Received ${signal}, starting graceful shutdown...`);
        cleanupBonjour();
        app.close().finally(() => {
            node_process_1.default.exit(0);
        });
    };
    node_process_1.default.removeAllListeners('SIGINT');
    node_process_1.default.removeAllListeners('SIGTERM');
    node_process_1.default.once('SIGINT', () => handleShutdown('SIGINT'));
    node_process_1.default.once('SIGTERM', () => handleShutdown('SIGTERM'));
    return app;
}
exports.app = bootstrap();
//# sourceMappingURL=main.js.map