@ixo/matrix
v1.2.3
Published
## Overview
Readme
@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
# Install using pnpm (recommended)
pnpm install @ixo/matrix
# Or using npm
npm install @ixo/matrix
# Or using yarn
yarn add @ixo/matrixConfiguration
The package requires several environment variables for proper operation:
Matrix Server
MATRIX_BASE_URL=https://your-matrix-server.com # Your Matrix homeserver URLOracle Admin Credentials
MATRIX_ORACLE_ADMIN_ACCESS_TOKEN=your_token # Admin access token
MATRIX_ORACLE_ADMIN_USER_ID=@admin:your.server # Admin user ID
MATRIX_ORACLE_ADMIN_PASSWORD=your_password # Password for cross-signingSecurity
MATRIX_RECOVERY_PHRASE=your_recovery_phrase # For secret storage & key backupStorage Paths (Optional)
All paths are created in the matrix-local-storage folder:
MATRIX_STORE_PATH=./matrix-store # General storage
MATRIX_SECRET_STORAGE_KEYS_PATH=./matrix-secret-storage # Secret keysEnvironment 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() {
// 1. Get the singleton instance
const manager = MatrixManager.getInstance();
// 2. Initialize the manager
await manager.init();
// 3. Create and join a room
const roomId = await manager.createRoomAndJoin({
did: 'did:ixo:123',
oracleName: 'myOracle',
userAccessToken: 'user_access_token',
});
// 4. Send a message
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
- Room Naming
// Rooms are named using a deterministic hash of DID and oracle name
const roomName = MatrixManager.generateRoomNameFromDidAndOracle(
'did:ixo:123',
'myOracle',
); // Results in format: 'ixo-{md5hash}'
// Room aliases are generated by replacing spaces with underscores
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
- Creating and Joining
// Create a room with all security features enabled
const roomId = await manager.createRoomAndJoin({
did: 'did:ixo:123',
oracleName: 'myOracle',
userAccessToken: 'user_token',
});- Access Control
// Check if a user has access to a room
const hasAccess = await manager.checkIsUserInRoom({
roomId,
userAccessToken: 'user_token',
});
// Get room by ID
const room = manager.getRoom(roomId);- Room Lifecycle
- 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:
// Get room ID from 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:
// Operations using Admin Token (automatically handled)
await manager.sendMessage({
roomId,
message: 'Hello World',
});
// Operations requiring User Token
// the user token is used only for joining the room -- the rest of the operations are handled by the admin token
await manager.createRoomAndJoin({
did: 'did:ixo:123',
oracleName: 'myOracle',
userAccessToken: 'user_token', // User token required
});
// Check if the user is in the room using the user token
await manager.checkIsUserInRoom({
roomId,
userAccessToken: 'user_token', // User token required
});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.
// Regular message
await manager.sendMessage({
roomId,
message: 'Hello World',
});
// Threaded reply
await manager.sendMessage({
roomId,
message: 'Reply',
threadId: 'original_message_id',
});
// Oracle admin message
await manager.sendMessage({
roomId,
message: 'Admin notification',
isOracleAdmin: true,
});State Management
Type-safe state management with validation:
interface ProjectState {
status: string;
lastUpdate: number;
}
// Set state
await manager.stateManager.setState<ProjectState>({
roomId,
stateKey: 'oracle_project',
data: {
status: 'active',
lastUpdate: Date.now(),
},
});
// Get state
const state = await manager.stateManager.getState<ProjectState>(
roomId,
'oracle_project',
);
// Update state
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';
// Create your graph
const workflow = new StateGraph(graphState)
.addNode('myNode', (state) => {
// Your node logic
})
.addEdge(START, 'myNode')
.addEdge('myNode', END);
// Compile the graph with Matrix checkpointing
const graph = workflow.compile({
checkpointer: new MatrixCheckpointSaver('your-graph-name'),
});API Reference
MatrixManager
The main interface for Matrix operations:
getInstance(): Get singleton instanceinit(): Initialize the managercreateRoomAndJoin(): Create and join a roomsendMessage(): Send a messagestop(): Cleanup resources
MatrixStateManager
Handles state management:
setState<T>(): Set typed stategetState<T>(): Get typed stateupdateState<T>(): Update existing statelistStateEvents<T>(): List all state events
Development
Testing
# Run unit tests
pnpm test
# Run integration tests
pnpm test:e2e
# Run with coverage
pnpm test:coverageError Handling
try {
await manager.sendMessage({
roomId,
message: 'Hello',
});
} catch (error) {
if (error instanceof MatrixError) {
// Handle Matrix-specific errors
console.error('Matrix error:', error.errcode);
} else {
// Handle other errors
console.error('General error:', error);
}
}License
Internal package - All rights reserved.
