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);
};
import DatabaseService from "./DatabaseService";
import OneUptimeDate from "../../Types/Date";
import ObjectID from "../../Types/ObjectID";
import QueryHelper from "../Types/Database/QueryHelper";
import Model from "../../Models/DatabaseModels/ApiKey";
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
import InMemoryTTLCache from "../Infrastructure/InMemoryTTLCache";
/*
 * 60s is the worst-case staleness on any single API node after a key is
 * revoked from the dashboard. We invalidate in-process immediately on
 * delete/update; this TTL is the upper bound for *other* processes.
 */
const POSITIVE_TTL_MS = 60 * 1000;
/*
 * Short TTL on misses so an invalid-key flood can't pin entries in the
 * bounded cache for long while still absorbing repeat hits.
 */
const NEGATIVE_TTL_MS = 10 * 1000;
export class Service extends DatabaseService {
    constructor() {
        super(Model);
        /*
         * Cache of `apiKey -> { id, projectId }`. The project-auth middleware hits
         * this on every API-key-authenticated request; without it that's a
         * Postgres findOneBy per request for automated callers.
         */
        this.apiKeyCache = new InMemoryTTLCache(10000);
    }
    async onBeforeCreate(createBy) {
        createBy.data.apiKey = ObjectID.generate();
        return { createBy, carryForward: null };
    }
    async onBeforeUpdate(updateBy) {
        /*
         * We don't know which keys are being updated without a query; updates
         * are rare so clearing is cheap.
         */
        this.apiKeyCache.clear();
        return { updateBy, carryForward: null };
    }
    async onBeforeDelete(deleteBy) {
        this.apiKeyCache.clear();
        return { deleteBy, carryForward: null };
    }
    /**
     * Resolves an API key string to its row, with a short-lived in-process
     * cache. Returns null for unknown or expired keys (also cached, for a
     * shorter TTL). Use this from the auth middleware hot path instead of
     * calling `findOneBy` directly.
     */
    async findApiKey(apiKey) {
        const cacheKey = apiKey.toString();
        const cached = this.apiKeyCache.get(cacheKey);
        if (cached !== undefined) {
            if (cached === null) {
                return null;
            }
            return {
                id: new ObjectID(cached.id),
                projectId: new ObjectID(cached.projectId),
            };
        }
        const row = await this.findOneBy({
            query: {
                apiKey: apiKey,
                expiresAt: QueryHelper.greaterThan(OneUptimeDate.getCurrentDate()),
            },
            select: {
                _id: true,
                projectId: true,
            },
            props: { isRoot: true },
        });
        if (!row || !row.id || !row.projectId) {
            this.apiKeyCache.set(cacheKey, null, NEGATIVE_TTL_MS);
            return null;
        }
        this.apiKeyCache.set(cacheKey, { id: row.id.toString(), projectId: row.projectId.toString() }, POSITIVE_TTL_MS);
        return { id: row.id, projectId: row.projectId };
    }
}
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object]),
    __metadata("design:returntype", Promise)
], Service.prototype, "onBeforeCreate", null);
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object]),
    __metadata("design:returntype", Promise)
], Service.prototype, "onBeforeUpdate", null);
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object]),
    __metadata("design:returntype", Promise)
], Service.prototype, "onBeforeDelete", null);
__decorate([
    CaptureSpan(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [ObjectID]),
    __metadata("design:returntype", Promise)
], Service.prototype, "findApiKey", null);
export default new Service();
//# sourceMappingURL=ApiKeyService.js.map