@memberjunction/server 5.43.0 → 5.45.0

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 (309) hide show
  1. package/dist/agentSessions/ReturningVisitorRecap.d.ts +39 -0
  2. package/dist/agentSessions/ReturningVisitorRecap.d.ts.map +1 -0
  3. package/dist/agentSessions/ReturningVisitorRecap.js +198 -0
  4. package/dist/agentSessions/ReturningVisitorRecap.js.map +1 -0
  5. package/dist/agentSessions/SessionJanitor.d.ts +13 -0
  6. package/dist/agentSessions/SessionJanitor.d.ts.map +1 -1
  7. package/dist/agentSessions/SessionJanitor.js +65 -7
  8. package/dist/agentSessions/SessionJanitor.js.map +1 -1
  9. package/dist/agentSessions/SessionManager.d.ts.map +1 -1
  10. package/dist/agentSessions/SessionManager.js +40 -0
  11. package/dist/agentSessions/SessionManager.js.map +1 -1
  12. package/dist/agentSessions/index.d.ts.map +1 -1
  13. package/dist/agentSessions/index.js +3 -1
  14. package/dist/agentSessions/index.js.map +1 -1
  15. package/dist/auth/magicLink/MagicLinkRouter.d.ts +10 -0
  16. package/dist/auth/magicLink/MagicLinkRouter.d.ts.map +1 -1
  17. package/dist/auth/magicLink/MagicLinkRouter.js +16 -0
  18. package/dist/auth/magicLink/MagicLinkRouter.js.map +1 -1
  19. package/dist/auth/magicLink/index.d.ts +1 -1
  20. package/dist/auth/magicLink/index.d.ts.map +1 -1
  21. package/dist/auth/magicLink/index.js +1 -1
  22. package/dist/auth/magicLink/index.js.map +1 -1
  23. package/dist/auth/magicLink/types.d.ts +26 -0
  24. package/dist/auth/magicLink/types.d.ts.map +1 -1
  25. package/dist/config.d.ts +1883 -144
  26. package/dist/config.d.ts.map +1 -1
  27. package/dist/config.js +160 -36
  28. package/dist/config.js.map +1 -1
  29. package/dist/context.d.ts.map +1 -1
  30. package/dist/context.js +45 -2
  31. package/dist/context.js.map +1 -1
  32. package/dist/generated/generated.d.ts +1684 -54
  33. package/dist/generated/generated.d.ts.map +1 -1
  34. package/dist/generated/generated.js +57105 -48029
  35. package/dist/generated/generated.js.map +1 -1
  36. package/dist/generic/ResolverBase.d.ts +13 -0
  37. package/dist/generic/ResolverBase.d.ts.map +1 -1
  38. package/dist/generic/ResolverBase.js +22 -0
  39. package/dist/generic/ResolverBase.js.map +1 -1
  40. package/dist/generic/RunViewResolver.d.ts.map +1 -1
  41. package/dist/generic/RunViewResolver.js +4 -0
  42. package/dist/generic/RunViewResolver.js.map +1 -1
  43. package/dist/index.d.ts +2 -2
  44. package/dist/index.d.ts.map +1 -1
  45. package/dist/index.js +110 -3
  46. package/dist/index.js.map +1 -1
  47. package/dist/integration/CustomColumnPromoter.d.ts.map +1 -1
  48. package/dist/integration/CustomColumnPromoter.js +6 -0
  49. package/dist/integration/CustomColumnPromoter.js.map +1 -1
  50. package/dist/realtimeWidget/WidgetRouter.d.ts +26 -0
  51. package/dist/realtimeWidget/WidgetRouter.d.ts.map +1 -0
  52. package/dist/realtimeWidget/WidgetRouter.js +182 -0
  53. package/dist/realtimeWidget/WidgetRouter.js.map +1 -0
  54. package/dist/realtimeWidget/WidgetSessionService.d.ts +265 -0
  55. package/dist/realtimeWidget/WidgetSessionService.d.ts.map +1 -0
  56. package/dist/realtimeWidget/WidgetSessionService.js +477 -0
  57. package/dist/realtimeWidget/WidgetSessionService.js.map +1 -0
  58. package/dist/realtimeWidget/host-identity.d.ts +40 -0
  59. package/dist/realtimeWidget/host-identity.d.ts.map +1 -0
  60. package/dist/realtimeWidget/host-identity.js +58 -0
  61. package/dist/realtimeWidget/host-identity.js.map +1 -0
  62. package/dist/realtimeWidget/index.d.ts +10 -0
  63. package/dist/realtimeWidget/index.d.ts.map +1 -0
  64. package/dist/realtimeWidget/index.js +9 -0
  65. package/dist/realtimeWidget/index.js.map +1 -0
  66. package/dist/realtimeWidget/visitorIdentity.d.ts +76 -0
  67. package/dist/realtimeWidget/visitorIdentity.d.ts.map +1 -0
  68. package/dist/realtimeWidget/visitorIdentity.js +202 -0
  69. package/dist/realtimeWidget/visitorIdentity.js.map +1 -0
  70. package/dist/realtimeWidget/widgetCore.d.ts +106 -0
  71. package/dist/realtimeWidget/widgetCore.d.ts.map +1 -0
  72. package/dist/realtimeWidget/widgetCore.js +173 -0
  73. package/dist/realtimeWidget/widgetCore.js.map +1 -0
  74. package/dist/realtimeWidget/widgetGuestElevation.d.ts +51 -0
  75. package/dist/realtimeWidget/widgetGuestElevation.d.ts.map +1 -0
  76. package/dist/realtimeWidget/widgetGuestElevation.js +79 -0
  77. package/dist/realtimeWidget/widgetGuestElevation.js.map +1 -0
  78. package/dist/resolvers/ComponentRegistryResolver.d.ts +7 -0
  79. package/dist/resolvers/ComponentRegistryResolver.d.ts.map +1 -1
  80. package/dist/resolvers/ComponentRegistryResolver.js +31 -8
  81. package/dist/resolvers/ComponentRegistryResolver.js.map +1 -1
  82. package/dist/resolvers/EntityPermissionResolver.d.ts.map +1 -1
  83. package/dist/resolvers/EntityPermissionResolver.js +1 -2
  84. package/dist/resolvers/EntityPermissionResolver.js.map +1 -1
  85. package/dist/resolvers/FileResolver.d.ts +74 -0
  86. package/dist/resolvers/FileResolver.d.ts.map +1 -1
  87. package/dist/resolvers/FileResolver.js +211 -2
  88. package/dist/resolvers/FileResolver.js.map +1 -1
  89. package/dist/resolvers/QueryResolver.d.ts +6 -4
  90. package/dist/resolvers/QueryResolver.d.ts.map +1 -1
  91. package/dist/resolvers/QueryResolver.js +29 -14
  92. package/dist/resolvers/QueryResolver.js.map +1 -1
  93. package/dist/resolvers/QuerySystemUserResolver.d.ts +9 -6
  94. package/dist/resolvers/QuerySystemUserResolver.d.ts.map +1 -1
  95. package/dist/resolvers/QuerySystemUserResolver.js +15 -13
  96. package/dist/resolvers/QuerySystemUserResolver.js.map +1 -1
  97. package/dist/resolvers/RealtimeBridgeResolver.d.ts +8 -1
  98. package/dist/resolvers/RealtimeBridgeResolver.d.ts.map +1 -1
  99. package/dist/resolvers/RealtimeBridgeResolver.js +28 -4
  100. package/dist/resolvers/RealtimeBridgeResolver.js.map +1 -1
  101. package/dist/resolvers/RealtimeClientSessionResolver.d.ts +91 -2
  102. package/dist/resolvers/RealtimeClientSessionResolver.d.ts.map +1 -1
  103. package/dist/resolvers/RealtimeClientSessionResolver.js +337 -17
  104. package/dist/resolvers/RealtimeClientSessionResolver.js.map +1 -1
  105. package/dist/resolvers/RemoteBrowserActionResolver.d.ts.map +1 -1
  106. package/dist/resolvers/RemoteBrowserActionResolver.js +17 -2
  107. package/dist/resolvers/RemoteBrowserActionResolver.js.map +1 -1
  108. package/dist/resolvers/RingCentralTelephonyResolver.d.ts +27 -0
  109. package/dist/resolvers/RingCentralTelephonyResolver.d.ts.map +1 -0
  110. package/dist/resolvers/RingCentralTelephonyResolver.js +87 -0
  111. package/dist/resolvers/RingCentralTelephonyResolver.js.map +1 -0
  112. package/dist/resolvers/RunAIAgentResolver.d.ts +12 -3
  113. package/dist/resolvers/RunAIAgentResolver.d.ts.map +1 -1
  114. package/dist/resolvers/RunAIAgentResolver.js +50 -17
  115. package/dist/resolvers/RunAIAgentResolver.js.map +1 -1
  116. package/dist/resolvers/SearchKnowledgeResolver.d.ts.map +1 -1
  117. package/dist/resolvers/SearchKnowledgeResolver.js +2 -0
  118. package/dist/resolvers/SearchKnowledgeResolver.js.map +1 -1
  119. package/dist/resolvers/TeamsMeetingsResolver.d.ts +28 -0
  120. package/dist/resolvers/TeamsMeetingsResolver.d.ts.map +1 -0
  121. package/dist/resolvers/TeamsMeetingsResolver.js +91 -0
  122. package/dist/resolvers/TeamsMeetingsResolver.js.map +1 -0
  123. package/dist/resolvers/TelephonyResolver.d.ts +26 -0
  124. package/dist/resolvers/TelephonyResolver.d.ts.map +1 -0
  125. package/dist/resolvers/TelephonyResolver.js +86 -0
  126. package/dist/resolvers/TelephonyResolver.js.map +1 -0
  127. package/dist/resolvers/TestQuerySQLResolver.d.ts +1 -1
  128. package/dist/resolvers/TestQuerySQLResolver.d.ts.map +1 -1
  129. package/dist/resolvers/TestQuerySQLResolver.js +2 -3
  130. package/dist/resolvers/TestQuerySQLResolver.js.map +1 -1
  131. package/dist/resolvers/VonageTelephonyResolver.d.ts +26 -0
  132. package/dist/resolvers/VonageTelephonyResolver.d.ts.map +1 -0
  133. package/dist/resolvers/VonageTelephonyResolver.js +86 -0
  134. package/dist/resolvers/VonageTelephonyResolver.js.map +1 -0
  135. package/dist/resolvers/meetingRecordingRegistration.d.ts +124 -0
  136. package/dist/resolvers/meetingRecordingRegistration.d.ts.map +1 -0
  137. package/dist/resolvers/meetingRecordingRegistration.js +311 -0
  138. package/dist/resolvers/meetingRecordingRegistration.js.map +1 -0
  139. package/dist/resolvers/peaksSidecar.d.ts +30 -0
  140. package/dist/resolvers/peaksSidecar.d.ts.map +1 -0
  141. package/dist/resolvers/peaksSidecar.js +51 -0
  142. package/dist/resolvers/peaksSidecar.js.map +1 -0
  143. package/dist/rest/MediaAccessKeys.d.ts +68 -0
  144. package/dist/rest/MediaAccessKeys.d.ts.map +1 -0
  145. package/dist/rest/MediaAccessKeys.js +96 -0
  146. package/dist/rest/MediaAccessKeys.js.map +1 -0
  147. package/dist/rest/MediaStreamHandler.d.ts +26 -0
  148. package/dist/rest/MediaStreamHandler.d.ts.map +1 -0
  149. package/dist/rest/MediaStreamHandler.js +195 -0
  150. package/dist/rest/MediaStreamHandler.js.map +1 -0
  151. package/dist/rest/mediaRange.d.ts +41 -0
  152. package/dist/rest/mediaRange.d.ts.map +1 -0
  153. package/dist/rest/mediaRange.js +60 -0
  154. package/dist/rest/mediaRange.js.map +1 -0
  155. package/dist/telephony/RingCentralTelephonyService.d.ts +115 -0
  156. package/dist/telephony/RingCentralTelephonyService.d.ts.map +1 -0
  157. package/dist/telephony/RingCentralTelephonyService.js +262 -0
  158. package/dist/telephony/RingCentralTelephonyService.js.map +1 -0
  159. package/dist/telephony/TeamsMeetingsRouter.d.ts +40 -0
  160. package/dist/telephony/TeamsMeetingsRouter.d.ts.map +1 -0
  161. package/dist/telephony/TeamsMeetingsRouter.js +96 -0
  162. package/dist/telephony/TeamsMeetingsRouter.js.map +1 -0
  163. package/dist/telephony/TeamsMeetingsService.d.ts +113 -0
  164. package/dist/telephony/TeamsMeetingsService.d.ts.map +1 -0
  165. package/dist/telephony/TeamsMeetingsService.js +196 -0
  166. package/dist/telephony/TeamsMeetingsService.js.map +1 -0
  167. package/dist/telephony/TwilioTelephonyRouter.d.ts +36 -0
  168. package/dist/telephony/TwilioTelephonyRouter.d.ts.map +1 -0
  169. package/dist/telephony/TwilioTelephonyRouter.js +143 -0
  170. package/dist/telephony/TwilioTelephonyRouter.js.map +1 -0
  171. package/dist/telephony/TwilioTelephonyService.d.ts +95 -0
  172. package/dist/telephony/TwilioTelephonyService.d.ts.map +1 -0
  173. package/dist/telephony/TwilioTelephonyService.js +193 -0
  174. package/dist/telephony/TwilioTelephonyService.js.map +1 -0
  175. package/dist/telephony/VonageTelephonyRouter.d.ts +41 -0
  176. package/dist/telephony/VonageTelephonyRouter.d.ts.map +1 -0
  177. package/dist/telephony/VonageTelephonyRouter.js +201 -0
  178. package/dist/telephony/VonageTelephonyRouter.js.map +1 -0
  179. package/dist/telephony/VonageTelephonyService.d.ts +90 -0
  180. package/dist/telephony/VonageTelephonyService.d.ts.map +1 -0
  181. package/dist/telephony/VonageTelephonyService.js +191 -0
  182. package/dist/telephony/VonageTelephonyService.js.map +1 -0
  183. package/dist/telephony/calendar-scheduler.d.ts +67 -0
  184. package/dist/telephony/calendar-scheduler.d.ts.map +1 -0
  185. package/dist/telephony/calendar-scheduler.js +133 -0
  186. package/dist/telephony/calendar-scheduler.js.map +1 -0
  187. package/dist/telephony/index.d.ts +29 -0
  188. package/dist/telephony/index.d.ts.map +1 -0
  189. package/dist/telephony/index.js +38 -0
  190. package/dist/telephony/index.js.map +1 -0
  191. package/dist/telephony/media-upgrade-router.d.ts +33 -0
  192. package/dist/telephony/media-upgrade-router.d.ts.map +1 -0
  193. package/dist/telephony/media-upgrade-router.js +56 -0
  194. package/dist/telephony/media-upgrade-router.js.map +1 -0
  195. package/dist/telephony/ringcentral-runtime.d.ts +14 -0
  196. package/dist/telephony/ringcentral-runtime.d.ts.map +1 -0
  197. package/dist/telephony/ringcentral-runtime.js +18 -0
  198. package/dist/telephony/ringcentral-runtime.js.map +1 -0
  199. package/dist/telephony/teams-meetings-runtime.d.ts +16 -0
  200. package/dist/telephony/teams-meetings-runtime.d.ts.map +1 -0
  201. package/dist/telephony/teams-meetings-runtime.js +20 -0
  202. package/dist/telephony/teams-meetings-runtime.js.map +1 -0
  203. package/dist/telephony/teamsAcsMediaRegistry.d.ts +69 -0
  204. package/dist/telephony/teamsAcsMediaRegistry.d.ts.map +1 -0
  205. package/dist/telephony/teamsAcsMediaRegistry.js +118 -0
  206. package/dist/telephony/teamsAcsMediaRegistry.js.map +1 -0
  207. package/dist/telephony/telephony-runtime.d.ts +14 -0
  208. package/dist/telephony/telephony-runtime.d.ts.map +1 -0
  209. package/dist/telephony/telephony-runtime.js +18 -0
  210. package/dist/telephony/telephony-runtime.js.map +1 -0
  211. package/dist/telephony/twilioMediaRegistry.d.ts +60 -0
  212. package/dist/telephony/twilioMediaRegistry.d.ts.map +1 -0
  213. package/dist/telephony/twilioMediaRegistry.js +106 -0
  214. package/dist/telephony/twilioMediaRegistry.js.map +1 -0
  215. package/dist/telephony/vonage-runtime.d.ts +14 -0
  216. package/dist/telephony/vonage-runtime.d.ts.map +1 -0
  217. package/dist/telephony/vonage-runtime.js +18 -0
  218. package/dist/telephony/vonage-runtime.js.map +1 -0
  219. package/dist/telephony/vonageMediaRegistry.d.ts +78 -0
  220. package/dist/telephony/vonageMediaRegistry.d.ts.map +1 -0
  221. package/dist/telephony/vonageMediaRegistry.js +158 -0
  222. package/dist/telephony/vonageMediaRegistry.js.map +1 -0
  223. package/package.json +88 -82
  224. package/src/__tests__/FileResolverPeaks.test.ts +64 -0
  225. package/src/__tests__/MediaAccessKeys.test.ts +68 -0
  226. package/src/__tests__/MediaStreamHandler.test.ts +91 -0
  227. package/src/__tests__/RealtimeBridgeResolver.test.ts +10 -1
  228. package/src/__tests__/RealtimeClientSessionResolver.test.ts +69 -0
  229. package/src/__tests__/RealtimeCoAgentAppAwareness.integration.test.ts +191 -0
  230. package/src/__tests__/RemoteBrowserSnapshot.test.ts +123 -0
  231. package/src/__tests__/SessionManager.test.ts +2 -0
  232. package/src/__tests__/meetingRecordingRegistration.test.ts +248 -0
  233. package/src/__tests__/search-knowledge-tags.test.ts +9 -9
  234. package/src/__tests__/teams-meetings-service.test.ts +65 -0
  235. package/src/__tests__/teamsAcsMediaRegistry.test.ts +82 -0
  236. package/src/__tests__/twilio-telephony-service.test.ts +23 -0
  237. package/src/__tests__/twilioMediaRegistry.test.ts +103 -0
  238. package/src/__tests__/vonageMediaRegistry.test.ts +180 -0
  239. package/src/__tests__/widget.test.ts +204 -0
  240. package/src/__tests__/widgetGuestElevation.test.ts +57 -0
  241. package/src/__tests__/widgetHostIdentity.test.ts +117 -0
  242. package/src/agentSessions/ReturningVisitorRecap.ts +242 -0
  243. package/src/agentSessions/SessionJanitor.ts +66 -6
  244. package/src/agentSessions/SessionManager.ts +41 -0
  245. package/src/agentSessions/index.ts +3 -1
  246. package/src/auth/magicLink/MagicLinkRouter.ts +17 -0
  247. package/src/auth/magicLink/index.ts +1 -0
  248. package/src/auth/magicLink/types.ts +26 -0
  249. package/src/config.ts +172 -38
  250. package/src/context.ts +50 -3
  251. package/src/generated/generated.ts +26726 -20464
  252. package/src/generic/ResolverBase.ts +28 -0
  253. package/src/generic/RunViewResolver.ts +4 -0
  254. package/src/index.ts +119 -3
  255. package/src/integration/CustomColumnPromoter.ts +6 -0
  256. package/src/realtimeWidget/WidgetRouter.ts +204 -0
  257. package/src/realtimeWidget/WidgetSessionService.ts +714 -0
  258. package/src/realtimeWidget/host-identity.ts +84 -0
  259. package/src/realtimeWidget/index.ts +15 -0
  260. package/src/realtimeWidget/visitorIdentity.ts +258 -0
  261. package/src/realtimeWidget/widgetCore.ts +231 -0
  262. package/src/realtimeWidget/widgetGuestElevation.ts +115 -0
  263. package/src/resolvers/ComponentRegistryResolver.ts +36 -10
  264. package/src/resolvers/EntityPermissionResolver.ts +1 -2
  265. package/src/resolvers/FileResolver.ts +199 -1
  266. package/src/resolvers/QueryResolver.ts +33 -19
  267. package/src/resolvers/QuerySystemUserResolver.ts +14 -10
  268. package/src/resolvers/RealtimeBridgeResolver.ts +36 -4
  269. package/src/resolvers/RealtimeClientSessionResolver.ts +383 -9
  270. package/src/resolvers/RemoteBrowserActionResolver.ts +18 -2
  271. package/src/resolvers/RingCentralTelephonyResolver.ts +64 -0
  272. package/src/resolvers/RunAIAgentResolver.ts +60 -15
  273. package/src/resolvers/SearchKnowledgeResolver.ts +2 -0
  274. package/src/resolvers/TeamsMeetingsResolver.ts +68 -0
  275. package/src/resolvers/TelephonyResolver.ts +63 -0
  276. package/src/resolvers/TestQuerySQLResolver.ts +2 -3
  277. package/src/resolvers/VonageTelephonyResolver.ts +63 -0
  278. package/src/resolvers/meetingRecordingRegistration.ts +432 -0
  279. package/src/resolvers/peaksSidecar.ts +52 -0
  280. package/src/rest/MediaAccessKeys.ts +121 -0
  281. package/src/rest/MediaStreamHandler.ts +223 -0
  282. package/src/rest/mediaRange.ts +76 -0
  283. package/src/telephony/RingCentralTelephonyService.ts +342 -0
  284. package/src/telephony/TeamsMeetingsRouter.ts +124 -0
  285. package/src/telephony/TeamsMeetingsService.ts +268 -0
  286. package/src/telephony/TwilioTelephonyRouter.ts +184 -0
  287. package/src/telephony/TwilioTelephonyService.ts +261 -0
  288. package/src/telephony/VonageTelephonyRouter.ts +239 -0
  289. package/src/telephony/VonageTelephonyService.ts +259 -0
  290. package/src/telephony/calendar-scheduler.ts +176 -0
  291. package/src/telephony/index.ts +43 -0
  292. package/src/telephony/media-upgrade-router.ts +62 -0
  293. package/src/telephony/ringcentral-runtime.ts +22 -0
  294. package/src/telephony/teams-meetings-runtime.ts +24 -0
  295. package/src/telephony/teamsAcsMediaRegistry.ts +152 -0
  296. package/src/telephony/telephony-runtime.ts +22 -0
  297. package/src/telephony/twilioMediaRegistry.ts +137 -0
  298. package/src/telephony/vonage-runtime.ts +22 -0
  299. package/src/telephony/vonageMediaRegistry.ts +200 -0
  300. package/dist/agents/skip-agent.d.ts +0 -111
  301. package/dist/agents/skip-agent.d.ts.map +0 -1
  302. package/dist/agents/skip-agent.js +0 -1487
  303. package/dist/agents/skip-agent.js.map +0 -1
  304. package/dist/agents/skip-sdk.d.ts +0 -261
  305. package/dist/agents/skip-sdk.d.ts.map +0 -1
  306. package/dist/agents/skip-sdk.js +0 -909
  307. package/dist/agents/skip-sdk.js.map +0 -1
  308. package/src/agents/skip-agent.ts +0 -1594
  309. package/src/agents/skip-sdk.ts +0 -1210
