@app-connect/core 1.7.25 → 1.7.27

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 (138) hide show
  1. package/.env.test +5 -5
  2. package/README.md +441 -441
  3. package/connector/developerPortal.js +31 -31
  4. package/connector/mock.js +84 -77
  5. package/connector/proxy/engine.js +164 -164
  6. package/connector/proxy/index.js +500 -500
  7. package/connector/registry.js +252 -252
  8. package/docs/README.md +50 -50
  9. package/docs/architecture.md +93 -93
  10. package/docs/connectors.md +116 -116
  11. package/docs/handlers.md +125 -125
  12. package/docs/libraries.md +101 -101
  13. package/docs/models.md +144 -144
  14. package/docs/routes.md +115 -115
  15. package/docs/tests.md +73 -73
  16. package/handlers/admin.js +523 -523
  17. package/handlers/appointment.js +193 -0
  18. package/handlers/auth.js +320 -296
  19. package/handlers/calldown.js +99 -99
  20. package/handlers/contact.js +280 -280
  21. package/handlers/disposition.js +82 -80
  22. package/handlers/log.js +990 -973
  23. package/handlers/managedAuth.js +446 -446
  24. package/handlers/managedOAuth.js +247 -0
  25. package/handlers/plugin.js +208 -208
  26. package/handlers/user.js +142 -142
  27. package/index.js +3162 -2652
  28. package/jest.config.js +56 -56
  29. package/lib/analytics.js +54 -54
  30. package/lib/authSession.js +109 -109
  31. package/lib/cacheCleanup.js +21 -0
  32. package/lib/callLogComposer.js +898 -898
  33. package/lib/callLogLookup.js +34 -0
  34. package/lib/constants.js +8 -8
  35. package/lib/debugTracer.js +177 -177
  36. package/lib/encode.js +30 -30
  37. package/lib/errorHandler.js +218 -206
  38. package/lib/generalErrorMessage.js +41 -41
  39. package/lib/jwt.js +18 -18
  40. package/lib/logger.js +190 -190
  41. package/lib/migrateCallLogsSchema.js +116 -0
  42. package/lib/ringcentral.js +266 -266
  43. package/lib/s3ErrorLogReport.js +65 -65
  44. package/lib/sharedSMSComposer.js +471 -471
  45. package/lib/util.js +67 -67
  46. package/mcp/README.md +412 -395
  47. package/mcp/lib/validator.js +91 -91
  48. package/mcp/mcpHandler.js +425 -425
  49. package/mcp/tools/cancelAppointment.js +101 -0
  50. package/mcp/tools/checkAuthStatus.js +105 -105
  51. package/mcp/tools/confirmAppointment.js +101 -0
  52. package/mcp/tools/createAppointment.js +157 -0
  53. package/mcp/tools/createCallLog.js +327 -316
  54. package/mcp/tools/createContact.js +117 -117
  55. package/mcp/tools/createMessageLog.js +287 -287
  56. package/mcp/tools/doAuth.js +60 -60
  57. package/mcp/tools/findContactByName.js +93 -93
  58. package/mcp/tools/findContactByPhone.js +101 -101
  59. package/mcp/tools/getCallLog.js +111 -102
  60. package/mcp/tools/getGoogleFilePicker.js +99 -99
  61. package/mcp/tools/getHelp.js +43 -43
  62. package/mcp/tools/getPublicConnectors.js +94 -94
  63. package/mcp/tools/getSessionInfo.js +90 -90
  64. package/mcp/tools/index.js +51 -41
  65. package/mcp/tools/listAppointments.js +163 -0
  66. package/mcp/tools/logout.js +99 -96
  67. package/mcp/tools/rcGetCallLogs.js +65 -65
  68. package/mcp/tools/updateAppointment.js +154 -0
  69. package/mcp/tools/updateCallLog.js +130 -126
  70. package/mcp/ui/App/App.tsx +358 -358
  71. package/mcp/ui/App/components/AuthInfoForm.tsx +113 -113
  72. package/mcp/ui/App/components/AuthSuccess.tsx +22 -22
  73. package/mcp/ui/App/components/ConnectorList.tsx +82 -82
  74. package/mcp/ui/App/components/DebugPanel.tsx +43 -43
  75. package/mcp/ui/App/components/OAuthConnect.tsx +270 -270
  76. package/mcp/ui/App/lib/callTool.ts +130 -130
  77. package/mcp/ui/App/lib/debugLog.ts +41 -41
  78. package/mcp/ui/App/lib/developerPortal.ts +111 -111
  79. package/mcp/ui/App/main.css +5 -5
  80. package/mcp/ui/App/root.tsx +13 -13
  81. package/mcp/ui/index.html +13 -13
  82. package/mcp/ui/package-lock.json +6356 -6356
  83. package/mcp/ui/package.json +25 -25
  84. package/mcp/ui/tsconfig.json +26 -26
  85. package/mcp/ui/vite.config.ts +16 -16
  86. package/models/accountDataModel.js +33 -33
  87. package/models/adminConfigModel.js +35 -35
  88. package/models/cacheModel.js +30 -26
  89. package/models/callDownListModel.js +34 -34
  90. package/models/callLogModel.js +33 -27
  91. package/models/dynamo/connectorSchema.js +146 -146
  92. package/models/dynamo/lockSchema.js +24 -24
  93. package/models/dynamo/noteCacheSchema.js +29 -29
  94. package/models/llmSessionModel.js +17 -17
  95. package/models/messageLogModel.js +25 -25
  96. package/models/sequelize.js +16 -16
  97. package/models/userModel.js +45 -45
  98. package/package.json +1 -1
  99. package/releaseNotes.json +1101 -1081
  100. package/test/connector/proxy/engine.test.js +126 -126
  101. package/test/connector/proxy/index.test.js +279 -279
  102. package/test/connector/proxy/sample.json +161 -161
  103. package/test/connector/registry.test.js +415 -415
  104. package/test/handlers/admin.test.js +616 -616
  105. package/test/handlers/auth.test.js +1092 -1018
  106. package/test/handlers/contact.test.js +1014 -1014
  107. package/test/handlers/log.test.js +1298 -1160
  108. package/test/handlers/managedAuth.test.js +457 -457
  109. package/test/handlers/plugin.test.js +380 -380
  110. package/test/index.test.js +105 -105
  111. package/test/lib/cacheCleanup.test.js +42 -0
  112. package/test/lib/callLogComposer.test.js +1231 -1231
  113. package/test/lib/debugTracer.test.js +328 -328
  114. package/test/lib/jwt.test.js +176 -176
  115. package/test/lib/logger.test.js +206 -206
  116. package/test/lib/oauth.test.js +359 -359
  117. package/test/lib/ringcentral.test.js +467 -467
  118. package/test/lib/sharedSMSComposer.test.js +1084 -1084
  119. package/test/lib/util.test.js +329 -329
  120. package/test/mcp/tools/checkAuthStatus.test.js +83 -83
  121. package/test/mcp/tools/createCallLog.test.js +436 -436
  122. package/test/mcp/tools/createContact.test.js +58 -58
  123. package/test/mcp/tools/createMessageLog.test.js +595 -595
  124. package/test/mcp/tools/doAuth.test.js +113 -113
  125. package/test/mcp/tools/findContactByName.test.js +275 -275
  126. package/test/mcp/tools/findContactByPhone.test.js +296 -296
  127. package/test/mcp/tools/getCallLog.test.js +298 -298
  128. package/test/mcp/tools/getGoogleFilePicker.test.js +281 -281
  129. package/test/mcp/tools/getPublicConnectors.test.js +107 -107
  130. package/test/mcp/tools/getSessionInfo.test.js +127 -127
  131. package/test/mcp/tools/logout.test.js +233 -233
  132. package/test/mcp/tools/rcGetCallLogs.test.js +56 -56
  133. package/test/mcp/tools/updateCallLog.test.js +360 -360
  134. package/test/models/accountDataModel.test.js +98 -98
  135. package/test/models/dynamo/connectorSchema.test.js +189 -189
  136. package/test/models/models.test.js +568 -539
  137. package/test/routes/managedAuthRoutes.test.js +235 -104
  138. package/test/setup.js +178 -178
