@app-connect/core 1.7.36 → 1.7.38

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 (287) hide show
  1. package/README.md +17 -16
  2. package/dist/connector/developerPortal.d.ts +6 -0
  3. package/{connector → dist/connector}/developerPortal.js +29 -12
  4. package/dist/connector/mock.d.ts +1 -0
  5. package/{connector → dist/connector}/mock.js +33 -17
  6. package/dist/connector/proxy/engine.d.ts +10 -0
  7. package/dist/connector/proxy/engine.js +222 -0
  8. package/dist/connector/proxy/index.d.ts +5 -0
  9. package/dist/connector/proxy/index.js +511 -0
  10. package/dist/connector/registry.d.ts +1 -0
  11. package/dist/connector/registry.js +243 -0
  12. package/dist/handlers/admin.d.ts +1 -0
  13. package/{handlers → dist/handlers}/admin.js +137 -78
  14. package/dist/handlers/appointment.d.ts +9 -0
  15. package/{handlers → dist/handlers}/appointment.js +58 -29
  16. package/dist/handlers/auth.d.ts +9 -0
  17. package/{handlers → dist/handlers}/auth.js +68 -40
  18. package/dist/handlers/calldown.d.ts +10 -0
  19. package/dist/handlers/calldown.js +134 -0
  20. package/dist/handlers/contact.d.ts +1 -0
  21. package/{handlers → dist/handlers}/contact.js +61 -39
  22. package/dist/handlers/disposition.d.ts +1 -0
  23. package/{handlers → dist/handlers}/disposition.js +20 -10
  24. package/dist/handlers/log.d.ts +1 -0
  25. package/{handlers → dist/handlers}/log.js +91 -124
  26. package/dist/handlers/managedAuth.d.ts +1 -0
  27. package/{handlers → dist/handlers}/managedAuth.js +134 -61
  28. package/dist/handlers/managedOAuth.d.ts +13 -0
  29. package/{handlers → dist/handlers}/managedOAuth.js +102 -30
  30. package/dist/handlers/plugin.d.ts +1 -0
  31. package/{handlers → dist/handlers}/plugin.js +59 -27
  32. package/dist/handlers/user.d.ts +1 -0
  33. package/{handlers → dist/handlers}/user.js +45 -27
  34. package/dist/index.d.ts +1 -0
  35. package/{index.js → dist/index.js} +548 -450
  36. package/dist/jest.config.d.ts +1 -0
  37. package/dist/jest.config.js +65 -0
  38. package/dist/lib/analytics.d.ts +4 -0
  39. package/{lib → dist/lib}/analytics.js +8 -6
  40. package/dist/lib/authSession.d.ts +5 -0
  41. package/{lib → dist/lib}/authSession.js +15 -43
  42. package/dist/lib/cacheCleanup.d.ts +4 -0
  43. package/{lib → dist/lib}/cacheCleanup.js +5 -17
  44. package/dist/lib/callLogComposer.d.ts +109 -0
  45. package/{lib → dist/lib}/callLogComposer.js +157 -197
  46. package/dist/lib/callLogLookup.d.ts +6 -0
  47. package/{lib → dist/lib}/callLogLookup.js +12 -34
  48. package/dist/lib/constants.d.ts +6 -0
  49. package/dist/lib/constants.js +9 -0
  50. package/dist/lib/debugTracer.d.ts +17 -0
  51. package/{lib → dist/lib}/debugTracer.js +7 -83
  52. package/dist/lib/encode.d.ts +3 -0
  53. package/dist/lib/encode.js +50 -0
  54. package/dist/lib/errorHandler.d.ts +7 -0
  55. package/dist/lib/errorHandler.js +161 -0
  56. package/dist/lib/generalErrorMessage.d.ts +7 -0
  57. package/{lib → dist/lib}/generalErrorMessage.js +6 -6
  58. package/dist/lib/jwt.d.ts +4 -0
  59. package/dist/lib/jwt.js +18 -0
  60. package/dist/lib/logger.d.ts +24 -0
  61. package/dist/lib/logger.js +126 -0
  62. package/dist/lib/migrateCallLogsSchema.d.ts +32 -0
  63. package/dist/lib/migrateCallLogsSchema.js +339 -0
  64. package/dist/lib/oauth.d.ts +4 -0
  65. package/{lib → dist/lib}/oauth.js +157 -160
  66. package/dist/lib/ringcentral.d.ts +24 -0
  67. package/dist/lib/ringcentral.js +226 -0
  68. package/dist/lib/s3ErrorLogReport.d.ts +4 -0
  69. package/{lib → dist/lib}/s3ErrorLogReport.js +11 -23
  70. package/dist/lib/sharedSMSComposer.d.ts +7 -0
  71. package/{lib → dist/lib}/sharedSMSComposer.js +21 -107
  72. package/dist/lib/util.d.ts +7 -0
  73. package/{lib → dist/lib}/util.js +9 -20
  74. package/dist/mcp/lib/oauthError.d.ts +1 -0
  75. package/dist/mcp/lib/oauthError.js +25 -0
  76. package/dist/mcp/lib/validator.d.ts +1 -0
  77. package/{mcp → dist/mcp}/lib/validator.js +16 -20
  78. package/dist/mcp/lib/widgetSessionToken.d.ts +1 -0
  79. package/dist/mcp/lib/widgetSessionToken.js +46 -0
  80. package/dist/mcp/mcpHandler.d.ts +8 -0
  81. package/{mcp → dist/mcp}/mcpHandler.js +98 -88
  82. package/dist/mcp/tools/cancelAppointment.d.ts +1 -0
  83. package/{mcp → dist/mcp}/tools/cancelAppointment.js +7 -16
  84. package/dist/mcp/tools/checkAuthStatus.d.ts +1 -0
  85. package/{mcp → dist/mcp}/tools/checkAuthStatus.js +21 -14
  86. package/dist/mcp/tools/confirmAppointment.d.ts +1 -0
  87. package/{mcp → dist/mcp}/tools/confirmAppointment.js +7 -16
  88. package/dist/mcp/tools/createAppointment.d.ts +1 -0
  89. package/{mcp → dist/mcp}/tools/createAppointment.js +7 -19
  90. package/dist/mcp/tools/createCallLog.d.ts +1 -0
  91. package/{mcp → dist/mcp}/tools/createCallLog.js +18 -29
  92. package/dist/mcp/tools/createContact.d.ts +1 -0
  93. package/{mcp → dist/mcp}/tools/createContact.js +8 -20
  94. package/dist/mcp/tools/createMessageLog.d.ts +1 -0
  95. package/{mcp → dist/mcp}/tools/createMessageLog.js +14 -26
  96. package/dist/mcp/tools/doAuth.d.ts +1 -0
  97. package/{mcp → dist/mcp}/tools/doAuth.js +17 -13
  98. package/dist/mcp/tools/findContactByName.d.ts +1 -0
  99. package/{mcp → dist/mcp}/tools/findContactByName.js +9 -15
  100. package/dist/mcp/tools/findContactByPhone.d.ts +1 -0
  101. package/{mcp → dist/mcp}/tools/findContactByPhone.js +8 -15
  102. package/dist/mcp/tools/getCallLog.d.ts +1 -0
  103. package/{mcp → dist/mcp}/tools/getCallLog.js +12 -21
  104. package/dist/mcp/tools/getGoogleFilePicker.d.ts +1 -0
  105. package/{mcp → dist/mcp}/tools/getGoogleFilePicker.js +9 -18
  106. package/dist/mcp/tools/getHelp.d.ts +1 -0
  107. package/{mcp → dist/mcp}/tools/getHelp.js +5 -6
  108. package/dist/mcp/tools/getPublicConnectors.d.ts +1 -0
  109. package/{mcp → dist/mcp}/tools/getPublicConnectors.js +19 -18
  110. package/dist/mcp/tools/getSessionInfo.d.ts +1 -0
  111. package/{mcp → dist/mcp}/tools/getSessionInfo.js +10 -16
  112. package/dist/mcp/tools/index.d.ts +8 -0
  113. package/dist/mcp/tools/index.js +50 -0
  114. package/dist/mcp/tools/listAppointments.d.ts +1 -0
  115. package/{mcp → dist/mcp}/tools/listAppointments.js +7 -19
  116. package/dist/mcp/tools/logout.d.ts +1 -0
  117. package/{mcp → dist/mcp}/tools/logout.js +16 -14
  118. package/dist/mcp/tools/rcGetCallLogs.d.ts +1 -0
  119. package/{mcp → dist/mcp}/tools/rcGetCallLogs.js +10 -8
  120. package/dist/mcp/tools/updateAppointment.d.ts +1 -0
  121. package/{mcp → dist/mcp}/tools/updateAppointment.js +17 -22
  122. package/dist/mcp/tools/updateCallLog.d.ts +1 -0
  123. package/{mcp → dist/mcp}/tools/updateCallLog.js +16 -26
  124. package/dist/models/accountDataModel.d.ts +3 -0
  125. package/dist/models/accountDataModel.js +39 -0
  126. package/dist/models/adminConfigModel.d.ts +2 -0
  127. package/dist/models/adminConfigModel.js +39 -0
  128. package/dist/models/cacheModel.d.ts +2 -0
  129. package/{models → dist/models}/cacheModel.js +7 -3
  130. package/dist/models/callDownListModel.d.ts +2 -0
  131. package/{models → dist/models}/callDownListModel.js +8 -4
  132. package/dist/models/callLogModel.d.ts +2 -0
  133. package/dist/models/callLogModel.js +43 -0
  134. package/dist/models/dynamo/connectorSchema.d.ts +2 -0
  135. package/dist/models/dynamo/connectorSchema.js +141 -0
  136. package/dist/models/dynamo/lockSchema.d.ts +2 -0
  137. package/{models → dist/models}/dynamo/lockSchema.js +5 -7
  138. package/dist/models/dynamo/noteCacheSchema.d.ts +2 -0
  139. package/{models → dist/models}/dynamo/noteCacheSchema.js +4 -6
  140. package/dist/models/llmSessionModel.d.ts +2 -0
  141. package/dist/models/llmSessionModel.js +21 -0
  142. package/dist/models/messageLogModel.d.ts +2 -0
  143. package/{models → dist/models}/messageLogModel.js +8 -4
  144. package/dist/models/sequelize.d.ts +2 -0
  145. package/dist/models/sequelize.js +68 -0
  146. package/dist/models/userModel.d.ts +2 -0
  147. package/dist/models/userModel.js +49 -0
  148. package/dist/package.json +100 -0
  149. package/dist/releaseNotes.json +1222 -0
  150. package/dist/tsconfig.json +14 -0
  151. package/dist/types/admin.d.ts +141 -0
  152. package/dist/types/analytics.d.ts +14 -0
  153. package/dist/types/appointment.d.ts +50 -0
  154. package/dist/types/auth.d.ts +137 -0
  155. package/dist/types/authSession.d.ts +35 -0
  156. package/dist/types/cacheCleanup.d.ts +12 -0
  157. package/dist/types/calldown.d.ts +54 -0
  158. package/dist/types/common.d.ts +46 -0
  159. package/dist/types/connector.d.ts +165 -0
  160. package/dist/types/contact.d.ts +125 -0
  161. package/dist/types/errorHandler.d.ts +60 -0
  162. package/dist/types/index.d.ts +76 -0
  163. package/dist/types/json.d.ts +9 -0
  164. package/dist/types/jwt.d.ts +8 -0
  165. package/dist/types/logging.d.ts +224 -0
  166. package/dist/types/managedAuth.d.ts +114 -0
  167. package/dist/types/managedOAuth.d.ts +59 -0
  168. package/dist/types/manifest.d.ts +120 -0
  169. package/dist/types/migration.d.ts +15 -0
  170. package/dist/types/plugin.d.ts +74 -0
  171. package/dist/types/ringcentral.d.ts +61 -0
  172. package/dist/types/s3ErrorLogReport.d.ts +16 -0
  173. package/dist/types/sharedSMSComposer.d.ts +105 -0
  174. package/dist/types/user.d.ts +46 -0
  175. package/dist/types/util.d.ts +7 -0
  176. package/package.json +34 -6
  177. package/releaseNotes.json +13 -1
  178. package/.env.test +0 -5
  179. package/connector/proxy/engine.js +0 -165
  180. package/connector/proxy/index.js +0 -500
  181. package/connector/registry.js +0 -252
  182. package/docs/README.md +0 -50
  183. package/docs/architecture.md +0 -94
  184. package/docs/connectors.md +0 -116
  185. package/docs/handlers.md +0 -128
  186. package/docs/libraries.md +0 -98
  187. package/docs/models.md +0 -146
  188. package/docs/routes.md +0 -119
  189. package/docs/tests.md +0 -73
  190. package/handlers/calldown.js +0 -99
  191. package/jest.config.js +0 -57
  192. package/lib/constants.js +0 -9
  193. package/lib/encode.js +0 -30
  194. package/lib/errorHandler.js +0 -218
  195. package/lib/jwt.js +0 -18
  196. package/lib/logger.js +0 -190
  197. package/lib/migrateCallLogsSchema.js +0 -237
  198. package/lib/ringcentral.js +0 -267
  199. package/mcp/README.md +0 -420
  200. package/mcp/tools/index.js +0 -51
  201. package/mcp/ui/App/App.tsx +0 -358
  202. package/mcp/ui/App/components/AuthInfoForm.tsx +0 -113
  203. package/mcp/ui/App/components/AuthSuccess.tsx +0 -22
  204. package/mcp/ui/App/components/ConnectorList.tsx +0 -82
  205. package/mcp/ui/App/components/DebugPanel.tsx +0 -43
  206. package/mcp/ui/App/components/OAuthConnect.tsx +0 -270
  207. package/mcp/ui/App/lib/callTool.ts +0 -130
  208. package/mcp/ui/App/lib/debugLog.ts +0 -41
  209. package/mcp/ui/App/lib/developerPortal.ts +0 -111
  210. package/mcp/ui/App/main.css +0 -6
  211. package/mcp/ui/App/root.tsx +0 -13
  212. package/mcp/ui/dist/index.html +0 -53
  213. package/mcp/ui/vite.config.ts +0 -16
  214. package/models/accountDataModel.js +0 -34
  215. package/models/adminConfigModel.js +0 -35
  216. package/models/callLogModel.js +0 -39
  217. package/models/dynamo/connectorSchema.js +0 -146
  218. package/models/llmSessionModel.js +0 -17
  219. package/models/sequelize.js +0 -17
  220. package/models/userModel.js +0 -45
  221. package/test/connector/developerPortal.test.js +0 -166
  222. package/test/connector/mock.test.js +0 -131
  223. package/test/connector/proxy/engine.test.js +0 -211
  224. package/test/connector/proxy/index.test.js +0 -525
  225. package/test/connector/proxy/sample.json +0 -162
  226. package/test/connector/registry.test.js +0 -416
  227. package/test/handlers/admin.test.js +0 -960
  228. package/test/handlers/appointment.test.js +0 -260
  229. package/test/handlers/auth.test.js +0 -1096
  230. package/test/handlers/calldown.test.js +0 -310
  231. package/test/handlers/contact.test.js +0 -1014
  232. package/test/handlers/disposition.test.js +0 -396
  233. package/test/handlers/log.test.js +0 -1847
  234. package/test/handlers/managedAuth.test.js +0 -458
  235. package/test/handlers/managedOAuth.test.js +0 -262
  236. package/test/handlers/plugin.test.js +0 -429
  237. package/test/handlers/user.test.js +0 -381
  238. package/test/index.test.js +0 -301
  239. package/test/lib/analytics.test.js +0 -146
  240. package/test/lib/authSession.test.js +0 -173
  241. package/test/lib/cacheCleanup.test.js +0 -127
  242. package/test/lib/callLogComposer.test.js +0 -1231
  243. package/test/lib/debugTracer.test.js +0 -328
  244. package/test/lib/encode.test.js +0 -59
  245. package/test/lib/errorHandler.test.js +0 -246
  246. package/test/lib/generalErrorMessage.test.js +0 -82
  247. package/test/lib/jwt.test.js +0 -176
  248. package/test/lib/logger.test.js +0 -206
  249. package/test/lib/oauth.test.js +0 -359
  250. package/test/lib/ringcentral.test.js +0 -467
  251. package/test/lib/s3ErrorLogReport.test.js +0 -187
  252. package/test/lib/sharedSMSComposer.test.js +0 -1084
  253. package/test/lib/util.test.js +0 -329
  254. package/test/mcp/mcpHandler.test.js +0 -73
  255. package/test/mcp/mcpHandlerMore.test.js +0 -384
  256. package/test/mcp/tools/appointmentTools.test.js +0 -362
  257. package/test/mcp/tools/checkAuthStatus.test.js +0 -83
  258. package/test/mcp/tools/createCallLog.test.js +0 -436
  259. package/test/mcp/tools/createContact.test.js +0 -58
  260. package/test/mcp/tools/createMessageLog.test.js +0 -595
  261. package/test/mcp/tools/doAuth.test.js +0 -113
  262. package/test/mcp/tools/findContactByName.test.js +0 -275
  263. package/test/mcp/tools/findContactByPhone.test.js +0 -296
  264. package/test/mcp/tools/getCallLog.test.js +0 -298
  265. package/test/mcp/tools/getGoogleFilePicker.test.js +0 -281
  266. package/test/mcp/tools/getPublicConnectors.test.js +0 -107
  267. package/test/mcp/tools/getSessionInfo.test.js +0 -127
  268. package/test/mcp/tools/logout.test.js +0 -233
  269. package/test/mcp/tools/rcGetCallLogs.test.js +0 -56
  270. package/test/mcp/tools/updateCallLog.test.js +0 -360
  271. package/test/models/accountDataModel.test.js +0 -98
  272. package/test/models/callDownListModel.test.js +0 -125
  273. package/test/models/dynamo/connectorSchema.test.js +0 -189
  274. package/test/models/dynamo/lockSchema.test.js +0 -37
  275. package/test/models/dynamo/noteCacheSchema.test.js +0 -45
  276. package/test/models/llmSessionModel.test.js +0 -91
  277. package/test/models/models.test.js +0 -660
  278. package/test/routes/calldownRoutes.test.js +0 -224
  279. package/test/routes/coreRouterBroadRoutes.test.js +0 -855
  280. package/test/routes/dispositionRoutes.test.js +0 -192
  281. package/test/routes/managedAuthRoutes.test.js +0 -386
  282. package/test/routes/pluginRoutes.test.js +0 -262
  283. package/test/setup.js +0 -178
  284. /package/{mcp → dist/mcp}/ui/index.html +0 -0
  285. /package/{mcp → dist/mcp}/ui/package-lock.json +0 -0
  286. /package/{mcp → dist/mcp}/ui/package.json +0 -0
  287. /package/{mcp → dist/mcp}/ui/tsconfig.json +0 -0
@@ -1,54 +1,58 @@
1
- const express = require('express');
2
- const cors = require('cors')
3
- const bodyParser = require('body-parser');
1
+ "use strict";
2
+ // @ts-check
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const express = /** @type {any} */ (require('express'));
5
+ const cors = /** @type {any} */ (require('cors'));
6
+ const bodyParser = /** @type {any} */ (require('body-parser'));
4
7
  require('body-parser-xml')(bodyParser);
5
- const dynamoose = require('dynamoose');
6
- const { DynamoDB } = require('@aws-sdk/client-dynamodb');
7
- const axios = require('axios');
8
- const { UserModel } = require('./models/userModel');
9
- const { LlmSessionModel } = require('./models/llmSessionModel');
10
- const { CallDownListModel } = require('./models/callDownListModel');
11
- const { CallLogModel } = require('./models/callLogModel');
12
- const { MessageLogModel } = require('./models/messageLogModel');
13
- const { AdminConfigModel } = require('./models/adminConfigModel');
14
- const { CacheModel } = require('./models/cacheModel');
15
- const { AccountDataModel } = require('./models/accountDataModel');
16
- const jwt = require('./lib/jwt');
17
- const logCore = require('./handlers/log');
18
- const contactCore = require('./handlers/contact');
19
- const appointmentCore = require('./handlers/appointment');
20
- const authCore = require('./handlers/auth');
21
- const adminCore = require('./handlers/admin');
22
- const userCore = require('./handlers/user');
23
- const dispositionCore = require('./handlers/disposition');
24
- const mock = require('./connector/mock');
25
- const proxyConnector = require('./connector/proxy');
8
+ const dynamoose = /** @type {any} */ (require('dynamoose'));
9
+ const { DynamoDB } = /** @type {any} */ (require('@aws-sdk/client-dynamodb'));
10
+ const axios = /** @type {any} */ (require('axios'));
11
+ const { UserModel } = /** @type {any} */ (require('./models/userModel'));
12
+ const { LlmSessionModel } = /** @type {any} */ (require('./models/llmSessionModel'));
13
+ const { CallDownListModel } = /** @type {any} */ (require('./models/callDownListModel'));
14
+ const { CallLogModel } = /** @type {any} */ (require('./models/callLogModel'));
15
+ const { MessageLogModel } = /** @type {any} */ (require('./models/messageLogModel'));
16
+ const { AdminConfigModel } = /** @type {any} */ (require('./models/adminConfigModel'));
17
+ const { CacheModel } = /** @type {any} */ (require('./models/cacheModel'));
18
+ const { AccountDataModel } = /** @type {any} */ (require('./models/accountDataModel'));
19
+ const jwt = /** @type {any} */ (require('./lib/jwt'));
20
+ const logCore = /** @type {any} */ (require('./handlers/log'));
21
+ const contactCore = /** @type {any} */ (require('./handlers/contact'));
22
+ const appointmentCore = /** @type {any} */ (require('./handlers/appointment'));
23
+ const authCore = /** @type {any} */ (require('./handlers/auth'));
24
+ const adminCore = /** @type {any} */ (require('./handlers/admin'));
25
+ const userCore = /** @type {any} */ (require('./handlers/user'));
26
+ const dispositionCore = /** @type {any} */ (require('./handlers/disposition'));
27
+ const mock = /** @type {any} */ (require('./connector/mock'));
28
+ const proxyConnector = /** @type {any} */ (require('./connector/proxy'));
26
29
  const releaseNotes = require('./releaseNotes.json');
