
Security News
The Changelog Podcast: Practical Steps to Stay Safe on npm
Learn the essential steps every developer should take to stay secure on npm and reduce exposure to supply chain attacks.
@nostr-dev-kit/messages
Advanced tools
High-level messaging library for NDK supporting NIP-17 and NIP-EE
High-level messaging library for NDK that provides a unified API for private messaging protocols on Nostr.
npm install @nostr-dev-kit/messages
# or
bun add @nostr-dev-kit/messages
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}`);
});
Main orchestrator class for messaging functionality.
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>
}
message - New message receivedconversation-created - New conversation startederror - Error occurredRepresents a conversation between users with real-time updates.
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
}
message - New message in conversationstate-change - Conversation state changederror - Error in conversationThe library uses a storage adapter pattern for flexibility:
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>
}
MemoryAdapter - In-memory storage (default)// 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();
// 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);
});
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
}
This package supports NDK's cache module system for persistent storage:
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 queryingconversations - Conversation metadata and participantsmlsGroups - (Future) MLS group statedmRelays - Relay preferences for DMsBenefits:
// Publish your DM relay preferences (kind 10050)
await messenger.publishDMRelays([
'wss://relay.damus.io',
'wss://nos.lol'
]);
This library implements NIP-17 (Private Direct Messages) with:
The library is designed to support NIP-EE (MLS-based messaging) when ready:
// 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
# 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
Contributions are welcome! Please read our contributing guidelines before submitting PRs.
MIT
FAQs
High-level messaging library for NDK supporting NIP-17 and NIP-EE
We found that @nostr-dev-kit/messages demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 2 open source maintainers collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Learn the essential steps every developer should take to stay secure on npm and reduce exposure to supply chain attacks.

Security News
Experts push back on new claims about AI-driven ransomware, warning that hype and sponsored research are distorting how the threat is understood.

Security News
Ruby's creator Matz assumes control of RubyGems and Bundler repositories while former maintainers agree to step back and transfer all rights to end the dispute.