@@ -1,316 +1,327 @@
1
- const jwt = require('../../lib/jwt');
2
- const connectorRegistry = require('../../connector/registry');
3
- const logCore = require('../../handlers/log');
4
- const contactCore = require('../../handlers/contact');
5
- const util = require('../../lib/util');
6
- const { CallLogModel } = require('../../models/callLogModel');
7
- /**
8
- * MCP Tool: Create Call Log
9
- *
10
- * This tool creates a call log in the CRM platform.
11
- */
12
-
13
- const toolDefinition = {
14
- name: 'createCallLog',
15
- description: '⚠️ REQUIRES CRM CONNECTION. | Create only one call log in the CRM platform. Returns the created log ID if successful. To use with `rcGetCallLogs`: pass a single item from the `records[]` array directly as `incomingData.logInfo`.',
16
- inputSchema: {
17
- type: 'object',
18
- properties: {
19
- incomingData: {
20
- type: 'object',
21
- description: 'Call log data to create',
22
- properties: {
23
- logInfo: {
24
- type: 'object',
25
- description: 'A single record from `rcGetCallLogs` — pass the object exactly as returned, with no changes.',
26
- properties: {
27
- id: {
28
- type: 'string',
29
- description: 'Call log ID from RingCentral'
30
- },
31
- sessionId: {
32
- type: 'string',
33
- description: 'Unique session identifier for the call'
34
- },
35
- telephonySessionId: {
36
- type: 'string',
37
- description: 'Telephony session ID'
38
- },
39
- startTime: {
40
- type: 'string',
41
- description: 'Call start time in ISO 8601 format'
42
- },
43
- duration: {
44
- type: 'number',
45
- description: 'Call duration in seconds'
46
- },
47
- type: {
48
- type: 'string',
49
- description: 'Call type (e.g., Voice)'
50
- },
51
- direction: {
52
- type: 'string',
53
- description: 'Call direction: "Inbound" or "Outbound"'
54
- },
55
- action: {
56
- type: 'string',
57
- description: 'Call action (e.g., Phone Call)'
58
- },
59
- result: {
60
- type: 'string',
61
- description: 'Call result (e.g., Accepted, Missed, Voicemail)'
62
- },
63
- to: {
64
- type: 'object',
65
- description: 'Recipient information',
66
- properties: {
67
- phoneNumber: {
68
- type: 'string',
69
- description: 'Recipient phone number in E.164 format'
70
- },
71
- name: {
72
- type: 'string',
73
- description: 'Recipient name'
74
- }
75
- }
76
- },
77
- from: {
78
- type: 'object',
79
- description: 'Caller information',
80
- properties: {
81
- phoneNumber: {
82
- type: 'string',
83
- description: 'Caller phone number in E.164 format'
84
- },
85
- name: {
86
- type: 'string',
87
- description: 'Caller name'
88
- },
89
- location: {
90
- type: 'string',
91
- description: 'Caller location'
92
- }
93
- }
94
- },
95
- recording: {
96
- type: 'object',
97
- description: 'Recording information',
98
- properties: {
99
- link: {
100
- type: 'string',
101
- description: 'Recording link URL'
102
- }
103
- }
104
- },
105
- customSubject: {
106
- type: 'string',
107
- description: 'Custom subject for the call log'
108
- },
109
- legs: {
110
- type: 'array',
111
- description: 'Call legs information (for multi-party calls)',
112
- items: {
113
- type: 'object'
114
- }
115
- },
116
- accountId: {
117
- type: 'string',
118
- description: 'RingCentral account ID'
119
- }
120
- },
121
- required: ['id', 'sessionId', 'direction', 'startTime', 'duration', 'to', 'from']
122
- },
123
- note: {
124
- type: 'string',
125
- description: 'User-entered call note/description'
126
- },
127
- aiNote: {
128
- type: 'string',
129
- description: 'AI-generated summary of the phone call'
130
- },
131
- transcript: {
132
- type: 'string',
133
- description: 'Call transcript text'
134
- },
135
- additionalSubmission: {
136
- type: 'object',
137
- description: 'Additional platform-specific custom fields (e.g., deals, matters, nonBillable flags, assigned users)',
138
- properties: {
139
- isAssignedToUser: {
140
- type: 'boolean',
141
- description: 'Whether to assign to a specific user'
142
- },
143
- adminAssignedUserToken: {
144
- type: 'string',
145
- description: 'JWT token of the assigned user'
146
- },
147
- adminAssignedUserRcId: {
148
- type: 'string',
149
- description: 'RingCentral extension ID of the assigned user'
150
- }
151
- }
152
- },
153
- contactName: {
154
- type: 'string',
155
- description: 'Contact name'
156
- },
157
- contactType: {
158
- type: 'string',
159
- description: 'Contact type'
160
- }
161
- },
162
- required: ['logInfo', 'contactName']
163
- },
164
- contactId: {
165
- type: 'string',
166
- description: 'OPTIONAL: CRM contact ID to associate with the call.'
167
- }
168
- },
169
- required: ['incomingData']
170
- },
171
- annotations: {
172
- readOnlyHint: false,
173
- openWorldHint: true,
174
- destructiveHint: false
175
- }
176
- };
177
-
178
- /**
179
- * Execute the createCallLog tool
180
- * @param {Object} args - The tool arguments
181
- * @param {string} args.jwtToken - JWT token with user and platform info
182
- * @param {Object} args.incomingData - Call log data including logInfo (RingCentral call log schema), contactName, contactType, note, aiNote, transcript, and additionalSubmission
183
- * @param {Object} args.incomingData.logInfo - RingCentral call log information with sessionId, direction, startTime, duration, from, to, result, recording, customSubject, etc.
184
- * @param {string} [args.incomingData.contactName] - Contact name
185
- * @param {string} [args.incomingData.contactType] - Contact type in CRM
186
- * @param {string} [args.incomingData.note] - User-entered call note
187
- * @param {string} [args.incomingData.aiNote] - AI-generated call summary
188
- * @param {string} [args.incomingData.transcript] - Call transcript
189
- * @param {Object} [args.incomingData.additionalSubmission] - Platform-specific custom fields
190
- * @param {string} args.contactId - OPTIONAL: CRM contact ID to associate with the call
191
- * @returns {Object} Result object with created log ID
192
- */
193
- async function execute(args) {
194
- try {
195
- const { jwtToken, incomingData } = args;
196
-
197
- if (!jwtToken) {
198
- throw new Error('Please go to Settings and authorize CRM platform');
199
- }
200
-
201
- if (!incomingData) {
202
- throw new Error('Incoming data must be provided');
203
- }
204
-
205
- // Validate logInfo exists
206
- if (!incomingData.logInfo) {
207
- throw new Error('incomingData.logInfo is required');
208
- }
209
-
210
- const { logInfo } = incomingData;
211
-
212
- // Check in DB if the call log already exists
213
- const existingCallLog = await CallLogModel.findOne({
214
- where: {
215
- sessionId: logInfo.sessionId
216
- }
217
- });
218
- if (existingCallLog) {
219
- throw new Error(`Call log already exists for session ${logInfo.sessionId}`);
220
- }
221
-
222
- // Decode JWT to get userId and platform
223
- const decodedToken = jwt.decodeJwt(jwtToken);
224
- if (!decodedToken) {
225
- throw new Error('Invalid JWT token');
226
- }
227
- const { id: userId, platform } = decodedToken;
228
-
229
- if (!userId) {
230
- throw new Error('Invalid JWT token: userId not found');
231
- }
232
-
233
- // Get the platform connector module
234
- const platformModule = connectorRegistry.getConnector(platform);
235
-
236
- if (!platformModule) {
237
- throw new Error(`Platform connector not found for: ${platform}`);
238
- }
239
-
240
- // Check if createCallLog is implemented
241
- if (!platformModule.createCallLog) {
242
- throw new Error(`createCallLog is not implemented for platform: ${platform}`);
243
- }
244
-
245
- // Calculate hashed account ID
246
- const hashedAccountId = incomingData.logInfo?.accountId
247
- ? util.getHashValue(incomingData.logInfo.accountId, process.env.HASH_KEY)
248
- : undefined;
249
-
250
- // Get contact Id from conversation
251
- let contactId = args.contactId ?? null;
252
- // Get contact Id from conversation if not provided
253
- if (!contactId) {
254
- const callDirection = logInfo.direction;
255
- const contactNumber = callDirection === 'Inbound' ? logInfo.from.phoneNumber : logInfo.to.phoneNumber;
256
- const contactInfo = await contactCore.findContact({
257
- platform,
258
- userId,
259
- phoneNumber: contactNumber,
260
- overridingFormat: '',
261
- isExtension: false
262
- });
263
- const filteredContact = contactInfo.contact?.filter(c => !c.isNewContact);
264
- if (contactInfo.successful && filteredContact?.length > 0) {
265
- contactId = filteredContact[0].id;
266
- incomingData.contactId = contactId;
267
- }
268
- else {
269
- return {
270
- success: false,
271
- message: 'Cannot find the contact. Please create the contact first.',
272
- error: 'Failed to get contact with number ' + contactNumber
273
- }
274
- }
275
- }
276
- else {
277
- incomingData.contactId = contactId;
278
- }
279
-
280
- // Call the createCallLog method
281
- const { successful, logId, returnMessage } = await logCore.createCallLog({
282
- platform,
283
- userId,
284
- incomingData,
285
- hashedAccountId,
286
- isFromSSCL: false
287
- });
288
-
289
- if (successful) {
290
- return {
291
- success: true,
292
- data: {
293
- logId,
294
- message: returnMessage?.message || 'Call log created successfully'
295
- }
296
- };
297
- }
298
- else {
299
- return {
300
- success: false,
301
- error: returnMessage?.message || 'Failed to create call log',
302
- };
303
- }
304
- }
305
- catch (error) {
306
- return {
307
- success: false,
308
- error: error.message || 'Unknown error occurred',
309
- errorDetails: error.stack
310
- };
311
- }
312
- }
313
-
314
- exports.definition = toolDefinition;
315
- exports.execute = execute;
316
-
1
+ const jwt = require('../../lib/jwt');
2
+ const connectorRegistry = require('../../connector/registry');
3
+ const logCore = require('../../handlers/log');
4
+ const contactCore = require('../../handlers/contact');
5
+ const util = require('../../lib/util');
6
+ const { CallLogModel } = require('../../models/callLogModel');
7
+ const { buildCallLogSessionWhere, getCallLogExtensionNumber } = require('../../lib/callLogLookup');
8
+ /**
9
+ * MCP Tool: Create Call Log
10
+ *
11
+ * This tool creates a call log in the CRM platform.
12
+ */
13
+
14
+ const toolDefinition = {
15
+ name: 'createCallLog',
16
+ description: '⚠️ REQUIRES CRM CONNECTION. | Create only one call log in the CRM platform. Returns the created log ID if successful. To use with `rcGetCallLogs`: pass a single item from the `records[]` array directly as `incomingData.logInfo`.',
17
+ inputSchema: {
18
+ type: 'object',
19
+ properties: {
20
+ incomingData: {
21
+ type: 'object',
22
+ description: 'Call log data to create',
23
+ properties: {
24
+ logInfo: {
25
+ type: 'object',
26
+ description: 'A single record from `rcGetCallLogs` — pass the object exactly as returned, with no changes.',
27
+ properties: {
28
+ id: {
29
+ type: 'string',
30
+ description: 'Call log ID from RingCentral'
31
+ },
32
+ sessionId: {
33
+ type: 'string',
34
+ description: 'Unique session identifier for the call'
35
+ },
36
+ extensionNumber: {
37
+ type: 'string',
38
+ description: 'RingCentral extension number for this call log'
39
+ },
40
+ telephonySessionId: {
41
+ type: 'string',
42
+ description: 'Telephony session ID'
43
+ },
44
+ startTime: {
45
+ type: 'string',
46
+ description: 'Call start time in ISO 8601 format'
47
+ },
48
+ duration: {
49
+ type: 'number',
50
+ description: 'Call duration in seconds'
51
+ },
52
+ type: {
53
+ type: 'string',
54
+ description: 'Call type (e.g., Voice)'
55
+ },
56
+ direction: {
57
+ type: 'string',
58
+ description: 'Call direction: "Inbound" or "Outbound"'
59
+ },
60
+ action: {
61
+ type: 'string',
62
+ description: 'Call action (e.g., Phone Call)'
63
+ },
64
+ result: {
65
+ type: 'string',
66
+ description: 'Call result (e.g., Accepted, Missed, Voicemail)'
67
+ },
68
+ to: {
69
+ type: 'object',
70
+ description: 'Recipient information',
71
+ properties: {
72
+ phoneNumber: {
73
+ type: 'string',
74
+ description: 'Recipient phone number in E.164 format'
75
+ },
76
+ name: {
77
+ type: 'string',
78
+ description: 'Recipient name'
79
+ }
80
+ }
81
+ },
82
+ from: {
83
+ type: 'object',
84
+ description: 'Caller information',
85
+ properties: {
86
+ phoneNumber: {
87
+ type: 'string',
88
+ description: 'Caller phone number in E.164 format'
89
+ },
90
+ name: {
91
+ type: 'string',
92
+ description: 'Caller name'
93
+ },
94
+ location: {
95
+ type: 'string',
96
+ description: 'Caller location'
97
+ }
98
+ }
99
+ },
100
+ recording: {
101
+ type: 'object',
102
+ description: 'Recording information',
103
+ properties: {
104
+ link: {
105
+ type: 'string',
106
+ description: 'Recording link URL'
107
+ }
108
+ }
109
+ },
110
+ customSubject: {
111
+ type: 'string',
112
+ description: 'Custom subject for the call log'
113
+ },
114
+ legs: {
115
+ type: 'array',
116
+ description: 'Call legs information (for multi-party calls)',
117
+ items: {
118
+ type: 'object'
119
+ }
120
+ },
121
+ accountId: {
122
+ type: 'string',
123
+ description: 'RingCentral account ID'
124
+ }
125
+ },
126
+ required: ['id', 'sessionId', 'direction', 'startTime', 'duration', 'to', 'from']
127
+ },
128
+ note: {
129
+ type: 'string',
130
+ description: 'User-entered call note/description'
131
+ },
132
+ aiNote: {
133
+ type: 'string',
134
+ description: 'AI-generated summary of the phone call'
135
+ },
136
+ transcript: {
137
+ type: 'string',
138
+ description: 'Call transcript text'
139
+ },
140
+ additionalSubmission: {
141
+ type: 'object',
142
+ description: 'Additional platform-specific custom fields (e.g., deals, matters, nonBillable flags, assigned users)',
143
+ properties: {
144
+ isAssignedToUser: {
145
+ type: 'boolean',
146
+ description: 'Whether to assign to a specific user'
147
+ },
148
+ adminAssignedUserToken: {
149
+ type: 'string',
150
+ description: 'JWT token of the assigned user'
151
+ },
152
+ adminAssignedUserRcId: {
153
+ type: 'string',
154
+ description: 'RingCentral extension ID of the assigned user'
155
+ }
156
+ }
157
+ },
158
+ contactName: {
159
+ type: 'string',
160
+ description: 'Contact name'
161
+ },
162
+ contactType: {
163
+ type: 'string',
164
+ description: 'Contact type'
165
+ },
166
+ extensionNumber: {
167
+ type: 'string',
168
+ description: 'RingCentral extension number for this call log'
169
+ }
170
+ },
171
+ required: ['logInfo', 'contactName']
172
+ },
173
+ contactId: {
174
+ type: 'string',
175
+ description: 'OPTIONAL: CRM contact ID to associate with the call.'
176
+ }
177
+ },
178
+ required: ['incomingData']
179
+ },
180
+ annotations: {
181
+ readOnlyHint: false,
182
+ openWorldHint: true,
183
+ destructiveHint: false
184
+ }
185
+ };
186
+
187
+ /**
188
+ * Execute the createCallLog tool
189
+ * @param {Object} args - The tool arguments
190
+ * @param {string} args.jwtToken - JWT token with user and platform info
191
+ * @param {Object} args.incomingData - Call log data including logInfo (RingCentral call log schema), contactName, contactType, note, aiNote, transcript, and additionalSubmission
192
+ * @param {Object} args.incomingData.logInfo - RingCentral call log information with sessionId, direction, startTime, duration, from, to, result, recording, customSubject, etc.
193
+ * @param {string} [args.incomingData.contactName] - Contact name
194
+ * @param {string} [args.incomingData.contactType] - Contact type in CRM
195
+ * @param {string} [args.incomingData.note] - User-entered call note
196
+ * @param {string} [args.incomingData.aiNote] - AI-generated call summary
197
+ * @param {string} [args.incomingData.transcript] - Call transcript
198
+ * @param {Object} [args.incomingData.additionalSubmission] - Platform-specific custom fields
199
+ * @param {string} args.contactId - OPTIONAL: CRM contact ID to associate with the call
200
+ * @returns {Object} Result object with created log ID
201
+ */
202
+ async function execute(args) {
203
+ try {
204
+ const { jwtToken, incomingData } = args;
205
+
206
+ if (!jwtToken) {
207
+ throw new Error('Please go to Settings and authorize CRM platform');
208
+ }
209
+
210
+ if (!incomingData) {
211
+ throw new Error('Incoming data must be provided');
212
+ }
213
+
214
+ // Validate logInfo exists
215
+ if (!incomingData.logInfo) {
216
+ throw new Error('incomingData.logInfo is required');
217
+ }
218
+
219
+ const { logInfo } = incomingData;
220
+ const extensionNumber = getCallLogExtensionNumber(incomingData);
221
+
222
+ // Check in DB if the call log already exists
223
+ const existingCallLog = await CallLogModel.findOne({
224
+ where: buildCallLogSessionWhere({
225
+ sessionId: logInfo.sessionId,
226
+ extensionNumber,
227
+ })
228
+ });
229
+ if (existingCallLog) {
230
+ throw new Error(`Call log already exists for session ${logInfo.sessionId}`);
231
+ }
232
+
233
+ // Decode JWT to get userId and platform
234
+ const decodedToken = jwt.decodeJwt(jwtToken);
235
+ if (!decodedToken) {
236
+ throw new Error('Invalid JWT token');
237
+ }
238
+ const { id: userId, platform } = decodedToken;
239
+
240
+ if (!userId) {
241
+ throw new Error('Invalid JWT token: userId not found');
242
+ }
243
+
244
+ // Get the platform connector module
245
+ const platformModule = connectorRegistry.getConnector(platform);
246
+
247
+ if (!platformModule) {
248
+ throw new Error(`Platform connector not found for: ${platform}`);
249
+ }
250
+
251
+ // Check if createCallLog is implemented
252
+ if (!platformModule.createCallLog) {
253
+ throw new Error(`createCallLog is not implemented for platform: ${platform}`);
254
+ }
255
+
256
+ // Calculate hashed account ID
257
+ const hashedAccountId = incomingData.logInfo?.accountId
258
+ ? util.getHashValue(incomingData.logInfo.accountId, process.env.HASH_KEY)
259
+ : undefined;
260
+
261
+ // Get contact Id from conversation
262
+ let contactId = args.contactId ?? null;
263
+ // Get contact Id from conversation if not provided
264
+ if (!contactId) {
265
+ const callDirection = logInfo.direction;
266
+ const contactNumber = callDirection === 'Inbound' ? logInfo.from.phoneNumber : logInfo.to.phoneNumber;
267
+ const contactInfo = await contactCore.findContact({
268
+ platform,
269
+ userId,
270
+ phoneNumber: contactNumber,
271
+ overridingFormat: '',
272
+ isExtension: false
273
+ });
274
+ const filteredContact = contactInfo.contact?.filter(c => !c.isNewContact);
275
+ if (contactInfo.successful && filteredContact?.length > 0) {
276
+ contactId = filteredContact[0].id;
277
+ incomingData.contactId = contactId;
278
+ }
279
+ else {
280
+ return {
281
+ success: false,
282
+ message: 'Cannot find the contact. Please create the contact first.',
283
+ error: 'Failed to get contact with number ' + contactNumber
284
+ }
285
+ }
286
+ }
287
+ else {
288
+ incomingData.contactId = contactId;
289
+ }
290
+
291
+ // Call the createCallLog method
292
+ const { successful, logId, returnMessage } = await logCore.createCallLog({
293
+ platform,
294
+ userId,
295
+ incomingData,
296
+ hashedAccountId,
297
+ isFromSSCL: false
298
+ });
299
+
300
+ if (successful) {
301
+ return {
302
+ success: true,
303
+ data: {
304
+ logId,
305
+ message: returnMessage?.message || 'Call log created successfully'
306
+ }
307
+ };
308
+ }
309
+ else {
310
+ return {
311
+ success: false,
312
+ error: returnMessage?.message || 'Failed to create call log',
313
+ };
314
+ }
315
+ }
316
+ catch (error) {
317
+ return {
318
+ success: false,
319
+ error: error.message || 'Unknown error occurred',
320
+ errorDetails: error.stack
321
+ };
322
+ }
323
+ }
324
+
325
+ exports.definition = toolDefinition;
326
+ exports.execute = execute;
327
+