Files
cinny/src/app/utils/scheduledMessages.ts
T
jaredandClaude Opus 4.8 668bdaad7d fix(wave-2): audit fixes — account-data races, search-cache wipe, export, media
Web fixes from the Wave-2 bug-hunt (findings in LOTUS_TODO):
- F1 (security): wipe the decrypted-plaintext search index on SERVER-FORCED
  logout too (token expiry / remote sign-out) — only manual logout did before.
  F4: the delete no longer reports success while onblocked (waits, 3s cap).
- M1/M2 (data-loss): useBookmarks + useUserNotes account-data writes are now
  serialized at MODULE scope (single queue + latestRef per client, echo-driven),
  fixing the cross-instance lost-update clobber (useBookmarks mounts per message
  row, so a per-instance queue was insufficient — caught in review).
- M6: room-history export gets a 200-page cap + Cancel + unmount-abort +
  correct date-range early-break (raw paginated ts). M4: image compression
  skips PNG (was flattening transparency to black), bakes EXIF orientation via
  createImageBitmap, .jpg-renames, and falls back to the original on decode
  failure instead of dropping the file. M5: MediaGallery lightbox opens the
  right item (shared thumb guard). M8: audio speed survives async decrypt.
- Desktop web wiring: D2 badge sums leaf rooms only (space double-count, like
  the favicon fix); D3 useTauriDnd re-hydrates from get_tray_dnd on mount; D5
  updater has a terminal state.

Reviewed; M7 reverted (past-time clamp is an intentional, tested contract).
tsc/eslint/prettier clean, build OK, 678 tests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 20:56:27 -04:00

56 lines
1.8 KiB
TypeScript

import { IContent, MatrixClient, Method } from 'matrix-js-sdk';
/**
* Schedule a message via MSC4140 (delayed messages).
* Synapse implementation: pass org.matrix.msc4140.delay on the standard
* /v3/rooms send endpoint. The server stores the event and returns delay_id
* instead of event_id.
*/
export async function scheduleMessage(
mx: MatrixClient,
roomId: string,
content: IContent,
sendAtMs: number,
): Promise<string> {
// A past/near target floors at 1000ms (send ~immediately) — an intentional,
// tested contract; the ScheduleMessageModal already guards ≥60s in the future.
const delayMs = Math.max(1000, Math.round(sendAtMs - Date.now()));
const txnId = `sched_${Date.now()}_${Math.random().toString(36).slice(2)}`;
const path = `/rooms/${encodeURIComponent(roomId)}/send/m.room.message/${txnId}`;
// Use standard v3 prefix with the MSC4140 delay query param.
const res = (await mx.http.authedRequest(
Method.Put,
path,
{
'org.matrix.msc4140.delay': delayMs,
},
content,
)) as { delay_id: string };
return res.delay_id;
}
/**
* Cancel a scheduled message via MSC4140.
*/
export async function cancelScheduledMessage(mx: MatrixClient, delayId: string): Promise<void> {
const path = `/delayed_events/${encodeURIComponent(delayId)}`;
await mx.http.authedRequest(
Method.Post,
path,
undefined,
{ action: 'cancel' },
{ prefix: '/_matrix/client/unstable/org.matrix.msc4140' },
);
}
export async function restartScheduledMessage(mx: MatrixClient, delayId: string): Promise<void> {
const path = `/delayed_events/${encodeURIComponent(delayId)}`;
await mx.http.authedRequest(
Method.Post,
path,
undefined,
{ action: 'restart' },
{ prefix: '/_matrix/client/unstable/org.matrix.msc4140' },
);
}