27
- const analytics = require('./lib/analytics');
28
- const util = require('./lib/util');
29
- const connectorRegistry = require('./connector/registry');
30
- const calldown = require('./handlers/calldown');
31
- const mcpHandler = require('./mcp/mcpHandler');
32
- const logger = require('./lib/logger');
33
- const { DebugTracer } = require('./lib/debugTracer');
34
- const s3ErrorLogReport = require('./lib/s3ErrorLogReport');
35
- const pluginCore = require('./handlers/plugin');
36
- const { sequelize } = require('./models/sequelize');
37
- const { ensureCallLogsHashedExtensionIdSchema } = require('./lib/migrateCallLogsSchema');
38
- const { handleDatabaseError } = require('./lib/errorHandler');
39
- const { updateAuthSession } = require('./lib/authSession');
40
- const managedAuthCore = require('./handlers/managedAuth');
41
- const managedOAuthCore = require('./handlers/managedOAuth');
42
-
30
+ const analytics = /** @type {any} */ (require('./lib/analytics'));
31
+ const util = /** @type {any} */ (require('./lib/util'));
32
+ const connectorRegistry = /** @type {any} */ (require('./connector/registry'));
33
+ const calldown = /** @type {any} */ (require('./handlers/calldown'));
34
+ const mcpHandler = /** @type {any} */ (require('./mcp/mcpHandler'));
35
+ const logger = /** @type {any} */ (require('./lib/logger'));
36
+ const { DebugTracer } = /** @type {any} */ (require('./lib/debugTracer'));
37
+ const s3ErrorLogReport = /** @type {any} */ (require('./lib/s3ErrorLogReport'));
38
+ const pluginCore = /** @type {any} */ (require('./handlers/plugin'));
39
+ const { sequelize } = /** @type {any} */ (require('./models/sequelize'));
40
+ const { runCallLogsSchemaMigration } = /** @type {any} */ (require('./lib/migrateCallLogsSchema'));
41
+ const { handleDatabaseError } = /** @type {any} */ (require('./lib/errorHandler'));
42
+ const { updateAuthSession } = /** @type {any} */ (require('./lib/authSession'));
43
+ const managedAuthCore = /** @type {any} */ (require('./handlers/managedAuth'));
44
+ const managedOAuthCore = /** @type {any} */ (require('./handlers/managedOAuth'));
45
+ const { MCP_OAUTH_REQUIRED_MESSAGE, MCP_OAUTH_STALE_CLIENT_MESSAGE, getMcpOAuthChallengeHeader, buildMcpOAuthError, } = /** @type {any} */ (require('./mcp/lib/oauthError'));
46
+ /** @type {any} */
43
47
  let packageJson = null;
44
48
  try {
45
49
  packageJson = require('./package.json');
46
50
  }
47
51
  catch (e) {
48
52
  logger.error('Error loading package.json', { stack: e.stack });
49
- packageJson = require('../package.json');
53
+ const fallbackPackageJsonPath = '../package.json';
54
+ packageJson = require(fallbackPackageJsonPath);
50
55
  }
51
-
52
56
  // For using dynamodb in local env
53
57
  // AWS SDK v3 requires a region even for local; ddb.local() omits it, so set manually.
54
58
  if (process.env.DYNAMODB_LOCALHOST) {
@@ -66,14 +70,12 @@ if (process.env.IS_PROD === 'false') {
66
70
  });
67
71
  }
68
72
  axios.defaults.headers.common['Unified-CRM-Extension-Version'] = packageJson.version;
69
-
70
73
  async function initDB() {
71
74
  if (!process.env.DISABLE_SYNC_DB_TABLE) {
72
75
  logger.info('creating db tables if not exist...');
73
76
  await UserModel.sync();
74
77
  await LlmSessionModel.sync();
75
78
  await CallLogModel.sync();
76
- await ensureCallLogsHashedExtensionIdSchema(sequelize);
77
79
  await MessageLogModel.sync();
78
80
  await AdminConfigModel.sync();
79
81
  await CacheModel.sync();
@@ -81,7 +83,6 @@ async function initDB() {
81
83
  await AccountDataModel.sync();
82
84
  }
83
85
  }
84
-
85
86
  function getAnalyticsVariablesInReqHeaders({ headers }) {
86
87
  const hashedExtensionId = headers['rc-extension-id'];
87
88
  const hashedAccountId = headers['rc-account-id'];
@@ -96,12 +97,10 @@ function getAnalyticsVariablesInReqHeaders({ headers }) {
96
97
  userAgent,
97
98
  author,
98
99
  eventAddedVia
99
- }
100
+ };
100
101
  }
101
-
102
102
  const JWT_REFRESH_THRESHOLD_SECONDS = 7 * 24 * 60 * 60; // 1 week
103
103
  const JWT_LEGACY_LONG_LIVED_THRESHOLD_SECONDS = 365 * 24 * 60 * 60; // 1 year
