@app-connect/core 1.7.37 → 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 (286) 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} +538 -449
  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/{lib → dist/lib}/migrateCallLogsSchema.js +75 -160
  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 +8 -0
  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/ringcentral.js +0 -267
  198. package/mcp/README.md +0 -420
  199. package/mcp/tools/index.js +0 -51
  200. package/mcp/ui/App/App.tsx +0 -358
  201. package/mcp/ui/App/components/AuthInfoForm.tsx +0 -113
  202. package/mcp/ui/App/components/AuthSuccess.tsx +0 -22
  203. package/mcp/ui/App/components/ConnectorList.tsx +0 -82
  204. package/mcp/ui/App/components/DebugPanel.tsx +0 -43
  205. package/mcp/ui/App/components/OAuthConnect.tsx +0 -270
  206. package/mcp/ui/App/lib/callTool.ts +0 -130
  207. package/mcp/ui/App/lib/debugLog.ts +0 -41
  208. package/mcp/ui/App/lib/developerPortal.ts +0 -111
  209. package/mcp/ui/App/main.css +0 -6
  210. package/mcp/ui/App/root.tsx +0 -13
  211. package/mcp/ui/dist/index.html +0 -53
  212. package/mcp/ui/vite.config.ts +0 -16
  213. package/models/accountDataModel.js +0 -34
  214. package/models/adminConfigModel.js +0 -35
  215. package/models/callLogModel.js +0 -39
  216. package/models/dynamo/connectorSchema.js +0 -146
  217. package/models/llmSessionModel.js +0 -17
  218. package/models/sequelize.js +0 -17
  219. package/models/userModel.js +0 -45
  220. package/test/connector/developerPortal.test.js +0 -166
  221. package/test/connector/mock.test.js +0 -131
  222. package/test/connector/proxy/engine.test.js +0 -211
  223. package/test/connector/proxy/index.test.js +0 -525
  224. package/test/connector/proxy/sample.json +0 -162
  225. package/test/connector/registry.test.js +0 -416
  226. package/test/handlers/admin.test.js +0 -960
  227. package/test/handlers/appointment.test.js +0 -260
  228. package/test/handlers/auth.test.js +0 -1096
  229. package/test/handlers/calldown.test.js +0 -310
  230. package/test/handlers/contact.test.js +0 -1014
  231. package/test/handlers/disposition.test.js +0 -396
  232. package/test/handlers/log.test.js +0 -1847
  233. package/test/handlers/managedAuth.test.js +0 -458
  234. package/test/handlers/managedOAuth.test.js +0 -262
  235. package/test/handlers/plugin.test.js +0 -429
  236. package/test/handlers/user.test.js +0 -381
  237. package/test/index.test.js +0 -301
  238. package/test/lib/analytics.test.js +0 -146
  239. package/test/lib/authSession.test.js +0 -173
  240. package/test/lib/cacheCleanup.test.js +0 -127
  241. package/test/lib/callLogComposer.test.js +0 -1231
  242. package/test/lib/debugTracer.test.js +0 -328
  243. package/test/lib/encode.test.js +0 -59
  244. package/test/lib/errorHandler.test.js +0 -246
  245. package/test/lib/generalErrorMessage.test.js +0 -82
  246. package/test/lib/jwt.test.js +0 -176
  247. package/test/lib/logger.test.js +0 -206
  248. package/test/lib/oauth.test.js +0 -359
  249. package/test/lib/ringcentral.test.js +0 -467
  250. package/test/lib/s3ErrorLogReport.test.js +0 -187
  251. package/test/lib/sharedSMSComposer.test.js +0 -1084
  252. package/test/lib/util.test.js +0 -329
  253. package/test/mcp/mcpHandler.test.js +0 -73
  254. package/test/mcp/mcpHandlerMore.test.js +0 -384
  255. package/test/mcp/tools/appointmentTools.test.js +0 -362
  256. package/test/mcp/tools/checkAuthStatus.test.js +0 -83
  257. package/test/mcp/tools/createCallLog.test.js +0 -436
  258. package/test/mcp/tools/createContact.test.js +0 -58
  259. package/test/mcp/tools/createMessageLog.test.js +0 -595
  260. package/test/mcp/tools/doAuth.test.js +0 -113
  261. package/test/mcp/tools/findContactByName.test.js +0 -275
  262. package/test/mcp/tools/findContactByPhone.test.js +0 -296
  263. package/test/mcp/tools/getCallLog.test.js +0 -298
  264. package/test/mcp/tools/getGoogleFilePicker.test.js +0 -281
  265. package/test/mcp/tools/getPublicConnectors.test.js +0 -107
  266. package/test/mcp/tools/getSessionInfo.test.js +0 -127
  267. package/test/mcp/tools/logout.test.js +0 -233
  268. package/test/mcp/tools/rcGetCallLogs.test.js +0 -56
  269. package/test/mcp/tools/updateCallLog.test.js +0 -360
  270. package/test/models/accountDataModel.test.js +0 -98
  271. package/test/models/callDownListModel.test.js +0 -125
  272. package/test/models/dynamo/connectorSchema.test.js +0 -189
  273. package/test/models/dynamo/lockSchema.test.js +0 -37
  274. package/test/models/dynamo/noteCacheSchema.test.js +0 -45
  275. package/test/models/llmSessionModel.test.js +0 -91
  276. package/test/models/models.test.js +0 -660
  277. package/test/routes/calldownRoutes.test.js +0 -224
  278. package/test/routes/coreRouterBroadRoutes.test.js +0 -855
  279. package/test/routes/dispositionRoutes.test.js +0 -192
  280. package/test/routes/managedAuthRoutes.test.js +0 -386
  281. package/test/routes/pluginRoutes.test.js +0 -262
  282. package/test/setup.js +0 -178
  283. /package/{mcp → dist/mcp}/ui/index.html +0 -0
  284. /package/{mcp → dist/mcp}/ui/package-lock.json +0 -0
  285. /package/{mcp → dist/mcp}/ui/package.json +0 -0
  286. /package/{mcp → dist/mcp}/ui/tsconfig.json +0 -0
