/** * rChats Automerge document schemas. * * Granularity: one directory doc per space + one doc per channel. * DocId format: {space}:chats:channels (directory) * {space}:chats:channel:{channelId} (messages) * {space}:chats:dm:{sortedDid1+Did2} (DM channels) */ import type { DocSchema } from '../../shared/local-first/document'; // ── Transclusion: structured ref to any rSpace object ── export interface Transclusion { module: string; // "rtasks" | "rcal" | "rdocs" | etc. docId: string; objectId?: string; display: 'inline' | 'card' | 'link'; snapshot?: { title: string; summary?: string; capturedAt: number }; } // ── Thread metadata ── export interface ThreadMeta { participantDids: string[]; lastActivity: number; replyCount: number; } // ── Document types ── export interface ChannelInfo { id: string; name: string; description: string; isPrivate: boolean; isDm: boolean; createdBy: string | null; createdAt: number; updatedAt: number; visibility?: import('../../shared/membrane').ObjectVisibility; } export interface ChatsDirectoryDoc { meta: { module: string; collection: string; version: number; spaceSlug: string; createdAt: number; }; channels: Record; } export interface Member { userId: string; displayName: string; joinedAt: number; } export interface ChatMessage { id: string; channelId: string; authorId: string; authorName: string; content: string; replyTo: string | null; threadId?: string; // points to root message ID if this is a thread reply reactions: Record; // emoji → DID[] transclusions: Transclusion[]; editedAt: number | null; createdAt: number; visibility?: import('../../shared/membrane').ObjectVisibility; } export interface ChatChannelDoc { meta: { module: string; collection: string; version: number; spaceSlug: string; createdAt: number; }; channelId: string; messages: Record; members: Record; threads: Record; // rootMessageId → thread metadata pins: string[]; // pinned message IDs isDm: boolean; } // ── Schema registration ── export const chatsDirectorySchema: DocSchema = { module: 'chats', collection: 'channels', version: 2, init: (): ChatsDirectoryDoc => ({ meta: { module: 'chats', collection: 'channels', version: 2, spaceSlug: '', createdAt: Date.now(), }, channels: {}, }), }; export const chatChannelSchema: DocSchema = { module: 'chats', collection: 'channel', version: 2, init: (): ChatChannelDoc => ({ meta: { module: 'chats', collection: 'channel', version: 2, spaceSlug: '', createdAt: Date.now(), }, channelId: '', messages: {}, members: {}, threads: {}, pins: [], isDm: false, }), }; // ── Helpers ── export function chatsDirectoryDocId(space: string) { return `${space}:chats:channels` as const; } export function chatChannelDocId(space: string, channelId: string) { return `${space}:chats:channel:${channelId}` as const; } export function dmChannelDocId(space: string, did1: string, did2: string): string { const sorted = [did1, did2].sort(); return `${space}:chats:dm:${sorted[0]}+${sorted[1]}`; }