fix(calls,matrix): address review findings from agent code review
- CallEmbed watchdog now SELF-HEALS: a genuine ready/joined signal arriving after the 25s timeout clears the error and notifies subscribers with undefined, so a slow-but-successful EC load no longer strands the user on the recovery screen over a live call. Listener dispatch wrapped in try/catch. - ringtones: synth notes route through a per-session master gain; stop() ramps it to 0 so the ring is silenced instantly on answer instead of letting the last scheduled phrase ring out over call audio. - IncomingCallBanner: ping fires exactly once per incoming call (guarded by refEventId) instead of re-pinging when ringtone settings change mid-banner. - focusCameraParticipant: try multiple tile selectors (EC labels vary by version), defer the tile click past EC's async spotlight layout switch (rAF x2), and dev-warn when no tile matches so testers get signal. - uploadContent: a cancelled upload (mx.cancelUpload -> AbortError) is no longer treated as retryable — previously the retry loop could resurrect an upload the user just cancelled. Also retry on 408. - addRoomIdToMDirect/removeRoomIdFromMDirect: guard against a corrupt m.direct whose values aren't arrays. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+11
-3
@@ -169,12 +169,17 @@ const matrixErrorFromUnknown = (e: unknown): MatrixError => {
|
||||
// HTTP statuses that should not be retried — client errors are deterministic
|
||||
// (e.g. 413 payload too large, 400 bad request, 401/403 auth) and won't succeed on retry.
|
||||
const isRetryableUploadError = (e: unknown): boolean => {
|
||||
// A user-cancelled / aborted upload must never be retried. matrix-js-sdk's
|
||||
// mx.cancelUpload() rejects the upload with a DOMException named "AbortError";
|
||||
// without this guard the retry loop would resurrect an upload the user just
|
||||
// cancelled.
|
||||
if ((e as { name?: unknown } | null | undefined)?.name === 'AbortError') return false;
|
||||
if (e instanceof MatrixError) {
|
||||
const status = e.httpStatus;
|
||||
// No status => network/transport failure (transient): retry.
|
||||
if (typeof status !== 'number') return true;
|
||||
// Retry on rate-limiting and server-side (5xx) errors only.
|
||||
return status === 429 || status >= 500;
|
||||
// Retry on request-timeout, rate-limiting and server-side (5xx) errors only.
|
||||
return status === 408 || status === 429 || status >= 500;
|
||||
}
|
||||
// Non-Matrix errors are typically network/transport failures: retry.
|
||||
return true;
|
||||
@@ -307,6 +312,8 @@ export const addRoomIdToMDirect = async (
|
||||
// (it can only be a DM room for one person)
|
||||
Object.keys(userIdToRoomIds).forEach((targetUserId) => {
|
||||
const roomIds = userIdToRoomIds[targetUserId];
|
||||
// Guard against a corrupt m.direct where a value isn't an array.
|
||||
if (!Array.isArray(roomIds)) return;
|
||||
|
||||
if (targetUserId !== userId) {
|
||||
const indexOfRoomId = roomIds.indexOf(roomId);
|
||||
@@ -316,7 +323,7 @@ export const addRoomIdToMDirect = async (
|
||||
}
|
||||
});
|
||||
|
||||
const roomIds = userIdToRoomIds[userId] || [];
|
||||
const roomIds = Array.isArray(userIdToRoomIds[userId]) ? userIdToRoomIds[userId] : [];
|
||||
if (roomIds.indexOf(roomId) === -1) {
|
||||
roomIds.push(roomId);
|
||||
}
|
||||
@@ -334,6 +341,7 @@ export const removeRoomIdFromMDirect = async (mx: MatrixClient, roomId: string):
|
||||
|
||||
Object.keys(userIdToRoomIds).forEach((targetUserId) => {
|
||||
const roomIds = userIdToRoomIds[targetUserId];
|
||||
if (!Array.isArray(roomIds)) return;
|
||||
const indexOfRoomId = roomIds.indexOf(roomId);
|
||||
if (indexOfRoomId > -1) {
|
||||
roomIds.splice(indexOfRoomId, 1);
|
||||
|
||||
Reference in New Issue
Block a user