@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,270 +0,0 @@
1
- import { useEffect, useRef, useState } from 'react'
2
- import { Button } from '@openai/apps-sdk-ui/components/Button'
3
- import { callTool, getServerUrl, updateModelContext } from '../lib/callTool'
4
- import { dbg } from '../lib/debugLog'
5
-
6
- type AuthStatus = 'ready' | 'creatingSession' | 'polling' | 'error'
7
-
8
- interface OAuthConnectProps {
9
- connectorManifest: any
10
- connectorName: string
11
- connectorDisplayName: string
12
- hostname: string
13
- openaiSessionId?: string | null
14
- rcExtensionId?: string | null
15
- onSuccess: (data: { jwtToken: string; userInfo?: any }) => void
16
- onError: (error: string) => void
17
- onBack: () => void
18
- }
19
-
20
- /**
21
- * Compose the OAuth authorization URL entirely client-side.
22
- * The widget already has the full manifest and serverUrl — no server round-trip needed.
23
- */
24
- function buildAuthUri(platform: any, sessionId: string, hostname: string, serverUrl: string): string {
25
- const oauth = platform.auth.oauth
26
- let stateParam = `sessionId=${sessionId}&platform=${platform.name}&hostname=${hostname}`
27
- if (oauth.customState) stateParam += `&${oauth.customState}`
28
-
29
- return `${oauth.authUrl}?` +
30
- `response_type=code` +
31
- `&client_id=${oauth.clientId}` +
32
- `${oauth.scope ? `&${oauth.scope}` : ''}` +
33
- `&state=${encodeURIComponent(stateParam)}` +
34
- `&redirect_uri=${serverUrl}/oauth-callback`
35
- }
36
-
37
- const POLL_INTERVAL_MS = 5_000;
38
- const MAX_POLL_ATTEMPTS = 100; // ~5 minutes
39
-
40
- export function OAuthConnect({
41
- connectorManifest,
42
- connectorName,
43
- connectorDisplayName,
44
- hostname,
45
- openaiSessionId,
46
- rcExtensionId,
47
- onSuccess,
48
- onError,
49
- onBack,
50
- }: OAuthConnectProps) {
51
- const [status, setStatus] = useState<AuthStatus>('ready')
52
- const [authUri, setAuthUri] = useState<string | null>(null)
53
- const [errorMsg, setErrorMsg] = useState<string | null>(null)
54
- const [sessionReady, setSessionReady] = useState(false)
55
-
56
- const sessionIdRef = useRef<string | null>(null)
57
- const pollTimerRef = useRef<ReturnType<typeof setInterval> | null>(null)
58
- const pollCountRef = useRef(0)
59
- const unmountedRef = useRef(false)
60
-
61
- // Cleanup on unmount
62
- useEffect(() => {
63
- return () => {
64
- unmountedRef.current = true
65
- if (pollTimerRef.current) clearInterval(pollTimerRef.current)
66
- }
67
- }, [])
68
-
69
- // Build authUri client-side immediately — no server round-trip needed.
70
- // Simultaneously call doAuth in the background to create the DB session.
71
- useEffect(() => {
72
- let cancelled = false
73
- const platform = connectorManifest?.platforms?.[connectorName]
74
-
75
- if (!platform) {
76
- setStatus('error')
77
- setErrorMsg('Invalid connector configuration')
78
- return
79
- }
80
-
81
- // Use openaiSessionId as the primary session key so the OAuth callback
82
- // can be correlated with the ChatGPT conversation. Fall back to a random
83
- // UUID when the widget is loaded outside ChatGPT.
84
- const sessionId = openaiSessionId ?? crypto.randomUUID()
85
- sessionIdRef.current = sessionId
86
- const serverUrl = getServerUrl() ?? ''
87
- const uri = buildAuthUri(platform, sessionId, hostname, serverUrl)
88
- setAuthUri(uri)
89
- dbg.info('authUri composed client-side, sessionId:', sessionId)
90
-
91
- // Create the server-side session in background (fast DB write only)
92
- callTool('doAuth', { connectorName, hostname, sessionId }).then((result) => {
93
- if (cancelled || unmountedRef.current) return
94
- if (!result?.success) {
95
- dbg.warn('doAuth session creation failed:', result?.error)
96
- setStatus('error')
97
- setErrorMsg(result?.error || 'Failed to prepare authentication session')
98
- return
99
- }
100
- dbg.info('doAuth session created successfully')
101
- setSessionReady(true)
102
- }).catch((err: any) => {
103
- if (cancelled || unmountedRef.current) return
104
- dbg.error('doAuth error:', err.message)
105
- setStatus('error')
106
- setErrorMsg(err.message || 'Failed to prepare authentication session')
107
- })
108
-
109
- return () => { cancelled = true }
110
- }, [connectorManifest, connectorName, hostname])
111
-
112
- const startPolling = () => {
113
- setStatus('polling')
114
- pollCountRef.current = 0
115
-
116
- pollTimerRef.current = setInterval(async () => {
117
- if (unmountedRef.current) {
118
- if (pollTimerRef.current) clearInterval(pollTimerRef.current)
119
- return
120
- }
121
-
122
- pollCountRef.current += 1
123
- if (pollCountRef.current > MAX_POLL_ATTEMPTS) {
124
- if (pollTimerRef.current) clearInterval(pollTimerRef.current)
125
- setStatus('error')
126
- setErrorMsg('Authorization timed out. Please try again.')
127
- return
128
- }
129
-
130
- try {
131
- const res = await callTool('checkAuthStatus', {
132
- sessionId: sessionIdRef.current,
133
- ...(rcExtensionId ? { rcExtensionId } : {}),
134
- })
135
- const sc = res?.data ?? null
136
-
137
- if (unmountedRef.current) return
138
-
139
- const dataStatus = sc?.status
140
- if (dataStatus === 'completed' && sc?.jwtToken) {
141
- if (pollTimerRef.current) clearInterval(pollTimerRef.current)
142
-
143
- // Push the JWT into ChatGPT's model context so it can be used
144
- // in future tool calls. updateModelContext tries ui/update-model-context
145
- // first (invisible to user, visible to model), then falls back to ui/message.
146
- const userLabel = sc.userInfo?.name ? ` as ${sc.userInfo.name}` : ''
147
- await updateModelContext(
148
- `CRM authentication with ${connectorDisplayName} completed${userLabel}. ` +
149
- `Platform: ${connectorName}. ` +
150
- `jwtToken: ${sc.jwtToken}. ` +
151
- `IMPORTANT: Store this jwtToken and pass it as a parameter to all future CRM tool calls.`
152
- )
153
- dbg.info('updateModelContext sent with jwtToken')
154
-
155
- onSuccess({
156
- jwtToken: sc.jwtToken,
157
- userInfo: sc.userInfo,
158
- })
159
- } else if (dataStatus === 'failed') {
160
- if (pollTimerRef.current) clearInterval(pollTimerRef.current)
161
- setStatus('error')
162
- setErrorMsg(sc?.errorMessage || 'Authorization failed')
163
- } else if (dataStatus === 'expired') {
164
- if (pollTimerRef.current) clearInterval(pollTimerRef.current)
165
- setStatus('error')
166
- setErrorMsg('Authorization session expired. Please try again.')
167
- }
168
- // 'pending' -> keep polling
169
- } catch {
170
- // Transient errors during polling are acceptable; keep trying
171
- }
172
- }, POLL_INTERVAL_MS)
173
- }
174
-
175
- const handleAuthorizeClick = () => {
176
- if (authUri && sessionReady) {
177
- window.open(authUri, '_blank', 'noopener,noreferrer')
178
- startPolling()
179
- }
180
- }
181
-
182
- const handleRetry = () => {
183
- setStatus('error')
184
- setErrorMsg(null)
185
- onError('retry')
186
- }
187
-
188
- // Error state
189
- if (status === 'error') {
190
- return (
191
- <div className="w-full max-w-md">
192
- <div className="mb-4">
193
- <button
194
- type="button"
195
- onClick={onBack}
196
- className="text-sm text-secondary hover:text-primary transition-colors mb-2 cursor-pointer"
197
- >
198
- &larr; Back
199
- </button>
200
- <h2 className="heading-lg">Authentication Error</h2>
201
- </div>
202
- <div className="rounded-lg border border-red-200 bg-red-50 p-4 mb-4">
203
- <p className="text-red-700 text-sm">{errorMsg}</p>
204
- </div>
205
- <Button color="primary" size="sm" onClick={handleRetry}>
206
- Try Again
207
- </Button>
208
- </div>
209
- )
210
- }
211
-
212
- // Ready to authorize or polling
213
- return (
214
- <div className="w-full max-w-md">
215
- <div className="mb-4">
216
- <button
217
- type="button"
218
- onClick={onBack}
219
- className="text-sm text-secondary hover:text-primary transition-colors mb-2 cursor-pointer"
220
- >
221
- &larr; Back
222
- </button>
223
- <h2 className="heading-lg">Authorize {connectorDisplayName}</h2>
224
- </div>
225
-
226
- <div className="rounded-xl border border-default bg-surface p-4 space-y-4">
227
- {status === 'ready' && (
228
- <>
229
- <p className="text-sm text-secondary">
230
- Click the button below to open {connectorDisplayName}'s authorization
231
- page. After you approve access, return here to continue.
232
- </p>
233
- <Button
234
- color="primary"
235
- size="md"
236
- onClick={handleAuthorizeClick}
237
- disabled={!sessionReady}
238
- >
239
- {sessionReady
240
- ? `Authorize in ${connectorDisplayName}`
241
- : 'Preparing…'}
242
- </Button>
243
- </>
244
- )}
245
-
246
- {status === 'polling' && (
247
- <div className="text-center space-y-3">
248
- <div className="animate-spin rounded-full h-5 w-5 border-b-2 border-primary mx-auto" />
249
- <p className="text-sm text-secondary">
250
- Waiting for you to authorize in {connectorDisplayName}...
251
- </p>
252
- <p className="text-xs text-secondary opacity-60">
253
- Complete the authorization in the opened tab, then come back here.
254
- </p>
255
- {authUri && (
256
- <a
257
- href={authUri}
258
- target="_blank"
259
- rel="noopener noreferrer"
260
- className="text-xs text-primary hover:underline"
261
- >
262
- Open authorization page again
263
- </a>
264
- )}
265
- </div>
266
- )}
267
- </div>
268
- </div>
269
- )
270
- }
@@ -1,130 +0,0 @@
1
- import { dbg } from './debugLog';
2
-
3
- /**
4
- * Server URL for direct HTTP tool calls.
5
- * Set from structuredContent.serverUrl when the initial tool output arrives.
6
- */
7
- let _serverUrl: string | null = null;
8
-
9
- /**
10
- * Send a JSON-RPC 2.0 request to the host (ChatGPT) and await the response.
11
- * Used for MCP Apps bridge calls that require a round-trip (e.g. ui/update-model-context).
12
- */
13
- function rpcRequest(method: string, params: unknown, timeoutMs = 10_000): Promise<unknown> {
14
- return new Promise((resolve, reject) => {
15
- const id = `${method}-${Date.now()}-${Math.random().toString(36).slice(2)}`
16
-
17
- const timer = setTimeout(() => {
18
- window.removeEventListener('message', onMessage)
19
- reject(new Error(`rpcRequest "${method}" timed out after ${timeoutMs}ms`))
20
- }, timeoutMs)
21
-
22
- function onMessage(event: MessageEvent) {
23
- if (event.source !== window.parent) return
24
- const msg = event.data
25
- if (!msg || msg.jsonrpc !== '2.0' || msg.id !== id) return
26
- clearTimeout(timer)
27
- window.removeEventListener('message', onMessage)
28
- if (msg.error) reject(new Error(msg.error.message ?? JSON.stringify(msg.error)))
29
- else resolve(msg.result)
30
- }
31
-
32
- window.addEventListener('message', onMessage, { passive: true })
33
- window.parent.postMessage({ jsonrpc: '2.0', id, method, params }, '*')
34
- })
35
- }
36
-
37
- /**
38
- * Inject text into the model's context without showing it as a visible chat message.
39
- * Uses the MCP Apps bridge ui/update-model-context (preferred), with ui/message as fallback.
40
- */
41
- export async function updateModelContext(text: string): Promise<void> {
42
- const content = [{ type: 'text', text }]
43
-
44
- // Primary: MCP Apps standard — invisible to user, visible to model
45
- try {
46
- await rpcRequest('ui/update-model-context', { content })
47
- dbg.info('updateModelContext: ui/update-model-context succeeded')
48
- return
49
- } catch (err: any) {
50
- dbg.warn('updateModelContext: ui/update-model-context failed, trying ui/message:', err.message)
51
- }
52
-
53
- // Fallback: visible user message (ui/message notification — fire and forget)
54
- try {
55
- window.parent.postMessage(
56
- { jsonrpc: '2.0', method: 'ui/message', params: { role: 'user', content } },
57
- '*',
58
- )
59
- dbg.info('updateModelContext: ui/message sent')
60
- return
61
- } catch (err: any) {
62
- dbg.warn('updateModelContext: ui/message failed, trying window.openai.sendMessage:', err.message)
63
- }
64
-
65
- // Last resort: legacy ChatGPT Apps SDK
66
- const openai = (window as any).openai
67
- if (typeof openai?.sendMessage === 'function') {
68
- openai.sendMessage(text)
69
- dbg.info('updateModelContext: window.openai.sendMessage used')
70
- } else {
71
- dbg.error('updateModelContext: no mechanism available to update model context')
72
- }
73
- }
74
-
75
- export function setServerUrl(url: string) {
76
- _serverUrl = url.replace(/\/+$/, '');
77
- dbg.info('serverUrl set to:', _serverUrl);
78
- }
79
-
80
- export function getServerUrl(): string | null {
81
- return _serverUrl;
82
- }
83
-
84
- /**
85
- * Call a widget-accessible tool on the server via direct fetch to /mcp/widget-tool-call.
86
- *
87
- * NOTE: window.openai.callTool() is intentionally NOT used here.
88
- * It routes through ChatGPT's LLM which drops widget-provided args when the MCP
89
- * tool has no Zod inputSchema registered — args arrive as undefined on the server.
90
- * Direct fetch correctly forwards all args.
91
- */
92
- export async function callTool(
93
- toolName: string,
94
- args: Record<string, unknown> = {},
95
- ): Promise<any> {
96
- dbg.info(`callTool("${toolName}", ${JSON.stringify(args)})`);
97
- dbg.info('_serverUrl:', _serverUrl);
98
-
99
- if (!_serverUrl) {
100
- const msg = 'serverUrl not set — ensure APP_SERVER env var is set and server restarted';
101
- dbg.error(msg);
102
- throw new Error(msg);
103
- }
104
-
105
- const endpoint = `${_serverUrl}/mcp/widget-tool-call`;
106
- const body = JSON.stringify({ tool: toolName, toolArgs: args });
107
- dbg.info('fetch POST', endpoint, 'body:', body);
108
-
109
- try {
110
- const res = await fetch(endpoint, {
111
- method: 'POST',
112
- headers: { 'Content-Type': 'application/json' },
113
- body,
114
- });
115
-
116
- const text = await res.text();
117
- dbg.info('fetch response:', res.status, text.slice(0, 300));
118
-
119
- if (!res.ok) {
120
- let parsed: any = null;
121
- try { parsed = JSON.parse(text); } catch { /* ignore */ }
122
- throw new Error(parsed?.error || `HTTP ${res.status}: ${text}`);
123
- }
124
-
125
- return JSON.parse(text);
126
- } catch (err: any) {
127
- dbg.error('fetch threw:', err.message);
128
- throw err;
129
- }
130
- }
@@ -1,41 +0,0 @@
1
- export interface DebugEntry {
2
- time: string
3
- level: 'info' | 'warn' | 'error'
4
- msg: string
5
- }
6
-
7
- const MAX_ENTRIES = 50;
8
- const entries: DebugEntry[] = [];
9
- const listeners = new Set<() => void>();
10
-
11
- function ts() {
12
- return new Date().toISOString().slice(11, 23); // HH:MM:SS.mmm
13
- }
14
-
15
- function push(level: DebugEntry['level'], parts: unknown[]) {
16
- const msg = parts
17
- .map((p) => (typeof p === 'object' ? JSON.stringify(p) : String(p)))
18
- .join(' ');
19
- entries.push({ time: ts(), level, msg });
20
- if (entries.length > MAX_ENTRIES) entries.shift();
21
- // Mirror to real console
22
- if (level === 'error') console.error('[debug]', msg);
23
- else if (level === 'warn') console.warn('[debug]', msg);
24
- else console.log('[debug]', msg);
25
- listeners.forEach((fn) => fn());
26
- }
27
-
28
- export const dbg = {
29
- info: (...args: unknown[]) => push('info', args),
30
- warn: (...args: unknown[]) => push('warn', args),
31
- error: (...args: unknown[]) => push('error', args),
32
- };
33
-
34
- export function getEntries(): DebugEntry[] {
35
- return [...entries];
36
- }
37
-
38
- export function subscribe(fn: () => void): () => void {
39
- listeners.add(fn);
40
- return () => listeners.delete(fn);
41
- }
@@ -1,111 +0,0 @@
1
- import { dbg } from './debugLog'
2
-
3
- const PORTAL_BASE = 'https://appconnect.labs.ringcentral.com/public-api'
4
-
5
- export const SUPPORTED_PLATFORMS = ['clio']
6
-
7
- export interface Connector {
8
- id: string
9
- name: string
10
- displayName: string
11
- description?: string
12
- status?: 'public' | 'private'
13
- }
14
-
15
- /**
16
- * Fetch the list of available connectors directly from the developer portal.
17
- * Merges public connectors with private ones (if rcAccountId is provided),
18
- * then filters to SUPPORTED_PLATFORMS.
19
- */
20
- export async function fetchConnectors(rcAccountId?: string | null): Promise<Connector[]> {
21
- dbg.info('fetchConnectors: rcAccountId=', rcAccountId ?? '(none)')
22
-
23
- const results: Connector[] = []
24
-
25
- // Public connectors
26
- const publicUrl = `${PORTAL_BASE}/connectors`
27
- dbg.info('fetchConnectors: GET', publicUrl)
28
- try {
29
- const resp = await fetch(publicUrl)
30
- dbg.info('fetchConnectors: public response status=', resp.status, 'ok=', resp.ok)
31
- if (!resp.ok) {
32
- const body = await resp.text().catch(() => '(unreadable)')
33
- throw new Error(`HTTP ${resp.status}: ${body.slice(0, 200)}`)
34
- }
35
- const data = await resp.json()
36
- dbg.info('fetchConnectors: public raw keys=', Object.keys(data).join(', '))
37
- const list: any[] = data?.connectors ?? data ?? []
38
- results.push(...list)
39
- dbg.info('fetchConnectors: public count=', list.length)
40
- } catch (err: any) {
41
- dbg.error('fetchConnectors: failed to fetch public connectors:', err.message, '| name=', err.name, '| url=', publicUrl)
42
- throw new Error(`Failed to load connectors: ${err.message}`)
43
- }
44
-
45
- // Private connectors (only if account ID is available)
46
- if (rcAccountId) {
47
- const privateUrl = `${PORTAL_BASE}/connectors/internal?accountId=${encodeURIComponent(rcAccountId)}`
48
- dbg.info('fetchConnectors: GET', privateUrl)
49
- try {
50
- const resp = await fetch(privateUrl)
51
- dbg.info('fetchConnectors: private response status=', resp.status, 'ok=', resp.ok)
52
- if (resp.ok) {
53
- const data = await resp.json()
54
- dbg.info('fetchConnectors: private raw keys=', Object.keys(data).join(', '))
55
- const list: any[] = data?.privateConnectors ?? data ?? []
56
- results.push(...list)
57
- dbg.info('fetchConnectors: private count=', list.length)
58
- } else {
59
- const body = await resp.text().catch(() => '(unreadable)')
60
- dbg.warn('fetchConnectors: private non-ok response:', resp.status, body.slice(0, 200))
61
- }
62
- } catch (err: any) {
63
- dbg.warn('fetchConnectors: failed to fetch private connectors (non-fatal):', err.message, '| name=', err.name)
64
- }
65
- }
66
-
67
- // Filter to supported platforms and normalise shape
68
- const supported = results
69
- .filter((c) => SUPPORTED_PLATFORMS.includes(c.name))
70
- .map((c): Connector => ({
71
- id: c.id,
72
- name: c.name,
73
- displayName: c.displayName,
74
- description: c.description || `Connect to ${c.displayName}`,
75
- status: (c.status as 'public' | 'private') ?? 'public',
76
- }))
77
-
78
- dbg.info('fetchConnectors: supported=', supported.map((c) => c.name).join(', '))
79
- return supported
80
- }
81
-
82
- /**
83
- * Fetch the manifest for a specific connector directly from the developer portal.
84
- */
85
- export async function fetchManifest(
86
- connectorId: string,
87
- isPrivate: boolean,
88
- rcAccountId?: string | null,
89
- ): Promise<any> {
90
- dbg.info('fetchManifest: connectorId=', connectorId, 'isPrivate=', isPrivate)
91
-
92
- const url = isPrivate && rcAccountId
93
- ? `${PORTAL_BASE}/connectors/${connectorId}/manifest?access=internal&type=connector&accountId=${encodeURIComponent(rcAccountId)}`
94
- : `${PORTAL_BASE}/connectors/${connectorId}/manifest`
95
-
96
- dbg.info('fetchManifest: GET', url)
97
- try {
98
- const resp = await fetch(url)
99
- dbg.info('fetchManifest: response status=', resp.status, 'ok=', resp.ok)
100
- if (!resp.ok) {
101
- const body = await resp.text().catch(() => '(unreadable)')
102
- throw new Error(`HTTP ${resp.status}: ${body.slice(0, 200)}`)
103
- }
104
- const manifest = await resp.json()
105
- dbg.info('fetchManifest: loaded platforms=', Object.keys(manifest?.platforms ?? {}).join(', '))
106
- return manifest
107
- } catch (err: any) {
108
- dbg.error('fetchManifest: failed:', err.message, '| name=', err.name, '| url=', url)
109
- throw err
110
- }
111
- }
@@ -1,6 +0,0 @@
1
- @import "tailwindcss";
2
- @import "@openai/apps-sdk-ui/css";
3
- /* Required for Tailwind to find class references in Apps SDK UI components. */
4
- @source "../../../node_modules/@openai/apps-sdk-ui";
5
-
6
- /* The rest of your application CSS */
@@ -1,13 +0,0 @@
1
- // Must be imported first to ensure Tailwind layers and style foundations are defined before any potential component styles
2
- import "./main.css"
3
-
4
- import { StrictMode } from "react"
5
- import { createRoot } from "react-dom/client"
6
- import { App } from "./App"
7
-
8
- createRoot(document.getElementById("root")!).render(
9
- <StrictMode>
10
- <App />
11
- </StrictMode>,
12
- )
13
-