fix: harden account rotation and active download recovery
Apply account enablement changes optimistically and persist rapid toggles sequentially without losing clicks. Refresh Mega-Debrid API and Web account pools during active downloads, isolate per-account cancellation budgets, rotate within the same conversion attempt, and keep pause, stop, resume, reset, and no-account gates consistent. Use the native Electron clipboard under Remote Desktop and make support bundle export bounded, redacted, responsive, guarded, visible, and atomic. Add end-to-end regressions for live account switching, persisted partial recovery, support export, native copy, availability preservation, and the 500 ms telemetry cadence.
This commit is contained in:
+27
-16
@@ -21,6 +21,7 @@ import { createRendererSettings } from "./renderer-state";
|
||||
import { validateRendererSettingsUpdate } from "./renderer-settings";
|
||||
import { applyMainWindowSecurity, createMainWindowWebPreferences, MAIN_WINDOW_EXTERNAL_HOSTS, openAllowedExternalUrl } from "./browser-security";
|
||||
import { assertTrustedIpcSender, type TrustedIpcOptions } from "./ipc-security";
|
||||
import { createSupportBundleExportRunner, writeSupportBundleAtomically } from "./support-bundle";
|
||||
|
||||
function validateString(value: unknown, name: string): string {
|
||||
if (typeof value !== "string") {
|
||||
@@ -604,13 +605,20 @@ function registerIpcHandlers(): void {
|
||||
}
|
||||
return controller.importQueue(json);
|
||||
});
|
||||
handleTrusted(IPC_CHANNELS.TOGGLE_CLIPBOARD, () => {
|
||||
handleTrusted(IPC_CHANNELS.TOGGLE_CLIPBOARD, () => {
|
||||
const settings = controller.getSettings();
|
||||
const next = !settings.clipboardWatch;
|
||||
controller.updateSettings({ clipboardWatch: next });
|
||||
updateClipboardWatcher();
|
||||
return next;
|
||||
});
|
||||
return next;
|
||||
});
|
||||
handleTrusted(IPC_CHANNELS.WRITE_CLIPBOARD_TEXT, (_event: IpcMainInvokeEvent, text: unknown) => {
|
||||
if (typeof text !== "string" || text.length > 16 * 1024 * 1024) {
|
||||
throw new Error("Ungültiger Zwischenablageinhalt");
|
||||
}
|
||||
clipboard.writeText(text);
|
||||
return true;
|
||||
});
|
||||
handleTrusted(IPC_CHANNELS.PICK_FOLDER, async () => {
|
||||
const options = {
|
||||
properties: ["openDirectory", "createDirectory"] as Array<"openDirectory" | "createDirectory">
|
||||
@@ -667,19 +675,22 @@ function registerIpcHandlers(): void {
|
||||
return controller.importOnlineBackup(key);
|
||||
});
|
||||
|
||||
handleTrusted(IPC_CHANNELS.EXPORT_SUPPORT_BUNDLE, async () => {
|
||||
const options = {
|
||||
defaultPath: controller.getSupportBundleDefaultFileName(),
|
||||
filters: [{ name: "Support Bundle", extensions: ["zip"] }]
|
||||
};
|
||||
const result = mainWindow ? await dialog.showSaveDialog(mainWindow, options) : await dialog.showSaveDialog(options);
|
||||
if (result.canceled || !result.filePath) {
|
||||
return { saved: false };
|
||||
}
|
||||
const exported = await controller.exportSupportBundle();
|
||||
await fs.promises.writeFile(result.filePath, exported.buffer);
|
||||
return { saved: true, filePath: result.filePath };
|
||||
});
|
||||
const runSupportBundleExport = createSupportBundleExportRunner({
|
||||
chooseFile: async () => {
|
||||
const options = {
|
||||
defaultPath: controller.getSupportBundleDefaultFileName(),
|
||||
filters: [{ name: "Support Bundle", extensions: ["zip"] }]
|
||||
};
|
||||
const result = mainWindow ? await dialog.showSaveDialog(mainWindow, options) : await dialog.showSaveDialog(options);
|
||||
return result.canceled || !result.filePath ? null : result.filePath;
|
||||
},
|
||||
build: async () => (await controller.exportSupportBundle()).buffer,
|
||||
write: writeSupportBundleAtomically,
|
||||
onSuccess: ({ filePath, bytes }) => controller.recordSupportBundleExported(filePath, bytes),
|
||||
onFailure: (error) => controller.recordSupportBundleExportFailed(error)
|
||||
});
|
||||
|
||||
handleTrusted(IPC_CHANNELS.EXPORT_SUPPORT_BUNDLE, () => runSupportBundleExport());
|
||||
|
||||
handleTrusted(IPC_CHANNELS.OPEN_LOG, async () => {
|
||||
const logPath = getLogFilePath();
|
||||
|
||||
Reference in New Issue
Block a user