eleven / ocho Public

web: fix message edits silently dropped (stale editing id) (#19)

The edit send in sendMessage read the module-level `editing` variable
inside the encrypt().then() callback, but cancelEdit() runs synchronously
right after and resets `editing` to null. By the time the async callback
fired, `editing` was already null, so the frame shipped as
`message_id: null` → Go unmarshals null into int64 as 0 → the hub's
`if in.MessageID <= 0 { continue }` silently dropped it. The edit never
reached editMessage, so nothing changed and no error surfaced.

Capture the id into a local before the async hop (as the pre-#17 code
did) so the sent frame carries the real message id.
Co-authored-by: Claude <noreply@anthropic.com>
James Adam 9cf1cf7c42da2621c0d7ed30371dfc14d52d4c0c parent 3ce4663
1 file changed, +6 −2
  • web/static/chat.js +6 −2
diff --git a/web/static/chat.js b/web/static/chat.js
index 3b1bc11..c6717b6 100644
--- a/web/static/chat.js
+++ b/web/static/chat.js
@@ -1201,10 +1201,14 @@ function sendMessage(raw) {
// Editing an existing message: re-encrypt the original payload with new text
// (preserving its name + any attachments) and send an edit.
if (editing != null) {
- const orig = msgData[editing] && msgData[editing].data;
+ // Capture the id before cancelEdit() (below) resets `editing` to null — the
+ // encrypt().then() send is async, so reading `editing` inside it would race
+ // and ship message_id: null, which the server drops.
+ const id = editing;
+ const orig = msgData[id] && msgData[id].data;
if (text && orig) {
encrypt(threadKeys[activeId], { ...orig, text }).then((blob) => {
- ws.send(JSON.stringify({ type: "edit", thread_id: activeId, message_id: editing, blob }));
+ ws.send(JSON.stringify({ type: "edit", thread_id: activeId, message_id: id, blob }));
});
}
cancelEdit();