@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,193 @@
1
+ /**
2
+ * @fileoverview Orchestrates Twilio telephony bridge sessions (inbound + outbound) for MJAPI.
3
+ *
4
+ * This is the composition layer between the carrier ingress (the public webhook + the Media-Streams
5
+ * WSS) and the ONE unified realtime-agent pathway. It does NOT re-implement any bridge logic: it
6
+ * resolves the Twilio provider + the agent identity, opens a server-side realtime session via the
7
+ * agent layer's `CreateBridgeRealtimeSession` factory, binds `RealTwilioBindings` (real REST client +
8
+ * the per-call media registry) onto the driver, and hands everything to
9
+ * `AIBridgeEngine.StartBridgeSession` — exactly the seam the LiveKit room coordinator uses.
10
+ *
11
+ * Collaborators are injected (engine, session factory, session manager) so the resolution/branching
12
+ * logic is unit-testable with fakes; the actual call placement + media flow are live-only (real Twilio
13
+ * credentials + a publicly reachable stream URL — see telephony-vendor-bindings.md T1).
14
+ *
15
+ * @module @memberjunction/server/telephony
16
+ */
17
+ import { RunView, LogError } from '@memberjunction/core';
18
+ import { AIBridgeEngine } from '@memberjunction/ai-bridge-server';
19
+ import { CreateBridgeRealtimeSession } from '@memberjunction/ai-agents';
20
+ import { DIRECTION_CONFIG_KEY, FROM_NUMBER_CONFIG_KEY, INBOUND_CALL_ID_CONFIG_KEY, } from '@memberjunction/ai-bridge-base';
21
+ import { TwilioCallSdk, RealTwilioBindings, RealTwilioRestClient } from '@memberjunction/ai-bridge-twilio';
22
+ import { SessionManager } from '../agentSessions/SessionManager.js';
23
+ const TWILIO_PROVIDER_DRIVER = 'TwilioBridge';
24
+ const AGENT_IDENTITY_ENTITY = 'MJ: AI Bridge Agent Identities';
25
+ const PHONE_IDENTITY_TYPE = 'PhoneNumber';
26
+ /**
27
+ * Starts Twilio bridge sessions. One instance per server, constructed alongside the telephony router and
28
+ * sharing the {@link TwilioCallMediaRegistry} with the Media-Streams WSS server.
29
+ */
30
+ export class TwilioTelephonyService {
31
+ constructor(config, registry, deps = {}) {
32
+ this.config = config;
33
+ this.registry = registry;
34
+ this.rest = new RealTwilioRestClient({
35
+ AccountSid: config.accountSid,
36
+ AuthToken: config.authToken,
37
+ ApiKeySid: config.apiKeySid,
38
+ ApiKeySecret: config.apiKeySecret,
39
+ });
40
+ this.engine = deps.engine ?? AIBridgeEngine.Instance;
41
+ this.sessionFactory = deps.sessionFactory ?? CreateBridgeRealtimeSession;
42
+ this.sessionManager = deps.sessionManager ?? new SessionManager();
43
+ }
44
+ /**
45
+ * Resolves the dialed DID to a pinned agent and starts an INBOUND bridge session. The bound
46
+ * `RealTwilioBindings` will accept the Media-Streams socket (opened by the webhook's TwiML) for the
47
+ * Call SID. Returns `{ accepted:false }` (never throws) when no agent identity matches the DID, so
48
+ * the webhook can answer with a polite "no agent" message instead of a 500.
49
+ */
50
+ async HandleInboundCall(input, contextUser, provider) {
51
+ try {
52
+ const identity = await this.resolveAgentIdentityByPhone(input.to, contextUser);
53
+ if (!identity) {
54
+ return { accepted: false, reason: `No active agent identity for dialed number '${input.to}'.` };
55
+ }
56
+ this.registry.RegisterCall(input.callSid);
57
+ await this.startBridge({
58
+ agentID: identity.AgentID,
59
+ direction: 'Inbound',
60
+ address: input.from,
61
+ inboundCallId: input.callSid,
62
+ contextUser,
63
+ provider,
64
+ });
65
+ return { accepted: true };
66
+ }
67
+ catch (e) {
68
+ LogError(`[Telephony][Twilio] inbound call ${input.callSid} failed: ${e instanceof Error ? e.message : String(e)}`);
69
+ return { accepted: false, reason: 'Internal error starting the agent.' };
70
+ }
71
+ }
72
+ /**
73
+ * Places an OUTBOUND call from a given agent identity to a destination number. The bound
74
+ * `RealTwilioBindings.createCall` issues the Twilio REST `POST /Calls` with the `<Connect><Stream>`
75
+ * TwiML; the returned Call SID is the bridge's external connection id.
76
+ *
77
+ * @returns The placed Call SID.
78
+ */
79
+ async PlaceOutboundCall(agentIdentityId, toNumber, contextUser, provider) {
80
+ const identity = await this.loadAgentIdentity(agentIdentityId, contextUser, provider);
81
+ if (!identity) {
82
+ throw new Error(`Agent identity '${agentIdentityId}' not found or inactive.`);
83
+ }
84
+ const session = await this.startBridge({
85
+ agentID: identity.AgentID,
86
+ direction: 'Outbound',
87
+ address: toNumber,
88
+ fromNumber: identity.IdentityValue,
89
+ contextUser,
90
+ provider,
91
+ });
92
+ return session.RoomKey ?? '';
93
+ }
94
+ // ── internals ────────────────────────────────────────────────────────────────
95
+ /** Shared inbound/outbound bridge-start: resolve provider, open the realtime session, bind the SDK, start. */
96
+ async startBridge(args) {
97
+ await this.engine.Config(false, args.contextUser, args.provider);
98
+ const twilioProvider = this.resolveProvider();
99
+ const agentSession = await this.sessionManager.CreateSession({ agentID: args.agentID, userID: args.contextUser.ID }, args.contextUser, args.provider);
100
+ const realtimeSession = await this.sessionFactory({
101
+ AgentID: args.agentID,
102
+ TargetAgentID: args.agentID,
103
+ ContextUser: args.contextUser,
104
+ MetadataProvider: args.provider,
105
+ AgentSessionID: agentSession.ID,
106
+ RoomName: args.address,
107
+ });
108
+ const active = await this.engine.StartBridgeSession({
109
+ AgentSessionID: agentSession.ID,
110
+ AgentID: args.agentID,
111
+ TargetAgentID: args.agentID,
112
+ Provider: twilioProvider,
113
+ RealtimeSession: realtimeSession,
114
+ Address: args.address,
115
+ Direction: args.direction,
116
+ Configuration: this.buildSessionConfiguration(args.direction, args.fromNumber, args.inboundCallId),
117
+ BindSdk: this.buildBindSdk(),
118
+ ContextUser: args.contextUser,
119
+ MetadataProvider: args.provider,
120
+ });
121
+ return { RoomKey: active.RoomKey };
122
+ }
123
+ /** Resolves the seeded Twilio provider row (by driver class, falling back to display name). */
124
+ resolveProvider() {
125
+ const provider = this.engine.ProviderByDriverClass(TWILIO_PROVIDER_DRIVER) ?? this.engine.ProviderByName('Twilio');
126
+ if (!provider) {
127
+ throw new Error(`No active 'MJ: AI Bridge Providers' row for the Twilio bridge (DriverClass '${TWILIO_PROVIDER_DRIVER}').`);
128
+ }
129
+ return provider;
130
+ }
131
+ /**
132
+ * Builds the per-session SDK binding that wires the REAL Twilio bindings (REST client + the per-call
133
+ * media registry) onto the telephony driver — overriding the package's default unbound SDK. This is
134
+ * where the offline-complete seams meet the live REST + websocket plumbing.
135
+ */
136
+ buildBindSdk() {
137
+ return (driver) => {
138
+ const telephony = driver;
139
+ telephony.SetSdkFactory(() => new TwilioCallSdk(new RealTwilioBindings({
140
+ Rest: this.rest,
141
+ MediaPump: this.registry,
142
+ StreamUrl: this.config.streamPublicUrl,
143
+ StatusCallbackUrl: this.config.statusCallbackUrl,
144
+ })));
145
+ };
146
+ }
147
+ /**
148
+ * Assembles the per-session bridge Configuration the telephony driver reads. The engine does NOT
149
+ * forward the top-level `Direction` into the driver's Configuration (it only stamps the DB row), and
150
+ * the bridge defaults to `'Outbound'` when the key is absent — so Direction MUST be set here, or an
151
+ * inbound call wrongly takes the outbound-dial path and fails with "No 'From' number is specified".
152
+ */
153
+ buildSessionConfiguration(direction, fromNumber, inboundCallId) {
154
+ const config = { [DIRECTION_CONFIG_KEY]: direction };
155
+ if (fromNumber) {
156
+ config[FROM_NUMBER_CONFIG_KEY] = fromNumber;
157
+ }
158
+ if (inboundCallId) {
159
+ config[INBOUND_CALL_ID_CONFIG_KEY] = inboundCallId;
160
+ }
161
+ return config;
162
+ }
163
+ /** Finds the active agent identity whose phone number matches the dialed DID. */
164
+ async resolveAgentIdentityByPhone(dialedNumber, contextUser) {
165
+ const normalized = (dialedNumber ?? '').trim();
166
+ if (!normalized) {
167
+ return null;
168
+ }
169
+ const rv = new RunView();
170
+ const result = await rv.RunView({
171
+ EntityName: AGENT_IDENTITY_ENTITY,
172
+ ExtraFilter: `IdentityType='${PHONE_IDENTITY_TYPE}' AND IdentityValue='${normalized.replace(/'/g, "''")}' AND IsActive=1`,
173
+ MaxRows: 1,
174
+ ResultType: 'entity_object',
175
+ }, contextUser);
176
+ if (!result.Success) {
177
+ LogError(`[Telephony][Twilio] agent-identity lookup failed: ${result.ErrorMessage}`);
178
+ return null;
179
+ }
180
+ return result.Results?.[0] ?? null;
181
+ }
182
+ /** Loads a specific agent identity by id (used by outbound PlaceCall), requiring it be active. */
183
+ async loadAgentIdentity(agentIdentityId, contextUser, provider) {
184
+ // Use the request-scoped provider (multi-provider safe), not the global Metadata.
185
+ const entity = await provider.GetEntityObject(AGENT_IDENTITY_ENTITY, contextUser);
186
+ const loaded = await entity.Load(agentIdentityId);
187
+ if (!loaded || !entity.IsActive) {
188
+ return null;
189
+ }
190
+ return entity;
191
+ }
192
+ }
193
+ //# sourceMappingURL=TwilioTelephonyService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TwilioTelephonyService.js","sourceRoot":"","sources":["../../src/telephony/TwilioTelephonyService.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,OAAO,EAA+B,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAEtF,OAAO,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AAClE,OAAO,EAAE,2BAA2B,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,EAGH,oBAAoB,EACpB,sBAAsB,EACtB,0BAA0B,GAC7B,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,kCAAkC,CAAC;AAE3G,OAAO,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAGpE,MAAM,sBAAsB,GAAG,cAAc,CAAC;AAC9C,MAAM,qBAAqB,GAAG,gCAAgC,CAAC;AAC/D,MAAM,mBAAmB,GAAG,aAAa,CAAC;AA2B1C;;;GAGG;AACH,MAAM,OAAO,sBAAsB;IAM/B,YACqB,MAA6B,EAC7B,QAAiC,EAClD,OAAmC,EAAE;QAFpB,WAAM,GAAN,MAAM,CAAuB;QAC7B,aAAQ,GAAR,QAAQ,CAAyB;QAGlD,IAAI,CAAC,IAAI,GAAG,IAAI,oBAAoB,CAAC;YACjC,UAAU,EAAE,MAAM,CAAC,UAAU;YAC7B,SAAS,EAAE,MAAM,CAAC,SAAS;YAC3B,SAAS,EAAE,MAAM,CAAC,SAAS;YAC3B,YAAY,EAAE,MAAM,CAAC,YAAY;SACpC,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,cAAc,CAAC,QAAQ,CAAC;QACrD,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,cAAc,IAAI,2BAA2B,CAAC;QACzE,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,cAAc,IAAI,IAAI,cAAc,EAAE,CAAC;IACtE,CAAC;IAED;;;;;OAKG;IACI,KAAK,CAAC,iBAAiB,CAAC,KAAuB,EAAE,WAAqB,EAAE,QAA2B;QACtG,IAAI,CAAC;YACD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,2BAA2B,CAAC,KAAK,CAAC,EAAE,EAAE,WAAW,CAAC,CAAC;YAC/E,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACZ,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,+CAA+C,KAAK,CAAC,EAAE,IAAI,EAAE,CAAC;YACpG,CAAC;YACD,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YAC1C,MAAM,IAAI,CAAC,WAAW,CAAC;gBACnB,OAAO,EAAE,QAAQ,CAAC,OAAO;gBACzB,SAAS,EAAE,SAAS;gBACpB,OAAO,EAAE,KAAK,CAAC,IAAI;gBACnB,aAAa,EAAE,KAAK,CAAC,OAAO;gBAC5B,WAAW;gBACX,QAAQ;aACX,CAAC,CAAC;YACH,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;QAC9B,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACT,QAAQ,CAAC,oCAAoC,KAAK,CAAC,OAAO,YAAY,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YACpH,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,oCAAoC,EAAE,CAAC;QAC7E,CAAC;IACL,CAAC;IAED;;;;;;OAMG;IACI,KAAK,CAAC,iBAAiB,CAAC,eAAuB,EAAE,QAAgB,EAAE,WAAqB,EAAE,QAA2B;QACxH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC,eAAe,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC;QACtF,IAAI,CAAC,QAAQ,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,mBAAmB,eAAe,0BAA0B,CAAC,CAAC;QAClF,CAAC;QACD,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC;YACnC,OAAO,EAAE,QAAQ,CAAC,OAAO;YACzB,SAAS,EAAE,UAAU;YACrB,OAAO,EAAE,QAAQ;YACjB,UAAU,EAAE,QAAQ,CAAC,aAAa;YAClC,WAAW;YACX,QAAQ;SACX,CAAC,CAAC;QACH,OAAO,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC;IACjC,CAAC;IAED,gFAAgF;IAEhF,8GAA8G;IACtG,KAAK,CAAC,WAAW,CAAC,IAQzB;QACG,MAAM,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;QACjE,MAAM,cAAc,GAAG,IAAI,CAAC,eAAe,EAAE,CAAC;QAE9C,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,aAAa,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,WAAW,CAAC,EAAE,EAAE,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;QACtJ,MAAM,eAAe,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC;YAC9C,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,aAAa,EAAE,IAAI,CAAC,OAAO;YAC3B,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,gBAAgB,EAAE,IAAI,CAAC,QAAQ;YAC/B,cAAc,EAAE,YAAY,CAAC,EAAE;YAC/B,QAAQ,EAAE,IAAI,CAAC,OAAO;SACzB,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,kBAAkB,CAAC;YAChD,cAAc,EAAE,YAAY,CAAC,EAAE;YAC/B,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,aAAa,EAAE,IAAI,CAAC,OAAO;YAC3B,QAAQ,EAAE,cAAc;YACxB,eAAe,EAAE,eAAe;YAChC,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,aAAa,EAAE,IAAI,CAAC,yBAAyB,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,aAAa,CAAC;YAClG,OAAO,EAAE,IAAI,CAAC,YAAY,EAAE;YAC5B,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,gBAAgB,EAAE,IAAI,CAAC,QAAQ;SAClC,CAAC,CAAC;QACH,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC;IACvC,CAAC;IAED,+FAA+F;IACvF,eAAe;QACnB,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,qBAAqB,CAAC,sBAAsB,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;QACnH,IAAI,CAAC,QAAQ,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,+EAA+E,sBAAsB,KAAK,CAAC,CAAC;QAChI,CAAC;QACD,OAAO,QAAQ,CAAC;IACpB,CAAC;IAED;;;;OAIG;IACI,YAAY;QACf,OAAO,CAAC,MAAM,EAAE,EAAE;YACd,MAAM,SAAS,GAAG,MAA6B,CAAC;YAChD,SAAS,CAAC,aAAa,CAAC,GAAG,EAAE,CACzB,IAAI,aAAa,CACb,IAAI,kBAAkB,CAAC;gBACnB,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,SAAS,EAAE,IAAI,CAAC,QAAQ;gBACxB,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,eAAe;gBACtC,iBAAiB,EAAE,IAAI,CAAC,MAAM,CAAC,iBAAiB;aACnD,CAAC,CACL,CACJ,CAAC;QACN,CAAC,CAAC;IACN,CAAC;IAED;;;;;OAKG;IACK,yBAAyB,CAAC,SAAiC,EAAE,UAAmB,EAAE,aAAsB;QAC5G,MAAM,MAAM,GAA4B,EAAE,CAAC,oBAAoB,CAAC,EAAE,SAAS,EAAE,CAAC;QAC9E,IAAI,UAAU,EAAE,CAAC;YACb,MAAM,CAAC,sBAAsB,CAAC,GAAG,UAAU,CAAC;QAChD,CAAC;QACD,IAAI,aAAa,EAAE,CAAC;YAChB,MAAM,CAAC,0BAA0B,CAAC,GAAG,aAAa,CAAC;QACvD,CAAC;QACD,OAAO,MAAM,CAAC;IAClB,CAAC;IAED,iFAAiF;IACzE,KAAK,CAAC,2BAA2B,CAAC,YAAoB,EAAE,WAAqB;QACjF,MAAM,UAAU,GAAG,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QAC/C,IAAI,CAAC,UAAU,EAAE,CAAC;YACd,OAAO,IAAI,CAAC;QAChB,CAAC;QACD,MAAM,EAAE,GAAG,IAAI,OAAO,EAAE,CAAC;QACzB,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,OAAO,CAC3B;YACI,UAAU,EAAE,qBAAqB;YACjC,WAAW,EAAE,iBAAiB,mBAAmB,wBAAwB,UAAU,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,kBAAkB;YACzH,OAAO,EAAE,CAAC;YACV,UAAU,EAAE,eAAe;SAC9B,EACD,WAAW,CACd,CAAC;QACF,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YAClB,QAAQ,CAAC,qDAAqD,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC;YACrF,OAAO,IAAI,CAAC;QAChB,CAAC;QACD,OAAO,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;IACvC,CAAC;IAED,kGAAkG;IAC1F,KAAK,CAAC,iBAAiB,CAAC,eAAuB,EAAE,WAAqB,EAAE,QAA2B;QACvG,kFAAkF;QAClF,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,eAAe,CAAgC,qBAAqB,EAAE,WAAW,CAAC,CAAC;QACjH,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QAClD,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;YAC9B,OAAO,IAAI,CAAC;QAChB,CAAC;QACD,OAAO,MAAM,CAAC;IAClB,CAAC;CACJ"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * @fileoverview Express + WSS wiring for the Vonage telephony ingress.
3
+ *
4
+ * Three public surfaces (carriers cannot present an MJ JWT — Vonage's signed-request HMAC or webhook JWT
5
+ * is the gate):
6
+ * - `POST /telephony/vonage/answer` — inbound answer webhook. Verifies the signature/JWT, resolves the
7
+ * dialed DID to a pinned agent, starts an inbound bridge session, and returns the `connect`-websocket
8
+ * NCCO that opens the bidirectional media leg.
9
+ * - `POST /telephony/vonage/event` — call-lifecycle event webhook (verified, acknowledged 200).
10
+ * - `WSS /telephony/vonage/media` — the bidirectional `audio/l16;rate=8000` media socket. Frames are
11
+ * routed to the active call's `RealVonageBindings` via the shared {@link VonageCallMediaRegistry}.
12
+ *
13
+ * Vonage media frames do not carry the call UUID, so the answer NCCO embeds it on the media URL as a
14
+ * `?call_uuid=…` query param; the WSS reads it from the upgrade request URL to key the socket.
15
+ *
16
+ * Mirrors the Twilio / magic-link / widget public-router pattern: mount the router BEFORE the unified auth
17
+ * middleware and attach the WSS to the shared HTTP server at startup. The signature/JWT-verification gate +
18
+ * inbound resolution use the offline-complete, unit-tested helpers from the Vonage provider package; this
19
+ * module is thin HTTP/WS plumbing over them and the {@link VonageTelephonyService}.
20
+ *
21
+ * @module @memberjunction/server/telephony
22
+ */
23
+ import { Router } from 'express';
24
+ import type { VonageTelephonyConfig } from '../config.js';
25
+ import { VonageCallMediaRegistry } from './vonageMediaRegistry.js';
26
+ import { VonageTelephonyService } from './VonageTelephonyService.js';
27
+ /** The mount path for the Vonage telephony public router. */
28
+ export declare const VONAGE_TELEPHONY_MOUNT_PATH = "/telephony/vonage";
29
+ /** The media websocket path Vonage's `connect`-websocket NCCO connects to. */
30
+ export declare const VONAGE_MEDIA_WSS_PATH = "/telephony/vonage/media";
31
+ /**
32
+ * Builds the Vonage telephony handler: the public answer/event router + a function to attach the media
33
+ * WSS to the shared HTTP server. Returns the registry + service for observability/tests.
34
+ */
35
+ export declare function createVonageTelephonyHandler(publicUrl: string, config: VonageTelephonyConfig): {
36
+ publicRouter: Router;
37
+ attachMediaStreamServer: () => void;
38
+ registry: VonageCallMediaRegistry;
39
+ service: VonageTelephonyService;
40
+ };
41
+ //# sourceMappingURL=VonageTelephonyRouter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VonageTelephonyRouter.d.ts","sourceRoot":"","sources":["../../src/telephony/VonageTelephonyRouter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,MAAM,EAAiD,MAAM,SAAS,CAAC;AAahF,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAErE,6DAA6D;AAC7D,eAAO,MAAM,2BAA2B,sBAAsB,CAAC;AAE/D,8EAA8E;AAC9E,eAAO,MAAM,qBAAqB,4BAA4B,CAAC;AAK/D;;;GAGG;AACH,wBAAgB,4BAA4B,CACxC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,qBAAqB,GAC9B;IACC,YAAY,EAAE,MAAM,CAAC;IACrB,uBAAuB,EAAE,MAAM,IAAI,CAAC;IACpC,QAAQ,EAAE,uBAAuB,CAAC;IAClC,OAAO,EAAE,sBAAsB,CAAC;CACnC,CAmBA"}
@@ -0,0 +1,201 @@
1
+ /**
2
+ * @fileoverview Express + WSS wiring for the Vonage telephony ingress.
3
+ *
4
+ * Three public surfaces (carriers cannot present an MJ JWT — Vonage's signed-request HMAC or webhook JWT
5
+ * is the gate):
6
+ * - `POST /telephony/vonage/answer` — inbound answer webhook. Verifies the signature/JWT, resolves the
7
+ * dialed DID to a pinned agent, starts an inbound bridge session, and returns the `connect`-websocket
8
+ * NCCO that opens the bidirectional media leg.
9
+ * - `POST /telephony/vonage/event` — call-lifecycle event webhook (verified, acknowledged 200).
10
+ * - `WSS /telephony/vonage/media` — the bidirectional `audio/l16;rate=8000` media socket. Frames are
11
+ * routed to the active call's `RealVonageBindings` via the shared {@link VonageCallMediaRegistry}.
12
+ *
13
+ * Vonage media frames do not carry the call UUID, so the answer NCCO embeds it on the media URL as a
14
+ * `?call_uuid=…` query param; the WSS reads it from the upgrade request URL to key the socket.
15
+ *
16
+ * Mirrors the Twilio / magic-link / widget public-router pattern: mount the router BEFORE the unified auth
17
+ * middleware and attach the WSS to the shared HTTP server at startup. The signature/JWT-verification gate +
18
+ * inbound resolution use the offline-complete, unit-tested helpers from the Vonage provider package; this
19
+ * module is thin HTTP/WS plumbing over them and the {@link VonageTelephonyService}.
20
+ *
21
+ * @module @memberjunction/server/telephony
22
+ */
23
+ import { Router, urlencoded, json } from 'express';
24
+ import { WebSocketServer } from 'ws';
25
+ import { RegisterMediaUpgradeRoute } from './media-upgrade-router.js';
26
+ import { LogError, LogStatus, Metadata } from '@memberjunction/core';
27
+ import { UserCache } from '@memberjunction/sqlserver-dataprovider';
28
+ import { verifyVonageSignature, verifyVonageJwt, resolveInboundCall, buildInboundAnswerNcco, parseVonageControlEvent, } from '@memberjunction/ai-bridge-vonage';
29
+ import { VonageCallMediaRegistry } from './vonageMediaRegistry.js';
30
+ import { VonageTelephonyService } from './VonageTelephonyService.js';
31
+ /** The mount path for the Vonage telephony public router. */
32
+ export const VONAGE_TELEPHONY_MOUNT_PATH = '/telephony/vonage';
33
+ /** The media websocket path Vonage's `connect`-websocket NCCO connects to. */
34
+ export const VONAGE_MEDIA_WSS_PATH = '/telephony/vonage/media';
35
+ /** A polite NCCO returned when no agent is available for the dialed number. */
36
+ const NO_AGENT_NCCO = [{ action: 'talk', text: 'Sorry, no agent is available to take this call.' }];
37
+ /**
38
+ * Builds the Vonage telephony handler: the public answer/event router + a function to attach the media
39
+ * WSS to the shared HTTP server. Returns the registry + service for observability/tests.
40
+ */
41
+ export function createVonageTelephonyHandler(publicUrl, config) {
42
+ const registry = new VonageCallMediaRegistry();
43
+ const service = new VonageTelephonyService(config, registry);
44
+ const publicRouter = Router();
45
+ // Vonage posts JSON webhook bodies; also accept urlencoded for signed-request `sig` schemes.
46
+ publicRouter.post('/answer', json(), urlencoded({ extended: false }), async (req, res) => {
47
+ await handleInboundAnswer(service, config, req, res);
48
+ });
49
+ publicRouter.post('/event', json(), urlencoded({ extended: false }), (req, res) => {
50
+ handleCallEvent(config, req, res);
51
+ });
52
+ return {
53
+ publicRouter,
54
+ attachMediaStreamServer: () => attachMediaStreamServer(registry),
55
+ registry,
56
+ service,
57
+ };
58
+ }
59
+ /** Handles the inbound answer webhook: verify → resolve → start bridge → return the connect-websocket NCCO. */
60
+ async function handleInboundAnswer(service, config, req, res) {
61
+ const params = coerceParams(req.body);
62
+ if (!verifyVonageRequest(config, req, params)) {
63
+ res.status(403).type('application/json').json({ error: 'Invalid Vonage signature.' });
64
+ return;
65
+ }
66
+ let resolved;
67
+ try {
68
+ resolved = resolveInboundCall(params);
69
+ }
70
+ catch (e) {
71
+ LogError(`[Telephony][Vonage] answer webhook unparseable: ${e instanceof Error ? e.message : String(e)}`);
72
+ res.status(200).type('application/json').json(NO_AGENT_NCCO);
73
+ return;
74
+ }
75
+ const context = resolveServerContext();
76
+ if (!context) {
77
+ LogError('[Telephony][Vonage] no server context user available; cannot start inbound call.');
78
+ res.status(200).type('application/json').json(NO_AGENT_NCCO);
79
+ return;
80
+ }
81
+ const result = await service.HandleInboundCall(resolved, context.user, context.provider);
82
+ if (!result.accepted) {
83
+ LogStatus(`[Telephony][Vonage] inbound ${resolved.callId} not accepted: ${result.reason ?? 'unknown'}`);
84
+ res.status(200).type('application/json').json(NO_AGENT_NCCO);
85
+ return;
86
+ }
87
+ const mediaUrl = appendCallUuid(config.mediaPublicUrl, resolved.callId);
88
+ res.status(200).type('application/json').json(buildInboundAnswerNcco(mediaUrl));
89
+ }
90
+ /** Handles a call-lifecycle event webhook: verify then acknowledge (the bridge tracks state via the media socket). */
91
+ function handleCallEvent(config, req, res) {
92
+ const params = coerceParams(req.body);
93
+ if (!verifyVonageRequest(config, req, params)) {
94
+ res.status(403).type('application/json').json({ error: 'Invalid Vonage signature.' });
95
+ return;
96
+ }
97
+ LogStatus(`[Telephony][Vonage] event: ${params['status'] ?? params['event'] ?? 'unknown'} for ${params['uuid'] ?? params['conversation_uuid'] ?? '?'}`);
98
+ res.status(200).end();
99
+ }
100
+ /** Verifies a public Vonage webhook via the webhook JWT (preferred) or the signed-request `sig` HMAC. */
101
+ function verifyVonageRequest(config, req, params) {
102
+ const secret = config.signatureSecret;
103
+ if (!secret) {
104
+ return false;
105
+ }
106
+ const jwtClaims = verifyVonageJwt(secret, req.get('Authorization'), Math.floor(Date.now() / 1000));
107
+ if (jwtClaims) {
108
+ return true;
109
+ }
110
+ return verifyVonageSignature(secret, params['sig'], params);
111
+ }
112
+ /**
113
+ * Attaches the media WSS to the shared HTTP server on {@link VONAGE_MEDIA_WSS_PATH}. Each socket is mapped
114
+ * to its call UUID from the `?call_uuid=…` query param the answer NCCO embedded on the media URL, then
115
+ * inbound frames are dispatched to the call's bindings via the registry; the socket is also the registry's
116
+ * outbound pump for that call.
117
+ */
118
+ function attachMediaStreamServer(registry) {
119
+ // noServer: the shared path-routing upgrade dispatcher owns the HTTP 'upgrade' event (a second
120
+ // {server}-bound WS server would fight GraphQL's socket and 400 the handshake). The dispatcher
121
+ // passes the original request through, so the call-UUID query on the media URL is preserved.
122
+ const wss = new WebSocketServer({ noServer: true });
123
+ wss.on('connection', (socket, request) => wireMediaSocket(socket, request, registry));
124
+ RegisterMediaUpgradeRoute(VONAGE_MEDIA_WSS_PATH, wss);
125
+ LogStatus(`[Telephony][Vonage] media WSS route registered at ${VONAGE_MEDIA_WSS_PATH}`);
126
+ }
127
+ /** Wires one media socket: key on the `call_uuid` query param, attach, dispatch inbound frames, tear down on close. */
128
+ function wireMediaSocket(socket, request, registry) {
129
+ const callUuid = readCallUuid(request);
130
+ if (!callUuid) {
131
+ LogError('[Telephony][Vonage] media socket connected with no call_uuid; closing.');
132
+ socket.close();
133
+ return;
134
+ }
135
+ const adapter = {
136
+ sendBinary: (data) => socket.send(data),
137
+ sendText: (data) => socket.send(data),
138
+ close: () => socket.close(),
139
+ };
140
+ registry.AttachSocket(callUuid, adapter);
141
+ // Vonage splits the media leg by frame type: BINARY frames carry raw L16 PCM audio; TEXT frames carry
142
+ // JSON control events (websocket:connected / websocket:dtmf / close). `ws` reports which via isBinary.
143
+ socket.on('message', (raw, isBinary) => {
144
+ if (isBinary) {
145
+ registry.DispatchInboundAudio(callUuid, toArrayBuffer(raw));
146
+ return;
147
+ }
148
+ const event = parseVonageControlEvent(raw.toString('utf8'));
149
+ if (event) {
150
+ registry.DispatchInboundEvent(callUuid, event);
151
+ }
152
+ });
153
+ socket.on('close', () => registry.EndCall(callUuid));
154
+ }
155
+ /** Copies a Node `Buffer` into a standalone `ArrayBuffer` (respecting byteOffset/length, never aliasing the pool). */
156
+ function toArrayBuffer(buf) {
157
+ const out = new ArrayBuffer(buf.byteLength);
158
+ new Uint8Array(out).set(buf);
159
+ return out;
160
+ }
161
+ /** Reads the `call_uuid` query param off the websocket upgrade request URL, or null when absent. */
162
+ function readCallUuid(request) {
163
+ try {
164
+ const url = new URL(request.url ?? '', 'http://localhost');
165
+ const value = url.searchParams.get('call_uuid');
166
+ return value && value.length > 0 ? value : null;
167
+ }
168
+ catch {
169
+ return null;
170
+ }
171
+ }
172
+ /** Appends the call UUID as a `call_uuid` query param to the media URL so the WSS can key the socket. */
173
+ function appendCallUuid(mediaUrl, callUuid) {
174
+ const sep = mediaUrl.includes('?') ? '&' : '?';
175
+ return `${mediaUrl}${sep}call_uuid=${encodeURIComponent(callUuid)}`;
176
+ }
177
+ /** Coerces an Express body (JSON object or urlencoded) to the `Record<string,string>` the verifiers expect. */
178
+ function coerceParams(body) {
179
+ const out = {};
180
+ if (body && typeof body === 'object') {
181
+ for (const [key, value] of Object.entries(body)) {
182
+ if (typeof value === 'string') {
183
+ out[key] = value;
184
+ }
185
+ else if (typeof value === 'number' || typeof value === 'boolean') {
186
+ out[key] = String(value);
187
+ }
188
+ }
189
+ }
190
+ return out;
191
+ }
192
+ /** Resolves the server-side principal + provider for the public webhook (no MJ JWT on a carrier request). */
193
+ function resolveServerContext() {
194
+ const user = UserCache.Instance.GetSystemUser() ?? UserCache.Users.find((u) => u.IsActive && u.Type?.trim().toLowerCase() === 'owner') ?? null;
195
+ const provider = Metadata.Provider; // global-provider-ok: public carrier webhook has no MJ JWT / per-request provider; the server's single default provider is correct
196
+ if (!user || !provider) {
197
+ return null;
198
+ }
199
+ return { user, provider };
200
+ }
201
+ //# sourceMappingURL=VonageTelephonyRouter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VonageTelephonyRouter.js","sourceRoot":"","sources":["../../src/telephony/VonageTelephonyRouter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,90 @@
1
+ /**
2
+ * @fileoverview Orchestrates Vonage telephony bridge sessions (inbound + outbound) for MJAPI.
3
+ *
4
+ * This is the composition layer between the carrier ingress (the public answer/event webhooks + the
5
+ * bidirectional media WSS) and the ONE unified realtime-agent pathway. It does NOT re-implement any
6
+ * bridge logic: it resolves the Vonage provider + the agent identity, opens a server-side realtime
7
+ * session via the agent layer's `CreateBridgeRealtimeSession` factory, binds `RealVonageBindings` (real
8
+ * REST Voice client + the per-call media registry) onto the driver, and hands everything to
9
+ * `AIBridgeEngine.StartBridgeSession` — exactly the seam the Twilio service + LiveKit room coordinator use.
10
+ *
11
+ * Collaborators are injected (engine, session factory, session manager) so the resolution/branching
12
+ * logic is unit-testable with fakes; the actual call placement + media flow are live-only (real Vonage
13
+ * credentials + a publicly reachable media URL — see telephony-vendor-bindings.md §T2).
14
+ *
15
+ * @module @memberjunction/server/telephony
16
+ */
17
+ import { UserInfo, IMetadataProvider } from '@memberjunction/core';
18
+ import { AIBridgeEngine } from '@memberjunction/ai-bridge-server';
19
+ import { CreateBridgeRealtimeSession } from '@memberjunction/ai-agents';
20
+ import { type BridgeNativeSdkBinding } from '@memberjunction/ai-bridge-base';
21
+ import type { VonageTelephonyConfig } from '../config.js';
22
+ import { SessionManager } from '../agentSessions/SessionManager.js';
23
+ import { VonageCallMediaRegistry } from './vonageMediaRegistry.js';
24
+ /** A resolved inbound call's identifying fields (parsed from the Vonage answer/event webhook). */
25
+ export interface InboundCallInput {
26
+ /** The Vonage call UUID (`uuid` / `conversation_uuid`). */
27
+ callId: string;
28
+ /** The caller's number (Vonage `from`). */
29
+ from: string;
30
+ /** The dialed DID (Vonage `to`) — resolved to an agent identity. */
31
+ to: string;
32
+ }
33
+ /** Result of starting an inbound bridge session. */
34
+ export interface InboundCallResult {
35
+ /** Whether a pinned agent was resolved + a bridge session started. */
36
+ accepted: boolean;
37
+ /** Why it was rejected (no agent identity for the DID, provider missing, etc.). */
38
+ reason?: string;
39
+ }
40
+ /** Injectable collaborators (production defaults wired in the constructor; fakes in tests). */
41
+ export interface VonageTelephonyServiceDeps {
42
+ engine?: Pick<AIBridgeEngine, 'ProviderByName' | 'ProviderByDriverClass' | 'StartBridgeSession' | 'Config'>;
43
+ sessionFactory?: typeof CreateBridgeRealtimeSession;
44
+ sessionManager?: Pick<SessionManager, 'CreateSession'>;
45
+ }
46
+ /**
47
+ * Starts Vonage bridge sessions. One instance per server, constructed alongside the telephony router and
48
+ * sharing the {@link VonageCallMediaRegistry} with the media WSS server.
49
+ */
50
+ export declare class VonageTelephonyService {
51
+ private readonly config;
52
+ private readonly registry;
53
+ private readonly voice;
54
+ private readonly engine;
55
+ private readonly sessionFactory;
56
+ private readonly sessionManager;
57
+ constructor(config: VonageTelephonyConfig, registry: VonageCallMediaRegistry, deps?: VonageTelephonyServiceDeps);
58
+ /**
59
+ * Resolves the dialed DID to a pinned agent and starts an INBOUND bridge session. The bound
60
+ * `RealVonageBindings` will accept the media socket (opened by the answer webhook's `connect` NCCO)
61
+ * for the call UUID. Returns `{ accepted:false }` (never throws) when no agent identity matches the
62
+ * DID, so the webhook can answer with a polite "no agent" NCCO instead of a 500.
63
+ */
64
+ HandleInboundCall(input: InboundCallInput, contextUser: UserInfo, provider: IMetadataProvider): Promise<InboundCallResult>;
65
+ /**
66
+ * Places an OUTBOUND call from a given agent identity to a destination number. The bound
67
+ * `RealVonageBindings.createCall` issues the Voice REST `POST /v1/calls` with the `connect`-websocket
68
+ * NCCO; the returned call UUID is the bridge's external connection id.
69
+ *
70
+ * @returns The placed call UUID.
71
+ */
72
+ PlaceOutboundCall(agentIdentityId: string, toNumber: string, contextUser: UserInfo, provider: IMetadataProvider): Promise<string>;
73
+ /** Shared inbound/outbound bridge-start: resolve provider, open the realtime session, bind the SDK, start. */
74
+ private startBridge;
75
+ /** Resolves the seeded Vonage provider row (by driver class, falling back to display name). */
76
+ private resolveProvider;
77
+ /**
78
+ * Builds the per-session SDK binding that wires the REAL Vonage bindings (REST Voice client + the
79
+ * per-call media registry) onto the telephony driver — overriding the package's default unbound SDK.
80
+ * This is where the offline-complete seams meet the live REST + websocket plumbing.
81
+ */
82
+ buildBindSdk(): BridgeNativeSdkBinding;
83
+ /** Assembles the per-session bridge configuration (direction/from-number/inbound-call-id config keys). */
84
+ private buildSessionConfiguration;
85
+ /** Finds the active agent identity whose phone number matches the dialed DID. */
86
+ private resolveAgentIdentityByPhone;
87
+ /** Loads a specific agent identity by id (used by outbound PlaceCall), requiring it be active. */
88
+ private loadAgentIdentity;
89
+ }
90
+ //# sourceMappingURL=VonageTelephonyService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VonageTelephonyService.d.ts","sourceRoot":"","sources":["../../src/telephony/VonageTelephonyService.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAW,QAAQ,EAAE,iBAAiB,EAAY,MAAM,sBAAsB,CAAC;AAEtF,OAAO,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AAClE,OAAO,EAAE,2BAA2B,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,EAEH,KAAK,sBAAsB,EAI9B,MAAM,gCAAgC,CAAC;AAExC,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACpE,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AAMnE,kGAAkG;AAClG,MAAM,WAAW,gBAAgB;IAC7B,2DAA2D;IAC3D,MAAM,EAAE,MAAM,CAAC;IACf,2CAA2C;IAC3C,IAAI,EAAE,MAAM,CAAC;IACb,oEAAoE;IACpE,EAAE,EAAE,MAAM,CAAC;CACd;AAED,oDAAoD;AACpD,MAAM,WAAW,iBAAiB;IAC9B,sEAAsE;IACtE,QAAQ,EAAE,OAAO,CAAC;IAClB,mFAAmF;IACnF,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,+FAA+F;AAC/F,MAAM,WAAW,0BAA0B;IACvC,MAAM,CAAC,EAAE,IAAI,CAAC,cAAc,EAAE,gBAAgB,GAAG,uBAAuB,GAAG,oBAAoB,GAAG,QAAQ,CAAC,CAAC;IAC5G,cAAc,CAAC,EAAE,OAAO,2BAA2B,CAAC;IACpD,cAAc,CAAC,EAAE,IAAI,CAAC,cAAc,EAAE,eAAe,CAAC,CAAC;CAC1D;AAED;;;GAGG;AACH,qBAAa,sBAAsB;IAO3B,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAP7B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAwB;IAC9C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqG;IAC5H,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAqC;IACpE,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAwC;gBAGlD,MAAM,EAAE,qBAAqB,EAC7B,QAAQ,EAAE,uBAAuB,EAClD,IAAI,GAAE,0BAA+B;IAazC;;;;;OAKG;IACU,iBAAiB,CAAC,KAAK,EAAE,gBAAgB,EAAE,WAAW,EAAE,QAAQ,EAAE,QAAQ,EAAE,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAsBvI;;;;;;OAMG;IACU,iBAAiB,CAAC,eAAe,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,QAAQ,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC;IAkB9I,8GAA8G;YAChG,WAAW;IAsCzB,+FAA+F;IAC/F,OAAO,CAAC,eAAe;IAQvB;;;;OAIG;IACI,YAAY,IAAI,sBAAsB;IAgB7C,0GAA0G;IAC1G,OAAO,CAAC,yBAAyB;IAcjC,iFAAiF;YACnE,2BAA2B;IAsBzC,kGAAkG;YACpF,iBAAiB;CASlC"}