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 ObjectID from "../../Types/ObjectID";
import Model from "../../Models/DatabaseModels/TelemetryIngestionKey";
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
import InMemoryTTLCache from "../Infrastructure/InMemoryTTLCache";
import { createHash } from "crypto";
/*
 * 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-token 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);
        this.projectIdCache = new InMemoryTTLCache(10000);
    }
    async onBeforeCreate(createBy) {
        if (!createBy.data.secretKey) {
            createBy.data.secretKey = ObjectID.generate();
        }
        return { createBy, carryForward: null };
    }
    async onBeforeDelete(deleteBy) {
        /*
         * We don't know which secretKey(s) are being deleted without an extra
         * query; clear the whole cache. Key deletes are rare so this is cheap.
         */
        this.projectIdCache.clear();
        return { deleteBy, carryForward: null };
    }
    async onBeforeUpdate(updateBy) {
        /*
         * Same reasoning as onBeforeDelete. secretKey is not user-editable today
         * but projectId could change, so be conservative.
         */
        this.projectIdCache.clear();
        return { updateBy, carryForward: null };
    }
    /**
     * Resolve an ingestion token to its projectId, with a short-lived
     * in-process cache to keep the hot ingest path off Postgres. Returns null
     * for unknown, malformed, or revoked tokens (also cached, for a shorter
     * TTL).
     */
    async getProjectIdFromSecretKey(secretKey) {
        const cacheKey = createHash("sha256")
            .update(secretKey)
            .digest("hex");
        const cached = this.projectIdCache.get(cacheKey);
        if (cached !== undefined) {
            return cached === null ? null : new ObjectID(cached);
        }
        let secretKeyObjectId;
        try {
            secretKeyObjectId = new ObjectID(secretKey);
        }
        catch (_a) {
            this.projectIdCache.set(cacheKey, null, NEGATIVE_TTL_MS);
            return null;
        }
        const token = await this.findOneBy({
            query: { secretKey: secretKeyObjectId },
            select: { projectId: true },
            props: { isRoot: true },
        });
        const projectId = token === null || token === void 0 ? void 0 : token.projectId;
        if (!projectId) {
            this.projectIdCache.set(cacheKey, null, NEGATIVE_TTL_MS);
            return null;
        }
        this.projectIdCache.set(cacheKey, projectId.toString(), POSITIVE_TTL_MS);
        return 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, "onBeforeDelete", 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", [String]),
    __metadata("design:returntype", Promise)
], Service.prototype, "getProjectIdFromSecretKey", null);
export default new Service();
//# sourceMappingURL=TelemetryIngestionKeyService.js.map