@memberjunction/server 6.2.0-edge.3 → 6.2.0-edge.5

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 (543) hide show
  1. package/README.md +20 -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 +236 -27
  15. package/dist/agentSessions/SessionJanitor.d.ts.map +1 -1
  16. package/dist/agentSessions/SessionJanitor.js +682 -54
  17. package/dist/agentSessions/SessionJanitor.js.map +1 -1
  18. package/dist/agentSessions/SessionManager.d.ts +48 -3
  19. package/dist/agentSessions/SessionManager.d.ts.map +1 -1
  20. package/dist/agentSessions/SessionManager.js +112 -9
  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/apiRoot.d.ts +32 -0
  31. package/dist/apiRoot.d.ts.map +1 -0
  32. package/dist/apiRoot.js +67 -0
  33. package/dist/apiRoot.js.map +1 -0
  34. package/dist/auth/AuthProviderCatalogRouter.d.ts.map +1 -1
  35. package/dist/auth/AuthProviderCatalogRouter.js +25 -0
  36. package/dist/auth/AuthProviderCatalogRouter.js.map +1 -1
  37. package/dist/auth/LoginScreenEngine.d.ts +22 -0
  38. package/dist/auth/LoginScreenEngine.d.ts.map +1 -0
  39. package/dist/auth/LoginScreenEngine.js +57 -0
  40. package/dist/auth/LoginScreenEngine.js.map +1 -0
  41. package/dist/auth/actionAuthorization.d.ts +40 -0
  42. package/dist/auth/actionAuthorization.d.ts.map +1 -0
  43. package/dist/auth/actionAuthorization.js +94 -0
  44. package/dist/auth/actionAuthorization.js.map +1 -0
  45. package/dist/auth/index.d.ts +1 -0
  46. package/dist/auth/index.d.ts.map +1 -1
  47. package/dist/auth/index.js +4 -10
  48. package/dist/auth/index.js.map +1 -1
  49. package/dist/auth/magicLink/MagicLinkRouter.d.ts.map +1 -1
  50. package/dist/auth/magicLink/MagicLinkRouter.js +3 -2
  51. package/dist/auth/magicLink/MagicLinkRouter.js.map +1 -1
  52. package/dist/auth/magicLink/MagicLinkService.d.ts.map +1 -1
  53. package/dist/auth/magicLink/MagicLinkService.js +6 -3
  54. package/dist/auth/magicLink/MagicLinkService.js.map +1 -1
  55. package/dist/auth/newUsers.d.ts +10 -0
  56. package/dist/auth/newUsers.d.ts.map +1 -1
  57. package/dist/auth/newUsers.js +80 -11
  58. package/dist/auth/newUsers.js.map +1 -1
  59. package/dist/config.d.ts +2514 -22
  60. package/dist/config.d.ts.map +1 -1
  61. package/dist/config.js +166 -4
  62. package/dist/config.js.map +1 -1
  63. package/dist/context.d.ts +8 -0
  64. package/dist/context.d.ts.map +1 -1
  65. package/dist/context.js +14 -11
  66. package/dist/context.js.map +1 -1
  67. package/dist/coreRoutes.d.ts +29 -0
  68. package/dist/coreRoutes.d.ts.map +1 -0
  69. package/dist/coreRoutes.js +142 -0
  70. package/dist/coreRoutes.js.map +1 -0
  71. package/dist/generated/graphql-schemas/__mj.d.ts +504 -3
  72. package/dist/generated/graphql-schemas/__mj.d.ts.map +1 -1
  73. package/dist/generated/graphql-schemas/__mj.js +2456 -7
  74. package/dist/generated/graphql-schemas/__mj.js.map +1 -1
  75. package/dist/generic/CacheInvalidationResolver.d.ts +43 -8
  76. package/dist/generic/CacheInvalidationResolver.d.ts.map +1 -1
  77. package/dist/generic/CacheInvalidationResolver.js +59 -19
  78. package/dist/generic/CacheInvalidationResolver.js.map +1 -1
  79. package/dist/generic/OrphanedConversationDetailReconciler.js +3 -3
  80. package/dist/generic/OrphanedConversationDetailReconciler.js.map +1 -1
  81. package/dist/generic/PushStatusResolver.js +1 -1
  82. package/dist/generic/PushStatusResolver.js.map +1 -1
  83. package/dist/generic/ResolverBase.d.ts +123 -48
  84. package/dist/generic/ResolverBase.d.ts.map +1 -1
  85. package/dist/generic/ResolverBase.js +293 -305
  86. package/dist/generic/ResolverBase.js.map +1 -1
  87. package/dist/generic/RunViewResolver.d.ts.map +1 -1
  88. package/dist/generic/RunViewResolver.js +16 -0
  89. package/dist/generic/RunViewResolver.js.map +1 -1
  90. package/dist/globalCors.d.ts +33 -0
  91. package/dist/globalCors.d.ts.map +1 -0
  92. package/dist/globalCors.js +58 -0
  93. package/dist/globalCors.js.map +1 -0
  94. package/dist/index.d.ts +17 -0
  95. package/dist/index.d.ts.map +1 -1
  96. package/dist/index.js +219 -278
  97. package/dist/index.js.map +1 -1
  98. package/dist/isolatedProvider.d.ts +20 -0
  99. package/dist/isolatedProvider.d.ts.map +1 -0
  100. package/dist/isolatedProvider.js +22 -0
  101. package/dist/isolatedProvider.js.map +1 -0
  102. package/dist/multiTenancy/index.d.ts.map +1 -1
  103. package/dist/multiTenancy/index.js +22 -2
  104. package/dist/multiTenancy/index.js.map +1 -1
  105. package/dist/realtimeProxy/RealtimeProxyServer.d.ts +44 -4
  106. package/dist/realtimeProxy/RealtimeProxyServer.d.ts.map +1 -1
  107. package/dist/realtimeProxy/RealtimeProxyServer.js +121 -16
  108. package/dist/realtimeProxy/RealtimeProxyServer.js.map +1 -1
  109. package/dist/realtimeProxy/RealtimeRelayTunnel.d.ts +171 -0
  110. package/dist/realtimeProxy/RealtimeRelayTunnel.d.ts.map +1 -0
  111. package/dist/realtimeProxy/RealtimeRelayTunnel.js +532 -0
  112. package/dist/realtimeProxy/RealtimeRelayTunnel.js.map +1 -0
  113. package/dist/realtimeSessions/RealtimeSessionEventService.d.ts +148 -0
  114. package/dist/realtimeSessions/RealtimeSessionEventService.d.ts.map +1 -0
  115. package/dist/realtimeSessions/RealtimeSessionEventService.js +191 -0
  116. package/dist/realtimeSessions/RealtimeSessionEventService.js.map +1 -0
  117. package/dist/realtimeSessions/RealtimeSessionVerificationService.d.ts +66 -0
  118. package/dist/realtimeSessions/RealtimeSessionVerificationService.d.ts.map +1 -0
  119. package/dist/realtimeSessions/RealtimeSessionVerificationService.js +139 -0
  120. package/dist/realtimeSessions/RealtimeSessionVerificationService.js.map +1 -0
  121. package/dist/realtimeSessions/RealtimeVerifyRouter.d.ts +38 -0
  122. package/dist/realtimeSessions/RealtimeVerifyRouter.d.ts.map +1 -0
  123. package/dist/realtimeSessions/RealtimeVerifyRouter.js +99 -0
  124. package/dist/realtimeSessions/RealtimeVerifyRouter.js.map +1 -0
  125. package/dist/realtimeSessions/RecordingAssemblyScheduler.d.ts +100 -0
  126. package/dist/realtimeSessions/RecordingAssemblyScheduler.d.ts.map +1 -0
  127. package/dist/realtimeSessions/RecordingAssemblyScheduler.js +173 -0
  128. package/dist/realtimeSessions/RecordingAssemblyScheduler.js.map +1 -0
  129. package/dist/realtimeSessions/SessionVerificationPortsBase.d.ts +61 -0
  130. package/dist/realtimeSessions/SessionVerificationPortsBase.d.ts.map +1 -0
  131. package/dist/realtimeSessions/SessionVerificationPortsBase.js +149 -0
  132. package/dist/realtimeSessions/SessionVerificationPortsBase.js.map +1 -0
  133. package/dist/realtimeSessions/SlidingWindowRateLimiter.d.ts +57 -0
  134. package/dist/realtimeSessions/SlidingWindowRateLimiter.d.ts.map +1 -0
  135. package/dist/realtimeSessions/SlidingWindowRateLimiter.js +69 -0
  136. package/dist/realtimeSessions/SlidingWindowRateLimiter.js.map +1 -0
  137. package/dist/realtimeSessions/index.d.ts +19 -0
  138. package/dist/realtimeSessions/index.d.ts.map +1 -0
  139. package/dist/realtimeSessions/index.js +19 -0
  140. package/dist/realtimeSessions/index.js.map +1 -0
  141. package/dist/realtimeSessions/ownedRealtimeSession.d.ts +30 -0
  142. package/dist/realtimeSessions/ownedRealtimeSession.d.ts.map +1 -0
  143. package/dist/realtimeSessions/ownedRealtimeSession.js +47 -0
  144. package/dist/realtimeSessions/ownedRealtimeSession.js.map +1 -0
  145. package/dist/realtimeSessions/sessionAccess.d.ts +92 -0
  146. package/dist/realtimeSessions/sessionAccess.d.ts.map +1 -0
  147. package/dist/realtimeSessions/sessionAccess.js +94 -0
  148. package/dist/realtimeSessions/sessionAccess.js.map +1 -0
  149. package/dist/realtimeSessions/sessionConfigStamps.d.ts +70 -0
  150. package/dist/realtimeSessions/sessionConfigStamps.d.ts.map +1 -0
  151. package/dist/realtimeSessions/sessionConfigStamps.js +93 -0
  152. package/dist/realtimeSessions/sessionConfigStamps.js.map +1 -0
  153. package/dist/realtimeSessions/subscriptionAuthorization.d.ts +65 -0
  154. package/dist/realtimeSessions/subscriptionAuthorization.d.ts.map +1 -0
  155. package/dist/realtimeSessions/subscriptionAuthorization.js +71 -0
  156. package/dist/realtimeSessions/subscriptionAuthorization.js.map +1 -0
  157. package/dist/realtimeSessions/verificationCore.d.ts +243 -0
  158. package/dist/realtimeSessions/verificationCore.d.ts.map +1 -0
  159. package/dist/realtimeSessions/verificationCore.js +356 -0
  160. package/dist/realtimeSessions/verificationCore.js.map +1 -0
  161. package/dist/realtimeSessions/verificationPages.d.ts +66 -0
  162. package/dist/realtimeSessions/verificationPages.d.ts.map +1 -0
  163. package/dist/realtimeSessions/verificationPages.js +110 -0
  164. package/dist/realtimeSessions/verificationPages.js.map +1 -0
  165. package/dist/realtimeSessions/verificationPolicy.d.ts +147 -0
  166. package/dist/realtimeSessions/verificationPolicy.d.ts.map +1 -0
  167. package/dist/realtimeSessions/verificationPolicy.js +249 -0
  168. package/dist/realtimeSessions/verificationPolicy.js.map +1 -0
  169. package/dist/realtimeSessions/verificationWorkflow.d.ts +263 -0
  170. package/dist/realtimeSessions/verificationWorkflow.d.ts.map +1 -0
  171. package/dist/realtimeSessions/verificationWorkflow.js +435 -0
  172. package/dist/realtimeSessions/verificationWorkflow.js.map +1 -0
  173. package/dist/realtimeWidget/widgetGuestElevation.d.ts +20 -2
  174. package/dist/realtimeWidget/widgetGuestElevation.d.ts.map +1 -1
  175. package/dist/realtimeWidget/widgetGuestElevation.js +31 -2
  176. package/dist/realtimeWidget/widgetGuestElevation.js.map +1 -1
  177. package/dist/resolvers/ActionResolver.d.ts +31 -5
  178. package/dist/resolvers/ActionResolver.d.ts.map +1 -1
  179. package/dist/resolvers/ActionResolver.js +75 -14
  180. package/dist/resolvers/ActionResolver.js.map +1 -1
  181. package/dist/resolvers/AdhocQueryResolver.d.ts +14 -1
  182. package/dist/resolvers/AdhocQueryResolver.d.ts.map +1 -1
  183. package/dist/resolvers/AdhocQueryResolver.js +21 -5
  184. package/dist/resolvers/AdhocQueryResolver.js.map +1 -1
  185. package/dist/resolvers/ArtifactFileResolver.d.ts +5 -1
  186. package/dist/resolvers/ArtifactFileResolver.d.ts.map +1 -1
  187. package/dist/resolvers/ArtifactFileResolver.js +9 -7
  188. package/dist/resolvers/ArtifactFileResolver.js.map +1 -1
  189. package/dist/resolvers/CacheStatsResolver.d.ts +27 -0
  190. package/dist/resolvers/CacheStatsResolver.d.ts.map +1 -1
  191. package/dist/resolvers/CacheStatsResolver.js +113 -2
  192. package/dist/resolvers/CacheStatsResolver.js.map +1 -1
  193. package/dist/resolvers/ClientToolRequestResolver.d.ts +4 -2
  194. package/dist/resolvers/ClientToolRequestResolver.d.ts.map +1 -1
  195. package/dist/resolvers/ClientToolRequestResolver.js +28 -10
  196. package/dist/resolvers/ClientToolRequestResolver.js.map +1 -1
  197. package/dist/resolvers/ConversationRunEventsResolver.d.ts +8 -4
  198. package/dist/resolvers/ConversationRunEventsResolver.d.ts.map +1 -1
  199. package/dist/resolvers/ConversationRunEventsResolver.js +6 -6
  200. package/dist/resolvers/ConversationRunEventsResolver.js.map +1 -1
  201. package/dist/resolvers/DatasetResolver.d.ts +24 -3
  202. package/dist/resolvers/DatasetResolver.d.ts.map +1 -1
  203. package/dist/resolvers/DatasetResolver.js +57 -8
  204. package/dist/resolvers/DatasetResolver.js.map +1 -1
  205. package/dist/resolvers/EntityRecordNameResolver.d.ts +2 -1
  206. package/dist/resolvers/EntityRecordNameResolver.d.ts.map +1 -1
  207. package/dist/resolvers/EntityRecordNameResolver.js +3 -2
  208. package/dist/resolvers/EntityRecordNameResolver.js.map +1 -1
  209. package/dist/resolvers/FetchEntityVectorsResolver.d.ts +27 -1
  210. package/dist/resolvers/FetchEntityVectorsResolver.d.ts.map +1 -1
  211. package/dist/resolvers/FetchEntityVectorsResolver.js +148 -2
  212. package/dist/resolvers/FetchEntityVectorsResolver.js.map +1 -1
  213. package/dist/resolvers/FileResolver.d.ts +82 -11
  214. package/dist/resolvers/FileResolver.d.ts.map +1 -1
  215. package/dist/resolvers/FileResolver.js +279 -101
  216. package/dist/resolvers/FileResolver.js.map +1 -1
  217. package/dist/resolvers/GetDataContextDataResolver.d.ts +33 -7
  218. package/dist/resolvers/GetDataContextDataResolver.d.ts.map +1 -1
  219. package/dist/resolvers/GetDataContextDataResolver.js +117 -38
  220. package/dist/resolvers/GetDataContextDataResolver.js.map +1 -1
  221. package/dist/resolvers/GetDataResolver.d.ts.map +1 -1
  222. package/dist/resolvers/GetDataResolver.js +6 -3
  223. package/dist/resolvers/GetDataResolver.js.map +1 -1
  224. package/dist/resolvers/HumanHandoffResolver.d.ts.map +1 -1
  225. package/dist/resolvers/HumanHandoffResolver.js +7 -1
  226. package/dist/resolvers/HumanHandoffResolver.js.map +1 -1
  227. package/dist/resolvers/IntegrationDiscoveryResolver.d.ts.map +1 -1
  228. package/dist/resolvers/IntegrationDiscoveryResolver.js +4 -2
  229. package/dist/resolvers/IntegrationDiscoveryResolver.js.map +1 -1
  230. package/dist/resolvers/MCPResolver.d.ts.map +1 -1
  231. package/dist/resolvers/MCPResolver.js +9 -4
  232. package/dist/resolvers/MCPResolver.js.map +1 -1
  233. package/dist/resolvers/QueryResolver.d.ts +2 -0
  234. package/dist/resolvers/QueryResolver.d.ts.map +1 -1
  235. package/dist/resolvers/QueryResolver.js +13 -0
  236. package/dist/resolvers/QueryResolver.js.map +1 -1
  237. package/dist/resolvers/RealtimeBridgeResolver.d.ts +54 -2
  238. package/dist/resolvers/RealtimeBridgeResolver.d.ts.map +1 -1
  239. package/dist/resolvers/RealtimeBridgeResolver.js +155 -10
  240. package/dist/resolvers/RealtimeBridgeResolver.js.map +1 -1
  241. package/dist/resolvers/RealtimeClientSessionResolver.d.ts +157 -33
  242. package/dist/resolvers/RealtimeClientSessionResolver.d.ts.map +1 -1
  243. package/dist/resolvers/RealtimeClientSessionResolver.js +404 -116
  244. package/dist/resolvers/RealtimeClientSessionResolver.js.map +1 -1
  245. package/dist/resolvers/RealtimeSessionEventsResolver.d.ts +61 -0
  246. package/dist/resolvers/RealtimeSessionEventsResolver.d.ts.map +1 -0
  247. package/dist/resolvers/RealtimeSessionEventsResolver.js +130 -0
  248. package/dist/resolvers/RealtimeSessionEventsResolver.js.map +1 -0
  249. package/dist/resolvers/RealtimeSessionVerificationResolver.d.ts +85 -0
  250. package/dist/resolvers/RealtimeSessionVerificationResolver.d.ts.map +1 -0
  251. package/dist/resolvers/RealtimeSessionVerificationResolver.js +188 -0
  252. package/dist/resolvers/RealtimeSessionVerificationResolver.js.map +1 -0
  253. package/dist/resolvers/RemoteBrowserActionResolver.d.ts +2 -0
  254. package/dist/resolvers/RemoteBrowserActionResolver.d.ts.map +1 -1
  255. package/dist/resolvers/RemoteBrowserActionResolver.js +5 -1
  256. package/dist/resolvers/RemoteBrowserActionResolver.js.map +1 -1
  257. package/dist/resolvers/RunAIAgentResolver.d.ts +10 -0
  258. package/dist/resolvers/RunAIAgentResolver.d.ts.map +1 -1
  259. package/dist/resolvers/RunAIAgentResolver.js +100 -14
  260. package/dist/resolvers/RunAIAgentResolver.js.map +1 -1
  261. package/dist/resolvers/RunTemplateResolver.d.ts.map +1 -1
  262. package/dist/resolvers/RunTemplateResolver.js +12 -11
  263. package/dist/resolvers/RunTemplateResolver.js.map +1 -1
  264. package/dist/resolvers/SearchKnowledgeStreamResolver.d.ts +12 -1
  265. package/dist/resolvers/SearchKnowledgeStreamResolver.d.ts.map +1 -1
  266. package/dist/resolvers/SearchKnowledgeStreamResolver.js +15 -2
  267. package/dist/resolvers/SearchKnowledgeStreamResolver.js.map +1 -1
  268. package/dist/resolvers/SqlLoggingConfigResolver.d.ts.map +1 -1
  269. package/dist/resolvers/SqlLoggingConfigResolver.js +2 -3
  270. package/dist/resolvers/SqlLoggingConfigResolver.js.map +1 -1
  271. package/dist/resolvers/SyncDataResolver.d.ts.map +1 -1
  272. package/dist/resolvers/SyncDataResolver.js +6 -2
  273. package/dist/resolvers/SyncDataResolver.js.map +1 -1
  274. package/dist/resolvers/SyncRolesUsersResolver.d.ts +2 -0
  275. package/dist/resolvers/SyncRolesUsersResolver.d.ts.map +1 -1
  276. package/dist/resolvers/SyncRolesUsersResolver.js +23 -6
  277. package/dist/resolvers/SyncRolesUsersResolver.js.map +1 -1
  278. package/dist/resolvers/TaskGraphFrameResolver.d.ts +2 -1
  279. package/dist/resolvers/TaskGraphFrameResolver.d.ts.map +1 -1
  280. package/dist/resolvers/TaskGraphFrameResolver.js +28 -1
  281. package/dist/resolvers/TaskGraphFrameResolver.js.map +1 -1
  282. package/dist/resolvers/TestQuerySQLResolver.d.ts +24 -0
  283. package/dist/resolvers/TestQuerySQLResolver.d.ts.map +1 -1
  284. package/dist/resolvers/TestQuerySQLResolver.js +65 -13
  285. package/dist/resolvers/TestQuerySQLResolver.js.map +1 -1
  286. package/dist/resolvers/TransactionGroupResolver.d.ts +19 -2
  287. package/dist/resolvers/TransactionGroupResolver.d.ts.map +1 -1
  288. package/dist/resolvers/TransactionGroupResolver.js +102 -24
  289. package/dist/resolvers/TransactionGroupResolver.js.map +1 -1
  290. package/dist/resolvers/UserAvatarResolver.d.ts +16 -0
  291. package/dist/resolvers/UserAvatarResolver.d.ts.map +1 -0
  292. package/dist/resolvers/UserAvatarResolver.js +124 -0
  293. package/dist/resolvers/UserAvatarResolver.js.map +1 -0
  294. package/dist/resolvers/UserResolver.d.ts.map +1 -1
  295. package/dist/resolvers/UserResolver.js +2 -17
  296. package/dist/resolvers/UserResolver.js.map +1 -1
  297. package/dist/resolvers/agent-run-data-guard.d.ts +31 -0
  298. package/dist/resolvers/agent-run-data-guard.d.ts.map +1 -0
  299. package/dist/resolvers/agent-run-data-guard.js +72 -0
  300. package/dist/resolvers/agent-run-data-guard.js.map +1 -0
  301. package/dist/resolvers/agentVisionConsentAudit.d.ts +37 -0
  302. package/dist/resolvers/agentVisionConsentAudit.d.ts.map +1 -0
  303. package/dist/resolvers/agentVisionConsentAudit.js +63 -0
  304. package/dist/resolvers/agentVisionConsentAudit.js.map +1 -0
  305. package/dist/resolvers/avatarInputValidation.d.ts +40 -0
  306. package/dist/resolvers/avatarInputValidation.d.ts.map +1 -0
  307. package/dist/resolvers/avatarInputValidation.js +97 -0
  308. package/dist/resolvers/avatarInputValidation.js.map +1 -0
  309. package/dist/resolvers/currentUserRoles.d.ts +29 -0
  310. package/dist/resolvers/currentUserRoles.d.ts.map +1 -1
  311. package/dist/resolvers/currentUserRoles.js +30 -0
  312. package/dist/resolvers/currentUserRoles.js.map +1 -1
  313. package/dist/resolvers/meetings/meetingMutations.d.ts +6 -0
  314. package/dist/resolvers/meetings/meetingMutations.d.ts.map +1 -1
  315. package/dist/resolvers/meetings/meetingMutations.js +21 -0
  316. package/dist/resolvers/meetings/meetingMutations.js.map +1 -1
  317. package/dist/rest/RealtimeRecordingHandler.d.ts +49 -0
  318. package/dist/rest/RealtimeRecordingHandler.d.ts.map +1 -0
  319. package/dist/rest/RealtimeRecordingHandler.js +383 -0
  320. package/dist/rest/RealtimeRecordingHandler.js.map +1 -0
  321. package/dist/rest/ViewOperationsHandler.d.ts +3 -1
  322. package/dist/rest/ViewOperationsHandler.d.ts.map +1 -1
  323. package/dist/rest/ViewOperationsHandler.js +21 -12
  324. package/dist/rest/ViewOperationsHandler.js.map +1 -1
  325. package/dist/rest/setupRESTEndpoints.d.ts +6 -0
  326. package/dist/rest/setupRESTEndpoints.d.ts.map +1 -1
  327. package/dist/rest/setupRESTEndpoints.js +6 -0
  328. package/dist/rest/setupRESTEndpoints.js.map +1 -1
  329. package/dist/serverExtensionReservedRoots.d.ts +12 -10
  330. package/dist/serverExtensionReservedRoots.d.ts.map +1 -1
  331. package/dist/serverExtensionReservedRoots.js +14 -17
  332. package/dist/serverExtensionReservedRoots.js.map +1 -1
  333. package/dist/services/MJStorageBlobStore.d.ts +8 -1
  334. package/dist/services/MJStorageBlobStore.d.ts.map +1 -1
  335. package/dist/services/MJStorageBlobStore.js +25 -19
  336. package/dist/services/MJStorageBlobStore.js.map +1 -1
  337. package/dist/services/StartTaskGraphDispatcher.js +2 -2
  338. package/dist/services/StartTaskGraphDispatcher.js.map +1 -1
  339. package/dist/services/TaskGraphActionRunner.d.ts +5 -3
  340. package/dist/services/TaskGraphActionRunner.d.ts.map +1 -1
  341. package/dist/services/TaskGraphActionRunner.js +27 -5
  342. package/dist/services/TaskGraphActionRunner.js.map +1 -1
  343. package/dist/services/TaskGraphAgentRunner.d.ts +14 -2
  344. package/dist/services/TaskGraphAgentRunner.d.ts.map +1 -1
  345. package/dist/services/TaskGraphAgentRunner.js +157 -9
  346. package/dist/services/TaskGraphAgentRunner.js.map +1 -1
  347. package/dist/services/TaskGraphContinuationDeliverer.d.ts +57 -4
  348. package/dist/services/TaskGraphContinuationDeliverer.d.ts.map +1 -1
  349. package/dist/services/TaskGraphContinuationDeliverer.js +607 -18
  350. package/dist/services/TaskGraphContinuationDeliverer.js.map +1 -1
  351. package/dist/sharedCache.d.ts +105 -0
  352. package/dist/sharedCache.d.ts.map +1 -0
  353. package/dist/sharedCache.js +279 -0
  354. package/dist/sharedCache.js.map +1 -0
  355. package/dist/types.d.ts +6 -0
  356. package/dist/types.d.ts.map +1 -1
  357. package/dist/types.js.map +1 -1
  358. package/package.json +99 -96
  359. package/src/__tests__/ActionResolver.authorization.test.ts +353 -0
  360. package/src/__tests__/AdhocQueryResolver.sqlAuthorizer.test.ts +104 -0
  361. package/src/__tests__/BridgeHostInstance.test.ts +232 -0
  362. package/src/__tests__/ClientToolRequestResolver.test.ts +116 -0
  363. package/src/__tests__/DatasetResolver.itemFilters.test.ts +201 -0
  364. package/src/__tests__/EntityRecordNameResolver.rowSecurity.test.ts +152 -0
  365. package/src/__tests__/FetchEntityVectorsResolver.test.ts +433 -0
  366. package/src/__tests__/FileResolver.storageAccess.test.ts +562 -0
  367. package/src/__tests__/GetDataContextDataResolver.sqlItems.test.ts +416 -0
  368. package/src/__tests__/HostInstance.test.ts +84 -0
  369. package/src/__tests__/HumanHandoffResolver.test.ts +17 -0
  370. package/src/__tests__/ListOperationsResolver.adhocScreen.test.ts +137 -0
  371. package/src/__tests__/LoginScreenEngine.test.ts +86 -0
  372. package/src/__tests__/MJStorageBlobStore.storageGate.test.ts +63 -0
  373. package/src/__tests__/MeetingResolver.test.ts +75 -1
  374. package/src/__tests__/RealtimeBridgeResolver.test.ts +415 -6
  375. package/src/__tests__/RealtimeClientSessionResolver.configTamper.test.ts +383 -0
  376. package/src/__tests__/RealtimeClientSessionResolver.test.ts +682 -58
  377. package/src/__tests__/RealtimeProxyServer.test.ts +16 -1
  378. package/src/__tests__/RealtimeRelay.test.ts +876 -0
  379. package/src/__tests__/RecordingAssemblyScheduler.test.ts +178 -0
  380. package/src/__tests__/RemoteBrowserActionResolver.goalRunLink.test.ts +129 -0
  381. package/src/__tests__/ResolverBase.adhocReadScope.test.ts +133 -2
  382. package/src/__tests__/ResolverBase.aggregateScreen.test.ts +174 -0
  383. package/src/__tests__/ResolverBase.balancedClause.test.ts +155 -0
  384. package/src/__tests__/ResolverBase.clauseUnscopedRead.test.ts +127 -0
  385. package/src/__tests__/ResolverBase.clientOldValues.test.ts +212 -6
  386. package/src/__tests__/ResolverBase.filterEscaping.test.ts +5 -2
  387. package/src/__tests__/ReturningVisitorRecap.test.ts +115 -0
  388. package/src/__tests__/RunAIAgentResolver.branch.test.ts +170 -0
  389. package/src/__tests__/RunAIAgentResolver.historyFrom.test.ts +6 -4
  390. package/src/__tests__/RunAIAgentResolver.runDataGuard.test.ts +258 -0
  391. package/src/__tests__/RunAIAgentResolver.stoppedPredecessor.test.ts +166 -0
  392. package/src/__tests__/RunTemplateResolver.test.ts +132 -0
  393. package/src/__tests__/RunViewResolver.cacheCheckForwarding.test.ts +63 -0
  394. package/src/__tests__/RunViewResolver.cacheCheckScreen.test.ts +165 -0
  395. package/src/__tests__/SearchKnowledgeStreamResolver.test.ts +161 -0
  396. package/src/__tests__/SessionJanitor.test.ts +1203 -21
  397. package/src/__tests__/SessionManager.test.ts +240 -17
  398. package/src/__tests__/SessionRunIDVerifier.test.ts +251 -0
  399. package/src/__tests__/SyncRolesUsersResolver.userRoles.test.ts +97 -0
  400. package/src/__tests__/TaskGraphActionRunner.durablePayload.test.ts +25 -0
  401. package/src/__tests__/TaskGraphAgentRunner.test.ts +266 -0
  402. package/src/__tests__/TaskGraphContinuationDeliverer.test.ts +403 -22
  403. package/src/__tests__/TaskGraphFrameResolver.test.ts +22 -0
  404. package/src/__tests__/TestQuerySQLResolver.test.ts +274 -0
  405. package/src/__tests__/TransactionGroupResolver.refusals.test.ts +98 -1
  406. package/src/__tests__/UpdateMJDataContextItem.oldValues.test.ts +220 -0
  407. package/src/__tests__/UserAvatarResolver.test.ts +255 -0
  408. package/src/__tests__/UserResolver.currentUser.test.ts +16 -1
  409. package/src/__tests__/ViewOperationsHandler.clauseScreen.test.ts +157 -0
  410. package/src/__tests__/actionAuthorization.test.ts +130 -0
  411. package/src/__tests__/agent-run-data-guard.test.ts +130 -0
  412. package/src/__tests__/agentVisionConsentAudit.test.ts +118 -0
  413. package/src/__tests__/apiRootBoot.test.ts +202 -0
  414. package/src/__tests__/avatarInputValidation.test.ts +160 -0
  415. package/src/__tests__/cacheInvalidationRecordData.test.ts +64 -0
  416. package/src/__tests__/conversationRunEvents.test.ts +56 -14
  417. package/src/__tests__/globalCors.test.ts +217 -0
  418. package/src/__tests__/isolatedProviderTransactions.test.ts +169 -0
  419. package/src/__tests__/magicLinkService.consume.test.ts +6 -0
  420. package/src/__tests__/magicLinkService.provisionLog.test.ts +5 -0
  421. package/src/__tests__/multiTenancy.postgresRewrite.test.ts +181 -0
  422. package/src/__tests__/multiTenancy.security.test.ts +51 -0
  423. package/src/__tests__/multiTenancy.test.ts +1 -1
  424. package/src/__tests__/newUsers.template.test.ts +151 -0
  425. package/src/__tests__/newUsers.test.ts +74 -5
  426. package/src/__tests__/orphanedConversationDetailReconciler.test.ts +17 -2
  427. package/src/__tests__/ownedRealtimeSession.test.ts +39 -0
  428. package/src/__tests__/pushStatusResolver.filter.test.ts +7 -0
  429. package/src/__tests__/realtimeRecordingHandler.test.ts +652 -0
  430. package/src/__tests__/realtimeSessions/RealtimeSessionEventService.test.ts +201 -0
  431. package/src/__tests__/realtimeSessions/RealtimeSessionEventsResolver.test.ts +215 -0
  432. package/src/__tests__/realtimeSessions/RealtimeSessionVerificationResolver.test.ts +102 -0
  433. package/src/__tests__/realtimeSessions/RealtimeSessionVerificationService.test.ts +349 -0
  434. package/src/__tests__/realtimeSessions/RealtimeVerifyRouter.test.ts +131 -0
  435. package/src/__tests__/realtimeSessions/SlidingWindowRateLimiter.test.ts +56 -0
  436. package/src/__tests__/realtimeSessions/helpers.ts +4 -0
  437. package/src/__tests__/realtimeSessions/sessionAccess.test.ts +129 -0
  438. package/src/__tests__/realtimeSessions/sessionConfigStamps.test.ts +124 -0
  439. package/src/__tests__/realtimeSessions/verificationCore.test.ts +355 -0
  440. package/src/__tests__/realtimeSessions/verificationPages.test.ts +84 -0
  441. package/src/__tests__/realtimeSessions/verificationPolicy.test.ts +226 -0
  442. package/src/__tests__/realtimeSessions/verificationWorkflow.test.ts +633 -0
  443. package/src/__tests__/resolverBase.fls.test.ts +87 -4
  444. package/src/__tests__/serverExtensionHostOverlay.test.ts +66 -0
  445. package/src/__tests__/serverExtensionReservedRoots.test.ts +11 -96
  446. package/src/__tests__/sharedCache.test.ts +312 -0
  447. package/src/__tests__/widgetGuestElevation.test.ts +44 -0
  448. package/src/agentSessions/BridgeHostInstance.ts +32 -0
  449. package/src/agentSessions/HostInstance.ts +124 -28
  450. package/src/agentSessions/ReturningVisitorRecap.ts +7 -3
  451. package/src/agentSessions/SessionJanitor.ts +821 -59
  452. package/src/agentSessions/SessionManager.ts +138 -26
  453. package/src/agentSessions/SessionRunIDVerifier.ts +171 -0
  454. package/src/agentSessions/index.ts +10 -3
  455. package/src/apiRoot.ts +78 -0
  456. package/src/auth/AuthProviderCatalogRouter.ts +26 -0
  457. package/src/auth/LoginScreenEngine.ts +50 -0
  458. package/src/auth/actionAuthorization.ts +116 -0
  459. package/src/auth/index.ts +4 -8
  460. package/src/auth/magicLink/MagicLinkRouter.ts +3 -2
  461. package/src/auth/magicLink/MagicLinkService.ts +6 -3
  462. package/src/auth/newUsers.ts +99 -11
  463. package/src/config.ts +171 -5
  464. package/src/context.ts +15 -10
  465. package/src/coreRoutes.ts +166 -0
  466. package/src/generated/graphql-schemas/__mj.ts +1815 -57
  467. package/src/generic/CacheInvalidationResolver.ts +73 -18
  468. package/src/generic/OrphanedConversationDetailReconciler.ts +3 -3
  469. package/src/generic/PushStatusResolver.ts +1 -1
  470. package/src/generic/ResolverBase.ts +335 -326
  471. package/src/generic/RunViewResolver.ts +21 -0
  472. package/src/globalCors.ts +71 -0
  473. package/src/index.ts +231 -300
  474. package/src/isolatedProvider.ts +22 -0
  475. package/src/multiTenancy/index.ts +24 -2
  476. package/src/realtimeProxy/RealtimeProxyServer.ts +148 -16
  477. package/src/realtimeProxy/RealtimeRelayTunnel.ts +645 -0
  478. package/src/realtimeSessions/README.md +179 -0
  479. package/src/realtimeSessions/RealtimeSessionEventService.ts +274 -0
  480. package/src/realtimeSessions/RealtimeSessionVerificationService.ts +168 -0
  481. package/src/realtimeSessions/RealtimeVerifyRouter.ts +109 -0
  482. package/src/realtimeSessions/RecordingAssemblyScheduler.ts +234 -0
  483. package/src/realtimeSessions/SessionVerificationPortsBase.ts +189 -0
  484. package/src/realtimeSessions/SlidingWindowRateLimiter.ts +92 -0
  485. package/src/realtimeSessions/index.ts +18 -0
  486. package/src/realtimeSessions/ownedRealtimeSession.ts +55 -0
  487. package/src/realtimeSessions/sessionAccess.ts +145 -0
  488. package/src/realtimeSessions/sessionConfigStamps.ts +123 -0
  489. package/src/realtimeSessions/subscriptionAuthorization.ts +116 -0
  490. package/src/realtimeSessions/verificationCore.ts +502 -0
  491. package/src/realtimeSessions/verificationPages.ts +149 -0
  492. package/src/realtimeSessions/verificationPolicy.ts +321 -0
  493. package/src/realtimeSessions/verificationWorkflow.ts +702 -0
  494. package/src/realtimeWidget/widgetGuestElevation.ts +34 -2
  495. package/src/resolvers/ActionResolver.ts +84 -21
  496. package/src/resolvers/AdhocQueryResolver.ts +24 -6
  497. package/src/resolvers/ArtifactFileResolver.ts +9 -8
  498. package/src/resolvers/CacheStatsResolver.ts +89 -2
  499. package/src/resolvers/ClientToolRequestResolver.ts +25 -7
  500. package/src/resolvers/ConversationRunEventsResolver.ts +15 -11
  501. package/src/resolvers/DatasetResolver.ts +70 -10
  502. package/src/resolvers/EntityRecordNameResolver.ts +3 -2
  503. package/src/resolvers/FetchEntityVectorsResolver.ts +179 -2
  504. package/src/resolvers/FileResolver.ts +321 -106
  505. package/src/resolvers/GetDataContextDataResolver.ts +139 -41
  506. package/src/resolvers/GetDataResolver.ts +6 -3
  507. package/src/resolvers/HumanHandoffResolver.ts +8 -0
  508. package/src/resolvers/IntegrationDiscoveryResolver.ts +4 -2
  509. package/src/resolvers/MCPResolver.ts +8 -5
  510. package/src/resolvers/QueryResolver.ts +11 -0
  511. package/src/resolvers/RealtimeBridgeResolver.ts +163 -11
  512. package/src/resolvers/RealtimeClientSessionResolver.ts +511 -129
  513. package/src/resolvers/RealtimeSessionEventsResolver.ts +133 -0
  514. package/src/resolvers/RealtimeSessionVerificationResolver.ts +174 -0
  515. package/src/resolvers/RemoteBrowserActionResolver.ts +11 -1
  516. package/src/resolvers/RunAIAgentResolver.ts +116 -14
  517. package/src/resolvers/RunTemplateResolver.ts +13 -12
  518. package/src/resolvers/SearchKnowledgeStreamResolver.ts +19 -3
  519. package/src/resolvers/SqlLoggingConfigResolver.ts +2 -4
  520. package/src/resolvers/SyncDataResolver.ts +6 -2
  521. package/src/resolvers/SyncRolesUsersResolver.ts +24 -6
  522. package/src/resolvers/TaskGraphFrameResolver.ts +33 -1
  523. package/src/resolvers/TestQuerySQLResolver.ts +68 -13
  524. package/src/resolvers/TransactionGroupResolver.ts +131 -27
  525. package/src/resolvers/UserAvatarResolver.ts +111 -0
  526. package/src/resolvers/UserResolver.ts +2 -16
  527. package/src/resolvers/__tests__/GetDataResolver.validation.test.ts +95 -0
  528. package/src/resolvers/agent-run-data-guard.ts +89 -0
  529. package/src/resolvers/agentVisionConsentAudit.ts +82 -0
  530. package/src/resolvers/avatarInputValidation.ts +123 -0
  531. package/src/resolvers/currentUserRoles.ts +32 -1
  532. package/src/resolvers/meetings/meetingMutations.ts +21 -0
  533. package/src/rest/RealtimeRecordingHandler.ts +464 -0
  534. package/src/rest/ViewOperationsHandler.ts +29 -13
  535. package/src/rest/setupRESTEndpoints.ts +6 -0
  536. package/src/serverExtensionReservedRoots.ts +14 -17
  537. package/src/services/MJStorageBlobStore.ts +31 -30
  538. package/src/services/StartTaskGraphDispatcher.ts +2 -2
  539. package/src/services/TaskGraphActionRunner.ts +25 -5
  540. package/src/services/TaskGraphAgentRunner.ts +188 -11
  541. package/src/services/TaskGraphContinuationDeliverer.ts +713 -17
  542. package/src/sharedCache.ts +305 -0
  543. package/src/types.ts +7 -0
