@memberjunction/server 5.44.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 (254) 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 +37 -0
  11. package/dist/agentSessions/SessionManager.js.map +1 -1
  12. package/dist/auth/magicLink/MagicLinkRouter.d.ts +10 -0
  13. package/dist/auth/magicLink/MagicLinkRouter.d.ts.map +1 -1
  14. package/dist/auth/magicLink/MagicLinkRouter.js +16 -0
  15. package/dist/auth/magicLink/MagicLinkRouter.js.map +1 -1
  16. package/dist/auth/magicLink/index.d.ts +1 -1
  17. package/dist/auth/magicLink/index.d.ts.map +1 -1
  18. package/dist/auth/magicLink/index.js +1 -1
  19. package/dist/auth/magicLink/index.js.map +1 -1
  20. package/dist/auth/magicLink/types.d.ts +26 -0
  21. package/dist/auth/magicLink/types.d.ts.map +1 -1
  22. package/dist/config.d.ts +1883 -144
  23. package/dist/config.d.ts.map +1 -1
  24. package/dist/config.js +160 -36
  25. package/dist/config.js.map +1 -1
  26. package/dist/context.d.ts.map +1 -1
  27. package/dist/context.js +45 -2
  28. package/dist/context.js.map +1 -1
  29. package/dist/generated/generated.d.ts +522 -0
  30. package/dist/generated/generated.d.ts.map +1 -1
  31. package/dist/generated/generated.js +2860 -0
  32. package/dist/generated/generated.js.map +1 -1
  33. package/dist/generic/ResolverBase.d.ts +13 -0
  34. package/dist/generic/ResolverBase.d.ts.map +1 -1
  35. package/dist/generic/ResolverBase.js +22 -0
  36. package/dist/generic/ResolverBase.js.map +1 -1
  37. package/dist/generic/RunViewResolver.d.ts.map +1 -1
  38. package/dist/generic/RunViewResolver.js +4 -0
  39. package/dist/generic/RunViewResolver.js.map +1 -1
  40. package/dist/index.d.ts +0 -2
  41. package/dist/index.d.ts.map +1 -1
  42. package/dist/index.js +101 -3
  43. package/dist/index.js.map +1 -1
  44. package/dist/integration/CustomColumnPromoter.d.ts.map +1 -1
  45. package/dist/integration/CustomColumnPromoter.js +6 -0
  46. package/dist/integration/CustomColumnPromoter.js.map +1 -1
  47. package/dist/realtimeWidget/WidgetRouter.d.ts +26 -0
  48. package/dist/realtimeWidget/WidgetRouter.d.ts.map +1 -0
  49. package/dist/realtimeWidget/WidgetRouter.js +182 -0
  50. package/dist/realtimeWidget/WidgetRouter.js.map +1 -0
  51. package/dist/realtimeWidget/WidgetSessionService.d.ts +265 -0
  52. package/dist/realtimeWidget/WidgetSessionService.d.ts.map +1 -0
  53. package/dist/realtimeWidget/WidgetSessionService.js +477 -0
  54. package/dist/realtimeWidget/WidgetSessionService.js.map +1 -0
  55. package/dist/realtimeWidget/host-identity.d.ts +40 -0
  56. package/dist/realtimeWidget/host-identity.d.ts.map +1 -0
  57. package/dist/realtimeWidget/host-identity.js +58 -0
  58. package/dist/realtimeWidget/host-identity.js.map +1 -0
  59. package/dist/realtimeWidget/index.d.ts +10 -0
  60. package/dist/realtimeWidget/index.d.ts.map +1 -0
  61. package/dist/realtimeWidget/index.js +9 -0
  62. package/dist/realtimeWidget/index.js.map +1 -0
  63. package/dist/realtimeWidget/visitorIdentity.d.ts +76 -0
  64. package/dist/realtimeWidget/visitorIdentity.d.ts.map +1 -0
  65. package/dist/realtimeWidget/visitorIdentity.js +202 -0
  66. package/dist/realtimeWidget/visitorIdentity.js.map +1 -0
  67. package/dist/realtimeWidget/widgetCore.d.ts +106 -0
  68. package/dist/realtimeWidget/widgetCore.d.ts.map +1 -0
  69. package/dist/realtimeWidget/widgetCore.js +173 -0
  70. package/dist/realtimeWidget/widgetCore.js.map +1 -0
  71. package/dist/realtimeWidget/widgetGuestElevation.d.ts +51 -0
  72. package/dist/realtimeWidget/widgetGuestElevation.d.ts.map +1 -0
  73. package/dist/realtimeWidget/widgetGuestElevation.js +79 -0
  74. package/dist/realtimeWidget/widgetGuestElevation.js.map +1 -0
  75. package/dist/resolvers/ComponentRegistryResolver.d.ts +7 -0
  76. package/dist/resolvers/ComponentRegistryResolver.d.ts.map +1 -1
  77. package/dist/resolvers/ComponentRegistryResolver.js +31 -8
  78. package/dist/resolvers/ComponentRegistryResolver.js.map +1 -1
  79. package/dist/resolvers/EntityPermissionResolver.d.ts.map +1 -1
  80. package/dist/resolvers/EntityPermissionResolver.js +1 -2
  81. package/dist/resolvers/EntityPermissionResolver.js.map +1 -1
  82. package/dist/resolvers/QuerySystemUserResolver.d.ts +9 -6
  83. package/dist/resolvers/QuerySystemUserResolver.d.ts.map +1 -1
  84. package/dist/resolvers/QuerySystemUserResolver.js +15 -13
  85. package/dist/resolvers/QuerySystemUserResolver.js.map +1 -1
  86. package/dist/resolvers/RealtimeClientSessionResolver.d.ts +10 -0
  87. package/dist/resolvers/RealtimeClientSessionResolver.d.ts.map +1 -1
  88. package/dist/resolvers/RealtimeClientSessionResolver.js +47 -3
  89. package/dist/resolvers/RealtimeClientSessionResolver.js.map +1 -1
  90. package/dist/resolvers/RingCentralTelephonyResolver.d.ts +27 -0
  91. package/dist/resolvers/RingCentralTelephonyResolver.d.ts.map +1 -0
  92. package/dist/resolvers/RingCentralTelephonyResolver.js +87 -0
  93. package/dist/resolvers/RingCentralTelephonyResolver.js.map +1 -0
  94. package/dist/resolvers/RunAIAgentResolver.d.ts.map +1 -1
  95. package/dist/resolvers/RunAIAgentResolver.js +14 -3
  96. package/dist/resolvers/RunAIAgentResolver.js.map +1 -1
  97. package/dist/resolvers/SearchKnowledgeResolver.d.ts.map +1 -1
  98. package/dist/resolvers/SearchKnowledgeResolver.js +2 -0
  99. package/dist/resolvers/SearchKnowledgeResolver.js.map +1 -1
  100. package/dist/resolvers/TeamsMeetingsResolver.d.ts +28 -0
  101. package/dist/resolvers/TeamsMeetingsResolver.d.ts.map +1 -0
  102. package/dist/resolvers/TeamsMeetingsResolver.js +91 -0
  103. package/dist/resolvers/TeamsMeetingsResolver.js.map +1 -0
  104. package/dist/resolvers/TelephonyResolver.d.ts +26 -0
  105. package/dist/resolvers/TelephonyResolver.d.ts.map +1 -0
  106. package/dist/resolvers/TelephonyResolver.js +86 -0
  107. package/dist/resolvers/TelephonyResolver.js.map +1 -0
  108. package/dist/resolvers/TestQuerySQLResolver.d.ts +1 -1
  109. package/dist/resolvers/TestQuerySQLResolver.d.ts.map +1 -1
  110. package/dist/resolvers/TestQuerySQLResolver.js +2 -3
  111. package/dist/resolvers/TestQuerySQLResolver.js.map +1 -1
  112. package/dist/resolvers/VonageTelephonyResolver.d.ts +26 -0
  113. package/dist/resolvers/VonageTelephonyResolver.d.ts.map +1 -0
  114. package/dist/resolvers/VonageTelephonyResolver.js +86 -0
  115. package/dist/resolvers/VonageTelephonyResolver.js.map +1 -0
  116. package/dist/rest/MediaStreamHandler.js +4 -1
  117. package/dist/rest/MediaStreamHandler.js.map +1 -1
  118. package/dist/telephony/RingCentralTelephonyService.d.ts +115 -0
  119. package/dist/telephony/RingCentralTelephonyService.d.ts.map +1 -0
  120. package/dist/telephony/RingCentralTelephonyService.js +262 -0
  121. package/dist/telephony/RingCentralTelephonyService.js.map +1 -0
  122. package/dist/telephony/TeamsMeetingsRouter.d.ts +40 -0
  123. package/dist/telephony/TeamsMeetingsRouter.d.ts.map +1 -0
  124. package/dist/telephony/TeamsMeetingsRouter.js +96 -0
  125. package/dist/telephony/TeamsMeetingsRouter.js.map +1 -0
  126. package/dist/telephony/TeamsMeetingsService.d.ts +113 -0
  127. package/dist/telephony/TeamsMeetingsService.d.ts.map +1 -0
  128. package/dist/telephony/TeamsMeetingsService.js +196 -0
  129. package/dist/telephony/TeamsMeetingsService.js.map +1 -0
  130. package/dist/telephony/TwilioTelephonyRouter.d.ts +36 -0
  131. package/dist/telephony/TwilioTelephonyRouter.d.ts.map +1 -0
  132. package/dist/telephony/TwilioTelephonyRouter.js +143 -0
  133. package/dist/telephony/TwilioTelephonyRouter.js.map +1 -0
  134. package/dist/telephony/TwilioTelephonyService.d.ts +95 -0
  135. package/dist/telephony/TwilioTelephonyService.d.ts.map +1 -0
  136. package/dist/telephony/TwilioTelephonyService.js +193 -0
  137. package/dist/telephony/TwilioTelephonyService.js.map +1 -0
  138. package/dist/telephony/VonageTelephonyRouter.d.ts +41 -0
  139. package/dist/telephony/VonageTelephonyRouter.d.ts.map +1 -0
  140. package/dist/telephony/VonageTelephonyRouter.js +201 -0
  141. package/dist/telephony/VonageTelephonyRouter.js.map +1 -0
  142. package/dist/telephony/VonageTelephonyService.d.ts +90 -0
  143. package/dist/telephony/VonageTelephonyService.d.ts.map +1 -0
  144. package/dist/telephony/VonageTelephonyService.js +191 -0
  145. package/dist/telephony/VonageTelephonyService.js.map +1 -0
  146. package/dist/telephony/calendar-scheduler.d.ts +67 -0
  147. package/dist/telephony/calendar-scheduler.d.ts.map +1 -0
  148. package/dist/telephony/calendar-scheduler.js +133 -0
  149. package/dist/telephony/calendar-scheduler.js.map +1 -0
  150. package/dist/telephony/index.d.ts +29 -0
  151. package/dist/telephony/index.d.ts.map +1 -0
  152. package/dist/telephony/index.js +38 -0
  153. package/dist/telephony/index.js.map +1 -0
  154. package/dist/telephony/media-upgrade-router.d.ts +33 -0
  155. package/dist/telephony/media-upgrade-router.d.ts.map +1 -0
  156. package/dist/telephony/media-upgrade-router.js +56 -0
  157. package/dist/telephony/media-upgrade-router.js.map +1 -0
  158. package/dist/telephony/ringcentral-runtime.d.ts +14 -0
  159. package/dist/telephony/ringcentral-runtime.d.ts.map +1 -0
  160. package/dist/telephony/ringcentral-runtime.js +18 -0
  161. package/dist/telephony/ringcentral-runtime.js.map +1 -0
  162. package/dist/telephony/teams-meetings-runtime.d.ts +16 -0
  163. package/dist/telephony/teams-meetings-runtime.d.ts.map +1 -0
  164. package/dist/telephony/teams-meetings-runtime.js +20 -0
  165. package/dist/telephony/teams-meetings-runtime.js.map +1 -0
  166. package/dist/telephony/teamsAcsMediaRegistry.d.ts +69 -0
  167. package/dist/telephony/teamsAcsMediaRegistry.d.ts.map +1 -0
  168. package/dist/telephony/teamsAcsMediaRegistry.js +118 -0
  169. package/dist/telephony/teamsAcsMediaRegistry.js.map +1 -0
  170. package/dist/telephony/telephony-runtime.d.ts +14 -0
  171. package/dist/telephony/telephony-runtime.d.ts.map +1 -0
  172. package/dist/telephony/telephony-runtime.js +18 -0
  173. package/dist/telephony/telephony-runtime.js.map +1 -0
  174. package/dist/telephony/twilioMediaRegistry.d.ts +60 -0
  175. package/dist/telephony/twilioMediaRegistry.d.ts.map +1 -0
  176. package/dist/telephony/twilioMediaRegistry.js +106 -0
  177. package/dist/telephony/twilioMediaRegistry.js.map +1 -0
  178. package/dist/telephony/vonage-runtime.d.ts +14 -0
  179. package/dist/telephony/vonage-runtime.d.ts.map +1 -0
  180. package/dist/telephony/vonage-runtime.js +18 -0
  181. package/dist/telephony/vonage-runtime.js.map +1 -0
  182. package/dist/telephony/vonageMediaRegistry.d.ts +78 -0
  183. package/dist/telephony/vonageMediaRegistry.d.ts.map +1 -0
  184. package/dist/telephony/vonageMediaRegistry.js +158 -0
  185. package/dist/telephony/vonageMediaRegistry.js.map +1 -0
  186. package/package.json +88 -83
  187. package/src/__tests__/search-knowledge-tags.test.ts +9 -9
  188. package/src/__tests__/teams-meetings-service.test.ts +65 -0
  189. package/src/__tests__/teamsAcsMediaRegistry.test.ts +82 -0
  190. package/src/__tests__/twilio-telephony-service.test.ts +23 -0
  191. package/src/__tests__/twilioMediaRegistry.test.ts +103 -0
  192. package/src/__tests__/vonageMediaRegistry.test.ts +180 -0
  193. package/src/__tests__/widget.test.ts +204 -0
  194. package/src/__tests__/widgetGuestElevation.test.ts +57 -0
  195. package/src/__tests__/widgetHostIdentity.test.ts +117 -0
  196. package/src/agentSessions/ReturningVisitorRecap.ts +242 -0
  197. package/src/agentSessions/SessionJanitor.ts +66 -6
  198. package/src/agentSessions/SessionManager.ts +38 -0
  199. package/src/auth/magicLink/MagicLinkRouter.ts +17 -0
  200. package/src/auth/magicLink/index.ts +1 -0
  201. package/src/auth/magicLink/types.ts +26 -0
  202. package/src/config.ts +172 -38
  203. package/src/context.ts +50 -3
  204. package/src/generated/generated.ts +1991 -1
  205. package/src/generic/ResolverBase.ts +28 -0
  206. package/src/generic/RunViewResolver.ts +4 -0
  207. package/src/index.ts +109 -3
  208. package/src/integration/CustomColumnPromoter.ts +6 -0
  209. package/src/realtimeWidget/WidgetRouter.ts +204 -0
  210. package/src/realtimeWidget/WidgetSessionService.ts +714 -0
  211. package/src/realtimeWidget/host-identity.ts +84 -0
  212. package/src/realtimeWidget/index.ts +15 -0
  213. package/src/realtimeWidget/visitorIdentity.ts +258 -0
  214. package/src/realtimeWidget/widgetCore.ts +231 -0
  215. package/src/realtimeWidget/widgetGuestElevation.ts +115 -0
  216. package/src/resolvers/ComponentRegistryResolver.ts +36 -10
  217. package/src/resolvers/EntityPermissionResolver.ts +1 -2
  218. package/src/resolvers/QuerySystemUserResolver.ts +14 -10
  219. package/src/resolvers/RealtimeClientSessionResolver.ts +59 -2
  220. package/src/resolvers/RingCentralTelephonyResolver.ts +64 -0
  221. package/src/resolvers/RunAIAgentResolver.ts +16 -4
  222. package/src/resolvers/SearchKnowledgeResolver.ts +2 -0
  223. package/src/resolvers/TeamsMeetingsResolver.ts +68 -0
  224. package/src/resolvers/TelephonyResolver.ts +63 -0
  225. package/src/resolvers/TestQuerySQLResolver.ts +2 -3
  226. package/src/resolvers/VonageTelephonyResolver.ts +63 -0
  227. package/src/rest/MediaStreamHandler.ts +4 -1
  228. package/src/telephony/RingCentralTelephonyService.ts +342 -0
  229. package/src/telephony/TeamsMeetingsRouter.ts +124 -0
  230. package/src/telephony/TeamsMeetingsService.ts +268 -0
  231. package/src/telephony/TwilioTelephonyRouter.ts +184 -0
  232. package/src/telephony/TwilioTelephonyService.ts +261 -0
  233. package/src/telephony/VonageTelephonyRouter.ts +239 -0
  234. package/src/telephony/VonageTelephonyService.ts +259 -0
  235. package/src/telephony/calendar-scheduler.ts +176 -0
  236. package/src/telephony/index.ts +43 -0
  237. package/src/telephony/media-upgrade-router.ts +62 -0
  238. package/src/telephony/ringcentral-runtime.ts +22 -0
  239. package/src/telephony/teams-meetings-runtime.ts +24 -0
  240. package/src/telephony/teamsAcsMediaRegistry.ts +152 -0
  241. package/src/telephony/telephony-runtime.ts +22 -0
  242. package/src/telephony/twilioMediaRegistry.ts +137 -0
  243. package/src/telephony/vonage-runtime.ts +22 -0
  244. package/src/telephony/vonageMediaRegistry.ts +200 -0
  245. package/dist/agents/skip-agent.d.ts +0 -111
  246. package/dist/agents/skip-agent.d.ts.map +0 -1
  247. package/dist/agents/skip-agent.js +0 -1487
  248. package/dist/agents/skip-agent.js.map +0 -1
  249. package/dist/agents/skip-sdk.d.ts +0 -261
  250. package/dist/agents/skip-sdk.d.ts.map +0 -1
  251. package/dist/agents/skip-sdk.js +0 -909
  252. package/dist/agents/skip-sdk.js.map +0 -1
  253. package/src/agents/skip-agent.ts +0 -1594
  254. package/src/agents/skip-sdk.ts +0 -1210
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@memberjunction/server",
3
- "version": "5.44.0",
3
+ "version": "5.45.0",
4
4
  "description": "MemberJunction: This project provides API access via GraphQL to the common data store.",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./src/index.ts",