104
-
105
104
  function getBearerTokenFromRequest(req) {
106
105
  const authHeader = req.headers?.authorization || req.headers?.Authorization;
107
106
  if (!authHeader || typeof authHeader !== 'string') {
@@ -113,7 +112,49 @@ function getBearerTokenFromRequest(req) {
113
112
  }
114
113
  return token;
115
114
  }
116
-
115
+ function normalizeTokenValue(value) {
116
+ const token = Array.isArray(value) ? value[0] : value;
117
+ if (typeof token !== 'string') {
118
+ return token || null;
119
+ }
120
+ const trimmedToken = token.trim();
121
+ return trimmedToken.toLowerCase().startsWith('bearer ')
122
+ ? trimmedToken.slice('bearer '.length).trim()
123
+ : trimmedToken;
124
+ }
125
+ function wrapDebugResponse(tracer, payload) {
126
+ if (tracer) {
127
+ return tracer.wrapResponse(payload);
128
+ }
129
+ return payload;
130
+ }
131
+ function getErrorResponse(e) {
132
+ if (e && e.message) {
133
+ return e.message;
134
+ }
135
+ return e;
136
+ }
137
+ function getRcAccessTokenFromRequest(req) {
138
+ return normalizeTokenValue(req.get?.('X-RC-Access-Token')
139
+ || req.headers?.['x-rc-access-token']
140
+ || req.body?.rcAccessToken
141
+ || req.query?.rcAccessToken);
142
+ }
143
+ function getFirstQueryValue(value) {
144
+ if (Array.isArray(value)) {
145
+ return value[0];
146
+ }
147
+ if (value === undefined || value === null) {
148
+ return undefined;
149
+ }
150
+ return value.toString();
151
+ }
152
+ function appendOAuthQueryParam(params, name, value) {
153
+ const normalizedValue = getFirstQueryValue(value);
154
+ if (normalizedValue) {
155
+ params.set(name, normalizedValue);
156
+ }
157
+ }
117
158
  function normalizeJwtFromRequest(req, res, next) {
118
159
  if (req.path?.startsWith('/mcp')) {
119
160
  return next();
@@ -122,19 +163,15 @@ function normalizeJwtFromRequest(req, res, next) {
122
163
  const queryToken = req.query?.jwtToken;
123
164
  let bearerToken = originalBearerToken;
124
165
  const isQueryAuth = !originalBearerToken && !!queryToken;
125
-
126
166
  // Backward compatibility: promote query jwtToken to Authorization Bearer.
127
167
  if (isQueryAuth) {
128
168
  req.headers.authorization = `Bearer ${queryToken}`;
129
169
  bearerToken = queryToken;
130
170
  }
131
-
132
171
  const token = bearerToken;
133
-
134
172
  if (!token) {
135
173
  return next();
136
174
  }
137
-
138
175
  const decodedToken = jwt.decodeJwt(token);
139
176
  if (!decodedToken?.id) {
140
177
  req.invalidJwtToken = true;
@@ -143,10 +180,8 @@ function normalizeJwtFromRequest(req, res, next) {
143
180
  }
144
181
  return next();
145
182
  }
146
-
147
183
  req.jwtToken = token;
148
184
  req.jwtAuth = decodedToken;
149
-
150
185
  if (typeof decodedToken.exp === 'number') {
151
186
  const now = Math.floor(Date.now() / 1000);
152
187
  const timeLeft = decodedToken.exp - now;
@@ -167,12 +202,10 @@ function normalizeJwtFromRequest(req, res, next) {
167
202
  }
168
203
  return next();
169
204
  }
170
-
171
205
  // Create a router with all core routes
172
206
  function createCoreRouter() {
173
207
  const router = express.Router();
174
208
  router.use(normalizeJwtFromRequest);
175
-
176
209
  // Move all app.get, app.post, etc. to router.get, router.post, etc.
177
210
  router.get('/releaseNotes', async function (req, res) {
178
211
  const tracer = req.headers['is-debug'] === 'true' ? DebugTracer.fromRequest(req) : null;
@@ -187,7 +220,7 @@ function createCoreRouter() {
187
220
  ...connectorReleaseNotes[version] ?? {}
188
221
  };
189
222
  }
190
- res.json(tracer ? tracer.wrapResponse(mergedReleaseNotes ?? {}) : (mergedReleaseNotes ?? {}));
223
+ res.json(wrapDebugResponse(tracer, mergedReleaseNotes ?? {}));
191
224
  });
192
225
  // Obsolete
193
226
  router.get('/crmManifest', (req, res) => {
@@ -265,17 +298,17 @@ function createCoreRouter() {
265
298
  result.getLogFormatType = !!platformModule.getLogFormatType;
266
299
  result.refreshUserInfo = !!platformModule.refreshUserInfo;
267
300
  result.cacheCallNote = !!process.env.USE_CACHE;
268
- res.status(200).send(tracer ? tracer.wrapResponse(result) : result);
301
+ res.status(200).send(wrapDebugResponse(tracer, result));
269
302
  }
270
303
  else {
271
304
  tracer?.trace('implementedInterfaces:noPlatform', {});
272
- res.status(400).send(tracer ? tracer.wrapResponse('Please provide platform.') : 'Please provide platform.');
305
+ res.status(400).send(wrapDebugResponse(tracer, 'Please provide platform.'));
273
306
  return;
274
307
  }
275
308
  }
276
309
  catch (e) {
277
310
  tracer?.traceError('implementedInterfaces:error', e);
278
- res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
311
+ res.status(400).send(wrapDebugResponse(tracer, { error: getErrorResponse(e) }));
279
312
  }
280
313
  });
281
314
  router.get('/licenseStatus', async (req, res) => {
@@ -285,14 +318,14 @@ function createCoreRouter() {
285
318
  let platformName = null;
286
319
  let success = false;
287
320
  let extraData = {};
288
- const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
321
+ const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers });
289
322
  try {
290
323
  const jwtToken = req.jwtToken || req.query.jwtToken;
291
324
  if (jwtToken) {
292
325
  const decodedToken = jwt.decodeJwt(jwtToken);
293
326
  if (!decodedToken) {
294
327
  tracer?.trace('licenseStatus:invalidJwtToken', {});
295
- res.status(400).send(tracer ? tracer.wrapResponse('Invalid JWT token') : 'Invalid JWT token');
328
+ res.status(400).send(wrapDebugResponse(tracer, 'Invalid JWT token'));
296
329
  success = false;
297
330
  return;
298
331
  }
@@ -300,36 +333,28 @@ function createCoreRouter() {
300
333
  platformName = platform;
301
334
  if (!userId) {
302
335
  tracer?.trace('licenseStatus:noUserId', {});
303
- res.status(400).send(tracer ? tracer.wrapResponse('No user ID') : 'No user ID');
336
+ res.status(400).send(wrapDebugResponse(tracer, 'No user ID'));
304
337
  success = true;
305
338
  }
306
339
  const licenseStatus = await authCore.getLicenseStatus({ userId, platform });
307
- res.status(200).send(tracer ? tracer.wrapResponse(licenseStatus) : licenseStatus);
340
+ res.status(200).send(wrapDebugResponse(tracer, licenseStatus));
308
341
  success = true;
309
342
  }
310
343
  else {
311
- res.status(200).send(tracer ? tracer.wrapResponse({
312
- isLicenseValid: false,
313
- licenseStatus: 'Invalid (Invalid user session)',
314
- licenseStatusDescription: ''
315
- }) : {
344
+ res.status(200).send(wrapDebugResponse(tracer, {
316
345
  isLicenseValid: false,
317
346
  licenseStatus: 'Invalid (Invalid user session)',
318
347
  licenseStatusDescription: ''
319
- });
348
+ }));
320
349
  success = true;
321
350
  }
322
351
  }
323
352
  catch (e) {
324
- res.status(200).send(tracer ? tracer.wrapResponse({
353
+ res.status(200).send(wrapDebugResponse(tracer, {
325
354
  isLicenseValid: false,
326
355
  licenseStatus: 'Invalid (Connect to get license status)',
327
356
  licenseStatusDescription: ''
328
- }) : {
329
- isLicenseValid: false,
330
- licenseStatus: 'Invalid (Connect to get license status)',
331
- licenseStatusDescription: ''
332
- });
357
+ }));
333
358
  success = false;
334
359
  }
335
360
  const requestEndTime = new Date().getTime();
@@ -359,14 +384,14 @@ function createCoreRouter() {
359
384
  let validationPass = false;
360
385
  let reason = '';
361
386
  let statusCode = 200;
362
- const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
387
+ const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers });
363
388
  try {
364
389
  const jwtToken = req.jwtToken || req.query.jwtToken;
365
390
  if (jwtToken) {
366
391
  const decodedToken = jwt.decodeJwt(jwtToken);
367
392
  if (!decodedToken) {
368
393
  tracer?.trace('authValidation:invalidJwtToken', {});
369
- res.status(400).send(tracer ? tracer.wrapResponse('Invalid JWT token') : 'Invalid JWT token');
394
+ res.status(400).send(wrapDebugResponse(tracer, 'Invalid JWT token'));
370
395
  return;
371
396
  }
372
397
  const { id: userId, platform } = decodedToken;
@@ -376,11 +401,11 @@ function createCoreRouter() {
376
401
  validationPass = successful;
377
402
  reason = failReason;
378
403
  statusCode = status;
379
- res.status(200).send(tracer ? tracer.wrapResponse({ successful, returnMessage }) : { successful, returnMessage });
404
+ res.status(200).send(wrapDebugResponse(tracer, { successful, returnMessage }));
380
405
  }
381
406
  else {
382
407
  tracer?.trace('authValidation:noToken', {});
383
- res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
408
+ res.status(400).send(wrapDebugResponse(tracer, 'Please go to Settings and authorize CRM platform'));
384
409
  success = false;
385
410
  }
386
411
  }
@@ -388,7 +413,7 @@ function createCoreRouter() {
388
413
  logger.error('Auth validation failed', { platform: platformName, stack: e.stack });
389
414
  tracer?.traceError('authValidation:error', e);
390
415
  statusCode = e.response?.status ?? 'unknown';
391
- res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
416
+ res.status(400).send(wrapDebugResponse(tracer, { error: getErrorResponse(e) }));
392
417
  success = false;
393
418
  }
394
419
  const requestEndTime = new Date().getTime();
@@ -416,13 +441,13 @@ function createCoreRouter() {
416
441
  tracer?.trace('apiKeyManagedAuthState:start', { query: req.query });
417
442
  try {
418
443
  const platform = req.query.platform;
419
- const rcAccessToken = req.query.rcAccessToken;
444
+ const rcAccessToken = getRcAccessTokenFromRequest(req);
420
445
  if (!platform) {
421
- res.status(400).send(tracer ? tracer.wrapResponse('Missing platform name') : 'Missing platform name');
446
+ res.status(400).send(wrapDebugResponse(tracer, 'Missing platform name'));
422
447
  return;
423
448
  }
424
449
  if (!rcAccessToken) {
425
- res.status(400).send(tracer ? tracer.wrapResponse('Missing RingCentral access token') : 'Missing RingCentral access token');
450
+ res.status(400).send(wrapDebugResponse(tracer, 'Missing RingCentral access token'));
426
451
  return;
427
452
  }
428
453
  const { rcAccountId, rcExtensionId } = await adminCore.validateRcUserToken({ rcAccessToken });
@@ -433,12 +458,12 @@ function createCoreRouter() {
433
458
  connectorId: req.query.connectorId,
434
459
  isPrivate: req.query.isPrivate === 'true'
435
460
  });
436
- res.status(200).send(tracer ? tracer.wrapResponse(managedAuthState) : managedAuthState);
461
+ res.status(200).send(wrapDebugResponse(tracer, managedAuthState));
437
462
  }
438
463
  catch (e) {
439
464
  logger.error('Get API key managed auth state failed', { stack: e.stack });
440
465
  tracer?.traceError('apiKeyManagedAuthState:error', e);
441
- res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
466
+ res.status(400).send(wrapDebugResponse(tracer, { error: getErrorResponse(e) }));
442
467
  }
443
468
  });
444
469
  router.get('/oauthManagedAuthState', async function (req, res) {
@@ -446,13 +471,13 @@ function createCoreRouter() {
446
471
  tracer?.trace('oauthManagedAuthState:start', { query: req.query });
447
472
  try {
448
473
  const platform = req.query.platform;
449
- const rcAccessToken = req.query.rcAccessToken;
474
+ const rcAccessToken = getRcAccessTokenFromRequest(req);
450
475
  if (!platform) {
451
- res.status(400).send(tracer ? tracer.wrapResponse('Missing platform name') : 'Missing platform name');
476
+ res.status(400).send(wrapDebugResponse(tracer, 'Missing platform name'));
452
477
  return;
453
478
  }
454
479
  if (!rcAccessToken) {
455
- res.status(400).send(tracer ? tracer.wrapResponse('Missing RingCentral access token') : 'Missing RingCentral access token');
480
+ res.status(400).send(wrapDebugResponse(tracer, 'Missing RingCentral access token'));
456
481
  return;
457
482
  }
458
483
  const { rcAccountId } = await adminCore.validateRcUserToken({ rcAccessToken });
@@ -462,12 +487,12 @@ function createCoreRouter() {
462
487
  rcAccountId,
463
488
  isAdmin: !!adminValidation.isValidated
464
489
  });
465
- res.status(200).send(tracer ? tracer.wrapResponse(state) : state);
490
+ res.status(200).send(wrapDebugResponse(tracer, state));
466
491
  }
467
492
  catch (e) {
468
493
  logger.error('Get managed OAuth state failed', { stack: e.stack });
469
494
  tracer?.traceError('oauthManagedAuthState:error', e);
470
- res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
495
+ res.status(400).send(wrapDebugResponse(tracer, { error: getErrorResponse(e) }));
471
496
  }
472
497
  });
473
498
  // Obsolete
@@ -480,25 +505,25 @@ function createCoreRouter() {
480
505
  const tracer = req.headers['is-debug'] === 'true' ? DebugTracer.fromRequest(req) : null;
481
506
  tracer?.trace('setAdminSettings:start', { body: req.body });
482
507
  let success = false;
483
- const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
508
+ const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers });
484
509
  try {
485
- const { isValidated, rcAccountId } = await adminCore.validateAdminRole({ rcAccessToken: req.query.rcAccessToken });
510
+ const { isValidated, rcAccountId } = await adminCore.validateAdminRole({ rcAccessToken: getRcAccessTokenFromRequest(req) });
486
511
  const hashedRcAccountId = util.getHashValue(rcAccountId, process.env.HASH_KEY);
487
512
  if (isValidated) {
488
513
  await adminCore.upsertAdminSettings({ hashedRcAccountId, adminSettings: req.body.adminSettings });
489
- res.status(200).send(tracer ? tracer.wrapResponse('Admin settings updated') : 'Admin settings updated');
514
+ res.status(200).send(wrapDebugResponse(tracer, 'Admin settings updated'));
490
515
  success = true;
491
516
  }
492
517
  else {
493
518
  tracer?.trace('setAdminSettings:adminValidationFailed', {});
494
- res.status(403).send(tracer ? tracer.wrapResponse('Admin validation failed') : 'Admin validation failed');
519
+ res.status(403).send(wrapDebugResponse(tracer, 'Admin validation failed'));
495
520
  success = false;
496
521
  }
497
522
  }
498
523
  catch (e) {
499
524
  logger.error('Set admin settings failed', { stack: e.stack });
500
525
  tracer?.traceError('setAdminSettings:error', e);
501
- res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
526
+ res.status(400).send(wrapDebugResponse(tracer, { error: getErrorResponse(e) }));
502
527
  success = false;
503
528
  }
504
529
  const requestEndTime = new Date().getTime();
@@ -521,7 +546,7 @@ function createCoreRouter() {
521
546
  tracer?.trace('getAdminSettings:start', { query: req.query });
522
547
  let platformName = null;
523
548
  let success = false;
524
- const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
549
+ const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers });
525
550
  try {
526
551
  const jwtToken = req.jwtToken || req.query.jwtToken;
527
552
  if (jwtToken) {
@@ -530,43 +555,40 @@ function createCoreRouter() {
530
555
  const user = await UserModel.findByPk(unAuthData?.id);
531
556
  if (!user) {
532
557
  tracer?.trace('getAdminSettings:userNotFound', {});
533
- res.status(400).send(tracer ? tracer.wrapResponse('User not found') : 'User not found');
558
+ res.status(400).send(wrapDebugResponse(tracer, 'User not found'));
534
559
  return;
535
560
  }
536
- const { isValidated, rcAccountId } = await adminCore.validateAdminRole({ rcAccessToken: req.query.rcAccessToken });
561
+ const { isValidated, rcAccountId } = await adminCore.validateAdminRole({ rcAccessToken: getRcAccessTokenFromRequest(req) });
537
562
  const hashedRcAccountId = util.getHashValue(rcAccountId, process.env.HASH_KEY);
538
563
  if (isValidated) {
539
564
  const adminSettings = await adminCore.getAdminSettings({ hashedRcAccountId });
540
565
  if (adminSettings) {
541
- res.status(200).send(tracer ? tracer.wrapResponse(adminSettings) : adminSettings);
566
+ res.status(200).send(wrapDebugResponse(tracer, adminSettings));
542
567
  }
543
568
  else {
544
- res.status(200).send(tracer ? tracer.wrapResponse({
569
+ res.status(200).send(wrapDebugResponse(tracer, {
545
570
  customConnector: null,
546
571
  userSettings: {}
547
- }) : {
548
- customConnector: null,
549
- userSettings: {}
550
- });
572
+ }));
551
573
  }
552
574
  success = true;
553
575
  }
554
576
  else {
555
577
  tracer?.trace('getAdminSettings:adminValidationFailed', {});
556
- res.status(403).send(tracer ? tracer.wrapResponse('Admin validation failed') : 'Admin validation failed');
578
+ res.status(403).send(wrapDebugResponse(tracer, 'Admin validation failed'));
557
579
  success = true;
558
580
  }
559
581
  }
560
582
  else {
561
583
  tracer?.trace('getAdminSettings:noToken', {});
562
- res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
584
+ res.status(400).send(wrapDebugResponse(tracer, 'Please go to Settings and authorize CRM platform'));
563
585
  success = false;
564
586
  }
565
587
  }
566
588
  catch (e) {
567
589
  console.log(`${e.stack}`);
568
590
  tracer?.traceError('getAdminSettings:error', e);
569
- res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
591
+ res.status(400).send(wrapDebugResponse(tracer, { error: getErrorResponse(e) }));
570
592
  }
571
593
  const requestEndTime = new Date().getTime();
572
594
  analytics.track({
@@ -589,18 +611,18 @@ function createCoreRouter() {
589
611
  try {
590
612
  const jwtToken = req.jwtToken || req.query.jwtToken;
591
613
  if (!jwtToken) {
592
- res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
614
+ res.status(400).send(wrapDebugResponse(tracer, 'Please go to Settings and authorize CRM platform'));
593
615
  return;
594
616
  }
595
617
  const unAuthData = jwt.decodeJwt(jwtToken);
596
618
  const user = await UserModel.findByPk(unAuthData?.id);
597
619
  if (!user) {
598
- res.status(400).send(tracer ? tracer.wrapResponse('User not found') : 'User not found');
620
+ res.status(400).send(wrapDebugResponse(tracer, 'User not found'));
599
621
  return;
600
622
  }
601
- const { isValidated, rcAccountId } = await adminCore.validateAdminRole({ rcAccessToken: req.query.rcAccessToken });
623
+ const { isValidated, rcAccountId } = await adminCore.validateAdminRole({ rcAccessToken: getRcAccessTokenFromRequest(req) });
602
624
  if (!isValidated) {
603
- res.status(403).send(tracer ? tracer.wrapResponse('Admin validation failed') : 'Admin validation failed');
625
+ res.status(403).send(wrapDebugResponse(tracer, 'Admin validation failed'));
604
626
  return;
605
627
  }
606
628
  const managedAuthSettings = await managedAuthCore.getManagedAuthAdminSettings({
@@ -609,12 +631,12 @@ function createCoreRouter() {
609
631
  connectorId: req.query.connectorId,
610
632
  isPrivate: req.query.isPrivate === 'true'
611
633
  });
612
- res.status(200).send(tracer ? tracer.wrapResponse(managedAuthSettings) : managedAuthSettings);
634
+ res.status(200).send(wrapDebugResponse(tracer, managedAuthSettings));
613
635
  }
614
636
  catch (e) {
615
637
  logger.error('Get managed auth settings failed', { stack: e.stack });
616
638
  tracer?.traceError('getAdminManagedAuth:error', e);
617
- res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
639
+ res.status(400).send(wrapDebugResponse(tracer, { error: getErrorResponse(e) }));
618
640
  }
619
641
  });
620
642
  router.post('/admin/managedAuth', async function (req, res) {
@@ -623,18 +645,18 @@ function createCoreRouter() {
623
645
  try {
624
646
  const jwtToken = req.jwtToken || req.query.jwtToken;
625
647
  if (!jwtToken) {
626
- res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
648
+ res.status(400).send(wrapDebugResponse(tracer, 'Please go to Settings and authorize CRM platform'));
627
649
  return;
628
650
  }
629
651
  const unAuthData = jwt.decodeJwt(jwtToken);
630
652
  const user = await UserModel.findByPk(unAuthData?.id);
631
653
  if (!user) {
632
- res.status(400).send(tracer ? tracer.wrapResponse('User not found') : 'User not found');
654
+ res.status(400).send(wrapDebugResponse(tracer, 'User not found'));
633
655
  return;
634
656
  }
635
- const { isValidated, rcAccountId } = await adminCore.validateAdminRole({ rcAccessToken: req.query.rcAccessToken });
657
+ const { isValidated, rcAccountId } = await adminCore.validateAdminRole({ rcAccessToken: getRcAccessTokenFromRequest(req) });
636
658
  if (!isValidated) {
637
- res.status(403).send(tracer ? tracer.wrapResponse('Admin validation failed') : 'Admin validation failed');
659
+ res.status(403).send(wrapDebugResponse(tracer, 'Admin validation failed'));
638
660
  return;
639
661
  }
640
662
  if (req.body?.scope === 'user') {
@@ -655,12 +677,12 @@ function createCoreRouter() {
655
677
  fieldsToRemove: req.body?.fieldsToRemove ?? []
656
678
  });
657
679
  }
658
- res.status(200).send(tracer ? tracer.wrapResponse('Shared authentication updated') : 'Shared authentication updated');
680
+ res.status(200).send(wrapDebugResponse(tracer, 'Shared authentication updated'));
659
681
  }
660
682
  catch (e) {
661
683
  logger.error('Set managed auth settings failed', { stack: e.stack });
662
684
  tracer?.traceError('setAdminManagedAuth:error', e);
663
- res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
685
+ res.status(400).send(wrapDebugResponse(tracer, { error: getErrorResponse(e) }));
664
686
  }
665
687
  });
666
688
  router.post('/admin/managedOAuth/cache', async function (req, res) {
@@ -672,64 +694,64 @@ function createCoreRouter() {
672
694
  }
673
695
  });
674
696
  try {
675
- const { isValidated, rcAccountId } = await adminCore.validateAdminRole({ rcAccessToken: req.query.rcAccessToken });
697
+ const { isValidated, rcAccountId } = await adminCore.validateAdminRole({ rcAccessToken: getRcAccessTokenFromRequest(req) });
676
698
  if (!isValidated) {
677
- res.status(403).send(tracer ? tracer.wrapResponse('Admin validation failed') : 'Admin validation failed');
699
+ res.status(403).send(wrapDebugResponse(tracer, 'Admin validation failed'));
678
700
  return;
679
701
  }
680
702
  await managedOAuthCore.upsertPendingManagedOAuth({
681
703
  rcAccountId: rcAccountId?.toString(),
682
704
  values: req.body?.values ?? {}
683
705
  });
684
- res.status(200).send(tracer ? tracer.wrapResponse({ successful: true }) : { successful: true });
706
+ res.status(200).send(wrapDebugResponse(tracer, { successful: true }));
685
707
  }
686
708
  catch (e) {
687
709
  logger.error('Set managed OAuth pending cache failed', { stack: e.stack });
688
710
  tracer?.traceError('setAdminManagedOAuthCache:error', e);
689
- res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
711
+ res.status(400).send(wrapDebugResponse(tracer, { error: getErrorResponse(e) }));
690
712
  }
691
713
  });
692
714
  router.delete('/admin/managedOAuth/cache', async function (req, res) {
693
715
  const tracer = req.headers['is-debug'] === 'true' ? DebugTracer.fromRequest(req) : null;
694
716
  tracer?.trace('deleteAdminManagedOAuthCache:start', {});
695
717
  try {
696
- const { isValidated, rcAccountId } = await adminCore.validateAdminRole({ rcAccessToken: req.query.rcAccessToken });
718
+ const { isValidated, rcAccountId } = await adminCore.validateAdminRole({ rcAccessToken: getRcAccessTokenFromRequest(req) });
697
719
  if (!isValidated) {
698
- res.status(403).send(tracer ? tracer.wrapResponse('Admin validation failed') : 'Admin validation failed');
720
+ res.status(403).send(wrapDebugResponse(tracer, 'Admin validation failed'));
699
721
  return;
700
722
  }
701
723
  await managedOAuthCore.clearPendingManagedOAuth({ rcAccountId: rcAccountId?.toString() });
702
- res.status(200).send(tracer ? tracer.wrapResponse({ successful: true }) : { successful: true });
724
+ res.status(200).send(wrapDebugResponse(tracer, { successful: true }));
703
725
  }
704
726
  catch (e) {
705
727
  logger.error('Delete managed OAuth pending cache failed', { stack: e.stack });
706
728
  tracer?.traceError('deleteAdminManagedOAuthCache:error', e);
707
- res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
729
+ res.status(400).send(wrapDebugResponse(tracer, { error: getErrorResponse(e) }));
708
730
  }
709
731
  });
710
732
  router.delete('/admin/managedOAuth/account', async function (req, res) {
711
733
  const tracer = req.headers['is-debug'] === 'true' ? DebugTracer.fromRequest(req) : null;
712
734
  tracer?.trace('deleteAdminManagedOAuthAccount:start', { query: req.query });
713
735
  try {
714
- const { isValidated, rcAccountId } = await adminCore.validateAdminRole({ rcAccessToken: req.query.rcAccessToken });
736
+ const { isValidated, rcAccountId } = await adminCore.validateAdminRole({ rcAccessToken: getRcAccessTokenFromRequest(req) });
715
737
  if (!isValidated) {
716
- res.status(403).send(tracer ? tracer.wrapResponse('Admin validation failed') : 'Admin validation failed');
738
+ res.status(403).send(wrapDebugResponse(tracer, 'Admin validation failed'));
717
739
  return;
718
740
  }
719
741
  if (!req.query.platform) {
720
- res.status(400).send(tracer ? tracer.wrapResponse('Missing platform name') : 'Missing platform name');
742
+ res.status(400).send(wrapDebugResponse(tracer, 'Missing platform name'));
721
743
  return;
722
744
  }
723
745
  await managedOAuthCore.resetManagedOAuth({
724
746
  rcAccountId: rcAccountId?.toString(),
725
747
  platform: req.query.platform
726
748
  });
727
- res.status(200).send(tracer ? tracer.wrapResponse({ successful: true }) : { successful: true });
749
+ res.status(200).send(wrapDebugResponse(tracer, { successful: true }));
728
750
  }
729
751
  catch (e) {
730
752
  logger.error('Delete managed OAuth account failed', { stack: e.stack });
731
753
  tracer?.traceError('deleteAdminManagedOAuthAccount:error', e);
732
- res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
754
+ res.status(400).send(wrapDebugResponse(tracer, { error: getErrorResponse(e) }));
733
755
  }
734
756
  });
735
757
  router.post('/admin/userMapping', async function (req, res) {
@@ -738,7 +760,7 @@ function createCoreRouter() {
738
760
  tracer?.trace('getUserMapping:start', { query: req.query });
739
761
  let platformName = null;
740
762
  let success = false;
741
- const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
763
+ const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers });
742
764
  try {
743
765
  const jwtToken = req.jwtToken || req.query.jwtToken;
744
766
  if (jwtToken) {
@@ -747,38 +769,38 @@ function createCoreRouter() {
747
769
  const user = await UserModel.findByPk(unAuthData?.id);
748
770
  if (!user) {
749
771
  tracer?.trace('getUserMapping:userNotFound', {});
750
- res.status(400).send(tracer ? tracer.wrapResponse('User not found') : 'User not found');
772
+ res.status(400).send(wrapDebugResponse(tracer, 'User not found'));
751
773
  return;
752
774
  }
753
- const { isValidated, rcAccountId } = await adminCore.validateAdminRole({ rcAccessToken: req.query.rcAccessToken });
775
+ const { isValidated, rcAccountId } = await adminCore.validateAdminRole({ rcAccessToken: getRcAccessTokenFromRequest(req) });
754
776
  const hashedRcAccountId = util.getHashValue(rcAccountId, process.env.HASH_KEY);
755
777
  if (isValidated) {
756
778
  const userMapping = await adminCore.getUserMapping({ user, hashedRcAccountId, rcExtensionList: req.body.rcExtensionList });
757
779
  if (userMapping?.isRevokeUserSession) {
758
- res.status(401).send(tracer ? tracer.wrapResponse(userMapping) : userMapping);
780
+ res.status(401).send(wrapDebugResponse(tracer, userMapping));
759
781
  success = false;
760
782
  }
761
783
  else {
762
- res.status(200).send(tracer ? tracer.wrapResponse(userMapping) : userMapping);
784
+ res.status(200).send(wrapDebugResponse(tracer, userMapping));
763
785
  success = true;
764
786
  }
765
787
  }
766
788
  else {
767
789
  tracer?.trace('getUserMapping:adminValidationFailed', {});
768
- res.status(403).send(tracer ? tracer.wrapResponse('Admin validation failed') : 'Admin validation failed');
790
+ res.status(403).send(wrapDebugResponse(tracer, 'Admin validation failed'));
769
791
  success = true;
770
792
  }
771
793
  }
772
794
  else {
773
795
  tracer?.trace('getUserMapping:noToken', {});
774
- res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
796
+ res.status(400).send(wrapDebugResponse(tracer, 'Please go to Settings and authorize CRM platform'));
775
797
  success = false;
776
798
  }
777
799
  }
778
800
  catch (e) {
779
801
  logger.error('Get user mapping failed', { stack: e.stack });
780
802
  tracer?.traceError('getUserMapping:error', e);
781
- res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
803
+ res.status(400).send(wrapDebugResponse(tracer, { error: getErrorResponse(e) }));
782
804
  }
783
805
  const requestEndTime = new Date().getTime();
784
806
  analytics.track({
@@ -801,7 +823,7 @@ function createCoreRouter() {
801
823
  tracer?.trace('reinitializeUserMapping:start', { body: req.body });
802
824
  let platformName = null;
803
825
  let success = false;
804
- const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
826
+ const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers });
805
827
  try {
806
828
  const jwtToken = req.jwtToken || req.query.jwtToken;
807
829
  if (jwtToken) {
@@ -810,38 +832,38 @@ function createCoreRouter() {
810
832
  const user = await UserModel.findByPk(unAuthData?.id);
811
833
  if (!user) {
812
834
  tracer?.trace('reinitializeUserMapping:userNotFound', {});
813
- res.status(400).send(tracer ? tracer.wrapResponse('User not found') : 'User not found');
835
+ res.status(400).send(wrapDebugResponse(tracer, 'User not found'));
814
836
  return;
815
837
  }
816
- const { isValidated, rcAccountId } = await adminCore.validateAdminRole({ rcAccessToken: req.query.rcAccessToken });
838
+ const { isValidated, rcAccountId } = await adminCore.validateAdminRole({ rcAccessToken: getRcAccessTokenFromRequest(req) });
817
839
  const hashedRcAccountId = util.getHashValue(rcAccountId, process.env.HASH_KEY);
818
840
  if (isValidated) {
819
841
  const userMapping = await adminCore.reinitializeUserMapping({ user, hashedRcAccountId, rcExtensionList: req.body.rcExtensionList });
820
842
  if (userMapping?.isRevokeUserSession) {
821
- res.status(401).send(tracer ? tracer.wrapResponse(userMapping) : userMapping);
843
+ res.status(401).send(wrapDebugResponse(tracer, userMapping));
822
844
  success = false;
823
845
  }
824
846
  else {
825
- res.status(200).send(tracer ? tracer.wrapResponse(userMapping) : userMapping);
847
+ res.status(200).send(wrapDebugResponse(tracer, userMapping));
826
848
  success = true;
827
849
  }
828
850
  }
829
851
  else {
830
852
  tracer?.trace('reinitializeUserMapping:adminValidationFailed', {});
831
- res.status(403).send(tracer ? tracer.wrapResponse('Admin validation failed') : 'Admin validation failed');
853
+ res.status(403).send(wrapDebugResponse(tracer, 'Admin validation failed'));
832
854
  success = true;
833
855
  }
834
856
  }
835
857
  else {
836
858
  tracer?.trace('reinitializeUserMapping:noToken', {});
837
- res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
859
+ res.status(400).send(wrapDebugResponse(tracer, 'Please go to Settings and authorize CRM platform'));
838
860
  success = false;
839
861
  }
840
862
  }
841
863
  catch (e) {
842
864
  logger.error('Reinitialize user mapping failed', { stack: e.stack });
843
865
  tracer?.traceError('reinitializeUserMapping:error', e);
844
- res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
866
+ res.status(400).send(wrapDebugResponse(tracer, { error: getErrorResponse(e) }));
845
867
  }
846
868
  const requestEndTime = new Date().getTime();
847
869
  analytics.track({
@@ -867,32 +889,32 @@ function createCoreRouter() {
867
889
  const jwtToken = req.jwtToken || req.query.jwtToken;
868
890
  if (!jwtToken) {
869
891
  tracer?.trace('getServerLoggingSettings:noToken', {});
870
- res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
892
+ res.status(400).send(wrapDebugResponse(tracer, 'Please go to Settings and authorize CRM platform'));
871
893
  return;
872
894
  }
873
- const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
895
+ const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers });
874
896
  try {
875
897
  const unAuthData = jwt.decodeJwt(jwtToken);
876
898
  if (!unAuthData?.id) {
877
899
  tracer?.trace('getServerLoggingSettings:noToken', {});
878
- res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
900
+ res.status(400).send(wrapDebugResponse(tracer, 'Please go to Settings and authorize CRM platform'));
879
901
  return;
880
902
  }
881
903
  platformName = unAuthData?.platform ?? 'Unknown';
882
904
  const user = await UserModel.findByPk(unAuthData?.id);
883
905
  if (!user) {
884
906
  tracer?.trace('getServerLoggingSettings:userNotFound', {});
885
- res.status(400).send(tracer ? tracer.wrapResponse('User not found') : 'User not found');
907
+ res.status(400).send(wrapDebugResponse(tracer, 'User not found'));
886
908
  return;
887
909
  }
888
910
  const serverLoggingSettings = await adminCore.getServerLoggingSettings({ user });
889
- res.status(200).send(tracer ? tracer.wrapResponse(serverLoggingSettings) : serverLoggingSettings);
911
+ res.status(200).send(wrapDebugResponse(tracer, serverLoggingSettings));
890
912
  success = true;
891
913
  }
892
914
  catch (e) {
893
915
  logger.error('Get server logging settings failed', { stack: e.stack });
894
916
  tracer?.traceError('getServerLoggingSettings:error', e);
895
- res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
917
+ res.status(400).send(wrapDebugResponse(tracer, { error: getErrorResponse(e) }));
896
918
  }
897
919
  const requestEndTime = new Date().getTime();
898
920
  analytics.track({
@@ -918,37 +940,37 @@ function createCoreRouter() {
918
940
  const jwtToken = req.jwtToken || req.query.jwtToken;
919
941
  if (!jwtToken) {
920
942
  tracer?.trace('setServerLoggingSettings:noToken', {});
921
- res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
943
+ res.status(400).send(wrapDebugResponse(tracer, 'Please go to Settings and authorize CRM platform'));
922
944
  return;
923
945
  }
924
946
  if (!req.body.additionalFieldValues) {
925
947
  tracer?.trace('setServerLoggingSettings:missingAdditionalFieldValues', {});
926
- res.status(400).send(tracer ? tracer.wrapResponse('Missing additionalFieldValues') : 'Missing additionalFieldValues');
948
+ res.status(400).send(wrapDebugResponse(tracer, 'Missing additionalFieldValues'));
927
949
  return;
928
950
  }
929
- const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
951
+ const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers });
930
952
  try {
931
953
  const unAuthData = jwt.decodeJwt(jwtToken);
932
954
  if (!unAuthData?.id) {
933
955
  tracer?.trace('setServerLoggingSettings:noToken', {});
934
- res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
956
+ res.status(400).send(wrapDebugResponse(tracer, 'Please go to Settings and authorize CRM platform'));
935
957
  return;
936
958
  }
937
959
  platformName = unAuthData?.platform ?? 'Unknown';
938
960
  const user = await UserModel.findByPk(unAuthData?.id);
939
961
  if (!user) {
940
962
  tracer?.trace('setServerLoggingSettings:userNotFound', {});
941
- res.status(400).send(tracer ? tracer.wrapResponse('User not found') : 'User not found');
963
+ res.status(400).send(wrapDebugResponse(tracer, 'User not found'));
942
964
  return;
943
965
  }
944
966
  const { successful, returnMessage } = await adminCore.updateServerLoggingSettings({ user, additionalFieldValues: req.body.additionalFieldValues });
945
- res.status(200).send(tracer ? tracer.wrapResponse({ successful, returnMessage }) : { successful, returnMessage });
967
+ res.status(200).send(wrapDebugResponse(tracer, { successful, returnMessage }));
946
968
  success = true;
947
969
  }
948
970
  catch (e) {
949
971
  logger.error('Set server logging settings failed', { stack: e.stack });
950
972
  tracer?.traceError('setServerLoggingSettings:error', e);
951
- res.status(400).send(tracer ? tracer.wrapResponse({ successful: false, returnMessage: { messageType: 'warning', message: 'Server logging settings update failed', ttl: 5000 } }) : { successful: false, returnMessage: { messageType: 'warning', message: 'Server logging settings update failed', ttl: 5000 } });
973
+ res.status(400).send(wrapDebugResponse(tracer, { successful: false, returnMessage: { messageType: 'warning', message: 'Server logging settings update failed', ttl: 5000 } }));
952
974
  success = false;
953
975
  }
954
976
  const requestEndTime = new Date().getTime();
@@ -965,36 +987,35 @@ function createCoreRouter() {
965
987
  author,
966
988
  eventAddedVia
967
989
  });
968
- })
990
+ });
969
991
  router.get('/user/preloadSettings', async function (req, res) {
970
992
  const tracer = req.headers['is-debug'] === 'true' ? DebugTracer.fromRequest(req) : null;
971
993
  tracer?.trace('getUserSettingsByAdmin:start', { query: req.query });
972
994
  try {
973
- const rcAccessToken = req.query.rcAccessToken;
995
+ const rcAccessToken = getRcAccessTokenFromRequest(req);
974
996
  const rcAccountId = req.query.rcAccountId;
975
997
  if (rcAccessToken || rcAccountId) {
976
998
  const userSettings = await userCore.getUserSettingsByAdmin({ rcAccessToken, rcAccountId });
977
- res.status(200).send(tracer ? tracer.wrapResponse(userSettings) : userSettings);
999
+ res.status(200).send(wrapDebugResponse(tracer, userSettings));
978
1000
  }
979
1001
  else {
980
1002
  tracer?.trace('getUserSettingsByAdmin:noRcAccessTokenOrRcAccountId', {});
981
- res.status(400).send(tracer ? tracer.wrapResponse('Cannot find rc user login') : 'Cannot find rc user login');
1003
+ res.status(400).send(wrapDebugResponse(tracer, 'Cannot find rc user login'));
982
1004
  }
983
1005
  }
984
1006
  catch (e) {
985
1007
  logger.error('Get user preload settings failed', { stack: e.stack });
986
1008
  tracer?.traceError('getUserSettingsByAdmin:error', e);
987
- res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
1009
+ res.status(400).send(wrapDebugResponse(tracer, { error: getErrorResponse(e) }));
988
1010
  }
989
- }
990
- );
1011
+ });
991
1012
  router.post('/user/refreshInfo', async function (req, res) {
992
1013
  const requestStartTime = new Date().getTime();
993
1014
  const tracer = req.headers['is-debug'] === 'true' ? DebugTracer.fromRequest(req) : null;
994
1015
  tracer?.trace('refreshUserInfo:start', { body: req.body });
995
1016
  let platformName = null;
996
1017
  let success = false;
997
- const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
1018
+ const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers });
998
1019
  try {
999
1020
  const jwtToken = req.jwtToken || req.query.jwtToken;
1000
1021
  if (jwtToken) {
@@ -1002,19 +1023,19 @@ function createCoreRouter() {
1002
1023
  platformName = unAuthData?.platform ?? 'Unknown';
1003
1024
  const userId = unAuthData?.id;
1004
1025
  const { successful, returnMessage } = await userCore.refreshUserInfo({ platform: platformName, userId, tracer });
1005
- res.status(200).send(tracer ? tracer.wrapResponse({ successful, returnMessage }) : { successful, returnMessage });
1026
+ res.status(200).send(wrapDebugResponse(tracer, { successful, returnMessage }));
1006
1027
  success = true;
1007
1028
  }
1008
1029
  else {
1009
1030
  tracer?.trace('refreshUserInfo:noToken', {});
1010
- res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
1031
+ res.status(400).send(wrapDebugResponse(tracer, 'Please go to Settings and authorize CRM platform'));
1011
1032
  success = false;
1012
1033
  }
1013
1034
  }
1014
1035
  catch (e) {
1015
1036
  logger.error('Refresh user info failed', { platform: platformName, stack: e.stack });
1016
1037
  tracer?.traceError('refreshUserInfo:error', e, { platform: platformName });
1017
- res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
1038
+ res.status(400).send(wrapDebugResponse(tracer, { error: getErrorResponse(e) }));
1018
1039
  }
1019
1040
  const requestEndTime = new Date().getTime();
1020
1041
  analytics.track({
@@ -1030,14 +1051,14 @@ function createCoreRouter() {
1030
1051
  author,
1031
1052
  eventAddedVia
1032
1053
  });
1033
- })
1054
+ });
1034
1055
  router.get('/user/settings', async function (req, res) {
1035
1056
  const requestStartTime = new Date().getTime();
1036
1057
  const tracer = req.headers['is-debug'] === 'true' ? DebugTracer.fromRequest(req) : null;
1037
1058
  tracer?.trace('getUserSettings:start', { query: req.query });
1038
1059
  let platformName = null;
1039
1060
  let success = false;
1040
- const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
1061
+ const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers });
1041
1062
  try {
1042
1063
  const jwtToken = req.jwtToken || req.query.jwtToken;
1043
1064
  if (jwtToken) {
@@ -1045,33 +1066,33 @@ function createCoreRouter() {
1045
1066
  platformName = unAuthData?.platform ?? 'Unknown';
1046
1067
  if (!unAuthData || !unAuthData?.id) {
1047
1068
  tracer?.trace('getUserSettings:noToken', {});
1048
- res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
1069
+ res.status(400).send(wrapDebugResponse(tracer, 'Please go to Settings and authorize CRM platform'));
1049
1070
  return;
1050
1071
  }
1051
1072
  const user = await UserModel.findByPk(unAuthData?.id);
1052
1073
  if (!user) {
1053
1074
  tracer?.trace('getUserSettings:userNotFound', {});
1054
- res.status(400).send(tracer ? tracer.wrapResponse('User not found') : 'User not found');
1075
+ res.status(400).send(wrapDebugResponse(tracer, 'User not found'));
1055
1076
  return;
1056
1077
  }
1057
1078
  else {
1058
- const rcAccessToken = req.query.rcAccessToken;
1079
+ const rcAccessToken = getRcAccessTokenFromRequest(req);
1059
1080
  const rcAccountId = req.query.rcAccountId;
1060
1081
  const userSettings = await userCore.getUserSettings({ user, rcAccessToken, rcAccountId });
1061
1082
  success = true;
1062
- res.status(200).send(tracer ? tracer.wrapResponse(userSettings) : userSettings);
1083
+ res.status(200).send(wrapDebugResponse(tracer, userSettings));
1063
1084
  }
1064
1085
  }
1065
1086
  else {
1066
1087
  success = false;
1067
1088
  tracer?.trace('getUserSettings:noToken', {});
1068
- res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
1089
+ res.status(400).send(wrapDebugResponse(tracer, 'Please go to Settings and authorize CRM platform'));
1069
1090
  }
1070
1091
  }
1071
1092
  catch (e) {
1072
1093
  logger.error('Get user settings failed', { platform: platformName, stack: e.stack });
1073
1094
  tracer?.traceError('getUserSettings:error', e, { platform: platformName });
1074
- res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
1095
+ res.status(400).send(wrapDebugResponse(tracer, { error: getErrorResponse(e) }));
1075
1096
  }
1076
1097
  const requestEndTime = new Date().getTime();
1077
1098
  analytics.track({
@@ -1094,7 +1115,7 @@ function createCoreRouter() {
1094
1115
  tracer?.trace('setUserSettings:start', { body: req.body });
1095
1116
  let platformName = null;
1096
1117
  let success = false;
1097
- const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
1118
+ const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers });
1098
1119
  try {
1099
1120
  const jwtToken = req.jwtToken || req.query.jwtToken;
1100
1121
  if (jwtToken) {
@@ -1102,29 +1123,29 @@ function createCoreRouter() {
1102
1123
  platformName = unAuthData?.platform;
1103
1124
  if (!platformName) {
1104
1125
  tracer?.trace('setUserSettings:unknownPlatform', {});
1105
- res.status(400).send(tracer ? tracer.wrapResponse('Unknown platform') : 'Unknown platform');
1126
+ res.status(400).send(wrapDebugResponse(tracer, 'Unknown platform'));
1106
1127
  return;
1107
1128
  }
1108
1129
  const user = await UserModel.findByPk(unAuthData?.id);
1109
1130
  if (!user) {
1110
1131
  tracer?.trace('setUserSettings:userNotFound', {});
1111
- res.status(400).send(tracer ? tracer.wrapResponse('User not found') : 'User not found');
1132
+ res.status(400).send(wrapDebugResponse(tracer, 'User not found'));
1112
1133
  return;
1113
1134
  }
1114
1135
  const { userSettings } = await userCore.updateUserSettings({ user, userSettings: req.body.userSettings, settingKeysToRemove: req.body.settingKeysToRemove || [], platformName });
1115
- res.status(200).send(tracer ? tracer.wrapResponse({ userSettings }) : { userSettings });
1136
+ res.status(200).send(wrapDebugResponse(tracer, { userSettings }));
1116
1137
  success = true;
1117
1138
  }
1118
1139
  else {
1119
1140
  tracer?.trace('setUserSettings:noToken', {});
1120
- res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
1141
+ res.status(400).send(wrapDebugResponse(tracer, 'Please go to Settings and authorize CRM platform'));
1121
1142
  success = false;
1122
1143
  }
1123
1144
  }
1124
1145
  catch (e) {
1125
1146
  logger.error('Set user settings failed', { platform: platformName, stack: e.stack });
1126
1147
  tracer?.traceError('setUserSettings:error', e, { platform: platformName });
1127
- res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
1148
+ res.status(400).send(wrapDebugResponse(tracer, { error: getErrorResponse(e) }));
1128
1149
  }
1129
1150
  const requestEndTime = new Date().getTime();
1130
1151
  analytics.track({
@@ -1151,22 +1172,22 @@ function createCoreRouter() {
1151
1172
  const user = await UserModel.findByPk(unAuthData?.id);
1152
1173
  if (!user) {
1153
1174
  tracer?.trace('hostname:userNotFound', {});
1154
- res.status(400).send(tracer ? tracer.wrapResponse('User not found') : 'User not found');
1175
+ res.status(400).send(wrapDebugResponse(tracer, 'User not found'));
1155
1176
  return;
1156
1177
  }
1157
- res.status(200).send(tracer ? tracer.wrapResponse(user.hostname) : user.hostname);
1178
+ res.status(200).send(wrapDebugResponse(tracer, user.hostname));
1158
1179
  }
1159
1180
  else {
1160
1181
  tracer?.trace('hostname:noToken', {});
1161
- res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
1182
+ res.status(400).send(wrapDebugResponse(tracer, 'Please go to Settings and authorize CRM platform'));
1162
1183
  }
1163
1184
  }
1164
1185
  catch (e) {
1165
1186
  logger.error('Get hostname failed', { stack: e.stack });
1166
1187
  tracer?.traceError('hostname:error', e);
1167
- res.status(500).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
1188
+ res.status(500).send(wrapDebugResponse(tracer, { error: getErrorResponse(e) }));
1168
1189
  }
1169
- })
1190
+ });
1170
1191
  router.get('/oauth-callback', async function (req, res) {
1171
1192
  const requestStartTime = new Date().getTime();
1172
1193
  const tracer = req.headers['is-debug'] === 'true' ? DebugTracer.fromRequest(req) : null;
@@ -1174,7 +1195,7 @@ function createCoreRouter() {
1174
1195
  let platformName = null;
1175
1196
  let success = false;
1176
1197
  let sessionId = null;
1177
- const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
1198
+ const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers });
1178
1199
  try {
1179
1200
  if (!req.query?.callbackUri || req.query.callbackUri === 'undefined') {
1180
1201
  // case: from mcp
@@ -1184,7 +1205,7 @@ function createCoreRouter() {
1184
1205
  }
1185
1206
  else {
1186
1207
  tracer?.trace('oauth-callback:missingCallbackUri', {});
1187
- res.status(400).send(tracer ? tracer.wrapResponse('Missing callbackUri') : 'Missing callbackUri');
1208
+ res.status(400).send(wrapDebugResponse(tracer, 'Missing callbackUri'));
1188
1209
  return;
1189
1210
  }
1190
1211
  }
@@ -1202,7 +1223,7 @@ function createCoreRouter() {
1202
1223
  const tokenUrl = req.query.tokenUrl;
1203
1224
  if (!platformName) {
1204
1225
  tracer?.trace('oauth-callback:missingPlatformName', {});
1205
- res.status(400).send(tracer ? tracer.wrapResponse('Missing platform name') : 'Missing platform name');
1226
+ res.status(400).send(wrapDebugResponse(tracer, 'Missing platform name'));
1206
1227
  return;
1207
1228
  }
1208
1229
  const hasAuthCodeInCallbackUri = req.query.callbackUri.includes('code=');
@@ -1238,12 +1259,12 @@ function createCoreRouter() {
1238
1259
  success = true;
1239
1260
  }
1240
1261
  else {
1241
- res.status(200).send(tracer ? tracer.wrapResponse({ jwtToken, name: userInfo.name, returnMessage }) : { jwtToken, name: userInfo.name, returnMessage });
1262
+ res.status(200).send(wrapDebugResponse(tracer, { jwtToken, name: userInfo.name, returnMessage }));
1242
1263
  success = true;
1243
1264
  }
1244
1265
  }
1245
1266
  else {
1246
- res.status(200).send(tracer ? tracer.wrapResponse({ returnMessage }) : { returnMessage });
1267
+ res.status(200).send(wrapDebugResponse(tracer, { returnMessage }));
1247
1268
  await updateAuthSession(sessionId, {
1248
1269
  status: 'failed',
1249
1270
  errorMessage: returnMessage?.message || 'Authentication failed'
@@ -1254,14 +1275,13 @@ function createCoreRouter() {
1254
1275
  catch (e) {
1255
1276
  logger.error('OAuth callback failed', { platform: platformName, stack: e.stack });
1256
1277
  tracer?.traceError('oauth-callback:error', e, { platform: platformName });
1257
- res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
1278
+ res.status(400).send(wrapDebugResponse(tracer, { error: getErrorResponse(e) }));
1258
1279
  if (sessionId) {
1259
1280
  await updateAuthSession(sessionId, {
1260
1281
  status: 'failed',
1261
- errorMessage: e.message || e.toString()
1282
+ errorMessage: getErrorResponse(e).toString()
1262
1283
  });
1263
1284
  }
1264
-
1265
1285
  success = false;
1266
1286
  }
1267
1287
  const requestEndTime = new Date().getTime();
@@ -1292,7 +1312,7 @@ function createCoreRouter() {
1292
1312
  });
1293
1313
  let platformName = null;
1294
1314
  let success = false;
1295
- const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
1315
+ const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers });
1296
1316
  try {
1297
1317
  const platform = req.body.platform;
1298
1318
  platformName = platform;
@@ -1300,12 +1320,12 @@ function createCoreRouter() {
1300
1320
  const hostname = req.body.hostname;
1301
1321
  const proxyId = req.body.proxyId;
1302
1322
  const additionalInfo = req.body.additionalInfo;
1303
- const rcAccessToken = req.body.rcAccessToken;
1323
+ const rcAccessToken = getRcAccessTokenFromRequest(req);
1304
1324
  const connectorId = req.body.connectorId;
1305
1325
  const isPrivate = !!req.body.isPrivate;
1306
1326
  if (!platform) {
1307
1327
  tracer?.trace('apiKeyLogin:missingPlatform', {});
1308
- res.status(400).send(tracer ? tracer.wrapResponse('Missing platform name') : 'Missing platform name');
1328
+ res.status(400).send(wrapDebugResponse(tracer, 'Missing platform name'));
1309
1329
  return;
1310
1330
  }
1311
1331
  let rcAccountId = null;
@@ -1332,18 +1352,18 @@ function createCoreRouter() {
1332
1352
  id: userInfo.id.toString(),
1333
1353
  platform: platform
1334
1354
  });
1335
- res.status(200).send(tracer ? tracer.wrapResponse({ jwtToken, name: userInfo.name, returnMessage }) : { jwtToken, name: userInfo.name, returnMessage });
1355
+ res.status(200).send(wrapDebugResponse(tracer, { jwtToken, name: userInfo.name, returnMessage }));
1336
1356
  success = true;
1337
1357
  }
1338
1358
  else {
1339
- res.status(400).send(tracer ? tracer.wrapResponse({ returnMessage }) : { returnMessage });
1359
+ res.status(400).send(wrapDebugResponse(tracer, { returnMessage }));
1340
1360
  success = false;
1341
1361
  }
1342
1362
  }
1343
1363
  catch (e) {
1344
1364
  logger.error('API key login failed', { platform: platformName, stack: e.stack });
1345
1365
  tracer?.traceError('apiKeyLogin:error', e, { platform: platformName });
1346
- res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
1366
+ res.status(400).send(wrapDebugResponse(tracer, { error: getErrorResponse(e) }));
1347
1367
  success = false;
1348
1368
  }
1349
1369
  const requestEndTime = new Date().getTime();
@@ -1360,14 +1380,14 @@ function createCoreRouter() {
1360
1380
  author,
1361
1381
  eventAddedVia
1362
1382
  });
1363
- })
1383
+ });
1364
1384
  router.post('/unAuthorize', async function (req, res) {
1365
1385
  const requestStartTime = new Date().getTime();
1366
1386
  const tracer = req.headers['is-debug'] === 'true' ? DebugTracer.fromRequest(req) : null;
1367
1387
  tracer?.trace('unAuthorize:start', { query: req.query });
1368
1388
  let platformName = null;
1369
1389
  let success = false;
1370
- const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
1390
+ const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers });
1371
1391
  try {
1372
1392
  const jwtToken = req.jwtToken || req.query.jwtToken;
1373
1393
  if (jwtToken) {
@@ -1376,24 +1396,24 @@ function createCoreRouter() {
1376
1396
  const userToLogout = await UserModel.findByPk(unAuthData?.id);
1377
1397
  if (!userToLogout) {
1378
1398
  tracer?.trace('unAuthorize:userNotFound', {});
1379
- res.status(400).send(tracer ? tracer.wrapResponse('User not found') : 'User not found');
1399
+ res.status(400).send(wrapDebugResponse(tracer, 'User not found'));
1380
1400
  return;
1381
1401
  }
1382
1402
  const platformModule = connectorRegistry.getConnector(unAuthData?.platform ?? 'Unknown');
1383
1403
  const { returnMessage } = await platformModule.unAuthorize({ user: userToLogout });
1384
- res.status(200).send(tracer ? tracer.wrapResponse(returnMessage) : returnMessage);
1404
+ res.status(200).send(wrapDebugResponse(tracer, returnMessage));
1385
1405
  success = true;
1386
1406
  }
1387
1407
  else {
1388
1408
  tracer?.trace('unAuthorize:noToken', {});
1389
- res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
1409
+ res.status(400).send(wrapDebugResponse(tracer, 'Please go to Settings and authorize CRM platform'));
1390
1410
  success = false;
1391
1411
  }
1392
1412
  }
1393
1413
  catch (e) {
1394
1414
  logger.error('Unauthorize failed', { platform: platformName, stack: e.stack });
1395
1415
  tracer?.traceError('unAuthorize:error', e, { platform: platformName });
1396
- res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
1416
+ res.status(400).send(wrapDebugResponse(tracer, { error: getErrorResponse(e) }));
1397
1417
  success = false;
1398
1418
  }
1399
1419
  const requestEndTime = new Date().getTime();
@@ -1417,24 +1437,23 @@ function createCoreRouter() {
1417
1437
  tracer?.trace('userInfoHash:start', { query: req.query });
1418
1438
  const extensionId = util.getHashValue(req.query.extensionId, process.env.HASH_KEY);
1419
1439
  const accountId = util.getHashValue(req.query.accountId, process.env.HASH_KEY);
1420
- res.status(200).send(tracer ? tracer.wrapResponse({ extensionId, accountId }) : { extensionId, accountId });
1440
+ res.status(200).send(wrapDebugResponse(tracer, { extensionId, accountId }));
1421
1441
  }
1422
1442
  catch (e) {
1423
1443
  logger.error('Get user info hash failed', { stack: e.stack });
1424
- res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
1444
+ res.status(400).send(wrapDebugResponse(tracer, { error: getErrorResponse(e) }));
1425
1445
  tracer?.traceError('userInfoHash:error', e);
1426
1446
  }
1427
- })
1447
+ });
1428
1448
  router.get('/contact', async function (req, res) {
1429
1449
  const requestStartTime = new Date().getTime();
1430
1450
  const tracer = req.headers['is-debug'] === 'true' ? DebugTracer.fromRequest(req) : null;
1431
1451
  tracer?.trace('findContact:start', { query: req.query });
1432
-
1433
1452
  let platformName = null;
1434
1453
  let success = false;
1435
1454
  let resultCount = 0;
1436
1455
  let extraData = {};
1437
- const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
1456
+ const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers });
1438
1457
  try {
1439
1458
  const jwtToken = req.jwtToken || req.query.jwtToken;
1440
1459
  if (jwtToken) {
@@ -1442,7 +1461,7 @@ function createCoreRouter() {
1442
1461
  tracer?.trace('findContact:jwtDecoded', { decodedToken });
1443
1462
  if (!decodedToken) {
1444
1463
  tracer?.trace('findContact:invalidToken', {});
1445
- res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
1464
+ res.status(400).send(wrapDebugResponse(tracer, 'Please go to Settings and authorize CRM platform'));
1446
1465
  return;
1447
1466
  }
1448
1467
  const { id: userId, platform } = decodedToken;
@@ -1457,12 +1476,12 @@ function createCoreRouter() {
1457
1476
  isForceRefreshAccountData: req.query?.isForceRefreshAccountData === 'true'
1458
1477
  });
1459
1478
  if (isRevokeUserSession) {
1460
- res.status(401).send(tracer ? tracer.wrapResponse({ successful, returnMessage }) : { successful, returnMessage });
1479
+ res.status(401).send(wrapDebugResponse(tracer, { successful, returnMessage }));
1461
1480
  success = false;
1462
1481
  }
1463
1482
  else {
1464
1483
  tracer?.trace('findContact:result', { successful, returnMessage, contact });
1465
- res.status(200).send(tracer ? tracer.wrapResponse({ successful, returnMessage, contact }) : { successful, returnMessage, contact });
1484
+ res.status(200).send(wrapDebugResponse(tracer, { successful, returnMessage, contact }));
1466
1485
  if (successful) {
1467
1486
  const nonNewContact = contact?.filter(c => !c.isNewContact) ?? [];
1468
1487
  resultCount = nonNewContact.length;
@@ -1475,7 +1494,7 @@ function createCoreRouter() {
1475
1494
  }
1476
1495
  else {
1477
1496
  tracer?.trace('findContact:noToken', {});
1478
- res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
1497
+ res.status(400).send(wrapDebugResponse(tracer, 'Please go to Settings and authorize CRM platform'));
1479
1498
  success = false;
1480
1499
  }
1481
1500
  }
@@ -1483,7 +1502,7 @@ function createCoreRouter() {
1483
1502
  logger.error('Find contact failed', { platform: platformName, stack: e.stack });
1484
1503
  tracer?.traceError('findContact:error', e, { platform: platformName });
1485
1504
  extraData.statusCode = e.response?.status ?? 'unknown';
1486
- res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
1505
+ res.status(400).send(wrapDebugResponse(tracer, { error: getErrorResponse(e) }));
1487
1506
  success = false;
1488
1507
  }
1489
1508
  const requestEndTime = new Date().getTime();
@@ -1512,25 +1531,25 @@ function createCoreRouter() {
1512
1531
  let platformName = null;
1513
1532
  let success = false;
1514
1533
  let extraData = {};
1515
- const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
1534
+ const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers });
1516
1535
  try {
1517
1536
  const jwtToken = req.jwtToken || req.query.jwtToken;
1518
1537
  if (jwtToken) {
1519
1538
  const decodedToken = jwt.decodeJwt(jwtToken);
1520
1539
  if (!decodedToken) {
1521
1540
  tracer?.trace('createContact:invalidToken', {});
1522
- res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
1541
+ res.status(400).send(wrapDebugResponse(tracer, 'Please go to Settings and authorize CRM platform'));
1523
1542
  return;
1524
1543
  }
1525
1544
  const { id: userId, platform } = decodedToken;
1526
1545
  platformName = platform;
1527
1546
  const { successful, returnMessage, contact, extraDataTracking, isRevokeUserSession } = await contactCore.createContact({ platform, userId, phoneNumber: req.body.phoneNumber, newContactName: req.body.newContactName, newContactType: req.body.newContactType, additionalSubmission: req.body.additionalSubmission });
1528
1547
  if (isRevokeUserSession) {
1529
- res.status(401).send(tracer ? tracer.wrapResponse({ successful, returnMessage }) : { successful, returnMessage });
1548
+ res.status(401).send(wrapDebugResponse(tracer, { successful, returnMessage }));
1530
1549
  success = false;
1531
1550
  }
1532
1551
  else {
1533
- res.status(200).send(tracer ? tracer.wrapResponse({ successful, returnMessage, contact }) : { successful, returnMessage, contact });
1552
+ res.status(200).send(wrapDebugResponse(tracer, { successful, returnMessage, contact }));
1534
1553
  success = true;
1535
1554
  if (extraDataTracking) {
1536
1555
  extraData = extraDataTracking;
@@ -1539,7 +1558,7 @@ function createCoreRouter() {
1539
1558
  }
1540
1559
  else {
1541
1560
  tracer?.trace('createContact:noToken', {});
1542
- res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
1561
+ res.status(400).send(wrapDebugResponse(tracer, 'Please go to Settings and authorize CRM platform'));
1543
1562
  success = false;
1544
1563
  }
1545
1564
  }
@@ -1547,7 +1566,7 @@ function createCoreRouter() {
1547
1566
  logger.error('Create contact failed', { platform: platformName, stack: e.stack });
1548
1567
  tracer?.traceError('createContact:error', e, { platform: platformName });
1549
1568
  extraData.statusCode = e.response?.status ?? 'unknown';
1550
- res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
1569
+ res.status(400).send(wrapDebugResponse(tracer, { error: getErrorResponse(e) }));
1551
1570
  success = false;
1552
1571
  }
1553
1572
  const requestEndTime = new Date().getTime();
@@ -1568,7 +1587,6 @@ function createCoreRouter() {
1568
1587
  eventAddedVia
1569
1588
  });
1570
1589
  });
1571
-
1572
1590
  router.get('/appointments', async function (req, res) {
1573
1591
  const requestStartTime = new Date().getTime();
1574
1592
  const tracer = req.headers['is-debug'] === 'true' ? DebugTracer.fromRequest(req) : null;
@@ -1576,14 +1594,14 @@ function createCoreRouter() {
1576
1594
  let platformName = null;
1577
1595
  let success = false;
1578
1596
  let extraData = {};
1579
- const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
1597
+ const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers });
1580
1598
  try {
1581
- const jwtToken = req.query.jwtToken;
1599
+ const jwtToken = req.jwtToken || req.query.jwtToken;
1582
1600
  if (jwtToken) {
1583
1601
  const decodedToken = jwt.decodeJwt(jwtToken);
1584
1602
  if (!decodedToken) {
1585
1603
  tracer?.trace('listAppointments:invalidToken', {});
1586
- res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
1604
+ res.status(400).send(wrapDebugResponse(tracer, 'Please go to Settings and authorize CRM platform'));
1587
1605
  return;
1588
1606
  }
1589
1607
  const { id: userId, platform } = decodedToken;
@@ -1593,11 +1611,11 @@ function createCoreRouter() {
1593
1611
  const forceSync = req.query.forceSync === 'true';
1594
1612
  const { successful, appointments, returnMessage, extraDataTracking, isRevokeUserSession } = await appointmentCore.listAppointments({ platform, userId, range, mineOnly, forceSync });
1595
1613
  if (isRevokeUserSession) {
1596
- res.status(401).send(tracer ? tracer.wrapResponse({ successful, returnMessage }) : { successful, returnMessage });
1614
+ res.status(401).send(wrapDebugResponse(tracer, { successful, returnMessage }));
1597
1615
  success = false;
1598
1616
  }
1599
1617
  else {
1600
- res.status(200).send(tracer ? tracer.wrapResponse({ successful, appointments, returnMessage }) : { successful, appointments, returnMessage });
1618
+ res.status(200).send(wrapDebugResponse(tracer, { successful, appointments, returnMessage }));
1601
1619
  success = true;
1602
1620
  if (extraDataTracking) {
1603
1621
  extraData = extraDataTracking;
@@ -1610,7 +1628,7 @@ function createCoreRouter() {
1610
1628
  }
1611
1629
  else {
1612
1630
  tracer?.trace('listAppointments:noToken', {});
1613
- res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
1631
+ res.status(400).send(wrapDebugResponse(tracer, 'Please go to Settings and authorize CRM platform'));
1614
1632
  success = false;
1615
1633
  }
1616
1634
  }
@@ -1618,7 +1636,7 @@ function createCoreRouter() {
1618
1636
  logger.error('List appointments failed', { platform: platformName, stack: e.stack });
1619
1637
  tracer?.traceError('listAppointments:error', e, { platform: platformName });
1620
1638
  extraData.statusCode = e.response?.status ?? 'unknown';
1621
- res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
1639
+ res.status(400).send(wrapDebugResponse(tracer, { error: getErrorResponse(e) }));
1622
1640
  success = false;
1623
1641
  }
1624
1642
  const requestEndTime = new Date().getTime();
@@ -1639,7 +1657,6 @@ function createCoreRouter() {
1639
1657
  eventAddedVia
1640
1658
  });
1641
1659
  });
1642
-
1643
1660
  router.post('/appointments', async function (req, res) {
1644
1661
  const requestStartTime = new Date().getTime();
1645
1662
  const tracer = req.headers['is-debug'] === 'true' ? DebugTracer.fromRequest(req) : null;
@@ -1647,14 +1664,14 @@ function createCoreRouter() {
1647
1664
  let platformName = null;
1648
1665
  let success = false;
1649
1666
  let extraData = {};
1650
- const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
1667
+ const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers });
1651
1668
  try {
1652
- const jwtToken = req.query.jwtToken;
1669
+ const jwtToken = req.jwtToken || req.query.jwtToken;
1653
1670
  if (jwtToken) {
1654
1671
  const decodedToken = jwt.decodeJwt(jwtToken);
1655
1672
  if (!decodedToken) {
1656
1673
  tracer?.trace('createAppointment:invalidToken', {});
1657
- res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
1674
+ res.status(400).send(wrapDebugResponse(tracer, 'Please go to Settings and authorize CRM platform'));
1658
1675
  return;
1659
1676
  }
1660
1677
  const { id: userId, platform } = decodedToken;
@@ -1662,20 +1679,20 @@ function createCoreRouter() {
1662
1679
  const payload = req.body?.payload ?? req.body;
1663
1680
  const { successful, appointmentId, appointment, returnMessage, extraDataTracking, isRevokeUserSession } = await appointmentCore.createAppointment({ platform, userId, payload });
1664
1681
  if (isRevokeUserSession) {
1665
- res.status(401).send(tracer ? tracer.wrapResponse({ successful, returnMessage }) : { successful, returnMessage });
1682
+ res.status(401).send(wrapDebugResponse(tracer, { successful, returnMessage }));
1666
1683
  success = false;
1667
1684
  }
1668
1685
  else {
1669
1686
  if (extraDataTracking) {
1670
1687
  extraData = extraDataTracking;
1671
1688
  }
1672
- res.status(200).send(tracer ? tracer.wrapResponse({ successful, appointmentId, appointment, returnMessage }) : { successful, appointmentId, appointment, returnMessage });
1689
+ res.status(200).send(wrapDebugResponse(tracer, { successful, appointmentId, appointment, returnMessage }));
1673
1690
  success = true;
1674
1691
  }
1675
1692
  }
1676
1693
  else {
1677
1694
  tracer?.trace('createAppointment:noToken', {});
1678
- res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
1695
+ res.status(400).send(wrapDebugResponse(tracer, 'Please go to Settings and authorize CRM platform'));
1679
1696
  success = false;
1680
1697
  }
1681
1698
  }
@@ -1683,7 +1700,7 @@ function createCoreRouter() {
1683
1700
  logger.error('Create appointment failed', { platform: platformName, stack: e.stack });
1684
1701
  tracer?.traceError('createAppointment:error', e, { platform: platformName });
1685
1702
  extraData.statusCode = e.response?.status ?? 'unknown';
1686
- res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
1703
+ res.status(400).send(wrapDebugResponse(tracer, { error: getErrorResponse(e) }));
1687
1704
  success = false;
1688
1705
  }
1689
1706
  const requestEndTime = new Date().getTime();
@@ -1704,7 +1721,6 @@ function createCoreRouter() {
1704
1721
  eventAddedVia
1705
1722
  });
1706
1723
  });
1707
-
1708
1724
  router.patch('/appointments/:appointmentId', async function (req, res) {
1709
1725
  const requestStartTime = new Date().getTime();
1710
1726
  const tracer = req.headers['is-debug'] === 'true' ? DebugTracer.fromRequest(req) : null;
@@ -1712,14 +1728,14 @@ function createCoreRouter() {
1712
1728
  let platformName = null;
1713
1729
  let success = false;
1714
1730
  let extraData = {};
1715
- const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
1731
+ const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers });
1716
1732
  try {
1717
- const jwtToken = req.query.jwtToken;
1733
+ const jwtToken = req.jwtToken || req.query.jwtToken;
1718
1734
  if (jwtToken) {
1719
1735
  const decodedToken = jwt.decodeJwt(jwtToken);
1720
1736
  if (!decodedToken) {
1721
1737
  tracer?.trace('updateAppointment:invalidToken', {});
1722
- res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
1738
+ res.status(400).send(wrapDebugResponse(tracer, 'Please go to Settings and authorize CRM platform'));
1723
1739
  return;
1724
1740
  }
1725
1741
  const { id: userId, platform } = decodedToken;
@@ -1728,20 +1744,20 @@ function createCoreRouter() {
1728
1744
  const patchBody = req.body?.patch ?? req.body;
1729
1745
  const { successful, appointment, returnMessage, extraDataTracking, isRevokeUserSession } = await appointmentCore.updateAppointment({ platform, userId, appointmentId, patchBody });
1730
1746
  if (isRevokeUserSession) {
1731
- res.status(401).send(tracer ? tracer.wrapResponse({ successful, returnMessage }) : { successful, returnMessage });
1747
+ res.status(401).send(wrapDebugResponse(tracer, { successful, returnMessage }));
1732
1748
  success = false;
1733
1749
  }
1734
1750
  else {
1735
1751
  if (extraDataTracking) {
1736
1752
  extraData = extraDataTracking;
1737
1753
  }
1738
- res.status(200).send(tracer ? tracer.wrapResponse({ successful, appointmentId, appointment, returnMessage }) : { successful, appointmentId, appointment, returnMessage });
1754
+ res.status(200).send(wrapDebugResponse(tracer, { successful, appointmentId, appointment, returnMessage }));
1739
1755
  success = true;
1740
1756
  }
1741
1757
  }
1742
1758
  else {
1743
1759
  tracer?.trace('updateAppointment:noToken', {});
1744
- res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
1760
+ res.status(400).send(wrapDebugResponse(tracer, 'Please go to Settings and authorize CRM platform'));
1745
1761
  success = false;
1746
1762
  }
1747
1763
  }
@@ -1749,7 +1765,7 @@ function createCoreRouter() {
1749
1765
  logger.error('Update appointment failed', { platform: platformName, stack: e.stack });
1750
1766
  tracer?.traceError('updateAppointment:error', e, { platform: platformName });
1751
1767
  extraData.statusCode = e.response?.status ?? 'unknown';
1752
- res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
1768
+ res.status(400).send(wrapDebugResponse(tracer, { error: getErrorResponse(e) }));
1753
1769
  success = false;
1754
1770
  }
1755
1771
  const requestEndTime = new Date().getTime();
@@ -1770,7 +1786,81 @@ function createCoreRouter() {
1770
1786
  eventAddedVia
1771
1787
  });
1772
1788
  });
1773
-
1789
+ router.post('/appointments/:appointmentId/status', async function (req, res) {
1790
+ const requestStartTime = new Date().getTime();
1791
+ const tracer = req.headers['is-debug'] === 'true' ? DebugTracer.fromRequest(req) : null;
1792
+ tracer?.trace('updateAppointmentStatus:start', { query: req.query, params: req.params });
1793
+ let platformName = null;
1794
+ let success = false;
1795
+ let extraData = {};
1796
+ const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers });
1797
+ try {
1798
+ const jwtToken = req.jwtToken || req.query.jwtToken;
1799
+ if (jwtToken) {
1800
+ const decodedToken = jwt.decodeJwt(jwtToken);
1801
+ if (!decodedToken) {
1802
+ tracer?.trace('updateAppointmentStatus:invalidToken', {});
1803
+ res.status(400).send(wrapDebugResponse(tracer, 'Please go to Settings and authorize CRM platform'));
1804
+ return;
1805
+ }
1806
+ const status = String(req.body?.status || '').trim().toLowerCase();
1807
+ if (!status) {
1808
+ tracer?.trace('updateAppointmentStatus:noStatus', {});
1809
+ res.status(400).send(wrapDebugResponse(tracer, 'Appointment status is required'));
1810
+ return;
1811
+ }
1812
+ const { id: userId, platform } = decodedToken;
1813
+ platformName = platform;
1814
+ const appointmentId = req.params.appointmentId;
1815
+ const { successful, appointment, returnMessage, extraDataTracking, isRevokeUserSession } = await appointmentCore.updateAppointment({
1816
+ platform,
1817
+ userId,
1818
+ appointmentId,
1819
+ patchBody: { status }
1820
+ });
1821
+ if (isRevokeUserSession) {
1822
+ res.status(401).send(wrapDebugResponse(tracer, { successful, returnMessage }));
1823
+ success = false;
1824
+ }
1825
+ else {
1826
+ if (extraDataTracking) {
1827
+ extraData = extraDataTracking;
1828
+ }
1829
+ res.status(200).send(wrapDebugResponse(tracer, { successful, appointmentId, appointment, returnMessage }));
1830
+ success = true;
1831
+ }
1832
+ }
1833
+ else {
1834
+ tracer?.trace('updateAppointmentStatus:noToken', {});
1835
+ res.status(400).send(wrapDebugResponse(tracer, 'Please go to Settings and authorize CRM platform'));
1836
+ success = false;
1837
+ }
1838
+ }
1839
+ catch (e) {
1840
+ logger.error('Update appointment status failed', { platform: platformName, stack: e.stack });
1841
+ tracer?.traceError('updateAppointmentStatus:error', e, { platform: platformName });
1842
+ extraData.statusCode = e.response?.status ?? 'unknown';
1843
+ res.status(400).send(wrapDebugResponse(tracer, { error: getErrorResponse(e) }));
1844
+ success = false;
1845
+ }
1846
+ const requestEndTime = new Date().getTime();
1847
+ analytics.track({
1848
+ eventName: 'Update appointment status',
1849
+ interfaceName: 'updateAppointmentStatus',
1850
+ connectorName: platformName,
1851
+ accountId: hashedAccountId,
1852
+ extensionId: hashedExtensionId,
1853
+ success,
1854
+ requestDuration: (requestEndTime - requestStartTime) / 1000,
1855
+ userAgent,
1856
+ ip,
1857
+ author,
1858
+ extras: {
1859
+ ...extraData
1860
+ },
1861
+ eventAddedVia
1862
+ });
1863
+ });
1774
1864
  router.get('/appointments/:appointmentId/refresh', async function (req, res) {
1775
1865
  const requestStartTime = new Date().getTime();
1776
1866
  const tracer = req.headers['is-debug'] === 'true' ? DebugTracer.fromRequest(req) : null;
@@ -1778,14 +1868,14 @@ function createCoreRouter() {
1778
1868
  let platformName = null;
1779
1869
  let success = false;
1780
1870
  let extraData = {};
1781
- const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
1871
+ const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers });
1782
1872
  try {
1783
- const jwtToken = req.query.jwtToken;
1873
+ const jwtToken = req.jwtToken || req.query.jwtToken;
1784
1874
  if (jwtToken) {
1785
1875
  const decodedToken = jwt.decodeJwt(jwtToken);
1786
1876
  if (!decodedToken) {
1787
1877
  tracer?.trace('refreshAppointment:invalidToken', {});
1788
- res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
1878
+ res.status(400).send(wrapDebugResponse(tracer, 'Please go to Settings and authorize CRM platform'));
1789
1879
  return;
1790
1880
  }
1791
1881
  const { id: userId, platform } = decodedToken;
@@ -1793,20 +1883,20 @@ function createCoreRouter() {
1793
1883
  const appointmentId = req.params.appointmentId;
1794
1884
  const { successful, appointment, returnMessage, extraDataTracking, isRevokeUserSession } = await appointmentCore.refreshAppointment({ platform, userId, appointmentId });
1795
1885
  if (isRevokeUserSession) {
1796
- res.status(401).send(tracer ? tracer.wrapResponse({ successful, returnMessage }) : { successful, returnMessage });
1886
+ res.status(401).send(wrapDebugResponse(tracer, { successful, returnMessage }));
1797
1887
  success = false;
1798
1888
  }
1799
1889
  else {
1800
1890
  if (extraDataTracking) {
1801
1891
  extraData = extraDataTracking;
1802
1892
  }
1803
- res.status(200).send(tracer ? tracer.wrapResponse({ successful, appointmentId, appointment, returnMessage }) : { successful, appointmentId, appointment, returnMessage });
1893
+ res.status(200).send(wrapDebugResponse(tracer, { successful, appointmentId, appointment, returnMessage }));
1804
1894
  success = true;
1805
1895
  }
1806
1896
  }
1807
1897
  else {
1808
1898
  tracer?.trace('refreshAppointment:noToken', {});
1809
- res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
1899
+ res.status(400).send(wrapDebugResponse(tracer, 'Please go to Settings and authorize CRM platform'));
1810
1900
  success = false;
1811
1901
  }
1812
1902
  }
@@ -1814,7 +1904,7 @@ function createCoreRouter() {
1814
1904
  logger.error('Refresh appointment failed', { platform: platformName, stack: e.stack });
1815
1905
  tracer?.traceError('refreshAppointment:error', e, { platform: platformName });
1816
1906
  extraData.statusCode = e.response?.status ?? 'unknown';
1817
- res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
1907
+ res.status(400).send(wrapDebugResponse(tracer, { error: getErrorResponse(e) }));
1818
1908
  success = false;
1819
1909
  }
1820
1910
  const requestEndTime = new Date().getTime();
@@ -1835,7 +1925,6 @@ function createCoreRouter() {
1835
1925
  eventAddedVia
1836
1926
  });
1837
1927
  });
