@notmeta/chat-sdk
v0.1.1
Published
TITO Chat SDK - Secure messaging for your apps
Maintainers
Readme
@notmeta/chat-sdk
Secure, cross-app messaging SDK with end-to-end encryption.
Features
- E2EE - End-to-end encryption using Olm/Megolm (Signal Protocol compatible)
- Cross-App - Users can discover and message across Gigalicious, Our Resistance, and Tru Local
- Drop-in Replacement - Hooks mirror Supabase chat interface for easy migration
- Real-time - Live updates for messages, typing indicators, and presence
Installation
npm install @notmeta/chat-sdk
# or
yarn add @notmeta/chat-sdkQuick Start
1. Wrap your app with TitoProvider
import { TitoProvider } from '@notmeta/chat-sdk';
function App() {
return (
<TitoProvider
config={{
homeserver: 'https://thisistheother.chat',
appNamespace: 'giga', // or 'or', 'trulocal'
}}
credentials={titoCredentials} // Get from auth bridge
>
<YourApp />
</TitoProvider>
);
}2. Use hooks in your components
import { useTitoRoom } from '@notmeta/chat-sdk';
function GigChat({ gigId }) {
const {
messages,
sendMessage,
typingUsers,
setTyping,
isLoading,
} = useTitoRoom(gigId);
// Same interface as your Supabase hooks!
return (
<div>
{messages.map((msg) => (
<Message key={msg.id} message={msg} />
))}
</div>
);
}Migration from Supabase
Before (Supabase)
import { useGigChat } from './hooks/useGigChat';
function Chat({ gigId }) {
const { messages, sendMessage } = useGigChat(gigId);
// ...
}After (TITO)
import { useTitoRoom } from '@notmeta/chat-sdk';
function Chat({ gigId }) {
const { messages, sendMessage } = useTitoRoom(gigId);
// Same interface - just swap the import!
}Auth Bridge
Connect your existing auth system to TITO:
// In your auth flow (after Supabase login)
import { getTitoCredentials } from '@notmeta/chat-sdk';
async function onLogin(supabaseUser) {
const titoCredentials = await getTitoCredentials(
supabaseUser.id,
supabaseUser.access_token,
{
homeserver: 'https://thisistheother.chat',
appNamespace: 'giga',
}
);
// Store credentials and pass to TitoProvider
localStorage.setItem('tito_credentials', JSON.stringify(titoCredentials));
}Hooks Reference
useTitoRoom(roomId)
Group chat functionality.
const {
messages, // ChatMessage[]
isLoading, // boolean
error, // Error | null
sendMessage, // (content, imageUrl?, replyToId?) => Promise<void>
deleteMessage, // (messageId) => Promise<void>
typingUsers, // TypingUser[]
setTyping, // (isTyping) => void
markAsRead, // () => void
loadMore, // () => Promise<void>
hasMore, // boolean
} = useTitoRoom(roomId);useTitoDM()
Direct messages.
const {
conversations, // DMConversation[]
isLoading, // boolean
error, // Error | null
startConversation, // (userId) => Promise<roomId>
deleteConversation, // (conversationId) => Promise<void>
} = useTitoDM();useTitoReactions(roomId)
Message reactions.
const {
addReaction, // (messageId, emoji) => Promise<void>
removeReaction, // (messageId, reactionEventId) => Promise<void>
} = useTitoReactions(roomId);useTitoSearch()
Cross-app user search.
const {
searchUsers, // (query) => Promise<ChatUser[]>
isSearching, // boolean
} = useTitoSearch();
// Find users across all apps!
const results = await searchUsers('kelly');
// Returns users from Giga, OR, Tru Local, etc.Cross-App Discovery
Users can discover each other across apps:
import { parseUserId, getAppBadge } from '@notmeta/chat-sdk';
function UserCard({ userId }) {
const { username, app } = parseUserId(userId);
const badge = getAppBadge(userId);
return (
<div>
<span>{username}</span>
{badge && (
<span style={{ color: badge.color }}>
{badge.name}
</span>
)}
</div>
);
}
// @kelly:giga.thisistheother.chat -> "kelly" with "Gigalicious" badge
// @sam:or.thisistheother.chat -> "sam" with "Our Resistance" badgeTypes
interface ChatMessage {
id: string;
room_id: string;
sender_id: string;
sender: ChatUser;
content: string;
image_url: string | null;
reply_to_id: string | null;
reply_to: ChatMessage | null;
is_deleted: boolean;
created_at: string;
reactions: MessageReaction[];
}
interface ChatUser {
id: string;
username: string;
display_name: string | null;
avatar_url: string | null;
}Security
- All messages are encrypted end-to-end using Olm/Megolm
- Based on the Signal Protocol (same as WhatsApp)
- Keys are stored locally on each device
- Server never sees message content
