@memberjunction/server 6.2.0-edge.2 → 6.2.0-edge.4

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 (435) hide show
  1. package/README.md +30 -0
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/agentSessions/BridgeHostInstance.d.ts +25 -0
  4. package/dist/agentSessions/BridgeHostInstance.d.ts.map +1 -0
  5. package/dist/agentSessions/BridgeHostInstance.js +30 -0
  6. package/dist/agentSessions/BridgeHostInstance.js.map +1 -0
  7. package/dist/agentSessions/HostInstance.d.ts +75 -11
  8. package/dist/agentSessions/HostInstance.d.ts.map +1 -1
  9. package/dist/agentSessions/HostInstance.js +99 -28
  10. package/dist/agentSessions/HostInstance.js.map +1 -1
  11. package/dist/agentSessions/ReturningVisitorRecap.d.ts.map +1 -1
  12. package/dist/agentSessions/ReturningVisitorRecap.js +7 -3
  13. package/dist/agentSessions/ReturningVisitorRecap.js.map +1 -1
  14. package/dist/agentSessions/SessionJanitor.d.ts +173 -25
  15. package/dist/agentSessions/SessionJanitor.d.ts.map +1 -1
  16. package/dist/agentSessions/SessionJanitor.js +452 -54
  17. package/dist/agentSessions/SessionJanitor.js.map +1 -1
  18. package/dist/agentSessions/SessionManager.d.ts +43 -2
  19. package/dist/agentSessions/SessionManager.d.ts.map +1 -1
  20. package/dist/agentSessions/SessionManager.js +99 -8
  21. package/dist/agentSessions/SessionManager.js.map +1 -1
  22. package/dist/agentSessions/SessionRunIDVerifier.d.ts +63 -0
  23. package/dist/agentSessions/SessionRunIDVerifier.d.ts.map +1 -0
  24. package/dist/agentSessions/SessionRunIDVerifier.js +129 -0
  25. package/dist/agentSessions/SessionRunIDVerifier.js.map +1 -0
  26. package/dist/agentSessions/index.d.ts +2 -0
  27. package/dist/agentSessions/index.d.ts.map +1 -1
  28. package/dist/agentSessions/index.js +10 -3
  29. package/dist/agentSessions/index.js.map +1 -1
  30. package/dist/auth/actionAuthorization.d.ts +40 -0
  31. package/dist/auth/actionAuthorization.d.ts.map +1 -0
  32. package/dist/auth/actionAuthorization.js +94 -0
  33. package/dist/auth/actionAuthorization.js.map +1 -0
  34. package/dist/auth/index.d.ts.map +1 -1
  35. package/dist/auth/index.js +3 -10
  36. package/dist/auth/index.js.map +1 -1
  37. package/dist/auth/magicLink/MagicLinkService.d.ts.map +1 -1
  38. package/dist/auth/magicLink/MagicLinkService.js +6 -3
  39. package/dist/auth/magicLink/MagicLinkService.js.map +1 -1
  40. package/dist/auth/newUsers.d.ts +10 -0
  41. package/dist/auth/newUsers.d.ts.map +1 -1
  42. package/dist/auth/newUsers.js +80 -11
  43. package/dist/auth/newUsers.js.map +1 -1
  44. package/dist/config.d.ts +4567 -71
  45. package/dist/config.d.ts.map +1 -1
  46. package/dist/config.js +246 -3
  47. package/dist/config.js.map +1 -1
  48. package/dist/context.d.ts +8 -0
  49. package/dist/context.d.ts.map +1 -1
  50. package/dist/context.js +25 -34
  51. package/dist/context.js.map +1 -1
  52. package/dist/generated/graphql-schemas/__mj.d.ts +1073 -10
  53. package/dist/generated/graphql-schemas/__mj.d.ts.map +1 -1
  54. package/dist/generated/graphql-schemas/__mj.js +9188 -3649
  55. package/dist/generated/graphql-schemas/__mj.js.map +1 -1
  56. package/dist/generic/OrphanedConversationDetailReconciler.js +3 -3
  57. package/dist/generic/OrphanedConversationDetailReconciler.js.map +1 -1
  58. package/dist/generic/ResolverBase.d.ts +62 -6
  59. package/dist/generic/ResolverBase.d.ts.map +1 -1
  60. package/dist/generic/ResolverBase.js +179 -35
  61. package/dist/generic/ResolverBase.js.map +1 -1
  62. package/dist/generic/RunViewResolver.d.ts +4 -0
  63. package/dist/generic/RunViewResolver.d.ts.map +1 -1
  64. package/dist/generic/RunViewResolver.js +37 -1
  65. package/dist/generic/RunViewResolver.js.map +1 -1
  66. package/dist/index.d.ts +7 -0
  67. package/dist/index.d.ts.map +1 -1
  68. package/dist/index.js +214 -159
  69. package/dist/index.js.map +1 -1
  70. package/dist/isolatedProvider.d.ts +20 -0
  71. package/dist/isolatedProvider.d.ts.map +1 -0
  72. package/dist/isolatedProvider.js +22 -0
  73. package/dist/isolatedProvider.js.map +1 -0
  74. package/dist/postgresqlCompat.d.ts +8 -0
  75. package/dist/postgresqlCompat.d.ts.map +1 -0
  76. package/dist/postgresqlCompat.js +19 -0
  77. package/dist/postgresqlCompat.js.map +1 -0
  78. package/dist/postgresqlPoolSettings.d.ts +108 -0
  79. package/dist/postgresqlPoolSettings.d.ts.map +1 -0
  80. package/dist/postgresqlPoolSettings.js +134 -0
  81. package/dist/postgresqlPoolSettings.js.map +1 -0
  82. package/dist/realtimeProxy/RealtimeProxyServer.d.ts +44 -4
  83. package/dist/realtimeProxy/RealtimeProxyServer.d.ts.map +1 -1
  84. package/dist/realtimeProxy/RealtimeProxyServer.js +121 -16
  85. package/dist/realtimeProxy/RealtimeProxyServer.js.map +1 -1
  86. package/dist/realtimeProxy/RealtimeRelayTunnel.d.ts +171 -0
  87. package/dist/realtimeProxy/RealtimeRelayTunnel.d.ts.map +1 -0
  88. package/dist/realtimeProxy/RealtimeRelayTunnel.js +532 -0
  89. package/dist/realtimeProxy/RealtimeRelayTunnel.js.map +1 -0
  90. package/dist/realtimeSessions/RealtimeSessionEventService.d.ts +148 -0
  91. package/dist/realtimeSessions/RealtimeSessionEventService.d.ts.map +1 -0
  92. package/dist/realtimeSessions/RealtimeSessionEventService.js +191 -0
  93. package/dist/realtimeSessions/RealtimeSessionEventService.js.map +1 -0
  94. package/dist/realtimeSessions/RealtimeSessionVerificationService.d.ts +66 -0
  95. package/dist/realtimeSessions/RealtimeSessionVerificationService.d.ts.map +1 -0
  96. package/dist/realtimeSessions/RealtimeSessionVerificationService.js +138 -0
  97. package/dist/realtimeSessions/RealtimeSessionVerificationService.js.map +1 -0
  98. package/dist/realtimeSessions/RealtimeVerifyRouter.d.ts +38 -0
  99. package/dist/realtimeSessions/RealtimeVerifyRouter.d.ts.map +1 -0
  100. package/dist/realtimeSessions/RealtimeVerifyRouter.js +98 -0
  101. package/dist/realtimeSessions/RealtimeVerifyRouter.js.map +1 -0
  102. package/dist/realtimeSessions/SessionVerificationPortsBase.d.ts +61 -0
  103. package/dist/realtimeSessions/SessionVerificationPortsBase.d.ts.map +1 -0
  104. package/dist/realtimeSessions/SessionVerificationPortsBase.js +149 -0
  105. package/dist/realtimeSessions/SessionVerificationPortsBase.js.map +1 -0
  106. package/dist/realtimeSessions/SlidingWindowRateLimiter.d.ts +57 -0
  107. package/dist/realtimeSessions/SlidingWindowRateLimiter.d.ts.map +1 -0
  108. package/dist/realtimeSessions/SlidingWindowRateLimiter.js +69 -0
  109. package/dist/realtimeSessions/SlidingWindowRateLimiter.js.map +1 -0
  110. package/dist/realtimeSessions/index.d.ts +17 -0
  111. package/dist/realtimeSessions/index.d.ts.map +1 -0
  112. package/dist/realtimeSessions/index.js +17 -0
  113. package/dist/realtimeSessions/index.js.map +1 -0
  114. package/dist/realtimeSessions/sessionAccess.d.ts +86 -0
  115. package/dist/realtimeSessions/sessionAccess.d.ts.map +1 -0
  116. package/dist/realtimeSessions/sessionAccess.js +90 -0
  117. package/dist/realtimeSessions/sessionAccess.js.map +1 -0
  118. package/dist/realtimeSessions/sessionConfigStamps.d.ts +70 -0
  119. package/dist/realtimeSessions/sessionConfigStamps.d.ts.map +1 -0
  120. package/dist/realtimeSessions/sessionConfigStamps.js +93 -0
  121. package/dist/realtimeSessions/sessionConfigStamps.js.map +1 -0
  122. package/dist/realtimeSessions/subscriptionAuthorization.d.ts +65 -0
  123. package/dist/realtimeSessions/subscriptionAuthorization.d.ts.map +1 -0
  124. package/dist/realtimeSessions/subscriptionAuthorization.js +71 -0
  125. package/dist/realtimeSessions/subscriptionAuthorization.js.map +1 -0
  126. package/dist/realtimeSessions/verificationCore.d.ts +243 -0
  127. package/dist/realtimeSessions/verificationCore.d.ts.map +1 -0
  128. package/dist/realtimeSessions/verificationCore.js +356 -0
  129. package/dist/realtimeSessions/verificationCore.js.map +1 -0
  130. package/dist/realtimeSessions/verificationPages.d.ts +66 -0
  131. package/dist/realtimeSessions/verificationPages.d.ts.map +1 -0
  132. package/dist/realtimeSessions/verificationPages.js +110 -0
  133. package/dist/realtimeSessions/verificationPages.js.map +1 -0
  134. package/dist/realtimeSessions/verificationPolicy.d.ts +147 -0
  135. package/dist/realtimeSessions/verificationPolicy.d.ts.map +1 -0
  136. package/dist/realtimeSessions/verificationPolicy.js +249 -0
  137. package/dist/realtimeSessions/verificationPolicy.js.map +1 -0
  138. package/dist/realtimeSessions/verificationWorkflow.d.ts +263 -0
  139. package/dist/realtimeSessions/verificationWorkflow.d.ts.map +1 -0
  140. package/dist/realtimeSessions/verificationWorkflow.js +435 -0
  141. package/dist/realtimeSessions/verificationWorkflow.js.map +1 -0
  142. package/dist/realtimeWidget/widgetGuestElevation.d.ts +20 -2
  143. package/dist/realtimeWidget/widgetGuestElevation.d.ts.map +1 -1
  144. package/dist/realtimeWidget/widgetGuestElevation.js +31 -2
  145. package/dist/realtimeWidget/widgetGuestElevation.js.map +1 -1
  146. package/dist/resolvers/ActionResolver.d.ts +31 -5
  147. package/dist/resolvers/ActionResolver.d.ts.map +1 -1
  148. package/dist/resolvers/ActionResolver.js +75 -14
  149. package/dist/resolvers/ActionResolver.js.map +1 -1
  150. package/dist/resolvers/AdhocQueryResolver.d.ts +35 -17
  151. package/dist/resolvers/AdhocQueryResolver.d.ts.map +1 -1
  152. package/dist/resolvers/AdhocQueryResolver.js +92 -166
  153. package/dist/resolvers/AdhocQueryResolver.js.map +1 -1
  154. package/dist/resolvers/CacheStatsResolver.d.ts +27 -0
  155. package/dist/resolvers/CacheStatsResolver.d.ts.map +1 -1
  156. package/dist/resolvers/CacheStatsResolver.js +113 -2
  157. package/dist/resolvers/CacheStatsResolver.js.map +1 -1
  158. package/dist/resolvers/ClientToolRequestResolver.d.ts +4 -2
  159. package/dist/resolvers/ClientToolRequestResolver.d.ts.map +1 -1
  160. package/dist/resolvers/ClientToolRequestResolver.js +28 -10
  161. package/dist/resolvers/ClientToolRequestResolver.js.map +1 -1
  162. package/dist/resolvers/EntityRecordNameResolver.d.ts +7 -23
  163. package/dist/resolvers/EntityRecordNameResolver.d.ts.map +1 -1
  164. package/dist/resolvers/EntityRecordNameResolver.js +9 -47
  165. package/dist/resolvers/EntityRecordNameResolver.js.map +1 -1
  166. package/dist/resolvers/FetchEntityVectorsResolver.d.ts +12 -1
  167. package/dist/resolvers/FetchEntityVectorsResolver.d.ts.map +1 -1
  168. package/dist/resolvers/FetchEntityVectorsResolver.js +83 -2
  169. package/dist/resolvers/FetchEntityVectorsResolver.js.map +1 -1
  170. package/dist/resolvers/GetDataResolver.d.ts.map +1 -1
  171. package/dist/resolvers/GetDataResolver.js +9 -0
  172. package/dist/resolvers/GetDataResolver.js.map +1 -1
  173. package/dist/resolvers/HumanHandoffResolver.d.ts +107 -0
  174. package/dist/resolvers/HumanHandoffResolver.d.ts.map +1 -0
  175. package/dist/resolvers/HumanHandoffResolver.js +330 -0
  176. package/dist/resolvers/HumanHandoffResolver.js.map +1 -0
  177. package/dist/resolvers/MCPResolver.d.ts.map +1 -1
  178. package/dist/resolvers/MCPResolver.js +9 -4
  179. package/dist/resolvers/MCPResolver.js.map +1 -1
  180. package/dist/resolvers/MeetingResolver.d.ts +69 -0
  181. package/dist/resolvers/MeetingResolver.d.ts.map +1 -0
  182. package/dist/resolvers/MeetingResolver.js +381 -0
  183. package/dist/resolvers/MeetingResolver.js.map +1 -0
  184. package/dist/resolvers/RealtimeBridgeResolver.d.ts +88 -3
  185. package/dist/resolvers/RealtimeBridgeResolver.d.ts.map +1 -1
  186. package/dist/resolvers/RealtimeBridgeResolver.js +352 -12
  187. package/dist/resolvers/RealtimeBridgeResolver.js.map +1 -1
  188. package/dist/resolvers/RealtimeClientSessionResolver.d.ts +156 -108
  189. package/dist/resolvers/RealtimeClientSessionResolver.d.ts.map +1 -1
  190. package/dist/resolvers/RealtimeClientSessionResolver.js +395 -293
  191. package/dist/resolvers/RealtimeClientSessionResolver.js.map +1 -1
  192. package/dist/resolvers/RealtimeSessionEventsResolver.d.ts +61 -0
  193. package/dist/resolvers/RealtimeSessionEventsResolver.d.ts.map +1 -0
  194. package/dist/resolvers/RealtimeSessionEventsResolver.js +130 -0
  195. package/dist/resolvers/RealtimeSessionEventsResolver.js.map +1 -0
  196. package/dist/resolvers/RealtimeSessionVerificationResolver.d.ts +85 -0
  197. package/dist/resolvers/RealtimeSessionVerificationResolver.d.ts.map +1 -0
  198. package/dist/resolvers/RealtimeSessionVerificationResolver.js +188 -0
  199. package/dist/resolvers/RealtimeSessionVerificationResolver.js.map +1 -0
  200. package/dist/resolvers/RemoteBrowserActionResolver.d.ts +2 -0
  201. package/dist/resolvers/RemoteBrowserActionResolver.d.ts.map +1 -1
  202. package/dist/resolvers/RemoteBrowserActionResolver.js +5 -1
  203. package/dist/resolvers/RemoteBrowserActionResolver.js.map +1 -1
  204. package/dist/resolvers/RunAIAgentResolver.d.ts +10 -0
  205. package/dist/resolvers/RunAIAgentResolver.d.ts.map +1 -1
  206. package/dist/resolvers/RunAIAgentResolver.js +68 -11
  207. package/dist/resolvers/RunAIAgentResolver.js.map +1 -1
  208. package/dist/resolvers/RunTemplateResolver.d.ts.map +1 -1
  209. package/dist/resolvers/RunTemplateResolver.js +12 -11
  210. package/dist/resolvers/RunTemplateResolver.js.map +1 -1
  211. package/dist/resolvers/SyncDataResolver.d.ts.map +1 -1
  212. package/dist/resolvers/SyncDataResolver.js +6 -2
  213. package/dist/resolvers/SyncDataResolver.js.map +1 -1
  214. package/dist/resolvers/SyncRolesUsersResolver.d.ts +2 -0
  215. package/dist/resolvers/SyncRolesUsersResolver.d.ts.map +1 -1
  216. package/dist/resolvers/SyncRolesUsersResolver.js +23 -6
  217. package/dist/resolvers/SyncRolesUsersResolver.js.map +1 -1
  218. package/dist/resolvers/UserAvatarResolver.d.ts +16 -0
  219. package/dist/resolvers/UserAvatarResolver.d.ts.map +1 -0
  220. package/dist/resolvers/UserAvatarResolver.js +124 -0
  221. package/dist/resolvers/UserAvatarResolver.js.map +1 -0
  222. package/dist/resolvers/UserResolver.d.ts.map +1 -1
  223. package/dist/resolvers/UserResolver.js +2 -17
  224. package/dist/resolvers/UserResolver.js.map +1 -1
  225. package/dist/resolvers/adhocTimeout.d.ts +7 -0
  226. package/dist/resolvers/adhocTimeout.d.ts.map +1 -0
  227. package/dist/resolvers/adhocTimeout.js +12 -0
  228. package/dist/resolvers/adhocTimeout.js.map +1 -0
  229. package/dist/resolvers/agentVisionConsentAudit.d.ts +37 -0
  230. package/dist/resolvers/agentVisionConsentAudit.d.ts.map +1 -0
  231. package/dist/resolvers/agentVisionConsentAudit.js +63 -0
  232. package/dist/resolvers/agentVisionConsentAudit.js.map +1 -0
  233. package/dist/resolvers/avatarInputValidation.d.ts +40 -0
  234. package/dist/resolvers/avatarInputValidation.d.ts.map +1 -0
  235. package/dist/resolvers/avatarInputValidation.js +97 -0
  236. package/dist/resolvers/avatarInputValidation.js.map +1 -0
  237. package/dist/resolvers/currentUserRoles.d.ts +29 -0
  238. package/dist/resolvers/currentUserRoles.d.ts.map +1 -1
  239. package/dist/resolvers/currentUserRoles.js +30 -0
  240. package/dist/resolvers/currentUserRoles.js.map +1 -1
  241. package/dist/resolvers/meetings/index.d.ts +5 -0
  242. package/dist/resolvers/meetings/index.d.ts.map +1 -0
  243. package/dist/resolvers/meetings/index.js +5 -0
  244. package/dist/resolvers/meetings/index.js.map +1 -0
  245. package/dist/resolvers/meetings/meetingHelpers.d.ts +17 -0
  246. package/dist/resolvers/meetings/meetingHelpers.d.ts.map +1 -0
  247. package/dist/resolvers/meetings/meetingHelpers.js +212 -0
  248. package/dist/resolvers/meetings/meetingHelpers.js.map +1 -0
  249. package/dist/resolvers/meetings/meetingMutations.d.ts +18 -0
  250. package/dist/resolvers/meetings/meetingMutations.d.ts.map +1 -0
  251. package/dist/resolvers/meetings/meetingMutations.js +439 -0
  252. package/dist/resolvers/meetings/meetingMutations.js.map +1 -0
  253. package/dist/resolvers/meetings/meetingQueries.d.ts +7 -0
  254. package/dist/resolvers/meetings/meetingQueries.d.ts.map +1 -0
  255. package/dist/resolvers/meetings/meetingQueries.js +113 -0
  256. package/dist/resolvers/meetings/meetingQueries.js.map +1 -0
  257. package/dist/resolvers/meetings/meetingTypes.d.ts +89 -0
  258. package/dist/resolvers/meetings/meetingTypes.d.ts.map +1 -0
  259. package/dist/resolvers/meetings/meetingTypes.js +345 -0
  260. package/dist/resolvers/meetings/meetingTypes.js.map +1 -0
  261. package/dist/rest/ViewOperationsHandler.d.ts.map +1 -1
  262. package/dist/rest/ViewOperationsHandler.js +8 -5
  263. package/dist/rest/ViewOperationsHandler.js.map +1 -1
  264. package/dist/services/TaskGraphActionRunner.d.ts +8 -0
  265. package/dist/services/TaskGraphActionRunner.d.ts.map +1 -1
  266. package/dist/services/TaskGraphActionRunner.js +27 -1
  267. package/dist/services/TaskGraphActionRunner.js.map +1 -1
  268. package/dist/services/TaskGraphContinuationDeliverer.d.ts +4 -3
  269. package/dist/services/TaskGraphContinuationDeliverer.d.ts.map +1 -1
  270. package/dist/services/TaskGraphContinuationDeliverer.js +13 -7
  271. package/dist/services/TaskGraphContinuationDeliverer.js.map +1 -1
  272. package/dist/services/WorkQueueHostService.d.ts +36 -0
  273. package/dist/services/WorkQueueHostService.d.ts.map +1 -0
  274. package/dist/services/WorkQueueHostService.js +97 -0
  275. package/dist/services/WorkQueueHostService.js.map +1 -0
  276. package/dist/services/workQueueConfig.d.ts +103 -0
  277. package/dist/services/workQueueConfig.d.ts.map +1 -0
  278. package/dist/services/workQueueConfig.js +48 -0
  279. package/dist/services/workQueueConfig.js.map +1 -0
  280. package/dist/sharedCache.d.ts +105 -0
  281. package/dist/sharedCache.d.ts.map +1 -0
  282. package/dist/sharedCache.js +276 -0
  283. package/dist/sharedCache.js.map +1 -0
  284. package/dist/types.d.ts +11 -0
  285. package/dist/types.d.ts.map +1 -1
  286. package/dist/types.js.map +1 -1
  287. package/package.json +97 -94
  288. package/src/__tests__/ActionResolver.authorization.test.ts +353 -0
  289. package/src/__tests__/AdhocQueryResolver.bugs.test.ts +14 -35
  290. package/src/__tests__/AdhocQueryResolver.pagination.test.ts +6 -2
  291. package/src/__tests__/AdhocQueryResolver.scopeGuard.test.ts +3 -3
  292. package/src/__tests__/AdhocQueryResolver.sqlAuthorizer.test.ts +104 -0
  293. package/src/__tests__/BridgeHostInstance.test.ts +232 -0
  294. package/src/__tests__/ClientToolRequestResolver.test.ts +116 -0
  295. package/src/__tests__/EntityRecordNameResolver.fieldSecurity.test.ts +27 -72
  296. package/src/__tests__/FetchEntityVectorsResolver.test.ts +285 -0
  297. package/src/__tests__/HostInstance.test.ts +84 -0
  298. package/src/__tests__/HumanHandoffResolver.test.ts +250 -0
  299. package/src/__tests__/MeetingResolver.test.ts +448 -0
  300. package/src/__tests__/RealtimeBridgeResolver.test.ts +651 -4
  301. package/src/__tests__/RealtimeClientSessionResolver.configTamper.test.ts +383 -0
  302. package/src/__tests__/RealtimeClientSessionResolver.test.ts +682 -58
  303. package/src/__tests__/RealtimeProxyServer.test.ts +16 -1
  304. package/src/__tests__/RealtimeRelay.test.ts +876 -0
  305. package/src/__tests__/RemoteBrowserActionResolver.goalRunLink.test.ts +129 -0
  306. package/src/__tests__/ResolverBase.adhocReadScope.test.ts +96 -0
  307. package/src/__tests__/ResolverBase.aggregateScreen.test.ts +174 -0
  308. package/src/__tests__/ResolverBase.clientOldValues.test.ts +6 -3
  309. package/src/__tests__/ResolverBase.filterEscaping.test.ts +21 -2
  310. package/src/__tests__/ResolverBase.includeBinaryFields.test.ts +291 -0
  311. package/src/__tests__/ReturningVisitorRecap.test.ts +115 -0
  312. package/src/__tests__/RunAIAgentResolver.branch.test.ts +169 -0
  313. package/src/__tests__/RunAIAgentResolver.historyFrom.test.ts +4 -4
  314. package/src/__tests__/RunAIAgentResolver.stoppedPredecessor.test.ts +166 -0
  315. package/src/__tests__/RunTemplateResolver.test.ts +132 -0
  316. package/src/__tests__/RunViewResolver.cacheCheckForwarding.test.ts +63 -0
  317. package/src/__tests__/SessionJanitor.test.ts +845 -18
  318. package/src/__tests__/SessionManager.test.ts +213 -17
  319. package/src/__tests__/SessionRunIDVerifier.test.ts +251 -0
  320. package/src/__tests__/SyncRolesUsersResolver.userRoles.test.ts +97 -0
  321. package/src/__tests__/TaskGraphActionRunner.durablePayload.test.ts +41 -0
  322. package/src/__tests__/TaskGraphContinuationDeliverer.test.ts +50 -3
  323. package/src/__tests__/UserAvatarResolver.test.ts +255 -0
  324. package/src/__tests__/UserResolver.currentUser.test.ts +16 -1
  325. package/src/__tests__/WorkQueueHostService.test.ts +133 -0
  326. package/src/__tests__/actionAuthorization.test.ts +130 -0
  327. package/src/__tests__/adhocTimeoutClamp.test.ts +26 -0
  328. package/src/__tests__/agentVisionConsentAudit.test.ts +118 -0
  329. package/src/__tests__/avatarInputValidation.test.ts +160 -0
  330. package/src/__tests__/isolatedProviderTransactions.test.ts +169 -0
  331. package/src/__tests__/magicLinkService.consume.test.ts +6 -0
  332. package/src/__tests__/magicLinkService.provisionLog.test.ts +5 -0
  333. package/src/__tests__/newUsers.template.test.ts +151 -0
  334. package/src/__tests__/newUsers.test.ts +74 -5
  335. package/src/__tests__/orphanedConversationDetailReconciler.test.ts +17 -2
  336. package/src/__tests__/postgresqlPoolSettings.test.ts +131 -0
  337. package/src/__tests__/realtimeSessions/RealtimeSessionEventService.test.ts +201 -0
  338. package/src/__tests__/realtimeSessions/RealtimeSessionEventsResolver.test.ts +215 -0
  339. package/src/__tests__/realtimeSessions/RealtimeSessionVerificationResolver.test.ts +102 -0
  340. package/src/__tests__/realtimeSessions/RealtimeSessionVerificationService.test.ts +349 -0
  341. package/src/__tests__/realtimeSessions/RealtimeVerifyRouter.test.ts +131 -0
  342. package/src/__tests__/realtimeSessions/SlidingWindowRateLimiter.test.ts +56 -0
  343. package/src/__tests__/realtimeSessions/helpers.ts +4 -0
  344. package/src/__tests__/realtimeSessions/sessionAccess.test.ts +129 -0
  345. package/src/__tests__/realtimeSessions/sessionConfigStamps.test.ts +124 -0
  346. package/src/__tests__/realtimeSessions/verificationCore.test.ts +355 -0
  347. package/src/__tests__/realtimeSessions/verificationPages.test.ts +84 -0
  348. package/src/__tests__/realtimeSessions/verificationPolicy.test.ts +226 -0
  349. package/src/__tests__/realtimeSessions/verificationWorkflow.test.ts +633 -0
  350. package/src/__tests__/resolverBase.fls.test.ts +87 -4
  351. package/src/__tests__/serverExtensionReservedRoots.test.ts +2 -0
  352. package/src/__tests__/sharedCache.test.ts +310 -0
  353. package/src/__tests__/translateBracketsToPG.test.ts +20 -0
  354. package/src/__tests__/widgetGuestElevation.test.ts +44 -0
  355. package/src/agentSessions/BridgeHostInstance.ts +32 -0
  356. package/src/agentSessions/HostInstance.ts +124 -28
  357. package/src/agentSessions/ReturningVisitorRecap.ts +7 -3
  358. package/src/agentSessions/SessionJanitor.ts +543 -57
  359. package/src/agentSessions/SessionManager.ts +125 -25
  360. package/src/agentSessions/SessionRunIDVerifier.ts +171 -0
  361. package/src/agentSessions/index.ts +10 -3
  362. package/src/auth/actionAuthorization.ts +116 -0
  363. package/src/auth/index.ts +3 -8
  364. package/src/auth/magicLink/MagicLinkService.ts +6 -3
  365. package/src/auth/newUsers.ts +99 -11
  366. package/src/config.ts +255 -3
  367. package/src/context.ts +26 -34
  368. package/src/generated/graphql-schemas/__mj.ts +22701 -18838
  369. package/src/generic/OrphanedConversationDetailReconciler.ts +3 -3
  370. package/src/generic/ResolverBase.ts +210 -36
  371. package/src/generic/RunViewResolver.ts +37 -2
  372. package/src/index.ts +236 -170
  373. package/src/isolatedProvider.ts +22 -0
  374. package/src/postgresqlCompat.ts +21 -0
  375. package/src/postgresqlPoolSettings.ts +213 -0
  376. package/src/realtimeProxy/RealtimeProxyServer.ts +148 -16
  377. package/src/realtimeProxy/RealtimeRelayTunnel.ts +645 -0
  378. package/src/realtimeSessions/README.md +179 -0
  379. package/src/realtimeSessions/RealtimeSessionEventService.ts +274 -0
  380. package/src/realtimeSessions/RealtimeSessionVerificationService.ts +167 -0
  381. package/src/realtimeSessions/RealtimeVerifyRouter.ts +108 -0
  382. package/src/realtimeSessions/SessionVerificationPortsBase.ts +189 -0
  383. package/src/realtimeSessions/SlidingWindowRateLimiter.ts +92 -0
  384. package/src/realtimeSessions/index.ts +16 -0
  385. package/src/realtimeSessions/sessionAccess.ts +141 -0
  386. package/src/realtimeSessions/sessionConfigStamps.ts +123 -0
  387. package/src/realtimeSessions/subscriptionAuthorization.ts +116 -0
  388. package/src/realtimeSessions/verificationCore.ts +502 -0
  389. package/src/realtimeSessions/verificationPages.ts +149 -0
  390. package/src/realtimeSessions/verificationPolicy.ts +321 -0
  391. package/src/realtimeSessions/verificationWorkflow.ts +702 -0
  392. package/src/realtimeWidget/widgetGuestElevation.ts +34 -2
  393. package/src/resolvers/ActionResolver.ts +84 -21
  394. package/src/resolvers/AdhocQueryResolver.ts +105 -187
  395. package/src/resolvers/CacheStatsResolver.ts +89 -2
  396. package/src/resolvers/ClientToolRequestResolver.ts +25 -7
  397. package/src/resolvers/EntityRecordNameResolver.ts +9 -51
  398. package/src/resolvers/FetchEntityVectorsResolver.ts +97 -2
  399. package/src/resolvers/GetDataResolver.ts +10 -0
  400. package/src/resolvers/HumanHandoffResolver.ts +312 -0
  401. package/src/resolvers/MCPResolver.ts +8 -5
  402. package/src/resolvers/MeetingResolver.ts +438 -0
  403. package/src/resolvers/RealtimeBridgeResolver.ts +385 -19
  404. package/src/resolvers/RealtimeClientSessionResolver.ts +503 -344
  405. package/src/resolvers/RealtimeSessionEventsResolver.ts +133 -0
  406. package/src/resolvers/RealtimeSessionVerificationResolver.ts +174 -0
  407. package/src/resolvers/RemoteBrowserActionResolver.ts +11 -1
  408. package/src/resolvers/RunAIAgentResolver.ts +78 -11
  409. package/src/resolvers/RunTemplateResolver.ts +13 -12
  410. package/src/resolvers/SyncDataResolver.ts +6 -2
  411. package/src/resolvers/SyncRolesUsersResolver.ts +24 -6
  412. package/src/resolvers/UserAvatarResolver.ts +111 -0
  413. package/src/resolvers/UserResolver.ts +2 -16
  414. package/src/resolvers/adhocTimeout.ts +12 -0
  415. package/src/resolvers/agentVisionConsentAudit.ts +82 -0
  416. package/src/resolvers/avatarInputValidation.ts +123 -0
  417. package/src/resolvers/currentUserRoles.ts +32 -1
  418. package/src/resolvers/meetings/index.ts +4 -0
  419. package/src/resolvers/meetings/meetingHelpers.ts +307 -0
  420. package/src/resolvers/meetings/meetingMutations.ts +556 -0
  421. package/src/resolvers/meetings/meetingQueries.ts +172 -0
  422. package/src/resolvers/meetings/meetingTypes.ts +238 -0
  423. package/src/rest/ViewOperationsHandler.ts +8 -5
  424. package/src/services/TaskGraphActionRunner.ts +29 -1
  425. package/src/services/TaskGraphContinuationDeliverer.ts +13 -7
  426. package/src/services/WorkQueueHostService.ts +129 -0
  427. package/src/services/workQueueConfig.ts +52 -0
  428. package/src/sharedCache.ts +302 -0
  429. package/src/types.ts +12 -0
  430. package/dist/resolvers/adhoc-query-helpers.d.ts +0 -33
  431. package/dist/resolvers/adhoc-query-helpers.d.ts.map +0 -1
  432. package/dist/resolvers/adhoc-query-helpers.js +0 -50
  433. package/dist/resolvers/adhoc-query-helpers.js.map +0 -1
  434. package/src/__tests__/adhoc-query-helpers.test.ts +0 -50
  435. package/src/resolvers/adhoc-query-helpers.ts +0 -67