1838
-
1839
1928
  router.post('/appointments/:appointmentId/confirm', async function (req, res) {
1840
1929
  const requestStartTime = new Date().getTime();
1841
1930
  const tracer = req.headers['is-debug'] === 'true' ? DebugTracer.fromRequest(req) : null;
@@ -1843,14 +1932,14 @@ function createCoreRouter() {
1843
1932
  let platformName = null;
1844
1933
  let success = false;
1845
1934
  let extraData = {};
1846
- const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
1935
+ const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers });
1847
1936
  try {
1848
- const jwtToken = req.query.jwtToken;
1937
+ const jwtToken = req.jwtToken || req.query.jwtToken;
1849
1938
  if (jwtToken) {
1850
1939
  const decodedToken = jwt.decodeJwt(jwtToken);
1851
1940
  if (!decodedToken) {
1852
1941
  tracer?.trace('confirmAppointment:invalidToken', {});
1853
- res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
1942
+ res.status(400).send(wrapDebugResponse(tracer, 'Please go to Settings and authorize CRM platform'));
1854
1943
  return;
1855
1944
  }
1856
1945
  const { id: userId, platform } = decodedToken;
@@ -1858,20 +1947,20 @@ function createCoreRouter() {
1858
1947
  const appointmentId = req.params.appointmentId;
1859
1948
  const { successful, appointment, returnMessage, extraDataTracking, isRevokeUserSession } = await appointmentCore.confirmAppointment({ platform, userId, appointmentId });
1860
1949
  if (isRevokeUserSession) {
1861
- res.status(401).send(tracer ? tracer.wrapResponse({ successful, returnMessage }) : { successful, returnMessage });
1950
+ res.status(401).send(wrapDebugResponse(tracer, { successful, returnMessage }));
1862
1951
  success = false;
1863
1952
  }
1864
1953
  else {
1865
1954
  if (extraDataTracking) {
1866
1955
  extraData = extraDataTracking;
1867
1956
  }
1868
- res.status(200).send(tracer ? tracer.wrapResponse({ successful, appointmentId, appointment, returnMessage }) : { successful, appointmentId, appointment, returnMessage });
1957
+ res.status(200).send(wrapDebugResponse(tracer, { successful, appointmentId, appointment, returnMessage }));
1869
1958
  success = true;
1870
1959
  }
1871
1960
  }
1872
1961
  else {
1873
1962
  tracer?.trace('confirmAppointment:noToken', {});
1874
- res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
1963
+ res.status(400).send(wrapDebugResponse(tracer, 'Please go to Settings and authorize CRM platform'));
1875
1964
  success = false;
1876
1965
  }
1877
1966
  }
@@ -1879,7 +1968,7 @@ function createCoreRouter() {
1879
1968
  logger.error('Confirm appointment failed', { platform: platformName, stack: e.stack });
1880
1969
  tracer?.traceError('confirmAppointment:error', e, { platform: platformName });
1881
1970
  extraData.statusCode = e.response?.status ?? 'unknown';
1882
- res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
1971
+ res.status(400).send(wrapDebugResponse(tracer, { error: getErrorResponse(e) }));
1883
1972
  success = false;
1884
1973
  }
1885
1974
  const requestEndTime = new Date().getTime();
@@ -1900,7 +1989,6 @@ function createCoreRouter() {
1900
1989
  eventAddedVia
1901
1990
  });
1902
1991
  });
