"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
    return function (target, key) { decorator(target, key, paramIndex); }
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.clearEnvCache = exports.ConfigRepository = void 0;
const common_1 = require("@nestjs/common");
const nestjs_cls_1 = require("nestjs-cls");
const node_fs_1 = require("node:fs");
const node_path_1 = require("node:path");
const constants_1 = require("../constants");
const decorators_1 = require("../decorators");
const env_dto_1 = require("../dtos/env.dto");
const enum_1 = require("../enum");
const set_1 = require("../utils/set");
const productionKeys = {
    client: 'LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUF2LzdTMzJjUkE1KysxTm5WRHNDTQpzcFAvakpISU1xT0pYRm5oNE53QTJPcHorUk1mZGNvOTJQc09naCt3d1FlRXYxVTJjMnBqelRpUS8ybHJLcS9rCnpKUmxYd2M0Y1Vlc1FETUpPRitQMnFPTlBiQUprWHZDWFlCVUxpdENJa29Md2ZoU0dOanlJS2FSRGhkL3ROeU4KOCtoTlJabllUMWhTSWo5U0NrS3hVQ096YXRQVjRtQ0RlclMrYkUrZ0VVZVdwOTlWOWF6dkYwRkltblRXcFFTdwpjOHdFWmdPTWg0c3ZoNmFpY3dkemtQQ3dFTGFrMFZhQkgzMUJFVUNRTGI5K0FJdEhBVXRKQ0t4aGI1V2pzMXM5CmJyWGZpMHZycGdjWi82RGFuWTJxZlNQem5PbXZEMkZycmxTMXE0SkpOM1ZvN1d3LzBZeS95TWNtelRXWmhHdWgKVVFJREFRQUIKLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tDQo=',
    server: 'LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUFvcG5ZRGEwYS9kVTVJZUc3NGlFRQpNd2RBS2pzTmN6TGRDcVJkMVo5eTVUMndqTzdlWUlPZUpUc2wzNTBzUjBwNEtmU1VEU1h2QzlOcERwYzF0T0tsCjVzaEMvQXhwdlFBTENva0Y0anQ4dnJyZDlmQ2FYYzFUcVJiT21uaGl1Z0Q2dmtyME8vRmIzVURpM1UwVHZoUFAKbFBkdlNhd3pMcldaUExmbUhWVnJiclNLbW45SWVTZ3kwN3VrV1RJeUxzY2lOcnZuQnl3c0phUmVEdW9OV1BCSApVL21vMm1YYThtNHdNV2hpWGVoaUlPUXFNdVNVZ1BlQ3NXajhVVngxQ0dsUnpQREEwYlZOUXZlS1hXVnhjRUk2ClVMRWdKeTJGNDlsSDArYVlDbUJmN05FcjZWUTJXQjk1ZXZUS1hLdm4wcUlNN25nRmxjVUF3NmZ1VjFjTkNUSlMKNndJREFRQUIKLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tDQo=',
};
const stagingKeys = {
    client: 'LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUFuSUNyTm5jbGpPSC9JdTNtWVVaRQp0dGJLV1c3OGRuajl5M0U2ekk3dU1NUndEckdYWFhkTGhkUDFxSWtlZHh0clVVeUpCMWR4R04yQW91S082MlNGCldrbU9PTmNGQlRBWFZTdjhUNVY0S0VwWnFQYWEwaXpNaGxMaE5sRXEvY1ZKdllrWlh1Z2x6b1o3cG1nbzFSdHgKam1iRm5NNzhrYTFRUUJqOVdLaEw2eWpWRUl2MDdVS0lKWHBNTnNuS2g1V083MjZhYmMzSE9udTlETjY5VnFFRQo3dGZrUnRWNmx2U1NzMkFVMngzT255cHA4ek53b0lPTWRibGsyb09aWWROZzY0Y3l2SzJoU0FlU3NVMFRyOVc5Ckgra0Y5QlNCNlk0QXl0QlVkSmkrK2pMSW5HM2Q5cU9ieFVzTlYrN05mRkF5NjJkL0xNR0xSOC9OUFc0U0s3c0MKRlFJREFRQUIKLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tDQo=',
    server: 'LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUE3Sy8yd3ZLUS9NdU8ydi9MUm5saAoyUy9zTHhDOGJiTEw1UUlKOGowQ3BVZW40YURlY2dYMUpKUmtGNlpUVUtpNTdTbEhtS3RSM2JOTzJmdTBUUVg5Ck5WMEJzVzllZVB0MmlTMWl4VVFmTzRObjdvTjZzbEtac01qd29RNGtGRGFmM3VHTlZJc0dMb3UxVWRLUVhpeDEKUlRHcXVTb3NZVjNWRlk3Q1hGYTVWaENBL3poVXNsNGFuVXp3eEF6M01jUFVlTXBaenYvbVZiQlRKVzBPSytWZgpWQUJvMXdYMkVBanpBekVHVzQ3Vko4czhnMnQrNHNPaHFBNStMQjBKVzlORUg5QUpweGZzWE4zSzVtM00yNUJVClZXcTlRYStIdHRENnJ0bnAvcUFweXVkWUdwZk9HYTRCUlZTR1MxMURZM0xrb2FlRzYwUEU5NHpoYjduOHpMWkgKelFJREFRQUIKLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tDQo=',
};
const WORKER_TYPES = new Set(Object.values(enum_1.ImmichWorker));
const TELEMETRY_TYPES = new Set(Object.values(enum_1.ImmichTelemetry));
const asSet = (value, defaults) => {
    const values = (value || '').replaceAll(/\s/g, '').split(',').filter(Boolean);
    return new Set(values.length === 0 ? defaults : values);
};
const resolveHelmetFile = (helmetFile) => {
    if (!helmetFile || helmetFile === 'false') {
        return;
    }
    helmetFile =
        helmetFile === 'true'
            ?
                (0, node_path_1.join)(__dirname, '..', '..', 'helmet.json')
            : helmetFile;
    try {
        return JSON.parse((0, node_fs_1.readFileSync)(helmetFile).toString());
    }
    catch (error) {
        throw new Error(`Failed to read helmet file: ${helmetFile}`, { cause: error });
    }
};
const getEnv = () => {
    const parseResult = env_dto_1.EnvSchema.safeParse(process.env);
    if (!parseResult.success) {
        const messages = ['Invalid environment variables: '];
        for (const issue of parseResult.error.issues) {
            const path = issue.path.join('.');
            messages.push(`  - [${path}] ${issue.message}`);
        }
        throw new Error(messages.join('\n'));
    }
    const dto = parseResult.data;
    const includedWorkers = asSet(dto.IMMICH_WORKERS_INCLUDE, [enum_1.ImmichWorker.Api, enum_1.ImmichWorker.Microservices]);
    const excludedWorkers = asSet(dto.IMMICH_WORKERS_EXCLUDE, []);
    const workers = [...(0, set_1.setDifference)(includedWorkers, excludedWorkers)];
    for (const worker of workers) {
        if (!WORKER_TYPES.has(worker)) {
            throw new Error(`Invalid worker(s) found: ${workers.join(',')}`);
        }
    }
    const environment = dto.IMMICH_ENV || enum_1.ImmichEnvironment.Production;
    const isProd = environment === enum_1.ImmichEnvironment.Production;
    const buildFolder = dto.IMMICH_BUILD_DATA || '/build';
    const folders = {
        geodata: (0, node_path_1.join)(buildFolder, 'geodata'),
        web: (0, node_path_1.join)(buildFolder, 'www'),
    };
    let redisConfig = {
        host: dto.REDIS_HOSTNAME || 'redis',
        port: dto.REDIS_PORT || 6379,
        db: dto.REDIS_DBINDEX || 0,
        username: dto.REDIS_USERNAME || undefined,
        password: dto.REDIS_PASSWORD || undefined,
        path: dto.REDIS_SOCKET || undefined,
    };
    const redisUrl = dto.REDIS_URL;
    if (redisUrl && redisUrl.startsWith('ioredis://')) {
        try {
            redisConfig = JSON.parse(Buffer.from(redisUrl.slice(10), 'base64').toString());
        }
        catch (error) {
            throw new Error('Failed to decode redis options', { cause: error });
        }
    }
    const includedTelemetries = dto.IMMICH_TELEMETRY_INCLUDE === 'all'
        ? new Set(Object.values(enum_1.ImmichTelemetry))
        : asSet(dto.IMMICH_TELEMETRY_INCLUDE, []);
    const excludedTelemetries = asSet(dto.IMMICH_TELEMETRY_EXCLUDE, []);
    const telemetries = (0, set_1.setDifference)(includedTelemetries, excludedTelemetries);
    for (const telemetry of telemetries) {
        if (!TELEMETRY_TYPES.has(telemetry)) {
            throw new Error(`Invalid telemetry found: ${telemetry}`);
        }
    }
    const databaseConnection = dto.DB_URL
        ? { connectionType: 'url', url: dto.DB_URL }
        : {
            connectionType: 'parts',
            host: dto.DB_HOSTNAME || 'database',
            port: dto.DB_PORT || 5432,
            username: dto.DB_USERNAME || 'postgres',
            password: dto.DB_PASSWORD || 'postgres',
            database: dto.DB_DATABASE_NAME || 'immich',
            ssl: dto.DB_SSL_MODE || undefined,
        };
    let vectorExtension;
    if (dto.DB_VECTOR_EXTENSION) {
        switch (dto.DB_VECTOR_EXTENSION) {
            case 'pgvector': {
                vectorExtension = enum_1.DatabaseExtension.Vector;
                break;
            }
            case 'vectorchord': {
                vectorExtension = enum_1.DatabaseExtension.VectorChord;
                break;
            }
        }
    }
    return {
        host: dto.IMMICH_HOST,
        port: dto.IMMICH_PORT || 2283,
        environment,
        configFile: dto.IMMICH_CONFIG_FILE,
        logLevel: dto.IMMICH_LOG_LEVEL,
        logFormat: dto.IMMICH_LOG_FORMAT || enum_1.LogFormat.Console,
        buildMetadata: {
            build: dto.IMMICH_BUILD,
            buildUrl: dto.IMMICH_BUILD_URL,
            buildImage: dto.IMMICH_BUILD_IMAGE,
            buildImageUrl: dto.IMMICH_BUILD_IMAGE_URL,
            repository: dto.IMMICH_REPOSITORY,
            repositoryUrl: dto.IMMICH_REPOSITORY_URL,
            sourceRef: dto.IMMICH_SOURCE_REF,
            sourceCommit: dto.IMMICH_SOURCE_COMMIT,
            sourceUrl: dto.IMMICH_SOURCE_URL,
            thirdPartySourceUrl: dto.IMMICH_THIRD_PARTY_SOURCE_URL,
            thirdPartyBugFeatureUrl: dto.IMMICH_THIRD_PARTY_BUG_FEATURE_URL,
            thirdPartyDocumentationUrl: dto.IMMICH_THIRD_PARTY_DOCUMENTATION_URL,
            thirdPartySupportUrl: dto.IMMICH_THIRD_PARTY_SUPPORT_URL,
        },
        bull: {
            config: {
                prefix: 'immich_bull',
                connection: { ...redisConfig },
                defaultJobOptions: {
                    attempts: 1,
                    removeOnComplete: true,
                    removeOnFail: false,
                },
            },
            queues: Object.values(enum_1.QueueName).map((name) => ({ name })),
        },
        cls: {
            config: {
                middleware: {
                    mount: true,
                    generateId: true,
                    setup: (cls, req, res) => {
                        const cid = req.header(enum_1.ImmichHeader.CorrelationId) || cls.get(nestjs_cls_1.CLS_ID);
                        cls.set(nestjs_cls_1.CLS_ID, cid);
                        res.header(enum_1.ImmichHeader.CorrelationId, cid);
                    },
                },
            },
        },
        database: {
            config: databaseConnection,
            skipMigrations: dto.DB_SKIP_MIGRATIONS ?? false,
            vectorExtension,
        },
        helmet: {
            config: resolveHelmetFile(dto.IMMICH_HELMET_FILE),
        },
        licensePublicKey: isProd ? productionKeys : stagingKeys,
        versionCheck: {
            url: isProd ? 'https://version.immich.cloud/version' : 'https://version.dev.immich.cloud/version',
        },
        network: {
            trustedProxies: dto.IMMICH_TRUSTED_PROXIES ?? ['linklocal', 'uniquelocal'],
        },
        otel: {
            metrics: {
                hostMetrics: telemetries.has(enum_1.ImmichTelemetry.Host),
            },
        },
        redis: redisConfig,
        resourcePaths: {
            lockFile: (0, node_path_1.join)(buildFolder, 'build-lock.json'),
            geodata: {
                dateFile: (0, node_path_1.join)(folders.geodata, 'geodata-date.txt'),
                admin1: (0, node_path_1.join)(folders.geodata, 'admin1CodesASCII.txt'),
                admin2: (0, node_path_1.join)(folders.geodata, 'admin2Codes.txt'),
                cities500: (0, node_path_1.join)(folders.geodata, constants_1.citiesFile),
                naturalEarthCountriesPath: (0, node_path_1.join)(folders.geodata, 'ne_10m_admin_0_countries.geojson'),
            },
            web: {
                root: folders.web,
                indexHtml: (0, node_path_1.join)(folders.web, 'index.html'),
            },
            corePlugin: (0, node_path_1.join)(buildFolder, 'plugins', 'immich-plugin-core'),
        },
        setup: {
            allow: dto.IMMICH_ALLOW_SETUP ?? true,
        },
        storage: {
            ignoreMountCheckErrors: !!dto.IMMICH_IGNORE_MOUNT_CHECK_ERRORS,
            mediaLocation: dto.IMMICH_MEDIA_LOCATION,
        },
        telemetry: {
            apiPort: dto.IMMICH_API_METRICS_PORT || 8081,
            microservicesPort: dto.IMMICH_MICROSERVICES_METRICS_PORT || 8082,
            metrics: telemetries,
        },
        workers,
        plugins: {
            external: {
                allow: dto.IMMICH_ALLOW_EXTERNAL_PLUGINS ?? false,
                installFolder: dto.IMMICH_PLUGINS_INSTALL_FOLDER,
            },
        },
        noColor: !!dto.NO_COLOR,
    };
};
let cached;
let ConfigRepository = class ConfigRepository {
    worker;
    constructor(worker) {
        this.worker = worker;
    }
    getEnv() {
        if (!cached) {
            cached = getEnv();
        }
        return cached;
    }
    isDev() {
        return this.getEnv().environment === enum_1.ImmichEnvironment.Development;
    }
    getWorker() {
        return this.worker;
    }
};
exports.ConfigRepository = ConfigRepository;
exports.ConfigRepository = ConfigRepository = __decorate([
    (0, common_1.Injectable)(),
    (0, decorators_1.Telemetry)({ enabled: false }),
    __param(0, (0, common_1.Inject)(constants_1.IWorker)),
    __param(0, (0, common_1.Optional)()),
    __metadata("design:paramtypes", [String])
], ConfigRepository);
const clearEnvCache = () => (cached = undefined);
exports.clearEnvCache = clearEnvCache;
//# sourceMappingURL=config.repository.js.map