@@ -27,88 +27,93 @@
27
27
  "@as-integrations/express5": "^1.0.0",
28
28
  "@graphql-tools/schema": "latest",
29
29
  "@graphql-tools/utils": "^11.0.0",
30
- "@memberjunction/actions": "5.44.0",
31
- "@memberjunction/actions-apollo": "5.44.0",
32
- "@memberjunction/actions-base": "5.44.0",
33
- "@memberjunction/actions-bizapps-accounting": "5.44.0",
34
- "@memberjunction/actions-bizapps-crm": "5.44.0",
35
- "@memberjunction/actions-bizapps-formbuilders": "5.44.0",
36
- "@memberjunction/actions-bizapps-lms": "5.44.0",
37
- "@memberjunction/actions-bizapps-social": "5.44.0",
38
- "@memberjunction/ai": "5.44.0",
39
- "@memberjunction/ai-agent-manager": "5.44.0",
40
- "@memberjunction/ai-agent-manager-actions": "5.44.0",
41
- "@memberjunction/ai-agents": "5.44.0",
42
- "@memberjunction/ai-bridge-server": "5.44.0",
43
- "@memberjunction/ai-core-plus": "5.44.0",
44
- "@memberjunction/ai-engine-base": "5.44.0",
45
- "@memberjunction/ai-mcp-client": "5.44.0",
46
- "@memberjunction/ai-prompts": "5.44.0",
47
- "@memberjunction/ai-provider-bundle": "5.44.0",
48
- "@memberjunction/ai-vector-sync": "5.44.0",
49
- "@memberjunction/ai-vectordb": "5.44.0",
50
- "@memberjunction/ai-vectors-pinecone": "5.44.0",
51
- "@memberjunction/aiengine": "5.44.0",
52
- "@memberjunction/api-keys": "5.44.0",
53
- "@memberjunction/auth-providers": "5.44.0",
54
- "@memberjunction/clustering-engine": "5.44.0",
55
- "@memberjunction/codegen-lib": "5.44.0",
56
- "@memberjunction/communication-engine": "5.44.0",
57
- "@memberjunction/communication-ms-graph": "5.44.0",
58
- "@memberjunction/notifications": "5.44.0",
59
- "@memberjunction/communication-sendgrid": "5.44.0",
60
- "@memberjunction/communication-types": "5.44.0",
61
- "@memberjunction/component-registry-client-sdk": "5.44.0",
62
- "@memberjunction/computer-use": "5.44.0",
63
- "@memberjunction/computer-use-engine": "5.44.0",
64
- "@memberjunction/config": "5.44.0",
65
- "@memberjunction/core": "5.44.0",
66
- "@memberjunction/core-actions": "5.44.0",
67
- "@memberjunction/core-entities": "5.44.0",
68
- "@memberjunction/core-entities-server": "5.44.0",
69
- "@memberjunction/data-context": "5.44.0",
70
- "@memberjunction/data-context-server": "5.44.0",
71
- "@memberjunction/doc-utils": "5.44.0",
72
- "@memberjunction/encryption": "5.44.0",
73
- "@memberjunction/entity-communications-base": "5.44.0",
74
- "@memberjunction/entity-communications-server": "5.44.0",
75
- "@memberjunction/esignature": "5.44.0",
76
- "@memberjunction/external-change-detection": "5.44.0",
77
- "@memberjunction/generic-database-provider": "5.44.0",
78
- "@memberjunction/global": "5.44.0",
79
- "@memberjunction/graphql-dataprovider": "5.44.0",
80
- "@memberjunction/integration-engine": "5.44.0",
81
- "@memberjunction/integration-progress-artifacts": "5.44.0",
82
- "@memberjunction/integration-schema-builder": "5.44.0",
83
- "@memberjunction/interactive-component-types": "5.44.0",
84
- "@memberjunction/lists": "5.44.0",
85
- "@memberjunction/lists-base": "5.44.0",
86
- "@memberjunction/livekit-room-server": "5.44.0",
87
- "@memberjunction/postgresql-dataprovider": "5.44.0",
88
- "@memberjunction/queue": "5.44.0",
89
- "@memberjunction/record-comparison": "5.44.0",
90
- "@memberjunction/redis-provider": "5.44.0",
91
- "@memberjunction/remote-browser-base": "5.44.0",
92
- "@memberjunction/remote-browser-cdp": "5.44.0",
93
- "@memberjunction/remote-browser-selfhost": "5.44.0",
94
- "@memberjunction/remote-browser-server": "5.44.0",
95
- "@memberjunction/scheduling-actions": "5.44.0",
96
- "@memberjunction/scheduling-base-types": "5.44.0",
97
- "@memberjunction/scheduling-engine": "5.44.0",
98
- "@memberjunction/scheduling-engine-base": "5.44.0",
99
- "@memberjunction/schema-engine": "5.44.0",
100
- "@memberjunction/search-engine": "5.44.0",
101
- "@memberjunction/server-extensions-core": "5.44.0",
102
- "@memberjunction/skip-types": "5.44.0",
103
- "@memberjunction/sql-dialect": "5.44.0",
104
- "@memberjunction/sqlserver-dataprovider": "5.44.0",
105
- "@memberjunction/storage": "5.44.0",
106
- "@memberjunction/tag-engine": "5.44.0",
107
- "@memberjunction/tag-engine-base": "5.44.0",
108
- "@memberjunction/templates": "5.44.0",
109
- "@memberjunction/testing-engine": "5.44.0",
110
- "@memberjunction/testing-engine-base": "5.44.0",
111
- "@memberjunction/version-history": "5.44.0",
30
+ "@memberjunction/actions": "5.45.0",
31
+ "@memberjunction/actions-apollo": "5.45.0",
32
+ "@memberjunction/actions-base": "5.45.0",
33
+ "@memberjunction/actions-bizapps-accounting": "5.45.0",
34
+ "@memberjunction/actions-bizapps-crm": "5.45.0",
35
+ "@memberjunction/actions-bizapps-formbuilders": "5.45.0",
36
+ "@memberjunction/actions-bizapps-lms": "5.45.0",
37
+ "@memberjunction/actions-bizapps-social": "5.45.0",
38
+ "@memberjunction/ai": "5.45.0",
39
+ "@memberjunction/ai-agent-manager": "5.45.0",
40
+ "@memberjunction/ai-agent-manager-actions": "5.45.0",
41
+ "@memberjunction/ai-agents": "5.45.0",
42
+ "@memberjunction/ai-bridge-base": "5.45.0",
43
+ "@memberjunction/ai-bridge-ringcentral": "5.45.0",
44
+ "@memberjunction/ai-bridge-server": "5.45.0",
45
+ "@memberjunction/ai-bridge-teams": "5.45.0",
46
+ "@memberjunction/ai-bridge-twilio": "5.45.0",
47
+ "@memberjunction/ai-bridge-vonage": "5.45.0",
48
+ "@memberjunction/ai-core-plus": "5.45.0",
49
+ "@memberjunction/ai-engine-base": "5.45.0",
50
+ "@memberjunction/ai-mcp-client": "5.45.0",
51
+ "@memberjunction/ai-prompts": "5.45.0",
52
+ "@memberjunction/ai-provider-bundle": "5.45.0",
53
+ "@memberjunction/ai-vector-sync": "5.45.0",
54
+ "@memberjunction/ai-vectordb": "5.45.0",
55
+ "@memberjunction/ai-vectors-pinecone": "5.45.0",
56
+ "@memberjunction/aiengine": "5.45.0",
57
+ "@memberjunction/api-keys": "5.45.0",
58
+ "@memberjunction/auth-providers": "5.45.0",
59
+ "@memberjunction/clustering-engine": "5.45.0",
60
+ "@memberjunction/codegen-lib": "5.45.0",
61
+ "@memberjunction/communication-engine": "5.45.0",
62
+ "@memberjunction/communication-ms-graph": "5.45.0",
63
+ "@memberjunction/notifications": "5.45.0",
64
+ "@memberjunction/communication-sendgrid": "5.45.0",
65
+ "@memberjunction/communication-types": "5.45.0",
66
+ "@memberjunction/component-registry-client-sdk": "5.45.0",
67
+ "@memberjunction/computer-use": "5.45.0",
68
+ "@memberjunction/computer-use-engine": "5.45.0",
69
+ "@memberjunction/config": "5.45.0",
70
+ "@memberjunction/core": "5.45.0",
71
+ "@memberjunction/core-actions": "5.45.0",
72
+ "@memberjunction/core-entities": "5.45.0",
73
+ "@memberjunction/core-entities-server": "5.45.0",
74
+ "@memberjunction/credentials": "5.45.0",
75
+ "@memberjunction/data-context": "5.45.0",
76
+ "@memberjunction/data-context-server": "5.45.0",
77
+ "@memberjunction/doc-utils": "5.45.0",
78
+ "@memberjunction/encryption": "5.45.0",
79
+ "@memberjunction/entity-communications-base": "5.45.0",
80
+ "@memberjunction/entity-communications-server": "5.45.0",
81
+ "@memberjunction/esignature": "5.45.0",
82
+ "@memberjunction/external-change-detection": "5.45.0",
83
+ "@memberjunction/generic-database-provider": "5.45.0",
84
+ "@memberjunction/global": "5.45.0",
85
+ "@memberjunction/graphql-dataprovider": "5.45.0",
86
+ "@memberjunction/integration-engine": "5.45.0",
87
+ "@memberjunction/integration-progress-artifacts": "5.45.0",
88
+ "@memberjunction/integration-schema-builder": "5.45.0",
89
+ "@memberjunction/interactive-component-types": "5.45.0",
90
+ "@memberjunction/lists": "5.45.0",
91
+ "@memberjunction/lists-base": "5.45.0",
92
+ "@memberjunction/livekit-room-server": "5.45.0",
93
+ "@memberjunction/postgresql-dataprovider": "5.45.0",
94
+ "@memberjunction/queue": "5.45.0",
95
+ "@memberjunction/record-comparison": "5.45.0",
96
+ "@memberjunction/redis-provider": "5.45.0",
97
+ "@memberjunction/remote-browser-base": "5.45.0",
98
+ "@memberjunction/remote-browser-cdp": "5.45.0",
99
+ "@memberjunction/remote-browser-selfhost": "5.45.0",
100
+ "@memberjunction/remote-browser-server": "5.45.0",
101
+ "@memberjunction/scheduling-actions": "5.45.0",
102
+ "@memberjunction/scheduling-base-types": "5.45.0",
103
+ "@memberjunction/scheduling-engine": "5.45.0",
104
+ "@memberjunction/scheduling-engine-base": "5.45.0",
105
+ "@memberjunction/schema-engine": "5.45.0",
106
+ "@memberjunction/search-engine": "5.45.0",
107
+ "@memberjunction/server-extensions-core": "5.45.0",
108
+ "@memberjunction/sql-dialect": "5.45.0",
109
+ "@memberjunction/sqlserver-dataprovider": "5.45.0",
110
+ "@memberjunction/storage": "5.45.0",
111
+ "@memberjunction/tag-engine": "5.45.0",
112
+ "@memberjunction/tag-engine-base": "5.45.0",
113
+ "@memberjunction/templates": "5.45.0",
114
+ "@memberjunction/testing-engine": "5.45.0",
115
+ "@memberjunction/testing-engine-base": "5.45.0",
116
+ "@memberjunction/version-history": "5.45.0",
112
117
  "@octokit/auth-app": "^7.1.5",
