@noematicsllc/talk-sdk
v0.2.0
Published
UNOFFICIAL TypeScript SDK for Nextcloud Talk API - Not affiliated with or endorsed by Nextcloud
Downloads
245
Maintainers
Readme
@noematicsllc/talk-sdk
⚠️ UNOFFICIAL SDK: This is an unofficial, community-maintained TypeScript SDK for the Nextcloud Talk API. This package is NOT affiliated with, endorsed by, or connected to Nextcloud GmbH or the Nextcloud project. Use at your own risk.
TypeScript SDK for the Nextcloud Talk API.
Installation
npm install @noematicsllc/talk-sdk
# or
pnpm add @noematicsllc/talk-sdkQuick Start
import { TalkClient } from '@noematicsllc/talk-sdk';
const client = new TalkClient({
host: 'https://nextcloud.local',
username: 'admin',
password: 'app-password'
});
// List all rooms
const rooms = await client.rooms.list();
// Find a room by token
const targetRoom = rooms.find(r => r.token === 'abcdefgh');
// Send a message
await targetRoom.sendMessage("Automated system check initialized.");Architecture
The SDK uses a 4-layer architecture:
1. Transport Layer (HttpClient)
Base HTTP client using the native Fetch API. Automatically injects mandatory OCS headers:
OCS-APIRequest: trueAccept: application/jsonAuthorization: Basic ...
2. Resource Layer
Logical modules mapped to specific API versions:
| Resource | API Version | Base Path |
|----------|-------------|-----------|
| RoomResource | v4 | /api/v4/room |
| ParticipantResource | v4 | /api/v4/room/{token}/participants |
| CallResource | v4 | /api/v4/call |
| SignalingResource | v3 | /api/v3/signaling |
| ChatResource | v1 | /api/v1/chat |
| PollResource | v1 | /api/v1/poll |
| ReactionResource | v1 | /api/v1/reaction |
3. Normalization Layer
DTO mappers that strip the ocs.meta and ocs.data envelopes, returning clean, flat objects.
4. Domain Layer
High-level entities like Room that encapsulate both the token (string) and id (integer) to handle the API's identifier inconsistencies.
Room Entity
The Room class provides a high-level interface for room operations:
const room = await client.rooms.get('abcdefgh');
// Chat
await room.sendMessage("Hello!");
const messages = await room.getHistory({ limit: 50 });
const result = await room.pollMessages({ lastKnownMessageId: 123 });
// Participants
const participants = await room.getParticipants();
await room.addParticipant('user-id');
// Calls
await room.joinCall({ flags: 7 });
const peers = await room.getCallPeers();
await room.leaveCall();
// Polls
await room.createPoll({
question: "What's for lunch?",
options: ["Pizza", "Sushi", "Tacos"]
});
// Reactions
await room.addReaction(messageId, "👍");Video Calls
⚠️ Experimental/Beta Feature: The video call functionality (WebRTC, signaling, and
VideoCallAPI) is currently in beta/experimental status. While the core implementation is complete, it has not been extensively tested in production environments. We recommend thorough testing before using in production applications. The API may change in future versions based on feedback and real-world usage.
Basic Video Call Setup
import { TalkClient, isWebRTCSupported } from '@noematicsllc/talk-sdk';
// Check browser compatibility first
if (!isWebRTCSupported()) {
console.error('WebRTC is not supported in this browser');
return;
}
const client = new TalkClient({
host: 'https://nextcloud.local',
username: 'admin',
password: 'app-password'
});
// Start a video call
const videoCall = client.startVideoCall('abc123');
// Join with media
await videoCall.join({
video: true,
audio: true,
video: { width: 1280, height: 720 } // Optional video constraints
});
// Control media
await videoCall.setVideoEnabled(false);
await videoCall.setAudioEnabled(true);
// Leave call
await videoCall.leave();Custom UI Composability
The VideoCall API is designed for full UI composability - you control how streams are rendered:
Event-Based Rendering
const videoCall = client.startVideoCall('abc123');
// Render each participant's stream in a separate window
videoCall.on('stream', (stream, peer) => {
const window = window.open('', `peer-${peer.sessionId}`, 'width=640,height=480');
if (window) {
const video = window.document.createElement('video');
video.srcObject = stream;
video.autoplay = true;
video.playsInline = true;
window.document.body.appendChild(video);
}
});
// Handle peer join/leave
videoCall.on('peer-joined', (peer) => {
console.log(`${peer.displayName} joined the call`);
});
videoCall.on('peer-left', (peer) => {
console.log(`${peer.displayName} left the call`);
});
await videoCall.join({ video: true, audio: true });Direct Stream Access
// Get all peer streams and render them however you want
const streams = videoCall.getPeerStreams();
streams.forEach((stream, sessionId) => {
// Render in custom layout, separate windows, canvas, etc.
renderInCustomLayout(stream, sessionId);
});
// Get local stream for preview
const localStream = videoCall.getLocalStream();
if (localStream) {
previewElement.srcObject = localStream;
}Complete Custom UI Example
const videoCall = client.startVideoCall('abc123');
// Custom UI with separate windows for each participant
const participantWindows = new Map<string, Window>();
videoCall.on('stream', (stream, peer) => {
// Open new window for this participant
const win = window.open('', `peer-${peer.sessionId}`, 'width=640,height=480');
if (!win) return;
win.document.write(`
<!DOCTYPE html>
<html>
<head><title>${peer.displayName}</title></head>
<body style="margin:0;background:#000;">
<video autoplay playsinline style="width:100%;height:100%;object-fit:contain;"></video>
</body>
</html>
`);
win.document.querySelector('video')!.srcObject = stream;
participantWindows.set(peer.sessionId, win);
});
videoCall.on('peer-left', (peer) => {
const win = participantWindows.get(peer.sessionId);
if (win) {
win.close();
participantWindows.delete(peer.sessionId);
}
});
await videoCall.join({ video: true, audio: true });Low-Level API (Advanced Users)
Note: The low-level WebRTC APIs (
WebRTCManager,SignalingConnection) are also experimental and may change.
For advanced use cases, you can use the low-level WebRTC APIs directly:
import { WebRTCManager, SignalingConnection, getUserMedia } from '@noematicsllc/talk-sdk';
// Get signaling settings
const settings = await client.call.getSignalingSettings(token);
// Create signaling connection
const signaling = new SignalingConnection({
server: settings.server!,
token,
helloAuthParams: settings.helloAuthParams,
}, {
onMessage: (message) => {
// Handle signaling messages yourself
}
});
// Get local media
const localStream = await getUserMedia({ video: true, audio: true });
// Create WebRTC manager
const manager = new WebRTCManager({
signalingSettings: settings,
roomToken: token,
sessionId: 'your-session-id',
handlers: {
onStream: (stream, peer) => {
// Handle peer streams
}
}
});
manager.setLocalStream(localStream);
await manager.connect();
// Add peers
const peers = await client.call.getPeers(token);
for (const peer of peers) {
await manager.addPeer(peer);
}Browser Compatibility
Before using video calls, check browser support:
import { checkBrowserCompatibility, requireWebRTC } from '@noematicsllc/talk-sdk';
// Check compatibility
const compat = checkBrowserCompatibility();
if (!compat.webrtcSupported) {
console.error('WebRTC not supported:', compat.errors);
}
// Or throw error if not supported
requireWebRTC(); // Throws if not supportedMessage Polling
Implement efficient message polling using the spec's pattern:
let lastKnownMessageId = 0;
while (polling) {
const result = await room.pollMessages({
lastKnownMessageId,
timeout: 30, // Long-poll timeout
});
for (const message of result.messages) {
console.log(`${message.actorDisplayName}: ${message.message}`);
}
if (result.lastKnownMessageId) {
lastKnownMessageId = result.lastKnownMessageId;
}
}Direct Resource Access
For advanced use cases, access resources directly:
// Direct resource access
const roomData = await client.roomResource.get('token');
const messages = await client.chat.receiveMessages('token', {
lookIntoFuture: 0,
limit: 100,
});
// Raw HTTP access
const response = await client.http.get('/custom/endpoint');Types
All API types are exported for TypeScript users:
import {
TalkRoom,
TalkChatMessage,
TalkParticipant,
ConversationType,
ParticipantType,
Permission,
InCallFlag,
} from '@noematicsllc/talk-sdk';Error Handling
The SDK throws HttpClientError for API errors:
import { HttpClientError } from '@noematicsllc/talk-sdk';
try {
await client.rooms.get('invalid-token');
} catch (error) {
if (error instanceof HttpClientError) {
console.error(`HTTP ${error.status}: ${error.message}`);
console.error(`OCS Status: ${error.ocsStatus}`);
}
}Disclaimer
This is an unofficial, community-maintained TypeScript SDK for the Nextcloud Talk API.
- NOT affiliated with Nextcloud GmbH
- NOT endorsed by the Nextcloud project
- NOT officially supported by Nextcloud
- Maintained independently by the community
- Use at your own risk
For official Nextcloud resources and support, please visit nextcloud.com or the Nextcloud GitHub organization.
License
MIT
