powr-sdk-api 4.6.5 → 4.7.0

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.
Files changed (2) hide show
  1. package/dist/routes/chat.js +91 -22
  2. package/package.json +1 -1
@@ -22,20 +22,9 @@ router.get('/conversations', async (req, res) => {
22
22
  projectId: projectId
23
23
  }).toArray();
24
24
 
25
- // Get user details for each conversation
25
+ // Build response for each conversation
26
26
  const conversationsWithUsers = await Promise.all(conversations.map(async conv => {
27
- const otherUserId = conv.participants.find(id => id !== userId);
28
- console.log('Looking for other user with ID:', otherUserId, 'type:', typeof otherUserId);
29
- const otherUser = await db.collection('users').findOne({
30
- _id: new ObjectId(otherUserId)
31
- }, {
32
- projection: {
33
- fullName: 1,
34
- username: 1,
35
- avatar: 1
36
- }
37
- });
38
- console.log('Found other user:', otherUser);
27
+ const isGroup = conv.type === 'group';
39
28
 
40
29
  // Get last message
41
30
  const lastMessage = await db.collection('messages').findOne({
@@ -54,14 +43,32 @@ router.get('/conversations', async (req, res) => {
54
43
  },
55
44
  read: false
56
45
  });
46
+ let displayName, avatar;
47
+ if (isGroup) {
48
+ displayName = conv.name || 'Group';
49
+ avatar = null; // Groups typically use icon, not user avatar
50
+ } else {
51
+ const otherUserId = conv.participants.find(p => String(p) !== String(userId));
52
+ const otherUser = otherUserId ? await db.collection('users').findOne({
53
+ _id: new ObjectId(otherUserId)
54
+ }, {
55
+ projection: {
56
+ fullName: 1,
57
+ avatar: 1
58
+ }
59
+ }) : null;
60
+ displayName = (otherUser === null || otherUser === void 0 ? void 0 : otherUser.fullName) || 'Unknown User';
61
+ avatar = otherUser === null || otherUser === void 0 ? void 0 : otherUser.avatar;
62
+ }
57
63
  return {
58
64
  id: conv._id.toString(),
59
- name: (otherUser === null || otherUser === void 0 ? void 0 : otherUser.fullName) || 'Unknown User',
60
- avatar: otherUser === null || otherUser === void 0 ? void 0 : otherUser.avatar,
65
+ type: isGroup ? 'group' : 'dm',
66
+ name: displayName,
67
+ avatar,
61
68
  lastMessage: (lastMessage === null || lastMessage === void 0 ? void 0 : lastMessage.content) || '',
62
69
  lastMessageTime: (lastMessage === null || lastMessage === void 0 ? void 0 : lastMessage.createdAt) || conv.createdAt,
63
70
  unreadCount,
64
- isOnline: false // Simple implementation - could be enhanced later
71
+ isOnline: false
65
72
  };
66
73
  }));
67
74
  return res.json({
@@ -214,23 +221,84 @@ router.post('/conversations/:conversationId/messages', async (req, res) => {
214
221
  }
215
222
  });
216
223
 
217
- // Create a new conversation
224
+ // Create a new conversation (DM or group)
218
225
  router.post('/conversations', async (req, res) => {
219
226
  try {
220
227
  const {
221
228
  participantId,
229
+ participantIds,
230
+ type,
231
+ name,
222
232
  projectId: bodyProjectId
223
233
  } = req.body;
224
234
  const userId = req.user.powrId;
225
235
  const userAccess = req.user.access;
226
236
  const projectId = bodyProjectId || req.projectId;
237
+ const db = await getDb();
238
+
239
+ // --- GROUP ---
240
+ if (type === 'group') {
241
+ if (!participantIds || !Array.isArray(participantIds) || participantIds.length === 0) {
242
+ return res.status(400).json({
243
+ success: false,
244
+ message: "participantIds (array) is required for group"
245
+ });
246
+ }
247
+ if (!name || typeof name !== 'string' || !name.trim()) {
248
+ return res.status(400).json({
249
+ success: false,
250
+ message: "name is required for group"
251
+ });
252
+ }
253
+
254
+ // Normalize participant IDs (ensure strings, dedupe, include creator)
255
+ const normalizedIds = [...new Set([userId, ...participantIds.map(id => String(id))])];
256
+
257
+ // Check if group with same projectId + name already exists
258
+ const existingGroup = await db.collection('conversations').findOne({
259
+ type: 'group',
260
+ projectId: projectId,
261
+ name: name.trim()
262
+ });
263
+ if (existingGroup) {
264
+ // Return existing if creator is a participant
265
+ const isParticipant = existingGroup.participants.some(p => String(p) === String(userId));
266
+ if (isParticipant) {
267
+ return res.json({
268
+ success: true,
269
+ data: {
270
+ id: existingGroup._id.toString(),
271
+ message: 'Group already exists'
272
+ }
273
+ });
274
+ }
275
+ }
276
+ const conversation = {
277
+ type: 'group',
278
+ participants: normalizedIds,
279
+ name: name.trim(),
280
+ projectId: projectId,
281
+ createdBy: userId,
282
+ createdAt: new Date(),
283
+ updatedAt: new Date()
284
+ };
285
+ const result = await db.collection('conversations').insertOne(conversation);
286
+ return res.status(201).json({
287
+ success: true,
288
+ data: {
289
+ id: result.insertedId.toString(),
290
+ message: 'Group created successfully'
291
+ }
292
+ });
293
+ }
294
+
295
+ // --- DM (default) ---
227
296
  if (!participantId) {
228
297
  return res.status(400).json({
229
298
  success: false,
230
- message: "Participant ID is required"
299
+ message: "Participant ID is required for DM (or use type: 'group' with participantIds)"
231
300
  });
232
301
  }
233
- const db = await getDb();
234
302
 
235
303
  // Check if user has permission to chat with this participant
236
304
  const participant = await db.collection('users').findOne({
@@ -250,13 +318,10 @@ router.post('/conversations', async (req, res) => {
250
318
  // Validate access permissions
251
319
  let hasPermission = false;
252
320
  if (userAccess === 100) {
253
- // Admin can chat with everyone
254
321
  hasPermission = true;
255
322
  } else if (userAccess === 900) {
256
- // Client can only chat with admins
257
323
  hasPermission = participant.access === 100;
258
324
  } else {
259
- // Employee can chat with employees and admins
260
325
  hasPermission = participant.access === 100 || participant.access === null;
261
326
  }
262
327
  if (!hasPermission) {
@@ -268,6 +333,9 @@ router.post('/conversations', async (req, res) => {
268
333
 
269
334
  // Check if conversation already exists
270
335
  const existingConversation = await db.collection('conversations').findOne({
336
+ type: {
337
+ $ne: 'group'
338
+ },
271
339
  participants: {
272
340
  $all: [userId, participantId]
273
341
  },
@@ -283,6 +351,7 @@ router.post('/conversations', async (req, res) => {
283
351
  });
284
352
  }
285
353
  const conversation = {
354
+ type: 'dm',
286
355
  participants: [userId, participantId],
287
356
  projectId: projectId,
288
357
  createdAt: new Date(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "powr-sdk-api",
3
- "version": "4.6.5",
3
+ "version": "4.7.0",
4
4
  "description": "Shared API core library for PowrStack projects. Zero dependencies - works with Express, Next.js API routes, and other frameworks. All features are optional and install only what you need.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",