shuttlepro-shared 1.4.1 → 1.4.2

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.
@@ -1,5 +1,4 @@
1
1
  const Call = require("../../models/Call");
2
- const mongoose = require("mongoose");
3
2
 
4
3
  class CallRepository {
5
4
  constructor() {
@@ -9,39 +8,32 @@ class CallRepository {
9
8
  };
10
9
  }
11
10
 
12
- // Create a new call with transaction support
11
+ // Create a new call without transaction
13
12
  async createCall(callData) {
14
- const session = await mongoose.startSession();
15
-
16
13
  try {
17
- return await session.withTransaction(async () => {
18
- const call = new Call({
19
- callId: callData.callId,
20
- callerName: callData.callerName,
21
- callerNumber: callData.callerNumber,
22
- whatsappSdp: callData.whatsappSdp,
23
- status: callData.status || "pending",
24
- autoAccepted: callData.autoAccepted || false,
25
- metadata: callData.metadata || {},
26
- tags: callData.tags || [],
27
- priority: callData.priority || 0,
28
- platformId: callData.platformId || null,
29
- workspaceId: callData.workspaceId || null,
30
- profileId: callData.profileId || null,
31
- });
32
-
33
- call.addToHistory("created", null, "Call created in system");
34
- await call.save({ session });
35
-
36
- await this._updateCallMetrics("created", session);
37
-
38
- return call;
14
+ const call = new Call({
15
+ callId: callData.callId,
16
+ callerName: callData.callerName,
17
+ callerNumber: callData.callerNumber,
18
+ whatsappSdp: callData.whatsappSdp,
19
+ status: callData.status || "pending",
20
+ autoAccepted: callData.autoAccepted || false,
21
+ metadata: callData.metadata || {},
22
+ tags: callData.tags || [],
23
+ priority: callData.priority || 0,
24
+ platformId: callData.platformId || null,
25
+ workspaceId: callData.workspaceId || null,
26
+ profileId: callData.profileId || null,
39
27
  });
28
+
29
+ call.addToHistory("created", null, "Call created in system");
30
+ await call.save();
31
+
32
+ await this._updateCallMetrics("created");
33
+ return call;
40
34
  } catch (error) {
41
35
  console.error(`Failed to create call ${callData.callId}:`, error);
42
36
  throw error;
43
- } finally {
44
- await session.endSession();
45
37
  }
46
38
  }
47
39
 
@@ -52,7 +44,6 @@ class CallRepository {
52
44
 
53
45
  if (options.lean) query.lean();
54
46
 
55
- // Auto-populate unless explicitly disabled
56
47
  if (options.populate !== false) {
57
48
  query.populate([
58
49
  { path: "platformId", model: "Integration" },
@@ -72,7 +63,7 @@ class CallRepository {
72
63
  }
73
64
  }
74
65
 
75
- // Bulk get calls with advanced filtering
66
+ // Bulk get calls
76
67
  async getCalls(filters = {}, options = {}) {
77
68
  try {
78
69
  const {
@@ -90,7 +81,6 @@ class CallRepository {
90
81
  } = filters;
91
82
 
92
83
  const query = {};
93
-
94
84
  if (status)
95
85
  query.status = Array.isArray(status) ? { $in: status } : status;
96
86
  if (agentId) query.agentId = agentId;
@@ -106,7 +96,7 @@ class CallRepository {
106
96
  }
107
97
 
108
98
  if (priority !== undefined) query.priority = { $gte: priority };
109
- if (tags && tags.length > 0) query.tags = { $in: tags };
99
+ if (tags?.length > 0) query.tags = { $in: tags };
110
100
 
111
101
  const skip = (page - 1) * limit;
112
102
 
@@ -144,128 +134,108 @@ class CallRepository {
144
134
  }
145
135
  }
146
136
 
147
- // Update call with optimistic locking
148
- async updateCall(callId, updateData, options = {}) {
149
- const session = options.session || (await mongoose.startSession());
150
- const shouldCommitSession = !options.session;
151
-
137
+ // Update call
138
+ async updateCall(callId, updateData) {
152
139
  try {
153
- return await session.withTransaction(async () => {
154
- const call = await Call.findOne({ callId }).session(session);
155
- if (!call) throw new Error(`Call ${callId} not found`);
140
+ const call = await Call.findOne({ callId });
141
+ if (!call) throw new Error(`Call ${callId} not found`);
156
142
 
157
- if (updateData.__v !== undefined && call.__v !== updateData.__v) {
158
- throw new Error(`Concurrent update detected for call ${callId}`);
159
- }
143
+ if (updateData.__v !== undefined && call.__v !== updateData.__v) {
144
+ throw new Error(`Concurrent update detected for call ${callId}`);
145
+ }
160
146
 
161
- const allowedFields = [
162
- "status",
163
- "agentId",
164
- "callerName",
165
- "callerNumber",
166
- "priority",
167
- "tags",
168
- "metadata",
169
- "isOnHold",
170
- "platformId",
171
- "workspaceId",
172
- "profileId",
173
- ];
174
-
175
- Object.keys(updateData).forEach((key) => {
176
- if (allowedFields.includes(key)) {
177
- call[key] = updateData[key];
178
- }
179
- });
180
-
181
- if (updateData.status && updateData.status !== call.status) {
182
- call.addToHistory(
183
- updateData.status,
184
- updateData.agentId || call.agentId,
185
- updateData.reason || `Status changed to ${updateData.status}`
186
- );
147
+ const allowedFields = [
148
+ "status",
149
+ "agentId",
150
+ "callerName",
151
+ "callerNumber",
152
+ "priority",
153
+ "tags",
154
+ "metadata",
155
+ "isOnHold",
156
+ "platformId",
157
+ "workspaceId",
158
+ "profileId",
159
+ ];
160
+
161
+ Object.keys(updateData).forEach((key) => {
162
+ if (allowedFields.includes(key)) {
163
+ call[key] = updateData[key];
187
164
  }
165
+ });
188
166
 
189
- call.updateHeartbeat();
190
- await call.save({ session });
167
+ if (updateData.status && updateData.status !== call.status) {
168
+ call.addToHistory(
169
+ updateData.status,
170
+ updateData.agentId || call.agentId,
171
+ updateData.reason || `Status changed to ${updateData.status}`
172
+ );
173
+ }
191
174
 
192
- return call;
193
- });
175
+ call.updateHeartbeat();
176
+ await call.save();
177
+ return call;
194
178
  } catch (error) {
195
179
  console.error(`Failed to update call ${callId}:`, error);
196
180
  throw error;
197
- } finally {
198
- if (shouldCommitSession) await session.endSession();
199
181
  }
200
182
  }
201
183
 
202
184
  // Assign call to agent
203
- async assignCallToAgent(callId, agentId, options = {}) {
204
- const session = await mongoose.startSession();
205
-
185
+ async assignCallToAgent(callId, agentId) {
206
186
  try {
207
- return await session.withTransaction(async () => {
208
- const call = await Call.findOne({ callId }).session(session);
209
- if (!call) throw new Error(`Call ${callId} not found`);
187
+ const call = await Call.findOne({ callId });
188
+ if (!call) throw new Error(`Call ${callId} not found`);
210
189
 
211
- if (call.status !== "pending" && call.status !== "hold") {
212
- throw new Error(`Call ${callId} is not available for assignment`);
213
- }
190
+ if (call.status !== "pending" && call.status !== "hold") {
191
+ throw new Error(`Call ${callId} is not available for assignment`);
192
+ }
214
193
 
215
- call.agentId = agentId;
216
- call.status = "active";
217
- call.startTime = new Date();
218
- call.isOnHold = false;
219
- call.addToHistory("answered", agentId, "Call answered by agent");
220
- call.updateHeartbeat();
194
+ call.agentId = agentId;
195
+ call.status = "active";
196
+ call.startTime = new Date();
197
+ call.isOnHold = false;
198
+ call.addToHistory("answered", agentId, "Call answered by agent");
199
+ call.updateHeartbeat();
221
200
 
222
- await call.save({ session });
223
- return call;
224
- });
201
+ await call.save();
202
+ return call;
225
203
  } catch (error) {
226
204
  console.error(
227
205
  `Failed to assign call ${callId} to agent ${agentId}:`,
228
206
  error
229
207
  );
230
208
  throw error;
231
- } finally {
232
- await session.endSession();
233
209
  }
234
210
  }
235
211
 
236
- // Bulk operations for call management
212
+ // Bulk update calls
237
213
  async bulkUpdateCalls(operations) {
238
- const session = await mongoose.startSession();
239
-
240
214
  try {
241
- return await session.withTransaction(async () => {
242
- const bulkOps = operations.map((op) => ({
243
- updateOne: {
244
- filter: { callId: op.callId },
245
- update: {
246
- $set: {
247
- ...op.updateData,
248
- lastHeartbeat: new Date(),
249
- },
250
- $push: {
251
- callHistory: {
252
- timestamp: new Date(),
253
- action: op.action || "bulk_update",
254
- agentId: op.agentId,
255
- details: op.details || "Bulk operation",
256
- },
215
+ const bulkOps = operations.map((op) => ({
216
+ updateOne: {
217
+ filter: { callId: op.callId },
218
+ update: {
219
+ $set: {
220
+ ...op.updateData,
221
+ lastHeartbeat: new Date(),
222
+ },
223
+ $push: {
224
+ callHistory: {
225
+ timestamp: new Date(),
226
+ action: op.action || "bulk_update",
227
+ agentId: op.agentId,
228
+ details: op.details || "Bulk operation",
257
229
  },
258
230
  },
259
231
  },
260
- }));
232
+ },
233
+ }));
261
234
 
262
- return await Call.bulkWrite(bulkOps, { session });
263
- });
235
+ return await Call.bulkWrite(bulkOps);
264
236
  } catch (error) {
265
237
  console.error("Failed to perform bulk update:", error);
266
238
  throw error;
267
- } finally {
268
- await session.endSession();
269
239
  }
270
240
  }
271
241
 
@@ -374,43 +344,34 @@ class CallRepository {
374
344
 
375
345
  // Cleanup stale connections
376
346
  async cleanupStaleConnections(timeoutMinutes = 5) {
377
- const session = await mongoose.startSession();
378
-
379
347
  try {
380
- return await session.withTransaction(async () => {
381
- const cutoffTime = new Date(Date.now() - timeoutMinutes * 60 * 1000);
382
-
383
- const staleCalls = await Call.find({
384
- status: { $in: ["active", "hold", "pending"] },
385
- lastHeartbeat: { $lt: cutoffTime },
386
- }).session(session);
387
-
388
- const results = [];
389
-
390
- for (const call of staleCalls) {
391
- if (call.agentId) {
392
- await this.moveCallToHoldQueue(call.callId, "Connection timeout", {
393
- session,
394
- });
395
- results.push({ callId: call.callId, action: "moved_to_hold" });
396
- } else {
397
- await this.endCall(call.callId, null, { session });
398
- results.push({ callId: call.callId, action: "ended" });
399
- }
400
- }
348
+ const cutoffTime = new Date(Date.now() - timeoutMinutes * 60 * 1000);
401
349
 
402
- console.log(`Cleaned up ${results.length} stale connections`);
403
- return results;
350
+ const staleCalls = await Call.find({
351
+ status: { $in: ["active", "hold", "pending"] },
352
+ lastHeartbeat: { $lt: cutoffTime },
404
353
  });
354
+
355
+ const results = [];
356
+
357
+ for (const call of staleCalls) {
358
+ if (call.agentId) {
359
+ await this.moveCallToHoldQueue(call.callId, "Connection timeout");
360
+ results.push({ callId: call.callId, action: "moved_to_hold" });
361
+ } else {
362
+ await this.endCall(call.callId);
363
+ results.push({ callId: call.callId, action: "ended" });
364
+ }
365
+ }
366
+
367
+ console.log(`Cleaned up ${results.length} stale connections`);
368
+ return results;
405
369
  } catch (error) {
406
370
  console.error("Failed to cleanup stale connections:", error);
407
371
  throw error;
408
- } finally {
409
- await session.endSession();
410
372
  }
411
373
  }
412
374
 
413
- // Helper methods
414
375
  _buildDateFilter(timeframe) {
415
376
  const now = new Date();
416
377
  switch (timeframe) {
@@ -464,7 +425,7 @@ class CallRepository {
464
425
  };
465
426
  }
466
427
 
467
- async _updateCallMetrics(action, session = null) {
428
+ async _updateCallMetrics(action) {
468
429
  try {
469
430
  console.log(`Updating metrics for action: ${action}`);
470
431
  } catch (error) {
@@ -472,67 +433,46 @@ class CallRepository {
472
433
  }
473
434
  }
474
435
 
475
- async moveCallToHoldQueue(
476
- callId,
477
- reason = "Agent disconnected",
478
- options = {}
479
- ) {
480
- const session = options.session || (await mongoose.startSession());
481
- const shouldCommitSession = !options.session;
482
-
436
+ async moveCallToHoldQueue(callId, reason = "Agent disconnected") {
483
437
  try {
484
- return await session.withTransaction(async () => {
485
- const call = await Call.findOne({ callId }).session(session);
486
- if (!call) throw new Error(`Call ${callId} not found`);
487
-
488
- const previousAgentId = call.agentId;
489
-
490
- call.agentId = null;
491
- call.status = "hold";
492
- call.isOnHold = true;
493
- call.autoAccepted = true;
494
- call.isHoldConnection = true;
495
- call.priority = Math.min(call.priority + 1, 10);
496
- call.addToHistory("disconnected", previousAgentId, reason);
497
- call.updateHeartbeat();
498
-
499
- await call.save({ session });
500
-
501
- console.log(
502
- `Call ${callId} moved back to hold queue due to: ${reason}`
503
- );
504
- return call;
505
- });
438
+ const call = await Call.findOne({ callId });
439
+ if (!call) throw new Error(`Call ${callId} not found`);
440
+
441
+ const previousAgentId = call.agentId;
442
+
443
+ call.agentId = null;
444
+ call.status = "hold";
445
+ call.isOnHold = true;
446
+ call.autoAccepted = true;
447
+ call.isHoldConnection = true;
448
+ call.priority = Math.min(call.priority + 1, 10);
449
+ call.addToHistory("disconnected", previousAgentId, reason);
450
+ call.updateHeartbeat();
451
+
452
+ await call.save();
453
+ console.log(`Call ${callId} moved back to hold queue due to: ${reason}`);
454
+ return call;
506
455
  } catch (error) {
507
456
  console.error(`Failed to move call ${callId} to hold queue:`, error);
508
457
  throw error;
509
- } finally {
510
- if (shouldCommitSession) await session.endSession();
511
458
  }
512
459
  }
513
460
 
514
- async endCall(callId, agentId = null, options = {}) {
515
- const session = options.session || (await mongoose.startSession());
516
- const shouldCommitSession = !options.session;
517
-
461
+ async endCall(callId, agentId = null) {
518
462
  try {
519
- return await session.withTransaction(async () => {
520
- const call = await Call.findOne({ callId }).session(session);
521
- if (!call) throw new Error(`Call ${callId} not found`);
463
+ const call = await Call.findOne({ callId });
464
+ if (!call) throw new Error(`Call ${callId} not found`);
522
465
 
523
- call.status = "ended";
524
- call.endTime = new Date();
525
- call.duration = call.currentDuration;
526
- call.addToHistory("ended", agentId, "Call ended");
466
+ call.status = "ended";
467
+ call.endTime = new Date();
468
+ call.duration = call.currentDuration;
469
+ call.addToHistory("ended", agentId, "Call ended");
527
470
 
528
- await call.save({ session });
529
- return call;
530
- });
471
+ await call.save();
472
+ return call;
531
473
  } catch (error) {
532
474
  console.error(`Failed to end call ${callId}:`, error);
533
475
  throw error;
534
- } finally {
535
- if (shouldCommitSession) await session.endSession();
536
476
  }
537
477
  }
538
478
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shuttlepro-shared",
3
- "version": "1.4.01",
3
+ "version": "1.4.02",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {