TypeScript/Node.js SDK for integrating your backend with the Ethora chat service platform. This SDK provides a clean, type-safe interface for managing chat rooms, users, and authentication tokens.
- Installation
- Quick Start
- Configuration
- API Reference
- Examples
- Architecture
- Error Handling
- Contributing
npm install @ethora/sdk-backend-integration
# or
yarn add @ethora/sdk-backend-integration- Node.js 18+ or higher
- TypeScript 5.0+ (for TypeScript projects)
Create a .env file or set the following environment variables:
ETHORA_CHAT_API_URL=https://api.ethoradev.com
ETHORA_CHAT_APP_ID=your_app_id
ETHORA_CHAT_APP_SECRET=your_app_secretimport { getChatRepositoryImpl } from '@ethora/sdk-backend-integration';
// Get repository instance
const chatRepo = getChatRepositoryImpl();
// Create a chat room for a workspace
const workspaceId = '123e4567-e89b-12d3-a456-426614174000';
await chatRepo.createChatRoom(workspaceId);
// Create a user
const userId = 'user-123';
await chatRepo.createUser(userId);
// Grant user access to chat room
await chatRepo.grantUserAccessToChatRoom(workspaceId, userId);
// Generate client JWT token for frontend
const clientToken = chatRepo.createChatUserJwtToken(userId);| Variable | Description | Required |
|---|---|---|
ETHORA_CHAT_API_URL |
Base URL for Ethora chat API | Yes |
ETHORA_CHAT_APP_ID |
Your Ethora application ID | Yes |
ETHORA_CHAT_APP_SECRET |
Secret key for JWT token generation | Yes |
You can also provide custom configuration by implementing your own secrets provider:
import { getSecrets } from '@ethora/sdk-backend-integration';
// The SDK uses environment variables by default
// You can override getSecrets() to use a secrets managerThe main interface for interacting with the Ethora chat service.
Generates a fully-qualified chat room JID from a workspace ID.
Parameters:
workspaceId(UUID): The unique identifier of the workspacefull(boolean, optional): Whether to include the full JID domain. Default:true
Returns: The fully-qualified JID string for the chat room
Example:
const chatName = chatRepo.createChatName(workspaceId, true);
// Returns: "appId_workspaceId@conference.xmpp.ethoradev.com"Creates a client-side JWT token for a specific user ID. This token can be used for client-side authentication with the chat service.
Parameters:
userId(UUID): The unique identifier of the user
Returns: The encoded JWT token for client-side authentication
Example:
const token = chatRepo.createChatUserJwtToken(userId);
// Use this token in your frontend applicationCreates a user in the chat service.
Parameters:
userId(UUID): The unique identifier of the useruserData(optional): Additional user data to include
Returns: Promise resolving to the API response
Example:
const response = await chatRepo.createUser(userId, {
displayName: 'John Doe',
email: 'john@example.com'
});Creates a chat room for a workspace.
Parameters:
workspaceId(UUID): The unique identifier of the workspaceroomData(optional): Additional room configuration data
Returns: Promise resolving to the API response
Example:
const response = await chatRepo.createChatRoom(workspaceId, {
description: 'Workspace chat room',
isPublic: false
});Grants a user access to a specific chat room.
Parameters:
workspaceId(UUID): The unique identifier of the workspaceuserId(UUID): The unique identifier of the user
Returns: Promise resolving to the API response
Example:
await chatRepo.grantUserAccessToChatRoom(workspaceId, userId);Grants chatbot access to a chat room.
Parameters:
workspaceId(UUID): The unique identifier of the workspace
Returns: Promise resolving to the API response
Example:
await chatRepo.grantChatbotAccessToChatRoom(workspaceId);Deletes multiple users from the chat service.
Parameters:
userIds(UUID[]): Array of user IDs to delete
Returns: Promise resolving to the API response
Example:
await chatRepo.deleteUsers([userId1, userId2, userId3]);Deletes a chat room from the chat service. Gracefully handles the case where the chat room doesn't exist.
Parameters:
workspaceId(UUID): The unique identifier of the workspace
Returns: Promise resolving to the API response
Example:
const response = await chatRepo.deleteChatRoom(workspaceId);
// Returns { ok: false, reason: "Chat room not found" } if room doesn't existSee the examples/ directory for complete working examples:
basic-usage.ts- Basic SDK usage patternsexpress-integration.ts- Express.js API integration
import { getChatRepositoryImpl } from '@ethora/sdk-backend-integration';
async function setupWorkspaceChat(workspaceId: string, userIds: string[]) {
const chatRepo = getChatRepositoryImpl();
try {
// 1. Create chat room
await chatRepo.createChatRoom(workspaceId);
console.log('Chat room created');
// 2. Create users
for (const userId of userIds) {
await chatRepo.createUser(userId);
console.log(`User ${userId} created`);
}
// 3. Grant users access to chat room
for (const userId of userIds) {
await chatRepo.grantUserAccessToChatRoom(workspaceId, userId);
console.log(`Access granted to user ${userId}`);
}
// 4. Grant chatbot access
await chatRepo.grantChatbotAccessToChatRoom(workspaceId);
console.log('Chatbot access granted');
return { success: true };
} catch (error) {
console.error('Error setting up workspace chat:', error);
throw error;
}
}import { getChatRepositoryImpl } from '@ethora/sdk-backend-integration';
function generateClientTokens(userIds: string[]): Record<string, string> {
const chatRepo = getChatRepositoryImpl();
const tokens: Record<string, string> = {};
for (const userId of userIds) {
tokens[userId] = chatRepo.createChatUserJwtToken(userId);
}
return tokens;
}
// Usage in API endpoint
app.get('/api/chat/tokens/:userId', (req, res) => {
const { userId } = req.params;
const token = chatRepo.createChatUserJwtToken(userId);
res.json({ token });
});async function cleanupWorkspace(workspaceId: string, userIds: string[]) {
const chatRepo = getChatRepositoryImpl();
try {
// Delete chat room (handles non-existent rooms gracefully)
await chatRepo.deleteChatRoom(workspaceId);
console.log('Chat room deleted');
// Delete users
if (userIds.length > 0) {
await chatRepo.deleteUsers(userIds);
console.log('Users deleted');
}
} catch (error) {
console.error('Error during cleanup:', error);
throw error;
}
}import express from 'express';
import { getChatRepositoryImpl } from '@ethora/sdk-backend-integration';
const app = express();
const chatRepo = getChatRepositoryImpl();
app.post('/workspaces/:workspaceId/chat', async (req, res) => {
try {
const { workspaceId } = req.params;
const response = await chatRepo.createChatRoom(workspaceId);
res.json(response);
} catch (error) {
res.status(500).json({ error: 'Failed to create chat room' });
}
});
app.post('/workspaces/:workspaceId/chat/users/:userId', async (req, res) => {
try {
const { workspaceId, userId } = req.params;
await chatRepo.grantUserAccessToChatRoom(workspaceId, userId);
res.json({ success: true });
} catch (error) {
res.status(500).json({ error: 'Failed to grant access' });
}
});src/
├── types/ # TypeScript type definitions
│ └── index.ts
├── config/ # Configuration management
│ └── secrets.ts
├── utils/ # Utility functions
│ ├── logger.ts # Logging utilities
│ └── jwt.ts # JWT token utilities
├── repositories/ # Repository implementations
│ └── ChatRepositoryImpl.ts
└── index.ts # Main entry point
- Types (
src/types/): TypeScript interfaces and type definitions - Configuration (
src/config/): Secrets and configuration management - Utilities (
src/utils/):- Logger: Structured logging with different log levels
- JWT: Token creation and verification utilities
- Repositories (
src/repositories/): Concrete implementations of repository interfaces
- Repository Pattern: Abstracts data access logic
- Singleton Pattern: Repository instance management
- Dependency Injection: Configurable dependencies
- Factory Pattern: Instance creation functions
The SDK uses Axios for HTTP requests and throws AxiosError for API-related errors. Always wrap SDK calls in try-catch blocks:
try {
await chatRepo.createChatRoom(workspaceId);
} catch (error) {
if (axios.isAxiosError(error)) {
console.error('API Error:', error.response?.status, error.response?.data);
} else {
console.error('Unexpected error:', error);
}
}The deleteChatRoom method gracefully handles non-existent rooms:
const response = await chatRepo.deleteChatRoom(workspaceId);
if (response.reason === 'Chat room not found') {
// Room was already deleted or never existed
console.log('Room not found, continuing...');
}- JWT Tokens: Never expose your
ETHORA_CHAT_APP_SECRETin client-side code - Environment Variables: Use a secrets manager in production
- Token Validation: Always validate tokens on the server side
- HTTPS: Always use HTTPS in production environments
npm run buildnpm run build:watchThe project uses strict TypeScript settings. See tsconfig.json for details.
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests if applicable
- Submit a pull request
Apache 2.0
For issues and questions, please open an issue on the GitHub repository.