@@ -0,0 +1,64 @@
1
+ /**
2
+ * @fileoverview GraphQL surface for OUTBOUND RingCentral telephony: `PlaceRingCentralCall` rings a real
3
+ * phone from an agent identity and connects the pinned agent. Thin — it authorizes the caller, then
4
+ * delegates to the startup-constructed {@link RingCentralTelephonyService} (which owns the bridge
5
+ * orchestration + the shared media registry). Inbound calls arrive via the public
6
+ * `POST /telephony/ringcentral/webhook` notification, not GraphQL.
7
+ *
8
+ * @module @memberjunction/server
9
+ */
10
+
11
+ import { Resolver, Mutation, Arg, Ctx, ObjectType, Field } from 'type-graphql';
12
+ import { LogError, IMetadataProvider } from '@memberjunction/core';
13
+ import { AppContext } from '../types.js';
14
+ import { ResolverBase } from '../generic/ResolverBase.js';
15
+ import { GetReadWriteProvider } from '../util.js';
16
+ import { GetRingCentralTelephonyService } from '../telephony/ringcentral-runtime.js';
17
+
18
+ /** Result of an outbound RingCentral place-call attempt. */
19
+ @ObjectType()
20
+ export class PlaceRingCentralCallResult {
21
+ @Field(() => Boolean)
22
+ Success: boolean;
23
+
24
+ @Field(() => String, { nullable: true })
25
+ ErrorMessage?: string;
26
+
27
+ /** The placed RingCentral telephony session id (the bridge's external connection id). */
28
+ @Field(() => String)
29
+ SessionId: string;
30
+ }
31
+
32
+ @Resolver()
33
+ export class RingCentralTelephonyResolver extends ResolverBase {
34
+ /**
35
+ * Places an outbound call from the given agent identity (its phone number is the caller-id) to a
36
+ * destination number, connecting the pinned agent over the realtime bridge. Returns the telephony
37
+ * session id.
38
+ */
39
+ @Mutation(() => PlaceRingCentralCallResult)
40
+ async PlaceRingCentralCall(
41
+ @Arg('agentIdentityId', () => String) agentIdentityId: string,
42
+ @Arg('toNumber', () => String) toNumber: string,
43
+ @Ctx() context: AppContext = {} as AppContext,
44
+ ): Promise<PlaceRingCentralCallResult> {
45
+ const failure = (msg: string): PlaceRingCentralCallResult => ({ Success: false, ErrorMessage: msg, SessionId: '' });
46
+ try {
47
+ const user = this.GetUserFromPayload(context.userPayload);
48
+ if (!user) {
49
+ return failure('Unable to determine current user.');
50
+ }
51
+ const service = GetRingCentralTelephonyService();
52
+ if (!service) {
53
+ return failure('RingCentral telephony is not configured on this server.');
54
+ }
55
+ const provider = GetReadWriteProvider(context.providers) as unknown as IMetadataProvider;
56
+ const sessionId = await service.PlaceOutboundCall(agentIdentityId, toNumber, user, provider);
57
+ return { Success: true, SessionId: sessionId };
58
+ } catch (error) {
59
+ const msg = error instanceof Error ? error.message : String(error);
60
+ LogError(`PlaceRingCentralCall failed: ${msg}`);
61
+ return failure(msg);
62
+ }
63
+ }
64
+ }
@@ -12,6 +12,7 @@ import { PUSH_STATUS_UPDATES_TOPIC } from '../generic/PushStatusResolver.js';
12
12
  import { startLivenessPulse } from '../generic/FireAndForgetHeartbeat.js';
