Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/covenant-gov/pacto-app/llms.txt

Use this file to discover all available pages before exploring further.

Pacto’s frontend communicates with the Rust backend exclusively through Tauri commands and Tauri events. A command is an async RPC call: the TypeScript frontend calls invoke('command_name', { ...params }) and awaits a serialized result. Events flow in the opposite direction — the backend emits them and the frontend registers listeners with listen. All message-related functionality (direct messages, MLS group messages, files, voice memos, reactions, and history loading) flows through the commands and events documented on this page.

Import pattern

import { invoke } from '@tauri-apps/api/core';
import { listen } from '@tauri-apps/api/event';

Commands

message

Send a text direct message or MLS group message. This is the primary send entry point for all text content. The receiver field doubles as the routing key: an npub1… value routes to the NIP-59 Gift Wrap DM path; any other value (a hex group ID) routes to the MLS Kind 444 path.
ParameterTypeDescription
receiverstringRecipient npub (DM) or group_id hex (MLS group)
contentstringMessage text
repliedTostringMessage ID being replied to, or empty string for no reply
fileAttachmentFile | nullOptional file attachment (use file_message for path-based sends)
virtualBucketstring | nullOptional virtual bucket label ("announcements" | "inbox" | "polls") for MLS groups
Returns: booleantrue on success.
// Send a DM
await invoke('message', {
  receiver: 'npub1abc...',
  content: 'Hello!',
  repliedTo: ''
});

// Send to an MLS group
await invoke('message', {
  receiver: 'a1b2c3d4...', // hex group_id
  content: 'Hey squad!',
  repliedTo: ''
});
Receiver routing: if a chat already exists for the given receiver, Pacto uses the existing chat type. If no chat exists yet, receiver.startsWith('npub1') → DM path; any other value → MLS group path.

file_message

Send a file from a local filesystem path. Reads the file, extracts the extension, and generates blurhash metadata for supported image types before delegating to message with the file bytes as an AttachmentFile. On Android, cached bytes from a prior cache_android_file call are used if available.
ParameterTypeDescription
receiverstringRecipient npub or group_id hex
repliedTostringMessage ID being replied to, or empty string
filePathstringAbsolute path to the local file (or Android content URI)
Returns: booleantrue on success.
await invoke('file_message', {
  receiver: 'npub1abc...',
  repliedTo: '',
  filePath: '/home/user/documents/report.pdf'
});

voice_message

Send a voice memo as a WAV audio attachment. Accepts raw PCM/WAV bytes recorded by the frontend, wraps them as a .wav AttachmentFile, and routes through message.
ParameterTypeDescription
receiverstringRecipient npub or group_id hex
repliedTostringMessage ID being replied to, or empty string
bytesnumber[]Raw WAV audio bytes
Returns: booleantrue on success.
// After recording audio into a Uint8Array:
await invoke('voice_message', {
  receiver: 'npub1abc...',
  repliedTo: '',
  bytes: Array.from(audioBytes)
});

react_to_message

React to an existing message with an emoji. For DMs the reaction is Gift Wrapped and sent to both the recipient and back to the sender (for self-recovery). For MLS groups the reaction is sent as an MLS application message.
ParameterTypeDescription
referenceIdstringID of the message being reacted to
chatIdstringnpub (DM) or group_id hex (MLS) — must match the chat that contains referenceId
emojistringEmoji character to react with, e.g. "👍"
Returns: booleantrue on success.
await invoke('react_to_message', {
  referenceId: 'abc123def456...',
  chatId: 'npub1abc...',
  emoji: '🔥'
});

get_message_views

Load a paginated slice of message history for a chat from the local SQLite database. MLS group chats are provisioned on first load if no DB row exists yet. Results are also merged into the in-memory ChatState cache.
ParameterTypeDescription
chatIdstringnpub (DM) or group_id hex (MLS)
limitnumberMaximum number of messages to return
offsetnumberPagination offset (0-based)
virtualBucketFilterstring | nullOptionally filter by virtual bucket ("announcements", "inbox", "polls")
Returns: Message[] — array of message objects.
const messages = await invoke('get_message_views', {
  chatId: 'npub1abc...',
  limit: 50,
  offset: 0,
  virtualBucketFilter: null
});

