"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const p_defer_1 = __importDefault(require("p-defer")); function mapAgeCleaner(map, property = 'maxAge') { let processingKey; let processingTimer; let processingDeferred; const cleanup = () => __awaiter(this, void 0, void 0, function* () { if (processingKey !== undefined) { // If we are already processing an item, we can safely exit return; } const setupTimer = (item) => __awaiter(this, void 0, void 0, function* () { processingDeferred = p_defer_1.default(); const delay = item[1][property] - Date.now(); if (delay <= 0) { // Remove the item immediately if the delay is equal to or below 0 map.delete(item[0]); processingDeferred.resolve(); return; } // Keep track of the current processed key processingKey = item[0]; processingTimer = setTimeout(() => { // Remove the item when the timeout fires map.delete(item[0]); if (processingDeferred) { processingDeferred.resolve(); } }, delay); // tslint:disable-next-line:strict-type-predicates if (typeof processingTimer.unref === 'function') { // Don't hold up the process from exiting processingTimer.unref(); } return processingDeferred.promise; }); try { for (const entry of map) { yield setupTimer(entry); } } catch (_a) { // Do nothing if an error occurs, this means the timer was cleaned up and we should stop processing } processingKey = undefined; }); const reset = () => { processingKey = undefined; if (processingTimer !== undefined) { clearTimeout(processingTimer); processingTimer = undefined; } if (processingDeferred !== undefined) { // tslint:disable-line:early-exit processingDeferred.reject(undefined); processingDeferred = undefined; } }; const originalSet = map.set.bind(map); map.set = (key, value) => { if (map.has(key)) { // If the key already exist, remove it so we can add it back at the end of the map. map.delete(key); } // Call the original `map.set` const result = originalSet(key, value); // If we are already processing a key and the key added is the current processed key, stop processing it if (processingKey && processingKey === key) { reset(); } // Always run the cleanup method in case it wasn't started yet cleanup(); // tslint:disable-line:no-floating-promises return result; }; cleanup(); // tslint:disable-line:no-floating-promises return map; } exports.default = mapAgeCleaner; // Add support for CJS module.exports = mapAgeCleaner; module.exports.default = mapAgeCleaner;