{"version":3,"sources":["../../../src/utils/runOnce.ts"],"sourcesContent":["import { mkdir, stat, unlink, writeFile } from 'fs/promises';\nimport { dirname } from 'path';\n\n/**\n * Ensures a callback function runs only once within a specified time window across multiple processes.\n * Uses a sentinel file to coordinate execution and prevent duplicate work.\n *\n * @param sentinelFilePath - Path to the sentinel file used for coordination\n * @param callback - The function to execute (should be async)\n * @param cacheTimeoutMs - Time window in milliseconds during which the sentinel is considered valid (default: 60000ms = 1 minute)\n *\n * @example\n * ```typescript\n * await runPrepareIntlayerOnce(\n *   '/tmp/intlayer-sentinel',\n *   async () => {\n *     // Your initialization logic here\n *     await prepareIntlayer();\n *   },\n *   30 * 1000 // 30 seconds cache\n * );\n * ```\n *\n * @throws {Error} When there are unexpected filesystem errors\n */\nexport const runOnce = async (\n  sentinelFilePath: string,\n  callback: () => void | Promise<void>,\n  cacheTimeoutMs: number = 60 * 1000 // 1 minute in milliseconds\n) => {\n  const currentTimestamp = Date.now();\n  const timeoutDuration = cacheTimeoutMs;\n\n  try {\n    // Check if sentinel file exists and get its stats\n    const sentinelStats = await stat(sentinelFilePath);\n    const sentinelAge = currentTimestamp - sentinelStats.mtime.getTime();\n\n    // If sentinel is older than the timeout, delete it and rebuild\n    if (sentinelAge > timeoutDuration) {\n      await unlink(sentinelFilePath);\n      // Fall through to create new sentinel and rebuild\n    } else {\n      // Sentinel is recent, no need to rebuild\n      return;\n    }\n  } catch (err: any) {\n    if (err.code === 'ENOENT') {\n      // File doesn't exist, continue to create it\n    } else {\n      throw err; // unexpected FS error\n    }\n  }\n\n  try {\n    // Ensure the directory exists before writing the file\n    await mkdir(dirname(sentinelFilePath), { recursive: true });\n\n    // O_EXCL ensures only the *first* process can create the file\n    await writeFile(sentinelFilePath, String(currentTimestamp), { flag: 'wx' });\n  } catch (err: any) {\n    if (err.code === 'EEXIST') {\n      // Another process already created it → we're done\n      return;\n    }\n    throw err; // unexpected FS error\n  }\n\n  await callback();\n};\n"],"mappings":"AAAA,SAAS,OAAO,MAAM,QAAQ,iBAAiB;AAC/C,SAAS,eAAe;AAwBjB,MAAM,UAAU,OACrB,kBACA,UACA,iBAAyB,KAAK,QAC3B;AACH,QAAM,mBAAmB,KAAK,IAAI;AAClC,QAAM,kBAAkB;AAExB,MAAI;AAEF,UAAM,gBAAgB,MAAM,KAAK,gBAAgB;AACjD,UAAM,cAAc,mBAAmB,cAAc,MAAM,QAAQ;AAGnE,QAAI,cAAc,iBAAiB;AACjC,YAAM,OAAO,gBAAgB;AAAA,IAE/B,OAAO;AAEL;AAAA,IACF;AAAA,EACF,SAAS,KAAU;AACjB,QAAI,IAAI,SAAS,UAAU;AAAA,IAE3B,OAAO;AACL,YAAM;AAAA,IACR;AAAA,EACF;AAEA,MAAI;AAEF,UAAM,MAAM,QAAQ,gBAAgB,GAAG,EAAE,WAAW,KAAK,CAAC;AAG1D,UAAM,UAAU,kBAAkB,OAAO,gBAAgB,GAAG,EAAE,MAAM,KAAK,CAAC;AAAA,EAC5E,SAAS,KAAU;AACjB,QAAI,IAAI,SAAS,UAAU;AAEzB;AAAA,IACF;AACA,UAAM;AAAA,EACR;AAEA,QAAM,SAAS;AACjB;","names":[]}