@ethora/sdk-backend 26.2.3 → 26.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +347 -110
- package/dist/repositories/EthoraSDKService.d.ts +42 -1
- package/dist/repositories/EthoraSDKService.d.ts.map +1 -1
- package/dist/repositories/EthoraSDKService.js +187 -15
- package/dist/repositories/EthoraSDKService.js.map +1 -1
- package/dist/scripts/test-logs.js +37 -10
- package/dist/scripts/test-logs.js.map +1 -1
- package/dist/types/index.d.ts +79 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/jwt.d.ts +4 -1
- package/dist/utils/jwt.d.ts.map +1 -1
- package/dist/utils/jwt.js +33 -7
- package/dist/utils/jwt.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
This guide will walk you through integrating the Ethora SDK into your existing Node.js backend application.
|
|
6
6
|
|
|
7
|
+
**Part of the [Ethora SDK ecosystem](https://github.com/dappros/ethora#ecosystem)** — see all SDKs, tools, and sample apps. Follow cross-SDK updates in the [Release Notes](https://github.com/dappros/ethora/blob/main/RELEASE-NOTES.md).
|
|
8
|
+
|
|
7
9
|
## Table of Contents
|
|
8
10
|
|
|
9
11
|
- [Prerequisites](#prerequisites)
|
|
@@ -36,6 +38,38 @@ Ethora exposes Swagger UI from every running backend instance at:
|
|
|
36
38
|
|
|
37
39
|
If you are running a separate staging instance, the same pattern applies (e.g. `https://api.asterotoken.com/api-docs/`).
|
|
38
40
|
|
|
41
|
+
## Tenant Admin / B2B Endpoints
|
|
42
|
+
|
|
43
|
+
The SDK also exposes the explicit tenant-admin surface added in the backend:
|
|
44
|
+
|
|
45
|
+
- `listApps()`, `getApp(appId)`, `createApp(appData)`, `deleteApp(appId)`
|
|
46
|
+
- `createUsersInApp(appId, payload)`, `getUsersBatchJob(appId, jobId)`, `deleteUsersInApp(appId, userIds)`
|
|
47
|
+
- `createChatRoomInApp(appId, chatId, roomData)`, `deleteChatRoomInApp(appId, chatId)`
|
|
48
|
+
- `grantUserAccessToChatRoomInApp(appId, chatId, userIds)`, `removeUserAccessFromChatRoomInApp(appId, chatId, userIds)`
|
|
49
|
+
- `getUserChatsInApp(appId, userId, params)`, `updateChatRoomInApp(appId, chatId, updateData)`
|
|
50
|
+
|
|
51
|
+
These helpers target explicit `/v2/apps/{appId}/...` routes so a parent-app / tenant backend can manage child apps without relying on implicit token scope.
|
|
52
|
+
|
|
53
|
+
## Token Types
|
|
54
|
+
|
|
55
|
+
The Ethora API uses several JWT/token types with different purposes:
|
|
56
|
+
|
|
57
|
+
- `B2B Server JWT`: used by this SDK automatically for server-to-server API calls. The backend accepts it primarily via `x-custom-token`, and many deployments also accept it in `Authorization: Bearer ...`.
|
|
58
|
+
- `Client JWT`: created by `createChatUserJwtToken(userId)` for client/chat credential flows only.
|
|
59
|
+
- `User JWT`: returned by Ethora login endpoints and used for user-session API calls outside this SDK's main server-to-server flow.
|
|
60
|
+
- `App JWT`: legacy app-scoped runtime token. Frontend/bootstrap login and sign-up flows now prefer explicit `appId`, while old app-token auth remains accepted for backward compatibility.
|
|
61
|
+
|
|
62
|
+
If you are using explicit tenant-admin routes like `/v2/apps/{appId}/...`, the intended token for backend integrations is `B2B Server JWT`.
|
|
63
|
+
|
|
64
|
+
## API Versioning
|
|
65
|
+
|
|
66
|
+
For new integrations, prefer `/v2/...` endpoints.
|
|
67
|
+
|
|
68
|
+
- Main runtime chat/user operations in this SDK use `/v2/...`.
|
|
69
|
+
- Explicit tenant-admin helpers use `/v2/apps/{appId}/...`.
|
|
70
|
+
- A few delete operations still map to legacy `/v1/...` endpoints because that is where backend parity currently exists.
|
|
71
|
+
- Frontend/bootstrap auth flows are moving toward explicit `appId` request context rather than relying on implicit app-token scope.
|
|
72
|
+
|
|
39
73
|
## Installation
|
|
40
74
|
|
|
41
75
|
### Step 1: Install the Package
|
|
@@ -141,10 +175,20 @@ export class ChatService {
|
|
|
141
175
|
// routes/chat.ts
|
|
142
176
|
import express, { Request, Response } from 'express';
|
|
143
177
|
import { getEthoraSDKService } from '@ethora/sdk-backend';
|
|
178
|
+
import type {
|
|
179
|
+
ChatRepository,
|
|
180
|
+
ApiResponse,
|
|
181
|
+
CreateChatRoomRequest,
|
|
182
|
+
CreateUserData,
|
|
183
|
+
UpdateUserData,
|
|
184
|
+
GetUsersQueryParams,
|
|
185
|
+
GetUserChatsQueryParams,
|
|
186
|
+
UUID
|
|
187
|
+
} from '@ethora/sdk-backend';
|
|
144
188
|
import axios from 'axios';
|
|
145
189
|
|
|
146
190
|
const router = express.Router();
|
|
147
|
-
const chatService = getEthoraSDKService();
|
|
191
|
+
const chatService: ChatRepository = getEthoraSDKService();
|
|
148
192
|
|
|
149
193
|
// Create a chat room for a workspace
|
|
150
194
|
router.post(
|
|
@@ -152,9 +196,9 @@ router.post(
|
|
|
152
196
|
async (req: Request, res: Response) => {
|
|
153
197
|
try {
|
|
154
198
|
const { workspaceId } = req.params;
|
|
155
|
-
const roomData = req.body;
|
|
199
|
+
const roomData: Partial<CreateChatRoomRequest> = req.body;
|
|
156
200
|
|
|
157
|
-
const response = await chatService.createChatRoom(workspaceId, {
|
|
201
|
+
const response: ApiResponse = await chatService.createChatRoom(workspaceId, {
|
|
158
202
|
title: roomData.title || `Chat Room ${workspaceId}`,
|
|
159
203
|
uuid: workspaceId,
|
|
160
204
|
type: roomData.type || 'group',
|
|
@@ -179,9 +223,9 @@ router.post(
|
|
|
179
223
|
router.post('/users/:userId', async (req: Request, res: Response) => {
|
|
180
224
|
try {
|
|
181
225
|
const { userId } = req.params;
|
|
182
|
-
const userData = req.body;
|
|
226
|
+
const userData: CreateUserData = req.body;
|
|
183
227
|
|
|
184
|
-
const response = await chatService.createUser(userId, userData);
|
|
228
|
+
const response: ApiResponse = await chatService.createUser(userId, userData);
|
|
185
229
|
res.json({ success: true, data: response });
|
|
186
230
|
} catch (error) {
|
|
187
231
|
if (axios.isAxiosError(error)) {
|
|
@@ -254,11 +298,11 @@ router.get('/users/:userId/chat-token', (req: Request, res: Response) => {
|
|
|
254
298
|
router.get('/users', async (req: Request, res: Response) => {
|
|
255
299
|
try {
|
|
256
300
|
const { chatName, xmppUsername } = req.query;
|
|
257
|
-
const params:
|
|
301
|
+
const params: GetUsersQueryParams = {};
|
|
258
302
|
if (chatName) params.chatName = String(chatName);
|
|
259
303
|
if (xmppUsername) params.xmppUsername = String(xmppUsername);
|
|
260
304
|
|
|
261
|
-
const response = await chatService.getUsers(
|
|
305
|
+
const response: ApiResponse = await chatService.getUsers(
|
|
262
306
|
Object.keys(params).length > 0 ? params : undefined,
|
|
263
307
|
);
|
|
264
308
|
res.json({ success: true, data: response });
|
|
@@ -277,17 +321,12 @@ router.get('/users', async (req: Request, res: Response) => {
|
|
|
277
321
|
// Update users (batch)
|
|
278
322
|
router.patch('/users', async (req: Request, res: Response) => {
|
|
279
323
|
try {
|
|
280
|
-
const { users } = req.body;
|
|
324
|
+
const { users } = req.body as { users: UpdateUserData[] };
|
|
281
325
|
if (!Array.isArray(users) || users.length === 0) {
|
|
282
326
|
return res.status(400).json({ error: 'users must be a non-empty array' });
|
|
283
327
|
}
|
|
284
|
-
if (users.length > 100) {
|
|
285
|
-
return res
|
|
286
|
-
.status(400)
|
|
287
|
-
.json({ error: 'Maximum 100 users allowed per request' });
|
|
288
|
-
}
|
|
289
328
|
|
|
290
|
-
const response = await chatService.updateUsers(users);
|
|
329
|
+
const response: ApiResponse = await chatService.updateUsers(users);
|
|
291
330
|
res.json({ success: true, data: response });
|
|
292
331
|
} catch (error) {
|
|
293
332
|
if (axios.isAxiosError(error)) {
|
|
@@ -301,6 +340,33 @@ router.patch('/users', async (req: Request, res: Response) => {
|
|
|
301
340
|
}
|
|
302
341
|
});
|
|
303
342
|
|
|
343
|
+
// Update chat room
|
|
344
|
+
router.patch(
|
|
345
|
+
'/workspaces/:workspaceId/chat',
|
|
346
|
+
async (req: Request, res: Response) => {
|
|
347
|
+
try {
|
|
348
|
+
const { workspaceId } = req.params;
|
|
349
|
+
const updateData: { title?: string; description?: string } = req.body;
|
|
350
|
+
const response: ApiResponse = await chatService.updateChatRoom(workspaceId, updateData);
|
|
351
|
+
res.json({ success: true, data: response });
|
|
352
|
+
} catch (error) {
|
|
353
|
+
res.status(500).json({ error: 'Failed to update chat room' });
|
|
354
|
+
}
|
|
355
|
+
},
|
|
356
|
+
);
|
|
357
|
+
|
|
358
|
+
// Get user chats
|
|
359
|
+
router.get('/users/:userId/chats', async (req: Request, res: Response) => {
|
|
360
|
+
try {
|
|
361
|
+
const { userId } = req.params;
|
|
362
|
+
const query: GetUserChatsQueryParams = req.query as unknown as GetUserChatsQueryParams;
|
|
363
|
+
const response: ApiResponse = await chatService.getUserChats(userId, query);
|
|
364
|
+
res.json({ success: true, data: response });
|
|
365
|
+
} catch (error) {
|
|
366
|
+
res.status(500).json({ error: 'Failed to get user chats' });
|
|
367
|
+
}
|
|
368
|
+
});
|
|
369
|
+
|
|
304
370
|
export default router;
|
|
305
371
|
```
|
|
306
372
|
|
|
@@ -314,9 +380,9 @@ import axios from 'axios';
|
|
|
314
380
|
|
|
315
381
|
@Injectable()
|
|
316
382
|
export class ChatService {
|
|
317
|
-
private readonly ethoraService = getEthoraSDKService();
|
|
383
|
+
private readonly ethoraService: ChatRepository = getEthoraSDKService();
|
|
318
384
|
|
|
319
|
-
async createChatRoom(workspaceId: string, roomData?:
|
|
385
|
+
async createChatRoom(workspaceId: string, roomData?: Partial<CreateChatRoomRequest>): Promise<ApiResponse> {
|
|
320
386
|
try {
|
|
321
387
|
return await this.ethoraService.createChatRoom(workspaceId, roomData);
|
|
322
388
|
} catch (error) {
|
|
@@ -333,7 +399,7 @@ export class ChatService {
|
|
|
333
399
|
}
|
|
334
400
|
}
|
|
335
401
|
|
|
336
|
-
async createUser(userId: string, userData?:
|
|
402
|
+
async createUser(userId: string, userData?: CreateUserData): Promise<ApiResponse> {
|
|
337
403
|
try {
|
|
338
404
|
return await this.ethoraService.createUser(userId, userData);
|
|
339
405
|
} catch (error) {
|
|
@@ -366,13 +432,16 @@ export class ChatController {
|
|
|
366
432
|
@Post('workspaces/:workspaceId/rooms')
|
|
367
433
|
async createChatRoom(
|
|
368
434
|
@Param('workspaceId') workspaceId: string,
|
|
369
|
-
@Body() roomData:
|
|
370
|
-
) {
|
|
435
|
+
@Body() roomData: Partial<CreateChatRoomRequest>,
|
|
436
|
+
): Promise<ApiResponse> {
|
|
371
437
|
return this.chatService.createChatRoom(workspaceId, roomData);
|
|
372
438
|
}
|
|
373
439
|
|
|
374
440
|
@Post('users/:userId')
|
|
375
|
-
async createUser(
|
|
441
|
+
async createUser(
|
|
442
|
+
@Param('userId') userId: string,
|
|
443
|
+
@Body() userData: CreateUserData
|
|
444
|
+
): Promise<ApiResponse> {
|
|
376
445
|
return this.chatService.createUser(userId, userData);
|
|
377
446
|
}
|
|
378
447
|
|
|
@@ -396,12 +465,12 @@ export async function chatRoutes(fastify: FastifyInstance) {
|
|
|
396
465
|
// Create chat room
|
|
397
466
|
fastify.post(
|
|
398
467
|
'/workspaces/:workspaceId/chat',
|
|
399
|
-
async (request: FastifyRequest, reply: FastifyReply) => {
|
|
468
|
+
async (request: FastifyRequest, reply: FastifyReply): Promise<ApiResponse | void> => {
|
|
400
469
|
const { workspaceId } = request.params as { workspaceId: string };
|
|
401
|
-
const roomData = request.body as
|
|
470
|
+
const roomData = request.body as Partial<CreateChatRoomRequest>;
|
|
402
471
|
|
|
403
472
|
try {
|
|
404
|
-
const response = await chatService.createChatRoom(
|
|
473
|
+
const response: ApiResponse = await chatService.createChatRoom(
|
|
405
474
|
workspaceId,
|
|
406
475
|
roomData,
|
|
407
476
|
);
|
|
@@ -426,6 +495,33 @@ export async function chatRoutes(fastify: FastifyInstance) {
|
|
|
426
495
|
|
|
427
496
|
## Common Use Cases
|
|
428
497
|
|
|
498
|
+
### Use Case 0: Tenant-admin / child-app management
|
|
499
|
+
|
|
500
|
+
Create and manage a child app through the explicit B2B admin surface:
|
|
501
|
+
|
|
502
|
+
```typescript
|
|
503
|
+
const sdk = getEthoraSDKService();
|
|
504
|
+
|
|
505
|
+
const app = await sdk.createApp({ displayName: 'Tenant Managed Demo' });
|
|
506
|
+
const childAppId = String((app as any).app?._id || (app as any).result?._id || '');
|
|
507
|
+
|
|
508
|
+
await sdk.createUsersInApp(childAppId, {
|
|
509
|
+
bypassEmailConfirmation: true,
|
|
510
|
+
usersList: [
|
|
511
|
+
{ uuid: 'workspace-u1', email: 'workspace-u1@example.com', firstName: 'Workspace', lastName: 'One' },
|
|
512
|
+
{ uuid: 'workspace-u2', email: 'workspace-u2@example.com', firstName: 'Workspace', lastName: 'Two' },
|
|
513
|
+
],
|
|
514
|
+
});
|
|
515
|
+
|
|
516
|
+
await sdk.createChatRoomInApp(childAppId, 'workspace-room', {
|
|
517
|
+
title: 'Workspace Room',
|
|
518
|
+
uuid: 'workspace-room',
|
|
519
|
+
type: 'public',
|
|
520
|
+
});
|
|
521
|
+
|
|
522
|
+
await sdk.grantUserAccessToChatRoomInApp(childAppId, 'workspace-room', ['workspace-u1', 'workspace-u2']);
|
|
523
|
+
```
|
|
524
|
+
|
|
429
525
|
### Use Case 1: Workspace Setup Flow
|
|
430
526
|
|
|
431
527
|
When creating a new workspace, set up the chat room and initial users:
|
|
@@ -435,8 +531,8 @@ async function setupWorkspaceChat(
|
|
|
435
531
|
workspaceId: string,
|
|
436
532
|
userIds: string[],
|
|
437
533
|
adminUserId: string,
|
|
438
|
-
) {
|
|
439
|
-
const chatService = getEthoraSDKService();
|
|
534
|
+
): Promise<{ success: boolean }> {
|
|
535
|
+
const chatService: ChatRepository = getEthoraSDKService();
|
|
440
536
|
|
|
441
537
|
try {
|
|
442
538
|
// 1. Create chat room
|
|
@@ -485,8 +581,8 @@ When a new user joins your platform:
|
|
|
485
581
|
async function onboardNewUser(
|
|
486
582
|
userId: string,
|
|
487
583
|
userData: { firstName: string; lastName: string; email: string },
|
|
488
|
-
) {
|
|
489
|
-
const chatService = getEthoraSDKService();
|
|
584
|
+
): Promise<{ success: boolean; chatToken: string }> {
|
|
585
|
+
const chatService: ChatRepository = getEthoraSDKService();
|
|
490
586
|
|
|
491
587
|
try {
|
|
492
588
|
// Create user in chat service
|
|
@@ -498,7 +594,7 @@ async function onboardNewUser(
|
|
|
498
594
|
});
|
|
499
595
|
|
|
500
596
|
// Generate client token for frontend
|
|
501
|
-
const clientToken = chatService.createChatUserJwtToken(userId);
|
|
597
|
+
const clientToken: string = chatService.createChatUserJwtToken(userId);
|
|
502
598
|
|
|
503
599
|
return {
|
|
504
600
|
success: true,
|
|
@@ -516,8 +612,11 @@ async function onboardNewUser(
|
|
|
516
612
|
When adding a user to an existing workspace:
|
|
517
613
|
|
|
518
614
|
```typescript
|
|
519
|
-
async function addUserToWorkspace(
|
|
520
|
-
|
|
615
|
+
async function addUserToWorkspace(
|
|
616
|
+
workspaceId: string,
|
|
617
|
+
userId: string,
|
|
618
|
+
): Promise<{ success: boolean }> {
|
|
619
|
+
const chatService: ChatRepository = getEthoraSDKService();
|
|
521
620
|
|
|
522
621
|
try {
|
|
523
622
|
// Ensure user exists
|
|
@@ -543,8 +642,11 @@ async function addUserToWorkspace(workspaceId: string, userId: string) {
|
|
|
543
642
|
When removing a user from a workspace:
|
|
544
643
|
|
|
545
644
|
```typescript
|
|
546
|
-
async function removeUserFromWorkspace(
|
|
547
|
-
|
|
645
|
+
async function removeUserFromWorkspace(
|
|
646
|
+
workspaceId: string,
|
|
647
|
+
userId: string,
|
|
648
|
+
): Promise<{ success: boolean }> {
|
|
649
|
+
const chatService: ChatRepository = getEthoraSDKService();
|
|
548
650
|
|
|
549
651
|
try {
|
|
550
652
|
// Remove access from workspace chat room
|
|
@@ -561,8 +663,8 @@ async function removeUserFromWorkspace(workspaceId: string, userId: string) {
|
|
|
561
663
|
async function removeMultipleUsersFromWorkspace(
|
|
562
664
|
workspaceId: string,
|
|
563
665
|
userIds: string[],
|
|
564
|
-
) {
|
|
565
|
-
const chatService = getEthoraSDKService();
|
|
666
|
+
): Promise<{ success: boolean }> {
|
|
667
|
+
const chatService: ChatRepository = getEthoraSDKService();
|
|
566
668
|
|
|
567
669
|
try {
|
|
568
670
|
await chatService.removeUserAccessFromChatRoom(workspaceId, userIds);
|
|
@@ -580,8 +682,11 @@ async function removeMultipleUsersFromWorkspace(
|
|
|
580
682
|
When deleting a workspace:
|
|
581
683
|
|
|
582
684
|
```typescript
|
|
583
|
-
async function cleanupWorkspaceChat(
|
|
584
|
-
|
|
685
|
+
async function cleanupWorkspaceChat(
|
|
686
|
+
workspaceId: string,
|
|
687
|
+
userIds: string[],
|
|
688
|
+
): Promise<{ success: boolean }> {
|
|
689
|
+
const chatService: ChatRepository = getEthoraSDKService();
|
|
585
690
|
|
|
586
691
|
try {
|
|
587
692
|
// Delete chat room (handles non-existent gracefully)
|
|
@@ -609,21 +714,25 @@ async function cleanupWorkspaceChat(workspaceId: string, userIds: string[]) {
|
|
|
609
714
|
Retrieve users from the chat service:
|
|
610
715
|
|
|
611
716
|
```typescript
|
|
612
|
-
async function getUsersExample() {
|
|
613
|
-
|
|
717
|
+
async function getUsersExample(): Promise<{
|
|
718
|
+
allUsers: ApiResponse;
|
|
719
|
+
groupChatUsers: ApiResponse;
|
|
720
|
+
oneOnOneUsers: ApiResponse
|
|
721
|
+
}> {
|
|
722
|
+
const chatService: ChatRepository = getEthoraSDKService();
|
|
614
723
|
|
|
615
724
|
try {
|
|
616
725
|
// Get all users
|
|
617
|
-
const allUsers = await chatService.getUsers();
|
|
726
|
+
const allUsers: ApiResponse = await chatService.getUsers();
|
|
618
727
|
console.log(`Total users: ${allUsers.results?.length || 0}`);
|
|
619
728
|
|
|
620
729
|
// Get users by chat name (group chat)
|
|
621
|
-
const groupChatUsers = await chatService.getUsers({
|
|
730
|
+
const groupChatUsers: ApiResponse = await chatService.getUsers({
|
|
622
731
|
chatName: 'appId_workspaceId',
|
|
623
732
|
});
|
|
624
733
|
|
|
625
734
|
// Get users by chat name (1-on-1 chat)
|
|
626
|
-
const oneOnOneUsers = await chatService.getUsers({
|
|
735
|
+
const oneOnOneUsers: ApiResponse = await chatService.getUsers({
|
|
627
736
|
chatName: 'userA-userB',
|
|
628
737
|
});
|
|
629
738
|
|
|
@@ -640,41 +749,65 @@ async function getUsersExample() {
|
|
|
640
749
|
Update multiple users at once:
|
|
641
750
|
|
|
642
751
|
```typescript
|
|
643
|
-
async function updateUsersExample() {
|
|
644
|
-
const chatService = getEthoraSDKService();
|
|
752
|
+
async function updateUsersExample(): Promise<ApiResponse> {
|
|
753
|
+
const chatService: ChatRepository = getEthoraSDKService();
|
|
645
754
|
|
|
646
755
|
try {
|
|
647
756
|
// Update multiple users (1-100 users per request)
|
|
648
|
-
const response = await chatService.updateUsers([
|
|
757
|
+
const response: ApiResponse = await chatService.updateUsers([
|
|
649
758
|
{
|
|
650
759
|
xmppUsername: 'appId_user1',
|
|
651
760
|
firstName: 'John',
|
|
652
761
|
lastName: 'Doe',
|
|
653
|
-
|
|
654
|
-
profileImage: 'https://example.com/avatar1.jpg',
|
|
655
|
-
},
|
|
656
|
-
{
|
|
657
|
-
xmppUsername: 'appId_user2',
|
|
658
|
-
firstName: 'Jane',
|
|
659
|
-
lastName: 'Smith',
|
|
660
|
-
username: 'janesmith',
|
|
661
|
-
},
|
|
762
|
+
}
|
|
662
763
|
]);
|
|
663
764
|
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
765
|
+
return response;
|
|
766
|
+
} catch (error) {
|
|
767
|
+
console.error('Failed to update users:', error);
|
|
768
|
+
throw error;
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
```
|
|
772
|
+
|
|
773
|
+
### Use Case 8: Updating Chat Room Metadata
|
|
774
|
+
|
|
775
|
+
Update room title or description:
|
|
776
|
+
|
|
777
|
+
```typescript
|
|
778
|
+
async function updateRoomExample(): Promise<ApiResponse> {
|
|
779
|
+
const chatService: ChatRepository = getEthoraSDKService();
|
|
780
|
+
|
|
781
|
+
try {
|
|
782
|
+
const response: ApiResponse = await chatService.updateChatRoom('workspaceId', {
|
|
783
|
+
title: 'New Room Title',
|
|
784
|
+
description: 'New Description',
|
|
673
785
|
});
|
|
786
|
+
return response;
|
|
787
|
+
} catch (error) {
|
|
788
|
+
console.error('Failed to update room:', error);
|
|
789
|
+
throw error;
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
```
|
|
674
793
|
|
|
794
|
+
### Use Case 9: Getting User Chats
|
|
795
|
+
|
|
796
|
+
Retrieve all rooms the user has access to:
|
|
797
|
+
|
|
798
|
+
```typescript
|
|
799
|
+
async function getUserChatsExample(): Promise<ApiResponse> {
|
|
800
|
+
const chatService: ChatRepository = getEthoraSDKService();
|
|
801
|
+
|
|
802
|
+
try {
|
|
803
|
+
const query: GetUserChatsQueryParams = {
|
|
804
|
+
limit: 20,
|
|
805
|
+
includeMembers: true
|
|
806
|
+
};
|
|
807
|
+
const response: ApiResponse = await chatService.getUserChats('userId', query);
|
|
675
808
|
return response;
|
|
676
809
|
} catch (error) {
|
|
677
|
-
console.error('Failed to
|
|
810
|
+
console.error('Failed to get user chats:', error);
|
|
678
811
|
throw error;
|
|
679
812
|
}
|
|
680
813
|
}
|
|
@@ -682,39 +815,80 @@ async function updateUsersExample() {
|
|
|
682
815
|
|
|
683
816
|
## API Reference
|
|
684
817
|
|
|
818
|
+
### Tenant-admin methods
|
|
819
|
+
|
|
820
|
+
#### `createApp(appData: CreateAppRequest): Promise<ApiResponse>`
|
|
821
|
+
|
|
822
|
+
Creates a child app through `POST /v2/apps`.
|
|
823
|
+
|
|
824
|
+
#### `createUsersInApp(appId: UUID, payload: BatchCreateUsersRequest): Promise<ApiResponse>`
|
|
825
|
+
|
|
826
|
+
Starts an async user-batch job through `POST /v2/apps/{appId}/users/batch`.
|
|
827
|
+
|
|
828
|
+
#### `createChatRoomInApp(appId: UUID, chatId: UUID, roomData?: Record<string, unknown>): Promise<ApiResponse>`
|
|
829
|
+
|
|
830
|
+
Creates a chat in a target app through `POST /v2/apps/{appId}/chats`.
|
|
831
|
+
|
|
832
|
+
#### `grantUserAccessToChatRoomInApp(appId: UUID, chatId: UUID, userId: UUID | UUID[]): Promise<ApiResponse>`
|
|
833
|
+
|
|
834
|
+
Adds user access in a target app through `POST /v2/apps/{appId}/chats/users-access`.
|
|
835
|
+
|
|
836
|
+
#### `deleteChatRoomInApp(appId: UUID, chatId: UUID): Promise<ApiResponse>`
|
|
837
|
+
|
|
838
|
+
Deletes a chat in a target app through `DELETE /v2/apps/{appId}/chats`.
|
|
839
|
+
|
|
685
840
|
### Core Methods
|
|
686
841
|
|
|
687
|
-
#### `createUser(userId: UUID, userData?:
|
|
842
|
+
#### `createUser(userId: UUID, userData?: CreateUserData): Promise<ApiResponse>`
|
|
688
843
|
|
|
689
844
|
Creates a user in the chat service using the `/v2/users/batch` endpoint.
|
|
690
845
|
|
|
691
|
-
**
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
846
|
+
**Interface: `CreateUserData`**
|
|
847
|
+
```typescript
|
|
848
|
+
interface CreateUserData {
|
|
849
|
+
email: string; // string: User's email address
|
|
850
|
+
firstName: string; // string: User's first name
|
|
851
|
+
lastName: string; // string: User's last name (min 2 chars)
|
|
852
|
+
password?: string; // string (optional): User's password
|
|
853
|
+
displayName?: string; // string (optional): Full display name
|
|
854
|
+
}
|
|
855
|
+
```
|
|
699
856
|
|
|
700
|
-
**
|
|
857
|
+
**Example Request:**
|
|
858
|
+
```typescript
|
|
859
|
+
await sdk.createUser("user-uuid-123", {
|
|
860
|
+
email: "john@example.com",
|
|
861
|
+
firstName: "John",
|
|
862
|
+
lastName: "Doe"
|
|
863
|
+
});
|
|
864
|
+
```
|
|
701
865
|
|
|
702
866
|
**Note:** The API requires `lastName` to be at least 2 characters. If not provided or too short, defaults to "User".
|
|
703
867
|
|
|
704
868
|
---
|
|
705
869
|
|
|
706
|
-
#### `createChatRoom(chatId: UUID, roomData?:
|
|
870
|
+
#### `createChatRoom(chatId: UUID, roomData?: CreateChatRoomRequest): Promise<ApiResponse>`
|
|
707
871
|
|
|
708
872
|
Creates a chat room using the `/v2/chats` endpoint.
|
|
709
873
|
|
|
710
|
-
**
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
874
|
+
**Interface: `CreateChatRoomRequest`**
|
|
875
|
+
```typescript
|
|
876
|
+
interface CreateChatRoomRequest {
|
|
877
|
+
title: string; // string: The display name of the chat room
|
|
878
|
+
uuid: string; // string: The workspace/chat identifier
|
|
879
|
+
type: string; // string: The room type (e.g., "group")
|
|
880
|
+
}
|
|
881
|
+
```
|
|
716
882
|
|
|
717
|
-
**
|
|
883
|
+
**Example Request:**
|
|
884
|
+
```typescript
|
|
885
|
+
const roomData: CreateChatRoomRequest = {
|
|
886
|
+
title: "Engineering",
|
|
887
|
+
uuid: "room-abc-123",
|
|
888
|
+
type: "group"
|
|
889
|
+
};
|
|
890
|
+
await sdk.createChatRoom("room-abc-123", roomData);
|
|
891
|
+
```
|
|
718
892
|
|
|
719
893
|
---
|
|
720
894
|
|
|
@@ -722,11 +896,14 @@ Creates a chat room using the `/v2/chats` endpoint.
|
|
|
722
896
|
|
|
723
897
|
Grants user(s) access to a chat room using the `/v2/chats/users-access` endpoint.
|
|
724
898
|
|
|
725
|
-
**
|
|
726
|
-
|
|
727
|
-
|
|
899
|
+
**Example Request:**
|
|
900
|
+
```typescript
|
|
901
|
+
// Single user
|
|
902
|
+
await sdk.grantUserAccessToChatRoom("workspace-123", "user-uuid-456");
|
|
728
903
|
|
|
729
|
-
|
|
904
|
+
// Multiple users
|
|
905
|
+
await sdk.grantUserAccessToChatRoom("workspace-123", ["user-1", "user-2"]);
|
|
906
|
+
```
|
|
730
907
|
|
|
731
908
|
**Note:** User IDs are automatically prefixed with `{appId}_` if they don't already have the prefix.
|
|
732
909
|
|
|
@@ -736,11 +913,10 @@ Grants user(s) access to a chat room using the `/v2/chats/users-access` endpoint
|
|
|
736
913
|
|
|
737
914
|
Removes user(s) access from a chat room using the `/v2/chats/users-access` DELETE endpoint.
|
|
738
915
|
|
|
739
|
-
**
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
**Returns:** Promise resolving to the API response
|
|
916
|
+
**Example Request:**
|
|
917
|
+
```typescript
|
|
918
|
+
await sdk.removeUserAccessFromChatRoom("workspace-123", "user-456");
|
|
919
|
+
```
|
|
744
920
|
|
|
745
921
|
**Note:** User IDs are automatically prefixed with `{appId}_` if they don't already have the prefix.
|
|
746
922
|
|
|
@@ -783,20 +959,79 @@ Retrieves users from the chat service using the `/v2/chats/users` endpoint.
|
|
|
783
959
|
|
|
784
960
|
Updates multiple users at once using the `/v2/chats/users` PATCH endpoint.
|
|
785
961
|
|
|
786
|
-
**
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
962
|
+
**Interface: `UpdateUserData`**
|
|
963
|
+
```typescript
|
|
964
|
+
interface UpdateUserData {
|
|
965
|
+
xmppUsername: string; // string: Required (format: {appId}_{userId})
|
|
966
|
+
firstName?: string; // string (optional): New first name
|
|
967
|
+
lastName?: string; // string (optional): New last name
|
|
968
|
+
username?: string; // string (optional): New username
|
|
969
|
+
profileImage?: string; // string (optional): URL to profile image
|
|
970
|
+
description?: string; // string (optional): User bio/description
|
|
971
|
+
email?: string; // string (optional): New email address
|
|
972
|
+
}
|
|
973
|
+
```
|
|
793
974
|
|
|
794
|
-
**
|
|
975
|
+
**Example Request:**
|
|
976
|
+
```typescript
|
|
977
|
+
await sdk.updateUsers([
|
|
978
|
+
{ xmppUsername: "appId_user1", firstName: "NewName" }
|
|
979
|
+
]);
|
|
980
|
+
```
|
|
795
981
|
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
982
|
+
---
|
|
983
|
+
|
|
984
|
+
#### `getUserChats(userId: UUID, params?: GetUserChatsQueryParams): Promise<ApiResponse>`
|
|
985
|
+
|
|
986
|
+
Retrieves all rooms the user has access to.
|
|
987
|
+
|
|
988
|
+
**Interface: `GetUserChatsQueryParams`**
|
|
989
|
+
```typescript
|
|
990
|
+
interface GetUserChatsQueryParams {
|
|
991
|
+
limit?: number; // number (optional): Pagination limit
|
|
992
|
+
offset?: number; // number (optional): Pagination offset
|
|
993
|
+
includeMembers?: boolean; // boolean (optional): Whether to return member lists
|
|
994
|
+
}
|
|
995
|
+
```
|
|
996
|
+
|
|
997
|
+
**Example Request:**
|
|
998
|
+
```typescript
|
|
999
|
+
const query: GetUserChatsQueryParams = { limit: 50, includeMembers: true };
|
|
1000
|
+
await sdk.getUserChats("user-uuid-123", query);
|
|
1001
|
+
```
|
|
1002
|
+
|
|
1003
|
+
---
|
|
1004
|
+
|
|
1005
|
+
#### `updateChatRoom(chatId: UUID, updateData: { title?: string; description?: string }): Promise<ApiResponse>`
|
|
1006
|
+
|
|
1007
|
+
Updates the metadata for a specific chat room.
|
|
1008
|
+
|
|
1009
|
+
**Example Request:**
|
|
1010
|
+
```typescript
|
|
1011
|
+
await sdk.updateChatRoom("workspace-123", {
|
|
1012
|
+
title: "New Team Title",
|
|
1013
|
+
description: "Updated room description"
|
|
1014
|
+
});
|
|
1015
|
+
```
|
|
1016
|
+
|
|
1017
|
+
---
|
|
1018
|
+
|
|
1019
|
+
#### `getUsers(params?: GetUsersQueryParams): Promise<ApiResponse>`
|
|
1020
|
+
|
|
1021
|
+
Retrieves users from the chat service using the `/v2/chats/users` endpoint.
|
|
1022
|
+
|
|
1023
|
+
**Interface: `GetUsersQueryParams`**
|
|
1024
|
+
```typescript
|
|
1025
|
+
interface GetUsersQueryParams {
|
|
1026
|
+
chatName?: string; // string (optional): Filter by roomId (appId_roomId)
|
|
1027
|
+
xmppUsername?: string; // string (optional): Filter by specific JID
|
|
1028
|
+
}
|
|
1029
|
+
```
|
|
1030
|
+
|
|
1031
|
+
**Example Request:**
|
|
1032
|
+
```typescript
|
|
1033
|
+
await sdk.getUsers({ chatName: "appId_workspace-123" });
|
|
1034
|
+
```
|
|
800
1035
|
|
|
801
1036
|
**Limits:** 1-100 users per request
|
|
802
1037
|
|
|
@@ -806,10 +1041,10 @@ Updates multiple users at once using the `/v2/chats/users` PATCH endpoint.
|
|
|
806
1041
|
|
|
807
1042
|
Deletes users from the chat service using the `/v1/users/batch` endpoint.
|
|
808
1043
|
|
|
809
|
-
**
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
1044
|
+
**Example Request:**
|
|
1045
|
+
```typescript
|
|
1046
|
+
await sdk.deleteUsers(["user-id-1", "user-id-2"]);
|
|
1047
|
+
```
|
|
813
1048
|
|
|
814
1049
|
**Note:** Gracefully handles non-existent users (422 status with "not found").
|
|
815
1050
|
|
|
@@ -819,10 +1054,10 @@ Deletes users from the chat service using the `/v1/users/batch` endpoint.
|
|
|
819
1054
|
|
|
820
1055
|
Deletes a chat room using the `/v1/chats` endpoint.
|
|
821
1056
|
|
|
822
|
-
**
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
1057
|
+
**Example Request:**
|
|
1058
|
+
```typescript
|
|
1059
|
+
await sdk.deleteChatRoom("workspace-uuid-123");
|
|
1060
|
+
```
|
|
826
1061
|
|
|
827
1062
|
**Note:** Gracefully handles non-existent rooms (422 status with "not found").
|
|
828
1063
|
|
|
@@ -853,6 +1088,8 @@ Creates a client-side JWT token for user authentication.
|
|
|
853
1088
|
|
|
854
1089
|
**Returns:** The encoded JWT token for client-side authentication
|
|
855
1090
|
|
|
1091
|
+
**Important:** Pass the same canonical user ID/UUID that your backend uses when creating that user in Ethora. Do not switch between different user-id formats when creating the user and then minting the client token.
|
|
1092
|
+
|
|
856
1093
|
---
|
|
857
1094
|
|
|
858
1095
|
## Error Handling
|