@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
@@ -11,11 +11,13 @@ vi.mock('@memberjunction/ai-engine-base', () => ({
11
11
  // --- Mock the client-direct service so CloseSession's run finalization is observable (no DB),
12
12
  // plus the channel-plugin host so the start/close lifecycle notifications are observable. ---
13
13
  const finalizeCoAgentRunMock = vi.fn(async () => undefined);
14
+ const keepCoAgentRunAliveMock = vi.fn();
14
15
  const hostSessionStartedMock = vi.fn(async () => undefined);
15
16
  const hostSessionClosedMock = vi.fn(async () => undefined);
16
17
  vi.mock('@memberjunction/ai-agents', () => ({
17
18
  RealtimeClientSessionService: class {
18
19
  FinalizeCoAgentRun = finalizeCoAgentRunMock;
20
+ KeepCoAgentRunAlive = keepCoAgentRunAliveMock;
19
21
  },
20
22
  RealtimeChannelServerHost: {
21
23
  get Instance() {
@@ -27,15 +29,28 @@ vi.mock('@memberjunction/ai-agents', () => ({
27
29
  },
28
30
  }));
29
31
 
30
- // --- Mock RunView.FromMetadataProvider so channel sweeps are controllable, while leaving the
31
- // rest of @memberjunction/core intact. ---
32
+ // --- Mock the recording assembly scheduler so a close's assembly request is observable (#5294) ---
33
+ const scheduleAssemblyMock = vi.fn();
34
+ vi.mock('../realtimeSessions/RecordingAssemblyScheduler.js', () => ({
35
+ RecordingAssemblyScheduler: {
36
+ get Instance() {
37
+ return { ScheduleAssembly: scheduleAssemblyMock };
38
+ },
39
+ },
40
+ }));
41
+
42
+ // --- Mock RunView.FromMetadataProvider so channel sweeps and run-id lookups are controllable,
43
+ // while leaving the rest of @memberjunction/core intact. RunViews runs each view through runViewMock. ---
32
44
  const runViewMock = vi.fn();
33
45
  vi.mock('@memberjunction/core', async (importOriginal) => {
34
46
  const actual = await importOriginal<typeof import('@memberjunction/core')>();
35
47
  return {
36
48
  ...actual,
37
49
  RunView: {
38
- FromMetadataProvider: () => ({ RunView: runViewMock }),
50
+ FromMetadataProvider: () => ({
51
+ RunView: runViewMock,
52
+ RunViews: (paramsList: unknown[]) => Promise.all(paramsList.map((params) => runViewMock(params))),
53
+ }),
39
54
  },
40
55
  };
41
56
  });
@@ -100,6 +115,27 @@ function makeSessionEntity(overrides: Partial<FakeEntity> = {}): FakeEntity {
100
115
  };
101
116
  }
102
117
 
118
+ /** Co-agent observability ids as a voice session's Config holds them. */
119
+ const CO_RUN_ID = 'a5a5a5a5-0000-4000-8000-0000000000c0';
120
+ const PROMPT_RUN_ID = 'a5a5a5a5-0000-4000-8000-0000000000b0';
121
+ const RUN_STEP_ID = 'a5a5a5a5-0000-4000-8000-0000000000a0';
122
+
123
+ /**
124
+ * Makes the given runs records of the session for the run-id lookups: `runIDs` carry the session's
125
+ * id, and `promptRunID` (when given) is the TargetLogID of the co-agent run's Prompt step.
126
+ */
127
+ function mockSessionRunRecords(runIDs: string[], promptRunID?: string): void {
128
+ runViewMock.mockImplementation(async (params: { EntityName?: string }) => {
129
+ if (params.EntityName === 'MJ: AI Agent Runs') {
130
+ return { Success: true, Results: runIDs.map((ID) => ({ ID })) };
131
+ }
132
+ if (params.EntityName === 'MJ: AI Agent Run Steps') {
133
+ return { Success: true, Results: promptRunID ? [{ ID: RUN_STEP_ID, StepType: 'Prompt', TargetLogID: promptRunID }] : [] };
134
+ }
135
+ return { Success: true, Results: [] };
136
+ });
137
+ }
138
+
103
139
  beforeEach(() => {
104
140
  hasPermissionMock.mockReset();
105
141
  finalizeCoAgentRunMock.mockClear();
@@ -109,6 +145,7 @@ beforeEach(() => {
109
145
  hostSessionClosedMock.mockResolvedValue(undefined);
110
146
  runViewMock.mockReset();
111
147
  runViewMock.mockResolvedValue({ Success: true, Results: [] });
148
+ scheduleAssemblyMock.mockReset();
112
149
  getSystemUserMock.mockReset();
113
150
  getSystemUserMock.mockReturnValue(undefined);
114
151
  });
@@ -228,8 +265,9 @@ describe('SessionManager.CloseSession', () => {
228
265
  const session = makeSessionEntity({
229
266
  ID: 'session-voice',
230
267
  Status: 'Active',
231
- Config_: JSON.stringify({ targetAgentID: 't1', coAgentRunID: 'co-run-5', promptRunID: 'prompt-run-5' }),
268
+ Config_: JSON.stringify({ targetAgentID: 't1', coAgentRunID: CO_RUN_ID, promptRunID: PROMPT_RUN_ID }),
232
269
  });
270
+ mockSessionRunRecords([CO_RUN_ID], PROMPT_RUN_ID);
233
271
  const { provider } = makeProvider(() => session);
234
272
  const mgr = new SessionManager();
235
273
  const user = makeUser();
@@ -238,7 +276,7 @@ describe('SessionManager.CloseSession', () => {
238
276
 
239
277
  expect(ok).toBe(true);
240
278
  expect(finalizeCoAgentRunMock).toHaveBeenCalledTimes(1);
241
- expect(finalizeCoAgentRunMock).toHaveBeenCalledWith('co-run-5', 'prompt-run-5', user, provider, true, null);
279
+ expect(finalizeCoAgentRunMock).toHaveBeenCalledWith(CO_RUN_ID, PROMPT_RUN_ID, user, provider, true, null);
242
280
  });
243
281
 
244
282
  it('threads the co-agent run-step id into finalize when the session config carries it', async () => {
@@ -247,11 +285,12 @@ describe('SessionManager.CloseSession', () => {
247
285
  Status: 'Active',
248
286
  Config_: JSON.stringify({
249
287
  targetAgentID: 't1',
250
- coAgentRunID: 'co-run-6',
251
- promptRunID: 'prompt-run-6',
252
- coAgentRunStepID: 'run-step-6',
288
+ coAgentRunID: CO_RUN_ID,
289
+ promptRunID: PROMPT_RUN_ID,
290
+ coAgentRunStepID: RUN_STEP_ID,
253
291
  }),
254
292
  });
293
+ mockSessionRunRecords([CO_RUN_ID], PROMPT_RUN_ID);
255
294
  const { provider } = makeProvider(() => session);
256
295
  const mgr = new SessionManager();
257
296
  const user = makeUser();
@@ -259,7 +298,7 @@ describe('SessionManager.CloseSession', () => {
259
298
  const ok = await mgr.CloseSession('session-voice-step', user, provider);
260
299
 
261
300
  expect(ok).toBe(true);
262
- expect(finalizeCoAgentRunMock).toHaveBeenCalledWith('co-run-6', 'prompt-run-6', user, provider, true, 'run-step-6');
301
+ expect(finalizeCoAgentRunMock).toHaveBeenCalledWith(CO_RUN_ID, PROMPT_RUN_ID, user, provider, true, RUN_STEP_ID);
263
302
  });
264
303
 
265
304
  it('finalizes as the SYSTEM user when a scoped anonymous owner closes their session (issue #3371)', async () => {
@@ -274,8 +313,9 @@ describe('SessionManager.CloseSession', () => {
274
313
  const session = makeSessionEntity({
275
314
  ID: 'session-anon',
276
315
  Status: 'Active',
277
- Config_: JSON.stringify({ targetAgentID: 't1', coAgentRunID: 'co-run-9', promptRunID: 'prompt-run-9' }),
316
+ Config_: JSON.stringify({ targetAgentID: 't1', coAgentRunID: CO_RUN_ID, promptRunID: PROMPT_RUN_ID }),
278
317
  });
318
+ mockSessionRunRecords([CO_RUN_ID], PROMPT_RUN_ID);
279
319
  const { provider } = makeProvider(() => session);
280
320
  const mgr = new SessionManager();
281
321
 
@@ -284,7 +324,7 @@ describe('SessionManager.CloseSession', () => {
284
324
  expect(ok).toBe(true);
285
325
  // The session-close writes themselves stay on the caller — only finalize elevates.
286
326
  expect(session.Status).toBe('Closed');
287
- expect(finalizeCoAgentRunMock).toHaveBeenCalledWith('co-run-9', 'prompt-run-9', systemUser, provider, true, null);
327
+ expect(finalizeCoAgentRunMock).toHaveBeenCalledWith(CO_RUN_ID, PROMPT_RUN_ID, systemUser, provider, true, null);
288
328
  });
289
329
 
290
330
  it('FAILS CLOSED — finalizes as the anonymous caller when no system user is available', async () => {
@@ -297,14 +337,15 @@ describe('SessionManager.CloseSession', () => {
297
337
  const session = makeSessionEntity({
298
338
  ID: 'session-anon-2',
299
339
  Status: 'Active',
300
- Config_: JSON.stringify({ targetAgentID: 't1', coAgentRunID: 'co-run-10', promptRunID: null }),
340
+ Config_: JSON.stringify({ targetAgentID: 't1', coAgentRunID: CO_RUN_ID, promptRunID: null }),
301
341
  });
342
+ mockSessionRunRecords([CO_RUN_ID]);
302
343
  const { provider } = makeProvider(() => session);
303
344
  const mgr = new SessionManager();
304
345
 
305
346
  await mgr.CloseSession('session-anon-2', anonUser, provider);
306
347
 
307
- expect(finalizeCoAgentRunMock).toHaveBeenCalledWith('co-run-10', null, anonUser, provider, true, null);
348
+ expect(finalizeCoAgentRunMock).toHaveBeenCalledWith(CO_RUN_ID, null, anonUser, provider, true, null);
308
349
  });
309
350
 
310
351
  it('does not finalize when the session config has no run ids (target only)', async () => {
@@ -334,8 +375,9 @@ describe('SessionManager.CloseSession', () => {
334
375
  const session = makeSessionEntity({
335
376
  ID: 'session-injected',
336
377
  Status: 'Active',
337
- Config_: JSON.stringify({ targetAgentID: 't1', coAgentRunID: 'co-run-injected', promptRunID: 'prompt-run-injected' }),
378
+ Config_: JSON.stringify({ targetAgentID: 't1', coAgentRunID: CO_RUN_ID, promptRunID: PROMPT_RUN_ID }),
338
379
  });
380
+ mockSessionRunRecords([CO_RUN_ID], PROMPT_RUN_ID);
339
381
  const { provider } = makeProvider(() => session);
340
382
  const mgr = new SessionManager(injectedService);
341
383
  const user = makeUser();
@@ -345,7 +387,7 @@ describe('SessionManager.CloseSession', () => {
345
387
  expect(ok).toBe(true);
346
388
  // The finalize call landed on the INJECTED instance, never the module-default one.
347
389
  expect(injectedFinalizeMock).toHaveBeenCalledTimes(1);
348
- expect(injectedFinalizeMock).toHaveBeenCalledWith('co-run-injected', 'prompt-run-injected', user, provider, true, null);
390
+ expect(injectedFinalizeMock).toHaveBeenCalledWith(CO_RUN_ID, PROMPT_RUN_ID, user, provider, true, null);
349
391
  expect(finalizeCoAgentRunMock).not.toHaveBeenCalled();
350
392
  });
351
393
 
@@ -353,8 +395,9 @@ describe('SessionManager.CloseSession', () => {
353
395
  const session = makeSessionEntity({
354
396
  ID: 'session-default-svc',
355
397
  Status: 'Active',
356
- Config_: JSON.stringify({ targetAgentID: 't1', coAgentRunID: 'co-run-default', promptRunID: 'prompt-run-default' }),
398
+ Config_: JSON.stringify({ targetAgentID: 't1', coAgentRunID: CO_RUN_ID, promptRunID: PROMPT_RUN_ID }),
357
399
  });
400
+ mockSessionRunRecords([CO_RUN_ID], PROMPT_RUN_ID);
358
401
  const { provider } = makeProvider(() => session);
359
402
  const mgr = new SessionManager(); // no injection — e.g. SessionJanitor, telephony services
360
403
  const user = makeUser();
@@ -362,7 +405,7 @@ describe('SessionManager.CloseSession', () => {
362
405
  const ok = await mgr.CloseSession('session-default-svc', user, provider);
363
406
 
364
407
  expect(ok).toBe(true);
365
- expect(finalizeCoAgentRunMock).toHaveBeenCalledWith('co-run-default', 'prompt-run-default', user, provider, true, null);
408
+ expect(finalizeCoAgentRunMock).toHaveBeenCalledWith(CO_RUN_ID, PROMPT_RUN_ID, user, provider, true, null);
366
409
  });
367
410
 
368
411
  it('stamps CloseReason = Explicit by default (untouched call sites get the right reason)', async () => {
@@ -425,6 +468,79 @@ describe('SessionManager.CloseSession', () => {
425
468
  });
426
469
  });
427
470
 
471
+ describe('SessionManager.CloseSessionForEndedBridge (a bridged agent left its room)', () => {
472
+ it.each([
473
+ ['Explicit', 'Explicit'],
474
+ ['HostEnded', 'Explicit'],
475
+ ['Error', 'Error'],
476
+ ['Janitor', 'Janitor'],
477
+ ['Shutdown', 'Shutdown'],
478
+ ] as const)('closes the session when its bridge ended with %s, stamping %s', async (bridgeReason, sessionReason) => {
479
+ const session = makeSessionEntity({ ID: 'session-bridged', Status: 'Active' });
480
+ const { provider } = makeProvider(() => session);
481
+ const mgr = new SessionManager();
482
+
483
+ const ok = await mgr.CloseSessionForEndedBridge('session-bridged', bridgeReason, makeUser(), provider);
484
+
485
+ expect(ok).toBe(true);
486
+ expect(session.Status).toBe('Closed');
487
+ expect(session.ClosedAt).toBeInstanceOf(Date);
488
+ expect(session.CloseReason).toBe(sessionReason);
489
+ // The same close the janitor runs: the channel plugins hear about it too.
490
+ expect(hostSessionClosedMock).toHaveBeenCalledWith('session-bridged', sessionReason);
491
+ });
492
+
493
+ it('keeps the reason of a session something else closed first (the janitor, the user)', async () => {
494
+ const session = makeSessionEntity({ ID: 'session-bridged', Status: 'Closed', CloseReason: 'Janitor' });
495
+ const { provider } = makeProvider(() => session);
496
+ const mgr = new SessionManager();
497
+
498
+ const ok = await mgr.CloseSessionForEndedBridge('session-bridged', 'Explicit', makeUser(), provider);
499
+
500
+ expect(ok).toBe(true);
501
+ expect(session.CloseReason).toBe('Janitor');
502
+ expect(session.Save).not.toHaveBeenCalled();
503
+ });
504
+
505
+ it('never throws: a close that fails is reported as not closed, leaving the session to the janitor', async () => {
506
+ const provider = {
507
+ GetEntityObject: vi.fn(async () => {
508
+ throw new Error('database unreachable');
509
+ }),
510
+ } as unknown as IMetadataProvider;
511
+ const mgr = new SessionManager();
512
+
513
+ await expect(mgr.CloseSessionForEndedBridge('session-bridged', 'Explicit', makeUser(), provider)).resolves.toBe(false);
514
+ });
515
+ });
516
+
517
+ describe('SessionManager.CloseSessionForFailedStart (an agent that never joined its room)', () => {
518
+ it('closes the session as Error, through the close the janitor runs', async () => {
519
+ const session = makeSessionEntity({ ID: 'session-unstarted', Status: 'Active' });
520
+ const { provider } = makeProvider(() => session);
521
+ const mgr = new SessionManager();
522
+
523
+ const ok = await mgr.CloseSessionForFailedStart('session-unstarted', makeUser(), provider);
524
+
525
+ expect(ok).toBe(true);
526
+ expect(session.Status).toBe('Closed');
527
+ expect(session.ClosedAt).toBeInstanceOf(Date);
528
+ expect(session.CloseReason).toBe('Error');
529
+ expect(hostSessionClosedMock).toHaveBeenCalledWith('session-unstarted', 'Error');
530
+ });
531
+
532
+ it('never throws: a close that fails is reported as not closed, leaving the session to the janitor', async () => {
533
+ const provider = {
534
+ GetEntityObject: vi.fn(async () => {
535
+ throw new Error('database unreachable');
536
+ }),
537
+ } as unknown as IMetadataProvider;
538
+ const mgr = new SessionManager();
539
+
540
+ await expect(mgr.CloseSessionForFailedStart('session-unstarted', makeUser(), provider)).resolves.toBe(false);
541
+ });
542
+ });
543
+
428
544
  describe('SessionManager.Heartbeat', () => {
429
545
  it('coalesces writes within the min interval (one write, not two)', async () => {
430
546
  const session = makeSessionEntity({ ID: 'session-1', Status: 'Active' });
@@ -461,6 +577,52 @@ describe('SessionManager.Heartbeat', () => {
461
577
  });
462
578
  });
463
579
 
580
+ describe('SessionManager.CloseSession — recording assembly (#5294)', () => {
581
+ it('CloseSession of a recorded session asks for its assembly now (the hidden-tab deferral ends with the call)', async () => {
582
+ const session = makeSessionEntity({ ID: 'session-1', Status: 'Active', RecordingStartedAt: new Date(0) });
583
+ const { provider } = makeProvider(() => session);
584
+ await new SessionManager().CloseSession('session-1', makeUser(), provider);
585
+ expect(scheduleAssemblyMock).toHaveBeenCalledWith('session-1', 0, false);
586
+ });
587
+
588
+ it('CloseSession of a session that was not recorded asks for no assembly', async () => {
589
+ const session = makeSessionEntity({ ID: 'session-1', Status: 'Active', RecordingStartedAt: null });
590
+ const { provider } = makeProvider(() => session);
591
+ await new SessionManager().CloseSession('session-1', makeUser(), provider);
592
+ expect(scheduleAssemblyMock).not.toHaveBeenCalled();
593
+ });
594
+ });
595
+
596
+ describe('SessionManager.Heartbeat — the session\'s co-agent run stays alive', () => {
597
+ beforeEach(() => {
598
+ keepCoAgentRunAliveMock.mockClear();
599
+ });
600
+
601
+ it('keeps the co-agent run alive for the run watchdog on each persisted heartbeat', async () => {
602
+ const session = makeSessionEntity({ ID: 'session-1', Status: 'Active', Config_: JSON.stringify({ coAgentRunID: CO_RUN_ID, promptRunID: PROMPT_RUN_ID }) });
603
+ mockSessionRunRecords([CO_RUN_ID], PROMPT_RUN_ID);
604
+ const { provider } = makeProvider(() => session);
605
+ const mgr = new SessionManager();
606
+
607
+ await mgr.Heartbeat('session-1', makeUser(), provider);
608
+ await mgr.Heartbeat('session-1', makeUser(), provider); // coalesced: no write, no re-registration
609
+
610
+ expect(keepCoAgentRunAliveMock).toHaveBeenCalledOnce();
611
+ expect(keepCoAgentRunAliveMock.mock.calls[0][0]).toBe(CO_RUN_ID);
612
+ expect(keepCoAgentRunAliveMock.mock.calls[0][1]).toBe(provider);
613
+ });
614
+
615
+ it('does nothing for a closed session, and passes no run for a session without one', async () => {
616
+ const closed = makeSessionEntity({ ID: 'session-closed', Status: 'Closed', Config_: JSON.stringify({ coAgentRunID: 'co-run-1' }) });
617
+ await new SessionManager().Heartbeat('session-closed', makeUser(), makeProvider(() => closed).provider);
618
+ expect(keepCoAgentRunAliveMock).not.toHaveBeenCalled();
619
+
620
+ const workspace = makeSessionEntity({ ID: 'session-2', Status: 'Active', Config_: null });
621
+ await new SessionManager().Heartbeat('session-2', makeUser(), makeProvider(() => workspace).provider);
622
+ expect(keepCoAgentRunAliveMock.mock.calls[0][0]).toBeUndefined();
623
+ });
624
+ });
625
+
464
626
  describe('SessionManager.Heartbeat — bounded heartbeatLastWrite (Round 11 memory-leak fix)', () => {
465
627
  // Regression coverage: heartbeatLastWrite used to be a plain, unbounded `Map`. SessionManager
466
628
  // is constructed fresh by every resolver that needs one (AgentSessionResolver,
@@ -626,3 +788,64 @@ describe('SessionManager — server-side channel plugin lifecycle notifications'
626
788
  expect(session.Status).toBe('Closed');
627
789
  });
628
790
  });
791
+
792
+ // A session's Config is writable by its owner (generic CRUD on MJ: AI Agent Sessions), so the run
793
+ // ids in it are acted on only when they are UUIDs of records that belong to the session.
794
+ describe('SessionManager — run ids in the owner-writable session Config', () => {
795
+ const SESSION_ID = 'c3c3c3c3-1000-4000-8000-000000000001';
796
+ const FOREIGN_RUN_ID = 'c3c3c3c3-1000-4000-8000-0000000000f1';
797
+ const FOREIGN_PROMPT_RUN_ID = 'c3c3c3c3-1000-4000-8000-0000000000f2';
798
+ const FOREIGN_STEP_ID = 'c3c3c3c3-1000-4000-8000-0000000000f3';
799
+ /** Harmless text that is not a UUID and would change the meaning of a quoted filter. */
800
+ const NOT_A_UUID = "x' OR '1'='1";
801
+
802
+ function issuedFilters(): string[] {
803
+ return runViewMock.mock.calls.map(([params]) => (params as { ExtraFilter?: string }).ExtraFilter ?? '');
804
+ }
805
+
806
+ beforeEach(() => {
807
+ keepCoAgentRunAliveMock.mockClear();
808
+ });
809
+
810
+ it('CloseSession does not finalize run ids that are not records of the session', async () => {
811
+ const session = makeSessionEntity({
812
+ ID: SESSION_ID,
813
+ Status: 'Active',
814
+ Config_: JSON.stringify({
815
+ targetAgentID: 't1',
816
+ coAgentRunID: FOREIGN_RUN_ID,
817
+ promptRunID: FOREIGN_PROMPT_RUN_ID,
818
+ coAgentRunStepID: FOREIGN_STEP_ID,
819
+ }),
820
+ });
821
+ const { provider } = makeProvider(() => session);
822
+
823
+ await new SessionManager().CloseSession(SESSION_ID, makeUser(), provider);
824
+
825
+ expect(finalizeCoAgentRunMock).not.toHaveBeenCalled();
826
+ });
827
+
828
+ it('CloseSession does not finalize run ids that are not UUIDs, and never puts them in a filter', async () => {
829
+ const session = makeSessionEntity({
830
+ ID: SESSION_ID,
831
+ Status: 'Active',
832
+ Config_: JSON.stringify({ targetAgentID: 't1', coAgentRunID: NOT_A_UUID, promptRunID: NOT_A_UUID }),
833
+ });
834
+ const { provider } = makeProvider(() => session);
835
+
836
+ await new SessionManager().CloseSession(SESSION_ID, makeUser(), provider);
837
+
838
+ expect(finalizeCoAgentRunMock).not.toHaveBeenCalled();
839
+ expect(issuedFilters().filter((f) => f.includes(NOT_A_UUID))).toEqual([]);
840
+ });
841
+
842
+ it('Heartbeat does not keep alive a run that is not a record of the session', async () => {
843
+ const session = makeSessionEntity({ ID: SESSION_ID, Status: 'Active', Config_: JSON.stringify({ coAgentRunID: FOREIGN_RUN_ID }) });
844
+ const { provider } = makeProvider(() => session);
845
+
846
+ await new SessionManager().Heartbeat(SESSION_ID, makeUser(), provider);
847
+
848
+ expect(keepCoAgentRunAliveMock).toHaveBeenCalledOnce();
849
+ expect(keepCoAgentRunAliveMock.mock.calls[0][0]).toBeUndefined();
850
+ });
851
+ });
@@ -0,0 +1,251 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2
+ import type { IMetadataProvider, RunViewParams, UserInfo } from '@memberjunction/core';
3
+ import { UserCache } from '@memberjunction/generic-database-provider';
4
+ import { SessionRunIDVerifier } from '../agentSessions/SessionRunIDVerifier.js';
5
+
6
+ const SESSION_ID = 'd3d3d3d3-0000-4000-8000-000000000001';
7
+ const CO_RUN_ID = 'd3d3d3d3-0000-4000-8000-000000000002';
8
+ const PROMPT_RUN_ID = 'd3d3d3d3-0000-4000-8000-000000000003';
9
+ const STEP_ID = 'd3d3d3d3-0000-4000-8000-000000000004';
10
+ const PAUSED_RUN_ID = 'd3d3d3d3-0000-4000-8000-000000000005';
11
+ const USER = { ID: 'd3d3d3d3-0000-4000-8000-0000000000aa' } as unknown as UserInfo;
12
+
13
+ /** Rows each lookup returns, keyed by entity name. */
14
+ type Rows = Record<string, Array<Record<string, unknown>>>;
15
+
16
+ function makeProvider(rows: Rows, success = true): { provider: IMetadataProvider; runViews: ReturnType<typeof vi.fn> } {
17
+ const runViews = vi.fn(async (paramsList: RunViewParams[]) =>
18
+ paramsList.map((params) => ({
19
+ Success: success,
20
+ Results: success ? rows[params.EntityName ?? ''] ?? [] : [],
21
+ ErrorMessage: success ? '' : 'lookup failed',
22
+ })),
23
+ );
24
+ return { provider: { RunViews: runViews } as unknown as IMetadataProvider, runViews };
25
+ }
26
+
27
+ function issuedViews(runViews: ReturnType<typeof vi.fn>): RunViewParams[] {
28
+ return runViews.mock.calls.flatMap(([paramsList]) => paramsList as RunViewParams[]);
29
+ }
30
+
31
+ beforeEach(() => {
32
+ vi.spyOn(console, 'error').mockImplementation(() => undefined);
33
+ });
34
+
35
+ afterEach(() => {
36
+ UserCache.Instance.SetUsers([]);
37
+ });
38
+
39
+ describe('SessionRunIDVerifier.Verify', () => {
40
+ it('keeps nothing, and runs no lookup, when no claim is a UUID', async () => {
41
+ const { provider, runViews } = makeProvider({});
42
+
43
+ const result = await new SessionRunIDVerifier().Verify(
44
+ SESSION_ID,
45
+ { CoAgentRunID: "x' OR '1'='1", PromptRunID: 'prompt-run-1', PendingFeedbackRunID: '' },
46
+ USER,
47
+ provider,
48
+ );
49
+
50
+ expect(result).toEqual({});
51
+ expect(runViews).not.toHaveBeenCalled();
52
+ });
53
+
54
+ it('looks up the claimed runs within the session and keeps only the ones it finds', async () => {
55
+ const { provider, runViews } = makeProvider({ 'MJ: AI Agent Runs': [{ ID: CO_RUN_ID }] });
56
+
57
+ const result = await new SessionRunIDVerifier().Verify(
58
+ SESSION_ID,
59
+ { CoAgentRunID: CO_RUN_ID, PendingFeedbackRunID: PAUSED_RUN_ID },
60
+ USER,
61
+ provider,
62
+ );
63
+
64
+ expect(result.CoAgentRunID).toBe(CO_RUN_ID);
65
+ expect(result.PendingFeedbackRunID).toBeUndefined();
66
+ const [runsView] = issuedViews(runViews);
67
+ expect(runsView.EntityName).toBe('MJ: AI Agent Runs');
68
+ expect(runsView.ExtraFilter).toBe(`AgentSessionID='${SESSION_ID}' AND ID IN ('${CO_RUN_ID}', '${PAUSED_RUN_ID}')`);
69
+ // No system user is cached here, so the lookup runs as the acting user.
70
+ expect(runViews.mock.calls[0][1]).toBe(USER);
71
+ });
72
+
73
+ it('runs the lookup as the system user when one is available', async () => {
74
+ // Row-level security can hide a session's own runs from its owner: a web-widget guest's
75
+ // delegated runs carry no ConversationID, so the guest's run filter does not match them.
76
+ const systemUser = { ID: UserCache.Instance.SYSTEM_USER_ID, Email: 'system@example.com' } as unknown as UserInfo;
77
+ UserCache.Instance.SetUsers([systemUser]);
78
+ const { provider, runViews } = makeProvider({ 'MJ: AI Agent Runs': [{ ID: PAUSED_RUN_ID }] });
79
+
80
+ const result = await new SessionRunIDVerifier().Verify(SESSION_ID, { PendingFeedbackRunID: PAUSED_RUN_ID }, USER, provider);
81
+
82
+ expect(result.PendingFeedbackRunID).toBe(PAUSED_RUN_ID);
83
+ expect(runViews.mock.calls[0][1]).toBe(systemUser);
84
+ });
85
+
86
+ it('keeps the prompt run and step that belong to the session\'s co-agent run', async () => {
87
+ const { provider, runViews } = makeProvider({
88
+ 'MJ: AI Agent Runs': [{ ID: CO_RUN_ID }],
89
+ 'MJ: AI Agent Run Steps': [{ ID: STEP_ID, StepType: 'Prompt', TargetLogID: PROMPT_RUN_ID }],
90
+ });
91
+
92
+ const result = await new SessionRunIDVerifier().Verify(
93
+ SESSION_ID,
94
+ { CoAgentRunID: CO_RUN_ID, PromptRunID: PROMPT_RUN_ID, CoAgentRunStepID: STEP_ID },
95
+ USER,
96
+ provider,
97
+ );
98
+
99
+ expect(result).toEqual({ CoAgentRunID: CO_RUN_ID, PromptRunID: PROMPT_RUN_ID, CoAgentRunStepID: STEP_ID, PendingFeedbackRunID: undefined });
100
+ const stepsView = issuedViews(runViews).find((view) => view.EntityName === 'MJ: AI Agent Run Steps');
101
+ expect(stepsView?.ExtraFilter).toBe(`AgentRunID='${CO_RUN_ID}' AND (ID='${STEP_ID}' OR TargetLogID='${PROMPT_RUN_ID}')`);
102
+ });
103
+
104
+ it('drops a prompt run that is the target of a step other than a Prompt step', async () => {
105
+ const { provider } = makeProvider({
106
+ 'MJ: AI Agent Runs': [{ ID: CO_RUN_ID }],
107
+ 'MJ: AI Agent Run Steps': [{ ID: STEP_ID, StepType: 'Tool', TargetLogID: PROMPT_RUN_ID }],
108
+ });
109
+
110
+ const result = await new SessionRunIDVerifier().Verify(SESSION_ID, { CoAgentRunID: CO_RUN_ID, PromptRunID: PROMPT_RUN_ID }, USER, provider);
111
+
112
+ expect(result.PromptRunID).toBeUndefined();
113
+ });
114
+
115
+ it('drops the prompt run and step when the co-agent run is not the session\'s', async () => {
116
+ const { provider } = makeProvider({
117
+ 'MJ: AI Agent Runs': [],
118
+ 'MJ: AI Agent Run Steps': [{ ID: STEP_ID, StepType: 'Prompt', TargetLogID: PROMPT_RUN_ID }],
119
+ });
120
+
121
+ const result = await new SessionRunIDVerifier().Verify(
122
+ SESSION_ID,
123
+ { CoAgentRunID: CO_RUN_ID, PromptRunID: PROMPT_RUN_ID, CoAgentRunStepID: STEP_ID },
124
+ USER,
125
+ provider,
126
+ );
127
+
128
+ expect(result).toEqual({ CoAgentRunID: undefined, PromptRunID: undefined, CoAgentRunStepID: undefined, PendingFeedbackRunID: undefined });
129
+ });
130
+
131
+ it('matches ids case-insensitively', async () => {
132
+ const { provider } = makeProvider({ 'MJ: AI Agent Runs': [{ ID: PAUSED_RUN_ID.toUpperCase() }] });
133
+
134
+ const result = await new SessionRunIDVerifier().Verify(SESSION_ID, { PendingFeedbackRunID: PAUSED_RUN_ID }, USER, provider);
135
+
136
+ expect(result.PendingFeedbackRunID).toBe(PAUSED_RUN_ID);
137
+ });
138
+
139
+ it('looks up the same claims again on every call', async () => {
140
+ const { provider, runViews } = makeProvider({ 'MJ: AI Agent Runs': [{ ID: CO_RUN_ID }] });
141
+ const verifier = new SessionRunIDVerifier();
142
+
143
+ await verifier.Verify(SESSION_ID, { CoAgentRunID: CO_RUN_ID }, USER, provider);
144
+ const second = await verifier.Verify(SESSION_ID, { CoAgentRunID: CO_RUN_ID }, USER, provider);
145
+
146
+ expect(second.CoAgentRunID).toBe(CO_RUN_ID);
147
+ expect(runViews).toHaveBeenCalledTimes(2);
148
+ });
149
+
150
+ it('reads the runs and steps from the database, not from a cached view', async () => {
151
+ const { provider, runViews } = makeProvider({ 'MJ: AI Agent Runs': [{ ID: CO_RUN_ID }] });
152
+
153
+ await new SessionRunIDVerifier().Verify(SESSION_ID, { CoAgentRunID: CO_RUN_ID, PromptRunID: PROMPT_RUN_ID }, USER, provider);
154
+
155
+ const views = issuedViews(runViews);
156
+ expect(views.map((view) => view.EntityName)).toEqual(['MJ: AI Agent Runs', 'MJ: AI Agent Run Steps']);
157
+ expect(views.every((view) => view.BypassCache === true)).toBe(true);
158
+ });
159
+
160
+ it('keeps nothing when a lookup fails, and looks up again next time', async () => {
161
+ const { provider, runViews } = makeProvider({}, false);
162
+ const verifier = new SessionRunIDVerifier();
163
+
164
+ const first = await verifier.Verify(SESSION_ID, { CoAgentRunID: CO_RUN_ID }, USER, provider);
165
+ await verifier.Verify(SESSION_ID, { CoAgentRunID: CO_RUN_ID }, USER, provider);
166
+
167
+ expect(first).toEqual({});
168
+ expect(runViews).toHaveBeenCalledTimes(2);
169
+ });
170
+
171
+ it('keeps nothing, without throwing, when the provider throws', async () => {
172
+ const provider = { RunViews: vi.fn(async () => { throw new Error('connection lost'); }) } as unknown as IMetadataProvider;
173
+
174
+ await expect(new SessionRunIDVerifier().Verify(SESSION_ID, { CoAgentRunID: CO_RUN_ID }, USER, provider)).resolves.toEqual({});
175
+ });
176
+ });
177
+
178
+ /**
179
+ * A run's `AgentSessionID` and a step's `AgentRunID` and `TargetLogID` can change after a lookup (the
180
+ * generated update mutations accept them), so each call must decide from what the rows say now.
181
+ */
182
+ describe('SessionRunIDVerifier.Verify — relationships that change between calls', () => {
183
+ const CLAIMS = { CoAgentRunID: CO_RUN_ID, PromptRunID: PROMPT_RUN_ID, CoAgentRunStepID: STEP_ID, PendingFeedbackRunID: PAUSED_RUN_ID };
184
+
185
+ /** Both runs are records of the session, and the step is the co-agent run's Prompt step for the prompt run. */
186
+ function linkedRows(): Rows {
187
+ return {
188
+ 'MJ: AI Agent Runs': [{ ID: CO_RUN_ID }, { ID: PAUSED_RUN_ID }],
189
+ 'MJ: AI Agent Run Steps': [{ ID: STEP_ID, StepType: 'Prompt', TargetLogID: PROMPT_RUN_ID }],
190
+ };
191
+ }
192
+
193
+ it('drops runs that stopped being records of the session since the last call', async () => {
194
+ const rows = linkedRows();
195
+ const { provider } = makeProvider(rows);
196
+ const verifier = new SessionRunIDVerifier();
197
+ const first = await verifier.Verify(SESSION_ID, CLAIMS, USER, provider);
198
+
199
+ // The runs were moved to another session, unlinked or deleted.
200
+ rows['MJ: AI Agent Runs'] = [];
201
+ const second = await verifier.Verify(SESSION_ID, CLAIMS, USER, provider);
202
+
203
+ expect(first).toEqual(CLAIMS);
204
+ expect(second).toEqual({ CoAgentRunID: undefined, PromptRunID: undefined, CoAgentRunStepID: undefined, PendingFeedbackRunID: undefined });
205
+ });
206
+
207
+ it('drops the prompt run and step once the step is no longer linked to the co-agent run', async () => {
208
+ const rows = linkedRows();
209
+ const { provider } = makeProvider(rows);
210
+ const verifier = new SessionRunIDVerifier();
211
+ const first = await verifier.Verify(SESSION_ID, CLAIMS, USER, provider);
212
+
213
+ rows['MJ: AI Agent Run Steps'] = [];
214
+ const second = await verifier.Verify(SESSION_ID, CLAIMS, USER, provider);
215
+
216
+ expect(first).toEqual(CLAIMS);
217
+ expect(second).toEqual({ ...CLAIMS, PromptRunID: undefined, CoAgentRunStepID: undefined });
218
+ });
219
+
220
+ it('still keeps a relationship that has not changed on the next call', async () => {
221
+ const { provider } = makeProvider(linkedRows());
222
+ const verifier = new SessionRunIDVerifier();
223
+
224
+ await verifier.Verify(SESSION_ID, CLAIMS, USER, provider);
225
+ const second = await verifier.Verify(SESSION_ID, CLAIMS, USER, provider);
226
+
227
+ expect(second).toEqual(CLAIMS);
228
+ });
229
+ });
230
+
231
+ describe('SessionRunIDVerifier.Verify — lookups as the acting user', () => {
232
+ it('does not give a user the result of a lookup made for another user', async () => {
233
+ // No system user is cached, so each lookup runs as the acting user, and only USER can see the run.
234
+ const otherUser = { ID: 'd3d3d3d3-0000-4000-8000-0000000000bb' } as unknown as UserInfo;
235
+ const runViews = vi.fn(async (paramsList: RunViewParams[], user: UserInfo) =>
236
+ paramsList.map((params) => {
237
+ const visible = user === USER && params.EntityName === 'MJ: AI Agent Runs';
238
+ return { Success: true, Results: visible ? [{ ID: CO_RUN_ID }] : [], ErrorMessage: '' };
239
+ }),
240
+ );
241
+ const provider = { RunViews: runViews } as unknown as IMetadataProvider;
242
+ const verifier = new SessionRunIDVerifier();
243
+
244
+ const forUser = await verifier.Verify(SESSION_ID, { CoAgentRunID: CO_RUN_ID }, USER, provider);
245
+ const forOtherUser = await verifier.Verify(SESSION_ID, { CoAgentRunID: CO_RUN_ID }, otherUser, provider);
246
+
247
+ expect(forUser.CoAgentRunID).toBe(CO_RUN_ID);
248
+ expect(forOtherUser.CoAgentRunID).toBeUndefined();
249
+ expect(runViews.mock.calls[1]?.[1]).toBe(otherUser);
250
+ });
251
+ });