@memberjunction/server 5.44.0 → 5.45.1

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 (267) 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/MagicLinkService.d.ts +7 -0
  17. package/dist/auth/magicLink/MagicLinkService.d.ts.map +1 -1
  18. package/dist/auth/magicLink/MagicLinkService.js +13 -3
  19. package/dist/auth/magicLink/MagicLinkService.js.map +1 -1
  20. package/dist/auth/magicLink/index.d.ts +1 -1
  21. package/dist/auth/magicLink/index.d.ts.map +1 -1
  22. package/dist/auth/magicLink/index.js +1 -1
  23. package/dist/auth/magicLink/index.js.map +1 -1
  24. package/dist/auth/magicLink/magicLinkCore.d.ts +38 -1
  25. package/dist/auth/magicLink/magicLinkCore.d.ts.map +1 -1
  26. package/dist/auth/magicLink/magicLinkCore.js +42 -19
  27. package/dist/auth/magicLink/magicLinkCore.js.map +1 -1
  28. package/dist/auth/magicLink/types.d.ts +26 -0
  29. package/dist/auth/magicLink/types.d.ts.map +1 -1
  30. package/dist/config.d.ts +1883 -144
  31. package/dist/config.d.ts.map +1 -1
  32. package/dist/config.js +160 -36
  33. package/dist/config.js.map +1 -1
  34. package/dist/context.d.ts.map +1 -1
  35. package/dist/context.js +45 -2
  36. package/dist/context.js.map +1 -1
  37. package/dist/generated/generated.d.ts +522 -0
  38. package/dist/generated/generated.d.ts.map +1 -1
  39. package/dist/generated/generated.js +2860 -0
  40. package/dist/generated/generated.js.map +1 -1
  41. package/dist/generic/ResolverBase.d.ts +13 -0
  42. package/dist/generic/ResolverBase.d.ts.map +1 -1
  43. package/dist/generic/ResolverBase.js +22 -0
  44. package/dist/generic/ResolverBase.js.map +1 -1
  45. package/dist/generic/RunViewResolver.d.ts.map +1 -1
  46. package/dist/generic/RunViewResolver.js +4 -0
  47. package/dist/generic/RunViewResolver.js.map +1 -1
  48. package/dist/index.d.ts +0 -2
  49. package/dist/index.d.ts.map +1 -1
  50. package/dist/index.js +101 -3
  51. package/dist/index.js.map +1 -1
  52. package/dist/integration/CustomColumnPromoter.d.ts.map +1 -1
  53. package/dist/integration/CustomColumnPromoter.js +6 -0
  54. package/dist/integration/CustomColumnPromoter.js.map +1 -1
  55. package/dist/realtimeWidget/WidgetRouter.d.ts +26 -0
  56. package/dist/realtimeWidget/WidgetRouter.d.ts.map +1 -0
  57. package/dist/realtimeWidget/WidgetRouter.js +182 -0
  58. package/dist/realtimeWidget/WidgetRouter.js.map +1 -0
  59. package/dist/realtimeWidget/WidgetSessionService.d.ts +265 -0
  60. package/dist/realtimeWidget/WidgetSessionService.d.ts.map +1 -0
  61. package/dist/realtimeWidget/WidgetSessionService.js +477 -0
  62. package/dist/realtimeWidget/WidgetSessionService.js.map +1 -0
  63. package/dist/realtimeWidget/host-identity.d.ts +40 -0
  64. package/dist/realtimeWidget/host-identity.d.ts.map +1 -0
  65. package/dist/realtimeWidget/host-identity.js +58 -0
  66. package/dist/realtimeWidget/host-identity.js.map +1 -0
  67. package/dist/realtimeWidget/index.d.ts +10 -0
  68. package/dist/realtimeWidget/index.d.ts.map +1 -0
  69. package/dist/realtimeWidget/index.js +9 -0
  70. package/dist/realtimeWidget/index.js.map +1 -0
  71. package/dist/realtimeWidget/visitorIdentity.d.ts +76 -0
  72. package/dist/realtimeWidget/visitorIdentity.d.ts.map +1 -0
  73. package/dist/realtimeWidget/visitorIdentity.js +202 -0
  74. package/dist/realtimeWidget/visitorIdentity.js.map +1 -0
  75. package/dist/realtimeWidget/widgetCore.d.ts +106 -0
  76. package/dist/realtimeWidget/widgetCore.d.ts.map +1 -0
  77. package/dist/realtimeWidget/widgetCore.js +173 -0
  78. package/dist/realtimeWidget/widgetCore.js.map +1 -0
  79. package/dist/realtimeWidget/widgetGuestElevation.d.ts +51 -0
  80. package/dist/realtimeWidget/widgetGuestElevation.d.ts.map +1 -0
  81. package/dist/realtimeWidget/widgetGuestElevation.js +79 -0
  82. package/dist/realtimeWidget/widgetGuestElevation.js.map +1 -0
  83. package/dist/resolvers/ComponentRegistryResolver.d.ts +7 -0
  84. package/dist/resolvers/ComponentRegistryResolver.d.ts.map +1 -1
  85. package/dist/resolvers/ComponentRegistryResolver.js +31 -8
  86. package/dist/resolvers/ComponentRegistryResolver.js.map +1 -1
  87. package/dist/resolvers/EntityPermissionResolver.d.ts.map +1 -1
  88. package/dist/resolvers/EntityPermissionResolver.js +1 -2
  89. package/dist/resolvers/EntityPermissionResolver.js.map +1 -1
  90. package/dist/resolvers/QuerySystemUserResolver.d.ts +9 -6
  91. package/dist/resolvers/QuerySystemUserResolver.d.ts.map +1 -1
  92. package/dist/resolvers/QuerySystemUserResolver.js +15 -13
  93. package/dist/resolvers/QuerySystemUserResolver.js.map +1 -1
  94. package/dist/resolvers/RealtimeClientSessionResolver.d.ts +10 -0
  95. package/dist/resolvers/RealtimeClientSessionResolver.d.ts.map +1 -1
  96. package/dist/resolvers/RealtimeClientSessionResolver.js +47 -3
  97. package/dist/resolvers/RealtimeClientSessionResolver.js.map +1 -1
  98. package/dist/resolvers/RingCentralTelephonyResolver.d.ts +27 -0
  99. package/dist/resolvers/RingCentralTelephonyResolver.d.ts.map +1 -0
  100. package/dist/resolvers/RingCentralTelephonyResolver.js +87 -0
  101. package/dist/resolvers/RingCentralTelephonyResolver.js.map +1 -0
  102. package/dist/resolvers/RunAIAgentResolver.d.ts +9 -0
  103. package/dist/resolvers/RunAIAgentResolver.d.ts.map +1 -1
  104. package/dist/resolvers/RunAIAgentResolver.js +20 -4
  105. package/dist/resolvers/RunAIAgentResolver.js.map +1 -1
  106. package/dist/resolvers/SearchKnowledgeResolver.d.ts.map +1 -1
  107. package/dist/resolvers/SearchKnowledgeResolver.js +2 -0
  108. package/dist/resolvers/SearchKnowledgeResolver.js.map +1 -1
  109. package/dist/resolvers/TeamsMeetingsResolver.d.ts +28 -0
  110. package/dist/resolvers/TeamsMeetingsResolver.d.ts.map +1 -0
  111. package/dist/resolvers/TeamsMeetingsResolver.js +91 -0
  112. package/dist/resolvers/TeamsMeetingsResolver.js.map +1 -0
  113. package/dist/resolvers/TelephonyResolver.d.ts +26 -0
  114. package/dist/resolvers/TelephonyResolver.d.ts.map +1 -0
  115. package/dist/resolvers/TelephonyResolver.js +86 -0
  116. package/dist/resolvers/TelephonyResolver.js.map +1 -0
  117. package/dist/resolvers/TestQuerySQLResolver.d.ts +1 -1
  118. package/dist/resolvers/TestQuerySQLResolver.d.ts.map +1 -1
  119. package/dist/resolvers/TestQuerySQLResolver.js +2 -3
  120. package/dist/resolvers/TestQuerySQLResolver.js.map +1 -1
  121. package/dist/resolvers/VonageTelephonyResolver.d.ts +26 -0
  122. package/dist/resolvers/VonageTelephonyResolver.d.ts.map +1 -0
  123. package/dist/resolvers/VonageTelephonyResolver.js +86 -0
  124. package/dist/resolvers/VonageTelephonyResolver.js.map +1 -0
  125. package/dist/rest/MediaStreamHandler.js +4 -1
  126. package/dist/rest/MediaStreamHandler.js.map +1 -1
  127. package/dist/telephony/RingCentralTelephonyService.d.ts +115 -0
  128. package/dist/telephony/RingCentralTelephonyService.d.ts.map +1 -0
  129. package/dist/telephony/RingCentralTelephonyService.js +262 -0
  130. package/dist/telephony/RingCentralTelephonyService.js.map +1 -0
  131. package/dist/telephony/TeamsMeetingsRouter.d.ts +40 -0
  132. package/dist/telephony/TeamsMeetingsRouter.d.ts.map +1 -0
  133. package/dist/telephony/TeamsMeetingsRouter.js +96 -0
  134. package/dist/telephony/TeamsMeetingsRouter.js.map +1 -0
  135. package/dist/telephony/TeamsMeetingsService.d.ts +113 -0
  136. package/dist/telephony/TeamsMeetingsService.d.ts.map +1 -0
  137. package/dist/telephony/TeamsMeetingsService.js +196 -0
  138. package/dist/telephony/TeamsMeetingsService.js.map +1 -0
  139. package/dist/telephony/TwilioTelephonyRouter.d.ts +36 -0
  140. package/dist/telephony/TwilioTelephonyRouter.d.ts.map +1 -0
  141. package/dist/telephony/TwilioTelephonyRouter.js +143 -0
  142. package/dist/telephony/TwilioTelephonyRouter.js.map +1 -0
  143. package/dist/telephony/TwilioTelephonyService.d.ts +95 -0
  144. package/dist/telephony/TwilioTelephonyService.d.ts.map +1 -0
  145. package/dist/telephony/TwilioTelephonyService.js +193 -0
  146. package/dist/telephony/TwilioTelephonyService.js.map +1 -0
  147. package/dist/telephony/VonageTelephonyRouter.d.ts +41 -0
  148. package/dist/telephony/VonageTelephonyRouter.d.ts.map +1 -0
  149. package/dist/telephony/VonageTelephonyRouter.js +201 -0
  150. package/dist/telephony/VonageTelephonyRouter.js.map +1 -0
  151. package/dist/telephony/VonageTelephonyService.d.ts +90 -0
  152. package/dist/telephony/VonageTelephonyService.d.ts.map +1 -0
  153. package/dist/telephony/VonageTelephonyService.js +191 -0
  154. package/dist/telephony/VonageTelephonyService.js.map +1 -0
  155. package/dist/telephony/calendar-scheduler.d.ts +67 -0
  156. package/dist/telephony/calendar-scheduler.d.ts.map +1 -0
  157. package/dist/telephony/calendar-scheduler.js +133 -0
  158. package/dist/telephony/calendar-scheduler.js.map +1 -0
  159. package/dist/telephony/index.d.ts +29 -0
  160. package/dist/telephony/index.d.ts.map +1 -0
  161. package/dist/telephony/index.js +38 -0
  162. package/dist/telephony/index.js.map +1 -0
  163. package/dist/telephony/media-upgrade-router.d.ts +33 -0
  164. package/dist/telephony/media-upgrade-router.d.ts.map +1 -0
  165. package/dist/telephony/media-upgrade-router.js +56 -0
  166. package/dist/telephony/media-upgrade-router.js.map +1 -0
  167. package/dist/telephony/ringcentral-runtime.d.ts +14 -0
  168. package/dist/telephony/ringcentral-runtime.d.ts.map +1 -0
  169. package/dist/telephony/ringcentral-runtime.js +18 -0
  170. package/dist/telephony/ringcentral-runtime.js.map +1 -0
  171. package/dist/telephony/teams-meetings-runtime.d.ts +16 -0
  172. package/dist/telephony/teams-meetings-runtime.d.ts.map +1 -0
  173. package/dist/telephony/teams-meetings-runtime.js +20 -0
  174. package/dist/telephony/teams-meetings-runtime.js.map +1 -0
  175. package/dist/telephony/teamsAcsMediaRegistry.d.ts +69 -0
  176. package/dist/telephony/teamsAcsMediaRegistry.d.ts.map +1 -0
  177. package/dist/telephony/teamsAcsMediaRegistry.js +118 -0
  178. package/dist/telephony/teamsAcsMediaRegistry.js.map +1 -0
  179. package/dist/telephony/telephony-runtime.d.ts +14 -0
  180. package/dist/telephony/telephony-runtime.d.ts.map +1 -0
  181. package/dist/telephony/telephony-runtime.js +18 -0
  182. package/dist/telephony/telephony-runtime.js.map +1 -0
  183. package/dist/telephony/twilioMediaRegistry.d.ts +60 -0
  184. package/dist/telephony/twilioMediaRegistry.d.ts.map +1 -0
  185. package/dist/telephony/twilioMediaRegistry.js +106 -0
  186. package/dist/telephony/twilioMediaRegistry.js.map +1 -0
  187. package/dist/telephony/vonage-runtime.d.ts +14 -0
  188. package/dist/telephony/vonage-runtime.d.ts.map +1 -0
  189. package/dist/telephony/vonage-runtime.js +18 -0
  190. package/dist/telephony/vonage-runtime.js.map +1 -0
  191. package/dist/telephony/vonageMediaRegistry.d.ts +78 -0
  192. package/dist/telephony/vonageMediaRegistry.d.ts.map +1 -0
  193. package/dist/telephony/vonageMediaRegistry.js +158 -0
  194. package/dist/telephony/vonageMediaRegistry.js.map +1 -0
  195. package/package.json +88 -83
  196. package/src/__tests__/RunAIAgentResolver.streaming.test.ts +128 -0
  197. package/src/__tests__/magicLink.test.ts +53 -3
  198. package/src/__tests__/search-knowledge-tags.test.ts +9 -9
  199. package/src/__tests__/teams-meetings-service.test.ts +65 -0
  200. package/src/__tests__/teamsAcsMediaRegistry.test.ts +82 -0
  201. package/src/__tests__/twilio-telephony-service.test.ts +23 -0
  202. package/src/__tests__/twilioMediaRegistry.test.ts +103 -0
  203. package/src/__tests__/vonageMediaRegistry.test.ts +180 -0
  204. package/src/__tests__/widget.test.ts +204 -0
  205. package/src/__tests__/widgetGuestElevation.test.ts +57 -0
  206. package/src/__tests__/widgetHostIdentity.test.ts +117 -0
  207. package/src/agentSessions/ReturningVisitorRecap.ts +242 -0
  208. package/src/agentSessions/SessionJanitor.ts +66 -6
  209. package/src/agentSessions/SessionManager.ts +38 -0
  210. package/src/auth/magicLink/MagicLinkRouter.ts +17 -0
  211. package/src/auth/magicLink/MagicLinkService.ts +13 -3
  212. package/src/auth/magicLink/index.ts +1 -0
  213. package/src/auth/magicLink/magicLinkCore.ts +48 -20
  214. package/src/auth/magicLink/types.ts +26 -0
  215. package/src/config.ts +172 -38
  216. package/src/context.ts +50 -3
  217. package/src/generated/generated.ts +1991 -1
  218. package/src/generic/ResolverBase.ts +28 -0
  219. package/src/generic/RunViewResolver.ts +4 -0
  220. package/src/index.ts +109 -3
  221. package/src/integration/CustomColumnPromoter.ts +6 -0
  222. package/src/realtimeWidget/WidgetRouter.ts +204 -0
  223. package/src/realtimeWidget/WidgetSessionService.ts +714 -0
  224. package/src/realtimeWidget/host-identity.ts +84 -0
  225. package/src/realtimeWidget/index.ts +15 -0
  226. package/src/realtimeWidget/visitorIdentity.ts +258 -0
  227. package/src/realtimeWidget/widgetCore.ts +231 -0
  228. package/src/realtimeWidget/widgetGuestElevation.ts +115 -0
  229. package/src/resolvers/ComponentRegistryResolver.ts +36 -10
  230. package/src/resolvers/EntityPermissionResolver.ts +1 -2
  231. package/src/resolvers/QuerySystemUserResolver.ts +14 -10
  232. package/src/resolvers/RealtimeClientSessionResolver.ts +59 -2
  233. package/src/resolvers/RingCentralTelephonyResolver.ts +64 -0
  234. package/src/resolvers/RunAIAgentResolver.ts +32 -8
  235. package/src/resolvers/SearchKnowledgeResolver.ts +2 -0
  236. package/src/resolvers/TeamsMeetingsResolver.ts +68 -0
  237. package/src/resolvers/TelephonyResolver.ts +63 -0
  238. package/src/resolvers/TestQuerySQLResolver.ts +2 -3
  239. package/src/resolvers/VonageTelephonyResolver.ts +63 -0
  240. package/src/rest/MediaStreamHandler.ts +4 -1
  241. package/src/telephony/RingCentralTelephonyService.ts +342 -0
  242. package/src/telephony/TeamsMeetingsRouter.ts +124 -0
  243. package/src/telephony/TeamsMeetingsService.ts +268 -0
  244. package/src/telephony/TwilioTelephonyRouter.ts +184 -0
  245. package/src/telephony/TwilioTelephonyService.ts +261 -0
  246. package/src/telephony/VonageTelephonyRouter.ts +239 -0
  247. package/src/telephony/VonageTelephonyService.ts +259 -0
  248. package/src/telephony/calendar-scheduler.ts +176 -0
  249. package/src/telephony/index.ts +43 -0
  250. package/src/telephony/media-upgrade-router.ts +62 -0
  251. package/src/telephony/ringcentral-runtime.ts +22 -0
  252. package/src/telephony/teams-meetings-runtime.ts +24 -0
  253. package/src/telephony/teamsAcsMediaRegistry.ts +152 -0
  254. package/src/telephony/telephony-runtime.ts +22 -0
  255. package/src/telephony/twilioMediaRegistry.ts +137 -0
  256. package/src/telephony/vonage-runtime.ts +22 -0
  257. package/src/telephony/vonageMediaRegistry.ts +200 -0
  258. package/dist/agents/skip-agent.d.ts +0 -111
  259. package/dist/agents/skip-agent.d.ts.map +0 -1
  260. package/dist/agents/skip-agent.js +0 -1487
  261. package/dist/agents/skip-agent.js.map +0 -1
  262. package/dist/agents/skip-sdk.d.ts +0 -261
  263. package/dist/agents/skip-sdk.d.ts.map +0 -1
  264. package/dist/agents/skip-sdk.js +0 -909
  265. package/dist/agents/skip-sdk.js.map +0 -1
  266. package/src/agents/skip-agent.ts +0 -1594
  267. 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.1",
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.1",
31
+ "@memberjunction/actions-apollo": "5.45.1",
32
+ "@memberjunction/actions-base": "5.45.1",
33
+ "@memberjunction/actions-bizapps-accounting": "5.45.1",
34
+ "@memberjunction/actions-bizapps-crm": "5.45.1",
35
+ "@memberjunction/actions-bizapps-formbuilders": "5.45.1",
36
+ "@memberjunction/actions-bizapps-lms": "5.45.1",
37
+ "@memberjunction/actions-bizapps-social": "5.45.1",
38
+ "@memberjunction/ai": "5.45.1",
39
+ "@memberjunction/ai-agent-manager": "5.45.1",
40
+ "@memberjunction/ai-agent-manager-actions": "5.45.1",
41
+ "@memberjunction/ai-agents": "5.45.1",
42
+ "@memberjunction/ai-bridge-base": "5.45.1",
43
+ "@memberjunction/ai-bridge-ringcentral": "5.45.1",
44
+ "@memberjunction/ai-bridge-server": "5.45.1",
45
+ "@memberjunction/ai-bridge-teams": "5.45.1",
46
+ "@memberjunction/ai-bridge-twilio": "5.45.1",
47
+ "@memberjunction/ai-bridge-vonage": "5.45.1",
48
+ "@memberjunction/ai-core-plus": "5.45.1",
49
+ "@memberjunction/ai-engine-base": "5.45.1",
50
+ "@memberjunction/ai-mcp-client": "5.45.1",
51
+ "@memberjunction/ai-prompts": "5.45.1",
52
+ "@memberjunction/ai-provider-bundle": "5.45.1",
53
+ "@memberjunction/ai-vector-sync": "5.45.1",
54
+ "@memberjunction/ai-vectordb": "5.45.1",
55
+ "@memberjunction/ai-vectors-pinecone": "5.45.1",
56
+ "@memberjunction/aiengine": "5.45.1",
57
+ "@memberjunction/api-keys": "5.45.1",
58
+ "@memberjunction/auth-providers": "5.45.1",
59
+ "@memberjunction/clustering-engine": "5.45.1",
60
+ "@memberjunction/codegen-lib": "5.45.1",
61
+ "@memberjunction/communication-engine": "5.45.1",
62
+ "@memberjunction/communication-ms-graph": "5.45.1",
63
+ "@memberjunction/notifications": "5.45.1",
64
+ "@memberjunction/communication-sendgrid": "5.45.1",
65
+ "@memberjunction/communication-types": "5.45.1",
66
+ "@memberjunction/component-registry-client-sdk": "5.45.1",
67
+ "@memberjunction/computer-use": "5.45.1",
68
+ "@memberjunction/computer-use-engine": "5.45.1",
69
+ "@memberjunction/config": "5.45.1",
70
+ "@memberjunction/core": "5.45.1",
71
+ "@memberjunction/core-actions": "5.45.1",
72
+ "@memberjunction/core-entities": "5.45.1",
73
+ "@memberjunction/core-entities-server": "5.45.1",
74
+ "@memberjunction/credentials": "5.45.1",
75
+ "@memberjunction/data-context": "5.45.1",
76
+ "@memberjunction/data-context-server": "5.45.1",
77
+ "@memberjunction/doc-utils": "5.45.1",
78
+ "@memberjunction/encryption": "5.45.1",
79
+ "@memberjunction/entity-communications-base": "5.45.1",
80
+ "@memberjunction/entity-communications-server": "5.45.1",
81
+ "@memberjunction/esignature": "5.45.1",
82
+ "@memberjunction/external-change-detection": "5.45.1",
83
+ "@memberjunction/generic-database-provider": "5.45.1",
84
+ "@memberjunction/global": "5.45.1",
85
+ "@memberjunction/graphql-dataprovider": "5.45.1",
86
+ "@memberjunction/integration-engine": "5.45.1",
87
+ "@memberjunction/integration-progress-artifacts": "5.45.1",
88
+ "@memberjunction/integration-schema-builder": "5.45.1",
89
+ "@memberjunction/interactive-component-types": "5.45.1",
90
+ "@memberjunction/lists": "5.45.1",
91
+ "@memberjunction/lists-base": "5.45.1",
92
+ "@memberjunction/livekit-room-server": "5.45.1",
93
+ "@memberjunction/postgresql-dataprovider": "5.45.1",
94
+ "@memberjunction/queue": "5.45.1",
95
+ "@memberjunction/record-comparison": "5.45.1",
96
+ "@memberjunction/redis-provider": "5.45.1",
97
+ "@memberjunction/remote-browser-base": "5.45.1",
98
+ "@memberjunction/remote-browser-cdp": "5.45.1",
99
+ "@memberjunction/remote-browser-selfhost": "5.45.1",
100
+ "@memberjunction/remote-browser-server": "5.45.1",
101
+ "@memberjunction/scheduling-actions": "5.45.1",
102
+ "@memberjunction/scheduling-base-types": "5.45.1",
103
+ "@memberjunction/scheduling-engine": "5.45.1",
104
+ "@memberjunction/scheduling-engine-base": "5.45.1",
105
+ "@memberjunction/schema-engine": "5.45.1",
106
+ "@memberjunction/search-engine": "5.45.1",
107
+ "@memberjunction/server-extensions-core": "5.45.1",
108
+ "@memberjunction/sql-dialect": "5.45.1",
109
+ "@memberjunction/sqlserver-dataprovider": "5.45.1",
110
+ "@memberjunction/storage": "5.45.1",
111
+ "@memberjunction/tag-engine": "5.45.1",
112
+ "@memberjunction/tag-engine-base": "5.45.1",
113
+ "@memberjunction/templates": "5.45.1",
114
+ "@memberjunction/testing-engine": "5.45.1",
115
+ "@memberjunction/testing-engine-base": "5.45.1",
116
+ "@memberjunction/version-history": "5.45.1",
112
117
  "@octokit/auth-app": "^7.1.5",
