@ixo/matrix
Overview
The @ixo/matrix package is a robust wrapper around the Matrix.org client SDK, specifically designed for the ixo-oracles ecosystem. It provides a secure, type-safe interface for managing Matrix communications with end-to-end encryption.
Key Features
- 🔐 End-to-end encrypted room management
- 💬 Secure messaging with threading support
- 🔄 Type-safe state management
- 🔑 Cross-signing and cryptographic key management
- 🏗️ Oracle-specific room naming and access control
- 📦 Local storage for crypto and general data
- ⚡ Singleton pattern for efficient resource management
Table of Contents
Getting Started
Installation
pnpm install @ixo/matrix
npm install @ixo/matrix
yarn add @ixo/matrix
Configuration
The package requires several environment variables for proper operation:
Matrix Server
MATRIX_BASE_URL=https://your-matrix-server.com
Oracle Admin Credentials
MATRIX_ORACLE_ADMIN_ACCESS_TOKEN=your_token
MATRIX_ORACLE_ADMIN_USER_ID=@admin:your.server
MATRIX_ORACLE_ADMIN_PASSWORD=your_password
Security
MATRIX_RECOVERY_PHRASE=your_recovery_phrase
Storage Paths (Optional)
All paths are created in the matrix-local-storage folder:
MATRIX_CRYPTO_STORE_PATH=./matrix-crypto-store
MATRIX_STORE_PATH=./matrix-store
MATRIX_SECRET_STORAGE_KEYS_PATH=./matrix-secret-storage
Environment Variables Explained
Cross-Signing and Security Variables
The package uses Matrix's cross-signing feature for enhanced security. This requires specific environment variables:
-
MATRIX_ORACLE_ADMIN_PASSWORD: Required for authenticating cross-signing key uploads. When setting up cross-signing, the package needs to upload device signing keys to the server. This operation requires authentication using the admin password.
-
MATRIX_RECOVERY_PHRASE: Used for:
- Creating and managing secret storage
- Generating recovery keys
- Restoring key backups
- Accessing encrypted data across devices
Prerequisites
- Access to a Matrix homeserver
- fs write permissions
Quick Start
import { MatrixManager } from '@ixo/matrix';
async function main() {
const manager = MatrixManager.getInstance();
await manager.init();
const roomId = await manager.createRoomAndJoin({
did: 'did:ixo:123',
oracleName: 'myOracle',
userAccessToken: 'user_access_token',
});
await manager.sendMessage({
roomId,
message: 'Hello World',
});
}
Core Concepts
Room Management
Rooms in the ixo-matrix ecosystem are secure, encrypted spaces for communication. Each room has:
- Unique DID-based identification
- Oracle-specific naming convention
- Controlled access permissions
- End-to-end encryption
Room Creation Process
const roomName = MatrixManager.generateRoomNameFromDidAndOracle(
'did:ixo:123',
'myOracle',
);
const roomAlias = MatrixManager.generateRoomAliasFromName(roomName);
- Room Configuration
Each room is created with specific security settings:
- Private visibility (not publicly listed)
- End-to-end encryption enabled (using m.megolm.v1.aes-sha2)
- Guest access forbidden
- Shared history visibility
- Admin power levels for specific operations:
- Kick: 9999
- Ban: 9999
- Invite: 9999
- Redact: 9999
const roomId = await manager.createRoomAndJoin({
did: 'did:ixo:123',
oracleName: 'myOracle',
userAccessToken: 'user_token',
});
const hasAccess = await manager.checkIsUserInRoom({
roomId,
userAccessToken: 'user_token',
});
const room = manager.getRoom(roomId);
- Rooms are created with encryption enabled by default
- Admin user is automatically given highest power level
- Initial state includes encryption, guest access, and history visibility settings
- Room can be found using DID and oracle name:
const existingRoomId = await manager.getRoomId({
did: 'did:ixo:123',
oracleName: 'myOracle',
});
Client Operations and User Tokens
The package uses two types of tokens for different operations:
1. Admin Token (MATRIX_ORACLE_ADMIN_ACCESS_TOKEN)
Used for:
- Sending messages in rooms
- Managing room state
- Setting up encryption
- Cross-signing operations
- Getting room information
- Managing room power levels
- Creating rooms
- Inviting users to rooms
2. User Token (Provided per operation)
Used only for:
- joining rooms
- Verifying room membership
Example usage:
await manager.sendMessage({
roomId,
message: 'Hello World',
});
await manager.createRoomAndJoin({
did: 'did:ixo:123',
oracleName: 'myOracle',
userAccessToken: 'user_token',
});
await manager.checkIsUserInRoom({
roomId,
userAccessToken: 'user_token',
});
Note: User tokens are temporary and automatically cleaned up after use. All other operations use the admin token internally.
Messaging
The package supports various message types and threading:
All the messages will be sent from the Oracle Admin client.
await manager.sendMessage({
roomId,
message: 'Hello World',
});
await manager.sendMessage({
roomId,
message: 'Reply',
threadId: 'original_message_id',
});
await manager.sendMessage({
roomId,
message: 'Admin notification',
isOracleAdmin: true,
});
State Management
Type-safe state management with validation:
interface ProjectState {
status: string;
lastUpdate: number;
}
await manager.stateManager.setState<ProjectState>({
roomId,
stateKey: 'oracle_project',
data: {
status: 'active',
lastUpdate: Date.now(),
},
});
const state = await manager.stateManager.getState<ProjectState>(
roomId,
'oracle_project',
);
await manager.stateManager.updateState<ProjectState>({
roomId,
stateKey: 'oracle_project',
data: {
status: 'completed',
},
});
LangChain Graph Checkpointing
The package provides a Matrix-based checkpointer implementation for LangChain graphs, allowing you to persist graph state in Matrix rooms:
import { MatrixCheckpointSaver } from '@ixo/matrix';
import { StateGraph } from '@langchain/langgraph';
const workflow = new StateGraph(graphState)
.addNode('myNode', (state) => {
})
.addEdge(START, 'myNode')
.addEdge('myNode', END);
const graph = workflow.compile({
checkpointer: new MatrixCheckpointSaver('your-graph-name'),
});
API Reference
MatrixManager
The main interface for Matrix operations:
getInstance(): Get singleton instance
init(): Initialize the manager
createRoomAndJoin(): Create and join a room
sendMessage(): Send a message
stop(): Cleanup resources
MatrixStateManager
Handles state management:
setState<T>(): Set typed state
getState<T>(): Get typed state
updateState<T>(): Update existing state
listStateEvents<T>(): List all state events
Development
Testing
pnpm test
pnpm test:e2e
pnpm test:coverage
Error Handling
try {
await manager.sendMessage({
roomId,
message: 'Hello',
});
} catch (error) {
if (error instanceof MatrixError) {
console.error('Matrix error:', error.errcode);
} else {
console.error('General error:', error);
}
}
License
Internal package - All rights reserved.