@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
@@ -0,0 +1,133 @@
1
+ /**
2
+ * @fileoverview GraphQL subscription that delivers **realtime session events** to the session they are
3
+ * addressed to — `subscription RealtimeSessionEvents(agentSessionId: String!)`.
4
+ *
5
+ * The event contract lives in `@memberjunction/ai-core-plus` (`realtime-session-events.ts`); the publisher
6
+ * apps call is `RealtimeSessionEventService`. This resolver is the delivery edge, and its whole job is
7
+ * authorization, done twice on purpose:
8
+ *
9
+ * 1. **At subscribe time** ({@link AuthorizeRealtimeSessionSubscription}). The session row is loaded and
10
+ * {@link AuthorizeSessionAccess} must allow the connection's authenticated principal: the session's
11
+ * `UserID` must be the caller's user and — for an anonymous widget guest, who shares one Anonymous
12
+ * user with every other guest — the guest's signed per-session scope must match the session's
13
+ * conversation. A refusal is an error on THIS subscription only (the socket and its other
14
+ * subscriptions are untouched) and is the same "not found" whether the session is missing or simply
15
+ * not yours, so ids cannot be probed.
16
+ * 2. **For every event** ({@link RealtimeSessionEventsFilter}). Each published event carries the owner and
17
+ * scope snapshot of its session; the filter re-applies the same decision against the CONNECTION's
18
+ * identity. Authorization therefore does not rest on a single check at one moment, and a replicated
19
+ * event from another server instance is judged exactly like a local one.
20
+ *
21
+ * In neither check does a client-supplied value decide who receives anything: `agentSessionId` only
22
+ * selects WHICH of the caller's own sessions to listen to; the identity it is checked against comes from
23
+ * the server-authenticated connection context.
24
+ *
25
+ * Events have no replay. A subscriber that was disconnected when an event fired recovers durable state
26
+ * from `RealtimeSessionVerificationStatus` (and from the session itself).
27
+ *
28
+ * @module @memberjunction/server
29
+ */
30
+
31
+ import { Resolver, Subscription, Root, Arg, ObjectType, Field } from 'type-graphql';
32
+ import { withFilter } from 'graphql-subscriptions';
33
+ import { PubSubManager } from '../generic/PubSubManager.js';
34
+ import {
35
+ AuthorizeRealtimeSessionSubscription,
36
+ RealtimeSessionEventsFilter,
37
+ type RealtimeSessionEventsArgs,
38
+ type RealtimeSessionEventsContext,
39
+ type SubscriptionAuthorizationDeps,
40
+ DEFAULT_SUBSCRIPTION_AUTHORIZATION_DEPS,
41
+ } from '../realtimeSessions/subscriptionAuthorization.js';
42
+ import { REALTIME_SESSION_EVENTS_TOPIC, type RealtimeSessionEventTopicPayload } from '../realtimeSessions/RealtimeSessionEventService.js';
43
+
44
+ /** One session event as the client receives it. The routing snapshot is deliberately NOT exposed. */
45
+ @ObjectType()
46
+ export class RealtimeSessionEventNotification {
47
+ /** Event type, e.g. `identity.verified`. Clients ignore types they do not know. */
48
+ @Field(() => String)
49
+ Type: string;
50
+
51
+ /** The session the event is addressed to. */
52
+ @Field(() => String)
53
+ AgentSessionID: string;
54
+
55
+ /** ISO-8601 instant the server emitted the event. */
56
+ @Field(() => String)
57
+ OccurredAt: string;
58
+
59
+ /** The event payload, JSON-encoded. Parse with `ParseRealtimeSessionEvent` from `@memberjunction/ai-core-plus`. */
60
+ @Field(() => String)
61
+ PayloadJson: string;
62
+ }
63
+
64
+ /**
65
+ * Builds the event stream for one authorized subscription: the shared topic, narrowed by
66
+ * {@link RealtimeSessionEventsFilter}.
67
+ */
68
+ function openEventStream(
69
+ root: unknown,
70
+ args: RealtimeSessionEventsArgs,
71
+ context: RealtimeSessionEventsContext,
72
+ info: unknown,
73
+ ): AsyncIterator<RealtimeSessionEventTopicPayload> {
74
+ const engine = PubSubManager.Instance.PubSubEngine;
75
+ if (!engine) {
76
+ throw new Error('Realtime session events are unavailable: PubSub is not configured.');
77
+ }
78
+ const filtered = withFilter(
79
+ () => engine.asyncIterator<RealtimeSessionEventTopicPayload>(REALTIME_SESSION_EVENTS_TOPIC),
80
+ (payload: RealtimeSessionEventTopicPayload, filterArgs: RealtimeSessionEventsArgs, filterContext: RealtimeSessionEventsContext) =>
81
+ RealtimeSessionEventsFilter({ payload, args: filterArgs, context: filterContext }),
82
+ );
83
+ return filtered(root, args, context, info);
84
+ }
85
+
86
+ /**
87
+ * The `subscribe` function: authorize FIRST (asynchronously), then open the stream. Exported (with an
88
+ * injectable `deps` argument graphql-js never passes) so the whole path is testable end to end.
89
+ *
90
+ * graphql-js awaits the value `subscribe` returns and turns a thrown error into a per-operation error
91
+ * result, which is exactly what a refusal should be (a failure of this subscription, not the socket).
92
+ */
93
+ export async function AuthorizeAndSubscribeToRealtimeSessionEvents(
94
+ root: unknown,
95
+ args: RealtimeSessionEventsArgs,
96
+ context: RealtimeSessionEventsContext,
97
+ info: unknown,
98
+ deps: SubscriptionAuthorizationDeps = DEFAULT_SUBSCRIPTION_AUTHORIZATION_DEPS,
99
+ ): Promise<AsyncIterator<RealtimeSessionEventTopicPayload>> {
100
+ await AuthorizeRealtimeSessionSubscription(args, context, deps);
101
+ return openEventStream(root, args, context, info);
102
+ }
103
+
104
+ @Resolver()
105
+ export class RealtimeSessionEventsResolver {
106
+ /**
107
+ * Subscribe to the events addressed to one of YOUR realtime sessions.
108
+ *
109
+ * @param agentSessionId - the `MJ: AI Agent Sessions` id to listen to. Must be a session the
110
+ * authenticated connection owns (and, for an anonymous widget guest, whose signed scope matches);
111
+ * otherwise the subscription is refused.
112
+ */
113
+ @Subscription(() => RealtimeSessionEventNotification, {
114
+ // graphql-subscriptions types `ResolverFn` as returning a bare AsyncIterator, but graphql-js
115
+ // AWAITS what `subscribe` returns (execute/subscribe.js: `await resolveFn(...)`), and awaiting is
116
+ // the only way to authorize against the database before opening the stream. The typing gap is in
117
+ // the library; `@ts-expect-error` (not a cast) so this fails to compile the day the type is fixed.
118
+ // @ts-expect-error subscribe may return Promise<AsyncIterator>; see comment above
119
+ subscribe: AuthorizeAndSubscribeToRealtimeSessionEvents,
120
+ })
121
+ RealtimeSessionEvents(
122
+ @Root() payload: RealtimeSessionEventTopicPayload,
123
+ @Arg('agentSessionId', () => String) _agentSessionId: string,
124
+ ): RealtimeSessionEventNotification {
125
+ // OwnerUserID / ScopeKey are server-internal filter keys and are intentionally not returned.
126
+ return {
127
+ Type: payload.Type,
128
+ AgentSessionID: payload.AgentSessionID,
129
+ OccurredAt: payload.OccurredAt,
130
+ PayloadJson: payload.PayloadJson,
131
+ };
132
+ }
133
+ }
@@ -0,0 +1,174 @@
1
+ /**
2
+ * @fileoverview GraphQL operations for **mid-session identity verification** of a realtime session.
3
+ *
4
+ * A person talking to an agent (often an anonymous widget guest) proves they control an email address
5
+ * without leaving the conversation. Three operations, all callable only as the session's OWN principal:
6
+ *
7
+ * | Operation | Kind | Purpose |
8
+ * |---|---|---|
9
+ * | `RequestRealtimeSessionVerification(agentSessionId, name, email)` | mutation | store a pending verification and email a one-time link + a typed code |
10
+ * | `SubmitRealtimeSessionVerificationCode(agentSessionId, code)` | mutation | redeem the typed code (the fallback for opening the email on another device) |
11
+ * | `RealtimeSessionVerificationStatus(agentSessionId)` | query | read the current state — the durable backstop for a missed `identity.verified` event |
12
+ *
13
+ * The emailed link is redeemed on a different surface — the public `GET/POST /realtime/verify` routes
14
+ * (`RealtimeVerifyRouter`) — because the person opening it holds no MJ token.
15
+ *
16
+ * The decisions, policy and limits live in `realtimeSessions/verificationWorkflow.ts`; this resolver
17
+ * only identifies the caller from the server-authenticated payload and maps the result. Note that it
18
+ * reads `userPayload.userRecord` directly and does **not** use `ResolverBase.GetUserFromPayload`: that
19
+ * helper falls back to an email lookup in the user cache, which would drop an anonymous guest's
20
+ * per-session scope — and a scope-less anonymous principal must never be treated as a named owner of
21
+ * the shared Anonymous user's sessions. No authenticated `userRecord` means no access.
22
+ *
23
+ * @module @memberjunction/server
24
+ */
25
+
26
+ import { Resolver, Mutation, Query, Arg, Ctx, ObjectType, Field, Int } from 'type-graphql';
27
+ import type { UserInfo } from '@memberjunction/core';
28
+ import type { AppContext } from '../types.js';
29
+ import { GetReadWriteProvider } from '../util.js';
30
+ import { NoLog } from '../logging/NoLog.js';
31
+ import { RealtimeSessionVerificationService } from '../realtimeSessions/RealtimeSessionVerificationService.js';
32
+ import type { PrincipalCaller, VerificationOperationResult } from '../realtimeSessions/verificationWorkflow.js';
33
+
34
+ /** Result of every verification operation. */
35
+ @ObjectType()
36
+ export class RealtimeSessionVerificationResult {
37
+ /** True when the operation did what was asked. */
38
+ @Field(() => Boolean)
39
+ Success: boolean;
40
+
41
+ /** The session's verification state after the operation: `unverified`, `pending` or `verified`. */
42
+ @Field(() => String)
43
+ VerificationState: string;
44
+
45
+ /**
46
+ * Machine-readable failure reason when `Success` is false — e.g. `invalid_email`, `consumer_domain`,
47
+ * `domain_blocked`, `rate_limited`, `send_limit_reached`, `invalid_code`, `attempts_exhausted`,
48
+ * `code_expired`, `session_not_found`, `session_closed`, `verification_unavailable`.
49
+ */
50
+ @Field(() => String, { nullable: true })
51
+ ErrorCode?: string;
52
+
53
+ /** A message safe to show a person. */
54
+ @Field(() => String, { nullable: true })
55
+ Message?: string;
56
+
57
+ /** ISO instant the pending link/code expires. */
58
+ @Field(() => String, { nullable: true })
59
+ ExpiresAt?: string;
60
+
61
+ /** Verification emails this session may still trigger. */
62
+ @Field(() => Int, { nullable: true })
63
+ SendsRemaining?: number;
64
+
65
+ /** Wrong code entries left before the pending verification is voided. */
66
+ @Field(() => Int, { nullable: true })
67
+ AttemptsRemaining?: number;
68
+
69
+ /** Seconds to wait before retrying, when rate limited. */
70
+ @Field(() => Int, { nullable: true })
71
+ RetryAfterSeconds?: number;
72
+
73
+ /** The verified address, once verified. */
74
+ @Field(() => String, { nullable: true })
75
+ VerifiedEmail?: string;
76
+
77
+ /** ISO instant verification completed. */
78
+ @Field(() => String, { nullable: true })
79
+ VerifiedAt?: string;
80
+
81
+ /** The session's new absolute deadline (ISO) when verification extended it. The server enforces it; this is informational. */
82
+ @Field(() => String, { nullable: true })
83
+ MaxSessionDeadlineIso?: string;
84
+ }
85
+
86
+ /** Maps the workflow result onto the GraphQL type. */
87
+ function toResult(result: VerificationOperationResult): RealtimeSessionVerificationResult {
88
+ return { ...result };
89
+ }
90
+
91
+ /** The result for a caller with no usable authenticated identity. */
92
+ function notAuthenticated(): RealtimeSessionVerificationResult {
93
+ return { Success: false, VerificationState: 'unverified', ErrorCode: 'session_not_found', Message: 'Session not found.' };
94
+ }
95
+
96
+ @Resolver()
97
+ export class RealtimeSessionVerificationResolver {
98
+ /**
99
+ * Ask to verify an email for your realtime session. Applies the session's policy (business-domain
100
+ * rules, blocked domains, send and rate limits), then emails a one-time link plus a short code.
101
+ *
102
+ * @param agentSessionId - your `MJ: AI Agent Sessions` id
103
+ * @param name - the name to greet in the email (sanitised and length-capped server-side)
104
+ * @param email - the address to verify
105
+ */
106
+ @Mutation(() => RealtimeSessionVerificationResult)
107
+ async RequestRealtimeSessionVerification(
108
+ @Arg('agentSessionId', () => String) agentSessionId: string,
109
+ @Arg('name', () => String) name: string,
110
+ @Arg('email', () => String) @NoLog email: string,
111
+ @Ctx() context: AppContext,
112
+ ): Promise<RealtimeSessionVerificationResult> {
113
+ const caller = this.callerFrom(context);
114
+ if (!caller) {
115
+ return notAuthenticated();
116
+ }
117
+ return toResult(
118
+ await RealtimeSessionVerificationService.Instance.RequestVerification(
119
+ { AgentSessionID: agentSessionId, Name: name, Email: email },
120
+ caller,
121
+ ),
122
+ );
123
+ }
124
+
125
+ /**
126
+ * Redeem the typed code from the verification email. Single use; voided after too many wrong entries.
127
+ *
128
+ * @param agentSessionId - your `MJ: AI Agent Sessions` id
129
+ * @param code - the code from the email (spaces and dashes are ignored)
130
+ */
131
+ @Mutation(() => RealtimeSessionVerificationResult)
132
+ async SubmitRealtimeSessionVerificationCode(
133
+ @Arg('agentSessionId', () => String) agentSessionId: string,
134
+ @Arg('code', () => String) @NoLog code: string,
135
+ @Ctx() context: AppContext,
136
+ ): Promise<RealtimeSessionVerificationResult> {
137
+ const caller = this.callerFrom(context);
138
+ if (!caller) {
139
+ return notAuthenticated();
140
+ }
141
+ return toResult(await RealtimeSessionVerificationService.Instance.SubmitCode({ AgentSessionID: agentSessionId, Code: code }, caller));
142
+ }
143
+
144
+ /**
145
+ * Read the current verification state of your realtime session. Use it after a reconnect: session
146
+ * events have no replay, so this is how a client that missed `identity.verified` finds out.
147
+ *
148
+ * @param agentSessionId - your `MJ: AI Agent Sessions` id
149
+ */
150
+ @Query(() => RealtimeSessionVerificationResult)
151
+ async RealtimeSessionVerificationStatus(
152
+ @Arg('agentSessionId', () => String) agentSessionId: string,
153
+ @Ctx() context: AppContext,
154
+ ): Promise<RealtimeSessionVerificationResult> {
155
+ const caller = this.callerFrom(context);
156
+ if (!caller) {
157
+ return notAuthenticated();
158
+ }
159
+ return toResult(await RealtimeSessionVerificationService.Instance.GetStatus({ AgentSessionID: agentSessionId }, caller));
160
+ }
161
+
162
+ /**
163
+ * Builds the caller from the server-authenticated payload, or null when there is none. Identity comes
164
+ * from `userPayload.userRecord` ONLY (see the module header).
165
+ */
166
+ private callerFrom(context: AppContext): PrincipalCaller | null {
167
+ const contextUser = context.userPayload?.userRecord as UserInfo | undefined;
168
+ const provider = GetReadWriteProvider(context.providers);
169
+ if (!contextUser?.ID || !provider) {
170
+ return null;
171
+ }
172
+ return { Kind: 'principal', ContextUser: contextUser, Provider: provider, ClientIp: context.ClientIp };
173
+ }
174
+ }
@@ -24,6 +24,7 @@ import { MJAIAgentSessionEntity, MJAIAgentEntity } from '@memberjunction/core-en
24
24
  import { NormalizeInstanceKey, RemoteBrowserEngine } from '@memberjunction/remote-browser-server';
