@ethora/sdk-backend 26.1.1 → 26.2.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 +111 -108
- package/dist/repositories/EthoraSDKService.d.ts +30 -18
- package/dist/repositories/EthoraSDKService.d.ts.map +1 -1
- package/dist/repositories/EthoraSDKService.js +159 -84
- package/dist/repositories/EthoraSDKService.js.map +1 -1
- package/dist/scripts/test-logs.d.ts +2 -0
- package/dist/scripts/test-logs.d.ts.map +1 -0
- package/dist/scripts/test-logs.js +93 -0
- package/dist/scripts/test-logs.js.map +1 -0
- package/dist/types/index.d.ts +14 -7
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +3 -1
package/README.md
CHANGED
|
@@ -79,7 +79,7 @@ npm install dotenv
|
|
|
79
79
|
In your main application file (e.g., `app.js`, `server.js`, or `index.ts`):
|
|
80
80
|
|
|
81
81
|
```typescript
|
|
82
|
-
import dotenv from
|
|
82
|
+
import dotenv from 'dotenv';
|
|
83
83
|
|
|
84
84
|
// Load environment variables
|
|
85
85
|
dotenv.config();
|
|
@@ -90,7 +90,7 @@ dotenv.config();
|
|
|
90
90
|
### Step 1: Import the SDK
|
|
91
91
|
|
|
92
92
|
```typescript
|
|
93
|
-
import { getEthoraSDKService } from
|
|
93
|
+
import { getEthoraSDKService } from '@ethora/sdk-backend';
|
|
94
94
|
```
|
|
95
95
|
|
|
96
96
|
### Step 2: Initialize the Service
|
|
@@ -101,7 +101,7 @@ You can initialize the service in several ways:
|
|
|
101
101
|
|
|
102
102
|
```typescript
|
|
103
103
|
// services/chatService.ts
|
|
104
|
-
import { getEthoraSDKService } from
|
|
104
|
+
import { getEthoraSDKService } from '@ethora/sdk-backend';
|
|
105
105
|
|
|
106
106
|
// Get the singleton instance
|
|
107
107
|
const chatService = getEthoraSDKService();
|
|
@@ -113,7 +113,7 @@ export default chatService;
|
|
|
113
113
|
|
|
114
114
|
```typescript
|
|
115
115
|
// In your route handler or service
|
|
116
|
-
import { getEthoraSDKService } from
|
|
116
|
+
import { getEthoraSDKService } from '@ethora/sdk-backend';
|
|
117
117
|
|
|
118
118
|
const chatService = getEthoraSDKService();
|
|
119
119
|
```
|
|
@@ -122,8 +122,8 @@ const chatService = getEthoraSDKService();
|
|
|
122
122
|
|
|
123
123
|
```typescript
|
|
124
124
|
// chat.service.ts
|
|
125
|
-
import { Injectable } from
|
|
126
|
-
import { getEthoraSDKService } from
|
|
125
|
+
import { Injectable } from '@nestjs/common';
|
|
126
|
+
import { getEthoraSDKService } from '@ethora/sdk-backend';
|
|
127
127
|
|
|
128
128
|
@Injectable()
|
|
129
129
|
export class ChatService {
|
|
@@ -139,16 +139,16 @@ export class ChatService {
|
|
|
139
139
|
|
|
140
140
|
```typescript
|
|
141
141
|
// routes/chat.ts
|
|
142
|
-
import express, { Request, Response } from
|
|
143
|
-
import { getEthoraSDKService } from
|
|
144
|
-
import axios from
|
|
142
|
+
import express, { Request, Response } from 'express';
|
|
143
|
+
import { getEthoraSDKService } from '@ethora/sdk-backend';
|
|
144
|
+
import axios from 'axios';
|
|
145
145
|
|
|
146
146
|
const router = express.Router();
|
|
147
147
|
const chatService = getEthoraSDKService();
|
|
148
148
|
|
|
149
149
|
// Create a chat room for a workspace
|
|
150
150
|
router.post(
|
|
151
|
-
|
|
151
|
+
'/workspaces/:workspaceId/chat',
|
|
152
152
|
async (req: Request, res: Response) => {
|
|
153
153
|
try {
|
|
154
154
|
const { workspaceId } = req.params;
|
|
@@ -157,7 +157,7 @@ router.post(
|
|
|
157
157
|
const response = await chatService.createChatRoom(workspaceId, {
|
|
158
158
|
title: roomData.title || `Chat Room ${workspaceId}`,
|
|
159
159
|
uuid: workspaceId,
|
|
160
|
-
type: roomData.type ||
|
|
160
|
+
type: roomData.type || 'group',
|
|
161
161
|
...roomData,
|
|
162
162
|
});
|
|
163
163
|
|
|
@@ -165,18 +165,18 @@ router.post(
|
|
|
165
165
|
} catch (error) {
|
|
166
166
|
if (axios.isAxiosError(error)) {
|
|
167
167
|
res.status(error.response?.status || 500).json({
|
|
168
|
-
error:
|
|
168
|
+
error: 'Failed to create chat room',
|
|
169
169
|
details: error.response?.data,
|
|
170
170
|
});
|
|
171
171
|
} else {
|
|
172
|
-
res.status(500).json({ error:
|
|
172
|
+
res.status(500).json({ error: 'Internal server error' });
|
|
173
173
|
}
|
|
174
174
|
}
|
|
175
|
-
}
|
|
175
|
+
},
|
|
176
176
|
);
|
|
177
177
|
|
|
178
178
|
// Create a user
|
|
179
|
-
router.post(
|
|
179
|
+
router.post('/users/:userId', async (req: Request, res: Response) => {
|
|
180
180
|
try {
|
|
181
181
|
const { userId } = req.params;
|
|
182
182
|
const userData = req.body;
|
|
@@ -186,50 +186,50 @@ router.post("/users/:userId", async (req: Request, res: Response) => {
|
|
|
186
186
|
} catch (error) {
|
|
187
187
|
if (axios.isAxiosError(error)) {
|
|
188
188
|
res.status(error.response?.status || 500).json({
|
|
189
|
-
error:
|
|
189
|
+
error: 'Failed to create user',
|
|
190
190
|
details: error.response?.data,
|
|
191
191
|
});
|
|
192
192
|
} else {
|
|
193
|
-
res.status(500).json({ error:
|
|
193
|
+
res.status(500).json({ error: 'Internal server error' });
|
|
194
194
|
}
|
|
195
195
|
}
|
|
196
196
|
});
|
|
197
197
|
|
|
198
198
|
// Grant user access to chat room
|
|
199
199
|
router.post(
|
|
200
|
-
|
|
200
|
+
'/workspaces/:workspaceId/chat/users/:userId',
|
|
201
201
|
async (req: Request, res: Response) => {
|
|
202
202
|
try {
|
|
203
203
|
const { workspaceId, userId } = req.params;
|
|
204
204
|
|
|
205
205
|
await chatService.grantUserAccessToChatRoom(workspaceId, userId);
|
|
206
|
-
res.json({ success: true, message:
|
|
206
|
+
res.json({ success: true, message: 'Access granted' });
|
|
207
207
|
} catch (error) {
|
|
208
208
|
if (axios.isAxiosError(error)) {
|
|
209
209
|
res.status(error.response?.status || 500).json({
|
|
210
|
-
error:
|
|
210
|
+
error: 'Failed to grant access',
|
|
211
211
|
details: error.response?.data,
|
|
212
212
|
});
|
|
213
213
|
} else {
|
|
214
|
-
res.status(500).json({ error:
|
|
214
|
+
res.status(500).json({ error: 'Internal server error' });
|
|
215
215
|
}
|
|
216
216
|
}
|
|
217
|
-
}
|
|
217
|
+
},
|
|
218
218
|
);
|
|
219
219
|
|
|
220
220
|
// Generate client JWT token
|
|
221
|
-
router.get(
|
|
221
|
+
router.get('/users/:userId/chat-token', (req: Request, res: Response) => {
|
|
222
222
|
try {
|
|
223
223
|
const { userId } = req.params;
|
|
224
224
|
const token = chatService.createChatUserJwtToken(userId);
|
|
225
225
|
res.json({ token });
|
|
226
226
|
} catch (error) {
|
|
227
|
-
res.status(500).json({ error:
|
|
227
|
+
res.status(500).json({ error: 'Failed to generate token' });
|
|
228
228
|
}
|
|
229
229
|
});
|
|
230
230
|
|
|
231
231
|
// Get users
|
|
232
|
-
router.get(
|
|
232
|
+
router.get('/users', async (req: Request, res: Response) => {
|
|
233
233
|
try {
|
|
234
234
|
const { chatName, xmppUsername } = req.query;
|
|
235
235
|
const params: any = {};
|
|
@@ -237,32 +237,32 @@ router.get("/users", async (req: Request, res: Response) => {
|
|
|
237
237
|
if (xmppUsername) params.xmppUsername = String(xmppUsername);
|
|
238
238
|
|
|
239
239
|
const response = await chatService.getUsers(
|
|
240
|
-
Object.keys(params).length > 0 ? params : undefined
|
|
240
|
+
Object.keys(params).length > 0 ? params : undefined,
|
|
241
241
|
);
|
|
242
242
|
res.json({ success: true, data: response });
|
|
243
243
|
} catch (error) {
|
|
244
244
|
if (axios.isAxiosError(error)) {
|
|
245
245
|
res.status(error.response?.status || 500).json({
|
|
246
|
-
error:
|
|
246
|
+
error: 'Failed to get users',
|
|
247
247
|
details: error.response?.data,
|
|
248
248
|
});
|
|
249
249
|
} else {
|
|
250
|
-
res.status(500).json({ error:
|
|
250
|
+
res.status(500).json({ error: 'Internal server error' });
|
|
251
251
|
}
|
|
252
252
|
}
|
|
253
253
|
});
|
|
254
254
|
|
|
255
255
|
// Update users (batch)
|
|
256
|
-
router.patch(
|
|
256
|
+
router.patch('/users', async (req: Request, res: Response) => {
|
|
257
257
|
try {
|
|
258
258
|
const { users } = req.body;
|
|
259
259
|
if (!Array.isArray(users) || users.length === 0) {
|
|
260
|
-
return res.status(400).json({ error:
|
|
260
|
+
return res.status(400).json({ error: 'users must be a non-empty array' });
|
|
261
261
|
}
|
|
262
262
|
if (users.length > 100) {
|
|
263
263
|
return res
|
|
264
264
|
.status(400)
|
|
265
|
-
.json({ error:
|
|
265
|
+
.json({ error: 'Maximum 100 users allowed per request' });
|
|
266
266
|
}
|
|
267
267
|
|
|
268
268
|
const response = await chatService.updateUsers(users);
|
|
@@ -270,11 +270,11 @@ router.patch("/users", async (req: Request, res: Response) => {
|
|
|
270
270
|
} catch (error) {
|
|
271
271
|
if (axios.isAxiosError(error)) {
|
|
272
272
|
res.status(error.response?.status || 500).json({
|
|
273
|
-
error:
|
|
273
|
+
error: 'Failed to update users',
|
|
274
274
|
details: error.response?.data,
|
|
275
275
|
});
|
|
276
276
|
} else {
|
|
277
|
-
res.status(500).json({ error:
|
|
277
|
+
res.status(500).json({ error: 'Internal server error' });
|
|
278
278
|
}
|
|
279
279
|
}
|
|
280
280
|
});
|
|
@@ -286,9 +286,9 @@ export default router;
|
|
|
286
286
|
|
|
287
287
|
```typescript
|
|
288
288
|
// chat/chat.service.ts
|
|
289
|
-
import { Injectable, HttpException, HttpStatus } from
|
|
290
|
-
import { getEthoraSDKService } from
|
|
291
|
-
import axios from
|
|
289
|
+
import { Injectable, HttpException, HttpStatus } from '@nestjs/common';
|
|
290
|
+
import { getEthoraSDKService } from '@ethora/sdk-backend';
|
|
291
|
+
import axios from 'axios';
|
|
292
292
|
|
|
293
293
|
@Injectable()
|
|
294
294
|
export class ChatService {
|
|
@@ -301,10 +301,10 @@ export class ChatService {
|
|
|
301
301
|
if (axios.isAxiosError(error)) {
|
|
302
302
|
throw new HttpException(
|
|
303
303
|
{
|
|
304
|
-
message:
|
|
304
|
+
message: 'Failed to create chat room',
|
|
305
305
|
details: error.response?.data,
|
|
306
306
|
},
|
|
307
|
-
error.response?.status || HttpStatus.INTERNAL_SERVER_ERROR
|
|
307
|
+
error.response?.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
308
308
|
);
|
|
309
309
|
}
|
|
310
310
|
throw error;
|
|
@@ -318,10 +318,10 @@ export class ChatService {
|
|
|
318
318
|
if (axios.isAxiosError(error)) {
|
|
319
319
|
throw new HttpException(
|
|
320
320
|
{
|
|
321
|
-
message:
|
|
321
|
+
message: 'Failed to create user',
|
|
322
322
|
details: error.response?.data,
|
|
323
323
|
},
|
|
324
|
-
error.response?.status || HttpStatus.INTERNAL_SERVER_ERROR
|
|
324
|
+
error.response?.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
325
325
|
);
|
|
326
326
|
}
|
|
327
327
|
throw error;
|
|
@@ -334,28 +334,28 @@ export class ChatService {
|
|
|
334
334
|
}
|
|
335
335
|
|
|
336
336
|
// chat/chat.controller.ts
|
|
337
|
-
import { Controller, Post, Get, Param, Body } from
|
|
338
|
-
import { ChatService } from
|
|
337
|
+
import { Controller, Post, Get, Param, Body } from '@nestjs/common';
|
|
338
|
+
import { ChatService } from './chat.service';
|
|
339
339
|
|
|
340
|
-
@Controller(
|
|
340
|
+
@Controller('chat')
|
|
341
341
|
export class ChatController {
|
|
342
342
|
constructor(private readonly chatService: ChatService) {}
|
|
343
343
|
|
|
344
|
-
@Post(
|
|
344
|
+
@Post('workspaces/:workspaceId/rooms')
|
|
345
345
|
async createChatRoom(
|
|
346
|
-
@Param(
|
|
347
|
-
@Body() roomData: any
|
|
346
|
+
@Param('workspaceId') workspaceId: string,
|
|
347
|
+
@Body() roomData: any,
|
|
348
348
|
) {
|
|
349
349
|
return this.chatService.createChatRoom(workspaceId, roomData);
|
|
350
350
|
}
|
|
351
351
|
|
|
352
|
-
@Post(
|
|
353
|
-
async createUser(@Param(
|
|
352
|
+
@Post('users/:userId')
|
|
353
|
+
async createUser(@Param('userId') userId: string, @Body() userData: any) {
|
|
354
354
|
return this.chatService.createUser(userId, userData);
|
|
355
355
|
}
|
|
356
356
|
|
|
357
|
-
@Get(
|
|
358
|
-
getClientToken(@Param(
|
|
357
|
+
@Get('users/:userId/token')
|
|
358
|
+
getClientToken(@Param('userId') userId: string) {
|
|
359
359
|
return { token: this.chatService.generateClientToken(userId) };
|
|
360
360
|
}
|
|
361
361
|
}
|
|
@@ -365,15 +365,15 @@ export class ChatController {
|
|
|
365
365
|
|
|
366
366
|
```typescript
|
|
367
367
|
// routes/chat.ts
|
|
368
|
-
import { FastifyInstance, FastifyRequest, FastifyReply } from
|
|
369
|
-
import { getEthoraSDKService } from
|
|
368
|
+
import { FastifyInstance, FastifyRequest, FastifyReply } from 'fastify';
|
|
369
|
+
import { getEthoraSDKService } from '@ethora/sdk-backend';
|
|
370
370
|
|
|
371
371
|
const chatService = getEthoraSDKService();
|
|
372
372
|
|
|
373
373
|
export async function chatRoutes(fastify: FastifyInstance) {
|
|
374
374
|
// Create chat room
|
|
375
375
|
fastify.post(
|
|
376
|
-
|
|
376
|
+
'/workspaces/:workspaceId/chat',
|
|
377
377
|
async (request: FastifyRequest, reply: FastifyReply) => {
|
|
378
378
|
const { workspaceId } = request.params as { workspaceId: string };
|
|
379
379
|
const roomData = request.body as any;
|
|
@@ -381,23 +381,23 @@ export async function chatRoutes(fastify: FastifyInstance) {
|
|
|
381
381
|
try {
|
|
382
382
|
const response = await chatService.createChatRoom(
|
|
383
383
|
workspaceId,
|
|
384
|
-
roomData
|
|
384
|
+
roomData,
|
|
385
385
|
);
|
|
386
386
|
return { success: true, data: response };
|
|
387
387
|
} catch (error) {
|
|
388
|
-
reply.code(500).send({ error:
|
|
388
|
+
reply.code(500).send({ error: 'Failed to create chat room' });
|
|
389
389
|
}
|
|
390
|
-
}
|
|
390
|
+
},
|
|
391
391
|
);
|
|
392
392
|
|
|
393
393
|
// Generate client token
|
|
394
394
|
fastify.get(
|
|
395
|
-
|
|
395
|
+
'/users/:userId/chat-token',
|
|
396
396
|
async (request: FastifyRequest, reply: FastifyReply) => {
|
|
397
397
|
const { userId } = request.params as { userId: string };
|
|
398
398
|
const token = chatService.createChatUserJwtToken(userId);
|
|
399
399
|
return { token };
|
|
400
|
-
}
|
|
400
|
+
},
|
|
401
401
|
);
|
|
402
402
|
}
|
|
403
403
|
```
|
|
@@ -412,7 +412,7 @@ When creating a new workspace, set up the chat room and initial users:
|
|
|
412
412
|
async function setupWorkspaceChat(
|
|
413
413
|
workspaceId: string,
|
|
414
414
|
userIds: string[],
|
|
415
|
-
adminUserId: string
|
|
415
|
+
adminUserId: string,
|
|
416
416
|
) {
|
|
417
417
|
const chatService = getEthoraSDKService();
|
|
418
418
|
|
|
@@ -421,15 +421,15 @@ async function setupWorkspaceChat(
|
|
|
421
421
|
await chatService.createChatRoom(workspaceId, {
|
|
422
422
|
title: `Workspace ${workspaceId}`,
|
|
423
423
|
uuid: workspaceId,
|
|
424
|
-
type:
|
|
424
|
+
type: 'group',
|
|
425
425
|
});
|
|
426
426
|
|
|
427
427
|
// 2. Create users (if they don't exist)
|
|
428
428
|
for (const userId of userIds) {
|
|
429
429
|
try {
|
|
430
430
|
await chatService.createUser(userId, {
|
|
431
|
-
firstName:
|
|
432
|
-
lastName:
|
|
431
|
+
firstName: 'User',
|
|
432
|
+
lastName: 'Name',
|
|
433
433
|
});
|
|
434
434
|
} catch (error) {
|
|
435
435
|
// User might already exist, continue
|
|
@@ -444,12 +444,12 @@ async function setupWorkspaceChat(
|
|
|
444
444
|
try {
|
|
445
445
|
await chatService.grantChatbotAccessToChatRoom(workspaceId);
|
|
446
446
|
} catch (error) {
|
|
447
|
-
console.warn(
|
|
447
|
+
console.warn('Chatbot access not configured or failed');
|
|
448
448
|
}
|
|
449
449
|
|
|
450
450
|
return { success: true };
|
|
451
451
|
} catch (error) {
|
|
452
|
-
console.error(
|
|
452
|
+
console.error('Failed to setup workspace chat:', error);
|
|
453
453
|
throw error;
|
|
454
454
|
}
|
|
455
455
|
}
|
|
@@ -462,7 +462,7 @@ When a new user joins your platform:
|
|
|
462
462
|
```typescript
|
|
463
463
|
async function onboardNewUser(
|
|
464
464
|
userId: string,
|
|
465
|
-
userData: { firstName: string; lastName: string; email: string }
|
|
465
|
+
userData: { firstName: string; lastName: string; email: string },
|
|
466
466
|
) {
|
|
467
467
|
const chatService = getEthoraSDKService();
|
|
468
468
|
|
|
@@ -483,7 +483,7 @@ async function onboardNewUser(
|
|
|
483
483
|
chatToken: clientToken,
|
|
484
484
|
};
|
|
485
485
|
} catch (error) {
|
|
486
|
-
console.error(
|
|
486
|
+
console.error('Failed to onboard user:', error);
|
|
487
487
|
throw error;
|
|
488
488
|
}
|
|
489
489
|
}
|
|
@@ -510,7 +510,7 @@ async function addUserToWorkspace(workspaceId: string, userId: string) {
|
|
|
510
510
|
|
|
511
511
|
return { success: true };
|
|
512
512
|
} catch (error) {
|
|
513
|
-
console.error(
|
|
513
|
+
console.error('Failed to add user to workspace:', error);
|
|
514
514
|
throw error;
|
|
515
515
|
}
|
|
516
516
|
}
|
|
@@ -533,13 +533,13 @@ async function cleanupWorkspaceChat(workspaceId: string, userIds: string[]) {
|
|
|
533
533
|
try {
|
|
534
534
|
await chatService.deleteUsers(userIds);
|
|
535
535
|
} catch (error) {
|
|
536
|
-
console.warn(
|
|
536
|
+
console.warn('Some users might not exist:', error);
|
|
537
537
|
}
|
|
538
538
|
}
|
|
539
539
|
|
|
540
540
|
return { success: true };
|
|
541
541
|
} catch (error) {
|
|
542
|
-
console.error(
|
|
542
|
+
console.error('Failed to cleanup workspace chat:', error);
|
|
543
543
|
throw error;
|
|
544
544
|
}
|
|
545
545
|
}
|
|
@@ -560,17 +560,17 @@ async function getUsersExample() {
|
|
|
560
560
|
|
|
561
561
|
// Get users by chat name (group chat)
|
|
562
562
|
const groupChatUsers = await chatService.getUsers({
|
|
563
|
-
chatName:
|
|
563
|
+
chatName: 'appId_workspaceId',
|
|
564
564
|
});
|
|
565
565
|
|
|
566
566
|
// Get users by chat name (1-on-1 chat)
|
|
567
567
|
const oneOnOneUsers = await chatService.getUsers({
|
|
568
|
-
chatName:
|
|
568
|
+
chatName: 'userA-userB',
|
|
569
569
|
});
|
|
570
570
|
|
|
571
571
|
return { allUsers, groupChatUsers, oneOnOneUsers };
|
|
572
572
|
} catch (error) {
|
|
573
|
-
console.error(
|
|
573
|
+
console.error('Failed to get users:', error);
|
|
574
574
|
throw error;
|
|
575
575
|
}
|
|
576
576
|
}
|
|
@@ -588,34 +588,34 @@ async function updateUsersExample() {
|
|
|
588
588
|
// Update multiple users (1-100 users per request)
|
|
589
589
|
const response = await chatService.updateUsers([
|
|
590
590
|
{
|
|
591
|
-
xmppUsername:
|
|
592
|
-
firstName:
|
|
593
|
-
lastName:
|
|
594
|
-
username:
|
|
595
|
-
profileImage:
|
|
591
|
+
xmppUsername: 'appId_user1',
|
|
592
|
+
firstName: 'John',
|
|
593
|
+
lastName: 'Doe',
|
|
594
|
+
username: 'johndoe',
|
|
595
|
+
profileImage: 'https://example.com/avatar1.jpg',
|
|
596
596
|
},
|
|
597
597
|
{
|
|
598
|
-
xmppUsername:
|
|
599
|
-
firstName:
|
|
600
|
-
lastName:
|
|
601
|
-
username:
|
|
598
|
+
xmppUsername: 'appId_user2',
|
|
599
|
+
firstName: 'Jane',
|
|
600
|
+
lastName: 'Smith',
|
|
601
|
+
username: 'janesmith',
|
|
602
602
|
},
|
|
603
603
|
]);
|
|
604
604
|
|
|
605
605
|
// Check results
|
|
606
606
|
response.results?.forEach((result: any) => {
|
|
607
|
-
if (result.status ===
|
|
607
|
+
if (result.status === 'updated') {
|
|
608
608
|
console.log(`User ${result.xmppUsername} updated successfully`);
|
|
609
|
-
} else if (result.status ===
|
|
609
|
+
} else if (result.status === 'not-found') {
|
|
610
610
|
console.warn(`User ${result.xmppUsername} not found`);
|
|
611
|
-
} else if (result.status ===
|
|
611
|
+
} else if (result.status === 'skipped') {
|
|
612
612
|
console.log(`User ${result.xmppUsername} update skipped`);
|
|
613
613
|
}
|
|
614
614
|
});
|
|
615
615
|
|
|
616
616
|
return response;
|
|
617
617
|
} catch (error) {
|
|
618
|
-
console.error(
|
|
618
|
+
console.error('Failed to update users:', error);
|
|
619
619
|
throw error;
|
|
620
620
|
}
|
|
621
621
|
}
|
|
@@ -628,8 +628,8 @@ async function updateUsersExample() {
|
|
|
628
628
|
The SDK uses Axios for HTTP requests, so errors are AxiosError instances:
|
|
629
629
|
|
|
630
630
|
```typescript
|
|
631
|
-
import axios from
|
|
632
|
-
import { getEthoraSDKService } from
|
|
631
|
+
import axios from 'axios';
|
|
632
|
+
import { getEthoraSDKService } from '@ethora/sdk-backend';
|
|
633
633
|
|
|
634
634
|
const chatService = getEthoraSDKService();
|
|
635
635
|
|
|
@@ -644,20 +644,20 @@ async function createChatRoomSafely(workspaceId: string) {
|
|
|
644
644
|
// Handle specific error cases
|
|
645
645
|
if (status === 422) {
|
|
646
646
|
// Validation error
|
|
647
|
-
console.error(
|
|
647
|
+
console.error('Validation error:', errorData);
|
|
648
648
|
} else if (status === 401) {
|
|
649
649
|
// Authentication error
|
|
650
|
-
console.error(
|
|
650
|
+
console.error('Authentication failed - check your credentials');
|
|
651
651
|
} else if (status === 404) {
|
|
652
652
|
// Resource not found
|
|
653
|
-
console.error(
|
|
653
|
+
console.error('Resource not found');
|
|
654
654
|
} else {
|
|
655
655
|
// Other HTTP errors
|
|
656
656
|
console.error(`HTTP error ${status}:`, errorData);
|
|
657
657
|
}
|
|
658
658
|
} else {
|
|
659
659
|
// Non-HTTP errors
|
|
660
|
-
console.error(
|
|
660
|
+
console.error('Unexpected error:', error);
|
|
661
661
|
}
|
|
662
662
|
throw error;
|
|
663
663
|
}
|
|
@@ -678,17 +678,17 @@ async function ensureChatRoomExists(workspaceId: string) {
|
|
|
678
678
|
if (axios.isAxiosError(error)) {
|
|
679
679
|
const errorData = error.response?.data;
|
|
680
680
|
const errorMessage =
|
|
681
|
-
typeof errorData ===
|
|
682
|
-
? (errorData as { error?: string }).error ||
|
|
683
|
-
: String(errorData ||
|
|
681
|
+
typeof errorData === 'object' && errorData !== null
|
|
682
|
+
? (errorData as { error?: string }).error || ''
|
|
683
|
+
: String(errorData || '');
|
|
684
684
|
|
|
685
685
|
// If room already exists, that's okay
|
|
686
686
|
if (
|
|
687
687
|
error.response?.status === 422 &&
|
|
688
|
-
(errorMessage.includes(
|
|
689
|
-
errorMessage.includes(
|
|
688
|
+
(errorMessage.includes('already exist') ||
|
|
689
|
+
errorMessage.includes('already exists'))
|
|
690
690
|
) {
|
|
691
|
-
console.log(
|
|
691
|
+
console.log('Chat room already exists, continuing...');
|
|
692
692
|
return; // Success - room exists
|
|
693
693
|
}
|
|
694
694
|
}
|
|
@@ -719,8 +719,8 @@ Create a service wrapper in your application:
|
|
|
719
719
|
|
|
720
720
|
```typescript
|
|
721
721
|
// services/chatService.ts
|
|
722
|
-
import { getEthoraSDKService } from
|
|
723
|
-
import type { ChatRepository } from
|
|
722
|
+
import { getEthoraSDKService } from '@ethora/sdk-backend';
|
|
723
|
+
import type { ChatRepository } from '@ethora/sdk-backend';
|
|
724
724
|
|
|
725
725
|
class ChatServiceWrapper {
|
|
726
726
|
private service: ChatRepository;
|
|
@@ -752,16 +752,16 @@ Validate environment variables on application startup:
|
|
|
752
752
|
// config/validateEnv.ts
|
|
753
753
|
function validateEthoraConfig() {
|
|
754
754
|
const required = [
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
755
|
+
'ETHORA_CHAT_API_URL',
|
|
756
|
+
'ETHORA_CHAT_APP_ID',
|
|
757
|
+
'ETHORA_CHAT_APP_SECRET',
|
|
758
758
|
];
|
|
759
759
|
|
|
760
760
|
const missing = required.filter((key) => !process.env[key]);
|
|
761
761
|
|
|
762
762
|
if (missing.length > 0) {
|
|
763
763
|
throw new Error(
|
|
764
|
-
`Missing required Ethora environment variables: ${missing.join(
|
|
764
|
+
`Missing required Ethora environment variables: ${missing.join(', ')}`,
|
|
765
765
|
);
|
|
766
766
|
}
|
|
767
767
|
}
|
|
@@ -775,8 +775,8 @@ validateEthoraConfig();
|
|
|
775
775
|
Integrate with your existing logging system:
|
|
776
776
|
|
|
777
777
|
```typescript
|
|
778
|
-
import { getEthoraSDKService } from
|
|
779
|
-
import { logger } from
|
|
778
|
+
import { getEthoraSDKService } from '@ethora/sdk-backend';
|
|
779
|
+
import { logger } from './utils/logger'; // Your logger
|
|
780
780
|
|
|
781
781
|
const chatService = getEthoraSDKService();
|
|
782
782
|
|
|
@@ -798,7 +798,7 @@ async function createChatRoomWithLogging(workspaceId: string) {
|
|
|
798
798
|
Use TypeScript types from the SDK:
|
|
799
799
|
|
|
800
800
|
```typescript
|
|
801
|
-
import type { UUID, ApiResponse } from
|
|
801
|
+
import type { UUID, ApiResponse } from '@ethora/sdk-backend';
|
|
802
802
|
|
|
803
803
|
async function createUserTyped(
|
|
804
804
|
userId: UUID,
|
|
@@ -806,7 +806,7 @@ async function createUserTyped(
|
|
|
806
806
|
firstName: string;
|
|
807
807
|
lastName: string;
|
|
808
808
|
email: string;
|
|
809
|
-
}
|
|
809
|
+
},
|
|
810
810
|
): Promise<ApiResponse> {
|
|
811
811
|
const chatService = getEthoraSDKService();
|
|
812
812
|
return await chatService.createUser(userId, userData);
|
|
@@ -839,7 +839,7 @@ try {
|
|
|
839
839
|
} catch (error) {
|
|
840
840
|
if (axios.isAxiosError(error) && error.response?.status === 422) {
|
|
841
841
|
// User already exists, continue
|
|
842
|
-
console.log(
|
|
842
|
+
console.log('User already exists');
|
|
843
843
|
} else {
|
|
844
844
|
throw error;
|
|
845
845
|
}
|
|
@@ -887,3 +887,6 @@ Apache 2.0
|
|
|
887
887
|
## Support
|
|
888
888
|
|
|
889
889
|
For issues and questions, please open an issue on the GitHub repository.
|
|
890
|
+
|
|
891
|
+
To run tests with logs run from root:
|
|
892
|
+
TEST_LOG_FILE=logs/chat-repo.log npm test
|