"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.bootstrapSolidApp = bootstrapSolidApp;
exports.bootstrapSolidCli = bootstrapSolidCli;
const common_1 = require("@nestjs/common");
const core_1 = require("@nestjs/core");
const platform_ws_1 = require("@nestjs/platform-ws");
const swagger_1 = require("@nestjs/swagger");
const helmet_1 = __importDefault(require("helmet"));
const qs_1 = __importDefault(require("qs"));
const fs_1 = require("fs");
const path_1 = require("path");
const nest_winston_1 = require("nest-winston");
const nest_commander_1 = require("nest-commander");
const winston_logger_1 = require("../winston.logger");
const wrap_response_interceptor_1 = require("../interceptors/wrap-response.interceptor");
const cors_helper_1 = require("./cors.helper");
const security_helper_1 = require("./security.helper");
const environment_helper_1 = require("./environment.helper");
function registerGlobalProcessHandlers() {
    process.on('unhandledRejection', (reason, promise) => {
        console.error('Unhandled Rejection at:', promise, 'reason:', reason);
    });
    process.on('uncaughtException', (err) => {
        console.error('Uncaught Exception thrown:', err);
    });
    process.on('warning', (warning) => {
        if (warning.name === 'DeprecationWarning' && (warning.message.includes('client.query()') || warning.message.includes('punycode'))) {
            return;
        }
        console.warn(warning);
    });
}
async function bootstrapSolidApp(appModuleFactory, options = {}) {
    registerGlobalProcessHandlers();
    const { globalPrefix = 'api', swagger = {}, permissionsPolicyOverrides = {}, verboseBootstrap = false } = options;
    const startTime = Date.now();
    const appModule = await appModuleFactory();
    const app = await core_1.NestFactory.create(appModule, {
        logger: nest_winston_1.WinstonModule.createLogger({ ...(0, winston_logger_1.createWinstonLoggerConfig)(), level: verboseBootstrap ? 'debug' : 'error' }),
    });
    const apiEnabled = (0, environment_helper_1.parseBooleanEnv)('API_ENABLED', true);
    if (!apiEnabled) {
        await app.init();
        app
            .get(nest_winston_1.WINSTON_MODULE_NEST_PROVIDER)
            .log('API server disabled via API_ENABLED=false. Skipping HTTP listen.', 'Bootstrap');
        return;
    }
    const server = app.getHttpAdapter().getInstance();
    server.get('/', (_req, res) => res.status(200).send('SOLID OK'));
    app.use((0, helmet_1.default)((0, security_helper_1.buildDefaultSecurityHeaderOptions)()));
    const isSwaggerPath = (path) => path === '/docs' ||
        path === '/docs/' ||
        path.startsWith('/docs/') ||
        path === '/docs-json' ||
        path === '/docs-yaml';
    app.use((req, res, next) => {
        if (isSwaggerPath(req.path)) {
            res.removeHeader('Content-Security-Policy');
        }
        next();
    });
    app.use((_req, res, next) => {
        res.setHeader('Permissions-Policy', (0, security_helper_1.buildPermissionsPolicyHeader)(permissionsPolicyOverrides));
        next();
    });
    const port = process.env.PORT || 3000;
    if (globalPrefix) {
        app.setGlobalPrefix(globalPrefix);
    }
    app.use((req, _res, next) => {
        if (req.query) {
            req.query = qs_1.default.parse(req.url.split('?')[1], {
                allowDots: true,
                depth: 20,
                arrayLimit: 100,
            });
        }
        next();
    });
    app.useGlobalPipes(new common_1.ValidationPipe({
        transform: true,
        transformOptions: { enableImplicitConversion: true },
    }));
    if (swagger !== false) {
        const { title = process.env.SOLID_APP_NAME, description = process.env.SOLID_APP_DESCRIPTION, version = '1.0' } = swagger;
        const swaggerConfig = new swagger_1.DocumentBuilder()
            .setTitle(title)
            .setDescription(description)
            .setVersion(version)
            .setExternalDoc('Postman Collection', '/docs-json')
            .addBearerAuth({
            description: 'Please enter token in following format: Bearer <JWT>',
            name: 'Authorization',
            bearerFormat: 'Bearer',
            scheme: 'Bearer',
            type: 'http',
            in: 'Header',
        }, 'jwt')
            .build();
        const document = swagger_1.SwaggerModule.createDocument(app, swaggerConfig);
        swagger_1.SwaggerModule.setup('/docs', app, document);
    }
    app.useGlobalInterceptors(new wrap_response_interceptor_1.WrapResponseInterceptor());
    app.enableCors((0, cors_helper_1.buildDefaultCorsOptions)());
    const types = require('pg').types;
    types.setTypeParser(types.builtins.INT8, (val) => parseInt(val));
    app.useWebSocketAdapter(new platform_ws_1.WsAdapter(app));
    await app.listen(port);
    app.useLogger(app.get(nest_winston_1.WINSTON_MODULE_NEST_PROVIDER));
    const elapsed = ((Date.now() - startTime) / 1000).toFixed(2);
    process.stdout.write(`\x1b[32mServer started on port ${port} in ${elapsed}s\x1b[0m\n`);
}
async function bootstrapSolidCli(appModuleFactory) {
    registerGlobalProcessHandlers();
    process.on('exit', (code) => {
        if (code !== 0) {
            console.error(`Exiting with error status code: ${code}`);
        }
    });
    const packageJsonPath = (0, path_1.resolve)(process.cwd(), 'package.json');
    if (!(0, fs_1.existsSync)(packageJsonPath)) {
        console.error('Does not seem to be a valid solid-api project.');
        console.error('Exit reason: missing package.json in the current directory.');
        process.exit(1);
    }
    const showLogs = process.argv.includes('--verbose') || process.argv.includes('-v');
    for (const flag of ['--verbose', '-v']) {
        const idx = process.argv.indexOf(flag);
        if (idx !== -1)
            process.argv.splice(idx, 1);
    }
    const appModule = await appModuleFactory();
    process.env.SOLID_CLI_RUNNING = 'true';
    const app = await nest_commander_1.CommandFactory.createWithoutRunning(appModule, {
        logger: showLogs ? ['debug', 'error', 'fatal', 'log', 'verbose', 'warn'] : false,
    });
    try {
        await nest_commander_1.CommandFactory.runApplication(app);
    }
    catch (e) {
        console.error('CLI exited abruptly due to an error:', e);
        process.exit(1);
    }
    process.exit(0);
}
//# sourceMappingURL=bootstrap.helper.js.map