"use strict";
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getLocalCryptographicMaterialsCache = void 0;
const lru_cache_1 = __importDefault(require("lru-cache"));
const material_management_1 = require("@aws-crypto/material-management");
function getLocalCryptographicMaterialsCache(capacity, proactiveFrequency = 1000 * 60) {
    const cache = new lru_cache_1.default({
        max: capacity,
        dispose(_key, value) {
            /* Zero out the unencrypted dataKey, when the material is removed from the cache. */
            value.response.zeroUnencryptedDataKey();
        },
    });
    (function proactivelyTryAndEvictTail() {
        const timeout = setTimeout(() => {
            mayEvictTail();
            proactivelyTryAndEvictTail();
        }, proactiveFrequency);
        /* In Node.js the event loop will _only_ exit if there are no outstanding events.
         * This means that if I did nothing the event loop would *always* be blocked.
         * This is unfortunate and very bad for things like Lambda.
         * So, I tell Node.js to not wait for this timer.
         * See: https://nodejs.org/api/timers.html#timers_timeout_unref
         */
        // @ts-ignore
        timeout.unref && timeout.unref();
    })();
    return {
        putEncryptionMaterial(key, material, plaintextLength, maxAge) {
            /* Precondition: putEncryptionMaterial plaintextLength can not be negative. */
            (0, material_management_1.needs)(plaintextLength >= 0, 'Malformed plaintextLength');
            /* Precondition: Only cache EncryptionMaterial. */
            (0, material_management_1.needs)((0, material_management_1.isEncryptionMaterial)(material), 'Malformed response.');
            /* Precondition: Only cache EncryptionMaterial that is cacheSafe. */
            (0, material_management_1.needs)(material.suite.cacheSafe, 'Can not cache non-cache safe material');
            const entry = Object.seal({
                response: material,
                bytesEncrypted: plaintextLength,
                messagesEncrypted: 1,
                now: Date.now(),
            });
            cache.set(key, entry, maxAge);
        },
        putDecryptionMaterial(key, material, maxAge) {
            /* Precondition: Only cache DecryptionMaterial. */
            (0, material_management_1.needs)((0, material_management_1.isDecryptionMaterial)(material), 'Malformed response.');
            /* Precondition: Only cache DecryptionMaterial that is cacheSafe. */
            (0, material_management_1.needs)(material.suite.cacheSafe, 'Can not cache non-cache safe material');
            const entry = Object.seal({
                response: material,
                bytesEncrypted: 0,
                messagesEncrypted: 0,
                now: Date.now(),
            });
            cache.set(key, entry, maxAge);
        },
        getEncryptionMaterial(key, plaintextLength) {
            /* Precondition: plaintextLength can not be negative. */
            (0, material_management_1.needs)(plaintextLength >= 0, 'Malformed plaintextLength');
            const entry = cache.get(key);
            /* Check for early return (Postcondition): If this key does not have an EncryptionMaterial, return false. */
            if (!entry)
                return false;
            /* Postcondition: Only return EncryptionMaterial. */
            (0, material_management_1.needs)((0, material_management_1.isEncryptionMaterial)(entry.response), 'Malformed response.');
            entry.bytesEncrypted += plaintextLength;
            entry.messagesEncrypted += 1;
            return entry;
        },
        getDecryptionMaterial(key) {
            const entry = cache.get(key);
            /* Check for early return (Postcondition): If this key does not have a DecryptionMaterial, return false. */
            if (!entry)
                return false;
            /* Postcondition: Only return DecryptionMaterial. */
            (0, material_management_1.needs)((0, material_management_1.isDecryptionMaterial)(entry.response), 'Malformed response.');
            return entry;
        },
        del(key) {
            cache.del(key);
        },
    };
    function mayEvictTail() {
        // @ts-ignore
        const { tail } = cache.dumpLru();
        /* Check for early return (Postcondition) UNTESTED: If there is no tail, then the cache is empty. */
        if (!tail)
            return;
        /* The underlying Yallist tail Node has a `value`.
         * This value is a lru-cache Entry and has a `key`.
         */
        const { key } = tail.value;
        // Peek will evict, but not update the "recently used"-ness of the key.
        cache.peek(key);
    }
}
exports.getLocalCryptographicMaterialsCache = getLocalCryptographicMaterialsCache;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2V0X2xvY2FsX2NyeXB0b2dyYXBoaWNfbWF0ZXJpYWxzX2NhY2hlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2dldF9sb2NhbF9jcnlwdG9ncmFwaGljX21hdGVyaWFsc19jYWNoZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEsb0VBQW9FO0FBQ3BFLHNDQUFzQzs7Ozs7O0FBRXRDLDBEQUEyQjtBQUMzQix5RUFPd0M7QUFTeEMsU0FBZ0IsbUNBQW1DLENBR2pELFFBQWdCLEVBQ2hCLHFCQUE2QixJQUFJLEdBQUcsRUFBRTtJQUV0QyxNQUFNLEtBQUssR0FBRyxJQUFJLG1CQUFHLENBQW1CO1FBQ3RDLEdBQUcsRUFBRSxRQUFRO1FBQ2IsT0FBTyxDQUFDLElBQUksRUFBRSxLQUFLO1lBQ2pCLG9GQUFvRjtZQUNwRixLQUFLLENBQUMsUUFBUSxDQUFDLHNCQUFzQixFQUFFLENBQUE7UUFDekMsQ0FBQztLQUNGLENBQUMsQ0FlRDtJQUFBLENBQUMsU0FBUywwQkFBMEI7UUFDbkMsTUFBTSxPQUFPLEdBQUcsVUFBVSxDQUFDLEdBQUcsRUFBRTtZQUM5QixZQUFZLEVBQUUsQ0FBQTtZQUNkLDBCQUEwQixFQUFFLENBQUE7UUFDOUIsQ0FBQyxFQUFFLGtCQUFrQixDQUFDLENBQUE7UUFDdEI7Ozs7O1dBS0c7UUFDSCxhQUFhO1FBQ2IsT0FBTyxDQUFDLEtBQUssSUFBSSxPQUFPLENBQUMsS0FBSyxFQUFFLENBQUE7SUFDbEMsQ0FBQyxDQUFDLEVBQUUsQ0FBQTtJQUVKLE9BQU87UUFDTCxxQkFBcUIsQ0FDbkIsR0FBVyxFQUNYLFFBQStCLEVBQy9CLGVBQXVCLEVBQ3ZCLE1BQWU7WUFFZiw4RUFBOEU7WUFDOUUsSUFBQSwyQkFBSyxFQUFDLGVBQWUsSUFBSSxDQUFDLEVBQUUsMkJBQTJCLENBQUMsQ0FBQTtZQUN4RCxrREFBa0Q7WUFDbEQsSUFBQSwyQkFBSyxFQUFDLElBQUEsMENBQW9CLEVBQUMsUUFBUSxDQUFD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