1903
-
1904
1992
  router.post('/appointments/:appointmentId/cancel', async function (req, res) {
1905
1993
  const requestStartTime = new Date().getTime();
1906
1994
  const tracer = req.headers['is-debug'] === 'true' ? DebugTracer.fromRequest(req) : null;
@@ -1908,14 +1996,14 @@ function createCoreRouter() {
1908
1996
  let platformName = null;
1909
1997
  let success = false;
1910
1998
  let extraData = {};
1911
- const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
1999
+ const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers });
1912
2000
  try {
1913
- const jwtToken = req.query.jwtToken;
2001
+ const jwtToken = req.jwtToken || req.query.jwtToken;
1914
2002
  if (jwtToken) {
1915
2003
  const decodedToken = jwt.decodeJwt(jwtToken);
1916
2004
  if (!decodedToken) {
1917
2005
  tracer?.trace('cancelAppointment:invalidToken', {});
1918
- res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
2006
+ res.status(400).send(wrapDebugResponse(tracer, 'Please go to Settings and authorize CRM platform'));
1919
2007
  return;
1920
2008
  }
1921
2009
  const { id: userId, platform } = decodedToken;
@@ -1923,20 +2011,20 @@ function createCoreRouter() {
1923
2011
  const appointmentId = req.params.appointmentId;
1924
2012
  const { successful, appointment, returnMessage, extraDataTracking, isRevokeUserSession } = await appointmentCore.cancelAppointment({ platform, userId, appointmentId });
1925
2013
  if (isRevokeUserSession) {
1926
- res.status(401).send(tracer ? tracer.wrapResponse({ successful, returnMessage }) : { successful, returnMessage });
2014
+ res.status(401).send(wrapDebugResponse(tracer, { successful, returnMessage }));
1927
2015
  success = false;
1928
2016
  }
1929
2017
  else {
1930
2018
  if (extraDataTracking) {
1931
2019
  extraData = extraDataTracking;
1932
2020
  }
1933
- res.status(200).send(tracer ? tracer.wrapResponse({ successful, appointmentId, appointment, returnMessage }) : { successful, appointmentId, appointment, returnMessage });
2021
+ res.status(200).send(wrapDebugResponse(tracer, { successful, appointmentId, appointment, returnMessage }));
1934
2022
  success = true;
1935
2023
  }
1936
2024
  }
1937
2025
  else {
1938
2026
  tracer?.trace('cancelAppointment:noToken', {});
1939
- res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
2027
+ res.status(400).send(wrapDebugResponse(tracer, 'Please go to Settings and authorize CRM platform'));
1940
2028
  success = false;
1941
2029
  }
1942
2030
  }
@@ -1944,7 +2032,7 @@ function createCoreRouter() {
1944
2032
  logger.error('Cancel appointment failed', { platform: platformName, stack: e.stack });
1945
2033
  tracer?.traceError('cancelAppointment:error', e, { platform: platformName });
1946
2034
  extraData.statusCode = e.response?.status ?? 'unknown';
1947
- res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
2035
+ res.status(400).send(wrapDebugResponse(tracer, { error: getErrorResponse(e) }));
1948
2036
  success = false;
1949
2037
  }
1950
2038
  const requestEndTime = new Date().getTime();
@@ -1972,30 +2060,31 @@ function createCoreRouter() {
1972
2060
  let platformName = null;
1973
2061
  let success = false;
1974
2062
  let extraData = {};
1975
- const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
2063
+ const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers });
1976
2064
  try {
1977
2065
  const jwtToken = req.jwtToken || req.query.jwtToken;
1978
2066
  if (jwtToken) {
1979
2067
  const decodedToken = jwt.decodeJwt(jwtToken);
1980
2068
  if (!decodedToken) {
1981
2069
  tracer?.trace('saveNoteCache:invalidToken', {});
1982
- res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
2070
+ res.status(400).send(wrapDebugResponse(tracer, 'Please go to Settings and authorize CRM platform'));
1983
2071
  return;
1984
2072
  }
1985
2073
  const { id: userId, platform } = decodedToken;
1986
2074
  platformName = platform;
1987
2075
  const { successful, returnMessage, extraDataTracking } = await logCore.saveNoteCache({ platform, userId, sessionId: req.body.sessionId, note: req.body.note });
1988
- res.status(200).send(tracer ? tracer.wrapResponse({ successful, returnMessage }) : { successful, returnMessage });
2076
+ res.status(200).send(wrapDebugResponse(tracer, { successful, returnMessage }));
1989
2077
  success = true;
1990
2078
  if (extraDataTracking) {
1991
2079
  extraData = extraDataTracking;
1992
2080
  }
1993
2081
  }
1994
- } catch (e) {
2082
+ }
2083
+ catch (e) {
1995
2084
  logger.error('Save note cache failed', { platform: platformName, stack: e.stack });
1996
2085
  tracer?.traceError('saveNoteCache:error', e, { platform: platformName });
1997
2086
  extraData.statusCode = e.response?.status ?? 'unknown';
1998
- res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
2087
+ res.status(400).send(wrapDebugResponse(tracer, { error: getErrorResponse(e) }));
1999
2088
  success = false;
2000
2089
  }
2001
2090
  const requestEndTime = new Date().getTime();
@@ -2015,7 +2104,7 @@ function createCoreRouter() {
2015
2104
  ...extraData
2016
2105
  }
2017
2106
  });