113
118
  "@octokit/rest": "^21.1.1",
114
119
  "@types/compression": "^1.8.1",
@@ -127,7 +127,7 @@ describe('SearchKnowledgeResolver', () => {
127
127
  const resolver = createResolver();
128
128
  mockSearch.mockResolvedValueOnce(createMockSearchResult());
129
129
 
130
- const result = await resolver.SearchKnowledge('test query', 20, undefined, undefined, fakeContext as never);
130
+ const result = await resolver.SearchKnowledge('test query', 20, undefined, undefined, undefined, undefined, undefined, fakeContext as never);
131
131
 
132
132
  expect(mockSearch).toHaveBeenCalledOnce();
133
133
  expect(result.Success).toBe(true);
@@ -139,7 +139,7 @@ describe('SearchKnowledgeResolver', () => {
139
139
  const resolver = createResolver();
140
140
  mockSearch.mockResolvedValueOnce(createMockSearchResult());
141
141
 
142
- await resolver.SearchKnowledge('cheese', 50, undefined, undefined, fakeContext as never);
142
+ await resolver.SearchKnowledge('cheese', 50, undefined, undefined, undefined, undefined, undefined, fakeContext as never);
143
143
 
144
144
  const searchParams = mockSearch.mock.calls[0][0];
145
145
  expect(searchParams.Query).toBe('cheese');
@@ -151,7 +151,7 @@ describe('SearchKnowledgeResolver', () => {
151
151
  mockSearch.mockResolvedValueOnce(createMockSearchResult());
152
152
 
153
153
  const filters = { EntityNames: ['Contacts'], SourceTypes: undefined, Tags: ['VIP'] };
154
- await resolver.SearchKnowledge('test', 20, filters as never, undefined, fakeContext as never);
154
+ await resolver.SearchKnowledge('test', 20, filters as never, undefined, undefined, undefined, undefined, fakeContext as never);
155
155
 
156
156
  const searchParams = mockSearch.mock.calls[0][0];
157
157
  expect(searchParams.Filters).toEqual({
@@ -165,7 +165,7 @@ describe('SearchKnowledgeResolver', () => {
165
165
  const resolver = createResolver();
166
166
  mockSearch.mockResolvedValueOnce(createMockSearchResult());
167
167
 
168
- await resolver.SearchKnowledge('test', 20, undefined, 0.5, fakeContext as never);
168
+ await resolver.SearchKnowledge('test', 20, undefined, 0.5, undefined, undefined, undefined, fakeContext as never);
169
169
 
170
170
  const searchParams = mockSearch.mock.calls[0][0];
171
171
  expect(searchParams.MinScore).toBe(0.5);
@@ -175,7 +175,7 @@ describe('SearchKnowledgeResolver', () => {
175
175
  const resolver = createResolver();
176
176
  mockSearch.mockResolvedValueOnce(createMockSearchResult());
177
177
 
178
- const result = await resolver.SearchKnowledge('test', 20, undefined, undefined, fakeContext as never);
178
+ const result = await resolver.SearchKnowledge('test', 20, undefined, undefined, undefined, undefined, undefined, fakeContext as never);
179
179
 
180
180
  const item = result.Results[0];
181
181
  expect(item.ID).toBe('result-1');
@@ -193,7 +193,7 @@ describe('SearchKnowledgeResolver', () => {
193
193
  SourceCounts: { Vector: 5, FullText: 3, Entity: 10, Storage: 0 }
194
194
  }));
195
195
 
196
- const result = await resolver.SearchKnowledge('test', 20, undefined, undefined, fakeContext as never);
196
+ const result = await resolver.SearchKnowledge('test', 20, undefined, undefined, undefined, undefined, undefined, fakeContext as never);
197
197
 
198
198
  expect(result.SourceCounts.Vector).toBe(5);
199
199
  expect(result.SourceCounts.FullText).toBe(3);
@@ -204,7 +204,7 @@ describe('SearchKnowledgeResolver', () => {
204
204
  const resolver = createResolver();
205
205
  mockSearch.mockResolvedValueOnce(createMockSearchResult({ Success: false, ErrorMessage: 'Query cannot be empty' }));
206
206
 
207
- const result = await resolver.SearchKnowledge(' ', 20, undefined, undefined, fakeContext as never);
207
+ const result = await resolver.SearchKnowledge(' ', 20, undefined, undefined, undefined, undefined, undefined, fakeContext as never);
208
208
 
209
209
  expect(mockSearch).toHaveBeenCalled();
210
210
  expect(result.Success).toBe(false);
@@ -214,7 +214,7 @@ describe('SearchKnowledgeResolver', () => {
214
214
  const resolver = new SearchKnowledgeResolver();
215
215
  (resolver as Record<string, unknown>)['GetUserFromPayload'] = vi.fn().mockReturnValue(null);
216
216
 
217
- const result = await resolver.SearchKnowledge('test', 20, undefined, undefined, fakeContext as never);
217
+ const result = await resolver.SearchKnowledge('test', 20, undefined, undefined, undefined, undefined, undefined, fakeContext as never);
218
218
 
219
219
  expect(result.Success).toBe(false);
220
220
  expect(result.ErrorMessage).toContain('current user');
@@ -224,7 +224,7 @@ describe('SearchKnowledgeResolver', () => {
224
224
  const resolver = createResolver();
225
225
  mockSearch.mockRejectedValueOnce(new Error('Connection failed'));
226
226
 
227
- const result = await resolver.SearchKnowledge('test', 20, undefined, undefined, fakeContext as never);
227
+ const result = await resolver.SearchKnowledge('test', 20, undefined, undefined, undefined, undefined, undefined, fakeContext as never);
228
228
 
229
229
  expect(result.Success).toBe(false);
230
230
  expect(result.ErrorMessage).toContain('Connection failed');
@@ -0,0 +1,65 @@
1
+ import { describe, it, expect, vi } from 'vitest';
2
+ import { TeamsMeetingsService } from '../telephony/TeamsMeetingsService.js';
3
+ import { TeamsAcsMediaRegistry } from '../telephony/teamsAcsMediaRegistry.js';
4
+ import { RealTeamsBindings } from '@memberjunction/ai-bridge-teams';
5
+ import type { BaseRealtimeBridge } from '@memberjunction/ai-bridge-base';
6
+ import type { TeamsMeetingsConfig } from '../config.js';
7
+
8
+ const CONFIG: TeamsMeetingsConfig = {
9
+ enabled: true,
10
+ tenantId: 'tenant-1',
11
+ botAccessToken: 'tok',
12
+ notificationClientState: 'secret',
13
+ acsSampleRate: 16000,
14
+ modelSampleRate: 16000,
15
+ };
16
+
17
+ describe('TeamsMeetingsService.buildBindSdk', () => {
18
+ it('binds a RealTeamsBindings factory onto the Teams driver (the live Graph + ACS wiring seam)', () => {
19
+ const service = new TeamsMeetingsService(CONFIG, new TeamsAcsMediaRegistry());
20
+ const setSdkFactory = vi.fn();
21
+ const fakeDriver = { SetSdkFactory: setSdkFactory } as unknown as BaseRealtimeBridge;
22
+ // A minimal fake Graph client (only used as a constructor arg here).
23
+ const graphClient = { CreateCall: vi.fn() } as unknown as Parameters<typeof service.buildBindSdk>[0];
24
+
25
+ service.buildBindSdk(graphClient)(fakeDriver);
26
+
27
+ expect(setSdkFactory).toHaveBeenCalledTimes(1);
28
+ const factory = setSdkFactory.mock.calls[0][0] as () => unknown;
29
+ expect(typeof factory).toBe('function');
30
+ // The factory yields a real (bound) RealTeamsBindings — proving the offline seam meets live plumbing.
31
+ expect(factory()).toBeInstanceOf(RealTeamsBindings);
32
+ });
33
+ });
34
+
35
+ describe('TeamsMeetingsService.JoinMeetingByUrl', () => {
36
+ it('returns accepted=false (never throws) when the agent identity is missing', async () => {
37
+ const provider = {
38
+ GetEntityObject: vi.fn().mockResolvedValue({ Load: vi.fn().mockResolvedValue(false), IsActive: false }),
39
+ };
40
+ const service = new TeamsMeetingsService(CONFIG, new TeamsAcsMediaRegistry());
41
+ const result = await service.JoinMeetingByUrl(
42
+ 'identity-1',
43
+ 'https://teams.microsoft.com/l/meetup-join/x',
44
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- minimal UserInfo stub for a pure-branch test
45
+ { ID: 'u1' } as never,
46
+ provider as never,
47
+ );
48
+ expect(result.accepted).toBe(false);
49
+ expect(result.reason).toMatch(/not found or inactive/i);
50
+ });
51
+ });
52
+
53
+ describe('TeamsMeetingsService notification drive helpers', () => {
54
+ it('tears down the call + registry on call-ended (no throw when no client registered)', () => {
55
+ const registry = new TeamsAcsMediaRegistry();
56
+ registry.RegisterCall('call-1');
57
+ expect(registry.HasCall('call-1')).toBe(true);
58
+ const service = new TeamsMeetingsService(CONFIG, registry);
59
+
60
+ service.DriveCallEnded('call-1');
61
+ expect(registry.HasCall('call-1')).toBe(false);
62
+ // An unknown roster drive is a silent no-op.
63
+ expect(() => service.DriveParticipantsUpdated('unknown', [{ id: 'p1' }])).not.toThrow();
64
+ });
65
+ });
@@ -0,0 +1,82 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { TeamsAcsMediaRegistry, type IAcsMediaTransport } from '../telephony/teamsAcsMediaRegistry.js';
3
+ import type { AcsInboundAudioFrame } from '@memberjunction/ai-bridge-teams';
4
+
5
+ class FakeTransport implements IAcsMediaTransport {
6
+ public readonly Sent: ArrayBuffer[] = [];
7
+ public Closed = false;
8
+ public sendAudioFrame(pcm: ArrayBuffer): void {
9
+ this.Sent.push(pcm);
10
+ }
11
+ public close(): void {
12
+ this.Closed = true;
13
+ }
14
+ }
15
+
16
+ const frame = (bytes: number): ArrayBuffer => new ArrayBuffer(bytes);
17
+
18
+ describe('TeamsAcsMediaRegistry', () => {
19
+ it('exposes the configured ACS sample rate', () => {
20
+ expect(new TeamsAcsMediaRegistry().SampleRate).toBe(16000);
21
+ expect(new TeamsAcsMediaRegistry(8000).SampleRate).toBe(8000);
22
+ });
23
+
24
+ it('buffers outbound PCM before the transport attaches, then flushes on attach', () => {
25
+ const registry = new TeamsAcsMediaRegistry();
26
+ const a = frame(4);
27
+ const b = frame(8);
28
+ registry.Send('call-1', a);
29
+ registry.Send('call-1', b);
30
+
31
+ const transport = new FakeTransport();
32
+ registry.AttachTransport('call-1', transport);
33
+
34
+ expect(transport.Sent).toEqual([a, b]);
35
+ });
36
+
37
+ it('sends immediately once the transport is attached', () => {
38
+ const registry = new TeamsAcsMediaRegistry();
39
+ const transport = new FakeTransport();
40
+ registry.AttachTransport('call-1', transport);
41
+ const a = frame(4);
42
+ registry.Send('call-1', a);
43
+ expect(transport.Sent).toEqual([a]);
44
+ });
45
+
46
+ it('dispatches inbound frames to all registered handlers for the call', () => {
47
+ const registry = new TeamsAcsMediaRegistry();
48
+ const seen: AcsInboundAudioFrame[] = [];
49
+ registry.OnFrame('call-1', (f) => seen.push(f));
50
+ registry.OnFrame('call-1', (f) => seen.push(f));
51
+ const f: AcsInboundAudioFrame = { Pcm: frame(2), ParticipantId: 'p1' };
52
+ registry.DispatchInbound('call-1', f);
53
+ expect(seen).toEqual([f, f]);
54
+ });
55
+
56
+ it('dispatches hand-raise signals to registered hand-raise handlers', () => {
57
+ const registry = new TeamsAcsMediaRegistry();
58
+ let raised: boolean | undefined;
59
+ registry.OnHandRaise('call-1', (_p, r) => (raised = r));
60
+ registry.DispatchHandRaise('call-1', 'p1', true);
61
+ expect(raised).toBe(true);
62
+ });
63
+
64
+ it('ignores inbound dispatch + hand-raise for unknown calls (no throw)', () => {
65
+ const registry = new TeamsAcsMediaRegistry();
66
+ expect(() => registry.DispatchInbound('nope', { Pcm: frame(2), ParticipantId: 'p1' })).not.toThrow();
67
+ expect(() => registry.DispatchHandRaise('nope', 'p1', true)).not.toThrow();
68
+ });
69
+
70
+ it('closes the transport and forgets the call on EndCall', () => {
71
+ const registry = new TeamsAcsMediaRegistry();
72
+ const transport = new FakeTransport();
73
+ registry.AttachTransport('call-1', transport);
74
+ expect(registry.HasCall('call-1')).toBe(true);
75
+
76
+ registry.EndCall('call-1');
77
+ expect(transport.Closed).toBe(true);
78
+ expect(registry.HasCall('call-1')).toBe(false);
79
+ // EndCall on an unknown call is a silent no-op.
80
+ expect(() => registry.EndCall('unknown')).not.toThrow();
81
+ });
82
+ });
@@ -0,0 +1,23 @@
1
+ import { describe, it, expect, vi } from 'vitest';
2
+ import { TwilioTelephonyService } from '../telephony/TwilioTelephonyService.js';
3
+ import { TwilioCallMediaRegistry } from '../telephony/twilioMediaRegistry.js';
4
+ import { TwilioCallSdk } from '@memberjunction/ai-bridge-twilio';
5
+ import type { BaseTelephonyBridge } from '@memberjunction/ai-bridge-base';
6
+
7
+ const CONFIG = { accountSid: 'AC1', authToken: 'tok', streamPublicUrl: 'wss://api.test/telephony/twilio/media' };
8
+
9
+ describe('TwilioTelephonyService.buildBindSdk', () => {
10
+ it('binds a TwilioCallSdk factory onto the telephony driver (the live REST + media wiring seam)', () => {
11
+ const service = new TwilioTelephonyService(CONFIG, new TwilioCallMediaRegistry());
12
+ const setSdkFactory = vi.fn();
13
+ const fakeDriver = { SetSdkFactory: setSdkFactory } as unknown as BaseTelephonyBridge;
14
+
15
+ service.buildBindSdk()(fakeDriver);
16
+
17
+ expect(setSdkFactory).toHaveBeenCalledTimes(1);
18
+ const factory = setSdkFactory.mock.calls[0][0] as () => unknown;
19
+ expect(typeof factory).toBe('function');
20
+ // The factory yields a real (bound) TwilioCallSdk — proving the offline seam meets live plumbing.
21
+ expect(factory()).toBeInstanceOf(TwilioCallSdk);
22
+ });
23
+ });
@@ -0,0 +1,103 @@
1
+ import { describe, it, expect, vi } from 'vitest';
2
+ import { TwilioCallMediaRegistry, type ITelephonyMediaSocket } from '../telephony/twilioMediaRegistry.js';
3
+ import type { TwilioMediaFrame } from '@memberjunction/ai-bridge-twilio';
4
+
5
+ /** A fake Media-Streams socket capturing sends + tracking close. */
6
+ function fakeSocket(): ITelephonyMediaSocket & { sent: string[]; closed: boolean } {
7
+ const sent: string[] = [];
8
+ return {
9
+ sent,
10
+ closed: false,
11
+ send(data: string) {
12
+ sent.push(data);
13
+ },
14
+ close() {
15
+ (this as { closed: boolean }).closed = true;
16
+ },
17
+ };
18
+ }
19
+
20
+ const mediaFrame = (payload: string): TwilioMediaFrame => ({ event: 'media', streamSid: 'MZ1', media: { payload } });
21
+
22
+ describe('TwilioCallMediaRegistry', () => {
23
+ describe('outbound buffering', () => {
24
+ it('buffers outbound frames before the socket connects, then flushes on AttachSocket in order', () => {
25
+ const reg = new TwilioCallMediaRegistry();
26
+ reg.RegisterCall('CA1');
27
+ reg.Send('CA1', mediaFrame('a'));
28
+ reg.Send('CA1', mediaFrame('b'));
29
+
30
+ const sock = fakeSocket();
31
+ reg.AttachSocket('CA1', sock, 'MZ1');
32
+
33
+ expect(sock.sent).toHaveLength(2);
34
+ expect(JSON.parse(sock.sent[0]).media.payload).toBe('a');
35
+ expect(JSON.parse(sock.sent[1]).media.payload).toBe('b');
36
+ });
37
+
38
+ it('sends immediately once the socket is attached', () => {
39
+ const reg = new TwilioCallMediaRegistry();
40
+ const sock = fakeSocket();
41
+ reg.AttachSocket('CA1', sock, 'MZ1');
42
+ reg.Send('CA1', mediaFrame('c'));
43
+ expect(sock.sent).toHaveLength(1);
44
+ expect(JSON.parse(sock.sent[0]).media.payload).toBe('c');
45
+ });
46
+ });
47
+
48
+ describe('inbound dispatch', () => {
49
+ it('delivers inbound frames to handlers registered before the socket existed', () => {
50
+ const reg = new TwilioCallMediaRegistry();
51
+ const received: TwilioMediaFrame[] = [];
52
+ reg.OnFrame('CA1', (f) => received.push(f));
53
+
54
+ reg.DispatchInbound('CA1', mediaFrame('in'));
55
+
56
+ expect(received).toHaveLength(1);
57
+ expect(received[0].media?.payload).toBe('in');
58
+ });
59
+
60
+ it('captures the stream SID from a start frame and exposes it via GetStreamSid', () => {
61
+ const reg = new TwilioCallMediaRegistry();
62
+ reg.RegisterCall('CA1');
63
+ expect(reg.GetStreamSid('CA1')).toBe('');
64
+ reg.DispatchInbound('CA1', { event: 'start', streamSid: 'MZ-XYZ' });
65
+ expect(reg.GetStreamSid('CA1')).toBe('MZ-XYZ');
66
+ });
67
+
68
+ it('drops inbound frames for an unknown call (no channel) without throwing', () => {
69
+ const reg = new TwilioCallMediaRegistry();
70
+ expect(() => reg.DispatchInbound('UNKNOWN', mediaFrame('x'))).not.toThrow();
71
+ });
72
+
73
+ it('fans out to multiple handlers (audio + dtmf + status all registered on one call)', () => {
74
+ const reg = new TwilioCallMediaRegistry();
75
+ const h1 = vi.fn();
76
+ const h2 = vi.fn();
77
+ reg.OnFrame('CA1', h1);
78
+ reg.OnFrame('CA1', h2);
79
+ reg.DispatchInbound('CA1', mediaFrame('y'));
80
+ expect(h1).toHaveBeenCalledTimes(1);
81
+ expect(h2).toHaveBeenCalledTimes(1);
82
+ });
83
+ });
84
+
85
+ describe('lifecycle', () => {
86
+ it('EndCall closes the socket and forgets the channel', () => {
87
+ const reg = new TwilioCallMediaRegistry();
88
+ const sock = fakeSocket();
89
+ reg.AttachSocket('CA1', sock, 'MZ1');
90
+ expect(reg.HasCall('CA1')).toBe(true);
91
+
92
+ reg.EndCall('CA1');
93
+
94
+ expect(sock.closed).toBe(true);
95
+ expect(reg.HasCall('CA1')).toBe(false);
96
+ });
97
+
98
+ it('EndCall on an unknown call is a no-op', () => {
99
+ const reg = new TwilioCallMediaRegistry();
100
+ expect(() => reg.EndCall('NOPE')).not.toThrow();
101
+ });
102
+ });
103
+ });