Complete provider waits and lifecycle visibility

Release aborted Real-Debrid, AllDebrid, and BestDebrid web callers even when underlying requests ignore cancellation while retaining terminal rejection observers. Publish provider cooldown deadlines and emit a fresh idle snapshot at the earliest expiry. Abort and visibly drain post-processing before dispatching one pending restart. Surface lifecycle phase, reason, retry countdown, and remaining work in the download controls. Add focused regressions for provider abort races, cooldown expiry, post-processing drain, pending start visibility, and the updated rapid stop contract.
This commit is contained in:
Sucukdeluxe
2026-08-22 10:39:07 +02:00
parent 1f97ce8b42
commit ad29239661
13 changed files with 595 additions and 82 deletions
+22
View File
@@ -191,6 +191,28 @@ describe("realdebrid-web", () => {
expect(mockBrowserWindowCtor).not.toHaveBeenCalled();
});
it("releases an aborted caller while the active web request ignores its signal", async () => {
let rejectRequest!: (error: Error) => void;
mockSessionFetch.mockReturnValue(new Promise<Response>((_resolve, reject) => {
rejectRequest = reject;
}));
const fallback = new RealDebridWebFallback("persist:realdebrid-web-rdw_abort_race", () => true);
const controller = new AbortController();
const running = fallback.unrestrict("https://rapidgator.net/file/abort-race", controller.signal)
.then(() => "resolved" as const, (error) => String(error));
await vi.waitFor(() => expect(mockSessionFetch).toHaveBeenCalledTimes(1));
controller.abort("test-stop");
const outcome = await Promise.race([
running,
new Promise<"timeout">((resolve) => setTimeout(() => resolve("timeout"), 200))
]);
expect(outcome).toContain("aborted:realdebrid-web");
rejectRequest(new Error("late realdebrid rejection"));
await Promise.resolve();
});
it("does not open a login window for an authenticated account with a fair-use error", async () => {
mockSessionFetch.mockResolvedValue(new Response("<input name=\"private_token\" value=\"session-token\">", { status: 200 }));
vi.stubGlobal("fetch", vi.fn().mockImplementation(async () => new Response(JSON.stringify({