2018
- })
2107
+ });
2019
2108
  router.get('/callLog', async function (req, res) {
2020
2109
  const requestStartTime = new Date().getTime();
2021
2110
  const tracer = req.headers['is-debug'] === 'true' ? DebugTracer.fromRequest(req) : null;
@@ -2023,14 +2112,14 @@ function createCoreRouter() {
2023
2112
  let platformName = null;
2024
2113
  let success = false;
2025
2114
  let extraData = {};
2026
- const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
2115
+ const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers });
2027
2116
  try {
2028
2117
  const jwtToken = req.jwtToken || req.query.jwtToken;
2029
2118
  if (jwtToken) {
2030
2119
  const decodedToken = jwt.decodeJwt(jwtToken);
2031
2120
  if (!decodedToken) {
2032
2121
  tracer?.trace('getCallLog:invalidToken', {});
2033
- res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
2122
+ res.status(400).send(wrapDebugResponse(tracer, 'Please go to Settings and authorize CRM platform'));
2034
2123
  return;
2035
2124
  }
2036
2125
  const { id: userId, platform } = decodedToken;
@@ -2044,11 +2133,11 @@ function createCoreRouter() {
2044
2133
  requireDetails: req.query.requireDetails === 'true'
2045
2134
  });
2046
2135
  if (isRevokeUserSession) {
2047
- res.status(401).send(tracer ? tracer.wrapResponse({ successful, returnMessage }) : { successful, returnMessage });
2136
+ res.status(401).send(wrapDebugResponse(tracer, { successful, returnMessage }));
2048
2137
  success = false;
2049
2138
  }
2050
2139
  else {
2051
- res.status(200).send(tracer ? tracer.wrapResponse({ successful, logs, returnMessage }) : { successful, logs, returnMessage });
2140
+ res.status(200).send(wrapDebugResponse(tracer, { successful, logs, returnMessage }));
2052
2141
  success = true;
2053
2142
  if (extraDataTracking) {
2054
2143
  extraData = extraDataTracking;
@@ -2058,14 +2147,14 @@ function createCoreRouter() {
2058
2147
  }
2059
2148
  else {
2060
2149
  tracer?.trace('getCallLog:noToken', {});
2061
- res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
2150
+ res.status(400).send(wrapDebugResponse(tracer, 'Please go to Settings and authorize CRM platform'));
2062
2151
  success = false;
2063
2152
  }
2064
2153
  }
2065
2154
  catch (e) {
2066
2155
  logger.error('Get call log failed', { platform: platformName, stack: e.stack });
2067
2156
  extraData.statusCode = e.response?.status ?? 'unknown';
2068
- res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
2157
+ res.status(400).send(wrapDebugResponse(tracer, { error: getErrorResponse(e) }));
2069
2158
  tracer?.traceError('getCallLog:error', e, { platform: platformName });
2070
2159
  success = false;
2071
2160
  }
@@ -2094,41 +2183,41 @@ function createCoreRouter() {
2094
2183
  let platformName = null;
2095
2184
  let success = false;
2096
2185
  let extraData = {};
2097
- const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
2186
+ const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers });
2098
2187
  try {
2099
2188
  const jwtToken = req.jwtToken || req.query.jwtToken;
2100
2189
  if (jwtToken) {
2101
2190
  const decodedToken = jwt.decodeJwt(jwtToken);
2102
2191
  if (!decodedToken) {
2103
2192
  tracer?.trace('createCallLog:invalidToken', {});
2104
- res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
2193
+ res.status(400).send(wrapDebugResponse(tracer, 'Please go to Settings and authorize CRM platform'));
2105
2194
  return;
2106
2195
  }
2107
2196
  const { id: userId, platform } = decodedToken;
2108
2197
  platformName = platform;
2109
2198
  const { successful, logId, returnMessage, extraDataTracking, isRevokeUserSession } = await logCore.createCallLog({ jwtToken, platform, userId, incomingData: req.body, hashedAccountId: hashedAccountId ?? util.getHashValue(req.body.logInfo?.accountId, process.env.HASH_KEY), isFromSSCL: userAgent === 'SSCL' });
2110
2199
  if (isRevokeUserSession) {
2111
- res.status(401).send(tracer ? tracer.wrapResponse({ successful, returnMessage }) : { successful, returnMessage });
2200
+ res.status(401).send(wrapDebugResponse(tracer, { successful, returnMessage }));
2112
2201
  success = false;
2113
2202
  }
2114
2203
  else {
2115
2204
  if (extraDataTracking) {
2116
2205
  extraData = extraDataTracking;
2117
2206
  }
2118
- res.status(200).send(tracer ? tracer.wrapResponse({ successful, logId, returnMessage }) : { successful, logId, returnMessage });
2207
+ res.status(200).send(wrapDebugResponse(tracer, { successful, logId, returnMessage }));
2119
2208
  success = true;
2120
2209
  }
2121
2210
  }
2122
2211
  else {
2123
2212
  tracer?.trace('createCallLog:noToken', {});
2124
- res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
2213
+ res.status(400).send(wrapDebugResponse(tracer, 'Please go to Settings and authorize CRM platform'));
2125
2214
  success = false;
2126
2215
  }
2127
2216
  }
2128
2217
  catch (e) {
2129
2218
  logger.error('Create call log failed', { platform: platformName, stack: e.stack });
2130
2219
  extraData.statusCode = e.response?.status ?? 'unknown';
2131
- res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
2220
+ res.status(400).send(wrapDebugResponse(tracer, { error: getErrorResponse(e) }));
2132
2221
  tracer?.traceError('createCallLog:error', e, { platform: platformName });
2133
2222
  success = false;
2134
2223
  }
@@ -2157,14 +2246,14 @@ function createCoreRouter() {
2157
2246
  let platformName = null;
2158
2247
  let success = false;
2159
2248
  let extraData = {};
2160
- const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
2249
+ const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers });
2161
2250
  try {
2162
2251
  const jwtToken = req.jwtToken || req.query.jwtToken;
2163
2252
  if (jwtToken) {
2164
2253
  const decodedToken = jwt.decodeJwt(jwtToken);
2165
2254
  if (!decodedToken) {
2166
2255
  tracer?.trace('updateCallLog:invalidToken', {});
2167
- res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
2256
+ res.status(400).send(wrapDebugResponse(tracer, 'Please go to Settings and authorize CRM platform'));
2168
2257
  return;
2169
2258
  }
2170
2259
  const { id: userId, platform } = decodedToken;
@@ -2173,19 +2262,19 @@ function createCoreRouter() {
2173
2262
  if (extraDataTracking) {
2174
2263
  extraData = extraDataTracking;
2175
2264
  }
2176
- res.status(200).send(tracer ? tracer.wrapResponse({ successful, logId, updatedNote, returnMessage }) : { successful, logId, updatedNote, returnMessage });
2265
+ res.status(200).send(wrapDebugResponse(tracer, { successful, logId, updatedNote, returnMessage }));
2177
2266
  success = true;
2178
2267
  }
2179
2268
  else {
2180
2269
  tracer?.trace('updateCallLog:noToken', {});
2181
- res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
2270
+ res.status(400).send(wrapDebugResponse(tracer, 'Please go to Settings and authorize CRM platform'));
2182
2271
  success = false;
2183
2272
  }
2184
2273
  }
2185
2274
  catch (e) {
2186
2275
  logger.error('Update call log failed', { platform: platformName, stack: e.stack });
2187
2276
  extraData.statusCode = e.response?.status ?? 'unknown';
2188
- res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
2277
+ res.status(400).send(wrapDebugResponse(tracer, { error: getErrorResponse(e) }));
2189
2278
  tracer?.traceError('updateCallLog:error', e, { platform: platformName });
2190
2279
  success = false;
2191
2280
  }
@@ -2214,21 +2303,21 @@ function createCoreRouter() {
2214
2303
  let platformName = null;
2215
2304
  let success = false;
2216
2305
  let extraData = {};
2217
- const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
2306
+ const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers });
2218
2307
  try {
2219
2308
  const jwtToken = req.jwtToken || req.query.jwtToken;
2220
2309
  if (jwtToken) {
2221
2310
  const decodedToken = jwt.decodeJwt(jwtToken);
2222
2311
  if (!decodedToken) {
2223
2312
  tracer?.trace('upsertCallDisposition:invalidJwtToken', {});
2224
- res.status(400).send(tracer ? tracer.wrapResponse('Invalid JWT token') : 'Invalid JWT token');
2313
+ res.status(400).send(wrapDebugResponse(tracer, 'Invalid JWT token'));
2225
2314
  return;
2226
2315
  }
2227
2316
  const { id: userId, platform } = decodedToken;
2228
2317
  platformName = platform;
2229
2318
  if (!userId) {
2230
2319
  tracer?.trace('upsertCallDisposition:invalidToken', {});
2231
- res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
2320
+ res.status(400).send(wrapDebugResponse(tracer, 'Please go to Settings and authorize CRM platform'));
2232
2321
  return;
2233
2322
  }
2234
2323
  const { successful, returnMessage, extraDataTracking, isRevokeUserSession } = await dispositionCore.upsertCallDisposition({
@@ -2241,27 +2330,27 @@ function createCoreRouter() {
2241
2330
  additionalSubmission: req.body.additionalSubmission
2242
2331
  });
2243
2332
  if (isRevokeUserSession) {
2244
- res.status(401).send(tracer ? tracer.wrapResponse({ successful, returnMessage }) : { successful, returnMessage });
2333
+ res.status(401).send(wrapDebugResponse(tracer, { successful, returnMessage }));
2245
2334
  success = false;
2246
2335
  }
2247
2336
  else {
2248
2337
  if (extraDataTracking) {
2249
2338
  extraData = extraDataTracking;
2250
2339
  }
2251
- res.status(200).send(tracer ? tracer.wrapResponse({ successful, returnMessage }) : { successful, returnMessage });
2340
+ res.status(200).send(wrapDebugResponse(tracer, { successful, returnMessage }));
2252
2341
  success = true;
2253
2342
  }
2254
2343
  }
2255
2344
  else {
2256
2345
  tracer?.trace('upsertCallDisposition:noToken', {});
2257
- res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
2346
+ res.status(400).send(wrapDebugResponse(tracer, 'Please go to Settings and authorize CRM platform'));
2258
2347
  success = false;
2259
2348
  }
2260
2349
  }
2261
2350
  catch (e) {
2262
2351
  logger.error('Upsert call disposition failed', { platform: platformName, stack: e.stack });
2263
2352
  extraData.statusCode = e.response?.status ?? 'unknown';
2264
- res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
2353
+ res.status(400).send(wrapDebugResponse(tracer, { error: getErrorResponse(e) }));
2265
2354
  tracer?.traceError('upsertCallDisposition:error', e, { platform: platformName });
2266
2355
  success = false;
2267
2356
  }
@@ -2291,41 +2380,41 @@ function createCoreRouter() {
2291
2380
  let success = false;
2292
2381
  let statusCode = 200;
2293
2382
  let extraData = {};
2294
- const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
2383
+ const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers });
2295
2384
  try {
2296
2385
  const jwtToken = req.jwtToken || req.query.jwtToken;
2297
2386
  if (jwtToken) {
2298
2387
  const decodedToken = jwt.decodeJwt(jwtToken);
2299
2388
  if (!decodedToken) {
2300
2389
  tracer?.trace('createMessageLog:invalidToken', {});
2301
- res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
2390
+ res.status(400).send(wrapDebugResponse(tracer, 'Please go to Settings and authorize CRM platform'));
2302
2391
  return;
2303
2392
  }
2304
2393
  const { id: userId, platform } = decodedToken;
2305
2394
  platformName = platform;
2306
2395
  const { successful, returnMessage, logIds, extraDataTracking, isRevokeUserSession } = await logCore.createMessageLog({ platform, userId, incomingData: req.body });
2307
2396
  if (isRevokeUserSession) {
2308
- res.status(401).send(tracer ? tracer.wrapResponse({ successful, returnMessage }) : { successful, returnMessage });
2397
+ res.status(401).send(wrapDebugResponse(tracer, { successful, returnMessage }));
2309
2398
  success = false;
2310
2399
  }
2311
2400
  else {
2312
2401
  if (extraDataTracking) {
2313
2402
  extraData = extraDataTracking;
2314
2403
  }
2315
- res.status(200).send(tracer ? tracer.wrapResponse({ successful, returnMessage, logIds }) : { successful, returnMessage, logIds });
2404
+ res.status(200).send(wrapDebugResponse(tracer, { successful, returnMessage, logIds }));
2316
2405
  success = true;
2317
2406
  }
2318
2407
  }
2319
2408
  else {
2320
2409
  tracer?.trace('createMessageLog:noToken', {});
2321
- res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
2410
+ res.status(400).send(wrapDebugResponse(tracer, 'Please go to Settings and authorize CRM platform'));
2322
2411
  success = false;
2323
2412
  }
2324
2413
  }
2325
2414
  catch (e) {
2326
2415
  logger.error('Create message log failed', { platform: platformName, stack: e.stack });
2327
2416
  statusCode = e.response?.status ?? 'unknown';
2328
- res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
2417
+ res.status(400).send(wrapDebugResponse(tracer, { error: getErrorResponse(e) }));
2329
2418
  tracer?.traceError('createMessageLog:error', e, { platform: platformName });
2330
2419
  success = false;
2331
2420
  }
@@ -2355,26 +2444,27 @@ function createCoreRouter() {
2355
2444
  let platformName = null;
2356
2445
  let success = false;
2357
2446
  let statusCode = 200;
2358
- const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
2447
+ const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers });
2359
2448
  try {
2360
2449
  const jwtToken = req.jwtToken || req.query.jwtToken;
2361
2450
  if (!jwtToken) {
2362
2451
  tracer?.trace('scheduleCallDown:noToken', {});
2363
- res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
2452
+ res.status(400).send(wrapDebugResponse(tracer, 'Please go to Settings and authorize CRM platform'));
2364
2453
  return;
2365
2454
  }
2366
2455
  try {
2367
- const { id } = await calldown.schedule({ jwtToken, rcAccessToken: req.query.rcAccessToken, body: req.body });
2456
+ const { id } = await calldown.schedule({ jwtToken, rcAccessToken: getRcAccessTokenFromRequest(req), body: req.body });
2368
2457
  success = true;
2369
- res.status(200).send(tracer ? tracer.wrapResponse({ successful: true, id }) : { successful: true, id });
2458
+ res.status(200).send(wrapDebugResponse(tracer, { successful: true, id }));
2370
2459
  }
2371
2460
  catch (e) {
2372
2461
  return handleDatabaseError(e, 'Error scheduling call down');
2373
2462
  }
2374
- } catch (e) {
2463
+ }
2464
+ catch (e) {
2375
2465
  logger.error('Schedule call down failed', { platform: platformName, stack: e.stack });
2376
2466
  statusCode = e.response?.status ?? 'unknown';
2377
- res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
2467
+ res.status(400).send(wrapDebugResponse(tracer, { error: getErrorResponse(e) }));
2378
2468
  tracer?.traceError('scheduleCallDown:error', e, { platform: platformName });
2379
2469
  success = false;
2380
2470
  }
