{"version":3,"file":"valueHistory.mjs","names":[],"sources":["../../src/tools/valueHistory.ts"],"sourcesContent":["import { ONE_MINUTE, addDuration, relativeNow } from '@openobserve/js-core/time'\nimport type { Duration, RelativeTime } from '@openobserve/js-core/time'\nimport { setInterval, clearInterval } from './timer'\nimport type { TimeoutId } from './timer'\nimport { removeItem } from './utils/arrayUtils'\n\nconst END_OF_TIMES = Infinity as RelativeTime\n\nexport interface ValueHistoryEntry<T> {\n  startTime: RelativeTime\n  endTime: RelativeTime\n  value: T\n  remove(): void\n  close(endTime: RelativeTime): void\n}\n\nexport const CLEAR_OLD_VALUES_INTERVAL = ONE_MINUTE\n\n/**\n * Store and keep track of values spans. This whole cache assumes that values are added in\n * chronological order (i.e. all entries have an increasing start time).\n */\nexport interface ValueHistory<Value> {\n  add: (value: Value, startTime: RelativeTime) => ValueHistoryEntry<Value>\n  find: (startTime?: RelativeTime, options?: { returnInactive: boolean }) => Value | undefined\n\n  closeActive: (endTime: RelativeTime) => void\n  findAll: (startTime?: RelativeTime, duration?: Duration) => Value[]\n  findAllEntries: (startTime?: RelativeTime, duration?: Duration) => Array<ValueHistoryEntry<Value>>\n  getEntries: (startTime: RelativeTime) => Array<ValueHistoryEntry<Value>>\n  reset: () => void\n  stop: () => void\n}\n\nlet cleanupHistoriesInterval: TimeoutId | undefined\n\nconst cleanupTasks: Set<() => void> = new Set()\n\nfunction cleanupHistories() {\n  cleanupTasks.forEach((task) => task())\n}\n\nexport function createValueHistory<Value>({\n  expireDelay,\n  maxEntries,\n}: {\n  expireDelay: number\n  maxEntries?: number\n}): ValueHistory<Value> {\n  let entries: Array<ValueHistoryEntry<Value>> = []\n\n  if (!cleanupHistoriesInterval) {\n    cleanupHistoriesInterval = setInterval(() => cleanupHistories(), CLEAR_OLD_VALUES_INTERVAL)\n  }\n\n  const clearExpiredValues = () => {\n    const oldTimeThreshold = relativeNow() - expireDelay\n    while (entries.length > 0 && entries[entries.length - 1].endTime < oldTimeThreshold) {\n      entries.pop()\n    }\n  }\n\n  cleanupTasks.add(clearExpiredValues)\n\n  /**\n   * Add a value to the history associated with a start time. Returns a reference to this newly\n   * added entry that can be removed or closed.\n   */\n  function add(value: Value, startTime: RelativeTime): ValueHistoryEntry<Value> {\n    const entry: ValueHistoryEntry<Value> = {\n      value,\n      startTime,\n      endTime: END_OF_TIMES,\n      remove: () => {\n        removeItem(entries, entry)\n      },\n      close: (endTime: RelativeTime) => {\n        entry.endTime = endTime\n      },\n    }\n\n    if (maxEntries && entries.length >= maxEntries) {\n      entries.pop()\n    }\n\n    entries.unshift(entry)\n\n    return entry\n  }\n\n  /**\n   * Return the latest value that was active during `startTime`, or the currently active value\n   * if no `startTime` is provided. This method assumes that entries are not overlapping.\n   *\n   * If `option.returnInactive` is true, returns the value at `startTime` (active or not).\n   */\n  function find(\n    startTime: RelativeTime = END_OF_TIMES,\n    options: { returnInactive: boolean } = { returnInactive: false }\n  ): Value | undefined {\n    for (const entry of entries) {\n      if (entry.startTime <= startTime) {\n        if (options.returnInactive || startTime <= entry.endTime) {\n          return entry.value\n        }\n        break\n      }\n    }\n  }\n\n  /**\n   * Helper function to close the currently active value, if any. This method assumes that entries\n   * are not overlapping.\n   */\n  function closeActive(endTime: RelativeTime) {\n    const latestEntry = entries[0]\n    if (latestEntry?.endTime === END_OF_TIMES) {\n      latestEntry.close(endTime)\n    }\n  }\n\n  /**\n   * Return all values with an active period overlapping with the duration,\n   * or all values that were active during `startTime` if no duration is provided,\n   * or all currently active values if no `startTime` is provided.\n   */\n  function findAll(startTime: RelativeTime = END_OF_TIMES, duration = 0 as Duration): Value[] {\n    const endTime = addDuration(startTime, duration)\n    return entries\n      .filter((entry) => entry.startTime <= endTime && startTime <= entry.endTime)\n      .map((entry) => entry.value)\n  }\n\n  /**\n   * Return all entries with an active period overlapping with the duration,\n   * or all entries that were active during `startTime` if no duration is provided,\n   * or all currently active entries if no `startTime` is provided.\n   */\n  function findAllEntries(\n    startTime: RelativeTime = END_OF_TIMES,\n    duration = 0 as Duration\n  ): Array<ValueHistoryEntry<Value>> {\n    const endTime = addDuration(startTime, duration)\n    return entries.filter((entry) => entry.startTime <= endTime && startTime <= entry.endTime)\n  }\n\n  /**\n   * Return all the entries whose start time is equal to the given startTime.\n   */\n  function getEntries(startTime: RelativeTime): Array<ValueHistoryEntry<Value>> {\n    return entries.filter((entry) => entry.startTime === startTime)\n  }\n\n  /**\n   * Remove all entries from this collection.\n   */\n  function reset() {\n    entries = []\n  }\n\n  /**\n   * Stop internal garbage collection of past entries.\n   */\n  function stop() {\n    cleanupTasks.delete(clearExpiredValues)\n    if (cleanupTasks.size === 0 && cleanupHistoriesInterval) {\n      clearInterval(cleanupHistoriesInterval)\n      cleanupHistoriesInterval = undefined\n    }\n  }\n\n  return { add, find, closeActive, findAll, findAllEntries, getEntries, reset, stop }\n}\n\n/**\n * Reset all global state. This is useful for testing to ensure clean state between tests.\n *\n * @internal\n */\nexport function resetValueHistoryGlobals() {\n  cleanupTasks.clear()\n  clearInterval(cleanupHistoriesInterval)\n  cleanupHistoriesInterval = undefined\n}\n"],"mappings":";;;;AAMA,MAAM,eAAe;AAUrB,MAAa,4BAA4B;AAkBzC,IAAI;AAEJ,MAAM,+BAAgC,IAAI,IAAI;AAE9C,SAAS,mBAAmB;CAC1B,aAAa,SAAS,SAAS,KAAK,CAAC;AACvC;AAEA,SAAgB,mBAA0B,EACxC,aACA,cAIsB;CACtB,IAAI,UAA2C,CAAC;CAEhD,IAAI,CAAC,0BACH,2BAA2B,kBAAkB,iBAAiB,GAAG,yBAAyB;CAG5F,MAAM,2BAA2B;EAC/B,MAAM,mBAAmB,YAAY,IAAI;EACzC,OAAO,QAAQ,SAAS,KAAK,QAAQ,QAAQ,SAAS,EAAE,CAAC,UAAU,kBACjE,QAAQ,IAAI;CAEhB;CAEA,aAAa,IAAI,kBAAkB;;;;;CAMnC,SAAS,IAAI,OAAc,WAAmD;EAC5E,MAAM,QAAkC;GACtC;GACA;GACA,SAAS;GACT,cAAc;IACZ,WAAW,SAAS,KAAK;GAC3B;GACA,QAAQ,YAA0B;IAChC,MAAM,UAAU;GAClB;EACF;EAEA,IAAI,cAAc,QAAQ,UAAU,YAClC,QAAQ,IAAI;EAGd,QAAQ,QAAQ,KAAK;EAErB,OAAO;CACT;;;;;;;CAQA,SAAS,KACP,YAA0B,cAC1B,UAAuC,EAAE,gBAAgB,MAAM,GAC5C;EACnB,KAAK,MAAM,SAAS,SAClB,IAAI,MAAM,aAAa,WAAW;GAChC,IAAI,QAAQ,kBAAkB,aAAa,MAAM,SAC/C,OAAO,MAAM;GAEf;EACF;CAEJ;;;;;CAMA,SAAS,YAAY,SAAuB;EAC1C,MAAM,cAAc,QAAQ;EAC5B,IAAI,aAAa,YAAY,cAC3B,YAAY,MAAM,OAAO;CAE7B;;;;;;CAOA,SAAS,QAAQ,YAA0B,cAAc,WAAW,GAAwB;EAC1F,MAAM,UAAU,YAAY,WAAW,QAAQ;EAC/C,OAAO,QACJ,QAAQ,UAAU,MAAM,aAAa,WAAW,aAAa,MAAM,OAAO,CAAC,CAC3E,KAAK,UAAU,MAAM,KAAK;CAC/B;;;;;;CAOA,SAAS,eACP,YAA0B,cAC1B,WAAW,GACsB;EACjC,MAAM,UAAU,YAAY,WAAW,QAAQ;EAC/C,OAAO,QAAQ,QAAQ,UAAU,MAAM,aAAa,WAAW,aAAa,MAAM,OAAO;CAC3F;;;;CAKA,SAAS,WAAW,WAA0D;EAC5E,OAAO,QAAQ,QAAQ,UAAU,MAAM,cAAc,SAAS;CAChE;;;;CAKA,SAAS,QAAQ;EACf,UAAU,CAAC;CACb;;;;CAKA,SAAS,OAAO;EACd,aAAa,OAAO,kBAAkB;EACtC,IAAI,aAAa,SAAS,KAAK,0BAA0B;GACvD,cAAc,wBAAwB;GACtC,2BAA2B,KAAA;EAC7B;CACF;CAEA,OAAO;EAAE;EAAK;EAAM;EAAa;EAAS;EAAgB;EAAY;EAAO;CAAK;AACpF"}