@tagea/capacitor-matrix
v0.3.1
Published
A capacitor plugin wrapping native matrix SDKs
Downloads
370
Readme
@tremaze/capacitor-matrix
A Capacitor plugin that provides a unified API for the Matrix communication protocol across Web, Android, and iOS.
- Web — powered by matrix-js-sdk
- Android — powered by matrix-rust-sdk (Kotlin bindings)
- iOS — powered by matrix-rust-components-swift
Features
- Authentication — password login, token-based login, session persistence
- Real-time sync — incremental sync with state change events
- Rooms — create, join, leave, list rooms with summaries
- Messaging — send/receive text, notices, emotes; paginated message history
- Media — upload and send images, audio, video, and files; resolve
mxc://URLs - Reactions & Redactions — react to messages, delete (redact) events
- Room management — rename rooms, set topics, invite/kick/ban/unban users
- Typing indicators — send and receive typing notifications
- Presence — set and query online/offline/unavailable status
- End-to-end encryption — cross-signing, key backup, secret storage, recovery, room key export/import
Requirements
| Platform | Minimum Version | | -------- | --------------- | | Capacitor | 8.0.0 | | iOS | 16.0 | | Android | API 24 (Android 7.0) |
Install
npm install @tremaze/capacitor-matrix
npx cap synciOS
No additional setup required. The Swift Package Manager dependency on matrix-rust-components-swift is resolved automatically.
Android
The plugin uses matrix-rust-sdk via Maven. Ensure your project's build.gradle includes mavenCentral() in the repositories block (this is the default for new Capacitor projects).
Usage
Import
import { Matrix } from '@tremaze/capacitor-matrix';Authentication
// Login with username and password
const session = await Matrix.login({
homeserverUrl: 'https://matrix.example.com',
userId: '@alice:example.com',
password: 'secret',
});
console.log('Logged in as', session.userId);
// Or restore a session using a stored access token
const session = await Matrix.loginWithToken({
homeserverUrl: 'https://matrix.example.com',
accessToken: 'syt_...',
userId: '@alice:example.com',
deviceId: 'ABCDEF',
});
// Check for an existing session (persisted in localStorage on web)
const existing = await Matrix.getSession();
if (existing) {
console.log('Already logged in as', existing.userId);
}
// Logout
await Matrix.logout();Sync
Start the background sync loop to receive real-time updates:
// Listen for sync state changes
await Matrix.addListener('syncStateChange', ({ state, error }) => {
console.log('Sync state:', state); // 'INITIAL' | 'SYNCING' | 'ERROR' | 'STOPPED'
if (error) console.error('Sync error:', error);
});
await Matrix.startSync();
// Later, stop syncing
await Matrix.stopSync();Rooms
// List joined rooms
const { rooms } = await Matrix.getRooms();
rooms.forEach((room) => {
console.log(room.name, `(${room.memberCount} members)`);
});
// Create a room
const { roomId } = await Matrix.createRoom({
name: 'Project Chat',
topic: 'Discussion about the project',
isEncrypted: true,
invite: ['@bob:example.com'],
});
// Join a room by ID or alias
await Matrix.joinRoom({ roomIdOrAlias: '#general:example.com' });
// Leave a room
await Matrix.leaveRoom({ roomId: '!abc:example.com' });
// Get room members
const { members } = await Matrix.getRoomMembers({ roomId });Messaging
// Send a text message
const { eventId } = await Matrix.sendMessage({
roomId: '!abc:example.com',
body: 'Hello, world!',
});
// Send a notice or emote
await Matrix.sendMessage({
roomId,
body: 'This is a notice',
msgtype: 'm.notice',
});
// Load message history (paginated)
const { events, nextBatch } = await Matrix.getRoomMessages({
roomId,
limit: 50,
});
// Load older messages
const older = await Matrix.getRoomMessages({
roomId,
limit: 50,
from: nextBatch,
});
// Listen for new messages in real time
await Matrix.addListener('messageReceived', ({ event }) => {
console.log(`${event.senderId}: ${event.content.body}`);
});Media
// Send an image (provide a file URI on native, or a blob URL on web)
await Matrix.sendMessage({
roomId,
body: 'photo.jpg',
msgtype: 'm.image',
fileUri: 'file:///path/to/photo.jpg',
fileName: 'photo.jpg',
mimeType: 'image/jpeg',
});
// Resolve an mxc:// URL to an HTTP URL for display
const { httpUrl } = await Matrix.getMediaUrl({
mxcUrl: 'mxc://example.com/abc123',
});Reactions & Redactions
// React to a message
await Matrix.sendReaction({
roomId,
eventId: '$someEvent',
key: '👍',
});
// Redact (delete) a message
await Matrix.redactEvent({
roomId,
eventId: '$someEvent',
reason: 'Sent by mistake',
});Room Management
await Matrix.setRoomName({ roomId, name: 'New Room Name' });
await Matrix.setRoomTopic({ roomId, topic: 'Updated topic' });
await Matrix.inviteUser({ roomId, userId: '@carol:example.com' });
await Matrix.kickUser({ roomId, userId: '@dave:example.com', reason: 'Inactive' });
await Matrix.banUser({ roomId, userId: '@eve:example.com' });
await Matrix.unbanUser({ roomId, userId: '@eve:example.com' });Typing Indicators
// Send a typing notification
await Matrix.sendTyping({ roomId, isTyping: true, timeout: 5000 });
// Stop typing
await Matrix.sendTyping({ roomId, isTyping: false });
// Listen for typing events
await Matrix.addListener('typingChanged', ({ roomId, userIds }) => {
if (userIds.length > 0) {
console.log(`${userIds.join(', ')} typing in ${roomId}`);
}
});Presence
// Set your presence
await Matrix.setPresence({ presence: 'online', statusMsg: 'Available' });
// Get another user's presence
const info = await Matrix.getPresence({ userId: '@bob:example.com' });
console.log(info.presence, info.statusMsg);End-to-End Encryption
// Initialize the crypto module (call after login, before startSync)
await Matrix.initializeCrypto();
// Check encryption status
const status = await Matrix.getEncryptionStatus();
console.log('Cross-signing ready:', status.isCrossSigningReady);
console.log('Key backup enabled:', status.isKeyBackupEnabled);
// Bootstrap cross-signing (first-time device setup)
await Matrix.bootstrapCrossSigning();
// Set up server-side key backup
const backup = await Matrix.setupKeyBackup();
// Set up recovery (generates a recovery key)
const { recoveryKey } = await Matrix.setupRecovery();
console.log('Save this recovery key:', recoveryKey);
// Or use a passphrase-based recovery key
const recovery = await Matrix.setupRecovery({ passphrase: 'my secret phrase' });
// Recover on a new device
await Matrix.recoverAndSetup({ recoveryKey: 'EsXa ...' });
// or
await Matrix.recoverAndSetup({ passphrase: 'my secret phrase' });
// Export/import room keys (for manual backup)
const { data } = await Matrix.exportRoomKeys({ passphrase: 'backup-pass' });
await Matrix.importRoomKeys({ data, passphrase: 'backup-pass' });Event Listeners
// Room updates (name change, new members, etc.)
await Matrix.addListener('roomUpdated', ({ roomId, summary }) => {
console.log(`Room ${summary.name} updated`);
});
// Read receipt updates (fires when another user reads messages in a room)
await Matrix.addListener('receiptReceived', ({ roomId }) => {
console.log(`New read receipt in ${roomId}`);
// Refresh message statuses to update read indicators
});
// Clean up all listeners
await Matrix.removeAllListeners();Read Markers
// Mark a room as read up to a specific event
await Matrix.markRoomAsRead({
roomId: '!abc:example.com',
eventId: '$latestEvent',
});
// Refresh read statuses for specific messages (useful after receiving a receiptReceived event)
const { events } = await Matrix.refreshEventStatuses({
roomId: '!abc:example.com',
eventIds: ['$event1', '$event2'],
});
events.forEach((evt) => {
console.log(`${evt.eventId}: ${evt.status}`, evt.readBy);
});API Reference
The full API reference is auto-generated below from the TypeScript definitions.
login(...)loginWithToken(...)logout()getSession()startSync()stopSync()getSyncState()createRoom(...)getRooms()getRoomMembers(...)joinRoom(...)leaveRoom(...)forgetRoom(...)sendMessage(...)editMessage(...)sendReply(...)getRoomMessages(...)markRoomAsRead(...)refreshEventStatuses(...)redactEvent(...)sendReaction(...)setRoomName(...)setRoomTopic(...)setRoomAvatar(...)inviteUser(...)kickUser(...)banUser(...)unbanUser(...)sendTyping(...)getMediaUrl(...)getThumbnailUrl(...)uploadContent(...)searchUsers(...)setPresence(...)getPresence(...)getDevices()deleteDevice(...)verifyDevice(...)setPusher(...)initializeCrypto()getEncryptionStatus()bootstrapCrossSigning()setupKeyBackup()getKeyBackupStatus()restoreKeyBackup(...)setupRecovery(...)clearAllData()isRecoveryEnabled()recoverAndSetup(...)resetRecoveryKey(...)exportRoomKeys(...)importRoomKeys(...)addListener('syncStateChange', ...)addListener('messageReceived', ...)addListener('roomUpdated', ...)addListener('typingChanged', ...)addListener('receiptReceived', ...)addListener('presenceChanged', ...)removeAllListeners()- Interfaces
- Type Aliases
login(...)
login(options: LoginOptions) => Promise<SessionInfo>| Param | Type |
| ------------- | ----------------------------------------------------- |
| options | LoginOptions |
Returns: Promise<SessionInfo>
loginWithToken(...)
loginWithToken(options: LoginWithTokenOptions) => Promise<SessionInfo>| Param | Type |
| ------------- | ----------------------------------------------------------------------- |
| options | LoginWithTokenOptions |
Returns: Promise<SessionInfo>
logout()
logout() => Promise<void>getSession()
getSession() => Promise<SessionInfo | null>Returns: Promise<SessionInfo | null>
startSync()
startSync() => Promise<void>stopSync()
stopSync() => Promise<void>getSyncState()
getSyncState() => Promise<{ state: SyncState; }>Returns: Promise<{ state: SyncState; }>
createRoom(...)
createRoom(options: { name?: string; topic?: string; isEncrypted?: boolean; isDirect?: boolean; invite?: string[]; preset?: 'private_chat' | 'trusted_private_chat' | 'public_chat'; historyVisibility?: 'invited' | 'joined' | 'shared' | 'world_readable'; }) => Promise<{ roomId: string; }>| Param | Type |
| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| options | { name?: string; topic?: string; isEncrypted?: boolean; isDirect?: boolean; invite?: string[]; preset?: 'private_chat' | 'trusted_private_chat' | 'public_chat'; historyVisibility?: 'invited' | 'joined' | 'shared' | 'world_readable'; } |
Returns: Promise<{ roomId: string; }>
getRooms()
getRooms() => Promise<{ rooms: RoomSummary[]; }>Returns: Promise<{ rooms: RoomSummary[]; }>
getRoomMembers(...)
getRoomMembers(options: { roomId: string; }) => Promise<{ members: RoomMember[]; }>| Param | Type |
| ------------- | -------------------------------- |
| options | { roomId: string; } |
Returns: Promise<{ members: RoomMember[]; }>
joinRoom(...)
joinRoom(options: { roomIdOrAlias: string; }) => Promise<{ roomId: string; }>| Param | Type |
| ------------- | --------------------------------------- |
| options | { roomIdOrAlias: string; } |
Returns: Promise<{ roomId: string; }>
leaveRoom(...)
leaveRoom(options: { roomId: string; }) => Promise<void>| Param | Type |
| ------------- | -------------------------------- |
| options | { roomId: string; } |
forgetRoom(...)
forgetRoom(options: { roomId: string; }) => Promise<void>| Param | Type |
| ------------- | -------------------------------- |
| options | { roomId: string; } |
sendMessage(...)
sendMessage(options: SendMessageOptions) => Promise<{ eventId: string; }>| Param | Type |
| ------------- | ----------------------------------------------------------------- |
| options | SendMessageOptions |
Returns: Promise<{ eventId: string; }>
editMessage(...)
editMessage(options: EditMessageOptions) => Promise<{ eventId: string; }>| Param | Type |
| ------------- | ----------------------------------------------------------------- |
| options | EditMessageOptions |
Returns: Promise<{ eventId: string; }>
sendReply(...)
sendReply(options: SendReplyOptions) => Promise<{ eventId: string; }>| Param | Type |
| ------------- | ------------------------------------------------------------- |
| options | SendReplyOptions |
Returns: Promise<{ eventId: string; }>
getRoomMessages(...)
getRoomMessages(options: { roomId: string; limit?: number; from?: string; }) => Promise<{ events: MatrixEvent[]; nextBatch?: string; }>| Param | Type |
| ------------- | --------------------------------------------------------------- |
| options | { roomId: string; limit?: number; from?: string; } |
Returns: Promise<{ events: MatrixEvent[]; nextBatch?: string; }>
markRoomAsRead(...)
markRoomAsRead(options: { roomId: string; eventId: string; }) => Promise<void>| Param | Type |
| ------------- | ------------------------------------------------- |
| options | { roomId: string; eventId: string; } |
refreshEventStatuses(...)
refreshEventStatuses(options: { roomId: string; eventIds: string[]; }) => Promise<{ events: MatrixEvent[]; }>| Param | Type |
| ------------- | ---------------------------------------------------- |
| options | { roomId: string; eventIds: string[]; } |
Returns: Promise<{ events: MatrixEvent[]; }>
redactEvent(...)
redactEvent(options: { roomId: string; eventId: string; reason?: string; }) => Promise<void>| Param | Type |
| ------------- | ------------------------------------------------------------------ |
| options | { roomId: string; eventId: string; reason?: string; } |
sendReaction(...)
sendReaction(options: { roomId: string; eventId: string; key: string; }) => Promise<{ eventId: string; }>| Param | Type |
| ------------- | -------------------------------------------------------------- |
| options | { roomId: string; eventId: string; key: string; } |
Returns: Promise<{ eventId: string; }>
setRoomName(...)
setRoomName(options: { roomId: string; name: string; }) => Promise<void>| Param | Type |
| ------------- | ---------------------------------------------- |
| options | { roomId: string; name: string; } |
setRoomTopic(...)
setRoomTopic(options: { roomId: string; topic: string; }) => Promise<void>| Param | Type |
| ------------- | ----------------------------------------------- |
| options | { roomId: string; topic: string; } |
setRoomAvatar(...)
setRoomAvatar(options: { roomId: string; mxcUrl: string; }) => Promise<void>| Param | Type |
| ------------- | ------------------------------------------------ |
| options | { roomId: string; mxcUrl: string; } |
inviteUser(...)
inviteUser(options: { roomId: string; userId: string; }) => Promise<void>| Param | Type |
| ------------- | ------------------------------------------------ |
| options | { roomId: string; userId: string; } |
kickUser(...)
kickUser(options: { roomId: string; userId: string; reason?: string; }) => Promise<void>| Param | Type |
| ------------- | ----------------------------------------------------------------- |
| options | { roomId: string; userId: string; reason?: string; } |
banUser(...)
banUser(options: { roomId: string; userId: string; reason?: string; }) => Promise<void>| Param | Type |
| ------------- | ----------------------------------------------------------------- |
| options | { roomId: string; userId: string; reason?: string; } |
unbanUser(...)
unbanUser(options: { roomId: string; userId: string; }) => Promise<void>| Param | Type |
| ------------- | ------------------------------------------------ |
| options | { roomId: string; userId: string; } |
sendTyping(...)
sendTyping(options: { roomId: string; isTyping: boolean; timeout?: number; }) => Promise<void>| Param | Type |
| ------------- | --------------------------------------------------------------------- |
| options | { roomId: string; isTyping: boolean; timeout?: number; } |
getMediaUrl(...)
getMediaUrl(options: { mxcUrl: string; }) => Promise<{ httpUrl: string; }>| Param | Type |
| ------------- | -------------------------------- |
| options | { mxcUrl: string; } |
Returns: Promise<{ httpUrl: string; }>
getThumbnailUrl(...)
getThumbnailUrl(options: ThumbnailUrlOptions) => Promise<{ httpUrl: string; }>| Param | Type |
| ------------- | ------------------------------------------------------------------- |
| options | ThumbnailUrlOptions |
Returns: Promise<{ httpUrl: string; }>
uploadContent(...)
uploadContent(options: UploadContentOptions) => Promise<UploadContentResult>| Param | Type |
| ------------- | --------------------------------------------------------------------- |
| options | UploadContentOptions |
Returns: Promise<UploadContentResult>
searchUsers(...)
searchUsers(options: { searchTerm: string; limit?: number; }) => Promise<{ results: UserProfile[]; limited: boolean; }>| Param | Type |
| ------------- | ---------------------------------------------------- |
| options | { searchTerm: string; limit?: number; } |
Returns: Promise<{ results: UserProfile[]; limited: boolean; }>
setPresence(...)
setPresence(options: { presence: 'online' | 'offline' | 'unavailable'; statusMsg?: string; }) => Promise<void>| Param | Type |
| ------------- | -------------------------------------------------------------------------------------- |
| options | { presence: 'online' | 'offline' | 'unavailable'; statusMsg?: string; } |
getPresence(...)
getPresence(options: { userId: string; }) => Promise<PresenceInfo>| Param | Type |
| ------------- | -------------------------------- |
| options | { userId: string; } |
Returns: Promise<PresenceInfo>
getDevices()
getDevices() => Promise<{ devices: DeviceInfo[]; }>Returns: Promise<{ devices: DeviceInfo[]; }>
deleteDevice(...)
deleteDevice(options: { deviceId: string; auth?: Record<string, unknown>; }) => Promise<void>| Param | Type |
| ------------- | ---------------------------------------------------------------------------------------------- |
| options | { deviceId: string; auth?: Record<string, unknown>; } |
verifyDevice(...)
verifyDevice(options: { deviceId: string; }) => Promise<void>| Param | Type |
| ------------- | ---------------------------------- |
| options | { deviceId: string; } |
setPusher(...)
setPusher(options: PusherOptions) => Promise<void>| Param | Type |
| ------------- | ------------------------------------------------------- |
| options | PusherOptions |
initializeCrypto()
initializeCrypto() => Promise<void>getEncryptionStatus()
getEncryptionStatus() => Promise<EncryptionStatus>Returns: Promise<EncryptionStatus>
bootstrapCrossSigning()
bootstrapCrossSigning() => Promise<void>setupKeyBackup()
setupKeyBackup() => Promise<KeyBackupStatus>Returns: Promise<KeyBackupStatus>
getKeyBackupStatus()
getKeyBackupStatus() => Promise<KeyBackupStatus>Returns: Promise<KeyBackupStatus>
restoreKeyBackup(...)
restoreKeyBackup(options?: { recoveryKey?: string | undefined; } | undefined) => Promise<{ importedKeys: number; }>| Param | Type |
| ------------- | -------------------------------------- |
| options | { recoveryKey?: string; } |
Returns: Promise<{ importedKeys: number; }>
setupRecovery(...)
setupRecovery(options?: { passphrase?: string | undefined; existingPassphrase?: string | undefined; } | undefined) => Promise<RecoveryKeyInfo>| Param | Type |
| ------------- | ------------------------------------------------------------------ |
| options | { passphrase?: string; existingPassphrase?: string; } |
Returns: Promise<RecoveryKeyInfo>
clearAllData()
clearAllData() => Promise<void>Wipe all local Matrix state (crypto DB, session, caches).
isRecoveryEnabled()
isRecoveryEnabled() => Promise<{ enabled: boolean; }>Returns: Promise<{ enabled: boolean; }>
recoverAndSetup(...)
recoverAndSetup(options: { recoveryKey?: string; passphrase?: string; }) => Promise<void>| Param | Type |
| ------------- | ----------------------------------------------------------- |
| options | { recoveryKey?: string; passphrase?: string; } |
resetRecoveryKey(...)
resetRecoveryKey(options?: { passphrase?: string | undefined; } | undefined) => Promise<RecoveryKeyInfo>| Param | Type |
| ------------- | ------------------------------------- |
| options | { passphrase?: string; } |
Returns: Promise<RecoveryKeyInfo>
exportRoomKeys(...)
exportRoomKeys(options: { passphrase: string; }) => Promise<{ data: string; }>| Param | Type |
| ------------- | ------------------------------------ |
| options | { passphrase: string; } |
Returns: Promise<{ data: string; }>
importRoomKeys(...)
importRoomKeys(options: { data: string; passphrase: string; }) => Promise<{ importedKeys: number; }>| Param | Type |
| ------------- | -------------------------------------------------- |
| options | { data: string; passphrase: string; } |
Returns: Promise<{ importedKeys: number; }>
addListener('syncStateChange', ...)
addListener(event: 'syncStateChange', listenerFunc: (data: SyncStateChangeEvent) => void) => Promise<PluginListenerHandle>| Param | Type |
| ------------------ | ---------------------------------------------------------------------------------------- |
| event | 'syncStateChange' |
| listenerFunc | (data: SyncStateChangeEvent) => void |
Returns: Promise<PluginListenerHandle>
addListener('messageReceived', ...)
addListener(event: 'messageReceived', listenerFunc: (data: MessageReceivedEvent) => void) => Promise<PluginListenerHandle>| Param | Type |
| ------------------ | ---------------------------------------------------------------------------------------- |
| event | 'messageReceived' |
| listenerFunc | (data: MessageReceivedEvent) => void |
Returns: Promise<PluginListenerHandle>
addListener('roomUpdated', ...)
addListener(event: 'roomUpdated', listenerFunc: (data: RoomUpdatedEvent) => void) => Promise<PluginListenerHandle>| Param | Type |
| ------------------ | -------------------------------------------------------------------------------- |
| event | 'roomUpdated' |
| listenerFunc | (data: RoomUpdatedEvent) => void |
Returns: Promise<PluginListenerHandle>
addListener('typingChanged', ...)
addListener(event: 'typingChanged', listenerFunc: (data: TypingEvent) => void) => Promise<PluginListenerHandle>| Param | Type |
| ------------------ | ---------------------------------------------------------------------- |
| event | 'typingChanged' |
| listenerFunc | (data: TypingEvent) => void |
Returns: Promise<PluginListenerHandle>
addListener('receiptReceived', ...)
addListener(event: 'receiptReceived', listenerFunc: (data: ReceiptReceivedEvent) => void) => Promise<PluginListenerHandle>| Param | Type |
| ------------------ | ---------------------------------------------------------------------------------------- |
| event | 'receiptReceived' |
| listenerFunc | (data: ReceiptReceivedEvent) => void |
Returns: Promise<PluginListenerHandle>
addListener('presenceChanged', ...)
addListener(event: 'presenceChanged', listenerFunc: (data: PresenceChangedEvent) => void) => Promise<PluginListenerHandle>| Param | Type |
| ------------------ | ---------------------------------------------------------------------------------------- |
| event | 'presenceChanged' |
| listenerFunc | (data: PresenceChangedEvent) => void |
Returns: Promise<PluginListenerHandle>
removeAllListeners()
removeAllListeners() => Promise<void>Interfaces
SessionInfo
| Prop | Type |
| ------------------- | ------------------- |
| accessToken | string |
| userId | string |
| deviceId | string |
| homeserverUrl | string |
LoginOptions
| Prop | Type |
| ------------------- | ------------------- |
| homeserverUrl | string |
| userId | string |
| password | string |
LoginWithTokenOptions
| Prop | Type |
| ------------------- | ------------------- |
| homeserverUrl | string |
| accessToken | string |
| userId | string |
| deviceId | string |
RoomSummary
| Prop | Type |
| ----------------- | --------------------------------------------------- |
| roomId | string |
| name | string |
| topic | string |
| memberCount | number |
| isEncrypted | boolean |
| unreadCount | number |
| lastEventTs | number |
| membership | 'join' | 'invite' | 'leave' | 'ban' |
| avatarUrl | string |
| isDirect | boolean |
RoomMember
| Prop | Type |
| ----------------- | --------------------------------------------------- |
| userId | string |
| displayName | string |
| membership | 'join' | 'invite' | 'leave' | 'ban' |
| avatarUrl | string |
SendMessageOptions
| Prop | Type | Description |
| -------------- | --------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- |
| roomId | string | |
| body | string | |
| msgtype | 'm.text' | 'm.notice' | 'm.emote' | 'm.image' | 'm.audio' | 'm.video' | 'm.file' | |
| fileUri | string | |
| fileName | string | |
| mimeType | string | |
| fileSize | number | |
| duration | number | Audio/video duration in milliseconds (sets info.duration per Matrix spec) |
| width | number | Image/video width in pixels (sets info.w per Matrix spec) |
| height | number | Image/video height in pixels (sets info.h per Matrix spec) |
EditMessageOptions
| Prop | Type | Description |
| -------------- | --------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------- |
| roomId | string | |
| eventId | string | |
| newBody | string | |
| msgtype | 'm.text' | 'm.notice' | 'm.emote' | 'm.image' | 'm.audio' | 'm.video' | 'm.file' | Required when editing a media message; must match the original msgtype |
| fileUri | string | New file to replace the media content (optional for caption-only edits) |
| fileName | string | |
| mimeType | string | |
| fileSize | number | |
| duration | number | Audio/video duration in milliseconds |
| width | number | Image/video width in pixels |
| height | number | Image/video height in pixels |
SendReplyOptions
| Prop | Type | Description |
| -------------------- | --------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- |
| roomId | string | |
| body | string | |
| replyToEventId | string | |
| msgtype | 'm.text' | 'm.notice' | 'm.emote' | 'm.image' | 'm.audio' | 'm.video' | 'm.file' | |
| fileUri | string | |
| fileName | string | |
| mimeType | string | |
| fileSize | number | |
| duration | number | Audio/video duration in milliseconds (sets info.duration per Matrix spec) |
| width | number | Image/video width in pixels (sets info.w per Matrix spec) |
| height | number | Image/video height in pixels (sets info.h per Matrix spec) |
MatrixEvent
| Prop | Type | Description |
| -------------------- | ---------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
| eventId | string | |
| roomId | string | |
| senderId | string | |
| type | string | |
| content | Record<string, unknown> | |
| originServerTs | number | |
| status | 'sending' | 'sent' | 'delivered' | 'read' | Delivery/read status for own messages: 'sending' | 'sent' | 'delivered' | 'read' |
| readBy | string[] | User IDs that have read this event |
| unsigned | Record<string, unknown> | Unsigned data (e.g. m.relations for edits, transaction_id for local echo) |
ThumbnailUrlOptions
| Prop | Type |
| ------------ | ------------------------------ |
| mxcUrl | string |
| width | number |
| height | number |
| method | 'scale' | 'crop' |
UploadContentResult
| Prop | Type |
| ---------------- | ------------------- |
| contentUri | string |
UploadContentOptions
| Prop | Type |
| -------------- | ------------------- |
| fileUri | string |
| fileName | string |
| mimeType | string |
UserProfile
| Prop | Type |
| ----------------- | ------------------- |
| userId | string |
| displayName | string |
| avatarUrl | string |
PresenceInfo
| Prop | Type |
| ------------------- | --------------------------------------------------- |
| presence | 'online' | 'offline' | 'unavailable' |
| statusMsg | string |
| lastActiveAgo | number |
DeviceInfo
| Prop | Type | Description |
| ---------------------------- | -------------------- | ------------------------------------------------- |
| deviceId | string | |
| displayName | string | |
| lastSeenTs | number | |
| lastSeenIp | string | |
| isCrossSigningVerified | boolean | Whether this device is verified via cross-signing |
PusherOptions
| Prop | Type |
| ----------------------- | ---------------------------------------------- |
| pushkey | string |
| kind | string | null |
| appId | string |
| appDisplayName | string |
| deviceDisplayName | string |
| lang | string |
| data | { url: string; format?: string; } |
EncryptionStatus
| Prop | Type |
| -------------------------- | ----------------------------------------------------------------- |
| isCrossSigningReady | boolean |
| crossSigningStatus | CrossSigningStatus |
| isKeyBackupEnabled | boolean |
| keyBackupVersion | string |
| isSecretStorageReady | boolean |
CrossSigningStatus
| Prop | Type |
| -------------------- | -------------------- |
| hasMaster | boolean |
| hasSelfSigning | boolean |
| hasUserSigning | boolean |
| isReady | boolean |
KeyBackupStatus
| Prop | Type |
| ------------- | -------------------- |
| exists | boolean |
| version | string |
| enabled | boolean |
RecoveryKeyInfo
| Prop | Type |
| ----------------- | ------------------- |
| recoveryKey | string |
PluginListenerHandle
| Prop | Type |
| ------------ | ----------------------------------------- |
| remove | () => Promise<void> |
SyncStateChangeEvent
| Prop | Type |
| ----------- | ----------------------------------------------- |
| state | SyncState |
| error | string |
MessageReceivedEvent
| Prop | Type |
| ----------- | --------------------------------------------------- |
| event | MatrixEvent |
RoomUpdatedEvent
| Prop | Type |
| ------------- | --------------------------------------------------- |
| roomId | string |
| summary | RoomSummary |
TypingEvent
| Prop | Type |
| ------------- | --------------------- |
| roomId | string |
| userIds | string[] |
ReceiptReceivedEvent
| Prop | Type | Description |
| ------------- | ------------------- | ---------------------------------- |
| roomId | string | |
| eventId | string | The event that was read |
| userId | string | The user who sent the read receipt |
PresenceChangedEvent
| Prop | Type |
| -------------- | ----------------------------------------------------- |
| userId | string |
| presence | PresenceInfo |
Type Aliases
SyncState
'INITIAL' | 'SYNCING' | 'ERROR' | 'STOPPED'
Record
Construct a type with a set of properties K of type T
{ [P in K]: T; }
Development
Setup
npm installBuild
npm run buildTest
npm test # run once
npm run test:watch # watch modeThe test suite covers the web layer (~98 tests) using Vitest with jsdom, mocking matrix-js-sdk at the module level.
Verify All Platforms
npm run verify # builds + tests web, builds Android, builds iOS
npm run verify:web # web only
npm run verify:android
npm run verify:iosLint & Format
npm run lint # check
npm run fmt # auto-fixExample App
An example app is included in example-app/ for manual testing against a local homeserver:
cd example-app
npm install
npm run devLicense
MIT
