feat: add Deepbrid, daily scheduling, and notification center

Add encrypted Deepbrid API accounts with account validation, provider routing, fallback, usage tracking, safe error handling, and verified 1Fichier downloads. Restore persistent recurring daily starts with local-calendar deduplication and legacy schedule compatibility. Add durable Discord package, run, remaining-volume, stall, and recovery notifications with privacy-safe telemetry and disk-failure recovery.
This commit is contained in:
Sucukdeluxe
2026-08-24 07:37:55 +02:00
parent 06e5bf4340
commit 1b7caba2eb
83 changed files with 12769 additions and 1098 deletions
+127
View File
@@ -0,0 +1,127 @@
import { describe, expect, it, vi } from "vitest";
import type { RendererSettings, UiSnapshot } from "../src/shared/types";
import {
activateDailyScheduleSettings,
buildScheduleCancellationSettingsUpdate,
buildDailyScheduleSettingsUpdate,
persistDailyScheduleSettingsUpdate,
resolveDailyScheduleInitialTime
} from "../src/renderer/App";
describe("daily schedule settings form", () => {
it("maps local time and the chosen start day to the recurring schedule settings", () => {
const now = new Date(2026, 7, 22, 18, 30, 0, 0);
expect(buildDailyScheduleSettingsUpdate("08:15", "today", now)).toEqual({
dailyStartEnabled: true,
dailyStartMinuteOfDay: 8 * 60 + 15,
dailyStartFirstLocalDate: "2026-08-22"
});
expect(buildDailyScheduleSettingsUpdate("23:45", "tomorrow", now)).toEqual({
dailyStartEnabled: true,
dailyStartMinuteOfDay: 23 * 60 + 45,
dailyStartFirstLocalDate: "2026-08-23"
});
});
it("prefills a previously saved disabled rule and uses local time only for the empty default", () => {
const now = new Date(2026, 7, 22, 18, 30, 0, 0);
const disabledSavedRule = {
dailyStartEnabled: false,
dailyStartMinuteOfDay: 8 * 60 + 15,
dailyStartFirstLocalDate: "2026-08-21"
};
expect(resolveDailyScheduleInitialTime(disabledSavedRule, now)).toBe("08:15");
expect(resolveDailyScheduleInitialTime({
dailyStartMinuteOfDay: 0,
dailyStartFirstLocalDate: ""
}, now)).toBe("18:30");
});
it.each(["", "8:15", "24:00", "12:60"])("reports the invalid time %j when activation is invoked directly", async (time) => {
const persist = vi.fn();
const showError = vi.fn();
await expect(activateDailyScheduleSettings(
time,
"today",
persist,
showError,
new Date(2026, 7, 22, 18, 30, 0, 0)
)).resolves.toBe(false);
expect(showError).toHaveBeenCalledWith("Bitte eine gültige Startzeit auswählen.");
expect(persist).not.toHaveBeenCalled();
});
it("applies persisted settings after a successful activation", async () => {
const persisted = { dailyStartEnabled: true } as RendererSettings;
const updateSettings = vi.fn().mockResolvedValue(persisted);
const applySettings = vi.fn();
const getSnapshot = vi.fn();
const applySnapshot = vi.fn();
const showError = vi.fn();
const update = {
dailyStartEnabled: true,
dailyStartMinuteOfDay: 495,
dailyStartFirstLocalDate: "2026-08-23"
};
await expect(persistDailyScheduleSettingsUpdate(update, "activate", {
updateSettings,
getSnapshot,
applySettings,
applySnapshot,
showError
})).resolves.toBe(true);
expect(updateSettings).toHaveBeenCalledWith(update);
expect(applySettings).toHaveBeenCalledWith(persisted);
expect(getSnapshot).not.toHaveBeenCalled();
expect(showError).not.toHaveBeenCalled();
});
it("cancels the active schedule through its owning settings field", () => {
expect(buildScheduleCancellationSettingsUpdate({
dailyStartEnabled: true,
scheduledStartEpochMs: 1_800_000_000_000
})).toEqual({ dailyStartEnabled: false });
expect(buildScheduleCancellationSettingsUpdate({
dailyStartEnabled: false,
scheduledStartEpochMs: 1_800_000_000_000
})).toEqual({ scheduledStartEpochMs: 0 });
});
it.each([
["activate" as const, "Zeitplan konnte nicht aktiviert werden: Error: Speichern fehlgeschlagen"],
["cancel" as const, "Zeitplan konnte nicht abgebrochen werden: Error: Speichern fehlgeschlagen"]
])("shows %s failures before reconciling the authoritative snapshot", async (operation, expectedMessage) => {
const authoritative = { settings: { dailyStartEnabled: false } } as UiSnapshot;
const sequence: string[] = [];
const updateSettings = vi.fn().mockRejectedValue(new Error("Speichern fehlgeschlagen"));
const getSnapshot = vi.fn(async () => {
sequence.push("snapshot");
return authoritative;
});
const applySnapshot = vi.fn((snapshot: UiSnapshot) => {
sequence.push(`apply:${String(snapshot.settings.dailyStartEnabled)}`);
});
const showError = vi.fn((message: string) => {
sequence.push(`error:${message}`);
});
await expect(persistDailyScheduleSettingsUpdate({ dailyStartEnabled: false }, operation, {
updateSettings,
getSnapshot,
applySettings: vi.fn(),
applySnapshot,
showError
})).resolves.toBe(false);
expect(showError).toHaveBeenCalledWith(expectedMessage);
expect(getSnapshot).toHaveBeenCalledTimes(1);
expect(applySnapshot).toHaveBeenCalledWith(authoritative);
expect(sequence).toEqual([`error:${expectedMessage}`, "snapshot", "apply:false"]);
});
});