25
25
  import { BeginBrowserGoalStep, FinalizeBrowserGoalStep, ExtractCoAgentRunID } from '../agentSessions/remoteBrowserGoalEngine.js';
26
26
  import { RemoteBrowserGoalRegistry } from '../agentSessions/remoteBrowserGoalRegistry.js';
27
+ import { SessionRunIDVerifier } from '../agentSessions/SessionRunIDVerifier.js';
27
28
  import { randomUUID } from 'node:crypto';
28
29
  import {
29
30
  RemoteBrowserAction,
@@ -261,6 +262,9 @@ export class RemoteBrowserActionResolver extends ResolverBase {
261
262
  */
262
263
  private startedScreencasts = new Map<string, number>();
263
264
 
265
+ /** Checks the co-agent run id read from a session's owner-editable `Config_` before a step is attached to it. */
266
+ private readonly runIDVerifier = new SessionRunIDVerifier();
267
+
264
268
  /**
265
269
  * Surfaces whose live tab-audio stream this resolver has already started, keyed by
266
270
  * {@link RemoteBrowserActionResolver.streamKey} for the same reason the screencast map is. Entries
@@ -400,7 +404,13 @@ export class RemoteBrowserActionResolver extends ResolverBase {
400
404
  const providerName = await this.resolveProviderName(session, contextUser, provider);
401
405
  // Observability: nest this goal's many prompt runs under ONE "Browser goal" step on the realtime
402
406
  // co-agent run (when the session has one). Best-effort — a null step just means the goal runs unlinked.
403
- const coAgentRunID = ExtractCoAgentRunID(session.Config_);
407
+ // The owner can edit Config_, so its run id is used only when it is a run of this session.
408
+ const { CoAgentRunID: coAgentRunID } = await this.runIDVerifier.Verify(
409
+ session.ID,
410
+ { CoAgentRunID: ExtractCoAgentRunID(session.Config_) },
411
+ contextUser,
412
+ provider,
413
+ );
404
414
  const goalStep = await BeginBrowserGoalStep(provider, contextUser, coAgentRunID, goal);
405
415
 
406
416
  // ASYNC START: a goal loop can run for minutes; do NOT hold this request open for it (browser
@@ -13,6 +13,7 @@ import { StartLivenessPulse } from '../generic/FireAndForgetHeartbeat.js';
13
13
  import { RequireSystemUser } from '../directives/RequireSystemUser.js';
14
14
  import { GetReadWriteProvider } from '../util.js';
15
15
  import { ResolveWidgetGuestRunContext, ElevateUserPayload } from '../realtimeWidget/widgetGuestElevation.js';
16
+ import { IsTrustedAgentRunCaller } from './agent-run-data-guard.js';
16
17
  import { SafeJSONParse, UUIDsEqual } from '@memberjunction/global';
17
18
  import { GetAttachmentService } from '@memberjunction/aiengine';
18
19
  import { NotificationEngine } from '@memberjunction/notifications';
@@ -252,6 +253,14 @@ export class RunAIAgentResolver extends ResolverBase {
252
253
  throw new Error(`AI Agent "${agentEntity.Name}" is not active (Status: ${agentEntity.Status})`);
253
254
  }
254
255
 
256
+ // Enforce agent run permissions for the calling user
257
+ if (currentUser && typeof AIEngine.Instance.CanUserRunAgent === 'function') {
258
+ const canRun = await AIEngine.Instance.CanUserRunAgent(agentEntity.ID, currentUser);
259
+ if (!canRun) {
260
+ throw new Error(`User does not have permission to run AI Agent "${agentEntity.Name}" (${agentEntity.ID})`);
261
+ }
262
+ }
263
+
255
264
  return agentEntity;
256
265
  }
257
266
 
@@ -293,7 +302,11 @@ export class RunAIAgentResolver extends ResolverBase {
293
302
  taskGraphDebug?: string,
294
303
  /** History floor for a conversation run — threaded into ExecuteAgentParams.ConversationHistoryFrom,
295
304
  * so the framework's own conversation reads (retrieval tools, artifacts, compaction) honour it too. */
296
- conversationHistoryFrom?: Date
305
+ conversationHistoryFrom?: Date,
306
+ /** ExecuteAgentParams.TrustReservedRunData: true only for a caller IsTrustedAgentRunCaller accepts. */
307
+ trustReservedRunData: boolean = false,
308
+ /** The conversation branch of the run — threaded into ExecuteAgentParams.ConversationBranchID. */
309
+ conversationBranchId?: string | null
297
310
  ): Promise<AIAgentRunResult> {
298
311
  const startTime = Date.now();
299
312
  // Best-effort handle for persistInFlightAgentFailure. Populated from a
@@ -362,7 +375,10 @@ export class RunAIAgentResolver extends ResolverBase {
362
375
  requestedSkillIDs: requestedSkillIDs,
363
376
  taskGraphDebug: parseTaskGraphDebug(taskGraphDebug),
364
377
  ConversationHistoryFrom: conversationHistoryFrom,
378
+ ...(conversationBranchId ? { ConversationBranchID: conversationBranchId } : {}),
365
379
  data: parsedData,
380
+ // Whether the run may read the reserved data keys (scope, agent-type params); BaseAgent drops them otherwise.
381
+ TrustReservedRunData: trustReservedRunData,
366
382
  context: {
367
383
  dataSource: dataSource
368
384
  }
@@ -561,6 +577,9 @@ export class RunAIAgentResolver extends ResolverBase {
561
577
  await this.CheckAPIKeyScopeAuthorization('agent:execute', agentId, userPayload);
562
578
 
563
579
  const p = GetReadWriteProvider(providers);
580
+ // Only the system user or an API key holding the agent:trusted scope may set a run's scope and agent-type
581
+ // params through data; for anyone else BaseAgent drops those keys (ExecuteAgentParams.TrustReservedRunData).
582
+ const trustRunData = await IsTrustedAgentRunCaller({ UserPayload: userPayload, IsWidgetGuestRun: false, AgentID: agentId });
564
583
 
565
584
  if (fireAndForget) {
566
585
  // Fire-and-forget mode: start execution in background, return immediately.
@@ -569,7 +588,8 @@ export class RunAIAgentResolver extends ResolverBase {
569
588
  p, dataSource, agentId, userPayload, messagesJson, sessionId, pubSub,
570
589
  data, payload, lastRunId, autoPopulateLastRunPayload, configurationId,
571
590
  conversationDetailId, createArtifacts || false, createNotification || false,
572
- sourceArtifactId, sourceArtifactVersionId, undefined /*conversationId*/, planMode, requestedSkillIDs, taskGraphDebug
591
+ sourceArtifactId, sourceArtifactVersionId, undefined /*conversationId*/, planMode, requestedSkillIDs, taskGraphDebug,
592
+ undefined /*conversationHistoryFrom*/, trustRunData
573
593
  );
574
594
 
575
595
  LogStatus(`🔥 Fire-and-forget: Agent ${agentId} execution started in background for session ${sessionId}`);
@@ -604,7 +624,9 @@ export class RunAIAgentResolver extends ResolverBase {
604
624
  undefined, // runRef
605
625
  planMode,
606
626
  requestedSkillIDs,
607
- taskGraphDebug
627
+ taskGraphDebug,
628
+ undefined, // conversationHistoryFrom
629
+ trustRunData
608
630
  );
609
631
  }
610
632
 
@@ -637,6 +659,9 @@ export class RunAIAgentResolver extends ResolverBase {
637
659
  @Arg('requestedSkillIDs', () => [String], { nullable: true }) requestedSkillIDs?: string[]
638
660
  ): Promise<AIAgentRunResult> {
639
661
  const p = GetReadWriteProvider(providers);
662
+ // @RequireSystemUser admits only the system user, whom the rule trusts; it is still asked, so every
663
+ // resolver entry that takes a client's data decides the same way.
664
+ const trustRunData = await IsTrustedAgentRunCaller({ UserPayload: userPayload, IsWidgetGuestRun: false, AgentID: agentId });
640
665
  return this.executeAIAgent(
641
666
  p,
642
667
  dataSource,
@@ -659,7 +684,10 @@ export class RunAIAgentResolver extends ResolverBase {
659
684
  undefined, // conversationId (not pre-resolved on this path)
660
685
  undefined, // runRef
661
686
  planMode,
662
- requestedSkillIDs
687
+ requestedSkillIDs,
688
+ undefined, // taskGraphDebug
689
+ undefined, // conversationHistoryFrom
690
+ trustRunData
663
691
  );
664
692
  }
665
693
 
@@ -752,6 +780,45 @@ export class RunAIAgentResolver extends ResolverBase {
752
780
  }
753
781
  }
754
782
 
783
+ /**
784
+ * The ID of this agent's newest root run in the conversation IF the user stopped it, else
785
+ * null. The query spans the runs that could be the predecessor (settled, or stopped by the
786
+ * user) and the newest decides, so a stopped run that a later settled run already followed
787
+ * is not chained to again. Uses the same filter and recognizer as `BaseAgent.findUserStoppedPredecessorRunId`
788
+ * (`MJAIAgentRunEntityExtended.BuildStoppedPredecessorFilter` / `IsUserStopped`), which carries the stopped run's
789
+ * completed results into the new run's context, so the two cannot pick different runs.
790
+ * Fail-soft: a lookup failure means no chaining, never a failed turn.
791
+ */
792
+ private async findUserStoppedPredecessorRunId(
793
+ conversationId: string,
794
+ agentId: string,
795
+ branchId: string | null,
796
+ contextUser: UserInfo,
797
+ provider: IMetadataProvider
798
+ ): Promise<string | null> {
799
+ try {
800
+ // The run must have replied on this turn's branch path: a run stopped on a sibling branch is not
801
+ // this path's history. The trunk needs no branch rows; a branch needs them to walk its ancestry.
802
+ const branches = branchId ? await ConversationEngine.LoadBranchesFresh(conversationId, contextUser, provider) : [];
803
+ const rv = RunView.FromMetadataProvider(provider);
804
+ const newest = await rv.RunView<{ ID: string; Status: string; CancellationReason: string | null }>({
805
+ EntityName: 'MJ: AI Agent Runs',
806
+ ExtraFilter: MJAIAgentRunEntityExtended.BuildStoppedPredecessorFilter(conversationId, agentId, branchId, branches),
807
+ OrderBy: '__mj_CreatedAt DESC',
808
+ MaxRows: 1,
809
+ Fields: ['ID', 'Status', 'CancellationReason'],
810
+ ResultType: 'simple',
811
+ // The row this looks for was written by the Stop button moments ago; read the database, not a cache.
812
+ BypassCache: true,
813
+ }, contextUser);
814
+ const run = newest.Success ? newest.Results?.[0] : undefined;
815
+ return run && MJAIAgentRunEntityExtended.IsUserStopped(run.Status, run.CancellationReason) ? run.ID : null;
816
+ } catch (error) {
817
+ LogError(`findUserStoppedPredecessorRunId failed; the turn runs unchained: ${error instanceof Error ? error.message : String(error)}`);
818
+ return null;
819
+ }
820
+ }
821
+
755
822
  /**
756
823
  * When a continuation run completes (lastRunId was provided), sync the corresponding
757
824
  * AIAgentRequest by marking it as responded. This keeps the dashboard accurate when
@@ -916,6 +983,12 @@ export class RunAIAgentResolver extends ResolverBase {
916
983
  const widgetElevation = await ResolveWidgetGuestRunContext(userPayload, p);
917
984
  const effectiveAgentId = widgetElevation ? widgetElevation.PinnedAgentId : agentId;
918
985
  const effectiveUserPayload = widgetElevation ? ElevateUserPayload(userPayload, widgetElevation.ElevatedUser) : userPayload;
986
+ // Only the system user or an API key holding the agent:trusted scope may set a run's scope and agent-type
987
+ // params through data (ExecuteAgentParams.TrustReservedRunData). Judged on the caller's own payload: a widget
988
+ // guest runs under an elevated server principal but is never trusted.
989
+ const trustRunData = await IsTrustedAgentRunCaller({
990
+ UserPayload: userPayload, IsWidgetGuestRun: widgetElevation !== null, AgentID: agentId,
991
+ });
919
992
 
920
993
  try {
921
994
  // Parsed before anything loads: a floor the caller asked for must never be dropped.
@@ -934,6 +1007,24 @@ export class RunAIAgentResolver extends ResolverBase {
934
1007
  throw new Error(`Conversation detail ${conversationDetailId} not found`);
935
1008
  }
936
1009
  const conversationId = currentDetail.ConversationID;
1010
+ // The branch the placeholder row was created on decides which path the run reads.
1011
+ const branchId: string | null = currentDetail.BranchID ?? null;
1012
+
1013
+ // A turn that follows a run the user STOPPED continues that run rather than starting
1014
+ // over: chain it by LastRunID (the chat client never sends one) and, when the caller
1015
+ // supplied no payload, roll the stopped run's FinalPayload into this run's start.
1016
+ let effectiveLastRunId = lastRunId;
1017
+ let effectiveAutoPopulate = autoPopulateLastRunPayload;
1018
+ if (!effectiveLastRunId) {
1019
+ const stoppedRunId = await this.findUserStoppedPredecessorRunId(conversationId, effectiveAgentId, branchId, currentUser, p);
1020
+ if (stoppedRunId) {
1021
+ effectiveLastRunId = stoppedRunId;
1022
+ if (effectiveAutoPopulate === undefined && payload == null) {
1023
+ effectiveAutoPopulate = true;
1024
+ }
1025
+ LogStatus(`↩️ Continuing from user-stopped run ${stoppedRunId} (chained by LastRunID)`);
1026
+ }
1027
+ }
937
1028
 
938
1029
  // Load conversation history with attachments from DB
939
1030
  const messages = await this.loadConversationHistoryWithAttachments(
@@ -944,7 +1035,8 @@ export class RunAIAgentResolver extends ResolverBase {
944
1035
  // The UI creates the agent-response placeholder row ('⏳ ...') before invoking
945
1036
  // this mutation — exclude it so the model never sees an empty assistant turn.
946
1037
  [conversationDetailId],
947
- historyFrom
1038
+ historyFrom,
1039
+ branchId
948
1040
  );
949
1041
 
950
1042
  // Convert to JSON string for the existing executeAIAgent method
@@ -955,11 +1047,13 @@ export class RunAIAgentResolver extends ResolverBase {
955
1047
  // The client will receive the result via WebSocket PubSub completion event.
956
1048
  this.executeAgentInBackground(
957
1049
  p, dataSource, effectiveAgentId, effectiveUserPayload, messagesJson, sessionId, pubSub,
958
- data, payload, lastRunId, autoPopulateLastRunPayload, configurationId,
1050
+ data, payload, effectiveLastRunId, effectiveAutoPopulate, configurationId,
959
1051
  conversationDetailId, createArtifacts || false, createNotification || false,
960
1052
  sourceArtifactId, sourceArtifactVersionId, conversationId, planMode, requestedSkillIDs,
961
1053
  undefined, // taskGraphDebug
962
- historyFrom
1054
+ historyFrom,
1055
+ trustRunData,
1056
+ branchId
963
1057
  );
964
1058
 
965
1059
  LogStatus(`🔥 Fire-and-forget: Agent ${effectiveAgentId} execution started in background for session ${sessionId}`);
@@ -982,8 +1076,8 @@ export class RunAIAgentResolver extends ResolverBase {
982
1076
  data,
983
1077
  payload,
984
1078
  undefined, // templateData
985
- lastRunId,
986
- autoPopulateLastRunPayload,
1079
+ effectiveLastRunId,
1080
+ effectiveAutoPopulate,
987
1081
  configurationId,
988
1082
  conversationDetailId,
989
1083
  createArtifacts || false,
@@ -995,7 +1089,9 @@ export class RunAIAgentResolver extends ResolverBase {
995
1089
  planMode,
996
1090
  requestedSkillIDs,
997
1091
  undefined, // taskGraphDebug
998
- historyFrom
1092
+ historyFrom,
1093
+ trustRunData,
1094
+ branchId
999
1095
  );
1000
1096
  } catch (error) {
1001
1097
  const errorMessage = (error as Error).message || 'Unknown error loading conversation history';
@@ -1217,7 +1313,11 @@ export class RunAIAgentResolver extends ResolverBase {
1217
1313
  requestedSkillIDs?: string[],
1218
1314
  taskGraphDebug?: string,
1219
1315
  /** History floor — threaded through to ExecuteAgentParams.ConversationHistoryFrom. */
1220
- conversationHistoryFrom?: Date
1316
+ conversationHistoryFrom?: Date,
1317
+ /** ExecuteAgentParams.TrustReservedRunData — see executeAIAgent. */
1318
+ trustReservedRunData: boolean = false,
1319
+ /** The conversation branch of the run — threaded through to ExecuteAgentParams.ConversationBranchID. */
1320
+ conversationBranchId?: string | null
1221
1321
  ): void {
1222
1322
  // Ref the liveness pulse reads to enrich heartbeats once the run is created.
1223
1323
  const runRef: { current: MJAIAgentRunEntityExtended | null } = { current: null };
@@ -1237,7 +1337,7 @@ export class RunAIAgentResolver extends ResolverBase {
1237
1337
  data, payload, undefined, lastRunId, autoPopulateLastRunPayload,
1238
1338
  configurationId, conversationDetailId, createArtifacts, createNotification,
1239
1339
  sourceArtifactId, sourceArtifactVersionId, conversationId, runRef, planMode, requestedSkillIDs, taskGraphDebug,
1240
- conversationHistoryFrom
1340
+ conversationHistoryFrom, trustReservedRunData, conversationBranchId
1241
1341
  ).catch((error: unknown) => {
1242
1342
  // Background execution failed unexpectedly (executeAIAgent has its own try-catch,
1243
1343
  // so this would only fire for truly unexpected errors).
@@ -1277,7 +1377,9 @@ export class RunAIAgentResolver extends ResolverBase {
1277
1377
  provider: IMetadataProvider,
1278
1378
  excludeDetailIds?: string[],
1279
1379
  /** History floor: only rows written at or after it are loaded, and no summary is used. */
1280
- historyFrom?: Date
1380
+ historyFrom?: Date,
1381
+ /** The branch whose path to load; null reads the trunk. */
1382
+ branchId?: string | null
1281
1383
  ): Promise<ChatMessage[]> {
1282
1384
  // Context windowing (summary boundary + raw tail, or legacy last-N when no
1283
1385
  // summary exists) shares ONE fold implementation with all other callers —
@@ -1294,7 +1396,7 @@ export class RunAIAgentResolver extends ResolverBase {
1294
1396
  // the agent against zero history.
1295
1397
  // 4. A history floor (`historyFrom`) is applied in the query, so rows before it never
1296
1398
  // leave the database, and again in the assembly, which then skips the summary.
1297
- const rows = await ConversationEngine.LoadWindowRowsFresh(conversationId, contextUser, provider, historyFrom);
1399
+ const rows = await ConversationEngine.LoadWindowRowsFresh(conversationId, contextUser, provider, historyFrom, branchId);
1298
1400
  const window = ConversationEngine.AssembleContextWindow(rows, {
1299
1401
  maxTailMessages: maxMessages,
1300
1402
  excludeDetailIds,
@@ -2,7 +2,7 @@ import { Resolver, Mutation, Arg, Ctx, ObjectType, Field } from 'type-graphql';
2
2
  import { AppContext, UserPayload } from '../types.js';
3
3
  import { LogError, LogStatus, Metadata, RunView } from '@memberjunction/core';
4
4
  import { MJTemplateContentEntity, MJTemplateEntityExtended } from '@memberjunction/core-entities';
5
- import { TemplateEngineServer } from '@memberjunction/templates';
5
+ import { GetTemplateRunRefusal, TemplateEngineServer } from '@memberjunction/templates';
6
6
  import { ResolverBase } from '../generic/ResolverBase.js';
7
7
  import { GetReadWriteProvider } from '../util.js';
8
8
 
@@ -45,6 +45,18 @@ export class RunTemplateResolver extends ResolverBase {
45
45
  try {
46
46
  LogStatus(`=== RUNNING TEMPLATE FOR ID: ${templateId} ===`);
47
47
 
48
+ // Same rule as the Template.Run remote operation, checked before anything is loaded
49
+ const currentUser = this.GetUserFromPayload(userPayload);
50
+ const p = GetReadWriteProvider(providers);
51
+ const refusal = GetTemplateRunRefusal(currentUser, p);
52
+ if (refusal) {
53
+ return {
54
+ success: false,
55
+ error: refusal,
56
+ executionTimeMs: Date.now() - startTime
57
+ };
58
+ }
59
+
48
60
  // Parse context data (JSON string)
49
61
  let data = {};
50
62
  if (contextData) {
@@ -59,17 +71,6 @@ export class RunTemplateResolver extends ResolverBase {
59
71
  }
60
72
  }
61
73
 
62
- // Get current user from payload
63
- const currentUser = this.GetUserFromPayload(userPayload);
64
- if (!currentUser) {
65
- return {
66
- success: false,
67
- error: 'Unable to determine current user',
68
- executionTimeMs: Date.now() - startTime
69
- };
70
- }
71
-
72
- const p = GetReadWriteProvider(providers);
73
74
  // Load the template entity
74
75
  const templateEntity = await p.GetEntityObject<MJTemplateEntityExtended>('MJ: Templates', currentUser);
75
76
  await templateEntity.Load(templateId);