@@ -2403,21 +2493,22 @@ function createCoreRouter() {
2403
2493
  let platformName = null;
2404
2494
  let success = false;
2405
2495
  let statusCode = 200;
2406
- const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
2496
+ const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers });
2407
2497
  try {
2408
2498
  const jwtToken = req.jwtToken || req.query.jwtToken;
2409
2499
  if (!jwtToken) {
2410
2500
  tracer?.trace('getCallDownList:noToken', {});
2411
- res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
2501
+ res.status(400).send(wrapDebugResponse(tracer, 'Please go to Settings and authorize CRM platform'));
2412
2502
  return;
2413
2503
  }
2414
2504
  const { items } = await calldown.list({ jwtToken, status: req.query.status });
2415
2505
  success = true;
2416
- res.status(200).send(tracer ? tracer.wrapResponse({ successful: true, items }) : { successful: true, items });
2417
- } catch (e) {
2506
+ res.status(200).send(wrapDebugResponse(tracer, { successful: true, items }));
2507
+ }
2508
+ catch (e) {
2418
2509
  logger.error('Get call down list failed', { platform: platformName, stack: e.stack });
2419
2510
  statusCode = e.response?.status ?? 'unknown';
2420
- res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
2511
+ res.status(400).send(wrapDebugResponse(tracer, { error: getErrorResponse(e) }));
2421
2512
  tracer?.traceError('getCallDownList:error', e, { platform: platformName });
2422
2513
  success = false;
2423
2514
  }
@@ -2444,28 +2535,29 @@ function createCoreRouter() {
2444
2535
  let platformName = null;
2445
2536
  let success = false;
2446
2537
  let statusCode = 200;
2447
- const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
2538
+ const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers });
2448
2539
  try {
2449
2540
  const jwtToken = req.jwtToken || req.query.jwtToken;
2450
2541
  const id = req.query.id;
2451
2542
  if (!jwtToken) {
2452
2543
  tracer?.trace('deleteCallDownItem:noToken', {});
2453
- res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
2544
+ res.status(400).send(wrapDebugResponse(tracer, 'Please go to Settings and authorize CRM platform'));
2454
2545
  return;
2455
2546
  }
2456
2547
  const rid = req.params.id || id;
2457
2548
  if (!rid) {
2458
2549
  tracer?.trace('deleteCallDownItem:missingId', {});
2459
- res.status(400).send(tracer ? tracer.wrapResponse('Missing id') : 'Missing id');
2550
+ res.status(400).send(wrapDebugResponse(tracer, 'Missing id'));
2460
2551
  return;
2461
2552
  }
2462
2553
  await calldown.remove({ jwtToken, id: rid });
2463
2554
  success = true;
2464
- res.status(200).send(tracer ? tracer.wrapResponse({ successful: true }) : { successful: true });
2465
- } catch (e) {
2555
+ res.status(200).send(wrapDebugResponse(tracer, { successful: true }));
2556
+ }
2557
+ catch (e) {
2466
2558
  logger.error('Delete call down item failed', { platform: platformName, stack: e.stack });
2467
2559
  statusCode = e.response?.status ?? 'unknown';
2468
- res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
2560
+ res.status(400).send(wrapDebugResponse(tracer, { error: getErrorResponse(e) }));
2469
2561
  tracer?.traceError('deleteCallDownItem:error', e, { platform: platformName });
2470
2562
  success = false;
2471
2563
  }
@@ -2492,27 +2584,28 @@ function createCoreRouter() {
2492
2584
  let platformName = null;
2493
2585
  let success = false;
2494
2586
  let statusCode = 200;
2495
- const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
2587
+ const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers });
2496
2588
  try {
2497
2589
  const jwtToken = req.jwtToken || req.query.jwtToken;
2498
2590
  if (!jwtToken) {
2499
2591
  tracer?.trace('markCallDownCalled:noToken', {});
2500
- res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
2592
+ res.status(400).send(wrapDebugResponse(tracer, 'Please go to Settings and authorize CRM platform'));
2501
2593
  return;
2502
2594
  }
2503
2595
  const id = req.params.id || req.body?.id;
2504
2596
  if (!id) {
2505
2597
  tracer?.trace('markCallDownCalled:missingId', {});
2506
- res.status(400).send(tracer ? tracer.wrapResponse('Missing id') : 'Missing id');
2598
+ res.status(400).send(wrapDebugResponse(tracer, 'Missing id'));
2507
2599
  return;
2508
2600
  }
2509
2601
  await calldown.update({ jwtToken, id, updateData: req.body });
2510
2602
  success = true;
2511
- res.status(200).send(tracer ? tracer.wrapResponse({ successful: true }) : { successful: true });
2512
- } catch (e) {
2603
+ res.status(200).send(wrapDebugResponse(tracer, { successful: true }));
2604
+ }
2605
+ catch (e) {
2513
2606
  logger.error('Mark call down called failed', { platform: platformName, stack: e.stack });
2514
2607
  statusCode = e.response?.status ?? 'unknown';
2515
- res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
2608
+ res.status(400).send(wrapDebugResponse(tracer, { error: getErrorResponse(e) }));
2516
2609
  tracer?.traceError('markCallDownCalled:error', e, { platform: platformName });
2517
2610
  success = false;
2518
2611
  }
@@ -2539,14 +2632,14 @@ function createCoreRouter() {
2539
2632
  let platformName = null;
2540
2633
  let success = false;
2541
2634
  let statusCode = 200;
2542
- const { hashedExtensionId, hashedAccountId, userAgent, ip, author } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
2635
+ const { hashedExtensionId, hashedAccountId, userAgent, ip, author } = getAnalyticsVariablesInReqHeaders({ headers: req.headers });
2543
2636
  try {
2544
2637
  const jwtToken = req.jwtToken || req.query.jwtToken;
2545
2638
  if (jwtToken) {
2546
2639
  const decodedToken = jwt.decodeJwt(jwtToken);
2547
2640
  if (!decodedToken) {
2548
2641
  tracer?.trace('findContactWithName:invalidJwtToken', {});
2549
- res.status(400).send(tracer ? tracer.wrapResponse('Invalid JWT token') : 'Invalid JWT token');
2642
+ res.status(400).send(wrapDebugResponse(tracer, 'Invalid JWT token'));
2550
2643
  success = false;
2551
2644
  return;
2552
2645
  }
@@ -2554,25 +2647,24 @@ function createCoreRouter() {
2554
2647
  platformName = platform;
2555
2648
  const { successful, returnMessage, contact, isRevokeUserSession } = await contactCore.findContactWithName({ platform, userId, name: req.query.name });
2556
2649
  if (isRevokeUserSession) {
2557
- res.status(401).send(tracer ? tracer.wrapResponse({ successful, returnMessage }) : { successful, returnMessage });
2650
+ res.status(401).send(wrapDebugResponse(tracer, { successful, returnMessage }));
2558
2651
  success = false;
2559
2652
  }
2560
2653
  else {
2561
- res.status(200).send(tracer ? tracer.wrapResponse({ successful, returnMessage, contact }) : { successful, returnMessage, contact });
2654
+ res.status(200).send(wrapDebugResponse(tracer, { successful, returnMessage, contact }));
2562
2655
  success = successful;
2563
2656
  }
2564
2657
  }
2565
2658
  else {
2566
2659
  tracer?.trace('contactSearchByName:noToken', {});
2567
- res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
2660
+ res.status(400).send(wrapDebugResponse(tracer, 'Please go to Settings and authorize CRM platform'));
2568
2661
  success = false;
2569
2662
  }
2570
-
2571
2663
  }
2572
2664
  catch (e) {
2573
2665
  logger.error('Contact search by name failed', { platform: platformName, stack: e.stack });
2574
2666
  statusCode = e.response?.status ?? 'unknown';
2575
- res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
2667
+ res.status(400).send(wrapDebugResponse(tracer, { error: getErrorResponse(e) }));
2576
2668
  tracer?.traceError('contactSearchByName:error', e, { platform: platformName });
2577
2669
  success = false;
2578
2670
  }
@@ -2599,7 +2691,7 @@ function createCoreRouter() {
2599
2691
  tracer?.trace('getAdminReport:start', { query: req.query });
2600
2692
  let platformName = null;
2601
2693
  let success = false;
2602
- const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
2694
+ const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers });
2603
2695
  const jwtToken = req.jwtToken || req.query.jwtToken;
2604
2696
  try {
2605
2697
  if (jwtToken) {
@@ -2607,21 +2699,21 @@ function createCoreRouter() {
2607
2699
  const user = await UserModel.findByPk(unAuthData?.id);
2608
2700
  if (!user) {
2609
2701
  tracer?.trace('getAdminReport:userNotFound', {});
2610
- res.status(400).send(tracer ? tracer.wrapResponse('User not found') : 'User not found');
2702
+ res.status(400).send(wrapDebugResponse(tracer, 'User not found'));
2611
2703
  return;
2612
2704
  }
2613
2705
  const report = await adminCore.getAdminReport({ rcAccountId: user.rcAccountId, timezone: req.query.timezone, timeFrom: req.query.timeFrom, timeTo: req.query.timeTo, groupBy: req.query.groupBy });
2614
- res.status(200).send(tracer ? tracer.wrapResponse(report) : report);
2706
+ res.status(200).send(wrapDebugResponse(tracer, report));
2615
2707
  success = true;
2616
2708
  return;
2617
2709
  }
2618
2710
  tracer?.trace('getAdminReport:invalidRequest', {});
2619
- res.status(400).send(tracer ? tracer.wrapResponse('Invalid request') : 'Invalid request');
2711
+ res.status(400).send(wrapDebugResponse(tracer, 'Invalid request'));
2620
2712
  success = false;
2621
2713
  }
2622
2714
  catch (e) {
2623
2715
  logger.error('Get admin report failed', { stack: e.stack });
2624
- res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
2716
+ res.status(400).send(wrapDebugResponse(tracer, { error: getErrorResponse(e) }));
2625
2717
  tracer?.traceError('getAdminReport:error', e, { platform: platformName });
2626
2718
  }
2627
2719
  const requestEndTime = new Date().getTime();
@@ -2645,7 +2737,7 @@ function createCoreRouter() {
2645
2737
  tracer?.trace('getUserReport:start', { query: req.query });
2646
2738
  let platformName = null;
2647
2739
  let success = false;
2648
- const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
2740
+ const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers });
2649
2741
  const jwtToken = req.jwtToken || req.query.jwtToken;
2650
2742
  try {
2651
2743
  if (jwtToken) {
@@ -2653,20 +2745,20 @@ function createCoreRouter() {
2653
2745
  const user = await UserModel.findByPk(unAuthData?.id);
2654
2746
  if (!user) {
2655
2747
  tracer?.trace('getUserReport:userNotFound', {});
2656
- res.status(400).send(tracer ? tracer.wrapResponse('User not found') : 'User not found');
2748
+ res.status(400).send(wrapDebugResponse(tracer, 'User not found'));
2657
2749
  return;
2658
2750
  }
2659
2751
  const report = await adminCore.getUserReport({ rcAccountId: user.rcAccountId, rcExtensionId: req.query.rcExtensionId, timezone: req.query.timezone, timeFrom: req.query.timeFrom, timeTo: req.query.timeTo });
2660
- res.status(200).send(tracer ? tracer.wrapResponse(report) : report);
2752
+ res.status(200).send(wrapDebugResponse(tracer, report));
2661
2753
  return;
2662
2754
  }
2663
2755
  tracer?.trace('getUserReport:invalidRequest', {});
2664
- res.status(400).send(tracer ? tracer.wrapResponse('Invalid request') : 'Invalid request');
2756
+ res.status(400).send(wrapDebugResponse(tracer, 'Invalid request'));
2665
2757
  success = false;
2666
2758
  }
2667
2759
  catch (e) {
2668
2760
  logger.error('Get user report failed', { stack: e.stack });
2669
- res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
2761
+ res.status(400).send(wrapDebugResponse(tracer, { error: getErrorResponse(e) }));
2670
2762
  tracer?.traceError('getUserReport:error', e, { platform: platformName });
2671
2763
  }
2672
2764
  const requestEndTime = new Date().getTime();
@@ -2694,15 +2786,15 @@ function createCoreRouter() {
2694
2786
  const user = await UserModel.findByPk(unAuthData?.id);
2695
2787
  if (!user) {
2696
2788
  tracer?.trace('onRingcentralOAuthCallback:userNotFound', {});
2697
- res.status(400).send(tracer ? tracer.wrapResponse('User not found') : 'User not found');
2789
+ res.status(400).send(wrapDebugResponse(tracer, 'User not found'));
2698
2790
  return;
2699
2791
  }
2700
2792
  await authCore.onRingcentralOAuthCallback({ code, rcAccountId: user.rcAccountId });
2701
- res.status(200).send(tracer ? tracer.wrapResponse({ successful: true }) : { successful: true });
2793
+ res.status(200).send(wrapDebugResponse(tracer, { successful: true }));
2702
2794
  return;
2703
2795
  }
2704
2796
  tracer?.trace('onRingcentralOAuthCallback:invalidRequest', {});
2705
- res.status(400).send(tracer ? tracer.wrapResponse('Invalid request') : 'Invalid request');
2797
+ res.status(400).send(wrapDebugResponse(tracer, 'Invalid request'));
2706
2798
  });
2707
2799
  router.get('/debug/report/url', async function (req, res) {
2708
2800
  const requestStartTime = new Date().getTime();
@@ -2710,17 +2802,17 @@ function createCoreRouter() {
2710
2802
  tracer?.trace('getErrorLogReportURL:start', { query: req.query });
2711
2803
  let platformName = null;
2712
2804
  let success = false;
2713
- const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
2805
+ const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers });
2714
2806
  const jwtToken = req.jwtToken || req.query.jwtToken;
2715
2807
  if (jwtToken) {
2716
2808
  const unAuthData = jwt.decodeJwt(jwtToken);
2717
2809
  const uploadUrl = await s3ErrorLogReport.getUploadUrl({ userId: unAuthData?.id, platform: unAuthData?.platform });
2718
- res.status(200).send(tracer ? tracer.wrapResponse({ presignedUrl: uploadUrl }) : { presignedUrl: uploadUrl });
2810
+ res.status(200).send(wrapDebugResponse(tracer, { presignedUrl: uploadUrl }));
2719
2811
  success = true;
2720
2812
  }
2721
2813
  else {
2722
2814
  tracer?.trace('getErrorLogReportURL:invalidRequest', {});
2723
- res.status(400).send(tracer ? tracer.wrapResponse('Invalid request') : 'Invalid request');
2815
+ res.status(400).send(wrapDebugResponse(tracer, 'Invalid request'));
2724
2816
  success = false;
2725
2817
  }
2726
2818
  const requestEndTime = new Date().getTime();
@@ -2738,7 +2830,6 @@ function createCoreRouter() {
2738
2830
  eventAddedVia
2739
2831
  });
2740
2832
  });
2741
-
2742
2833
  router.post('/plugin/async-callback/:taskId', async function (req, res) {
2743
2834
  const tracer = req.headers['is-debug'] === 'true' ? DebugTracer.fromRequest(req) : null;
2744
2835
  tracer?.trace('pluginAsyncCallback:start', { taskId: req.params.taskId, body: req.body });
@@ -2747,42 +2838,40 @@ function createCoreRouter() {
2747
2838
  taskId: req.params.taskId,
2748
2839
  body: req.body || {},
2749
2840
  });
2750
- res.status(result.statusCode).send(tracer ? tracer.wrapResponse(result.body) : result.body);
2841
+ res.status(result.statusCode).send(wrapDebugResponse(tracer, result.body));
2751
2842
  }
2752
2843
  catch (e) {
2753
2844
  logger.error('Plugin async callback failed', { taskId: req.params.taskId, stack: e.stack });
2754
2845
  tracer?.traceError('pluginAsyncCallback:error', e);
2755
- res.status(500).send(tracer ? tracer.wrapResponse({ successful: false, message: e.message || e }) : { successful: false, message: e.message || e });
2846
+ res.status(500).send(wrapDebugResponse(tracer, { successful: false, message: getErrorResponse(e) }));
2756
2847
  }
2757
2848
  });
2758
-
2759
2849
  router.post('/plugin/register', async function (req, res) {
2760
2850
  const requestStartTime = new Date().getTime();
2761
2851
  const tracer = req.headers['is-debug'] === 'true' ? DebugTracer.fromRequest(req) : null;
2762
2852
  tracer?.trace('pluginRegister:start', { body: req.body });
2763
2853
  let success = false;
2764
- const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
2854
+ const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers });
2765
2855
  try {
2766
2856
  const { pluginId, rcAccountId, pluginAccess, pluginName, ownerRcAccountId } = req.body || {};
2767
- const rcAccessToken = req.query?.rcAccessToken;
2857
+ const rcAccessToken = getRcAccessTokenFromRequest(req);
2768
2858
  if (!pluginId || !rcAccountId) {
2769
- res.status(400).send(tracer ? tracer.wrapResponse({ successful: false, returnMessage: 'pluginId and rcAccountId are required' }) : { successful: false, returnMessage: 'pluginId and rcAccountId are required' });
2859
+ res.status(400).send(wrapDebugResponse(tracer, { successful: false, returnMessage: 'pluginId and rcAccountId are required' }));
2770
2860
  return;
2771
2861
  }
2772
2862
  if (!rcAccessToken) {
2773
- res.status(400).send(tracer ? tracer.wrapResponse({ successful: false, returnMessage: 'Missing RingCentral access token' }) : { successful: false, returnMessage: 'Missing RingCentral access token' });
2863
+ res.status(400).send(wrapDebugResponse(tracer, { successful: false, returnMessage: 'Missing RingCentral access token' }));
2774
2864
  return;
2775
2865
  }
2776
2866
  const { isValidated, rcAccountId: validatedRcAccountId } = await adminCore.validateAdminRole({ rcAccessToken });
2777
2867
  if (!isValidated) {
2778
- res.status(403).send(tracer ? tracer.wrapResponse({ successful: false, returnMessage: 'Admin validation failed' }) : { successful: false, returnMessage: 'Admin validation failed' });
2868
+ res.status(403).send(wrapDebugResponse(tracer, { successful: false, returnMessage: 'Admin validation failed' }));
2779
2869
  return;
2780
2870
  }
2781
2871
  if (validatedRcAccountId?.toString() !== rcAccountId?.toString()) {
2782
- res.status(403).send(tracer ? tracer.wrapResponse({ successful: false, returnMessage: 'rcAccountId mismatch' }) : { successful: false, returnMessage: 'rcAccountId mismatch' });
2872
+ res.status(403).send(wrapDebugResponse(tracer, { successful: false, returnMessage: 'rcAccountId mismatch' }));
2783
2873
  return;
2784
2874
  }
2785
-
2786
2875
  await pluginCore.registerPluginAccount({
2787
2876
  pluginId,
2788
2877
  rcAccessToken,
@@ -2791,15 +2880,15 @@ function createCoreRouter() {
2791
2880
  pluginAccess,
2792
2881
  pluginName,
2793
2882
  });
2794
- res.status(200).send(tracer ? tracer.wrapResponse({ successful: true }) : { successful: true });
2883
+ res.status(200).send(wrapDebugResponse(tracer, { successful: true }));
2795
2884
  success = true;
2796
- } catch (e) {
2885
+ }
2886
+ catch (e) {
2797
2887
  logger.error('Plugin register failed', { stack: e.stack });
2798
- res.status(400).send(tracer ? tracer.wrapResponse({ successful: false, returnMessage: e.message || e }) : { successful: false, returnMessage: e.message || e });
2888
+ res.status(400).send(wrapDebugResponse(tracer, { successful: false, returnMessage: getErrorResponse(e) }));
2799
2889
  tracer?.traceError('pluginRegister:error', e);
2800
2890
  success = false;
2801
2891
  }
2802
-
2803
2892
  const requestEndTime = new Date().getTime();
2804
2893
  analytics.track({
2805
2894
  eventName: 'Plugin Register',
@@ -2814,44 +2903,43 @@ function createCoreRouter() {
2814
2903
  eventAddedVia
2815
2904
  });
2816
2905
  });
