fix(replay): recover failed archives and release deleted sessions

This commit is contained in:
DCCONSTRUCTIONS
2026-07-29 01:55:23 +03:00
parent 2a97cf28c0
commit 1eba7c82ba
8 changed files with 217 additions and 7 deletions
@@ -17,6 +17,7 @@ let ObservationSessionApiError;
let ObservationSessionContractError;
let decodeObservationRecordedMediaManifest;
let createObservationReplayCoordinator;
let deleteObservationSessionAfterTeardown;
let resolveObservationSessionReplay;
let waitForObservationReplayPreparation;
let storeObservationReplayPreparation;
@@ -45,6 +46,7 @@ before(async () => {
} = await server.ssrLoadModule("/src/core/observation/sessionArchive.ts"));
({
createObservationReplayCoordinator,
deleteObservationSessionAfterTeardown,
resolveObservationSessionReplay,
waitForObservationReplayPreparation,
storeObservationReplayPreparation,
@@ -437,6 +439,56 @@ test("delete API uses one opaque same-origin target and requires an empty 204",
);
});
test("session deletion releases the selected presentation before the DELETE request", async () => {
const events = [];
await deleteObservationSessionAfterTeardown("session-20260716T205632Z", {
onDeleteBegin: async (sessionId) => {
events.push(`release:${sessionId}`);
},
deleteSession: async (sessionId) => {
events.push(`delete:${sessionId}`);
},
});
assert.deepEqual(events, [
"release:session-20260716T205632Z",
"delete:session-20260716T205632Z",
]);
let deleteCalled = false;
await assert.rejects(
deleteObservationSessionAfterTeardown("session-20260716T205632Z", {
onDeleteBegin: async () => {
throw new Error("viewer teardown failed");
},
deleteSession: async () => {
deleteCalled = true;
},
}),
/viewer teardown failed/,
);
assert.equal(deleteCalled, false);
});
test("App atomically clears the selected Rerun source before deleting its session", async () => {
const appSource = await readFile(new URL("../src/App.tsx", import.meta.url), "utf8");
assert.match(
appSource,
/selectedRecordedSessionIdRef\.current = session\.id[\s\S]*setRecordedReplay\(launch\)/,
);
assert.match(
appSource,
/releaseRecordedReplayForDelete[\s\S]*selectedRecordedSessionIdRef\.current !== sessionId[\s\S]*selectedRecordedSessionIdRef\.current = null[\s\S]*setRecordedReplay\(null\)[\s\S]*setSourceUrl\(""\)/,
);
assert.match(
appSource,
/onDeleteBegin=\{releaseRecordedReplayForDelete\}/,
);
assert.match(
appSource,
/onDeleteBegin:\s*releaseRecordedReplayForDelete/,
);
});
test("replay API accepts only a same-origin seekable recording descriptor", async () => {
const calls = [];
const launch = await replayObservationSession("session-20260716T205632Z", {