@nostr-dev-kit/messages
Version:
High-level messaging library for NDK supporting NIP-17 and NIP-EE
283 lines (209 loc) • 7.07 kB
Markdown
# @nostr-dev-kit/messages
High-level messaging library for NDK that provides a unified API for private messaging protocols on Nostr.
## Features
- 🎯 **Simple API** - One-line message sending with automatic protocol handling
- 🔐 **NIP-17 Support** - Gift-wrapped private messages with proper relay management
- 💬 **Conversation Management** - Automatic grouping, threading, and read status
- 📡 **Event-Driven** - Real-time updates via EventEmitter pattern
- 💾 **Storage Abstraction** - Pluggable storage adapters for persistence
- 🔄 **Future-Proof** - Ready for NIP-EE (MLS) when implemented
## Installation
```bash
npm install @nostr-dev-kit/messages
# or
bun add @nostr-dev-kit/messages
```
## Quick Start
```typescript
import NDK from '@nostr-dev-kit/ndk';
import { NDKMessenger } from '@nostr-dev-kit/messages';
// Initialize NDK
const ndk = new NDK({
explicitRelayUrls: ['wss://relay.damus.io'],
signer: new NDKPrivateKeySigner(privateKey)
});
await ndk.connect();
// Create messenger
const messenger = new NDKMessenger(ndk);
await messenger.start();
// Send a message
const recipient = ndk.getUser({ npub: "npub1..." });
await messenger.sendMessage(recipient, "Hello!");
// Listen for messages
messenger.on('message', (message) => {
console.log(`New message from ${message.sender.npub}: ${message.content}`);
});
```
## API Reference
### NDKMessenger
Main orchestrator class for messaging functionality.
```typescript
class NDKMessenger extends EventEmitter {
constructor(ndk: NDK, options?: MessengerOptions)
// Start/stop the messenger
async start(): Promise<void>
stop(): void
// Send messages
async sendMessage(recipient: NDKUser, content: string): Promise<NDKMessage>
// Manage conversations
async getConversation(user: NDKUser): Promise<NDKConversation>
async getConversations(): Promise<NDKConversation[]>
// Publish relay preferences
async publishDMRelays(relays: string[]): Promise<NDKEvent>
}
```
#### Events
- `message` - New message received
- `conversation-created` - New conversation started
- `error` - Error occurred
### NDKConversation
Represents a conversation between users with real-time updates.
```typescript
class NDKConversation extends EventEmitter {
readonly id: string
readonly participants: NDKUser[]
readonly protocol: 'nip17' | 'mls'
// Send messages
async sendMessage(content: string): Promise<NDKMessage>
// Get messages
async getMessages(limit?: number): Promise<NDKMessage[]>
// Mark as read
async markAsRead(): Promise<void>
// Helpers
getUnreadCount(): number
getOtherParticipant(): NDKUser | undefined
getLastMessage(): NDKMessage | undefined
}
```
#### Events
- `message` - New message in conversation
- `state-change` - Conversation state changed
- `error` - Error in conversation
### Storage Adapters
The library uses a storage adapter pattern for flexibility:
```typescript
interface StorageAdapter {
saveMessage(message: NDKMessage): Promise<void>
getMessages(conversationId: string, limit?: number): Promise<NDKMessage[]>
markAsRead(messageIds: string[]): Promise<void>
getConversations(userId: string): Promise<ConversationMeta[]>
saveConversation(conversation: ConversationMeta): Promise<void>
}
```
#### Built-in Adapters
- `MemoryAdapter` - In-memory storage (default)
- More adapters coming soon (Dexie, SQLite)
## Examples
### Basic Messaging
```typescript
// Initialize
const messenger = new NDKMessenger(ndk);
await messenger.start();
// Send message
const bob = ndk.getUser({ npub: "npub1bob..." });
await messenger.sendMessage(bob, "Hey Bob!");
// Get conversation
const conversation = await messenger.getConversation(bob);
const messages = await conversation.getMessages();
// Mark as read
await conversation.markAsRead();
```
### Real-time Updates
```typescript
// Listen to all messages
messenger.on('message', (message) => {
if (message.sender.pubkey !== messenger.myPubkey) {
showNotification(`New message from ${message.sender.displayName}`);
}
});
// Listen to specific conversation
conversation.on('message', (message) => {
updateChatUI(message);
});
conversation.on('error', (error) => {
console.error('Conversation error:', error);
});
```
### Custom Storage
```typescript
import { MemoryAdapter } from '@nostr-dev-kit/messages';
// Use custom storage
const messenger = new NDKMessenger(ndk, {
storage: new MemoryAdapter(),
autoStart: true
});
// Or implement your own
class MyStorageAdapter implements StorageAdapter {
// ... implement interface methods
}
```
### Cache Module Integration
This package supports NDK's cache module system for persistent storage:
```typescript
import NDKCacheAdapterDexie from '@nostr-dev-kit/cache-dexie';
import { CacheModuleStorage, messagesCacheModule } from '@nostr-dev-kit/messages';
// Use with cache adapter that supports modules
const cacheAdapter = new NDKCacheAdapterDexie({ dbName: 'my-app' });
const ndk = new NDK({
cacheAdapter,
// ... other options
});
// Messages will automatically use cache if available
const messenger = new NDKMessenger(ndk, {
storage: new CacheModuleStorage(cacheAdapter, userPubkey)
});
```
The messages cache module creates these collections:
- `messages` - Individual messages with indexes for efficient querying
- `conversations` - Conversation metadata and participants
- `mlsGroups` - (Future) MLS group state
- `dmRelays` - Relay preferences for DMs
Benefits:
- **Persistent Storage**: Messages survive app restarts (IndexedDB in browser)
- **Automatic Migrations**: Schema upgrades handled automatically
- **Type Safety**: Fully typed collections and queries
- **Performance**: Indexed fields for fast lookups
### Relay Management
```typescript
// Publish your DM relay preferences (kind 10050)
await messenger.publishDMRelays([
'wss://relay.damus.io',
'wss://nos.lol'
]);
```
## NIP-17 Implementation
This library implements NIP-17 (Private Direct Messages) with:
- Automatic rumor creation with proper pubkey setting
- Gift wrapping with ephemeral keys
- Relay discovery via kind 10050
- Automatic subscription to kind 1059 events
- Message deduplication
## Future: NIP-EE Support
The library is designed to support NIP-EE (MLS-based messaging) when ready:
```typescript
// Future API (same interface, different protocol)
const conversation = await messenger.createConversation([alice, bob, charlie]);
console.log(conversation.protocol); // 'mls' if all support it, 'nip17' otherwise
```
## Development
```bash
# Install dependencies
bun install
# Build
bun run build
# Run tests
bun test
# Run example
cd examples/nip-17-chat
bunx tsx generate-keys.ts
bunx tsx src/index.ts
```
## Contributing
Contributions are welcome! Please read our contributing guidelines before submitting PRs.
## License
MIT
## See Also
- [NIP-17: Private Direct Messages](https://nips.nostr.com/17)
- [NIP-EE: End-to-End Encrypted Messaging using MLS](https://nips.nostr.com/EE)
- [NDK Documentation](https://ndk.fyi)
- [Example App](./examples/nip-17-chat)