2817
-
2818
2906
  router.delete('/plugin/unregister', async function (req, res) {
2819
2907
  const requestStartTime = new Date().getTime();
2820
2908
  const tracer = req.headers['is-debug'] === 'true' ? DebugTracer.fromRequest(req) : null;
2821
2909
  tracer?.trace('pluginUnregister:start', { query: req.query });
2822
2910
  let success = false;
2823
- const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
2911
+ const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers });
2824
2912
  try {
2825
2913
  const { pluginId, rcAccountId, pluginName } = req.query || {};
2826
- const rcAccessToken = req.query?.rcAccessToken;
2914
+ const rcAccessToken = getRcAccessTokenFromRequest(req);
2827
2915
  if (!pluginId || !rcAccountId) {
2828
- res.status(400).send(tracer ? tracer.wrapResponse({ successful: false, returnMessage: 'pluginId and rcAccountId are required' }) : { successful: false, returnMessage: 'pluginId and rcAccountId are required' });
2916
+ res.status(400).send(wrapDebugResponse(tracer, { successful: false, returnMessage: 'pluginId and rcAccountId are required' }));
2829
2917
  return;
2830
2918
  }
2831
2919
  if (!rcAccessToken) {
2832
- res.status(400).send(tracer ? tracer.wrapResponse({ successful: false, returnMessage: 'Missing RingCentral access token' }) : { successful: false, returnMessage: 'Missing RingCentral access token' });
2920
+ res.status(400).send(wrapDebugResponse(tracer, { successful: false, returnMessage: 'Missing RingCentral access token' }));
2833
2921
  return;
2834
2922
  }
2835
2923
  const { isValidated, rcAccountId: validatedRcAccountId } = await adminCore.validateAdminRole({ rcAccessToken });
2836
2924
  if (!isValidated) {
2837
- res.status(403).send(tracer ? tracer.wrapResponse({ successful: false, returnMessage: 'Admin validation failed' }) : { successful: false, returnMessage: 'Admin validation failed' });
2925
+ res.status(403).send(wrapDebugResponse(tracer, { successful: false, returnMessage: 'Admin validation failed' }));
2838
2926
  return;
2839
2927
  }
2840
2928
  if (validatedRcAccountId?.toString() !== rcAccountId?.toString()) {
2841
- res.status(403).send(tracer ? tracer.wrapResponse({ successful: false, returnMessage: 'rcAccountId mismatch' }) : { successful: false, returnMessage: 'rcAccountId mismatch' });
2929
+ res.status(403).send(wrapDebugResponse(tracer, { successful: false, returnMessage: 'rcAccountId mismatch' }));
2842
2930
  return;
2843
2931
  }
2844
-
2845
2932
  await pluginCore.unregisterPluginAccount({
2846
2933
  pluginId,
2847
2934
  rcAccountId: rcAccountId?.toString(),
2848
2935
  pluginName,
2849
2936
  });
2850
- res.status(200).send(tracer ? tracer.wrapResponse({ successful: true }) : { successful: true });
2937
+ res.status(200).send(wrapDebugResponse(tracer, { successful: true }));
2851
2938
  success = true;
2852
- } catch (e) {
2939
+ }
2940
+ catch (e) {
2853
2941
  logger.error('Plugin unregister failed', { stack: e.stack });
2854
- res.status(400).send(tracer ? tracer.wrapResponse({ successful: false, returnMessage: e.message || e }) : { successful: false, returnMessage: e.message || e });
2942
+ res.status(400).send(wrapDebugResponse(tracer, { successful: false, returnMessage: getErrorResponse(e) }));
2855
2943
  tracer?.traceError('pluginUnregister:error', e);
2856
2944
  success = false;
2857
2945
  }
@@ -2869,7 +2957,6 @@ function createCoreRouter() {
2869
2957
  eventAddedVia
2870
2958
  });
2871
2959
  });
2872
-
2873
2960
  router.get('/plugin/licenseStatus', async function (req, res) {
2874
2961
  const tracer = req.headers['is-debug'] === 'true' ? DebugTracer.fromRequest(req) : null;
2875
2962
  tracer?.trace('getPluginLicenseStatus:start', { query: req.query });
@@ -2877,31 +2964,30 @@ function createCoreRouter() {
2877
2964
  const jwtToken = req.jwtToken || req.query.jwtToken;
2878
2965
  if (!jwtToken) {
2879
2966
  tracer?.trace('getPluginLicenseStatus:noToken', {});
2880
- res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
2967
+ res.status(400).send(wrapDebugResponse(tracer, 'Please go to Settings and authorize CRM platform'));
2881
2968
  return;
2882
2969
  }
2883
2970
  const unAuthData = jwt.decodeJwt(jwtToken);
2884
2971
  const user = await UserModel.findByPk(unAuthData?.id);
2885
2972
  if (!user) {
2886
2973
  tracer?.trace('getPluginLicenseStatus:userNotFound', {});
2887
- res.status(400).send(tracer ? tracer.wrapResponse('User not found') : 'User not found');
2974
+ res.status(400).send(wrapDebugResponse(tracer, 'User not found'));
2888
2975
  return;
2889
2976
  }
2890
2977
  const { rcAccountId, pluginId } = req.query;
2891
2978
  if (!rcAccountId || !pluginId) {
2892
- res.status(400).send(tracer ? tracer.wrapResponse('rcAccountId and pluginId are required') : 'rcAccountId and pluginId are required');
2979
+ res.status(400).send(wrapDebugResponse(tracer, 'rcAccountId and pluginId are required'));
2893
2980
  return;
2894
2981
  }
2895
2982
  const licenseStatus = await pluginCore.getPluginLicenseStatus({ rcAccountId, pluginId });
2896
- res.status(200).send(tracer ? tracer.wrapResponse(licenseStatus) : licenseStatus);
2983
+ res.status(200).send(wrapDebugResponse(tracer, licenseStatus));
2897
2984
  }
2898
2985
  catch (e) {
2899
2986
  logger.error('Get plugin license status failed', { stack: e.stack });
2900
- res.status(200).send(tracer ? tracer.wrapResponse({ licenseStatus: false, licenseStatusDescription: e.message || e }) : { licenseStatus: false, licenseStatusDescription: e.message || e });
2987
+ res.status(200).send(wrapDebugResponse(tracer, { licenseStatus: false, licenseStatusDescription: getErrorResponse(e) }));
2901
2988
  tracer?.traceError('getPluginLicenseStatus:error', e);
2902
2989
  }
2903
2990
  });
2904
-
2905
2991
  if (process.env.IS_PROD === 'false') {
2906
2992
  router.post('/registerMockUser', async function (req, res) {
2907
2993
  const secretKey = req.query.secretKey;
@@ -2958,7 +3044,6 @@ function createCoreRouter() {
2958
3044
  router.get('/.well-known/openai-apps-challenge', (req, res) => {
2959
3045
  res.send(process.env.CHATGPT_VERIFICATION_CODE);
2960
3046
  });
2961
-
2962
3047
  // --- METADATA ENDPOINT 1: Resource Metadata ---
2963
3048
  // Tells the client "I am protected" and "Here is who protects me"
2964
3049
  router.get('/.well-known/oauth-protected-resource', (req, res) => {
@@ -2969,7 +3054,6 @@ function createCoreRouter() {
2969
3054
  scopes_supported: ["ReadAccounts"]
2970
3055
  });
2971
3056
  });
2972
-
2973
3057
  // --- METADATA ENDPOINT 2: Auth Server Metadata ---
2974
3058
  // Usually, you can redirect to your provider's configuration.
2975
3059
  // If your provider supports OIDC discovery, this is often sufficient.
@@ -2977,54 +3061,68 @@ function createCoreRouter() {
2977
3061
  res.json({
2978
3062
  issuer: process.env.APP_SERVER,
2979
3063
  registration_endpoint: `${process.env.APP_SERVER}/oauth/register`,
2980
-
2981
- // CHANGE THIS: Don't point to RingCentral. Point to your own Shim.
3064
+ // Keep the shim so unsupported metadata params are stripped before RingCentral.
2982
3065
  authorization_endpoint: `${process.env.APP_SERVER}/oauth/authorize_shim`,
2983
-
2984
- // Keep the token endpoint pointing to RingCentral (that usually works fine)
3066
+ // MCP clients exchange the authorization code with RingCentral directly using PKCE.
2985
3067
  token_endpoint: `${process.env.RINGCENTRAL_SERVER}/restapi/oauth/token`,
2986
- token_endpoint_auth_methods_supported: ["client_secret_basic"],
2987
- response_types_supported: ["code"]
3068
+ token_endpoint_auth_methods_supported: ["none"],
3069
+ response_types_supported: ["code"],
3070
+ grant_types_supported: ["authorization_code", "refresh_token"],
3071
+ code_challenge_methods_supported: ["S256"]
2988
3072
  });
2989
3073
  });
2990
-
2991
3074
  router.get('/oauth/authorize_shim', (req, res) => {
2992
- // 1. Get the parameters ChatGPT sent us
2993
- const { response_type, client_id, redirect_uri, state, scope } = req.query;
2994
-
2995
- // 2. Rebuild the query string for RingCentral
2996
- // We explicitly LEAVE OUT 'resource' and any other junk
2997
- const params = new URLSearchParams({
2998
- response_type,
2999
- client_id, // This will be your RC Client ID (since ChatGPT got it from /register)
3000
- redirect_uri,
3001
- state,
3002
- scope
3003
- });
3004
-
3005
- // 3. Redirect the user's browser to the REAL RingCentral URL
3075
+ const mcpClientId = process.env.RINGCENTRAL_MCP_CLIENT_ID;
3076
+ if (!mcpClientId) {
3077
+ return res.status(500).send('RINGCENTRAL_MCP_CLIENT_ID is not configured');
3078
+ }
3079
+ const { response_type, client_id, redirect_uri, state, scope, code_challenge, code_challenge_method, } = req.query;
3080
+ const requestedClientId = getFirstQueryValue(client_id);
3081
+ const requestedCodeChallenge = getFirstQueryValue(code_challenge);
3082
+ const requestedCodeChallengeMethod = getFirstQueryValue(code_challenge_method);
3083
+ if (requestedClientId && requestedClientId !== mcpClientId) {
3084
+ return res.status(400).send(buildMcpOAuthError({
3085
+ error: 'mcp_oauth_client_mismatch',
3086
+ message: MCP_OAUTH_STALE_CLIENT_MESSAGE,
3087
+ }));
3088
+ }
3089
+ if (!getFirstQueryValue(response_type) || !getFirstQueryValue(redirect_uri)) {
3090
+ return res.status(400).send('Missing OAuth authorization parameters');
3091
+ }
3092
+ if (!requestedCodeChallenge || requestedCodeChallengeMethod !== 'S256') {
3093
+ return res.status(400).send('PKCE S256 code_challenge is required');
3094
+ }
3095
+ const params = new URLSearchParams();
3096
+ appendOAuthQueryParam(params, 'response_type', response_type);
3097
+ params.set('client_id', mcpClientId);
3098
+ appendOAuthQueryParam(params, 'redirect_uri', redirect_uri);
3099
+ appendOAuthQueryParam(params, 'state', state);
3100
+ appendOAuthQueryParam(params, 'scope', scope);
3101
+ appendOAuthQueryParam(params, 'code_challenge', code_challenge);
3102
+ appendOAuthQueryParam(params, 'code_challenge_method', code_challenge_method);
3006
3103
  const rcUrl = `${process.env.RINGCENTRAL_SERVER}/restapi/oauth/authorize?${params.toString()}`;
3007
-
3008
3104
  console.log("Proxying OAuth request to:", rcUrl); // Helpful for debugging
3009
3105
  res.redirect(rcUrl);
3010
3106
  });
3011
-
3012
3107
  router.post('/oauth/register', (req, res) => {
3013
- // The MCP client calls this to get credentials.
3014
- // We simply return our hardcoded RingCentral app credentials.
3108
+ const mcpClientId = process.env.RINGCENTRAL_MCP_CLIENT_ID;
3109
+ if (!mcpClientId) {
3110
+ return res.status(500).send('RINGCENTRAL_MCP_CLIENT_ID is not configured');
3111
+ }
3112
+ // Dynamic registration for MCP public clients. No client secret is issued.
3015
3113
  res.json({
3016
- client_id: process.env.RINGCENTRAL_CLIENT_ID,
3017
- client_secret: process.env.RINGCENTRAL_CLIENT_SECRET
3114
+ client_id: mcpClientId,
3115
+ token_endpoint_auth_method: 'none',
3116
+ grant_types: ['authorization_code', 'refresh_token'],
3117
+ response_types: ['code']
3018
3118
  });
3019
3119
  });
3020
-
3021
3120
  router.use('/mcp', (req, res, next) => {
3022
3121
  // Widget tool calls are unauthenticated — they come from the iframe
3023
3122
  // which has no access to the RC bearer token.
3024
3123
  if (req.path === '/widget-tool-call') {
3025
3124
  return next();
3026
3125
  }
3027
-
3028
3126
  const authHeader = req.headers.authorization;
3029
3127
  const token = authHeader?.split(' ')[1]; // Remove "Bearer "
3030
3128
  // Allow GET and OPTIONS (CORS preflight) to pass freely.
@@ -3046,16 +3144,23 @@ function createCoreRouter() {
3046
3144
  }
3047
3145
  // SCENARIO 1: No Token provided. Kick off the OAuth flow.
3048
3146
  if (!token) {
3049
- res.setHeader('WWW-Authenticate', `Bearer realm="mcp", resource_metadata="${process.env.APP_SERVER}/.well-known/oauth-protected-resource"`);
3050
- return res.status(401).send();
3147
+ res.setHeader('WWW-Authenticate', getMcpOAuthChallengeHeader({
3148
+ appServer: process.env.APP_SERVER,
3149
+ errorDescription: MCP_OAUTH_REQUIRED_MESSAGE,
3150
+ }));
3151
+ return res.status(401).json(buildMcpOAuthError({
3152
+ message: MCP_OAUTH_REQUIRED_MESSAGE,
3153
+ }));
3051
3154
  }
3052
-
3053
3155
  // SCENARIO 2: Token provided. Verify it.
3054
3156
  try {
3055
3157
  next();
3056
- } catch {
3057
- res.setHeader('WWW-Authenticate', `Bearer realm="mcp", resource_metadata="${process.env.APP_SERVER}/.well-known/oauth-protected-resource"`);
3058
- return res.status(401).send();
3158
+ }
3159
+ catch {
3160
+ res.setHeader('WWW-Authenticate', getMcpOAuthChallengeHeader({
3161
+ appServer: process.env.APP_SERVER,
3162
+ }));
3163
+ return res.status(401).json(buildMcpOAuthError());
3059
3164
  }
3060
3165
  });
3061
3166
  // Handle OPTIONS for CORS preflight
@@ -3066,21 +3171,18 @@ function createCoreRouter() {
3066
3171
  res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
3067
3172
  res.status(200).end();
3068
3173
  });
3069
-
3070
3174
  // Dedicated endpoint for all MCP traffic
3071
3175
  router.post('/mcp', async (req, res) => {
3072
3176
  // Set CORS headers
3073
3177
  res.setHeader('Access-Control-Allow-Origin', '*');
3074
3178
  res.setHeader('Content-Type', 'application/json');
3075
-
3076
3179
  await mcpHandler.handleMcpRequest(req, res);
3077
3180
  });
3078
-
3079
3181
  // Lightweight endpoint for widget tool calls (bypasses MCP protocol)
3080
3182
  router.options('/mcp/widget-tool-call', (req, res) => {
3081
3183
  res.setHeader('Access-Control-Allow-Origin', '*');
3082
3184
  res.setHeader('Access-Control-Allow-Methods', 'POST, OPTIONS');
3083
- res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
3185
+ res.setHeader('Access-Control-Allow-Headers', 'Content-Type, X-App-Connect-Widget-Token');
3084
3186
  res.status(200).end();
3085
3187
  });
3086
3188
  router.post('/mcp/widget-tool-call', async (req, res) => {
@@ -3088,10 +3190,8 @@ function createCoreRouter() {
3088
3190
  res.setHeader('Content-Type', 'application/json');
3089
3191
  await mcpHandler.handleWidgetToolCall(req, res);
3090
3192
  });
3091
-
3092
3193
  return router;
3093
3194
  }
3094
-
3095
3195
  // Create middleware for core functionality
3096
3196
  function createCoreMiddleware() {
3097
3197
  return [
@@ -3111,23 +3211,26 @@ function createCoreMiddleware() {
3111
3211
  })
3112
3212
  ];
3113
3213
  }
3114
-
3115
3214
  // Initialize core services
3116
3215
  async function initializeCore(options = {}) {
3117
- const {
3118
- skipDatabaseInit = false,
3119
- skipAnalyticsInit = false,
3120
- } = options;
3121
-
3216
+ const { skipDatabaseInit = false, skipAnalyticsInit = false, } = options;
3122
3217
  if (!skipAnalyticsInit) {
3123
3218
  analytics.init();
3124
3219
  }
3125
-
3126
3220
  if (!skipDatabaseInit) {
3127
3221
  await initDB();
3222
+ // Run the heavy callLogs primary-key migration in the BACKGROUND, off the
3223
+ // readiness critical path. It must not gate coreInit: on a large production
3224
+ // table the index rebuild takes minutes, and blocking here would stall every
3225
+ // request (including the load-balancer health check) and fail the deploy.
3226
+ // The runner is self-guarding (advisory-locked across instances, idempotent,
3227
+ // never throws) and uses online DDL on Postgres so live traffic is unaffected.
3228
+ // Gated on the same flag as the schema sync so operators have one switch.
3229
+ if (!process.env.DISABLE_SYNC_DB_TABLE) {
3230
+ runCallLogsSchemaMigration(sequelize, logger);
3231
+ }
3128
3232
  }
3129
3233
  }
3130
-
3131
3234
  // Create a complete app with core functionality
3132
3235
  function createCoreApp(options = {}) {
3133
3236
  const coreInit = initializeCore(options).catch((err) => {
@@ -3138,14 +3241,14 @@ function createCoreApp(options = {}) {
3138
3241
  throw err;
3139
3242
  });
3140
3243
  const app = express();
3141
-
3142
3244
  // Block routing until DB sync/migrations finish so traffic never hits a half-ready DB,
3143
3245
  // and ensure init failures are logged instead of only as unhandled rejections.
3144
3246
  app.use(async (req, res, next) => {
3145
3247
  try {
3146
3248
  await coreInit;
3147
3249
  next();
3148
- } catch (e) {
3250
+ }
3251
+ catch (e) {
3149
3252
  logger.error('Request rejected: core initialization failed', {
3150
3253
  message: e?.message,
3151
3254
  stack: e?.stack,
@@ -3155,22 +3258,17 @@ function createCoreApp(options = {}) {
3155
3258
  .json({ error: 'Service unavailable', detail: e?.message });
3156
3259
  }
3157
3260
  });
3158
-
3159
3261
  // Allow bigger POST body size
3160
3262
  app.use(express.json({ limit: '50mb' }));
3161
3263
  app.use(express.urlencoded({ limit: '50mb', extended: true }));
3162
-
3163
3264
  // Apply core middleware
3164
3265
  const coreMiddleware = createCoreMiddleware();
3165
3266
  coreMiddleware.forEach(middleware => app.use(middleware));
3166
-
3167
3267
  // Apply core routes
3168
3268
  const coreRouter = createCoreRouter();
3169
3269
  app.use('/', coreRouter);
3170
-
3171
3270
  return app;
3172
3271
  }
3173
-
3174
3272
  exports.createCoreRouter = createCoreRouter;
3175
3273
  exports.createCoreMiddleware = createCoreMiddleware;
3176
3274
  exports.createCoreApp = createCoreApp;