fetch_messages

Sync Gift Wrap events (Kind 1059) from Nostr relays for the currently authenticated account. When init: true, also hydrates the local database from disk before syncing and triggers init_finished once the initial load is complete. Automatically triggers sync_mls_groups_now after Gift Wrap sync to pick up any pending MLS group messages.
ParameterTypeDescription
initbooleantrue on first call after login (loads DB and emits init_finished)
relayUrlstring | nullIf set, sync only from this specific relay (single-relay reconnection mode)
Returns: void
// Initial load on login
await invoke('fetch_messages', { init: true, relayUrl: null });

// Re-sync a specific relay
await invoke('fetch_messages', { init: false, relayUrl: 'wss://relay.example.com' });

create_account

Generate a new Nostr keypair derived from a freshly generated BIP39 12-word mnemonic. Returns the keypair for display/backup before the mnemonic is discarded. Parameters: none Returns: LoginKeyPair{ nsec: string, npub: string, mnemonic: string }
const keyPair = await invoke('create_account');
console.log('New npub:', keyPair.npub);
console.log('Save this mnemonic:', keyPair.mnemonic);

get_or_create_invite_code

Retrieve the current user’s invite code from local storage or the network. If no code exists locally, checks the account’s published application-specific data on Nostr relays before generating and publishing a new one. Parameters: none Returns: string — 8-character uppercase alphanumeric invite code.
const code = await invoke('get_or_create_invite_code');
// e.g. "XKBD29FQ"

Tauri events

Listen for these events using listen from @tauri-apps/api/event. Each listen call returns an unlisten function — always call it on component teardown to avoid memory leaks.

message_new

Emitted when a new DM rumor is processed after unwrapping a Gift Wrap. The chat_id is always the other user’s npub. Payload: { message: Message, chat_id: string }
const unlisten = await listen('message_new', (event) => {
  const { chat_id, message } = event.payload;
  console.log(`New DM in ${chat_id}:`, message.content);
});

// Later, on component teardown:
unlisten();

init_finished

Emitted once after the initial account hydration completes during fetch_messages({ init: true }). Contains the full set of known profiles and chats to populate the UI state. Payload: { profiles: Profile[], chats: Chat[] }
const unlisten = await listen('init_finished', (event) => {
  const { profiles, chats } = event.payload;
  console.log(`Loaded ${chats.length} chats and ${profiles.length} profiles`);
});

typing-update

Emitted when a typing indicator is received for a conversation. The conversation_id is the npub for DMs or the group_id hex for MLS groups. Payload: { conversation_id: string }
const unlisten = await listen('typing-update', (event) => {
  const { conversation_id } = event.payload;
  // Show typing indicator for the relevant chat
});

Full DM send and receive example

import { invoke } from '@tauri-apps/api/core';
import { listen } from '@tauri-apps/api/event';

// 1. Listen for incoming DMs before sending
const unlisten = await listen('message_new', (event) => {
  const { chat_id, message } = event.payload;
  console.log(`New message in ${chat_id}:`, message.content);
});

// 2. Send a DM
await invoke('message', {
  receiver: 'npub1abc...',
  content: 'Hello!',
  repliedTo: ''
});

// 3. Load history for this conversation
const history = await invoke('get_message_views', {
  chatId: 'npub1abc...',
  limit: 50,
  offset: 0,
  virtualBucketFilter: null
});

// 4. Teardown
unlisten();
For MLS group messages, substitute the hex group_id for the npub in receiver / chatId and listen to mls_message_new (with payload { group_id, message }) instead of message_new. See MLS Commands for the full group messaging reference.

Build docs developers (and LLMs) love