feat(scheduler): persist recurring daily starts

Add a local-calendar daily start scheduler with pending receipts, per-day deduplication, DST-safe target calculation, missed-day recovery, and retryable account/start failure outcomes.

Persist and validate the daily rule, expose its next target to the renderer, preserve legacy one-time schedules until a daily rule is saved, and gate boot auto-resume on recorded active-run evidence.

Wire boot, settings, account, suspend, resume, interval, and shutdown lifecycle handling with focused RED/GREEN coverage for calendar, persistence, renderer, and controller boundaries.
This commit is contained in:
Sucukdeluxe
2026-08-22 09:36:45 +02:00
parent d7384c34d1
commit 4eb95c92b9
14 changed files with 843 additions and 71 deletions
+9 -1
View File
@@ -3,6 +3,7 @@ import { getMegaDebridAccountsForMode, getMegaDebridDisabledAccountIdsForMode }
import { getRealDebridAccounts } from "../shared/real-debrid-accounts";
import type { AppSettings, DebridAccountStatus, DebridProvider, RendererAccount, RendererAccountKind, RendererSettings } from "../shared/types";
import { collectAccountStatusRedactionValues, sanitizeDebridAccountStatus } from "./account-status-sanitizer";
import { nextDailyStartEpochMs } from "./daily-start-scheduler";
function maskValue(value: string, keepStart = 3, keepEnd = 3): string {
const trimmed = value.trim();
@@ -251,7 +252,14 @@ export function createRendererSettings(settings: AppSettings): RendererSettings
megaDebridAccountTotalUsageBytes: { ...settings.megaDebridAccountTotalUsageBytes },
debridAccountStatuses: Object.fromEntries(Object.entries(settings.debridAccountStatuses).map(([id, status]) => [id, safeStatus(status, redactions)])),
providerDailyUsageDay: settings.providerDailyUsageDay,
scheduledStartEpochMs: settings.scheduledStartEpochMs
dailyStartEnabled: settings.dailyStartEnabled,
dailyStartMinuteOfDay: settings.dailyStartMinuteOfDay,
dailyStartFirstLocalDate: settings.dailyStartFirstLocalDate,
dailyStartLastHandledLocalDate: settings.dailyStartLastHandledLocalDate,
dailyStartPendingLocalDate: settings.dailyStartPendingLocalDate,
dailyStartLastOutcome: settings.dailyStartLastOutcome,
scheduledStartEpochMs: settings.scheduledStartEpochMs,
nextDailyStartEpochMs: nextDailyStartEpochMs(settings)
} as RendererSettings;
}