{"version":3,"file":"cleanup-queue.cjs","sources":["../../../src/collection/cleanup-queue.ts"],"sourcesContent":["type CleanupTask = {\n  executeAt: number\n  callback: () => void\n}\n\n/**\n * Batches many GC registrations behind a single shared timeout.\n */\nexport class CleanupQueue {\n  private static instance: CleanupQueue | null = null\n\n  private tasks: Map<unknown, CleanupTask> = new Map()\n\n  private timeoutId: ReturnType<typeof setTimeout> | null = null\n  private microtaskScheduled = false\n\n  private constructor() {}\n\n  public static getInstance(): CleanupQueue {\n    if (!CleanupQueue.instance) {\n      CleanupQueue.instance = new CleanupQueue()\n    }\n    return CleanupQueue.instance\n  }\n\n  /**\n   * Queues a cleanup task and defers timeout selection to a microtask so\n   * multiple synchronous registrations can share one root timer.\n   */\n  public schedule(key: unknown, gcTime: number, callback: () => void): void {\n    const executeAt = Date.now() + gcTime\n    this.tasks.set(key, { executeAt, callback })\n\n    if (!this.microtaskScheduled) {\n      this.microtaskScheduled = true\n      Promise.resolve().then(() => {\n        this.microtaskScheduled = false\n        this.updateTimeout()\n      })\n    }\n  }\n\n  public cancel(key: unknown): void {\n    this.tasks.delete(key)\n  }\n\n  /**\n   * Keeps only one active timeout: whichever task is due next.\n   */\n  private updateTimeout(): void {\n    if (this.timeoutId !== null) {\n      clearTimeout(this.timeoutId)\n      this.timeoutId = null\n    }\n\n    if (this.tasks.size === 0) {\n      return\n    }\n\n    let earliestTime = Infinity\n    for (const task of this.tasks.values()) {\n      if (task.executeAt < earliestTime) {\n        earliestTime = task.executeAt\n      }\n    }\n\n    const delay = Math.max(0, earliestTime - Date.now())\n    this.timeoutId = setTimeout(() => this.process(), delay)\n  }\n\n  /**\n   * Runs every task whose deadline has passed, then schedules the next wakeup\n   * if there is still pending work.\n   */\n  private process(): void {\n    this.timeoutId = null\n    const now = Date.now()\n    for (const [key, task] of this.tasks.entries()) {\n      if (now >= task.executeAt) {\n        this.tasks.delete(key)\n        try {\n          task.callback()\n        } catch (error) {\n          console.error('Error in CleanupQueue task:', error)\n        }\n      }\n    }\n\n    if (this.tasks.size > 0) {\n      this.updateTimeout()\n    }\n  }\n\n  /**\n   * Resets the singleton instance for tests.\n   */\n  public static resetInstance(): void {\n    if (CleanupQueue.instance) {\n      if (CleanupQueue.instance.timeoutId !== null) {\n        clearTimeout(CleanupQueue.instance.timeoutId)\n      }\n      CleanupQueue.instance = null\n    }\n  }\n}\n"],"names":[],"mappings":";;AAQO,MAAM,gBAAN,MAAM,cAAa;AAAA,EAQhB,cAAc;AALtB,SAAQ,4BAAuC,IAAA;AAE/C,SAAQ,YAAkD;AAC1D,SAAQ,qBAAqB;AAAA,EAEN;AAAA,EAEvB,OAAc,cAA4B;AACxC,QAAI,CAAC,cAAa,UAAU;AAC1B,oBAAa,WAAW,IAAI,cAAA;AAAA,IAC9B;AACA,WAAO,cAAa;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMO,SAAS,KAAc,QAAgB,UAA4B;AACxE,UAAM,YAAY,KAAK,IAAA,IAAQ;AAC/B,SAAK,MAAM,IAAI,KAAK,EAAE,WAAW,UAAU;AAE3C,QAAI,CAAC,KAAK,oBAAoB;AAC5B,WAAK,qBAAqB;AAC1B,cAAQ,UAAU,KAAK,MAAM;AAC3B,aAAK,qBAAqB;AAC1B,aAAK,cAAA;AAAA,MACP,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEO,OAAO,KAAoB;AAChC,SAAK,MAAM,OAAO,GAAG;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA,EAKQ,gBAAsB;AAC5B,QAAI,KAAK,cAAc,MAAM;AAC3B,mBAAa,KAAK,SAAS;AAC3B,WAAK,YAAY;AAAA,IACnB;AAEA,QAAI,KAAK,MAAM,SAAS,GAAG;AACzB;AAAA,IACF;AAEA,QAAI,eAAe;AACnB,eAAW,QAAQ,KAAK,MAAM,OAAA,GAAU;AACtC,UAAI,KAAK,YAAY,cAAc;AACjC,uBAAe,KAAK;AAAA,MACtB;AAAA,IACF;AAEA,UAAM,QAAQ,KAAK,IAAI,GAAG,eAAe,KAAK,KAAK;AACnD,SAAK,YAAY,WAAW,MAAM,KAAK,QAAA,GAAW,KAAK;AAAA,EACzD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,UAAgB;AACtB,SAAK,YAAY;AACjB,UAAM,MAAM,KAAK,IAAA;AACjB,eAAW,CAAC,KAAK,IAAI,KAAK,KAAK,MAAM,WAAW;AAC9C,UAAI,OAAO,KAAK,WAAW;AACzB,aAAK,MAAM,OAAO,GAAG;AACrB,YAAI;AACF,eAAK,SAAA;AAAA,QACP,SAAS,OAAO;AACd,kBAAQ,MAAM,+BAA+B,KAAK;AAAA,QACpD;AAAA,MACF;AAAA,IACF;AAEA,QAAI,KAAK,MAAM,OAAO,GAAG;AACvB,WAAK,cAAA;AAAA,IACP;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,OAAc,gBAAsB;AAClC,QAAI,cAAa,UAAU;AACzB,UAAI,cAAa,SAAS,cAAc,MAAM;AAC5C,qBAAa,cAAa,SAAS,SAAS;AAAA,MAC9C;AACA,oBAAa,WAAW;AAAA,IAC1B;AAAA,EACF;AACF;AA/FE,cAAe,WAAgC;AAD1C,IAAM,eAAN;;"}