13
13
  import { RequireSystemUser } from '../directives/RequireSystemUser.js';
14
14
  import { GetReadWriteProvider } from '../util.js';
15
+ import { resolveWidgetGuestRunContext, elevateUserPayload } from '../realtimeWidget/widgetGuestElevation.js';
15
16
  import { SafeJSONParse, UUIDsEqual } from '@memberjunction/global';
16
17
  import { GetAttachmentService } from '@memberjunction/aiengine';
17
18
  import { NotificationEngine } from '@memberjunction/notifications';
@@ -376,7 +377,12 @@ export class RunAIAgentResolver extends ResolverBase {
376
377
  conversationId?: string,
377
378
  /** Optional external ref the caller can read to observe the agent run as it becomes available
378
379
  * (used by the fire-and-forget liveness pulse to enrich heartbeats with the run id/status). */
379
- runRef?: { current: MJAIAgentRunEntityExtended | null }
380
+ runRef?: { current: MJAIAgentRunEntityExtended | null },
381
+ /** Per-request Plan Mode toggle — threaded into ExecuteAgentParams.planMode (root-agent HITL gate). */
382
+ planMode?: boolean,
383
+ /** Skill IDs the user requested (via `/skill-name`) — threaded into ExecuteAgentParams.requestedSkillIDs.
384
+ * The framework intersects them with the agent's accepted skills AND the user's Run permission. */
385
+ requestedSkillIDs?: string[]
380
386
  ): Promise<AIAgentRunResult> {
381
387
  const startTime = Date.now();
382
388
 
@@ -428,6 +434,8 @@ export class RunAIAgentResolver extends ResolverBase {
428
434
  lastRunId: lastRunId,
429
435
  autoPopulateLastRunPayload: autoPopulateLastRunPayload,
430
436
  configurationId: configurationId,
437
+ planMode: planMode,
438
+ requestedSkillIDs: requestedSkillIDs,
431
439
  data: parsedData,
432
440
  context: {
433
441
  dataSource: dataSource
@@ -614,7 +622,12 @@ export class RunAIAgentResolver extends ResolverBase {
614
622
  @Arg('createNotification', { nullable: true }) createNotification?: boolean,
615
623
  @Arg('sourceArtifactId', { nullable: true }) sourceArtifactId?: string,
616
624
  @Arg('sourceArtifactVersionId', { nullable: true }) sourceArtifactVersionId?: string,
617
- @Arg('fireAndForget', { nullable: true }) fireAndForget?: boolean
625
+ @Arg('fireAndForget', { nullable: true }) fireAndForget?: boolean,
626
+ /** Per-request Plan Mode toggle — symmetric with RunAIAgentFromConversationDetail. */
627
+ @Arg('planMode', { nullable: true }) planMode?: boolean,
628
+ /** Skill IDs the user requested — symmetric with RunAIAgentFromConversationDetail. Intersected
629
+ * server-side with the agent's accepted skills AND the user's Run permission. */
630
+ @Arg('requestedSkillIDs', () => [String], { nullable: true }) requestedSkillIDs?: string[]
618
631
  ): Promise<AIAgentRunResult> {
619
632
  // Check API key scope authorization for agent execution
620
633
  await this.CheckAPIKeyScopeAuthorization('agent:execute', agentId, userPayload);
@@ -628,7 +641,7 @@ export class RunAIAgentResolver extends ResolverBase {
628
641
  p, dataSource, agentId, userPayload, messagesJson, sessionId, pubSub,
629
642
  data, payload, lastRunId, autoPopulateLastRunPayload, configurationId,
630
643
  conversationDetailId, createArtifacts || false, createNotification || false,
631
- sourceArtifactId, sourceArtifactVersionId
644
+ sourceArtifactId, sourceArtifactVersionId, undefined /*conversationId*/, planMode, requestedSkillIDs
632
645
  );
633
646
 
634
647
  LogStatus(`🔥 Fire-and-forget: Agent ${agentId} execution started in background for session ${sessionId}`);
@@ -658,7 +671,11 @@ export class RunAIAgentResolver extends ResolverBase {
658
671
  createArtifacts || false,
659
672
  createNotification || false,
660
673
  sourceArtifactId,
661
- sourceArtifactVersionId
674
+ sourceArtifactVersionId,
675
+ undefined, // conversationId (not pre-resolved on this path)
676
+ undefined, // runRef
677
+ planMode,
678
+ requestedSkillIDs
662
679
  );
663
680
  }
664
681
 
@@ -684,7 +701,11 @@ export class RunAIAgentResolver extends ResolverBase {
684
701
  @Arg('createArtifacts', { nullable: true }) createArtifacts?: boolean,
685
702
  @Arg('createNotification', { nullable: true }) createNotification?: boolean,
686
703
  @Arg('sourceArtifactId', { nullable: true }) sourceArtifactId?: string,
687
- @Arg('sourceArtifactVersionId', { nullable: true }) sourceArtifactVersionId?: string
704
+ @Arg('sourceArtifactVersionId', { nullable: true }) sourceArtifactVersionId?: string,
705
+ /** Per-request Plan Mode toggle — symmetric with the other run mutations. */
706
+ @Arg('planMode', { nullable: true }) planMode?: boolean,
707
+ /** User-requested skill IDs — symmetric with the other run mutations. */
708
+ @Arg('requestedSkillIDs', () => [String], { nullable: true }) requestedSkillIDs?: string[]
688
709
  ): Promise<AIAgentRunResult> {
689
710
  const p = GetReadWriteProvider(providers);
690
711
  return this.executeAIAgent(
@@ -705,7 +726,11 @@ export class RunAIAgentResolver extends ResolverBase {
705
726
  createArtifacts || false,
706
727
  createNotification || false,
707
728
  sourceArtifactId,
708
- sourceArtifactVersionId
729
+ sourceArtifactVersionId,
730
+ undefined, // conversationId (not pre-resolved on this path)
731
+ undefined, // runRef
732
+ planMode,
733
+ requestedSkillIDs
709
734
  );
710
735
  }
711
736
 
@@ -932,7 +957,9 @@ export class RunAIAgentResolver extends ResolverBase {
932
957
  @Arg('createNotification', { nullable: true }) createNotification?: boolean,
933
958
  @Arg('sourceArtifactId', { nullable: true }) sourceArtifactId?: string,
934
959
  @Arg('sourceArtifactVersionId', { nullable: true }) sourceArtifactVersionId?: string,
935
- @Arg('fireAndForget', { nullable: true }) fireAndForget?: boolean
960
+ @Arg('fireAndForget', { nullable: true }) fireAndForget?: boolean,
961
+ @Arg('planMode', { nullable: true }) planMode?: boolean,
962
+ @Arg('requestedSkillIDs', () => [String], { nullable: true }) requestedSkillIDs?: string[]
936
963
  ): Promise<AIAgentRunResult> {
937
964
  // Check API key scope authorization for agent execution
938
965
  await this.CheckAPIKeyScopeAuthorization('agent:execute', agentId, userPayload);
@@ -948,6 +975,17 @@ export class RunAIAgentResolver extends ResolverBase {
948
975
  };
949
976
  }
950
977
 
978
+ // PUBLIC WEB-WIDGET PRIVILEGED DISPATCH (public-web-widget.md Phase 0): when the request is a
979
+ // widget guest, the agent runs under a TRUSTED SERVER PRINCIPAL and the agent id is taken
980
+ // AUTHORITATIVELY from the widget instance (never the client-supplied arg) — so a guest needs
981
+ // no grants to WRITE the AI run entities and cannot run an arbitrary agent under elevation.
982
+ // Conversation OWNERSHIP is still enforced under the guest principal below: the guest loads its
983
+ // own ConversationDetail through the Widget Guest RLS filters, so a detail id from another
984
+ // session resolves to "not found" before any elevated work happens.
985
+ const widgetElevation = await resolveWidgetGuestRunContext(userPayload, p);
986
+ const effectiveAgentId = widgetElevation ? widgetElevation.pinnedAgentId : agentId;
987
+ const effectiveUserPayload = widgetElevation ? elevateUserPayload(userPayload, widgetElevation.elevatedUser) : userPayload;
988
+
951
989
  try {
952
990
  // LATENCY OPTIMIZATION (Opt #2 + #3): Load ConversationDetail once here to extract
953
991
  // conversationId, then pass it downstream. Previously this record was loaded multiple
@@ -978,13 +1016,13 @@ export class RunAIAgentResolver extends ResolverBase {
978
1016
  // Fire-and-forget mode: start execution in background, return immediately.
979
1017
  // The client will receive the result via WebSocket PubSub completion event.
980
1018
  this.executeAgentInBackground(
981
- p, dataSource, agentId, userPayload, messagesJson, sessionId, pubSub,
1019
+ p, dataSource, effectiveAgentId, effectiveUserPayload, messagesJson, sessionId, pubSub,
982
1020
  data, payload, lastRunId, autoPopulateLastRunPayload, configurationId,
983
1021
  conversationDetailId, createArtifacts || false, createNotification || false,
984
- sourceArtifactId, sourceArtifactVersionId, conversationId
1022
+ sourceArtifactId, sourceArtifactVersionId, conversationId, planMode, requestedSkillIDs
985
1023
  );
986
1024
 
987
- LogStatus(`🔥 Fire-and-forget: Agent ${agentId} execution started in background for session ${sessionId}`);
1025
+ LogStatus(`🔥 Fire-and-forget: Agent ${effectiveAgentId} execution started in background for session ${sessionId}`);
988
1026
 
989
1027
  return {
990
1028
  success: true,
@@ -996,8 +1034,8 @@ export class RunAIAgentResolver extends ResolverBase {
996
1034
  return this.executeAIAgent(
997
1035
  p,
998
1036
  dataSource,
999
- agentId,
1000
- userPayload,
1037
+ effectiveAgentId,
1038
+ effectiveUserPayload,
1001
1039
  messagesJson,
1002
1040
  sessionId,
1003
1041
  pubSub,
@@ -1012,7 +1050,10 @@ export class RunAIAgentResolver extends ResolverBase {
1012
1050
  createNotification || false,
1013
1051
  sourceArtifactId,
1014
1052
  sourceArtifactVersionId,
1015
- conversationId // LATENCY OPT #2: pass pre-resolved conversationId
1053
+ conversationId, // LATENCY OPT #2: pass pre-resolved conversationId
1054
+ undefined, // runRef
1055
+ planMode,
1056
+ requestedSkillIDs
1016
1057
  );
1017
1058
  } catch (error) {
1018
1059
  const errorMessage = (error as Error).message || 'Unknown error loading conversation history';
@@ -1227,7 +1268,11 @@ export class RunAIAgentResolver extends ResolverBase {
1227
1268
  sourceArtifactId?: string,
1228
1269
  sourceArtifactVersionId?: string,
1229
1270
  /** LATENCY OPT #2: Pre-resolved conversationId avoids redundant DB load in AgentRunner */
1230
- conversationId?: string
1271
+ conversationId?: string,
1272
+ /** Per-request Plan Mode toggle — threaded through to ExecuteAgentParams.planMode. */
1273
+ planMode?: boolean,
1274
+ /** Skill IDs the user requested — threaded through to ExecuteAgentParams.requestedSkillIDs. */
1275
+ requestedSkillIDs?: string[]
1231
1276
  ): void {
1232
1277
  // Ref the liveness pulse reads to enrich heartbeats once the run is created.
1233
1278
  const runRef: { current: MJAIAgentRunEntityExtended | null } = { current: null };
@@ -1245,7 +1290,7 @@ export class RunAIAgentResolver extends ResolverBase {
1245
1290
  p, dataSource, agentId, userPayload, messagesJson, sessionId, pubSub,
1246
1291
  data, payload, undefined, lastRunId, autoPopulateLastRunPayload,
1247
1292
  configurationId, conversationDetailId, createArtifacts, createNotification,
1248
- sourceArtifactId, sourceArtifactVersionId, conversationId, runRef
1293
+ sourceArtifactId, sourceArtifactVersionId, conversationId, runRef, planMode, requestedSkillIDs
1249
1294
  ).catch((error: unknown) => {
1250
1295
  // Background execution failed unexpectedly (executeAIAgent has its own try-catch,
1251
1296
  // so this would only fire for truly unexpected errors).
@@ -213,6 +213,7 @@ export class SearchKnowledgeResolver extends ResolverBase {
213
213
  ): Promise<SearchKnowledgeResult> {
214
214
  const startTime = Date.now();
215
215
  try {
216
+ await this.CheckAPIKeyScopeAuthorization('search:execute', '*', userPayload);
216
217
  const currentUser = this.GetUserFromPayload(userPayload);
217
218
  if (!currentUser) {
218
219
  return this.errorResult('Unable to determine current user', startTime);
@@ -400,6 +401,7 @@ export class SearchKnowledgeResolver extends ResolverBase {
400
401
  ): Promise<SearchKnowledgeResult> {
401
402
  const startTime = Date.now();
402
403
  try {
404
+ await this.CheckAPIKeyScopeAuthorization('search:execute', '*', userPayload);
403
405
  const currentUser = this.GetUserFromPayload(userPayload);
404
406
  if (!currentUser) {
405
407
  return this.errorResult('Unable to determine current user', startTime);
@@ -0,0 +1,68 @@
1
+ /**
2
+ * @fileoverview GraphQL surface for Teams meeting joins: `StartTeamsMeetingSession` has an agent identity
3
+ * join a Teams meeting by URL and connects the pinned agent over the realtime bridge. Thin — it authorizes
4
+ * the caller, then delegates to the startup-constructed {@link TeamsMeetingsService} (which owns the bridge
5
+ * orchestration + the shared ACS media registry). Roster/call-ended updates arrive via the public
6
+ * `POST /meetings/teams/notifications` Graph webhook, not GraphQL.
7
+ *
8
+ * Mirrors `TelephonyResolver.ts` (the Twilio `PlaceTwilioCall` equivalent).
9
+ *
10
+ * @module @memberjunction/server
11
+ */
12
+
13
+ import { Resolver, Mutation, Arg, Ctx, ObjectType, Field } from 'type-graphql';
14
+ import { LogError, IMetadataProvider } from '@memberjunction/core';
15
+ import { AppContext } from '../types.js';
16
+ import { ResolverBase } from '../generic/ResolverBase.js';
17
+ import { GetReadWriteProvider } from '../util.js';
18
+ import { GetTeamsMeetingsService } from '../telephony/teams-meetings-runtime.js';
19
+
20
+ /** Result of a Teams meeting join attempt. */
21
+ @ObjectType()
22
+ export class StartTeamsMeetingResult {
23
+ @Field(() => Boolean)
24
+ Success: boolean;
25
+
26
+ @Field(() => String, { nullable: true })
27
+ ErrorMessage?: string;
28
+
29
+ /** The Graph call id the bot joined (the bridge's external connection id), when successful. */
30
+ @Field(() => String)
31
+ CallId: string;
32
+ }
33
+
34
+ @Resolver()
35
+ export class TeamsMeetingsResolver extends ResolverBase {
36
+ /**
37
+ * Has the given agent identity join a Teams meeting by URL, connecting the pinned agent over the realtime
38
+ * bridge. Returns the Graph call id.
39
+ */
40
+ @Mutation(() => StartTeamsMeetingResult)
41
+ async StartTeamsMeetingSession(
42
+ @Arg('agentIdentityId', () => String) agentIdentityId: string,
43
+ @Arg('joinUrl', () => String) joinUrl: string,
44
+ @Ctx() context: AppContext = {} as AppContext,
45
+ ): Promise<StartTeamsMeetingResult> {
46
+ const failure = (msg: string): StartTeamsMeetingResult => ({ Success: false, ErrorMessage: msg, CallId: '' });
47
+ try {
48
+ const user = this.GetUserFromPayload(context.userPayload);
49
+ if (!user) {
50
+ return failure('Unable to determine current user.');
51
+ }
52
+ const service = GetTeamsMeetingsService();
53
+ if (!service) {
54
+ return failure('Teams meetings are not configured on this server.');
55
+ }
56
+ const provider = GetReadWriteProvider(context.providers) as unknown as IMetadataProvider;
57
+ const result = await service.JoinMeetingByUrl(agentIdentityId, joinUrl, user, provider);
58
+ if (!result.accepted) {
59
+ return failure(result.reason ?? 'The meeting join was not accepted.');
60
+ }
61
+ return { Success: true, CallId: result.callId ?? '' };
62
+ } catch (error) {
63
+ const msg = error instanceof Error ? error.message : String(error);
64
+ LogError(`StartTeamsMeetingSession failed: ${msg}`);
65
+ return failure(msg);
66
+ }
67
+ }
68
+ }
@@ -0,0 +1,63 @@
1
+ /**
2
+ * @fileoverview GraphQL surface for OUTBOUND telephony: `PlaceTwilioCall` rings a real phone from
3
+ * an agent identity and connects the pinned agent. Thin — it authorizes the caller, then delegates to
4
+ * the startup-constructed {@link TwilioTelephonyService} (which owns the bridge orchestration + the
5
+ * shared media registry). Inbound calls arrive via the public `POST /telephony/twilio/voice` webhook,
6
+ * not GraphQL.
7
+ *
8
+ * @module @memberjunction/server
9
+ */
10
+
11
+ import { Resolver, Mutation, Arg, Ctx, ObjectType, Field } from 'type-graphql';
12
+ import { LogError, IMetadataProvider } from '@memberjunction/core';
13
+ import { AppContext } from '../types.js';
14
+ import { ResolverBase } from '../generic/ResolverBase.js';
15
+ import { GetReadWriteProvider } from '../util.js';
16
+ import { GetTwilioTelephonyService } from '../telephony/telephony-runtime.js';
17
+
18
+ /** Result of an outbound place-call attempt. */
19
+ @ObjectType()
20
+ export class PlaceCallResult {
21
+ @Field(() => Boolean)
22
+ Success: boolean;
23
+
24
+ @Field(() => String, { nullable: true })
25
+ ErrorMessage?: string;
26
+
27
+ /** The placed Twilio Call SID (the bridge's external connection id). */
28
+ @Field(() => String)
29
+ CallSid: string;
30
+ }
31
+
32
+ @Resolver()
33
+ export class TelephonyResolver extends ResolverBase {
34
+ /**
35
+ * Places an outbound call from the given agent identity (its phone number is the caller-id) to a
36
+ * destination number, connecting the pinned agent over the realtime bridge. Returns the Call SID.
37
+ */
38
+ @Mutation(() => PlaceCallResult)
39
+ async PlaceTwilioCall(
40
+ @Arg('agentIdentityId', () => String) agentIdentityId: string,
41
+ @Arg('toNumber', () => String) toNumber: string,
42
+ @Ctx() context: AppContext = {} as AppContext,
43
+ ): Promise<PlaceCallResult> {
44
+ const failure = (msg: string): PlaceCallResult => ({ Success: false, ErrorMessage: msg, CallSid: '' });
45
+ try {
46
+ const user = this.GetUserFromPayload(context.userPayload);
47
+ if (!user) {
48
+ return failure('Unable to determine current user.');
49
+ }
50
+ const service = GetTwilioTelephonyService();
51
+ if (!service) {
52
+ return failure('Twilio telephony is not configured on this server.');
53
+ }
54
+ const provider = GetReadWriteProvider(context.providers) as unknown as IMetadataProvider;
55
+ const callSid = await service.PlaceOutboundCall(agentIdentityId, toNumber, user, provider);
56
+ return { Success: true, CallSid: callSid };
57
+ } catch (error) {
58
+ const msg = error instanceof Error ? error.message : String(error);
59
+ LogError(`PlaceTwilioCall failed: ${msg}`);
60
+ return failure(msg);
61
+ }
62
+ }
63
+ }
@@ -2,7 +2,6 @@ import { Arg, Ctx, Field, InputType, Int, ObjectType, Query, Resolver } from 'ty
2
2
  import { GraphQLJSONObject } from 'graphql-type-json';
3
3
  import { RunQuery, IRunQueryProvider, LogError, LogStatus, QueryExecutionSpec } from '@memberjunction/core';
4
4
  import { AppContext } from '../types.js';
5
- import { RequireSystemUser } from '../directives/RequireSystemUser.js';
6
5
  import { GetReadOnlyProvider } from '../util.js';
7
6
  import { ResolverBase } from '../generic/ResolverBase.js';
8
7
 
@@ -85,7 +84,7 @@ export class TestQuerySQLResult {
85
84
  * enabling external systems (e.g., Skip-Brain) to test query SQL before saving to the database.
86
85
  *
87
86
  * Security:
88
- * - Requires system user authentication (@RequireSystemUser)
87
+ * - Requires `query:test` scope for API key users (no-op for JWT auth)
89
88
  * - Uses read-only database connection (no mutation possible)
90
89
  * - Enforces MaxRows limit (default 100) to prevent unbounded queries
91
90
  *
@@ -93,7 +92,6 @@ export class TestQuerySQLResult {
93
92
  */
94
93
  @Resolver()
95
94
  export class TestQuerySQLResolver extends ResolverBase {
96
- @RequireSystemUser()
97
95
  @Query(() => TestQuerySQLResult, {
98
96
  description: 'Test transient SQL with full composition + Nunjucks template processing without requiring a saved query'
99
97
  })
@@ -102,6 +100,7 @@ export class TestQuerySQLResolver extends ResolverBase {
102
100
  @Ctx() context: AppContext
103
101
  ): Promise<TestQuerySQLResult> {
104
102
  try {
103
+ await this.CheckAPIKeyScopeAuthorization('query:test', '*', context.userPayload);
105
104
  // Use read-only provider for security — no mutation possible
106
105
  const provider = GetReadOnlyProvider(context.providers, { allowFallbackToReadWrite: false });
107
106
  if (!provider) {
@@ -0,0 +1,63 @@
1
+ /**
2
+ * @fileoverview GraphQL surface for OUTBOUND Vonage telephony: `PlaceVonageCall` rings a real phone from
3
+ * an agent identity and connects the pinned agent. Thin — it authorizes the caller, then delegates to
4
+ * the startup-constructed {@link VonageTelephonyService} (which owns the bridge orchestration + the
5
+ * shared media registry). Inbound calls arrive via the public `POST /telephony/vonage/answer` webhook,
6
+ * not GraphQL.
7
+ *
8
+ * @module @memberjunction/server
9
+ */
10
+
11
+ import { Resolver, Mutation, Arg, Ctx, ObjectType, Field } from 'type-graphql';
12
+ import { LogError, IMetadataProvider } from '@memberjunction/core';
13
+ import { AppContext } from '../types.js';
14
+ import { ResolverBase } from '../generic/ResolverBase.js';
15
+ import { GetReadWriteProvider } from '../util.js';
16
+ import { GetVonageTelephonyService } from '../telephony/vonage-runtime.js';
17
+
18
+ /** Result of an outbound place-call attempt. */
19
+ @ObjectType()
20
+ export class PlaceVonageCallResult {
21
+ @Field(() => Boolean)
22
+ Success: boolean;
23
+
24
+ @Field(() => String, { nullable: true })
25
+ ErrorMessage?: string;
26
+
27
+ /** The placed Vonage call UUID (the bridge's external connection id). */
28
+ @Field(() => String)
29
+ CallId: string;
30
+ }
31
+
32
+ @Resolver()
33
+ export class VonageTelephonyResolver extends ResolverBase {
34
+ /**
35
+ * Places an outbound call from the given agent identity (its phone number is the caller-id) to a
36
+ * destination number, connecting the pinned agent over the realtime bridge. Returns the call UUID.
37
+ */
38
+ @Mutation(() => PlaceVonageCallResult)
39
+ async PlaceVonageCall(
40
+ @Arg('agentIdentityId', () => String) agentIdentityId: string,
41
+ @Arg('toNumber', () => String) toNumber: string,
42
+ @Ctx() context: AppContext = {} as AppContext,
43
+ ): Promise<PlaceVonageCallResult> {
44
+ const failure = (msg: string): PlaceVonageCallResult => ({ Success: false, ErrorMessage: msg, CallId: '' });
45
+ try {
46
+ const user = this.GetUserFromPayload(context.userPayload);
47
+ if (!user) {
48
+ return failure('Unable to determine current user.');
49
+ }
50
+ const service = GetVonageTelephonyService();
51
+ if (!service) {
52
+ return failure('Vonage telephony is not configured on this server.');
53
+ }
54
+ const provider = GetReadWriteProvider(context.providers) as unknown as IMetadataProvider;
55
+ const callId = await service.PlaceOutboundCall(agentIdentityId, toNumber, user, provider);
56
+ return { Success: true, CallId: callId };
57
+ } catch (error) {
58
+ const msg = error instanceof Error ? error.message : String(error);
59
+ LogError(`PlaceVonageCall failed: ${msg}`);
60
+ return failure(msg);
61
+ }
62
+ }
63
+ }