chore(broker): wire mentions through WS topic_send + dedupe imports
Some checks failed
CI / Lint (push) Has been cancelled
CI / Typecheck (push) Has been cancelled
CI / Broker tests (Postgres) (push) Has been cancelled
CI / Docker build (linux/amd64) (push) Has been cancelled

WSSendMessage gains an optional mentions field; the broker forwards
it into appendTopicMessage so WS-driven topic sends get the same
write-time fan-out path as REST POST /v1/messages. v1 messages
(today's plaintext-base64) still fall back to a body regex when the
field is omitted, so existing CLIs aren't broken; v2 ciphertext
clients in phase 3 will populate it.

Also drops the duplicate meshMember import (kept the meshMember-as-
memberTable alias which the rest of the file uses).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Alejandro Gutiérrez
2026-05-02 20:45:57 +01:00
parent b70536195a
commit 82ebd2b6be
3 changed files with 13 additions and 5 deletions

View File

@@ -38,7 +38,6 @@ import {
meshFileKey, meshFileKey,
meshContext, meshContext,
meshMember as memberTable, meshMember as memberTable,
meshMember,
meshMemory, meshMemory,
meshNotification, meshNotification,
meshState, meshState,
@@ -896,12 +895,12 @@ async function fanOutMentions(args: {
const recipients = await db const recipients = await db
.select({ .select({
id: meshMember.id, id: memberTable.id,
displayName: meshMember.displayName, displayName: memberTable.displayName,
}) })
.from(meshMember) .from(memberTable)
.where( .where(
and(eq(meshMember.meshId, topic.meshId), isNull(meshMember.revokedAt)), and(eq(memberTable.meshId, topic.meshId), isNull(memberTable.revokedAt)),
); );
const tokenSet = new Set(tokens); const tokenSet = new Set(tokens);
const targets = recipients const targets = recipients

View File

@@ -1952,6 +1952,7 @@ async function handleSend(
senderSessionPubkey: conn.sessionPubkey ?? undefined, senderSessionPubkey: conn.sessionPubkey ?? undefined,
nonce: msg.nonce, nonce: msg.nonce,
ciphertext: msg.ciphertext, ciphertext: msg.ciphertext,
mentions: msg.mentions,
}).catch((e) => }).catch((e) =>
log.warn("appendTopicMessage failed", { topic_id: topicId, err: String(e) }), log.warn("appendTopicMessage failed", { topic_id: topicId, err: String(e) }),
); );

View File

@@ -98,6 +98,14 @@ export interface WSSendMessage {
nonce: string; // base64 nonce: string; // base64
ciphertext: string; // base64 ciphertext: string; // base64
id?: string; // client-side correlation id id?: string; // client-side correlation id
/**
* Optional client-extracted `@-mention` display names (lowercased,
* no `@` prefix, max 16). Required when `body_version: 2` cipher
* lands in v0.3.0 phase 3 — the server can't read v2 ciphertext to
* regex-match. Today's v1 plaintext path falls back to a regex on
* the body when this is absent.
*/
mentions?: string[];
} }
/** Broker → client: an envelope addressed to this peer. */ /** Broker → client: an envelope addressed to this peer. */