113
118
  "@octokit/rest": "^21.1.1",
114
119
  "@types/compression": "^1.8.1",
@@ -0,0 +1,128 @@
1
+ /**
2
+ * @fileoverview Wire-shape tests for RunAIAgentResolver's streaming callback.
3
+ *
4
+ * The conversation client (ConversationsRuntime's ConversationStreaming) parses the
5
+ * exact JSON this resolver publishes to the PushStatusUpdates topic — in particular
6
+ * `data.type === 'streaming'` and `data.streaming.{content,isPartial,kind}`. These
7
+ * tests pin the published shape so the server and client can't silently drift
8
+ * (the client's own parsing of this same shape is pinned in
9
+ * packages/ConversationsRuntime/src/__tests__/ConversationStreaming.test.ts).
10
+ */
11
+ import 'reflect-metadata'; // must precede any type-graphql decorator evaluation
12
+ import { describe, it, expect, vi } from 'vitest';
13
+ import type { PubSubEngine } from 'type-graphql';
14
+
15
+ // type-graphql's real decorators need emitDecoratorMetadata to infer field types
16
+ // (`@Field() success: boolean`), which vitest's esbuild transform does not emit.
17
+ // The GraphQL schema is irrelevant here — no-op every decorator so the resolver
18
+ // module can be imported and its streaming callback exercised directly.
19
+ vi.mock('type-graphql', () => {
20
+ const decoratorFactory = (..._args: unknown[]) => (..._decorated: unknown[]) => undefined;
21
+ const exportNames = [
22
+ 'Resolver', 'Query', 'Mutation', 'Subscription', 'Arg', 'Args', 'ArgsType', 'Ctx', 'Root',
23
+ 'Info', 'Field', 'FieldResolver', 'ObjectType', 'InputType', 'InterfaceType', 'Authorized',
24
+ 'UseMiddleware', 'Extensions', 'Directive', 'ID', 'Int', 'Float', 'GraphQLISODateTime',
25
+ 'GraphQLTimestamp', 'registerEnumType', 'createMethodDecorator', 'createParamDecorator',
26
+ 'buildSchema', 'buildSchemaSync', 'PubSub',
27
+ ];
28
+ return Object.fromEntries(exportNames.map((name) => [name, decoratorFactory]));
29
+ });
30
+ import type { AgentExecutionStreamingCallback } from '@memberjunction/ai-core-plus';
31
+
32
+ import { RunAIAgentResolver } from '../resolvers/RunAIAgentResolver.js';
33
+ import type { UserPayload } from '../types.js';
34
+
35
+ /** Access the private factory without widening the class's public API. */
36
+ interface StreamingCallbackFactory {
37
+ createStreamingCallback(
38
+ pubSub: PubSubEngine,
39
+ sessionId: string,
40
+ userPayload: UserPayload,
41
+ agentRunRef: { current: unknown }
42
+ ): AgentExecutionStreamingCallback;
43
+ }
44
+
45
+ function buildHarness() {
46
+ const publish = vi.fn().mockResolvedValue(undefined);
47
+ const pubSub = { publish } as unknown as PubSubEngine;
48
+ const userPayload = { sessionId: 'session-1' } as UserPayload;
49
+ const agentRunRef = {
50
+ current: {
51
+ ID: 'run-1',
52
+ GetAll: () => ({ ID: 'run-1', ConversationDetailID: 'detail-1', Agent: 'Betty' }),
53
+ },
54
+ };
55
+ const resolver = new RunAIAgentResolver() as unknown as StreamingCallbackFactory;
56
+ const callback = resolver.createStreamingCallback(pubSub, 'session-1', userPayload, agentRunRef);
57
+ return { publish, callback };
58
+ }
59
+
60
+ /** Parse the published envelope back out of the pubSub.publish mock. */
61
+ function publishedData(publish: ReturnType<typeof vi.fn>): Record<string, unknown> {
62
+ expect(publish).toHaveBeenCalledOnce();
63
+ const envelope = publish.mock.calls[0][1] as { message: string };
64
+ const parsed = JSON.parse(envelope.message) as Record<string, unknown>;
65
+ expect(parsed.type).toBe('StreamingContent');
66
+ expect(parsed.resolver).toBe('RunAIAgentResolver');
67
+ return parsed.data as Record<string, unknown>;
68
+ }
69
+
70
+ describe('RunAIAgentResolver.createStreamingCallback', () => {
71
+ it('publishes the streaming wire shape the conversation client parses', () => {
72
+ const { publish, callback } = buildHarness();
73
+
74
+ callback({ content: 'Hel', isComplete: false, stepType: 'prompt', modelName: 'gpt-x', kind: 'final-response' });
75
+
76
+ const data = publishedData(publish);
77
+ expect(data.type).toBe('streaming');
78
+ expect(data.agentRunId).toBe('run-1');
79
+ expect((data.agentRun as Record<string, unknown>).ConversationDetailID).toBe('detail-1');
80
+ expect(data.streaming).toMatchObject({
81
+ content: 'Hel',
82
+ isPartial: true,
83
+ stepName: 'prompt',
84
+ kind: 'final-response',
85
+ });
86
+ });
87
+
88
+ it('maps isComplete=true to isPartial=false on the final chunk', () => {
89
+ const { publish, callback } = buildHarness();
90
+
91
+ callback({ content: '', isComplete: true, kind: 'final-response' });
92
+
93
+ const data = publishedData(publish);
94
+ expect((data.streaming as Record<string, unknown>).isPartial).toBe(false);
95
+ });
96
+
97
+ it('passes an absent kind through untouched — unmarked raw streams must stay unrendered', () => {
98
+ // Guard rail: if the resolver ever defaults unmarked chunks to a renderable
99
+ // kind (e.g. `chunk.kind ?? 'final-response'` left in from local testing),
100
+ // every Loop agent's raw JSON envelope would render into chat bubbles.
101
+ // This test fails the moment such a fallback exists.
102
+ const { publish, callback } = buildHarness();
103
+
104
+ callback({ content: '{"taskComplete":', isComplete: false, stepType: 'prompt' });
105
+
106
+ const data = publishedData(publish);
107
+ expect((data.streaming as Record<string, unknown>).kind).toBeUndefined();
108
+ });
109
+
110
+ it('does not publish when no agent run is available yet', () => {
111
+ const publish = vi.fn();
112
+ const pubSub = { publish } as unknown as PubSubEngine;
113
+ const resolver = new RunAIAgentResolver() as unknown as StreamingCallbackFactory;
114
+ const callback = resolver.createStreamingCallback(
115
+ pubSub,
116
+ 'session-1',
117
+ { sessionId: 'session-1' } as UserPayload,
118
+ { current: null }
119
+ );
120
+ const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => undefined);
121
+ try {
122
+ callback({ content: 'early', isComplete: false });
123
+ expect(publish).not.toHaveBeenCalled();
124
+ } finally {
125
+ consoleSpy.mockRestore();
126
+ }
127
+ });
128
+ });
@@ -1,6 +1,6 @@
1
1
  import { describe, it, expect } from 'vitest';
