feat(chat): direct chats and groups between users in the pet's window
Server mode: a rail beside the pet's chat lists the pet, then the user's direct chats (one per pair) and groups with unread counts, and + for a new chat. A room shows its messages (group senders named), loads older pages, and sends text, pasted / dropped / attached files (<= 10 x 25 MB; images inline). A group's creator renames it and adds or removes people; anyone may leave. A blue dot on the pet counts unread messages. Only a room's members read or write it, an admin included (roomFor → 404). Files are stored under server-made names in <data dir>/chat/<room>/ and served to members only under a sandbox CSP + nosniff. chat_message / chat_room frames reach exactly the ids in `to` (scope.exactAudience). New tables chat_rooms / chat_members / chat_messages / chat_files (additive).
This commit is contained in:
+7
-1
@@ -340,10 +340,16 @@ function broadcastAudience(type, data) {
|
||||
* the role-based rules above. Pure (no DB): asked for every client. A change
|
||||
* to a member's OWN Claude Code config (`cc_config_changed` with `ownerId`,
|
||||
* routes/cc-config.js) names their files: it reaches that member and nobody
|
||||
* else, an admin or analyst included.
|
||||
* else, an admin or analyst included. A chat frame (`chat_message`,
|
||||
* `chat_room`) reaches exactly the users in its `to`.
|
||||
*/
|
||||
function exactAudience(type, data) {
|
||||
const d = data && typeof data === "object" ? data : {};
|
||||
// Chat (server/lib/chat.js): only the room's members, whatever their role —
|
||||
// an admin reads no one else's chat. No list = nobody.
|
||||
if (type === "chat_message" || type === "chat_room") {
|
||||
return new Set(Array.isArray(d.to) ? d.to : []);
|
||||
}
|
||||
if (type === "cc_config_changed" && d.ownerId != null) return new Set([d.ownerId]);
|
||||
return null;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user