{
  "version": 3,
  "sources": ["../src/main.ts"],
  "sourcesContent": ["import { localJsonStorage } from '@alwatr/local-storage';\nimport { createLogger } from '@alwatr/logger';\nimport { packageTracer } from '@alwatr/package-tracer';\nimport { parseDuration, type Duration } from '@alwatr/parse-duration';\n\nimport type { Task, TaskState, TaskOptions } from './types.js';\n\n__dev_mode__: packageTracer.add(__package_name__, __package_version__);\n\nconst logger = createLogger(__package_name__);\n\nexport type { Task, TaskState, TaskOptions } from './types.js';\n\nconst RETRY_DELAY_MS = 500;\n\n/**\n * Manages scheduled tasks with persistence and conditional execution\n */\nexport class TaskScheduler {\n  private tasks_ = new Map<string, Task>();\n  private timeouts_ = new Map<string, number>();\n  private storageKey_ = 'task-scheduler';\n  private storageVersion_ = 2;\n\n  /**\n   * Adds a new scheduled task\n   * @param id - Unique task identifier\n   * @param fn - Function to execute\n   * @param interval - Execution interval (e.g., '5m', '1h')\n   * @param options - Additional task options\n   */\n  addTask(id: string, fn: () => Promise<void> | void, interval: Duration, options?: TaskOptions): void {\n    logger.logMethodArgs?.('addTask', { id, interval });\n\n    const now = Date.now();\n    const state = this.getTaskState_(id);\n    const parsedInterval = parseDuration(interval);\n    if (parsedInterval <= 0) {\n      logger.error('addTask', 'invalid_interval', { id, interval });\n      return;\n    }\n\n    const lastRun = state?.lastRun ?? 0;\n    let nextRun: number;\n\n    if (state === null) {\n      // First time ever: run after the initial interval.\n      nextRun = now + parsedInterval;\n    }\n    else if (lastRun === 0) {\n      // First time after adding: run immediately.\n      nextRun = now;\n    }\n    else {\n      // Check if it's time to run (interval has passed since last run)\n      const timeSinceLastRun = now - lastRun;\n      if (timeSinceLastRun >= parsedInterval) {\n        // It's overdue - run immediately (no matter how much time has passed)\n        nextRun = now;\n      }\n      else {\n        // Schedule for the next regular time\n        nextRun = lastRun + parsedInterval;\n      }\n    }\n\n    const task: Task = {\n      id,\n      fn,\n      interval: parsedInterval,\n      lastRun,\n      nextRun,\n      shouldRun: options?.shouldRun,\n    };\n\n    this.tasks_.set(id, task);\n    this.scheduleNextRun_(task);\n    this.saveState_();\n  }\n\n  /**\n   * Updates the last run timestamp for a task (useful for external trigger tasks)\n   * @param id - Task identifier\n   * @param timestamp - New last run timestamp (defaults to now)\n   */\n  updateLastRun(id: string, timestamp = Date.now()): void {\n    logger.logMethodArgs?.('updateLastRun', { id, timestamp });\n\n    const task = this.tasks_.get(id);\n    if (!task) return;\n\n    task.lastRun = timestamp;\n    task.nextRun = timestamp + task.interval;\n    this.saveState_();\n\n    // Reschedule to respect new timing\n    this.scheduleNextRun_(task);\n  }\n\n  /**\n   * Removes a task from the scheduler\n   * @param id - Task identifier to remove\n   */\n  removeTask(id: string): void {\n    logger.logMethodArgs?.('removeTask', { id });\n    const timeoutId = this.timeouts_.get(id);\n    if (timeoutId) {\n      clearTimeout(timeoutId);\n      this.timeouts_.delete(id);\n    }\n    this.tasks_.delete(id);\n    this.removeTaskFromStorage_(id);\n  }\n\n  /**\n   * Sets up interval-based scheduling for a task\n   * @param task - Task to schedule\n   */\n  private scheduleNextRun_(task: Task): void {\n    const now = Date.now();\n    const delay = Math.max(0, task.nextRun - now);\n\n    logger.logMethodArgs?.('scheduleNextRun_', { id: task.id, nextRun: new Date(task.nextRun).toISOString(), delay });\n\n    const existingTimeout = this.timeouts_.get(task.id);\n    if (existingTimeout) {\n      clearTimeout(existingTimeout);\n    }\n\n    const timeoutId = setTimeout(() => {\n      this.tryExecuteTask_(task);\n    }, delay);\n\n    this.timeouts_.set(task.id, timeoutId);\n  }\n\n  /**\n   * Attempts to execute a task if conditions are met\n   * @param task - Task to try executing\n   */\n  private async tryExecuteTask_(task: Task): Promise<void> {\n    // timeout fired, so delete it\n    this.timeouts_.delete(task.id);\n\n    // Check condition first\n    if (task.shouldRun && !task.shouldRun()) {\n      logger.logOther?.('tryExecuteTask_', `Condition not met for task '${task.id}'. Retrying in ${RETRY_DELAY_MS}ms...`);\n      // Condition failed. Reschedule a check for the near future without changing the official `nextRun`.\n      const retryTimeoutId = setTimeout(() => this.tryExecuteTask_(task), RETRY_DELAY_MS);\n      this.timeouts_.set(task.id, retryTimeoutId);\n      return;\n    }\n\n    logger.logMethodArgs?.('tryExecuteTask_', { id: task.id, nextRun: new Date(task.nextRun).toISOString() });\n    await this.executeTask_(task);\n  }\n\n  /**\n   * Executes a task and updates its state\n   * @param task - Task to execute\n   */\n  private async executeTask_(task: Task): Promise<void> {\n    logger.logMethodArgs?.('executeTask_', { id: task.id });\n\n    try {\n      await task.fn();\n\n      // SUCCESS! Update state and schedule the real next run.\n      const now = Date.now();\n      task.lastRun = now;\n      // Calculate next run based on the *previous schedule* to prevent time drift.\n      task.nextRun = task.nextRun + task.interval;\n\n      this.scheduleNextRun_(task);\n      this.saveState_(); // Persist only on successful run.\n    }\n    catch (error) {\n      logger.error('executeTask_', `Task '${task.id}' failed. It will be retried at the next scheduled interval.`, error);\n      // On failure, we don't update timestamps, but we must calculate the next run time to avoid a tight loop.\n      task.nextRun = task.nextRun + task.interval;\n\n      this.scheduleNextRun_(task);\n    }\n  }\n\n  /**\n   * Persists current task states to localStorage\n   */\n  private saveState_(): void {\n    logger.logMethod?.('saveState_');\n\n    // Get existing states from storage\n    const { states: existingStates } = localJsonStorage.getItem<{ states: TaskState[] }>(\n      this.storageKey_,\n      { states: [] },\n      this.storageVersion_,\n    );\n\n    // Create a map for easier lookup and updates\n    const statesMap = new Map<string, TaskState>();\n\n    // Add existing states first\n    existingStates.forEach((state) => {\n      statesMap.set(state.id, state);\n    });\n\n    // Update/add current task states\n    Array.from(this.tasks_.values()).forEach((task) => {\n      statesMap.set(task.id, {\n        id: task.id,\n        lastRun: task.lastRun,\n      });\n    });\n\n    const states: TaskState[] = Array.from(statesMap.values());\n    localJsonStorage.setItem<{ states: TaskState[] }>(this.storageKey_, { states }, this.storageVersion_);\n  }\n\n  /**\n   * Removes a specific task from localStorage\n   * @param id - Task identifier to remove\n   */\n  private removeTaskFromStorage_(id: string): void {\n    logger.logMethodArgs?.('removeTaskFromStorage_', { id });\n\n    const { states } = localJsonStorage.getItem<{ states: TaskState[] }>(this.storageKey_, { states: [] }, this.storageVersion_);\n    const filteredStates = states.filter((state) => state.id !== id);\n    localJsonStorage.setItem<{ states: TaskState[] }>(this.storageKey_, { states: filteredStates }, this.storageVersion_);\n  }\n\n  /**\n   * Retrieves stored state for a specific task\n   * @param id - Task identifier\n   * @returns Task state or null if not found\n   */\n  private getTaskState_(id: string): TaskState | null {\n    logger.logMethodArgs?.('getTaskState_', { id });\n\n    const { states } = localJsonStorage.getItem<{ states: TaskState[] }>(this.storageKey_, { states: [] }, this.storageVersion_);\n    return states.find((state) => state.id === id) ?? null;\n  }\n}\n\n/**\n * Singleton instance for global task scheduling\n */\nexport const taskScheduler = new TaskScheduler();\n"],
  "mappings": "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",
  "names": []
}
