@app-connect/core 1.7.24 → 1.7.26

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 (137) hide show
  1. package/.env.test +5 -5
  2. package/README.md +441 -441
  3. package/connector/developerPortal.js +31 -42
  4. package/connector/mock.js +84 -77
  5. package/connector/proxy/engine.js +164 -163
  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 -117
  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 +296 -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 +984 -973
  23. package/handlers/managedAuth.js +446 -446
  24. package/handlers/plugin.js +208 -208
  25. package/handlers/user.js +142 -142
  26. package/index.js +3140 -2652
  27. package/jest.config.js +56 -56
  28. package/lib/analytics.js +54 -54
  29. package/lib/authSession.js +109 -109
  30. package/lib/cacheCleanup.js +21 -0
  31. package/lib/callLogComposer.js +898 -898
  32. package/lib/callLogLookup.js +34 -0
  33. package/lib/constants.js +8 -8
  34. package/lib/debugTracer.js +177 -177
  35. package/lib/encode.js +30 -30
  36. package/lib/errorHandler.js +218 -206
  37. package/lib/generalErrorMessage.js +41 -41
  38. package/lib/jwt.js +18 -18
  39. package/lib/logger.js +190 -190
  40. package/lib/migrateCallLogsSchema.js +116 -0
  41. package/lib/ringcentral.js +266 -266
  42. package/lib/s3ErrorLogReport.js +65 -65
  43. package/lib/sharedSMSComposer.js +471 -471
  44. package/lib/util.js +67 -67
  45. package/mcp/README.md +412 -395
  46. package/mcp/lib/validator.js +91 -91
  47. package/mcp/mcpHandler.js +425 -425
  48. package/mcp/tools/cancelAppointment.js +101 -0
  49. package/mcp/tools/checkAuthStatus.js +105 -105
  50. package/mcp/tools/confirmAppointment.js +101 -0
  51. package/mcp/tools/createAppointment.js +157 -0
  52. package/mcp/tools/createCallLog.js +327 -316
  53. package/mcp/tools/createContact.js +117 -117
  54. package/mcp/tools/createMessageLog.js +287 -287
  55. package/mcp/tools/doAuth.js +60 -60
  56. package/mcp/tools/findContactByName.js +93 -93
  57. package/mcp/tools/findContactByPhone.js +101 -101
  58. package/mcp/tools/getCallLog.js +111 -102
  59. package/mcp/tools/getGoogleFilePicker.js +99 -99
  60. package/mcp/tools/getHelp.js +43 -43
  61. package/mcp/tools/getPublicConnectors.js +94 -94
  62. package/mcp/tools/getSessionInfo.js +90 -90
  63. package/mcp/tools/index.js +51 -41
  64. package/mcp/tools/listAppointments.js +163 -0
  65. package/mcp/tools/logout.js +96 -96
  66. package/mcp/tools/rcGetCallLogs.js +65 -65
  67. package/mcp/tools/updateAppointment.js +154 -0
  68. package/mcp/tools/updateCallLog.js +130 -126
  69. package/mcp/ui/App/App.tsx +358 -358
  70. package/mcp/ui/App/components/AuthInfoForm.tsx +113 -113
  71. package/mcp/ui/App/components/AuthSuccess.tsx +22 -22
  72. package/mcp/ui/App/components/ConnectorList.tsx +82 -82
  73. package/mcp/ui/App/components/DebugPanel.tsx +43 -43
  74. package/mcp/ui/App/components/OAuthConnect.tsx +270 -270
  75. package/mcp/ui/App/lib/callTool.ts +130 -130
  76. package/mcp/ui/App/lib/debugLog.ts +41 -41
  77. package/mcp/ui/App/lib/developerPortal.ts +111 -111
  78. package/mcp/ui/App/main.css +5 -5
  79. package/mcp/ui/App/root.tsx +13 -13
  80. package/mcp/ui/index.html +13 -13
  81. package/mcp/ui/package-lock.json +6356 -6356
  82. package/mcp/ui/package.json +25 -25
  83. package/mcp/ui/tsconfig.json +26 -26
  84. package/mcp/ui/vite.config.ts +16 -16
  85. package/models/accountDataModel.js +33 -33
  86. package/models/adminConfigModel.js +35 -35
  87. package/models/cacheModel.js +30 -26
  88. package/models/callDownListModel.js +34 -34
  89. package/models/callLogModel.js +33 -27
  90. package/models/dynamo/connectorSchema.js +146 -146
  91. package/models/dynamo/lockSchema.js +24 -24
  92. package/models/dynamo/noteCacheSchema.js +29 -29
  93. package/models/llmSessionModel.js +17 -17
  94. package/models/messageLogModel.js +25 -25
  95. package/models/sequelize.js +16 -16
  96. package/models/userModel.js +45 -45
  97. package/package.json +72 -72
  98. package/releaseNotes.json +1093 -1073
  99. package/test/connector/proxy/engine.test.js +126 -93
  100. package/test/connector/proxy/index.test.js +279 -279
  101. package/test/connector/proxy/sample.json +161 -161
  102. package/test/connector/registry.test.js +415 -415
  103. package/test/handlers/admin.test.js +616 -616
  104. package/test/handlers/auth.test.js +1018 -1015
  105. package/test/handlers/contact.test.js +1014 -1014
  106. package/test/handlers/log.test.js +1298 -1160
  107. package/test/handlers/managedAuth.test.js +458 -458
  108. package/test/handlers/plugin.test.js +380 -380
  109. package/test/index.test.js +105 -105
  110. package/test/lib/cacheCleanup.test.js +42 -0
  111. package/test/lib/callLogComposer.test.js +1231 -1231
  112. package/test/lib/debugTracer.test.js +328 -328
  113. package/test/lib/jwt.test.js +176 -176
  114. package/test/lib/logger.test.js +206 -206
  115. package/test/lib/oauth.test.js +359 -359
  116. package/test/lib/ringcentral.test.js +467 -467
  117. package/test/lib/sharedSMSComposer.test.js +1084 -1084
  118. package/test/lib/util.test.js +329 -329
  119. package/test/mcp/tools/checkAuthStatus.test.js +83 -82
  120. package/test/mcp/tools/createCallLog.test.js +436 -436
  121. package/test/mcp/tools/createContact.test.js +58 -58
  122. package/test/mcp/tools/createMessageLog.test.js +595 -595
  123. package/test/mcp/tools/doAuth.test.js +113 -113
  124. package/test/mcp/tools/findContactByName.test.js +275 -275
  125. package/test/mcp/tools/findContactByPhone.test.js +296 -296
  126. package/test/mcp/tools/getCallLog.test.js +298 -298
  127. package/test/mcp/tools/getGoogleFilePicker.test.js +281 -281
  128. package/test/mcp/tools/getPublicConnectors.test.js +107 -107
  129. package/test/mcp/tools/getSessionInfo.test.js +127 -127
  130. package/test/mcp/tools/logout.test.js +233 -233
  131. package/test/mcp/tools/rcGetCallLogs.test.js +56 -56
  132. package/test/mcp/tools/updateCallLog.test.js +360 -360
  133. package/test/models/accountDataModel.test.js +98 -98
  134. package/test/models/dynamo/connectorSchema.test.js +189 -189
  135. package/test/models/models.test.js +568 -539
  136. package/test/routes/managedAuthRoutes.test.js +104 -129
  137. 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
+