@@ -1,9 +1,13 @@
1
1
  import { Arg, Ctx, Field, ObjectType, Query, Resolver } from "type-graphql";
2
+ import type { DatabaseProviderBase, UserInfo } from "@memberjunction/core";
3
+ import { IsValidUUID, UUIDsEqual } from "@memberjunction/global";
4
+ import { DataContext, DataContextItem } from "@memberjunction/data-context";
5
+ import { MJDataContextEntity, MJDataContextItemEntity } from "@memberjunction/core-entities";
6
+ import { RenderPipeline } from "@memberjunction/generic-database-provider";
2
7
  import { AppContext } from "../types.js";
3
- import { DataContext } from "@memberjunction/data-context";
4
- import { GetReadOnlyDataSource, GetReadOnlyProvider } from "../util.js";
5
- import { MJDataContextItemEntity } from "@memberjunction/core-entities";
8
+ import { GetReadOnlyProvider } from "../util.js";
6
9
  import { ResolverBase } from "../generic/ResolverBase.js";
10
+ import { IsScopeLimitedPrincipal } from "../auth/scopeLimitedPrincipal.js";
7
11
 
8
12
  @ObjectType()
9
13
  export class GetDataContextItemDataOutputType {
@@ -39,6 +43,28 @@ export class GetDataContextDataOutputType {
39
43
  }
40
44
 
41
45
 
46
+ /** The outcome of loading one data context item: its data as JSON, or why it has none. */
47
+ interface ItemOutcome {
48
+ Result: string | null;
49
+ Error: string | null;
50
+ }
51
+
52
+ /** Which `sql` items of a data context may run: the read-only provider, and each refused item's reason. */
53
+ interface SQLItemGate {
54
+ Provider: DatabaseProviderBase | null;
55
+ Refusals: Map<DataContextItem, string>;
56
+ }
57
+
58
+ /**
59
+ * Loads the data of data contexts and their items.
60
+ *
61
+ * Items of type `sql` hold raw SQL, which is held to the rules ExecuteAdhocQuery applies to
62
+ * caller-supplied SQL. It runs only for the data context's owner or an administrator (Owner-type
63
+ * user), never for a scope-limited session, only on the read-only provider, and only as a single read
64
+ * statement over entity base views the caller may read in full. A SQL item that may not run is
65
+ * refused on its own, and the other items still load. Items of the other types load through entity
66
+ * permissions for the calling user.
67
+ */
42
68
  @Resolver()
43
69
  export class GetDataContextDataResolver extends ResolverBase {
44
70
  /**
@@ -52,30 +78,25 @@ export class GetDataContextDataResolver extends ResolverBase {
52
78
  ) {
53
79
  // Check API key scope authorization for data context read
54
80
  await this.CheckAPIKeyScopeAuthorization('datacontext:read', DataContextItemID, appCtx.userPayload);
81
+ if (!IsValidUUID(DataContextItemID)) {
82
+ return { Success: false, ErrorMessage: 'DataContextItemID must be a UUID', Result: null };
83
+ }
55
84
 
56
85
  try {
57
- const ds = GetReadOnlyDataSource(appCtx.dataSources, {
58
- allowFallbackToReadWrite: true,
59
- })
86
+ const user: UserInfo = appCtx.userPayload.userRecord;
60
87
  const md = GetReadOnlyProvider(appCtx.providers, {allowFallbackToReadWrite: true});
61
- const dciData = await md.GetEntityObject<MJDataContextItemEntity>("MJ: Data Context Items", appCtx.userPayload.userRecord);
88
+ const dciData = await md.GetEntityObject<MJDataContextItemEntity>("MJ: Data Context Items", user);
62
89
  if (await dciData.Load(DataContextItemID)) {
63
90
  const dci = DataContext.CreateDataContextItem(); // use class factory to get whatever lowest level sub-class is registered
64
- await dci.LoadMetadataFromEntityRecord(dciData, md, appCtx.userPayload.userRecord);
91
+ await dci.LoadMetadataFromEntityRecord(dciData, md, user);
92
+ const ownerID = dci.Type === 'sql' ? await this.loadDataContextOwnerID(dciData.DataContextID, md, user) : null;
93
+ const gate = this.authorizeSQLItems([dci], ownerID, appCtx);
65
94
  // now the metadata is loaded so we can call the regular load function
66
- if (await dci.LoadData(ds)) {
67
- return {
68
- Success: true,
69
- ErrorMessage: null,
70
- Result: JSON.stringify(dci.Data),
71
- }
72
- }
73
- else {
74
- return {
75
- Success: false,
76
- ErrorMessage: 'Error loading data context item data',
77
- Result: null,
78
- }
95
+ const outcome = await this.loadItem(dci, gate, user, false);
96
+ return {
97
+ Success: outcome.Error === null,
98
+ ErrorMessage: outcome.Error,
99
+ Result: outcome.Result,
79
100
  }
80
101
  }
81
102
  else {
@@ -89,14 +110,15 @@ export class GetDataContextDataResolver extends ResolverBase {
89
110
  catch (e) {
90
111
  return {
91
112
  Success: false,
92
- ErrorMessage: e,
113
+ ErrorMessage: e instanceof Error ? e.message : String(e),
93
114
  Result: null,
94
115
  }
95
116
  }
96
117
  }
97
118
 
98
119
  /**
99
- * Returns data for a given data context.
120
+ * Returns data for a given data context. `Results` and `ErrorMessages` hold one entry per item, in
121
+ * item order. `Success` is true, and `ErrorMessages` null, only when every item loaded.
100
122
  * @param DataContextID
101
123
  */
102
124
  @Query(() => GetDataContextDataOutputType)
@@ -106,38 +128,114 @@ export class GetDataContextDataResolver extends ResolverBase {
106
128
  ) {
107
129
  // Check API key scope authorization for data context read
108
130
  await this.CheckAPIKeyScopeAuthorization('datacontext:read', DataContextID, appCtx.userPayload);
131
+ // DataContext.LoadMetadata places this ID in the item filter, so it must be a plain UUID.
132
+ if (!IsValidUUID(DataContextID)) {
133
+ return { Success: false, ErrorMessages: ['DataContextID must be a UUID'], Results: null };
134
+ }
109
135
 
110
136
  try {
111
137
  // our job here is to load the entire data context, so we do that with the Data Context object
138
+ const user: UserInfo = appCtx.userPayload.userRecord;
139
+ const md = GetReadOnlyProvider(appCtx.providers, { allowFallbackToReadWrite: true });
112
140
  const dc = new DataContext();
113
- const ds = GetReadOnlyDataSource(appCtx.dataSources, {
114
- allowFallbackToReadWrite: true,
115
- })
116
- const success = await dc.Load(DataContextID, ds, true, false, 0, appCtx.userPayload.userRecord);
117
- if (success) {
118
- const retVal = {
119
- Success: true,
120
- ErrorMessages: null,
121
- Results: dc.Items.map((item) => {
122
- return JSON.stringify(item.Data);
123
- }),
124
- }
125
- return retVal;
126
- }
127
- else {
141
+ if (!(await dc.LoadMetadata(DataContextID, user, md))) {
128
142
  return {
129
143
  Success: false,
130
144
  ErrorMessages: ['Error loading data context'],
131
- Results: null,
145
+ Results: null,
132
146
  }
133
147
  }
148
+ const gate = this.authorizeSQLItems(dc.Items, dc.MJDataContextEntity.UserID, appCtx);
149
+ const outcomes = await Promise.all(dc.Items.map((item) => this.loadItem(item, gate, user, true)));
150
+ const allLoaded = outcomes.every((outcome) => outcome.Error === null);
151
+ return {
152
+ Success: allLoaded,
153
+ ErrorMessages: allLoaded ? null : outcomes.map((outcome) => outcome.Error),
154
+ Results: outcomes.map((outcome) => outcome.Result),
155
+ }
134
156
  }
135
157
  catch (e) {
136
158
  return {
137
159
  Success: false,
138
- ErrorMessages: [e],
160
+ ErrorMessages: [e instanceof Error ? e.message : String(e)],
139
161
  Results: null,
140
162
  }
141
163
  }
142
164
  }
143
- }
165
+
166
+ /**
167
+ * Decides which `sql` items among `items` may run. Returns the read-only provider they run on, and
168
+ * the reason for each SQL item that may not run.
169
+ */
170
+ private authorizeSQLItems(items: DataContextItem[], ownerID: string | null, appCtx: AppContext): SQLItemGate {
171
+ const refusals = new Map<DataContextItem, string>();
172
+ const sqlItems = items.filter((item) => item.Type === 'sql');
173
+ if (sqlItems.length === 0) {
174
+ return { Provider: null, Refusals: refusals };
175
+ }
176
+ const user: UserInfo | undefined = appCtx.userPayload?.userRecord;
177
+ const provider = GetReadOnlyProvider(appCtx.providers, { allowFallbackToReadWrite: false });
178
+ for (const item of sqlItems) {
179
+ const refusal = this.sqlItemRefusal(item, ownerID, user, provider);
180
+ if (refusal !== null) {
181
+ refusals.set(item, refusal);
182
+ }
183
+ }
184
+ return { Provider: provider, Refusals: refusals };
185
+ }
186
+
187
+ /** Returns why `item` may not run for `user`, or null when it may. */
188
+ private sqlItemRefusal(item: DataContextItem, ownerID: string | null, user: UserInfo | undefined, provider: DatabaseProviderBase | null): string | null {
189
+ if (!user || IsScopeLimitedPrincipal(user)) {
190
+ return 'SQL data context items cannot be run by a scope-limited or unidentified session.';
191
+ }
192
+ if (!this.mayRunDataContextSQL(ownerID, user)) {
193
+ return 'Only the owner of this data context, or an administrator, may run its SQL items.';
194
+ }
195
+ if (!provider) {
196
+ return 'No read-only data source is configured, so SQL data context items cannot run.';
197
+ }
198
+ return this.screenItemSQL(item.SQL ?? '', provider, user);
199
+ }
200
+
201
+ /** True when `user` owns the data context or is an administrator (Owner-type user). */
202
+ private mayRunDataContextSQL(ownerID: string | null, user: UserInfo): boolean {
203
+ const isOwner = !!ownerID && UUIDsEqual(ownerID, user.ID);
204
+ return isOwner || user.Type?.trim().toLowerCase() === 'owner';
205
+ }
206
+
207
+ /**
208
+ * Returns why `sqlText` may not run, or null when it is a single read statement whose every table
209
+ * reference is an entity base view `user` may read without row-level or field-level narrowing. It is
210
+ * the check ExecuteAdhocQuery makes on the rendered SQL.
211
+ */
212
+ private screenItemSQL(sqlText: string, provider: DatabaseProviderBase, user: UserInfo): string | null {
213
+ try {
214
+ const rendered = RenderPipeline.Run(sqlText, { Platform: provider.PlatformKey, ContextUser: user, RequireReadStatement: true });
215
+ this.assertFullQueryUsesReadableEntityViews(rendered.Trace.AfterTemplates, provider, user, 'data context SQL');
216
+ return null;
217
+ }
218
+ catch (e) {
219
+ const reason = e instanceof Error ? e.message : String(e);
220
+ return reason || 'The SQL of this item did not pass the read-only check.';
221
+ }
222
+ }
223
+
224
+ /** Loads one item's data unless `gate` refused it. Returns the data as JSON, or why there is none. */
225
+ private async loadItem(item: DataContextItem, gate: SQLItemGate, user: UserInfo, forceRefresh: boolean): Promise<ItemOutcome> {
226
+ const refusal = gate.Refusals.get(item);
227
+ if (refusal !== undefined) {
228
+ return { Result: null, Error: refusal };
229
+ }
230
+ if (await item.LoadData(gate.Provider, forceRefresh, false, 0, user)) {
231
+ return { Result: JSON.stringify(item.Data), Error: null };
232
+ }
233
+ return { Result: null, Error: item.DataLoadingError || 'Error loading data context item data' };
234
+ }
235
+
236
+ /** Returns the owner (`UserID`) of a data context, or null when the caller cannot load it. */
237
+ private async loadDataContextOwnerID(dataContextID: string, provider: DatabaseProviderBase, user: UserInfo): Promise<string | null> {
238
+ const dataContext = await provider.GetEntityObject<MJDataContextEntity>('MJ: Data Contexts', user);
239
+ return (await dataContext.Load(dataContextID)) ? dataContext.UserID : null;
240
+ }
241
+ }
@@ -158,14 +158,17 @@ export class GetDataResolver {
158
158
  // Defense-in-depth: even system-token holders get SELECT-only SQL here.
159
159
  // The read-only pool is the primary control, but if it is ever
160
160
  // misconfigured to a read-write login this validator still refuses DML/DDL
161
- // (mirrors AdhocQueryResolver).
162
- const validation = SQLExpressionValidator.Instance.validateFullQuery(resolvedSQL);
161
+ // (mirrors AdhocQueryResolver). The validator reads exactly the text that
162
+ // runs: it is trimmed here as validate() trims it, and literal \n sequences
163
+ // are not rewritten as ValidateFullQuery would.
164
+ const sqlToRun = resolvedSQL.trim();
165
+ const validation = SQLExpressionValidator.Instance.validate(sqlToRun, { context: 'full_query', Dialect: platform });
163
166
  if (!validation.valid) {
164
167
  return { result: null, error: validation.error || 'SQL validation failed' };
165
168
  }
166
169
 
167
170
  const request = new sql.Request(readOnlyDataSource);
168
- const result = await request.query(resolvedSQL);
171
+ const result = await request.query(sqlToRun);
169
172
  return { result: result.recordset, error: null };
170
173
  } catch (err) {
171
174
  // Extract clean SQL error message
@@ -2,9 +2,11 @@ import { Resolver, Mutation, Query, Subscription, Arg, Ctx, Root, ObjectType, Fi
2
2
  import { IMetadataProvider, LogError, UserInfo } from '@memberjunction/core';
3
3
  import { MJGlobal, UUIDsEqual } from '@memberjunction/global';
4
4
  import { NotificationEngine } from '@memberjunction/notifications';
5
+ import { UserCache } from '@memberjunction/generic-database-provider';
5
6
  import {
6
7
  LiveKitSipService,
7
8
  RoomHandoffEngine,
9
+ HandoffOfferRegistry,
8
10
  type HandoffOfferEvent,
9
11
  type HandoffOfferView,
10
12
  type IHandoffNotifier,
@@ -207,6 +209,12 @@ export class NotificationHandoffNotifier implements IHandoffNotifier {
207
209
  }
208
210
  }
209
211
 
212
+ // The registry's background sweep and list queries run outside any request, so they need a server identity. Resolve the
213
+ // system user lazily: the user cache may not have loaded when this module does.
214
+ HandoffOfferRegistry.Instance.Configure({
215
+ ResolveContextUser: () => UserCache.Instance.GetSystemUser(),
216
+ });
217
+
210
218
  /**
211
219
  * Binds the handoff engine's collaborators that only the server host can supply (same module-load rationale as the other
212
220
  * realtime bindings): the pub/sub publisher, the notification sender, and a room-presence check over the LiveKit credentials
@@ -3,7 +3,7 @@ import { CompositeKey, DatabaseProviderBase, EntityInfo, LocalCacheManager, Meta
3
3
  import { GetReadOnlyProvider, GetReadWriteProvider } from "../util.js";
4
4
  import { NoLog } from "../logging/NoLog.js";
5
5
  import { UUIDsEqual } from "@memberjunction/global";
6
- import { DrainResponseBody } from "@memberjunction/network-utils";
6
+ import { DrainResponseBody, SafeFetch } from "@memberjunction/network-utils";
7
7
  import { CronExpressionHelper } from "@memberjunction/scheduling-engine";
8
8
  import {
9
9
  MJCompanyIntegrationEntity,
@@ -6467,7 +6467,9 @@ export class IntegrationDiscoveryResolver extends ResolverBase {
6467
6467
 
6468
6468
  private async sendWebhook(url: string, payload: Record<string, unknown>): Promise<void> {
6469
6469
  try {
6470
- const response = await fetch(url, {
6470
+ // SECURITY: the webhook URL is caller-supplied, so go through the SSRF guard —
6471
+ // SafeFetch validates the URL (and every redirect hop) resolves to a public address.
6472
+ const response = await SafeFetch(url, {
6471
6473
  method: 'POST',
6472
6474
  headers: { 'Content-Type': 'application/json' },
6473
6475
  body: JSON.stringify(payload)
@@ -639,11 +639,14 @@ export class MCPResolver extends ResolverBase {
639
639
  // Publish syncing progress
640
640
  this.publishProgress(pubSub, sessionId, user.ID, ConnectionID, 'syncing', 'Synchronizing tools to database...');
641
641
 
642
- // Perform the sync
643
- const syncResult: MCPSyncToolsResult = await manager.syncTools(ConnectionID, { contextUser: user });
644
-
645
- // Remove event listener
646
- manager.removeEventListener('toolsSynced', eventHandler);
642
+ // Perform the sync; always detach the listener, even if syncTools throws, so failed
643
+ // syncs don't stack handlers on the shared manager.
644
+ let syncResult: MCPSyncToolsResult;
645
+ try {
646
+ syncResult = await manager.syncTools(ConnectionID, { contextUser: user });
647
+ } finally {
648
+ manager.removeEventListener('toolsSynced', eventHandler);
649
+ }
647
650
 
648
651
  if (!syncResult.success) {
649
652
  this.publishProgress(pubSub, sessionId, user.ID, ConnectionID, 'error', `Sync failed: ${syncResult.error}`);
@@ -101,6 +101,12 @@ export class RunQueryCacheStatusInput {
101
101
 
102
102
  @Field(() => Int, { description: 'The number of rows in cached results' })
103
103
  rowCount: number; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name — renaming it breaks every client query
104
+
105
+ @Field(() => String, {
106
+ nullable: true,
107
+ description: "The query definition hash the cached results were written under, as this server returned it. When it differs from the server's, the result is 'stale' with fresh rows. Empty string for a slot with no hash; omit to skip the definition check."
108
+ })
109
+ definitionHash?: string; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name, matching its siblings
104
110
  }
105
111
 
106
112
  @InputType()
@@ -140,6 +146,9 @@ export class RunQueryWithCacheCheckResultOutput {
140
146
 
141
147
  @Field(() => String, { nullable: true, description: 'Error message if status is error' })
142
148
  errorMessage?: string; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name — renaming it breaks every client query
149
+
150
+ @Field(() => String, { nullable: true, description: "The server's definition hash for the query; store it with the cached results and send it back in cacheStatus.definitionHash" })
151
+ definitionHash?: string; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name, matching its siblings
143
152
  }
144
153
 
145
154
  @ObjectType()
@@ -558,6 +567,7 @@ export class RunQueryResolver extends ResolverBase {
558
567
  cacheStatus: item.cacheStatus ? {
559
568
  maxUpdatedAt: item.cacheStatus.maxUpdatedAt,
560
569
  rowCount: item.cacheStatus.rowCount,
570
+ definitionHash: item.cacheStatus.definitionHash ?? undefined,
561
571
  } : undefined,
562
572
  }));
563
573
 
@@ -572,6 +582,7 @@ export class RunQueryResolver extends ResolverBase {
572
582
  maxUpdatedAt: result.maxUpdatedAt,
573
583
  rowCount: result.rowCount,
574
584
  errorMessage: result.errorMessage,
585
+ definitionHash: result.definitionHash,
575
586
  }));
576
587
 
577
588
  return {
@@ -7,8 +7,13 @@ import {
7
7
  LiveKitTokenService,
8
8
  LiveKitAgentRoomCoordinator,
9
9
  LiveKitEgressService,
10
+ LiveKitParticipantService,
10
11
  LiveKitUserIdentity,
11
12
  RoomHandoffEngine,
13
+ type AgentRoomHostOptions,
14
+ type AgentRoomSession,
15
+ type ParticipantUpdateResult,
16
+ type StartAgentRoomSessionParams,
12
17
  } from '@memberjunction/livekit-room-server';
13
18
  import { AppContext } from '../types.js';
14
19
  import { ResolverBase } from '../generic/ResolverBase.js';
@@ -18,7 +23,8 @@ import { AIBridgeEngine } from '@memberjunction/ai-bridge-server';
18
23
  import { SessionManager } from '../agentSessions/SessionManager.js';
19
24
  import { NotificationEngine } from '@memberjunction/notifications';
20
25
  import { RegisterMeetingRecordingFile, CorrelateRecordingStart } from './meetingRecordingRegistration.js';
21
- import { RoomAuthorizationService } from '@memberjunction/livekit-room-server';
26
+ import { WriteAgentVisionConsentAudit } from './agentVisionConsentAudit.js';
27
+ import { RoomAuthorizationService, type RoomAuthorizationResult } from '@memberjunction/livekit-room-server';
22
28
 
23
29
  /**
24
30
  * Binds the agent realtime-session factory onto the LiveKit room coordinator's model-session creation seam.
@@ -44,6 +50,23 @@ LiveKitAgentRoomCoordinator.Instance.SetTurnToolBinder((session, handler) => {
44
50
  runtime.SetLocalToolHandler(handler);
45
51
  });
46
52
 
53
+ /**
54
+ * Binds whether an agent watches meetings (same module-load rationale as the factory above). The coordinator asks per
55
+ * model session; the answer is the agent's `realtime.video.watchMeetings` setting, which the session runtime read from
56
+ * its effective configuration (`@memberjunction/ai-agents`). The coordinator also requires a model that takes video.
57
+ */
58
+ LiveKitAgentRoomCoordinator.Instance.SetAgentVisionResolver((session) => GetBridgeRealtimeRuntime(session)?.WatchesMeetingVideo === true);
59
+
60
+ /**
61
+ * Binds how a failed agent start is recorded on the agent's co-agent run (same module-load rationale as the factory
62
+ * above). The coordinator closes the model session of a start that fails before the bridge engine takes it; that close
63
+ * alone finalizes the run as Completed, so the coordinator first has the session's runtime finalize it as Failed, with the
64
+ * start's error.
65
+ */
66
+ LiveKitAgentRoomCoordinator.Instance.SetFailedStartRecorder(async (session, error) => {
67
+ await GetBridgeRealtimeRuntime(session)?.Finalize(false, error);
68
+ });
69
+
47
70
  /**
48
71
  * Binds the co-agent run finalizer onto the bridge engine (same module-load rationale as the factory above).
49
72
  * Lets the engine finalize a session's dangling co-agent observability run when it reaps a bridge WITHOUT a
@@ -233,7 +256,30 @@ export class LiveKitRecordingResult {
233
256
  RecordingFileID?: string;
234
257
  }
235
258
 
236
- /** A selectable provider-native voice for the dev voice picker. */
259
+ /** A person's choice of whether agents may see their camera and shared screen in a room. */
260
+ @InputType()
261
+ export class SetLiveKitAgentVisionInput {
262
+ @Field(() => String)
263
+ RoomName: string;
264
+
265
+ /** `true` to let agents see, `false` to stop. */
266
+ @Field(() => Boolean)
267
+ Allow: boolean;
268
+ }
269
+
270
+ @ObjectType()
271
+ export class LiveKitAgentVisionResult {
272
+ @Field(() => Boolean)
273
+ Success: boolean;
274
+
275
+ @Field(() => String, { nullable: true })
276
+ ErrorMessage?: string;
277
+ }
278
+
279
+ /**
280
+ * A selectable provider-native voice for the dev voice picker: one per persona, or one per voice only the driver declares.
281
+ * Two personas can share an `ID` (a voice, and the same voice with a face); `PersonaID` tells them apart.
282
+ */
237
283
  @ObjectType()
238
284
  export class RealtimeVoiceOptionResult {
239
285
  @Field(() => String)
@@ -241,6 +287,22 @@ export class RealtimeVoiceOptionResult {
241
287
 
242
288
  @Field(() => String)
243
289
  Name: string;
290
+
291
+ /** The persona this voice belongs to (`MJ: AI Personas.ID`). Null for a voice only the driver declares. */
292
+ @Field(() => String, { nullable: true })
293
+ PersonaID?: string;
294
+
295
+ /**
296
+ * The avatar that comes with this voice: the `APIName` of its persona's preset Video binding on the model's vendor,
297
+ * which is what `realtime.video.avatarId` takes. Null for a voice without one, and for every voice only the driver
298
+ * declares.
299
+ */
300
+ @Field(() => String, { nullable: true })
301
+ AvatarID?: string;
302
+
303
+ /** The persona's preview image URL, or null when it has none. */
304
+ @Field(() => String, { nullable: true })
305
+ PreviewImageURL?: string;
244
306
  }
245
307
 
246
308
  /** An active Realtime model with the voices its driver supports — feeds the dev model/voice picker. */
@@ -300,7 +362,9 @@ export class RealtimeBridgeResolver extends ResolverBase {
300
362
 
301
363
  /**
302
364
  * Starts (or reuses) an agent's presence in a LiveKit room and returns a client token so the calling
303
- * user can immediately join the same room.
365
+ * user can immediately join the same room. The token is minted before anything starts, so a start that can't give the
366
+ * user one fails with nothing started. When no `AgentSessionID` is passed, an agent session is created for the
367
+ * agent; if the agent then fails to start, that session is closed (`Error`) before the failure is returned.
304
368
  */
305
369
  @Mutation(() => LiveKitAgentRoomSessionResult)
306
370
  async StartLiveKitAgentRoomSession(
@@ -331,18 +395,22 @@ export class RealtimeBridgeResolver extends ResolverBase {
331
395
  }
332
396
  }
333
397
 
398
+ // The user's token first: a start that can't let the user into the room fails before anything starts there. Minted
399
+ // after the agent joined, a failure left the agent in a room the user couldn't enter and gave the UI no bridge id to
400
+ // stop it by.
401
+ const clientToken = await new LiveKitTokenService().MintClientToken(roomName, this.participantIdentity(user), user.Name ?? user.Email);
402
+
334
403
  // Opt-in: an agent that can bring a person, a number or another agent into this room (the same room, so a visitor
335
404
  // is escalated without leaving it). Falls through to the standard start when the server cannot do handoffs.
336
405
  const handoffSessionBridgeID = await this.startWithHandoff(input, roomName, user, provider);
337
406
  if (handoffSessionBridgeID) {
338
- const handoffToken = await new LiveKitTokenService().MintClientToken(roomName, this.participantIdentity(user), user.Name ?? user.Email);
339
407
  return {
340
408
  Success: true,
341
409
  SessionBridgeID: handoffSessionBridgeID,
342
410
  RoomName: roomName,
343
- ServerUrl: handoffToken.ServerUrl,
344
- ClientToken: handoffToken.Token,
345
- Identity: handoffToken.Identity,
411
+ ServerUrl: clientToken.ServerUrl,
412
+ ClientToken: clientToken.Token,
413
+ Identity: clientToken.Identity,
346
414
  };
347
415
  }
348
416
 
@@ -351,6 +419,10 @@ export class RealtimeBridgeResolver extends ResolverBase {
351
419
  // freshly-created one. Previously this minted a bare random UUID with no backing row, so the
352
420
  // bridge INSERT failed the FK_AIAgentSessionBridge_Session constraint.
353
421
  let agentSessionID = input.AgentSessionID?.trim();
422
+ // A session created here exists for this agent's time in the room alone, so it closes when the agent leaves, however
423
+ // it leaves, or at once if the agent fails to start (see startAgentInRoom). A session the caller supplied is the
424
+ // caller's to close.
425
+ let createdSessionID: string | undefined;
354
426
  if (!agentSessionID) {
355
427
  if (!input.AgentID?.trim()) {
356
428
  return failure('An AgentID is required to start an agent room session.', roomName);
@@ -361,9 +433,10 @@ export class RealtimeBridgeResolver extends ResolverBase {
361
433
  provider,
362
434
  );
363
435
  agentSessionID = createdSession.ID;
436
+ createdSessionID = createdSession.ID;
364
437
  }
365
438
 
366
- const session = await LiveKitAgentRoomCoordinator.Instance.StartAgentRoomSession({
439
+ const session = await this.startAgentInRoom(createdSessionID, user, provider, {
367
440
  AgentSessionID: agentSessionID,
368
441
  RoomName: roomName,
369
442
  AgentID: input.AgentID,
@@ -377,9 +450,6 @@ export class RealtimeBridgeResolver extends ResolverBase {
377
450
  MetadataProvider: provider,
378
451
  });
379
452
 
380
- const tokenService = new LiveKitTokenService();
381
- const clientToken = await tokenService.MintClientToken(roomName, this.participantIdentity(user), user.Name ?? user.Email);
382
-
383
453
  return {
384
454
  Success: true,
385
455
  SessionBridgeID: session.SessionBridgeID,
@@ -399,6 +469,7 @@ export class RealtimeBridgeResolver extends ResolverBase {
399
469
  * Stops one agent's presence in a room (the bot leaves) — the remove half of in-room agent management.
400
470
  * Identified by the `SessionBridgeID` returned from {@link StartLiveKitAgentRoomSession}. Returns `true`
401
471
  * when the bridge was stopped. Best-effort: a missing/already-stopped bridge or any error resolves `false`.
472
+ * The agent session the start created for the agent is closed (`Explicit`) before this returns.
402
473
  *
403
474
  * @param sessionBridgeID The `MJ: AI Agent Session Bridges` row id of the agent to remove.
404
475
  */
@@ -433,6 +504,7 @@ export class RealtimeBridgeResolver extends ResolverBase {
433
504
  * coordinator's server-side roster). This is the "End meeting" half of the Zoom-style leave control —
434
505
  * usable by any participant, including one who only *joined* the room and never tracked the bridge ids.
435
506
  * Returns `true` when the teardown ran (even if the room held zero agents). Best-effort: any error → `false`.
507
+ * The agent sessions the starts created for the agents are closed (`Explicit`) as each agent leaves.
436
508
  *
437
509
  * @param roomName The LiveKit room to end.
438
510
  */
@@ -672,6 +744,46 @@ export class RealtimeBridgeResolver extends ResolverBase {
672
744
  }
673
745
  }
674
746
 
747
+ /**
748
+ * Records whether the current user lets agents see their camera and shared screen in a room. The participant is
749
+ * worked out from the authenticated user, never sent by the client, so a person can only answer for themselves. To
750
+ * allow, the room must be one they may enter ({@link RoomAuthorizationService}, as for every room mutation). A
751
+ * withdrawal skips that check: a cancelled meeting or a failed lookup must not keep an agent watching someone who is
752
+ * still in the room, and the identity is always the caller's own. LiveKit refuses either way when they are not in it. The choice is set as their `mj.agentCanSee` attribute through LiveKit's server SDK (a
753
+ * participant's token can't change its own attributes) and audited, applied or not.
754
+ */
755
+ @Mutation(() => LiveKitAgentVisionResult)
756
+ async SetLiveKitAgentVision(
757
+ @Arg('input', () => SetLiveKitAgentVisionInput) input: SetLiveKitAgentVisionInput,
758
+ @Ctx() context: AppContext = {} as AppContext,
759
+ ): Promise<LiveKitAgentVisionResult> {
760
+ try {
761
+ const user = this.GetUserFromPayload(context.userPayload);
762
+ if (!user) {
763
+ return { Success: false, ErrorMessage: 'Unable to determine current user.' };
764
+ }
765
+ const provider = GetReadWriteProvider(context.providers) as unknown as IMetadataProvider;
766
+ const auth: RoomAuthorizationResult = input.Allow
767
+ ? await RoomAuthorizationService.Instance.AuthorizeRoomAccess(input.RoomName, user, provider)
768
+ : { Authorized: true };
769
+ const result: ParticipantUpdateResult = auth.Authorized
770
+ ? await new LiveKitParticipantService().SetAgentVision(input.RoomName, this.participantIdentity(user), input.Allow)
771
+ : { Success: false, ErrorMessage: auth.Reason ?? 'Unauthorized room access.' };
772
+ await WriteAgentVisionConsentAudit(
773
+ { User: user, RoomName: input.RoomName, Allow: input.Allow, Applied: result.Success, ErrorMessage: result.ErrorMessage },
774
+ provider,
775
+ );
776
+ if (result.Success) {
777
+ return { Success: true };
778
+ }
779
+ return { Success: false, ErrorMessage: result.NotInRoom ? 'You are not in this room.' : result.ErrorMessage };
780
+ } catch (error) {
781
+ const msg = error instanceof Error ? error.message : String(error);
782
+ LogError(`SetLiveKitAgentVision failed: ${msg}`);
783
+ return { Success: false, ErrorMessage: msg };
784
+ }
785
+ }
786
+
675
787
  /**
676
788
  * Starts the agent through the handoff-capable room starter when the caller asked for it and the server can do it.
677
789
  * Returns the bridge id, or `undefined` to mean "use the standard start" (not requested, no starter, no agent named).
@@ -704,6 +816,46 @@ export class RealtimeBridgeResolver extends ResolverBase {
704
816
  return started.SessionBridgeID;
705
817
  }
706
818
 
819
+ /**
820
+ * Starts the agent in the room through the coordinator. An agent session created for this agent's time in the room
821
+ * (`createdSessionID`) is this start's to close: once the agent has joined, through the end-of-session hook from
822
+ * {@link closeSessionWhenAgentLeaves}; when the start fails, at once, as `Error`, through
823
+ * {@link SessionManager.CloseSessionForFailedStart}, before the error propagates, since the agent never joined and that
824
+ * hook never runs (#5308). By then the coordinator has closed any model session the start opened, its co-agent run
825
+ * finalized as failed. A session the caller supplied gets neither: it is the caller's.
826
+ */
827
+ private async startAgentInRoom(
828
+ createdSessionID: string | undefined,
829
+ user: UserInfo,
830
+ provider: IMetadataProvider,
831
+ params: Omit<StartAgentRoomSessionParams, 'Host'>,
832
+ ): Promise<AgentRoomSession> {
833
+ const coordinator = LiveKitAgentRoomCoordinator.Instance;
834
+ if (!createdSessionID) {
835
+ return coordinator.StartAgentRoomSession(params);
836
+ }
837
+ try {
838
+ return await coordinator.StartAgentRoomSession({ ...params, Host: this.closeSessionWhenAgentLeaves(createdSessionID, user, provider) });
839
+ } catch (error) {
840
+ await this.sessionManager.CloseSessionForFailedStart(createdSessionID, user, provider);
841
+ throw error;
842
+ }
843
+ }
844
+
845
+ /**
846
+ * What the coordinator is given for an agent session created for one agent's time in a room: its end-of-session hook
847
+ * closes the session once the agent's bridge has ended, whatever ended it (the agent stopped, the meeting ended, everyone
848
+ * left, the model session lost), through {@link SessionManager.CloseSessionForEndedBridge}. The close runs as the user
849
+ * who started the agent, whoever stops it: the session is theirs.
850
+ */
851
+ private closeSessionWhenAgentLeaves(agentSessionID: string, user: UserInfo, provider: IMetadataProvider): AgentRoomHostOptions {
852
+ return {
853
+ OnSessionEnded: async (reason) => {
854
+ await this.sessionManager.CloseSessionForEndedBridge(agentSessionID, reason, user, provider);
855
+ },
856
+ };
857
+ }
858
+
707
859
  /** Builds a stable, lowercased participant identity from the authenticated user (shared with the handoff engine, which watches for it). */
708
860
  private participantIdentity(user: UserInfo): string {
709
861
  return LiveKitUserIdentity(user.ID);