2
2
  import jwt from 'jsonwebtoken';
3
- import { createPublicKey } from 'node:crypto';
3
+ import { createPublicKey, type JsonWebKey } from 'node:crypto';
4
4
  import {
5
5
  generateRawToken,
6
6
  hashToken,
@@ -228,6 +228,56 @@ describe('magic-link core', () => {
228
228
  });
229
229
  });
230
230
 
231
+ describe('buildConsumeInviteSQL (postgresql dialect)', () => {
232
+ // PG uses `schema.table` (unquoted — PostgreSQLDataProvider.ExecuteSQL auto-quotes
233
+ // the PascalCase identifiers). SS uses the bracket-quoted `[schema].[table]` form.
234
+ const pgTable = '__mj.MagicLinkInvite';
235
+ const pgSql = buildConsumeInviteSQL(pgTable, 'postgresql');
236
+
237
+ it('targets the supplied unquoted schema.table', () => {
238
+ expect(pgSql).toContain(`UPDATE ${pgTable} `);
239
+ });
240
+
241
+ it('uses UPDATE … RETURNING as the atomic single-use gate (no OUTPUT/DECLARE table var)', () => {
242
+ expect(pgSql).toContain('RETURNING ID;');
243
+ expect(pgSql).not.toContain('OUTPUT');
244
+ expect(pgSql).not.toContain('DECLARE');
245
+ });
246
+
247
+ it('binds the invite ID as PG positional param $1, not T-SQL @p0 (injection-safe)', () => {
248
+ expect(pgSql).toContain('ID = $1');
249
+ expect(pgSql).not.toContain('@p0');
250
+ expect(pgSql).not.toMatch(/@/); // no T-SQL @-anything survives on PG
251
+ expect(pgSql).not.toMatch(/ID = '/);
252
+ });
253
+
254
+ it('uses PG timestamp expressions, not T-SQL SYSUTCDATETIME()', () => {
255
+ expect(pgSql).not.toContain('SYSUTCDATETIME');
256
+ expect(pgSql).toContain("(now() AT TIME ZONE 'utc')");
257
+ expect(pgSql).toContain("ConsumedAt = COALESCE(ConsumedAt, (now() AT TIME ZONE 'utc'))");
258
+ });
259
+
260
+ it('guards atomically on Active + not-exhausted + not-expired (same predicate as SS)', () => {
261
+ const where = pgSql.slice(pgSql.indexOf('WHERE'));
262
+ expect(where).toContain("Status = 'Active'");
263
+ expect(where).toContain('UseCount < MaxUses');
264
+ expect(where).toContain("ExpiresAt > (now() AT TIME ZONE 'utc')");
265
+ });
266
+
267
+ it('increments UseCount and flips Status on the last use (same semantics as SS)', () => {
268
+ expect(pgSql).toContain('UseCount = UseCount + 1');
269
+ expect(pgSql).toContain("Status = CASE WHEN UseCount + 1 >= MaxUses THEN 'Consumed' ELSE Status END");
270
+ });
271
+
272
+ it('rejects a non-whitelisted PG table identifier (defense-in-depth against injection)', () => {
273
+ // Bracket-quoted (SS) form is not a valid PG identifier here.
274
+ expect(() => buildConsumeInviteSQL('[__mj].[MagicLinkInvite]', 'postgresql')).toThrow();
275
+ expect(() => buildConsumeInviteSQL('__mj.MagicLinkInvite; DROP TABLE x;--', 'postgresql')).toThrow();
276
+ expect(() => buildConsumeInviteSQL('__mj.Magic Link', 'postgresql')).toThrow();
277
+ expect(() => buildConsumeInviteSQL(pgTable, 'postgresql')).not.toThrow();
278
+ });
279
+ });
280
+
231
281
  describe('canIssueInvites', () => {
232
282
  it('always allows Owners, regardless of issuer-role config (case/space-insensitive)', () => {
233
283
  expect(canIssueInvites('Owner', [], [])).toBe(true);
@@ -351,7 +401,7 @@ describe('MagicLinkKeyManager', () => {
351
401
  expect(header.kid).toBe(jwk.kid);
352
402
 
353
403
  // Full verification against the public key reconstructed from the JWK.
354
- const publicKey = createPublicKey({ key: jwk as object, format: 'jwk' });
404
+ const publicKey = createPublicKey({ key: jwk as unknown as JsonWebKey, format: 'jwk' });
355
405
  const decoded = jwt.verify(token, publicKey, {
356
406
  algorithms: ['RS256'],
357
407
  issuer: 'http://localhost:4051',
@@ -375,7 +425,7 @@ describe('MagicLinkKeyManager', () => {
375
425
  ttlSeconds: 3600,
376
426
  });
377
427
  const token = km.Sign(claims);
378
- const publicKey = createPublicKey({ key: km.GetJWKS().keys[0] as object, format: 'jwk' });
428
+ const publicKey = createPublicKey({ key: km.GetJWKS().keys[0] as unknown as JsonWebKey, format: 'jwk' });
379
429
 
380
430
  // Flip a character in the payload segment.
381
431
  const parts = token.split('.');
@@ -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
+ });