@@ -1,15 +1,32 @@
1
- const oauth = require('../lib/oauth');
2
- const { UserModel } = require('../models/userModel');
3
- const connectorRegistry = require('../connector/registry');
4
- const Op = require('sequelize').Op;
5
- const { RingCentral } = require('../lib/ringcentral');
6
- const adminCore = require('./admin');
7
- const { Connector } = require('../models/dynamo/connectorSchema');
1
+ "use strict";
2
+ // @ts-check
3
+ /** @typedef {import('../types').ApiKeyLoginParams} ApiKeyLoginParams */
4
+ /** @typedef {import('../types').AuthHandlerResult} AuthHandlerResult */
5
+ /** @typedef {import('../types').AuthValidationParams} AuthValidationParams */
6
+ /** @typedef {import('../types').AuthValidationResult} AuthValidationResult */
7
+ /** @typedef {import('../types').LicenseStatusParams} LicenseStatusParams */
8
+ /** @typedef {import('../types').OAuthCallbackParams} OAuthCallbackParams */
9
+ /** @typedef {import('../types').RingcentralOAuthCallbackParams} RingcentralOAuthCallbackParams */
10
+ /** @typedef {import('../types').SaveUserInfoParams} SaveUserInfoParams */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ const oauth = /** @type {any} */ (require('../lib/oauth'));
13
+ const { UserModel: UserModelImport } = require('../models/userModel');
14
+ const UserModel = /** @type {any} */ (UserModelImport);
15
+ const connectorRegistry = /** @type {any} */ (require('../connector/registry'));
16
+ const Op = /** @type {any} */ (require('sequelize').Op);
17
+ const { RingCentral: RingCentralImport } = require('../lib/ringcentral');
18
+ const RingCentral = /** @type {any} */ (RingCentralImport);
19
+ const adminCore = /** @type {any} */ (require('./admin'));
20
+ const { Connector: ConnectorImport } = require('../models/dynamo/connectorSchema');
21
+ const Connector = /** @type {any} */ (ConnectorImport);
8
22
  const { handleDatabaseError } = require('../lib/errorHandler');
9
- const managedAuthCore = require('./managedAuth');
10
- const managedOAuthCore = require('./managedOAuth');
23
+ const managedAuthCore = /** @type {any} */ (require('./managedAuth'));
24
+ const managedOAuthCore = /** @type {any} */ (require('./managedOAuth'));
11
25
  const { getHashValue } = require('../lib/util');
12
-
26
+ /**
27
+ * @param {OAuthCallbackParams} params
28
+ * @returns {Promise<AuthHandlerResult>}
29
+ */
13
30
  async function onOAuthCallback({ platform, hostname, tokenUrl, query, hashedRcExtensionId, isFromMCP = false }) {
14
31
  const callbackUri = query.callbackUri;
15
32
  const apiUrl = query.apiUrl;
@@ -43,9 +60,8 @@ async function onOAuthCallback({ platform, hostname, tokenUrl, query, hashedRcEx
43
60
  messageType: 'danger',
44
61
  message: oauthInfo.failMessage
45
62
  }
46
- }
63
+ };
47
64
  }
48
-
49
65
  // Some platforms require different oauth queries, this won't affect normal OAuth process unless CRM module implements getOverridingOAuthOption() method
50
66
  let overridingOAuthOption = null;
