@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,51 +0,0 @@
1
- /**
2
- * MCP Tools Index
3
- *
4
- * Two separate registries:
5
- * - tools: Registered in the MCP server — visible to and callable by the AI model
6
- * - widgetTools: Only accessible via POST /mcp/widget-tool-call — hidden from the AI model
7
- */
8
-
9
- const getHelp = require('./getHelp');
10
- const getPublicConnectors = require('./getPublicConnectors');
11
- const getSessionInfo = require('./getSessionInfo');
12
- const doAuth = require('./doAuth');
13
- const checkAuthStatus = require('./checkAuthStatus');
14
- const logout = require('./logout');
15
- const findContact = require('./findContactByPhone');
16
- const findContactWithName = require('./findContactByName');
17
- const createCallLog = require('./createCallLog');
18
- const rcGetCallLogs = require('./rcGetCallLogs');
19
- // const getGoogleFilePicker = require('./getGoogleFilePicker');
20
- const createContact = require('./createContact');
21
- const createAppointment = require('./createAppointment');
22
- const updateAppointment = require('./updateAppointment');
23
- const confirmAppointment = require('./confirmAppointment');
24
- const cancelAppointment = require('./cancelAppointment');
25
- const listAppointments = require('./listAppointments');
26
-
27
- // AI-visible MCP tools — registered in the MCP server
28
- module.exports.tools = [
29
- getHelp,
30
- getPublicConnectors,
31
- getSessionInfo,
32
- logout,
33
- findContact,
34
- findContactWithName,
35
- createCallLog,
36
- rcGetCallLogs,
37
- // getGoogleFilePicker,
38
- createContact,
39
- listAppointments,
40
- createAppointment,
41
- updateAppointment,
42
- confirmAppointment,
43
- cancelAppointment,
44
- ];
45
-
46
- // Widget-only tools — callable via /mcp/widget-tool-call, NOT registered as MCP tools
47
- module.exports.widgetTools = [
48
- doAuth,
49
- checkAuthStatus,
50
- ];
51
-
@@ -1,358 +0,0 @@
1
- import { useState, useEffect, useCallback } from 'react'
2
- import { ConnectorList, type Connector } from './components/ConnectorList'
3
- import { AuthInfoForm } from './components/AuthInfoForm'
4
- import { OAuthConnect } from './components/OAuthConnect'
5
- import { AuthSuccess } from './components/AuthSuccess'
6
- import { setServerUrl } from './lib/callTool'
7
- import { fetchConnectors, fetchManifest } from './lib/developerPortal'
8
- import { dbg } from './lib/debugLog'
9
-
10
- // Initial structuredContent from getPublicConnectors — serverUrl, rcAccountId, rcExtensionId, openaiSessionId
11
- interface ToolOutput {
12
- serverUrl?: string
13
- rcAccountId?: string | null
14
- rcExtensionId?: string | null
15
- openaiSessionId?: string | null
16
- error?: boolean
17
- errorMessage?: string
18
- }
19
-
20
- type Step = 'loadingConnectors' | 'select' | 'loading' | 'authInfo' | 'oauth' | 'success' | 'error'
21
-
22
- interface FlowState {
23
- connectorManifest: any | null
24
- connectorName: string | null
25
- connectorDisplayName: string | null
26
- hostname: string
27
- userInfo: any | null
28
- }
29
-
30
- const INITIAL_FLOW_STATE: FlowState = {
31
- connectorManifest: null,
32
- connectorName: null,
33
- connectorDisplayName: null,
34
- hostname: '',
35
- userInfo: null,
36
- }
37
-
38
- /**
39
- * Extract and apply serverUrl from tool output as early as possible.
40
- * Must be called synchronously so it's set before any tool calls.
41
- */
42
- function applyServerUrl(output: ToolOutput | null) {
43
- dbg.info('applyServerUrl: received output keys:', output ? Object.keys(output).join(', ') : 'null');
44
- dbg.info('applyServerUrl: serverUrl =', output?.serverUrl ?? '(none)');
45
- if (output?.serverUrl) {
46
- setServerUrl(output.serverUrl);
47
- }
48
- return output;
49
- }
50
-
51
- /**
52
- * Hook to receive the initial tool output (serverUrl + rcAccountId).
53
- *
54
- * Listens via three mechanisms per the ChatGPT Apps SDK docs:
55
- * 1. window.openai.toolOutput — synchronous read on mount
56
- * 2. openai:set_globals event — ChatGPT pushes globals into the iframe
57
- * 3. ui/notifications/tool-result postMessage — MCP Apps bridge notification
58
- * 4. Polling window.openai.toolOutput — fallback for async population
59
- */
60
- function useToolResult() {
61
- const [toolResult, setToolResult] = useState<ToolOutput | null>(() => {
62
- const openai = (window as any).openai
63
- dbg.info('init: window.openai exists?', !!openai);
64
- dbg.info('init: window.openai.toolOutput?', JSON.stringify(openai?.toolOutput)?.slice(0, 200) ?? 'null');
65
- const output = openai?.toolOutput
66
- if (output && Object.keys(output).length > 0) {
67
- return applyServerUrl(output)
68
- }
69
- return null
70
- })
71
-
72
- useEffect(() => {
73
- if (toolResult) return
74
-
75
- // MCP Apps bridge: tool-result notification
76
- const onMessage = (event: MessageEvent) => {
77
- if (event.source !== window.parent) return
78
- const message = event.data
79
- if (!message || message.jsonrpc !== '2.0') return
80
- if (message.method !== 'ui/notifications/tool-result') return
81
- const payload = message.params?.structuredContent ?? message.params ?? null
82
- if (payload) setToolResult(applyServerUrl(payload))
83
- }
84
- window.addEventListener('message', onMessage, { passive: true })
85
-
86
- // ChatGPT extension: openai:set_globals event
87
- const onSetGlobals = (event: Event) => {
88
- const detail = (event as CustomEvent).detail
89
- const output = detail?.globals?.toolOutput ?? (window as any).openai?.toolOutput
90
- if (output && Object.keys(output).length > 0) {
91
- setToolResult(applyServerUrl(output))
92
- }
93
- }
94
- window.addEventListener('openai:set_globals', onSetGlobals, { passive: true })
95
-
96
- // Fallback: poll window.openai.toolOutput for async population
97
- const interval = setInterval(() => {
98
- const output = (window as any).openai?.toolOutput
99
- if (output && Object.keys(output).length > 0) {
100
- setToolResult(applyServerUrl(output))
101
- clearInterval(interval)
102
- }
103
- }, 100)
104
-
105
- return () => {
106
- window.removeEventListener('message', onMessage)
107
- window.removeEventListener('openai:set_globals', onSetGlobals)
108
- clearInterval(interval)
109
- }
110
- }, [toolResult])
111
-
112
- return toolResult
113
- }
114
-
115
- export function App() {
116
- const data = useToolResult()
117
- const [step, setStep] = useState<Step>('loadingConnectors')
118
- const [connectors, setConnectors] = useState<Connector[]>([])
119
- const [flow, setFlow] = useState<FlowState>(INITIAL_FLOW_STATE)
120
- const [errorMsg, setErrorMsg] = useState<string | null>(null)
121
-
122
- // Fetch connector list from developer portal once serverUrl (and optionally rcAccountId) is known
123
- useEffect(() => {
124
- if (!data || data.error) return
125
-
126
- async function loadConnectors() {
127
- try {
128
- dbg.info('loadConnectors: fetching with rcAccountId=', data!.rcAccountId ?? '(none)')
129
- const list = await fetchConnectors(data!.rcAccountId)
130
- setConnectors(list)
131
- setStep('select')
132
- } catch (err: any) {
133
- dbg.error('loadConnectors failed:', err.message)
134
- setStep('error')
135
- setErrorMsg(err.message || 'Failed to load connectors')
136
- }
137
- }
138
-
139
- loadConnectors()
140
- }, [data])
141
-
142
- const resetToSelect = useCallback(() => {
143
- setStep('select')
144
- setFlow(INITIAL_FLOW_STATE)
145
- setErrorMsg(null)
146
- }, [])
147
-
148
- const handleConnectorSelect = useCallback(async (connector: Connector) => {
149
- dbg.info('connector selected:', JSON.stringify(connector))
150
- setStep('loading')
151
- setErrorMsg(null)
152
-
153
- try {
154
- const manifest = await fetchManifest(
155
- connector.id,
156
- connector.status === 'private',
157
- data?.rcAccountId,
158
- )
159
-
160
- if (!manifest) {
161
- setStep('error')
162
- setErrorMsg('Failed to load connector configuration')
163
- return
164
- }
165
-
166
- const connectorName = connector.name
167
- const platform = manifest?.platforms?.[connectorName]
168
-
169
- if (!platform) {
170
- setStep('error')
171
- setErrorMsg('Invalid connector configuration')
172
- return
173
- }
174
-
175
- setFlow((prev) => ({
176
- ...prev,
177
- connectorManifest: manifest,
178
- connectorName,
179
- connectorDisplayName: connector.displayName,
180
- }))
181
-
182
- const envType = platform.environment?.type
183
- const authType = platform.auth?.type
184
-
185
- // For oauth with dynamic/selectable environments, collect auth info first
186
- if (authType === 'oauth' && (envType === 'dynamic' || envType === 'selectable')) {
187
- setStep('authInfo')
188
- return
189
- }
190
-
191
- // For fixed environments, extract hostname from the fixed URL
192
- if (envType === 'fixed' && platform.environment?.url) {
193
- try {
194
- const url = new URL(platform.environment.url)
195
- setFlow((prev) => ({ ...prev, hostname: url.hostname }))
196
- } catch {
197
- // hostname stays empty
198
- }
199
- }
200
-
201
- setStep('oauth')
202
- } catch (err: any) {
203
- setStep('error')
204
- setErrorMsg(err.message || 'Failed to load connector')
205
- }
206
- }, [data?.rcAccountId])
207
-
208
- const handleAuthInfoSubmit = useCallback(
209
- (value: { hostname?: string; selection?: string }) => {
210
- try {
211
- const platform = flow.connectorManifest?.platforms?.[flow.connectorName!]
212
- const envType = platform?.environment?.type
213
- let resolvedHostname = ''
214
-
215
- if (envType === 'dynamic' && value.hostname) {
216
- resolvedHostname = new URL(value.hostname).hostname
217
- } else if (envType === 'selectable' && value.selection) {
218
- const sel = platform.environment.selections?.find(
219
- (s: { name: string; const: string }) => s.name === value.selection,
220
- )
221
- if (sel?.const) {
222
- resolvedHostname = new URL(sel.const).hostname
223
- }
224
- }
225
-
226
- setFlow((prev) => ({ ...prev, hostname: resolvedHostname }))
227
- setStep('oauth')
228
- } catch (err: any) {
229
- setStep('error')
230
- setErrorMsg(err.message || 'Failed to process environment selection')
231
- }
232
- },
233
- [flow.connectorManifest, flow.connectorName],
234
- )
235
-
236
- const handleAuthSuccess = useCallback(
237
- (authData: { jwtToken?: string; userInfo?: any }) => {
238
- setFlow((prev) => ({ ...prev, userInfo: authData.userInfo ?? null }))
239
- setStep('success')
240
- },
241
- [],
242
- )
243
-
244
- const handleAuthError = useCallback(
245
- (error: string) => {
246
- if (error === 'retry') {
247
- setStep('oauth')
248
- return
249
- }
250
- setStep('error')
251
- setErrorMsg(error)
252
- },
253
- [],
254
- )
255
-
256
- // Waiting for initial tool output from ChatGPT
257
- if (!data) {
258
- return (
259
- <div className="flex items-center justify-center min-h-[150px] p-4">
260
- <div className="animate-spin rounded-full h-6 w-6 border-b-2 border-primary" />
261
- </div>
262
- )
263
- }
264
-
265
- // Error from initial tool call
266
- if (data.error) {
267
- return (
268
- <div className="p-4">
269
- <div className="rounded-lg border border-yellow-200 bg-yellow-50 p-4">
270
- <p className="text-yellow-800">{data.errorMessage || 'An error occurred'}</p>
271
- </div>
272
- </div>
273
- )
274
- }
275
-
276
- return (
277
- <div className="p-4">
278
- {step === 'loadingConnectors' && (
279
- <div className="flex items-center justify-center min-h-[150px]">
280
- <div className="text-center space-y-3">
281
- <div className="animate-spin rounded-full h-6 w-6 border-b-2 border-primary mx-auto" />
282
- <p className="text-sm text-secondary">Loading connectors...</p>
283
- </div>
284
- </div>
285
- )}
286
-
287
- {step === 'select' && (
288
- <ConnectorList connectors={connectors} onSelect={handleConnectorSelect} />
289
- )}
290
-
291
- {step === 'loading' && (
292
- <div className="flex items-center justify-center min-h-[150px]">
293
- <div className="text-center space-y-3">
294
- <div className="animate-spin rounded-full h-6 w-6 border-b-2 border-primary mx-auto" />
295
- <p className="text-sm text-secondary">Loading...</p>
296
- </div>
297
- </div>
298
- )}
299
-
300
- {step === 'authInfo' && flow.connectorManifest && flow.connectorName && (
301
- <AuthInfoForm
302
- environmentType={
303
- flow.connectorManifest.platforms[flow.connectorName].environment.type
304
- }
305
- urlIdentifier={
306
- flow.connectorManifest.platforms[flow.connectorName].environment.urlIdentifier
307
- }
308
- instructions={
309
- flow.connectorManifest.platforms[flow.connectorName].environment.instructions
310
- }
311
- selections={
312
- flow.connectorManifest.platforms[flow.connectorName].environment.selections
313
- }
314
- connectorDisplayName={flow.connectorDisplayName!}
315
- onSubmit={handleAuthInfoSubmit}
316
- onBack={resetToSelect}
317
- />
318
- )}
319
-
320
- {step === 'oauth' && flow.connectorManifest && flow.connectorName && (
321
- <OAuthConnect
322
- connectorManifest={flow.connectorManifest}
323
- connectorName={flow.connectorName}
324
- connectorDisplayName={flow.connectorDisplayName!}
325
- hostname={flow.hostname}
326
- openaiSessionId={data?.openaiSessionId ?? null}
327
- rcExtensionId={data?.rcExtensionId ?? null}
328
- onSuccess={handleAuthSuccess}
329
- onError={handleAuthError}
330
- onBack={resetToSelect}
331
- />
332
- )}
333
-
334
- {step === 'success' && (
335
- <AuthSuccess
336
- connectorDisplayName={flow.connectorDisplayName!}
337
- userInfo={flow.userInfo ?? undefined}
338
- />
339
- )}
340
-
341
- {step === 'error' && (
342
- <div className="w-full max-w-md">
343
- <div className="rounded-lg border border-red-200 bg-red-50 p-4 mb-4">
344
- <p className="text-red-700 text-sm font-semibold">Error</p>
345
- <p className="text-red-700 text-sm mt-1">{errorMsg || 'An error occurred'}</p>
346
- </div>
347
- <button
348
- type="button"
349
- onClick={resetToSelect}
350
- className="text-sm text-primary hover:underline cursor-pointer"
351
- >
352
- &larr; Back to connector list
353
- </button>
354
- </div>
355
- )}
356
- </div>
357
- )
358
- }
@@ -1,113 +0,0 @@
1
- import { useState } from 'react'
2
- import { Button } from '@openai/apps-sdk-ui/components/Button'
3
- import { Input } from '@openai/apps-sdk-ui/components/Input'
4
-
5
- interface Selection {
6
- name: string
7
- const: string
8
- }
9
-
10
- interface AuthInfoFormProps {
11
- environmentType: 'dynamic' | 'selectable'
12
- urlIdentifier?: string
13
- instructions?: string
14
- selections?: Selection[]
15
- connectorDisplayName: string
16
- onSubmit: (value: { hostname?: string; selection?: string }) => void
17
- onBack: () => void
18
- }
19
-
20
- export function AuthInfoForm({
21
- environmentType,
22
- urlIdentifier,
23
- instructions,
24
- selections,
25
- connectorDisplayName,
26
- onSubmit,
27
- onBack,
28
- }: AuthInfoFormProps) {
29
- const [hostname, setHostname] = useState('')
30
- const [selectedName, setSelectedName] = useState<string | null>(null)
31
-
32
- const handleSubmit = (e: React.FormEvent) => {
33
- e.preventDefault()
34
- if (environmentType === 'dynamic') {
35
- onSubmit({ hostname })
36
- } else if (selectedName) {
37
- onSubmit({ selection: selectedName })
38
- }
39
- }
40
-
41
- return (
42
- <div className="w-full max-w-md">
43
- <div className="mb-4">
44
- <button
45
- type="button"
46
- onClick={onBack}
47
- className="text-sm text-secondary hover:text-primary transition-colors mb-2 cursor-pointer"
48
- >
49
- &larr; Back
50
- </button>
51
- <h2 className="heading-lg">Connect to {connectorDisplayName}</h2>
52
- </div>
53
-
54
- <form onSubmit={handleSubmit} className="space-y-4">
55
- {environmentType === 'dynamic' && (
56
- <div className="space-y-2">
57
- <p className="text-secondary text-sm">
58
- {instructions || `Enter your ${connectorDisplayName} hostname`}
59
- </p>
60
- {urlIdentifier && (
61
- <p className="text-xs text-secondary opacity-70">
62
- Example: {urlIdentifier}
63
- </p>
64
- )}
65
- <Input
66
- type="url"
67
- value={hostname}
68
- onChange={(e: React.ChangeEvent<HTMLInputElement>) => setHostname(e.target.value)}
69
- placeholder="https://your-instance.example.com"
70
- size="md"
71
- />
72
- </div>
73
- )}
74
-
75
- {environmentType === 'selectable' && selections && (
76
- <div className="space-y-2">
77
- <p className="text-secondary text-sm">
78
- Select your {connectorDisplayName} environment
79
- </p>
80
- <div className="space-y-2">
81
- {selections.map((sel) => (
82
- <button
83
- key={sel.name}
84
- type="button"
85
- onClick={() => setSelectedName(sel.name)}
86
- className={`w-full text-left rounded-xl border p-3 transition-colors cursor-pointer ${
87
- selectedName === sel.name
88
- ? 'border-primary bg-surface-hover'
89
- : 'border-default bg-surface hover:border-primary'
90
- }`}
91
- >
92
- <span className="font-medium text-sm">{sel.name}</span>
93
- </button>
94
- ))}
95
- </div>
96
- </div>
97
- )}
98
-
99
- <Button
100
- type="submit"
101
- color="primary"
102
- size="md"
103
- disabled={
104
- (environmentType === 'dynamic' && !hostname.trim()) ||
105
- (environmentType === 'selectable' && !selectedName)
106
- }
107
- >
108
- Continue
109
- </Button>
110
- </form>
111
- </div>
112
- )
113
- }
@@ -1,22 +0,0 @@
1
- interface AuthSuccessProps {
2
- connectorDisplayName: string
3
- userInfo?: { id?: string; name?: string }
4
- }
5
-
6
- export function AuthSuccess({ connectorDisplayName, userInfo }: AuthSuccessProps) {
7
- return (
8
- <div className="w-full max-w-md">
9
- <div className="rounded-xl border border-green-200 bg-green-50 p-5 text-center space-y-2">
10
- <div className="text-2xl text-green-700">&#10003;</div>
11
- <h2 className="heading-lg text-green-800">Connected</h2>
12
- <p className="text-sm text-green-700">
13
- Successfully connected to <strong>{connectorDisplayName}</strong>
14
- {userInfo?.name ? ` as ${userInfo.name}` : ''}.
15
- </p>
16
- <p className="text-xs text-green-600 mt-2">
17
- You can now use the AI assistant to interact with your CRM.
18
- </p>
19
- </div>
20
- </div>
21
- )
22
- }
@@ -1,82 +0,0 @@
1
- import { useState } from 'react'
2
- import { Button } from "@openai/apps-sdk-ui/components/Button"
3
- import { Badge } from "@openai/apps-sdk-ui/components/Badge"
4
-
5
- export interface Connector {
6
- id: string
7
- name: string
8
- displayName: string
9
- description?: string
10
- status?: 'public' | 'private'
11
- }
12
-
13
- interface ConnectorListProps {
14
- connectors: Connector[]
15
- disabled?: boolean
16
- onSelect: (connector: Connector) => void
17
- }
18
-
19
- export function ConnectorList({ connectors, disabled, onSelect }: ConnectorListProps) {
20
- const [selectedName, setSelectedName] = useState<string | null>(null)
21
-
22
- if (!connectors || connectors.length === 0) {
23
- return (
24
- <div className="p-4 text-center text-secondary">
25
- <p>No connectors available</p>
26
- </div>
27
- )
28
- }
29
-
30
- const handleSelect = (connector: Connector) => {
31
- setSelectedName(connector.displayName)
32
- onSelect(connector)
33
- }
34
-
35
- return (
36
- <div className="w-full max-w-md">
37
- <div className="mb-4">
38
- <h2 className="heading-lg">Available Connectors</h2>
39
- <p className="text-secondary text-sm mt-1">
40
- Select a CRM to connect with RingCentral
41
- </p>
42
- </div>
43
-
44
- <div className="space-y-3">
45
- {connectors.map((connector) => {
46
- const isSelected = selectedName === connector.displayName
47
- return (
48
- <div
49
- key={connector.displayName}
50
- className="rounded-xl border border-default bg-surface p-4 hover:border-primary transition-colors"
51
- >
52
- <div className="flex items-center justify-between gap-3">
53
- <div className="flex-1">
54
- <div className="flex items-center gap-2">
55
- <h3 className="font-medium">{connector.displayName}</h3>
56
- {connector.status === 'private' && (
57
- <Badge color="secondary" size="sm">Private</Badge>
58
- )}
59
- </div>
60
- {connector.description && (
61
- <p className="text-secondary text-sm mt-1">
62
- {connector.description}
63
- </p>
64
- )}
65
- </div>
66
- <Button
67
- color={isSelected ? 'secondary' : 'primary'}
68
- size="sm"
69
- onClick={() => handleSelect(connector)}
70
- disabled={disabled || isSelected}
71
- >
72
- {isSelected ? 'Connecting...' : 'Connect'}
73
- </Button>
74
- </div>
75
- </div>
76
- )
77
- })}
78
- </div>
79
- </div>
80
- )
81
- }
82
-
@@ -1,43 +0,0 @@
1
- import { useState, useEffect } from 'react'
2
- import { getEntries, subscribe, type DebugEntry } from '../lib/debugLog'
3
-
4
- const LEVEL_STYLE: Record<DebugEntry['level'], string> = {
5
- info: 'text-blue-700',
6
- warn: 'text-yellow-700',
7
- error: 'text-red-700 font-semibold',
8
- }
9
-
10
- export function DebugPanel() {
11
- const [entries, setEntries] = useState(getEntries)
12
- const [open, setOpen] = useState(false)
13
-
14
- useEffect(() => subscribe(() => setEntries(getEntries())), [])
15
-
16
- return (
17
- <div className="mt-4 border border-default rounded-lg overflow-hidden text-xs">
18
- <button
19
- type="button"
20
- onClick={() => setOpen((v) => !v)}
21
- className="w-full flex items-center justify-between px-3 py-2 bg-surface hover:bg-surface-hover cursor-pointer text-secondary"
22
- >
23
- <span>Debug log ({entries.length} entries)</span>
24
- <span>{open ? '▲' : '▼'}</span>
25
- </button>
26
-
27
- {open && (
28
- <div className="max-h-60 overflow-y-auto bg-black/5 p-2 space-y-0.5 font-mono">
29
- {entries.length === 0 && (
30
- <p className="text-secondary italic">No entries yet.</p>
31
- )}
32
- {entries.map((e, i) => (
33
- <div key={i} className={`${LEVEL_STYLE[e.level]} leading-tight`}>
34
- <span className="opacity-50 mr-1">{e.time}</span>
35
- <span>[{e.level}]</span>{' '}
36
- <span className="break-all">{e.msg}</span>
37
- </div>
38
- ))}
39
- </div>
40
- )}
41
- </div>
42
- )
43
- }