@@ -0,0 +1,556 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import {
3
+ IMetadataProvider,
4
+ LogError,
5
+ RunView,
6
+ UserInfo,
7
+ } from '@memberjunction/core';
8
+ import { EscapeSQLString, UUIDsEqual } from '@memberjunction/global';
9
+ import type {
10
+ MJMeetingEntity,
11
+ MJMeetingParticipantEntity,
12
+ } from '@memberjunction/core-entities';
13
+ import {
14
+ LiveKitTokenService,
15
+ LiveKitAgentRoomCoordinator,
16
+ LiveKitEgressService,
17
+ LiveKitUserIdentity,
18
+ } from '@memberjunction/livekit-room-server';
19
+ import { SessionManager } from '../../agentSessions/SessionManager.js';
20
+ import { CorrelateRecordingStart } from '../meetingRecordingRegistration.js';
21
+ import {
22
+ MeetingResult,
23
+ StartMeetingResult,
24
+ CreateMeetingInput,
25
+ UpdateMeetingInput,
26
+ RSVPMeetingInput,
27
+ MeetingParticipantType,
28
+ } from './meetingTypes.js';
29
+ import * as defaultHelpers from './meetingHelpers.js';
30
+
31
+ export type MeetingHelpers = typeof defaultHelpers;
32
+
33
+ function resolveHelpers(overrides?: Partial<MeetingHelpers>): MeetingHelpers {
34
+ return { ...defaultHelpers, ...overrides };
35
+ }
36
+
37
+ export async function ExecuteCreateMeeting(
38
+ provider: IMetadataProvider,
39
+ user: UserInfo,
40
+ input: CreateMeetingInput,
41
+ helpers?: Partial<MeetingHelpers>,
42
+ ): Promise<MeetingResult> {
43
+ const h = resolveHelpers(helpers);
44
+ try {
45
+ const trimmedTitle = input.Title?.trim();
46
+ if (!trimmedTitle) {
47
+ return { Success: false, ErrorMessage: 'Meeting title is required.' };
48
+ }
49
+
50
+ if (input.ScheduledStartAt && input.ScheduledEndAt && input.ScheduledEndAt <= input.ScheduledStartAt) {
51
+ return { Success: false, ErrorMessage: 'Scheduled end time must be after scheduled start time.' };
52
+ }
53
+
54
+ const allowDialIn = input.AllowPhoneDialIn ?? false;
55
+ let dialInPhoneNumberID = input.DialInPhoneNumberID?.trim();
56
+ let dialInCode: string | undefined;
57
+
58
+ if (allowDialIn) {
59
+ if (!dialInPhoneNumberID) {
60
+ // Select default active phone number
61
+ const defaultNumber = await h.ResolveDefaultPhoneNumber(user, provider);
62
+ if (!defaultNumber) {
63
+ return {
64
+ Success: false,
65
+ ErrorMessage: 'Cannot allow phone dial-in: no active phone numbers are configured in the system.',
66
+ };
67
+ }
68
+ dialInPhoneNumberID = defaultNumber.ID;
69
+ }
70
+
71
+ // Generate a random unique dial-in code (6 digits)
72
+ dialInCode = await h.GenerateUniqueDialInCode(dialInPhoneNumberID, user, provider);
73
+ if (!dialInCode) {
74
+ return { Success: false, ErrorMessage: 'Failed to generate a unique dial-in code for this phone number.' };
75
+ }
76
+ }
77
+
78
+ // Room name is always unguessable and generated: mj-mtg-<uuid>
79
+ const roomName = `mj-mtg-${randomUUID()}`;
80
+
81
+ const meeting = await provider.GetEntityObject<MJMeetingEntity>('MJ: Meetings', user);
82
+ meeting.Title = trimmedTitle;
83
+ meeting.Description = input.Description?.trim() || null;
84
+ meeting.HostUserID = user.ID;
85
+ meeting.RoomName = roomName;
86
+ meeting.Status = 'Scheduled';
87
+ meeting.ScheduledStartAt = input.ScheduledStartAt ?? null;
88
+ meeting.ScheduledEndAt = input.ScheduledEndAt ?? null;
89
+ meeting.AllowPhoneDialIn = allowDialIn;
90
+ meeting.DialInPhoneNumberID = allowDialIn ? dialInPhoneNumberID! : null;
91
+ meeting.DialInCode = allowDialIn ? dialInCode! : null;
92
+ meeting.RecordingPolicy = h.NormalizeRecordingPolicy(input.RecordingPolicy);
93
+
94
+ if (!(await meeting.Save())) {
95
+ const err = meeting.LatestResult?.CompleteMessage ?? 'Failed to save meeting.';
96
+ LogError(`[MeetingResolver] CreateMeeting save failed: ${err}`);
97
+ return { Success: false, ErrorMessage: err };
98
+ }
99
+
100
+ // Add Host as accepted participant
101
+ const hostParticipant = await provider.GetEntityObject<MJMeetingParticipantEntity>('MJ: Meeting Participants', user);
102
+ hostParticipant.MeetingID = meeting.ID;
103
+ hostParticipant.UserID = user.ID;
104
+ hostParticipant.Role = 'Host';
105
+ hostParticipant.InviteStatus = 'Accepted';
106
+ await hostParticipant.Save();
107
+
108
+ // Add other participants
109
+ const participants: MeetingParticipantType[] = [h.MapParticipantToType(hostParticipant, user.Name, user.Email)];
110
+
111
+ if (input.Participants && input.Participants.length > 0) {
112
+ for (const pInput of input.Participants) {
113
+ // Skip if duplicate of host
114
+ if (pInput.UserID && UUIDsEqual(pInput.UserID, user.ID)) {
115
+ continue;
116
+ }
117
+
118
+ const participant = await provider.GetEntityObject<MJMeetingParticipantEntity>('MJ: Meeting Participants', user);
119
+ participant.MeetingID = meeting.ID;
120
+
121
+ if (pInput.AgentID && pInput.AgentID.trim()) {
122
+ participant.AgentID = pInput.AgentID.trim();
123
+ participant.Role = 'Agent';
124
+ participant.InviteStatus = 'Accepted';
125
+ } else if (pInput.UserID && pInput.UserID.trim()) {
126
+ participant.UserID = pInput.UserID.trim();
127
+ participant.Role = h.NormalizeParticipantRole(pInput.Role, 'Attendee');
128
+ participant.InviteStatus = 'Invited';
129
+ } else {
130
+ // External guest
131
+ participant.ExternalName = pInput.ExternalName?.trim() || null;
132
+ participant.ExternalEmail = pInput.ExternalEmail?.trim() || null;
133
+ participant.ExternalPhone = pInput.ExternalPhone?.trim() || null;
134
+ participant.Role = h.NormalizeParticipantRole(pInput.Role, 'Attendee');
135
+ participant.InviteStatus = 'Invited';
136
+ }
137
+
138
+ if (await participant.Save()) {
139
+ participants.push(h.MapParticipantToType(participant));
140
+
141
+ // Send notification for internal users
142
+ if (participant.UserID) {
143
+ void h.SendMeetingInviteNotification(meeting, participant.UserID, user, provider);
144
+ }
145
+ }
146
+ }
147
+ }
148
+
149
+ return {
150
+ Success: true,
151
+ Meeting: h.MapMeetingToType(meeting, participants),
152
+ };
153
+ } catch (error) {
154
+ const msg = error instanceof Error ? error.message : String(error);
155
+ LogError(`[MeetingResolver] CreateMeeting exception: ${msg}`);
156
+ return { Success: false, ErrorMessage: msg };
157
+ }
158
+ }
159
+
160
+ export async function ExecuteUpdateMeeting(
161
+ provider: IMetadataProvider,
162
+ user: UserInfo,
163
+ input: UpdateMeetingInput,
164
+ helpers?: Partial<MeetingHelpers>,
165
+ ): Promise<MeetingResult> {
166
+ const h = resolveHelpers(helpers);
167
+ try {
168
+ const meeting = await h.LoadMeetingEntity(input.MeetingID, user, provider);
169
+ if (!meeting) {
170
+ return { Success: false, ErrorMessage: 'Meeting not found.' };
171
+ }
172
+
173
+ // Check authorization (host or co-host)
174
+ const authorized = await h.IsUserHostOrCoHost(meeting, user, provider);
175
+ if (!authorized) {
176
+ return { Success: false, ErrorMessage: 'Unauthorized: only the host or co-host may modify this meeting.' };
177
+ }
178
+
179
+ if (meeting.Status === 'Ended' || meeting.Status === 'Cancelled') {
180
+ return { Success: false, ErrorMessage: `Cannot modify a meeting with status '${meeting.Status}'.` };
181
+ }
182
+
183
+ if (input.Title !== undefined) {
184
+ const trimmedTitle = input.Title.trim();
185
+ if (!trimmedTitle) {
186
+ return { Success: false, ErrorMessage: 'Meeting title cannot be empty.' };
187
+ }
188
+ meeting.Title = trimmedTitle;
189
+ }
190
+
191
+ if (input.Description !== undefined) {
192
+ meeting.Description = input.Description?.trim() || null;
193
+ }
194
+
195
+ if (input.ScheduledStartAt !== undefined) {
196
+ meeting.ScheduledStartAt = input.ScheduledStartAt;
197
+ }
198
+
199
+ if (input.ScheduledEndAt !== undefined) {
200
+ meeting.ScheduledEndAt = input.ScheduledEndAt;
201
+ }
202
+
203
+ if (meeting.ScheduledStartAt && meeting.ScheduledEndAt && meeting.ScheduledEndAt <= meeting.ScheduledStartAt) {
204
+ return { Success: false, ErrorMessage: 'Scheduled end time must be after scheduled start time.' };
205
+ }
206
+
207
+ if (input.RecordingPolicy !== undefined) {
208
+ meeting.RecordingPolicy = h.NormalizeRecordingPolicy(input.RecordingPolicy);
209
+ }
210
+
211
+ if (input.AllowPhoneDialIn !== undefined) {
212
+ meeting.AllowPhoneDialIn = input.AllowPhoneDialIn;
213
+ if (meeting.AllowPhoneDialIn && !meeting.DialInCode) {
214
+ let phoneID = input.DialInPhoneNumberID?.trim() || meeting.DialInPhoneNumberID;
215
+ if (!phoneID) {
216
+ const defPhone = await h.ResolveDefaultPhoneNumber(user, provider);
217
+ phoneID = defPhone?.ID;
218
+ }
219
+ if (phoneID) {
220
+ meeting.DialInPhoneNumberID = phoneID;
221
+ meeting.DialInCode = await h.GenerateUniqueDialInCode(phoneID, user, provider);
222
+ }
223
+ }
224
+ }
225
+
226
+ if (input.DialInPhoneNumberID !== undefined && input.DialInPhoneNumberID.trim()) {
227
+ meeting.DialInPhoneNumberID = input.DialInPhoneNumberID.trim();
228
+ }
229
+
230
+ if (!(await meeting.Save())) {
231
+ const err = meeting.LatestResult?.CompleteMessage ?? 'Failed to update meeting.';
232
+ return { Success: false, ErrorMessage: err };
233
+ }
234
+
235
+ // If participants specified in update, sync participants (upsert by UserID/AgentID/ExternalEmail)
236
+ if (input.Participants !== undefined) {
237
+ const existing = await h.LoadParticipants(meeting.ID, user, provider);
238
+
239
+ for (const pInput of input.Participants) {
240
+ const isSelf = pInput.UserID && UUIDsEqual(pInput.UserID, user.ID);
241
+ const match = existing.find(
242
+ (e) =>
243
+ (pInput.UserID && e.UserID && UUIDsEqual(e.UserID, pInput.UserID)) ||
244
+ (pInput.AgentID && e.AgentID && UUIDsEqual(e.AgentID, pInput.AgentID)) ||
245
+ (pInput.ExternalEmail && e.ExternalEmail && e.ExternalEmail.toLowerCase() === pInput.ExternalEmail.toLowerCase()),
246
+ );
247
+
248
+ if (match) {
249
+ if (!isSelf && pInput.Role) {
250
+ const rv = provider ? RunView.FromMetadataProvider(provider) : new RunView();
251
+ const escapedPID = EscapeSQLString(match.ID);
252
+ const partRes = await rv.RunView<MJMeetingParticipantEntity>(
253
+ {
254
+ EntityName: 'MJ: Meeting Participants',
255
+ ExtraFilter: `ID = '${escapedPID}'`,
256
+ ResultType: 'entity_object',
257
+ },
258
+ user,
259
+ );
260
+ if (partRes.Success && partRes.Results && partRes.Results.length > 0) {
261
+ const part = partRes.Results[0];
262
+ part.Role = h.NormalizeParticipantRole(pInput.Role, part.Role);
263
+ await part.Save();
264
+ }
265
+ }
266
+ } else {
267
+ // New participant
268
+ const newPart = await provider.GetEntityObject<MJMeetingParticipantEntity>('MJ: Meeting Participants', user);
269
+ newPart.MeetingID = meeting.ID;
270
+
271
+ if (pInput.AgentID && pInput.AgentID.trim()) {
272
+ newPart.AgentID = pInput.AgentID.trim();
273
+ newPart.Role = 'Agent';
274
+ newPart.InviteStatus = 'Accepted';
275
+ } else if (pInput.UserID && pInput.UserID.trim()) {
276
+ newPart.UserID = pInput.UserID.trim();
277
+ newPart.Role = h.NormalizeParticipantRole(pInput.Role, 'Attendee');
278
+ newPart.InviteStatus = 'Invited';
279
+ } else {
280
+ newPart.ExternalName = pInput.ExternalName?.trim() || null;
281
+ newPart.ExternalEmail = pInput.ExternalEmail?.trim() || null;
282
+ newPart.ExternalPhone = pInput.ExternalPhone?.trim() || null;
283
+ newPart.Role = h.NormalizeParticipantRole(pInput.Role, 'Attendee');
284
+ newPart.InviteStatus = 'Invited';
285
+ }
286
+
287
+ if (await newPart.Save()) {
288
+ if (newPart.UserID) {
289
+ void h.SendMeetingInviteNotification(meeting, newPart.UserID, user, provider);
290
+ }
291
+ }
292
+ }
293
+ }
294
+ }
295
+
296
+ const updatedParticipants = await h.LoadParticipants(meeting.ID, user, provider);
297
+ return {
298
+ Success: true,
299
+ Meeting: h.MapMeetingToType(meeting, updatedParticipants),
300
+ };
301
+ } catch (error) {
302
+ const msg = error instanceof Error ? error.message : String(error);
303
+ LogError(`[MeetingResolver] UpdateMeeting exception: ${msg}`);
304
+ return { Success: false, ErrorMessage: msg };
305
+ }
306
+ }
307
+
308
+ /**
309
+ * Starts a meeting for the `StartMeeting` mutation (`MeetingResolver`): marks it `Live`, ensures its Interaction, starts
310
+ * each agent participant in the room under an agent session created for it, starts an automatic recording, and mints the
311
+ * caller's client token. An agent that fails to start doesn't fail the meeting; the session created for it is closed
312
+ * (`Error`).
313
+ */
314
+ export async function ExecuteStartMeeting(
315
+ provider: IMetadataProvider,
316
+ user: UserInfo,
317
+ meetingID: string,
318
+ sessionManager: SessionManager,
319
+ helpers?: Partial<MeetingHelpers>,
320
+ ): Promise<StartMeetingResult> {
321
+ const h = resolveHelpers(helpers);
322
+ try {
323
+ const meeting = await h.LoadMeetingEntity(meetingID, user, provider);
324
+ if (!meeting) {
325
+ return { Success: false, ErrorMessage: 'Meeting not found.' };
326
+ }
327
+
328
+ const authorized = await h.IsUserHostOrCoHost(meeting, user, provider);
329
+ if (!authorized) {
330
+ return { Success: false, ErrorMessage: 'Unauthorized: only the host or co-host may start this meeting.' };
331
+ }
332
+
333
+ if (meeting.Status === 'Ended' || meeting.Status === 'Cancelled') {
334
+ return { Success: false, ErrorMessage: `Meeting cannot be started because its status is '${meeting.Status}'.` };
335
+ }
336
+
337
+ const now = new Date();
338
+ meeting.Status = 'Live';
339
+ meeting.StartedAt = meeting.StartedAt ?? now;
340
+ if (!(await meeting.Save())) {
341
+ return { Success: false, ErrorMessage: meeting.LatestResult?.CompleteMessage ?? 'Failed to update meeting status to Live.' };
342
+ }
343
+
344
+ // 1. Create or get Interaction row for this meeting
345
+ const interaction = await h.EnsureMeetingInteraction(meeting, user, provider);
346
+
347
+ // 2. Start all AI agent participants
348
+ const participants = await h.LoadParticipants(meeting.ID, user, provider);
349
+ const agentParticipants = participants.filter((p) => p.Role === 'Agent' && p.AgentID);
350
+
351
+ for (const ap of agentParticipants) {
352
+ // Set once this agent's session exists, so a start that fails after it was created can close it.
353
+ let createdSessionID: string | undefined;
354
+ try {
355
+ const createdSession = await sessionManager.CreateSession(
356
+ { agentID: ap.AgentID!, userID: user.ID },
357
+ user,
358
+ provider,
359
+ );
360
+ createdSessionID = createdSession.ID;
361
+ await LiveKitAgentRoomCoordinator.Instance.StartAgentRoomSession({
362
+ AgentSessionID: createdSession.ID,
363
+ RoomName: meeting.RoomName,
364
+ AgentID: ap.AgentID!,
365
+ ContextUser: user,
366
+ MetadataProvider: provider,
367
+ TurnMode: 'Active',
368
+ TurnAddressing: 'Auto',
369
+ // The session exists for this agent's time in the room alone: it closes when the agent leaves (the meeting is
370
+ // ended, everyone leaves, the agent is stopped), not when the janitor finds it idle.
371
+ Host: {
372
+ OnSessionEnded: async (reason) => {
373
+ await sessionManager.CloseSessionForEndedBridge(createdSession.ID, reason, user, provider);
374
+ },
375
+ },
376
+ });
377
+ } catch (agentErr) {
378
+ LogError(`[MeetingResolver] Failed to start agent participant ${ap.AgentID} in room ${meeting.RoomName}: ${agentErr instanceof Error ? agentErr.message : String(agentErr)}`);
379
+ // The agent never joined, so the hook above never runs: close its session now (Error), not when the janitor finds
380
+ // it idle. The coordinator has already closed any model session the start opened (#5308).
381
+ if (createdSessionID) {
382
+ await sessionManager.CloseSessionForFailedStart(createdSessionID, user, provider);
383
+ }
384
+ }
385
+ }
386
+
387
+ // 3. Initiate recording if RecordingPolicy is 'Automatic'
388
+ if (meeting.RecordingPolicy === 'Automatic') {
389
+ try {
390
+ const egress = await new LiveKitEgressService().StartRoomRecording({ RoomName: meeting.RoomName });
391
+ if (egress && egress.EgressID) {
392
+ void CorrelateRecordingStart(meeting.RoomName, egress.EgressID, user, provider);
393
+ if (interaction) {
394
+ await h.RecordInteractionEvent(interaction.ID, 'RecordingStarted', user, provider, { EgressID: egress.EgressID });
395
+ }
396
+ }
397
+ } catch (recErr) {
398
+ LogError(`[MeetingResolver] Automatic recording initiation failed for room ${meeting.RoomName}: ${recErr instanceof Error ? recErr.message : String(recErr)}`);
399
+ }
400
+ }
401
+
402
+ // 4. Mint LiveKit client token for the caller
403
+ const tokenService = new LiveKitTokenService();
404
+ const identity = LiveKitUserIdentity(user.ID);
405
+ const mintedToken = await tokenService.MintClientToken(meeting.RoomName, identity, user.Name ?? user.Email);
406
+
407
+ return {
408
+ Success: true,
409
+ Meeting: h.MapMeetingToType(meeting, participants),
410
+ RoomName: meeting.RoomName,
411
+ ClientToken: mintedToken.Token,
412
+ };
413
+ } catch (error) {
414
+ const msg = error instanceof Error ? error.message : String(error);
415
+ LogError(`[MeetingResolver] StartMeeting exception: ${msg}`);
416
+ return { Success: false, ErrorMessage: msg };
417
+ }
418
+ }
419
+
420
+ export async function ExecuteEndMeeting(
421
+ provider: IMetadataProvider,
422
+ user: UserInfo,
423
+ meetingID: string,
424
+ helpers?: Partial<MeetingHelpers>,
425
+ ): Promise<MeetingResult> {
426
+ const h = resolveHelpers(helpers);
427
+ try {
428
+ const meeting = await h.LoadMeetingEntity(meetingID, user, provider);
429
+ if (!meeting) {
430
+ return { Success: false, ErrorMessage: 'Meeting not found.' };
431
+ }
432
+
433
+ const authorized = await h.IsUserHostOrCoHost(meeting, user, provider);
434
+ if (!authorized) {
435
+ return { Success: false, ErrorMessage: 'Unauthorized: only the host or co-host may end this meeting.' };
436
+ }
437
+
438
+ const now = new Date();
439
+ meeting.Status = 'Ended';
440
+ meeting.EndedAt = now;
441
+ if (!(await meeting.Save())) {
442
+ return { Success: false, ErrorMessage: meeting.LatestResult?.CompleteMessage ?? 'Failed to update meeting status to Ended.' };
443
+ }
444
+
445
+ // 1. Stop all AI agents in room
446
+ try {
447
+ await LiveKitAgentRoomCoordinator.Instance.StopAllAgentsInRoom(meeting.RoomName, 'Explicit', user, provider);
448
+ } catch (err) {
449
+ LogError(`[MeetingResolver] Error stopping agents for room ${meeting.RoomName}: ${err instanceof Error ? err.message : String(err)}`);
450
+ }
451
+
452
+ // 2. Close Interaction record if exists
453
+ await h.CloseMeetingInteraction(meeting.RoomName, user, provider);
454
+
455
+ const participants = await h.LoadParticipants(meeting.ID, user, provider);
456
+ return {
457
+ Success: true,
458
+ Meeting: h.MapMeetingToType(meeting, participants),
459
+ };
460
+ } catch (error) {
461
+ const msg = error instanceof Error ? error.message : String(error);
462
+ LogError(`[MeetingResolver] EndMeeting exception: ${msg}`);
463
+ return { Success: false, ErrorMessage: msg };
464
+ }
465
+ }
466
+
467
+ export async function ExecuteCancelMeeting(
468
+ provider: IMetadataProvider,
469
+ user: UserInfo,
470
+ meetingID: string,
471
+ helpers?: Partial<MeetingHelpers>,
472
+ ): Promise<MeetingResult> {
473
+ const h = resolveHelpers(helpers);
474
+ try {
475
+ const meeting = await h.LoadMeetingEntity(meetingID, user, provider);
476
+ if (!meeting) {
477
+ return { Success: false, ErrorMessage: 'Meeting not found.' };
478
+ }
479
+
480
+ const authorized = await h.IsUserHostOrCoHost(meeting, user, provider);
481
+ if (!authorized) {
482
+ return { Success: false, ErrorMessage: 'Unauthorized: only the host or co-host may cancel this meeting.' };
483
+ }
484
+
485
+ meeting.Status = 'Cancelled';
486
+ if (!(await meeting.Save())) {
487
+ return { Success: false, ErrorMessage: meeting.LatestResult?.CompleteMessage ?? 'Failed to cancel meeting.' };
488
+ }
489
+
490
+ const participants = await h.LoadParticipants(meeting.ID, user, provider);
491
+ return {
492
+ Success: true,
493
+ Meeting: h.MapMeetingToType(meeting, participants),
494
+ };
495
+ } catch (error) {
496
+ const msg = error instanceof Error ? error.message : String(error);
497
+ LogError(`[MeetingResolver] CancelMeeting exception: ${msg}`);
498
+ return { Success: false, ErrorMessage: msg };
499
+ }
500
+ }
501
+
502
+ export async function ExecuteRSVPMeeting(
503
+ provider: IMetadataProvider,
504
+ user: UserInfo,
505
+ input: RSVPMeetingInput,
506
+ helpers?: Partial<MeetingHelpers>,
507
+ ): Promise<MeetingResult> {
508
+ const h = resolveHelpers(helpers);
509
+ try {
510
+ const rv = provider ? RunView.FromMetadataProvider(provider) : new RunView();
511
+
512
+ const validStatuses: MJMeetingParticipantEntity['InviteStatus'][] = ['Accepted', 'Declined', 'Tentative'];
513
+ const statusInput = input.InviteStatus.trim();
514
+ const matchedStatus = validStatuses.find((s) => s.toLowerCase() === statusInput.toLowerCase());
515
+ if (!matchedStatus) {
516
+ return { Success: false, ErrorMessage: `Invalid RSVP status: '${statusInput}'. Expected Accepted, Declined, or Tentative.` };
517
+ }
518
+
519
+ const escapedMeetingID = EscapeSQLString(input.MeetingID.trim());
520
+ const escapedUserID = EscapeSQLString(user.ID);
521
+
522
+ const pResult = await rv.RunView<MJMeetingParticipantEntity>(
523
+ {
524
+ EntityName: 'MJ: Meeting Participants',
525
+ ExtraFilter: `MeetingID = '${escapedMeetingID}' AND UserID = '${escapedUserID}'`,
526
+ ResultType: 'entity_object',
527
+ },
528
+ user,
529
+ );
530
+
531
+ if (!pResult.Success || !pResult.Results || pResult.Results.length === 0) {
532
+ return { Success: false, ErrorMessage: 'Participant record not found for the caller in this meeting.' };
533
+ }
534
+
535
+ const participant = pResult.Results[0];
536
+ participant.InviteStatus = matchedStatus;
537
+ if (!(await participant.Save())) {
538
+ return { Success: false, ErrorMessage: participant.LatestResult?.CompleteMessage ?? 'Failed to save RSVP response.' };
539
+ }
540
+
541
+ const meeting = await h.LoadMeetingEntity(input.MeetingID, user, provider);
542
+ if (!meeting) {
543
+ return { Success: false, ErrorMessage: 'Meeting not found.' };
544
+ }
545
+
546
+ const participants = await h.LoadParticipants(meeting.ID, user, provider);
547
+ return {
548
+ Success: true,
549
+ Meeting: h.MapMeetingToType(meeting, participants),
550
+ };
551
+ } catch (error) {
552
+ const msg = error instanceof Error ? error.message : String(error);
553
+ LogError(`[MeetingResolver] RSVPMeeting exception: ${msg}`);
554
+ return { Success: false, ErrorMessage: msg };
555
+ }
556
+ }