51
67
  if (platformModule.getOverridingOAuthOption != null) {
@@ -56,7 +72,6 @@ async function onOAuthCallback({ platform, hostname, tokenUrl, query, hashedRcEx
56
72
  const { accessToken, refreshToken, expires, data } = await oauthApp.code.getToken(callbackUri, overridingOAuthOption);
57
73
  const authHeader = `Bearer ${accessToken}`;
58
74
  const { successful, platformUserInfo, returnMessage } = await platformModule.getUserInfo({ authHeader, tokenUrl: resolvedTokenUrl, apiUrl, hostname: resolvedHostname, platform, username, callbackUri, query, proxyId, proxyConfig, userEmail, data });
59
-
60
75
  if (successful) {
61
76
  let userInfo = null;
62
77
  try {
@@ -96,10 +111,13 @@ async function onOAuthCallback({ platform, hostname, tokenUrl, query, hashedRcEx
96
111
  return {
97
112
  userInfo: null,
98
113
  returnMessage
99
- }
114
+ };
100
115
  }
101
116
  }
102
-
117
+ /**
118
+ * @param {ApiKeyLoginParams} params
119
+ * @returns {Promise<AuthHandlerResult>}
120
+ */
103
121
  async function onApiKeyLogin({ platform, hostname, apiKey, proxyId, rcAccountId, rcExtensionId, connectorId, isPrivate, hashedRcExtensionId, additionalInfo }) {
104
122
  const platformModule = connectorRegistry.getConnector(platform);
105
123
  let resolvedAdditionalInfo = {
@@ -109,6 +127,7 @@ async function onApiKeyLogin({ platform, hostname, apiKey, proxyId, rcAccountId,
109
127
  resolvedAdditionalInfo.apiKey = apiKey;
110
128
  }
111
129
  let resolvedApiKey = apiKey;
130
+ /** @type {Array<Record<string, unknown>>} */
112
131
  let managedFieldDefinitions = [];
113
132
  if (rcAccountId) {
114
133
  managedFieldDefinitions = await managedAuthCore.getManagedFieldDefinitions({ rcAccountId, platform, connectorId, isPrivate });
@@ -179,9 +198,12 @@ async function onApiKeyLogin({ platform, hostname, apiKey, proxyId, rcAccountId,
179
198
  return {
180
199
  userInfo: null,
181
200
  returnMessage
182
- }
201
+ };
183
202
  }
184
-
203
+ /**
204
+ * @param {SaveUserInfoParams} params
205
+ * @returns {Promise<unknown>}
206
+ */
185
207
  async function saveUserInfo({ platformUserInfo, platform, hostname, accessToken, refreshToken, tokenExpiry, rcAccountId, hashedRcExtensionId, proxyId }) {
186
208
  const id = platformUserInfo.id;
187
209
  const name = platformUserInfo.name;
@@ -192,23 +214,21 @@ async function saveUserInfo({ platformUserInfo, platform, hostname, accessToken,
192
214
  platformAdditionalInfo.proxyId = proxyId;
193
215
  if (existingUser) {
194
216
  try {
195
- await existingUser.update(
196
- {
197
- platform,
198
- hostname,
199
- timezoneName,
200
- timezoneOffset,
201
- accessToken,
202
- refreshToken,
203
- tokenExpiry,
204
- rcAccountId,
205
- hashedRcExtensionId,
206
- platformAdditionalInfo: {
207
- ...existingUser.platformAdditionalInfo, // keep existing platformAdditionalInfo
208
- ...platformAdditionalInfo,
209
- }
217
+ await existingUser.update({
218
+ platform,
219
+ hostname,
220
+ timezoneName,
221
+ timezoneOffset,
222
+ accessToken,
223
+ refreshToken,
224
+ tokenExpiry,
225
+ rcAccountId,
226
+ hashedRcExtensionId,
227
+ platformAdditionalInfo: {
228
+ ...existingUser.platformAdditionalInfo, // keep existing platformAdditionalInfo
229
+ ...platformAdditionalInfo,
210
230
  }
211
- );
231
+ });
212
232
  }
213
233
  catch (error) {
214
234
  return handleDatabaseError(error, 'Error saving user info');
@@ -240,7 +260,10 @@ async function saveUserInfo({ platformUserInfo, platform, hostname, accessToken,
240
260
  name
241
261
  };
242
262
  }
243
-
263
+ /**
264
+ * @param {LicenseStatusParams} params
265
+ * @returns {Promise<unknown>}
266
+ */
244
267
  async function getLicenseStatus({ userId, platform }) {
245
268
  const user = await UserModel.findByPk(userId);
246
269
  if (!user) {
@@ -248,14 +271,17 @@ async function getLicenseStatus({ userId, platform }) {
248
271
  isLicenseValid: false,
249
272
  licenseStatus: 'Invalid (User not found)',
250
273
  licenseStatusDescription: ''
251
- }
274
+ };
252
275
  }
253
276
  const platformModule = connectorRegistry.getConnector(platform);
254
277
  const licenseStatus = await platformModule.getLicenseStatus({ userId, platform, user });
255
278
  return licenseStatus;
256
279
  }
257
-
258
280
  // Just for oauth ATM
281
+ /**
282
+ * @param {AuthValidationParams} params
283
+ * @returns {Promise<AuthValidationResult>}
284
+ */
259
285
  async function authValidation({ platform, userId }) {
260
286
  let existingUser = await UserModel.findOne({
261
287
  where: {
@@ -283,18 +309,21 @@ async function authValidation({ platform, userId }) {
283
309
  returnMessage,
284
310
  status,
285
311
  failReason: successful ? '' : 'CRM. API failed'
286
- }
312
+ };
287
313
  }
288
314
  else {
289
315
  return {
290
316
  successful: false,
291
317
  status: 404,
292
318
  failReason: 'App Connect. User not found in database'
293
- }
319
+ };
294
320
  }
295
321
  }
296
-
297
322
  // Ringcentral
323
+ /**
324
+ * @param {RingcentralOAuthCallbackParams} params
325
+ * @returns {Promise<void>}
326
+ */
298
327
  async function onRingcentralOAuthCallback({ code, rcAccountId }) {
299
328
  if (!process.env.RINGCENTRAL_SERVER || !process.env.RINGCENTRAL_CLIENT_ID || !process.env.RINGCENTRAL_CLIENT_SECRET) {
300
329
  return;
@@ -314,7 +343,6 @@ async function onRingcentralOAuthCallback({ code, rcAccountId }) {
314
343
  adminTokenExpiry: expire_time
315
344
  });
316
345
  }
317
-
318
346
  exports.onOAuthCallback = onOAuthCallback;
319
347
  exports.onApiKeyLogin = onApiKeyLogin;
320
348
  exports.authValidation = authValidation;
@@ -0,0 +1,10 @@
1
+ /** @typedef {import('../types').CallDownJwtData} CallDownJwtData */
2
+ /** @typedef {import('../types').CallDownListParams} CallDownListParams */
3
+ /** @typedef {import('../types').CallDownListResult} CallDownListResult */
4
+ /** @typedef {import('../types').CallDownMarkCalledParams} CallDownMarkCalledParams */
5
+ /** @typedef {import('../types').CallDownOperationResult} CallDownOperationResult */
6
+ /** @typedef {import('../types').CallDownRecordParams} CallDownRecordParams */
7
+ /** @typedef {import('../types').CallDownScheduleParams} CallDownScheduleParams */
8
+ /** @typedef {import('../types').CallDownScheduleResult} CallDownScheduleResult */
9
+ /** @typedef {import('../types').CallDownUpdateParams} CallDownUpdateParams */
10
+ export {};
@@ -0,0 +1,134 @@
1
+ "use strict";
2
+ // @ts-check
3
+ /** @typedef {import('../types').CallDownJwtData} CallDownJwtData */
4
+ /** @typedef {import('../types').CallDownListParams} CallDownListParams */
5
+ /** @typedef {import('../types').CallDownListResult} CallDownListResult */
6
+ /** @typedef {import('../types').CallDownMarkCalledParams} CallDownMarkCalledParams */
7
+ /** @typedef {import('../types').CallDownOperationResult} CallDownOperationResult */
8
+ /** @typedef {import('../types').CallDownRecordParams} CallDownRecordParams */
9
+ /** @typedef {import('../types').CallDownScheduleParams} CallDownScheduleParams */
10
+ /** @typedef {import('../types').CallDownScheduleResult} CallDownScheduleResult */
11
+ /** @typedef {import('../types').CallDownUpdateParams} CallDownUpdateParams */
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ const { UserModel: UserModelImport } = require('../models/userModel');
14
+ const UserModel = /** @type {any} */ (UserModelImport);
15
+ const { CallDownListModel: CallDownListModelImport } = require('../models/callDownListModel');
16
+ const CallDownListModel = /** @type {any} */ (CallDownListModelImport);
17
+ const { Op: OpImport } = require('sequelize');
18
+ const Op = /** @type {any} */ (OpImport);
19
+ const jwt = /** @type {any} */ (require('../lib/jwt'));
20
+ const { handleDatabaseError } = require('../lib/errorHandler');
21
+ /**
22
+ * @param {CallDownScheduleParams} params
23
+ * @returns {Promise<CallDownScheduleResult>}
24
+ */
25
+ async function schedule({ jwtToken, body }) {
26
+ const unAuthData = /** @type {CallDownJwtData | null} */ (jwt.decodeJwt(jwtToken));
27
+ if (!unAuthData?.id)
28
+ throw new Error('Unauthorized');
29
+ const user = await UserModel.findByPk(unAuthData.id);
30
+ if (!user)
31
+ throw new Error('User not found');
32
+ const crypto = require('crypto');
33
+ const recordId = crypto.randomBytes(16).toString('hex');
34
+ const payload = {
35
+ id: recordId,
36
+ userId: user.id,
37
+ contactId: body.contactId?.toString?.() ?? body.contactId,
38
+ contactType: body.contactType ?? 'contact',
39
+ contactName: body.contactName ?? '',
40
+ phoneNumber: body.phoneNumber ?? '',
41
+ status: 'scheduled',
42
+ scheduledAt: body.scheduledAt ? new Date(body.scheduledAt) : null,
43
+ lastCallAt: null
44
+ };
45
+ await CallDownListModel.create(payload);
46
+ return { id: recordId };
47
+ }
48
+ /**
49
+ * @param {CallDownListParams} params
50
+ * @returns {Promise<CallDownListResult>}
51
+ */
52
+ async function list({ jwtToken, status }) {
53
+ const unAuthData = /** @type {CallDownJwtData | null} */ (jwt.decodeJwt(jwtToken));
54
+ if (!unAuthData?.id)
55
+ throw new Error('Unauthorized');
56
+ const statusParam = (status || 'All').toString().toLowerCase();
57
+ /** @type {{ userId: string | number, status?: unknown }} */
58
+ const whereClause = { userId: unAuthData.id };
59
+ if (statusParam === 'called')
60
+ whereClause.status = 'called';
61
+ else if (['not called', 'not_called', 'notcalled'].includes(statusParam))
62
+ whereClause.status = { [Op.ne]: 'called' };
63
+ const items = await CallDownListModel.findAll({ where: whereClause, order: [["scheduledAt", "ASC"]] });
64
+ return { items };
65
+ }
66
+ /**
67
+ * @param {CallDownRecordParams} params
68
+ * @returns {Promise<CallDownOperationResult>}
69
+ */
70
+ async function remove({ jwtToken, id }) {
71
+ const unAuthData = /** @type {CallDownJwtData | null} */ (jwt.decodeJwt(jwtToken));
72
+ if (!unAuthData?.id)
73
+ throw new Error('Unauthorized');
74
+ const deleted = await CallDownListModel.destroy({ where: { id, userId: unAuthData.id } });
75
+ if (!deleted)
76
+ throw new Error('Not found');
77
+ return { successful: true };
78
+ }
79
+ /**
80
+ * @param {CallDownMarkCalledParams} params
81
+ * @returns {Promise<CallDownOperationResult>}
82
+ */
83
+ async function markCalled({ jwtToken, id, lastCallAt }) {
84
+ const unAuthData = /** @type {CallDownJwtData | null} */ (jwt.decodeJwt(jwtToken));
85
+ if (!unAuthData?.id)
86
+ throw new Error('Unauthorized');
87
+ const when = lastCallAt ? new Date(/** @type {any} */ (lastCallAt)) : new Date();
88
+ try {
89
+ const [affected] = await CallDownListModel.update({ status: 'called', lastCallAt: when }, { where: { id, userId: unAuthData.id } });
90
+ if (!affected)
91
+ throw new Error('Not found');
92
+ return { successful: true };
93
+ }
94
+ catch (error) {
95
+ return handleDatabaseError(error, 'Error marking call as called', { id, userId: unAuthData.id });
96
+ }
97
+ }
98
+ /**
99
+ * @param {CallDownUpdateParams} params
100
+ * @returns {Promise<CallDownOperationResult>}
101
+ */
102
+ async function update({ jwtToken, id, updateData }) {
103
+ const unAuthData = /** @type {CallDownJwtData | null} */ (jwt.decodeJwt(jwtToken));
104
+ if (!unAuthData?.id)
105
+ throw new Error('Unauthorized');
106
+ // Prepare the update object with only valid fields
107
+ const allowedFields = ['contactId', 'contactType', 'contactName', 'phoneNumber', 'status', 'scheduledAt', 'lastCallAt', 'note'];
108
+ /** @type {Record<string, unknown>} */
109
+ const updateObject = {};
110
+ // Filter and prepare update data
111
+ Object.keys(updateData).forEach(key => {
112
+ if (allowedFields.includes(key)) {
113
+ let value = updateData[key];
114
+ // Handle date fields
115
+ if ((key === 'scheduledAt' || key === 'lastCallAt') && value) {
116
+ value = new Date(/** @type {any} */ (value));
117
+ }
118
+ updateObject[key] = value;
119
+ }
120
+ });
121
+ // If no valid fields to update, throw error
122
+ if (Object.keys(updateObject).length === 0) {
123
+ throw new Error('No valid fields to update');
124
+ }
125
+ const [affected] = await CallDownListModel.update(updateObject, { where: { id, userId: unAuthData.id } });
126
+ if (!affected)
127
+ throw new Error('Not found');
128
+ return { successful: true };
129
+ }
130
+ exports.schedule = schedule;
131
+ exports.list = list;
132
+ exports.remove = remove;
133
+ exports.markCalled = markCalled;
134
+ exports.update = update;
@@ -0,0 +1 @@
1
+ export {};
@@ -1,10 +1,30 @@
1
- const oauth = require('../lib/oauth');
2
- const { UserModel } = require('../models/userModel');
3
- const connectorRegistry = require('../connector/registry');
4
- const { Connector } = require('../models/dynamo/connectorSchema');
5
- const { handleApiError } = require('../lib/errorHandler');
6
- const { AccountDataModel } = require('../models/accountDataModel');
7
-
1
+ "use strict";
2
+ // @ts-check
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ /** @typedef {import('../types').AccountContactDataRecord} AccountContactDataRecord */
5
+ /** @typedef {import('../types').ContactConnectorImplementation} ContactConnectorImplementation */
6
+ /** @typedef {import('../types').ContactHandlerResult} ContactHandlerResult */
7
+ /** @typedef {import('../types').ContactHandlerUser} ContactHandlerUser */
8
+ /** @typedef {import('../types').CreateContactParams} CreateContactParams */
9
+ /** @typedef {import('../types').FindContactParams} FindContactParams */
10
+ /** @typedef {import('../types').FindContactWithNameParams} FindContactWithNameParams */
11
+ /** @typedef {import('../types').OAuthInfo} OAuthInfo */
12
+ /** @typedef {import('../types').ProviderError} ProviderError */
13
+ /** @typedef {import('../types').ProxyConfig} ProxyConfig */
14
+ const oauth = /** @type {{ getOAuthApp(info: OAuthInfo): any, checkAndRefreshAccessToken(oauthApp: any, user: ContactHandlerUser): Promise<ContactHandlerUser | null> }} */ (require('../lib/oauth'));
15
+ const { UserModel: RawUserModel } = require('../models/userModel');
16
+ const UserModel = /** @type {{ findOne(options: Record<string, unknown>): Promise<ContactHandlerUser | null> }} */ (RawUserModel);
17
+ const connectorRegistry = /** @type {{ getConnector(platform: string): ContactConnectorImplementation }} */ ( /** @type {unknown} */(require('../connector/registry')));
18
+ const { Connector: RawConnector } = require('../models/dynamo/connectorSchema');
19
+ const Connector = /** @type {{ getProxyConfig(proxyId: string): Promise<ProxyConfig | null> }} */ ( /** @type {unknown} */(RawConnector));
20
+ const { handleApiError: rawHandleApiError } = require('../lib/errorHandler');
21
+ const handleApiError = /** @type {(error: unknown, platform: string, operation: string, context?: Record<string, unknown>) => ContactHandlerResult} */ (rawHandleApiError);
22
+ const { AccountDataModel: RawAccountDataModel } = require('../models/accountDataModel');
23
+ const AccountDataModel = /** @type {{ findOne(options: Record<string, unknown>): Promise<AccountContactDataRecord | null>, create(values: Record<string, unknown>): Promise<AccountContactDataRecord> }} */ (RawAccountDataModel);
24
+ /**
25
+ * @param {FindContactParams} params
26
+ * @returns {Promise<ContactHandlerResult>}
27
+ */
8
28
  async function findContact({ platform, userId, phoneNumber, overridingFormat, isExtension, tracer, isForceRefreshAccountData = false }) {
9
29
  tracer?.trace('handler.findContact:entered', { platform, userId, phoneNumber });
10
30
  try {
@@ -15,7 +35,6 @@ async function findContact({ platform, userId, phoneNumber, overridingFormat, is
15
35
  }
16
36
  });
17
37
  tracer?.trace('handler.findContact:userFound', { user });
18
-
19
38
  if (!user || !user.accessToken) {
20
39
  tracer?.trace('handler.findContact:noUser', { userId });
21
40
  return {
@@ -34,7 +53,7 @@ async function findContact({ platform, userId, phoneNumber, overridingFormat, is
34
53
  platformName: platform,
35
54
  dataKey: `contact-${phoneNumber}`
36
55
  }
37
- })
56
+ });
38
57
  if (!isForceRefreshAccountData) {
39
58
  if (existingMatchedContactInfo) {
40
59
  console.log('found existing matched contact info in account data');
@@ -50,7 +69,6 @@ async function findContact({ platform, userId, phoneNumber, overridingFormat, is
50
69
  const platformModule = connectorRegistry.getConnector(platform);
51
70
  const authType = await platformModule.getAuthType({ proxyId, proxyConfig });
52
71
  tracer?.trace('handler.findContact:authType', { authType });
53
-
54
72
  let authHeader = '';
55
73
  switch (authType) {
56
74
  case 'oauth':
@@ -65,7 +83,7 @@ async function findContact({ platform, userId, phoneNumber, overridingFormat, is
65
83
  ttl: 5000
66
84
  },
67
85
  isRevokeUserSession: true
68
- }
86
+ };
69
87
  }
70
88
  authHeader = `Bearer ${user.accessToken}`;
71
89
  tracer?.trace('handler.findContact:oauthAuth', { authHeader });
@@ -76,10 +94,8 @@ async function findContact({ platform, userId, phoneNumber, overridingFormat, is
76
94
  tracer?.trace('handler.findContact:apiKeyAuth', {});
77
95
  break;
78
96
  }
79
-
80
97
  const { successful, matchedContactInfo, returnMessage, extraDataTracking } = await platformModule.findContact({ user, authHeader, phoneNumber, overridingFormat, isExtension, proxyConfig, tracer, isForceRefreshAccountData });
81
98
  tracer?.trace('handler.findContact:platformFindResult', { successful, matchedContactInfo });
82
-
83
99
  const matchedNonNewContacts = matchedContactInfo?.filter(c => !c.isNewContact) ?? [];
84
100
  if (matchedContactInfo != null && matchedNonNewContacts.length > 0) {
85
101
  tracer?.trace('handler.findContact:contactsFound', { count: matchedContactInfo.length });
@@ -115,37 +131,40 @@ async function findContact({ platform, userId, phoneNumber, overridingFormat, is
115
131
  returnMessage,
116
132
  extraDataTracking,
117
133
  contact: matchedContactInfo,
118
- }
134
+ };
119
135
  }
120
136
  return {
121
137
  successful,
122
- returnMessage:
123
- {
138
+ returnMessage: {
124
139
  message: `Contact not found`,
125
140
  messageType: 'warning',
126
141
  details: [{
127
- title: 'Details',
128
- items: [
129
- {
130
- id: '1',
131
- type: 'text',
132
- text: `A contact with the phone number ${phoneNumber} could not be found in your ${platform} account.`
133
- }
134
- ]
135
- }],
142
+ title: 'Details',
143
+ items: [
144
+ {
145
+ id: '1',
146
+ type: 'text',
147
+ text: `A contact with the phone number ${phoneNumber} could not be found in your ${platform} account.`
148
+ }
149
+ ]
150
+ }],
136
151
  ttl: 5000
137
152
  },
138
153
  contact: matchedContactInfo,
139
154
  extraDataTracking
140
155
  };
141
156
  }
142
- } catch (e) {
143
- tracer?.traceError('handler.findContact:error', e, { platform, statusCode: e.response?.status });
144
- return handleApiError(e, platform, 'findContact', { userId, overridingFormat, isExtension });
145
-
157
+ }
158
+ catch (e) {
159
+ const error = /** @type {ProviderError} */ (e);
160
+ tracer?.traceError('handler.findContact:error', error, { platform, statusCode: error.response?.status });
161
+ return handleApiError(error, platform, 'findContact', { userId, overridingFormat, isExtension });
146
162
  }
147
163
  }
148
-
164
+ /**
165
+ * @param {CreateContactParams} params
166
+ * @returns {Promise<ContactHandlerResult>}
167
+ */
149
168
  async function createContact({ platform, userId, phoneNumber, newContactName, newContactType, additionalSubmission }) {
150
169
  try {
151
170
  let user = await UserModel.findOne({
@@ -178,7 +197,7 @@ async function createContact({ platform, userId, phoneNumber, newContactName, ne
178
197
  ttl: 5000
179
198
  },
180
199
  isRevokeUserSession: true
181
- }
200
+ };
182
201
  }
183
202
  authHeader = `Bearer ${user.accessToken}`;
184
203
  break;
@@ -194,11 +213,15 @@ async function createContact({ platform, userId, phoneNumber, newContactName, ne
194
213
  else {
195
214
  return { successful: false, returnMessage };
196
215
  }
197
- } catch (e) {
216
+ }
217
+ catch (e) {
198
218
  return handleApiError(e, platform, 'createContact', { userId, phoneNumber, newContactName, newContactType, additionalSubmission });
199
219
  }
200
220
  }
201
-
221
+ /**
222
+ * @param {FindContactWithNameParams} params
223
+ * @returns {Promise<ContactHandlerResult>}
224
+ */
202
225
  async function findContactWithName({ platform, userId, name }) {
203
226
  try {
204
227
  let user = await UserModel.findOne({
@@ -238,7 +261,7 @@ async function findContactWithName({ platform, userId, name }) {
238
261
  ttl: 5000
239
262
  },
240
263
  isRevokeUserSession: true
241
- }
264
+ };
242
265
  }
243
266
  authHeader = `Bearer ${user.accessToken}`;
244
267
  break;
@@ -257,12 +280,11 @@ async function findContactWithName({ platform, userId, name }) {
257
280
  successful,
258
281
  returnMessage,
259
282
  contact: matchedContactInfo,
260
- }
283
+ };
261
284
  }
262
285
  return {
263
286
  successful,
264
- returnMessage:
265
- {
287
+ returnMessage: {
266
288
  message: `No contact found with name ${name} `,
267
289
  messageType: 'warning',
268
290
  ttl: 5000
@@ -270,11 +292,11 @@ async function findContactWithName({ platform, userId, name }) {
270
292
  contact: matchedContactInfo
271
293
  };
272
294
  }
273
- } catch (e) {
295
+ }
296
+ catch (e) {
274
297
  return handleApiError(e, platform, 'findContactWithName', { userId, name });
275
298
  }
276
299
  }
277
-
278
300
  exports.findContact = findContact;
279
301
  exports.createContact = createContact;
280
302
  exports.findContactWithName = findContactWithName;
@@ -0,0 +1 @@
1
+ export {};
@@ -1,11 +1,22 @@
1
- const { CallLogModel } = require('../models/callLogModel');
2
- const { UserModel } = require('../models/userModel');
3
- const oauth = require('../lib/oauth');
4
- const connectorRegistry = require('../connector/registry');
5
- const { Connector } = require('../models/dynamo/connectorSchema');
1
+ "use strict";
2
+ // @ts-check
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const { CallLogModel: CallLogModelImport } = require('../models/callLogModel');
5
+ const { UserModel: UserModelImport } = require('../models/userModel');
6
+ const oauth = /** @type {any} */ (require('../lib/oauth'));
7
+ const connectorRegistry = /** @type {any} */ (require('../connector/registry'));
8
+ const { Connector: ConnectorImport } = require('../models/dynamo/connectorSchema');
6
9
  const { handleApiError } = require('../lib/errorHandler');
7
10
  const { buildCallLogSessionWhere } = require('../lib/callLogLookup');
8
-
11
+ const CallLogModel = /** @type {any} */ (CallLogModelImport);
12
+ const UserModel = /** @type {any} */ (UserModelImport);
13
+ const Connector = /** @type {any} */ (ConnectorImport);
14
+ /** @typedef {import('../types').UpsertCallDispositionParams} UpsertCallDispositionParams */
15
+ /** @typedef {import('../types').UpsertCallDispositionResult} UpsertCallDispositionResult */
16
+ /**
17
+ * @param {UpsertCallDispositionParams} params
18
+ * @returns {Promise<UpsertCallDispositionResult>}
19
+ */
9
20
  async function upsertCallDisposition({ platform, userId, sessionId, extensionNumber, hashedExtensionId, dispositions }) {
10
21
  try {
11
22
  const existingCallLog = await CallLogModel.findOne({
@@ -23,7 +34,7 @@ async function upsertCallDisposition({ platform, userId, sessionId, extensionNum
23
34
  messageType: 'warning',
24
35
  ttl: 3000
25
36
  }
26
- }
37
+ };
27
38
  }
28
39
  let user = await UserModel.findByPk(userId);
29
40
  if (!user) {
@@ -34,7 +45,7 @@ async function upsertCallDisposition({ platform, userId, sessionId, extensionNum
34
45
  messageType: 'warning',
35
46
  ttl: 3000
36
47
  }
37
- }
48
+ };
38
49
  }
39
50
  const proxyId = user.platformAdditionalInfo?.proxyId;
40
51
  let proxyConfig = null;
@@ -57,7 +68,7 @@ async function upsertCallDisposition({ platform, userId, sessionId, extensionNum
57
68
  ttl: 5000
58
69
  },
59
70
  isRevokeUserSession: true
60
- }
71
+ };
61
72
  }
62
73
  authHeader = `Bearer ${user.accessToken}`;
63
74
  break;
@@ -79,5 +90,4 @@ async function upsertCallDisposition({ platform, userId, sessionId, extensionNum
79
90
  return handleApiError(e, platform, 'upsertCallDisposition', { userId, sessionId, extensionNumber, hashedExtensionId, dispositions });
80
91
  }
81
92
  }
82
-
83
93
  exports.upsertCallDisposition = upsertCallDisposition;
@@ -0,0 +1 @@
1
+ export {};