Right-click a message for 复制/撤回/删除/多选 (README §3.5). 引用/收藏/翻译/
转发 deliberately left out of this pass -- quote and forward need their own
composer-state flows, and there's no confirmed single-message favorite
endpoint yet; a menu item that doesn't work is worse than a smaller correct
menu.
- lib/messages/actions.ts: gates recall to own messages, server-confirmed
seq (not the SDK's local pending-seq placeholder), and bootstrap's
message_policy.recall_window_seconds -- scoped to P2P for now, no
group-admin recall yet.
- lib/api/bootstrap.ts + api/hooks.ts: first GET /bootstrap wiring
(message_policy, forward limits, etc.), cached indefinitely per session.
- lib/api/messages.ts: recall goes through REST, not native WS -- and
requires a body `{version, reason}` this backend tracks per-message
independently of Tinode's own seq (confirmed in
docs/IM-前后端对接文档.md:1248 and by hitting a live 400
MALFORMED_REQUEST/version first, since no version field is actually
delivered anywhere in the WS {data} packet this app reads messages from).
Defaults to version:1 -- the correct value for any never-before-edited
message, which covers the common case; a real edit/recall race surfaces
as a version-conflict error rather than being silently papered over.
- Basic multi-select: enter via the context menu's "多选" (no long-press
gesture yet), header becomes "已选择 N 条消息"+取消, bottom bar currently
offers only 删除 (bulk 转发/收藏 wait on those features existing).
Verified end to end: recall correctly withheld past the 120s window and
correctly available within it, the real recall REST call round-trips and
the message disappears locally; multi-select mode enters/exits and
pre-selects the long-pressed/right-clicked message.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
27 lines
1.4 KiB
TypeScript
27 lines
1.4 KiB
TypeScript
// Message-level REST endpoints that sit alongside the native WS protocol. Recall goes through REST
|
|
// (not a Tinode WS operation) -- ported from the old app's context-menu.jsx recallOwnMessage, which
|
|
// calls this then hard-deletes the message from the local topic cache itself.
|
|
import { imPost } from './client';
|
|
|
|
export interface RecallResult {
|
|
topic: string;
|
|
seq: number;
|
|
status: string;
|
|
version: number;
|
|
updated_at: string;
|
|
}
|
|
|
|
/**
|
|
* This backend tracks its own optimistic-concurrency `version` per message (distinct from Tinode's
|
|
* `seq` -- confirmed in docs/IM-前后端对接文档.md:1248, `{"version":1,"reason":"..."}` request,
|
|
* `{"version":2,...}` response), which is NOT delivered anywhere in the native WS `{data}` packet
|
|
* this app reads messages from (confirmed live: a real message's WS payload carries no `version`
|
|
* field at all). Since there's currently no source for a message's true current version, this
|
|
* defaults to 1 (the version of any never-before-edited-or-recalled message, the overwhelmingly
|
|
* common case) -- a real edit/recall race would surface as a version-conflict error from the
|
|
* server, which the caller should treat as "refetch and retry," not silently ignore.
|
|
*/
|
|
export function recallMessage(topic: string, seq: number, version = 1, reason?: string) {
|
|
return imPost<RecallResult>(`/topics/${encodeURIComponent(topic)}/messages/${seq}/recall`, { version, reason });
|
|
}
|