powr-sdk-api 4.6.5 → 4.7.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.
Files changed (2) hide show
  1. package/dist/routes/chat.js +99 -29
  2. package/package.json +1 -1
@@ -17,25 +17,14 @@ router.get('/conversations', async (req, res) => {
17
17
  const projectId = req.projectId;
18
18
  console.log('Current user ID:', userId, 'Access:', userAccess, 'Project:', projectId);
19
19
  const db = await getDb();
20
+ // Show all conversations user is in (1:1 DMs and groups, any project)
20
21
  const conversations = await db.collection('conversations').find({
21
- participants: userId,
22
- projectId: projectId
22
+ participants: userId
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({
@@ -90,11 +97,13 @@ router.get('/conversations/:conversationId/messages', async (req, res) => {
90
97
  // Verify user is part of conversation
91
98
  const conversation = await db.collection('conversations').findOne({
92
99
  _id: new ObjectId(conversationId),
93
- participants: userId,
94
- projectId: projectId
100
+ participants: userId
95
101
  });
96
102
  if (!conversation) {
97
- return res.error('Conversation not found', 404);
103
+ return res.status(404).json({
104
+ success: false,
105
+ message: 'Conversation not found'
106
+ });
98
107
  }
99
108
  const messages = await db.collection('messages').find({
100
109
  conversationId: conversationId
@@ -157,8 +166,7 @@ router.post('/conversations/:conversationId/messages', async (req, res) => {
157
166
  // Verify user is part of conversation
158
167
  const conversation = await db.collection('conversations').findOne({
159
168
  _id: new ObjectId(conversationId),
160
- participants: userId,
161
- projectId: projectId
169
+ participants: userId
162
170
  });
163
171
  if (!conversation) {
164
172
  return res.status(404).json({
@@ -214,23 +222,84 @@ router.post('/conversations/:conversationId/messages', async (req, res) => {
214
222
  }
215
223
  });
216
224
 
217
- // Create a new conversation
225
+ // Create a new conversation (DM or group)
218
226
  router.post('/conversations', async (req, res) => {
219
227
  try {
220
228
  const {
221
229
  participantId,
230
+ participantIds,
231
+ type,
232
+ name,
222
233
  projectId: bodyProjectId
223
234
  } = req.body;
224
235
  const userId = req.user.powrId;
225
236
  const userAccess = req.user.access;
226
237
  const projectId = bodyProjectId || req.projectId;
238
+ const db = await getDb();
239
+
240
+ // --- GROUP ---
241
+ if (type === 'group') {
242
+ if (!participantIds || !Array.isArray(participantIds) || participantIds.length === 0) {
243
+ return res.status(400).json({
244
+ success: false,
245
+ message: "participantIds (array) is required for group"
246
+ });
247
+ }
248
+ if (!name || typeof name !== 'string' || !name.trim()) {
249
+ return res.status(400).json({
250
+ success: false,
251
+ message: "name is required for group"
252
+ });
253
+ }
254
+
255
+ // Normalize participant IDs (ensure strings, dedupe, include creator)
256
+ const normalizedIds = [...new Set([userId, ...participantIds.map(id => String(id))])];
257
+
258
+ // Check if group with same projectId + name already exists
259
+ const existingGroup = await db.collection('conversations').findOne({
260
+ type: 'group',
261
+ projectId: projectId,
262
+ name: name.trim()
263
+ });
264
+ if (existingGroup) {
265
+ // Return existing if creator is a participant
266
+ const isParticipant = existingGroup.participants.some(p => String(p) === String(userId));
267
+ if (isParticipant) {
268
+ return res.json({
269
+ success: true,
270
+ data: {
271
+ id: existingGroup._id.toString(),
272
+ message: 'Group already exists'
273
+ }
274
+ });
275
+ }
276
+ }
277
+ const conversation = {
278
+ type: 'group',
279
+ participants: normalizedIds,
280
+ name: name.trim(),
281
+ projectId: projectId,
282
+ createdBy: userId,
283
+ createdAt: new Date(),
284
+ updatedAt: new Date()
285
+ };
286
+ const result = await db.collection('conversations').insertOne(conversation);
287
+ return res.status(201).json({
288
+ success: true,
289
+ data: {
290
+ id: result.insertedId.toString(),
291
+ message: 'Group created successfully'
292
+ }
293
+ });
294
+ }
295
+
296
+ // --- DM (default) ---
227
297
  if (!participantId) {
228
298
  return res.status(400).json({
229
299
  success: false,
230
- message: "Participant ID is required"
300
+ message: "Participant ID is required for DM (or use type: 'group' with participantIds)"
231
301
  });
232
302
  }
233
- const db = await getDb();
234
303
 
235
304
  // Check if user has permission to chat with this participant
236
305
  const participant = await db.collection('users').findOne({
@@ -250,13 +319,10 @@ router.post('/conversations', async (req, res) => {
250
319
  // Validate access permissions
251
320
  let hasPermission = false;
252
321
  if (userAccess === 100) {
253
- // Admin can chat with everyone
254
322
  hasPermission = true;
255
323
  } else if (userAccess === 900) {
256
- // Client can only chat with admins
257
324
  hasPermission = participant.access === 100;
258
325
  } else {
259
- // Employee can chat with employees and admins
260
326
  hasPermission = participant.access === 100 || participant.access === null;
261
327
  }
262
328
  if (!hasPermission) {
@@ -268,6 +334,9 @@ router.post('/conversations', async (req, res) => {
268
334
 
269
335
  // Check if conversation already exists
270
336
  const existingConversation = await db.collection('conversations').findOne({
337
+ type: {
338
+ $ne: 'group'
339
+ },
271
340
  participants: {
272
341
  $all: [userId, participantId]
273
342
  },
@@ -283,6 +352,7 @@ router.post('/conversations', async (req, res) => {
283
352
  });
284
353
  }
285
354
  const conversation = {
355
+ type: 'dm',
286
356
  participants: [userId, participantId],
287
357
  projectId: projectId,
288
358
  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.1",
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",