From 4ae61dc4e1dcca6ae24131fcd9acc55124e3c0af Mon Sep 17 00:00:00 2001 From: Christophe Besson Date: Fri, 9 Oct 2026 12:16:51 +0200 Subject: feat: let the operator purge a group's chat (MNP 6.1) Signed chat_purge from the Chat settings deletes every stored message; epoch keys and attachments stay. The ack is broadcast so open chat panels empty. Co-Authored-By: Claude Opus 5.5 --- .../meshbay-hub/tests/test_app_settings_plugin.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'packages/meshbay-hub/tests') diff --git a/packages/meshbay-hub/tests/test_app_settings_plugin.py b/packages/meshbay-hub/tests/test_app_settings_plugin.py index a56d70f..d469d8a 100644 --- a/packages/meshbay-hub/tests/test_app_settings_plugin.py +++ b/packages/meshbay-hub/tests/test_app_settings_plugin.py @@ -391,3 +391,23 @@ def test_a_saved_setting_reaches_the_page_that_renders_the_pane(): replay = replay[:replay.index("\n}") + 2] for cb in ("_onChatDirectory", "_onChatLinkPreview", "_onAppDirectories"): assert cb in replay, f"{cb} is never called for the requester" + + +def test_a_purge_empties_the_operators_own_chat_too(): + """The same trap for `chat_purge`: the operator who purged is the one whose + request would swallow the broadcast, and their chat would stay full.""" + transport = transport_source() + block = transport[transport.index("const BROADCAST_ACK_TYPES"):] + assert "'chat_purge_ack'" in block[:block.index("]);")] + replay = transport[transport.index("function _replayBroadcast"):] + replay = replay[:replay.index("\n}") + 2] + assert "_onChatPurged" in replay + + chat = (STATIC / "chat-app.js").read_text(encoding="utf-8") + hook = chat[chat.index("transport.onChatPurged = "):] + hook = hook[:hook.index("};")] + assert "setMessages([])" in hook and "setHasMore(false)" in hook + assert "transport.onChatPurged = null" in chat, "a closed panel keeps the hook" + + pane = (STATIC / "chat-app-settings.js").read_text(encoding="utf-8") + assert "transport.purgeChat(signFn)" in pane -- cgit v1.2.3