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

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 (560) hide show
  1. package/README.md +47 -1
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/agentSessions/SessionJanitor.d.ts +91 -30
  4. package/dist/agentSessions/SessionJanitor.d.ts.map +1 -1
  5. package/dist/agentSessions/SessionJanitor.js +311 -81
  6. package/dist/agentSessions/SessionJanitor.js.map +1 -1
  7. package/dist/agentSessions/SessionManager.d.ts +17 -3
  8. package/dist/agentSessions/SessionManager.d.ts.map +1 -1
  9. package/dist/agentSessions/SessionManager.js +44 -10
  10. package/dist/agentSessions/SessionManager.js.map +1 -1
  11. package/dist/apiRoot.d.ts +32 -0
  12. package/dist/apiRoot.d.ts.map +1 -0
  13. package/dist/apiRoot.js +67 -0
  14. package/dist/apiRoot.js.map +1 -0
  15. package/dist/auth/AuthProviderCatalogRouter.d.ts.map +1 -1
  16. package/dist/auth/AuthProviderCatalogRouter.js +27 -0
  17. package/dist/auth/AuthProviderCatalogRouter.js.map +1 -1
  18. package/dist/auth/LoginScreenEngine.d.ts +22 -0
  19. package/dist/auth/LoginScreenEngine.d.ts.map +1 -0
  20. package/dist/auth/LoginScreenEngine.js +57 -0
  21. package/dist/auth/LoginScreenEngine.js.map +1 -0
  22. package/dist/auth/index.d.ts +1 -0
  23. package/dist/auth/index.d.ts.map +1 -1
  24. package/dist/auth/index.js +52 -10
  25. package/dist/auth/index.js.map +1 -1
  26. package/dist/auth/initializeProviders.d.ts +10 -0
  27. package/dist/auth/initializeProviders.d.ts.map +1 -1
  28. package/dist/auth/initializeProviders.js +37 -1
  29. package/dist/auth/initializeProviders.js.map +1 -1
  30. package/dist/auth/localDevAuth.d.ts +79 -0
  31. package/dist/auth/localDevAuth.d.ts.map +1 -0
  32. package/dist/auth/localDevAuth.js +439 -0
  33. package/dist/auth/localDevAuth.js.map +1 -0
  34. package/dist/auth/magicLink/MagicLinkKeys.d.ts +2 -2
  35. package/dist/auth/magicLink/MagicLinkKeys.d.ts.map +1 -1
  36. package/dist/auth/magicLink/MagicLinkKeys.js +1 -1
  37. package/dist/auth/magicLink/MagicLinkKeys.js.map +1 -1
  38. package/dist/auth/magicLink/MagicLinkRouter.d.ts.map +1 -1
  39. package/dist/auth/magicLink/MagicLinkRouter.js +3 -2
  40. package/dist/auth/magicLink/MagicLinkRouter.js.map +1 -1
  41. package/dist/auth/magicLink/types.d.ts +12 -0
  42. package/dist/auth/magicLink/types.d.ts.map +1 -1
  43. package/dist/auth/sessionUserClone.d.ts +1 -1
  44. package/dist/auth/sessionUserClone.d.ts.map +1 -1
  45. package/dist/auth/sessionUserClone.js +3 -2
  46. package/dist/auth/sessionUserClone.js.map +1 -1
  47. package/dist/broadcast/BaseCacheInvalidationBroadcastProvider.d.ts +292 -0
  48. package/dist/broadcast/BaseCacheInvalidationBroadcastProvider.d.ts.map +1 -0
  49. package/dist/broadcast/BaseCacheInvalidationBroadcastProvider.js +442 -0
  50. package/dist/broadcast/BaseCacheInvalidationBroadcastProvider.js.map +1 -0
  51. package/dist/broadcast/index.d.ts +6 -0
  52. package/dist/broadcast/index.d.ts.map +1 -0
  53. package/dist/broadcast/index.js +6 -0
  54. package/dist/broadcast/index.js.map +1 -0
  55. package/dist/broadcast/providers/AWSIoTCoreBroadcastProvider.d.ts +43 -0
  56. package/dist/broadcast/providers/AWSIoTCoreBroadcastProvider.d.ts.map +1 -0
  57. package/dist/broadcast/providers/AWSIoTCoreBroadcastProvider.js +144 -0
  58. package/dist/broadcast/providers/AWSIoTCoreBroadcastProvider.js.map +1 -0
  59. package/dist/broadcast/providers/AzureWebPubSubBroadcastProvider.d.ts +46 -0
  60. package/dist/broadcast/providers/AzureWebPubSubBroadcastProvider.d.ts.map +1 -0
  61. package/dist/broadcast/providers/AzureWebPubSubBroadcastProvider.js +149 -0
  62. package/dist/broadcast/providers/AzureWebPubSubBroadcastProvider.js.map +1 -0
  63. package/dist/broadcast/providers/GCPPubSubBroadcastProvider.d.ts +49 -0
  64. package/dist/broadcast/providers/GCPPubSubBroadcastProvider.d.ts.map +1 -0
  65. package/dist/broadcast/providers/GCPPubSubBroadcastProvider.js +131 -0
  66. package/dist/broadcast/providers/GCPPubSubBroadcastProvider.js.map +1 -0
  67. package/dist/broadcast/providers/SequencedRoleBucketBroadcastProvider.d.ts +24 -0
  68. package/dist/broadcast/providers/SequencedRoleBucketBroadcastProvider.d.ts.map +1 -0
  69. package/dist/broadcast/providers/SequencedRoleBucketBroadcastProvider.js +51 -0
  70. package/dist/broadcast/providers/SequencedRoleBucketBroadcastProvider.js.map +1 -0
  71. package/dist/cache.d.ts +3 -2
  72. package/dist/cache.d.ts.map +1 -1
  73. package/dist/cache.js.map +1 -1
  74. package/dist/config.d.ts +632 -22
  75. package/dist/config.d.ts.map +1 -1
  76. package/dist/config.js +104 -4
  77. package/dist/config.js.map +1 -1
  78. package/dist/context.d.ts +3 -1
  79. package/dist/context.d.ts.map +1 -1
  80. package/dist/context.js +29 -8
  81. package/dist/context.js.map +1 -1
  82. package/dist/coreRoutes.d.ts +29 -0
  83. package/dist/coreRoutes.d.ts.map +1 -0
  84. package/dist/coreRoutes.js +156 -0
  85. package/dist/coreRoutes.js.map +1 -0
  86. package/dist/generated/graphql-schemas/__mj.d.ts +1016 -29
  87. package/dist/generated/graphql-schemas/__mj.d.ts.map +1 -1
  88. package/dist/generated/graphql-schemas/__mj.js +5125 -434
  89. package/dist/generated/graphql-schemas/__mj.js.map +1 -1
  90. package/dist/generic/CacheInvalidationResolver.d.ts +85 -30
  91. package/dist/generic/CacheInvalidationResolver.d.ts.map +1 -1
  92. package/dist/generic/CacheInvalidationResolver.js +175 -60
  93. package/dist/generic/CacheInvalidationResolver.js.map +1 -1
  94. package/dist/generic/OrphanedConversationDetailReconciler.d.ts.map +1 -1
  95. package/dist/generic/OrphanedConversationDetailReconciler.js +2 -0
  96. package/dist/generic/OrphanedConversationDetailReconciler.js.map +1 -1
  97. package/dist/generic/PubSubManager.d.ts +10 -0
  98. package/dist/generic/PubSubManager.d.ts.map +1 -1
  99. package/dist/generic/PubSubManager.js +44 -1
  100. package/dist/generic/PubSubManager.js.map +1 -1
  101. package/dist/generic/PushStatusResolver.d.ts +39 -6
  102. package/dist/generic/PushStatusResolver.d.ts.map +1 -1
  103. package/dist/generic/PushStatusResolver.js +94 -12
  104. package/dist/generic/PushStatusResolver.js.map +1 -1
  105. package/dist/generic/ResolverBase.d.ts +168 -69
  106. package/dist/generic/ResolverBase.d.ts.map +1 -1
  107. package/dist/generic/ResolverBase.js +464 -405
  108. package/dist/generic/ResolverBase.js.map +1 -1
  109. package/dist/generic/RunViewResolver.d.ts +11 -3
  110. package/dist/generic/RunViewResolver.d.ts.map +1 -1
  111. package/dist/generic/RunViewResolver.js +91 -13
  112. package/dist/generic/RunViewResolver.js.map +1 -1
  113. package/dist/generic/actionOutputFieldSecurity.d.ts +26 -0
  114. package/dist/generic/actionOutputFieldSecurity.d.ts.map +1 -0
  115. package/dist/generic/actionOutputFieldSecurity.js +47 -0
  116. package/dist/generic/actionOutputFieldSecurity.js.map +1 -0
  117. package/dist/generic/fieldSecurityTransport.d.ts +30 -0
  118. package/dist/generic/fieldSecurityTransport.d.ts.map +1 -0
  119. package/dist/generic/fieldSecurityTransport.js +30 -0
  120. package/dist/generic/fieldSecurityTransport.js.map +1 -0
  121. package/dist/globalCors.d.ts +33 -0
  122. package/dist/globalCors.d.ts.map +1 -0
  123. package/dist/globalCors.js +58 -0
  124. package/dist/globalCors.js.map +1 -0
  125. package/dist/index.d.ts +14 -0
  126. package/dist/index.d.ts.map +1 -1
  127. package/dist/index.js +230 -222
  128. package/dist/index.js.map +1 -1
  129. package/dist/integration/CustomColumnPromoter.d.ts.map +1 -1
  130. package/dist/integration/CustomColumnPromoter.js +6 -1
  131. package/dist/integration/CustomColumnPromoter.js.map +1 -1
  132. package/dist/logging/variablesLoggingMiddleware.d.ts +12 -0
  133. package/dist/logging/variablesLoggingMiddleware.d.ts.map +1 -1
  134. package/dist/logging/variablesLoggingMiddleware.js +50 -1
  135. package/dist/logging/variablesLoggingMiddleware.js.map +1 -1
  136. package/dist/multiTenancy/index.d.ts.map +1 -1
  137. package/dist/multiTenancy/index.js +22 -2
  138. package/dist/multiTenancy/index.js.map +1 -1
  139. package/dist/realtimeSessions/RealtimeSessionVerificationService.d.ts.map +1 -1
  140. package/dist/realtimeSessions/RealtimeSessionVerificationService.js +2 -1
  141. package/dist/realtimeSessions/RealtimeSessionVerificationService.js.map +1 -1
  142. package/dist/realtimeSessions/RealtimeVerifyRouter.d.ts.map +1 -1
  143. package/dist/realtimeSessions/RealtimeVerifyRouter.js +2 -1
  144. package/dist/realtimeSessions/RealtimeVerifyRouter.js.map +1 -1
  145. package/dist/realtimeSessions/RecordingAssemblyScheduler.d.ts +100 -0
  146. package/dist/realtimeSessions/RecordingAssemblyScheduler.d.ts.map +1 -0
  147. package/dist/realtimeSessions/RecordingAssemblyScheduler.js +173 -0
  148. package/dist/realtimeSessions/RecordingAssemblyScheduler.js.map +1 -0
  149. package/dist/realtimeSessions/SessionVerificationPortsBase.d.ts.map +1 -1
  150. package/dist/realtimeSessions/SessionVerificationPortsBase.js +1 -0
  151. package/dist/realtimeSessions/SessionVerificationPortsBase.js.map +1 -1
  152. package/dist/realtimeSessions/index.d.ts +2 -0
  153. package/dist/realtimeSessions/index.d.ts.map +1 -1
  154. package/dist/realtimeSessions/index.js +2 -0
  155. package/dist/realtimeSessions/index.js.map +1 -1
  156. package/dist/realtimeSessions/ownedRealtimeSession.d.ts +32 -0
  157. package/dist/realtimeSessions/ownedRealtimeSession.d.ts.map +1 -0
  158. package/dist/realtimeSessions/ownedRealtimeSession.js +56 -0
  159. package/dist/realtimeSessions/ownedRealtimeSession.js.map +1 -0
  160. package/dist/realtimeSessions/sessionAccess.d.ts +91 -8
  161. package/dist/realtimeSessions/sessionAccess.d.ts.map +1 -1
  162. package/dist/realtimeSessions/sessionAccess.js +127 -20
  163. package/dist/realtimeSessions/sessionAccess.js.map +1 -1
  164. package/dist/realtimeSessions/sessionConfigStamps.js +1 -1
  165. package/dist/realtimeSessions/sessionConfigStamps.js.map +1 -1
  166. package/dist/realtimeSessions/subscriptionAuthorization.d.ts.map +1 -1
  167. package/dist/realtimeSessions/subscriptionAuthorization.js +5 -2
  168. package/dist/realtimeSessions/subscriptionAuthorization.js.map +1 -1
  169. package/dist/realtimeSessions/verificationWorkflow.d.ts +2 -0
  170. package/dist/realtimeSessions/verificationWorkflow.d.ts.map +1 -1
  171. package/dist/realtimeSessions/verificationWorkflow.js +1 -1
  172. package/dist/realtimeSessions/verificationWorkflow.js.map +1 -1
  173. package/dist/realtimeWidget/WidgetRouter.d.ts.map +1 -1
  174. package/dist/realtimeWidget/WidgetRouter.js +19 -3
  175. package/dist/realtimeWidget/WidgetRouter.js.map +1 -1
  176. package/dist/realtimeWidget/WidgetSessionService.d.ts +67 -7
  177. package/dist/realtimeWidget/WidgetSessionService.d.ts.map +1 -1
  178. package/dist/realtimeWidget/WidgetSessionService.js +201 -19
  179. package/dist/realtimeWidget/WidgetSessionService.js.map +1 -1
  180. package/dist/realtimeWidget/host-identity.d.ts +1 -1
  181. package/dist/realtimeWidget/host-identity.js +1 -1
  182. package/dist/realtimeWidget/widgetCore.d.ts +20 -1
  183. package/dist/realtimeWidget/widgetCore.d.ts.map +1 -1
  184. package/dist/realtimeWidget/widgetCore.js +17 -1
  185. package/dist/realtimeWidget/widgetCore.js.map +1 -1
  186. package/dist/realtimeWidget/widgetGuestElevation.d.ts +1 -1
  187. package/dist/realtimeWidget/widgetGuestElevation.d.ts.map +1 -1
  188. package/dist/realtimeWidget/widgetGuestElevation.js +2 -1
  189. package/dist/realtimeWidget/widgetGuestElevation.js.map +1 -1
  190. package/dist/resolvers/ActionResolver.d.ts +19 -1
  191. package/dist/resolvers/ActionResolver.d.ts.map +1 -1
  192. package/dist/resolvers/ActionResolver.js +63 -12
  193. package/dist/resolvers/ActionResolver.js.map +1 -1
  194. package/dist/resolvers/AdhocQueryResolver.d.ts.map +1 -1
  195. package/dist/resolvers/AdhocQueryResolver.js +1 -0
  196. package/dist/resolvers/AdhocQueryResolver.js.map +1 -1
  197. package/dist/resolvers/AgentRunStatusPublisher.d.ts +18 -4
  198. package/dist/resolvers/AgentRunStatusPublisher.d.ts.map +1 -1
  199. package/dist/resolvers/AgentRunStatusPublisher.js +32 -8
  200. package/dist/resolvers/AgentRunStatusPublisher.js.map +1 -1
  201. package/dist/resolvers/AgentSessionResolver.d.ts +10 -4
  202. package/dist/resolvers/AgentSessionResolver.d.ts.map +1 -1
  203. package/dist/resolvers/AgentSessionResolver.js +40 -17
  204. package/dist/resolvers/AgentSessionResolver.js.map +1 -1
  205. package/dist/resolvers/ArtifactFileResolver.d.ts +5 -1
  206. package/dist/resolvers/ArtifactFileResolver.d.ts.map +1 -1
  207. package/dist/resolvers/ArtifactFileResolver.js +9 -7
  208. package/dist/resolvers/ArtifactFileResolver.js.map +1 -1
  209. package/dist/resolvers/ConversationRunEventsResolver.d.ts +8 -4
  210. package/dist/resolvers/ConversationRunEventsResolver.d.ts.map +1 -1
  211. package/dist/resolvers/ConversationRunEventsResolver.js +6 -6
  212. package/dist/resolvers/ConversationRunEventsResolver.js.map +1 -1
  213. package/dist/resolvers/DatasetResolver.d.ts +24 -3
  214. package/dist/resolvers/DatasetResolver.d.ts.map +1 -1
  215. package/dist/resolvers/DatasetResolver.js +57 -8
  216. package/dist/resolvers/DatasetResolver.js.map +1 -1
  217. package/dist/resolvers/EntityCommunicationsResolver.d.ts +13 -1
  218. package/dist/resolvers/EntityCommunicationsResolver.d.ts.map +1 -1
  219. package/dist/resolvers/EntityCommunicationsResolver.js +50 -14
  220. package/dist/resolvers/EntityCommunicationsResolver.js.map +1 -1
  221. package/dist/resolvers/EntityRecordNameResolver.d.ts +2 -1
  222. package/dist/resolvers/EntityRecordNameResolver.d.ts.map +1 -1
  223. package/dist/resolvers/EntityRecordNameResolver.js +3 -2
  224. package/dist/resolvers/EntityRecordNameResolver.js.map +1 -1
  225. package/dist/resolvers/FetchEntityVectorsResolver.d.ts +46 -3
  226. package/dist/resolvers/FetchEntityVectorsResolver.d.ts.map +1 -1
  227. package/dist/resolvers/FetchEntityVectorsResolver.js +211 -50
  228. package/dist/resolvers/FetchEntityVectorsResolver.js.map +1 -1
  229. package/dist/resolvers/FileCategoryResolver.d.ts.map +1 -1
  230. package/dist/resolvers/FileCategoryResolver.js +1 -0
  231. package/dist/resolvers/FileCategoryResolver.js.map +1 -1
  232. package/dist/resolvers/FileResolver.d.ts +87 -11
  233. package/dist/resolvers/FileResolver.d.ts.map +1 -1
  234. package/dist/resolvers/FileResolver.js +292 -105
  235. package/dist/resolvers/FileResolver.js.map +1 -1
  236. package/dist/resolvers/GetDataContextDataResolver.d.ts +33 -7
  237. package/dist/resolvers/GetDataContextDataResolver.d.ts.map +1 -1
  238. package/dist/resolvers/GetDataContextDataResolver.js +117 -38
  239. package/dist/resolvers/GetDataContextDataResolver.js.map +1 -1
  240. package/dist/resolvers/GetDataResolver.d.ts.map +1 -1
  241. package/dist/resolvers/GetDataResolver.js +6 -3
  242. package/dist/resolvers/GetDataResolver.js.map +1 -1
  243. package/dist/resolvers/IntegrationDiscoveryResolver.d.ts.map +1 -1
  244. package/dist/resolvers/IntegrationDiscoveryResolver.js +49 -9
  245. package/dist/resolvers/IntegrationDiscoveryResolver.js.map +1 -1
  246. package/dist/resolvers/MergeRecordsResolver.d.ts +8 -1
  247. package/dist/resolvers/MergeRecordsResolver.d.ts.map +1 -1
  248. package/dist/resolvers/MergeRecordsResolver.js +31 -3
  249. package/dist/resolvers/MergeRecordsResolver.js.map +1 -1
  250. package/dist/resolvers/PipelineProgressResolver.d.ts +6 -0
  251. package/dist/resolvers/PipelineProgressResolver.d.ts.map +1 -1
  252. package/dist/resolvers/PipelineProgressResolver.js +5 -3
  253. package/dist/resolvers/PipelineProgressResolver.js.map +1 -1
  254. package/dist/resolvers/QueryResolver.d.ts +2 -0
  255. package/dist/resolvers/QueryResolver.d.ts.map +1 -1
  256. package/dist/resolvers/QueryResolver.js +33 -6
  257. package/dist/resolvers/QueryResolver.js.map +1 -1
  258. package/dist/resolvers/QuerySystemUserResolver.d.ts +2 -0
  259. package/dist/resolvers/QuerySystemUserResolver.d.ts.map +1 -1
  260. package/dist/resolvers/QuerySystemUserResolver.js +15 -6
  261. package/dist/resolvers/QuerySystemUserResolver.js.map +1 -1
  262. package/dist/resolvers/RSUResolver.d.ts.map +1 -1
  263. package/dist/resolvers/RSUResolver.js +12 -0
  264. package/dist/resolvers/RSUResolver.js.map +1 -1
  265. package/dist/resolvers/RealtimeClientSessionResolver.d.ts +18 -10
  266. package/dist/resolvers/RealtimeClientSessionResolver.d.ts.map +1 -1
  267. package/dist/resolvers/RealtimeClientSessionResolver.js +92 -54
  268. package/dist/resolvers/RealtimeClientSessionResolver.js.map +1 -1
  269. package/dist/resolvers/RemoteBrowserActionResolver.d.ts.map +1 -1
  270. package/dist/resolvers/RemoteBrowserActionResolver.js +11 -9
  271. package/dist/resolvers/RemoteBrowserActionResolver.js.map +1 -1
  272. package/dist/resolvers/RunAIAgentResolver.d.ts +56 -8
  273. package/dist/resolvers/RunAIAgentResolver.d.ts.map +1 -1
  274. package/dist/resolvers/RunAIAgentResolver.js +241 -67
  275. package/dist/resolvers/RunAIAgentResolver.js.map +1 -1
  276. package/dist/resolvers/RunTemplateResolver.d.ts.map +1 -1
  277. package/dist/resolvers/RunTemplateResolver.js +4 -4
  278. package/dist/resolvers/RunTemplateResolver.js.map +1 -1
  279. package/dist/resolvers/RunTestResolver.d.ts.map +1 -1
  280. package/dist/resolvers/RunTestResolver.js +3 -1
  281. package/dist/resolvers/RunTestResolver.js.map +1 -1
  282. package/dist/resolvers/SearchKnowledgeStreamResolver.d.ts +12 -1
  283. package/dist/resolvers/SearchKnowledgeStreamResolver.d.ts.map +1 -1
  284. package/dist/resolvers/SearchKnowledgeStreamResolver.js +15 -2
  285. package/dist/resolvers/SearchKnowledgeStreamResolver.js.map +1 -1
  286. package/dist/resolvers/SqlLoggingConfigResolver.d.ts.map +1 -1
  287. package/dist/resolvers/SqlLoggingConfigResolver.js +2 -3
  288. package/dist/resolvers/SqlLoggingConfigResolver.js.map +1 -1
  289. package/dist/resolvers/SyncDataResolver.d.ts.map +1 -1
  290. package/dist/resolvers/SyncDataResolver.js +4 -0
  291. package/dist/resolvers/SyncDataResolver.js.map +1 -1
  292. package/dist/resolvers/TaskGraphFrameResolver.d.ts +2 -1
  293. package/dist/resolvers/TaskGraphFrameResolver.d.ts.map +1 -1
  294. package/dist/resolvers/TaskGraphFrameResolver.js +28 -1
  295. package/dist/resolvers/TaskGraphFrameResolver.js.map +1 -1
  296. package/dist/resolvers/TestQuerySQLResolver.d.ts +24 -0
  297. package/dist/resolvers/TestQuerySQLResolver.d.ts.map +1 -1
  298. package/dist/resolvers/TestQuerySQLResolver.js +66 -13
  299. package/dist/resolvers/TestQuerySQLResolver.js.map +1 -1
  300. package/dist/resolvers/TransactionGroupResolver.d.ts +34 -2
  301. package/dist/resolvers/TransactionGroupResolver.d.ts.map +1 -1
  302. package/dist/resolvers/TransactionGroupResolver.js +150 -27
  303. package/dist/resolvers/TransactionGroupResolver.js.map +1 -1
  304. package/dist/resolvers/UserViewResolver.d.ts +1 -1
  305. package/dist/resolvers/UserViewResolver.d.ts.map +1 -1
  306. package/dist/resolvers/UserViewResolver.js +2 -1
  307. package/dist/resolvers/UserViewResolver.js.map +1 -1
  308. package/dist/resolvers/agent-run-data-guard.d.ts +31 -0
  309. package/dist/resolvers/agent-run-data-guard.d.ts.map +1 -0
  310. package/dist/resolvers/agent-run-data-guard.js +72 -0
  311. package/dist/resolvers/agent-run-data-guard.js.map +1 -0
  312. package/dist/rest/EntityCRUDHandler.d.ts +6 -0
  313. package/dist/rest/EntityCRUDHandler.d.ts.map +1 -1
  314. package/dist/rest/EntityCRUDHandler.js +19 -5
  315. package/dist/rest/EntityCRUDHandler.js.map +1 -1
  316. package/dist/rest/RESTEndpointHandler.d.ts.map +1 -1
  317. package/dist/rest/RESTEndpointHandler.js +8 -5
  318. package/dist/rest/RESTEndpointHandler.js.map +1 -1
  319. package/dist/rest/RealtimeRecordingHandler.d.ts +49 -0
  320. package/dist/rest/RealtimeRecordingHandler.d.ts.map +1 -0
  321. package/dist/rest/RealtimeRecordingHandler.js +383 -0
  322. package/dist/rest/RealtimeRecordingHandler.js.map +1 -0
  323. package/dist/rest/ViewOperationsHandler.d.ts +9 -1
  324. package/dist/rest/ViewOperationsHandler.d.ts.map +1 -1
  325. package/dist/rest/ViewOperationsHandler.js +43 -17
  326. package/dist/rest/ViewOperationsHandler.js.map +1 -1
  327. package/dist/rest/setupRESTEndpoints.d.ts +6 -0
  328. package/dist/rest/setupRESTEndpoints.d.ts.map +1 -1
  329. package/dist/rest/setupRESTEndpoints.js +6 -0
  330. package/dist/rest/setupRESTEndpoints.js.map +1 -1
  331. package/dist/serverExtensionReservedRoots.d.ts +12 -10
  332. package/dist/serverExtensionReservedRoots.d.ts.map +1 -1
  333. package/dist/serverExtensionReservedRoots.js +14 -17
  334. package/dist/serverExtensionReservedRoots.js.map +1 -1
  335. package/dist/serverRoleConfigUnits.d.ts +29 -0
  336. package/dist/serverRoleConfigUnits.d.ts.map +1 -0
  337. package/dist/serverRoleConfigUnits.js +33 -0
  338. package/dist/serverRoleConfigUnits.js.map +1 -0
  339. package/dist/services/MJStorageBlobStore.d.ts +8 -1
  340. package/dist/services/MJStorageBlobStore.d.ts.map +1 -1
  341. package/dist/services/MJStorageBlobStore.js +25 -19
  342. package/dist/services/MJStorageBlobStore.js.map +1 -1
  343. package/dist/services/StartTaskGraphDispatcher.js +2 -2
  344. package/dist/services/StartTaskGraphDispatcher.js.map +1 -1
  345. package/dist/services/TaskGraphActionRunner.d.ts +5 -3
  346. package/dist/services/TaskGraphActionRunner.d.ts.map +1 -1
  347. package/dist/services/TaskGraphActionRunner.js +27 -5
  348. package/dist/services/TaskGraphActionRunner.js.map +1 -1
  349. package/dist/services/TaskGraphAgentRunner.d.ts +14 -2
  350. package/dist/services/TaskGraphAgentRunner.d.ts.map +1 -1
  351. package/dist/services/TaskGraphAgentRunner.js +157 -9
  352. package/dist/services/TaskGraphAgentRunner.js.map +1 -1
  353. package/dist/services/TaskGraphContinuationDeliverer.d.ts +59 -2
  354. package/dist/services/TaskGraphContinuationDeliverer.d.ts.map +1 -1
  355. package/dist/services/TaskGraphContinuationDeliverer.js +626 -16
  356. package/dist/services/TaskGraphContinuationDeliverer.js.map +1 -1
  357. package/dist/sharedCache.d.ts.map +1 -1
  358. package/dist/sharedCache.js +3 -0
  359. package/dist/sharedCache.js.map +1 -1
  360. package/dist/types.d.ts +23 -1
  361. package/dist/types.d.ts.map +1 -1
  362. package/dist/types.js.map +1 -1
  363. package/package.json +99 -98
  364. package/src/__tests__/ActionResolver.fieldSecurity.test.ts +237 -0
  365. package/src/__tests__/AdhocQueryResolver.dialect.test.ts +137 -0
  366. package/src/__tests__/AgentRunStatusPublisher.test.ts +49 -0
  367. package/src/__tests__/AgentSessionResolver.ownership.test.ts +137 -0
  368. package/src/__tests__/CustomColumnPromoterOnePass.test.ts +15 -1
  369. package/src/__tests__/DatasetResolver.itemFilters.test.ts +201 -0
  370. package/src/__tests__/EntityCommunicationsResolver.actingUser.test.ts +151 -0
  371. package/src/__tests__/EntityRecordNameResolver.rowSecurity.test.ts +152 -0
  372. package/src/__tests__/EvolutionActsOnWhatItDetects.test.ts +113 -0
  373. package/src/__tests__/FetchEntityVectorsResolver.test.ts +369 -18
  374. package/src/__tests__/FileResolver.fieldSecurity.test.ts +82 -0
  375. package/src/__tests__/FileResolver.storageAccess.test.ts +562 -0
  376. package/src/__tests__/GetDataContextDataResolver.sqlItems.test.ts +416 -0
  377. package/src/__tests__/ListOperationsResolver.adhocScreen.test.ts +137 -0
  378. package/src/__tests__/LoginScreenEngine.test.ts +86 -0
  379. package/src/__tests__/MJStorageBlobStore.storageGate.test.ts +63 -0
  380. package/src/__tests__/PipelineProgressResolver.filter.test.ts +58 -0
  381. package/src/__tests__/QuerySystemUserResolver.fieldSecurity.test.ts +49 -0
  382. package/src/__tests__/RESTEndpointHandler.test.ts +25 -0
  383. package/src/__tests__/RealtimeClientSessionResolver.configTamper.test.ts +23 -3
  384. package/src/__tests__/RealtimeClientSessionResolver.test.ts +324 -46
  385. package/src/__tests__/RecordingAssemblyScheduler.test.ts +178 -0
  386. package/src/__tests__/RemoteBrowserActionResolver.ownership.test.ts +98 -0
  387. package/src/__tests__/ResolverBase.adhocReadScope.test.ts +133 -2
  388. package/src/__tests__/ResolverBase.balancedClause.test.ts +155 -0
  389. package/src/__tests__/ResolverBase.clauseUnscopedRead.test.ts +127 -0
  390. package/src/__tests__/ResolverBase.clientOldValues.test.ts +243 -7
  391. package/src/__tests__/ResolverBase.deleteReturnProjection.test.ts +52 -0
  392. package/src/__tests__/ResolverBase.entityMessageRelay.test.ts +176 -0
  393. package/src/__tests__/ResolverBase.filterEscaping.test.ts +5 -2
  394. package/src/__tests__/ResolverBase.includeBinaryFields.test.ts +23 -1
  395. package/src/__tests__/ResolverBase.publishStatusUpdate.test.ts +68 -0
  396. package/src/__tests__/ResolverBase.userViewCacheAndDedup.test.ts +130 -0
  397. package/src/__tests__/RunAIAgentResolver.branch.test.ts +69 -13
  398. package/src/__tests__/RunAIAgentResolver.conversationWriter.test.ts +210 -0
  399. package/src/__tests__/RunAIAgentResolver.fireAndForgetCompletion.test.ts +209 -0
  400. package/src/__tests__/RunAIAgentResolver.historyFrom.test.ts +20 -28
  401. package/src/__tests__/RunAIAgentResolver.runDataGuard.test.ts +264 -0
  402. package/src/__tests__/RunAIAgentResolver.serverReply.test.ts +358 -0
  403. package/src/__tests__/RunAIAgentResolver.stoppedPredecessor.test.ts +4 -1
  404. package/src/__tests__/RunTemplateResolver.test.ts +35 -2
  405. package/src/__tests__/RunViewResolver.cacheCheckForwarding.test.ts +11 -0
  406. package/src/__tests__/RunViewResolver.cacheCheckScreen.test.ts +165 -0
  407. package/src/__tests__/SearchKnowledgeStreamResolver.test.ts +161 -0
  408. package/src/__tests__/SessionJanitor.test.ts +365 -10
  409. package/src/__tests__/SessionManager.test.ts +122 -0
  410. package/src/__tests__/TaskGraphActionRunner.durablePayload.test.ts +25 -0
  411. package/src/__tests__/TaskGraphAgentRunner.test.ts +266 -0
  412. package/src/__tests__/TaskGraphContinuationDeliverer.test.ts +468 -23
  413. package/src/__tests__/TaskGraphFrameResolver.test.ts +22 -0
  414. package/src/__tests__/TestQuerySQLResolver.test.ts +274 -0
  415. package/src/__tests__/TransactionGroupResolver.fieldSecurity.test.ts +199 -0
  416. package/src/__tests__/TransactionGroupResolver.refusals.test.ts +98 -1
  417. package/src/__tests__/UpdateMJDataContextItem.oldValues.test.ts +220 -0
  418. package/src/__tests__/UserViewResolver.updateWhereClause.test.ts +15 -0
  419. package/src/__tests__/ViewOperationsHandler.clauseScreen.test.ts +157 -0
  420. package/src/__tests__/ViewOperationsHandler.test.ts +7 -2
  421. package/src/__tests__/WidgetSessionService.test.ts +583 -4
  422. package/src/__tests__/agent-run-data-guard.test.ts +130 -0
  423. package/src/__tests__/apiRootBoot.test.ts +202 -0
  424. package/src/__tests__/buildMagicLinkSessionUser.test.ts +96 -0
  425. package/src/__tests__/cacheBroadcastProviders.test.ts +403 -0
  426. package/src/__tests__/cacheInvalidationRecordData.test.ts +109 -0
  427. package/src/__tests__/conversationRunEvents.test.ts +56 -14
  428. package/src/__tests__/fieldSecurityFixtures.ts +91 -0
  429. package/src/__tests__/globalCors.test.ts +217 -0
  430. package/src/__tests__/localDevAuth.test.ts +196 -0
  431. package/src/__tests__/multiTenancy.postgresRewrite.test.ts +181 -0
  432. package/src/__tests__/multiTenancy.security.test.ts +51 -0
  433. package/src/__tests__/multiTenancy.test.ts +1 -1
  434. package/src/__tests__/orphanedConversationDetailReconciler.test.ts +10 -0
  435. package/src/__tests__/ownedRealtimeSession.test.ts +39 -0
  436. package/src/__tests__/pushStatusResolver.filter.test.ts +64 -1
  437. package/src/__tests__/realtimeRecordingHandler.test.ts +669 -0
  438. package/src/__tests__/realtimeSessions/RealtimeSessionEventsResolver.test.ts +29 -1
  439. package/src/__tests__/realtimeSessions/ownedRealtimeSession.anonymous.test.ts +31 -0
  440. package/src/__tests__/realtimeSessions/ownedRealtimeSession.namedScoped.test.ts +37 -0
  441. package/src/__tests__/realtimeSessions/sessionAccess.test.ts +146 -7
  442. package/src/__tests__/realtimeSessions/sessionConfigStamps.test.ts +1 -1
  443. package/src/__tests__/realtimeSessions/verificationWorkflow.test.ts +25 -4
  444. package/src/__tests__/resolverBase.cloudEventChangedFields.test.ts +157 -0
  445. package/src/__tests__/resolverBase.fieldSecurityTransport.test.ts +222 -0
  446. package/src/__tests__/resolverBase.fls.test.ts +146 -97
  447. package/src/__tests__/restTransport.fieldSecurity.test.ts +148 -0
  448. package/src/__tests__/runParamsTimeZone.test.ts +179 -0
  449. package/src/__tests__/runStreams.fieldSecurity.test.ts +100 -0
  450. package/src/__tests__/runViewProperties.test.ts +114 -0
  451. package/src/__tests__/scalabilityBenchmarks.test.ts +765 -0
  452. package/src/__tests__/scalabilityDatabaseIntegration.test.ts +207 -0
  453. package/src/__tests__/serverExtensionHostOverlay.test.ts +66 -0
  454. package/src/__tests__/serverExtensionReservedRoots.test.ts +11 -98
  455. package/src/__tests__/sessionUserClone.test.ts +5 -1
  456. package/src/__tests__/sharedCache.test.ts +5 -3
  457. package/src/__tests__/startupSweepOrder.test.ts +40 -0
  458. package/src/__tests__/unifiedAuth.test.ts +28 -0
  459. package/src/__tests__/widgetGuestElevation.test.ts +2 -0
  460. package/src/agentSessions/SessionJanitor.ts +369 -93
  461. package/src/agentSessions/SessionManager.ts +45 -10
  462. package/src/apiRoot.ts +78 -0
  463. package/src/auth/AuthProviderCatalogRouter.ts +29 -0
  464. package/src/auth/LoginScreenEngine.ts +50 -0
  465. package/src/auth/index.ts +57 -12
  466. package/src/auth/initializeProviders.ts +43 -1
  467. package/src/auth/localDevAuth.ts +528 -0
  468. package/src/auth/magicLink/MagicLinkKeys.ts +2 -2
  469. package/src/auth/magicLink/MagicLinkRouter.ts +3 -2
  470. package/src/auth/magicLink/types.ts +10 -0
  471. package/src/auth/sessionUserClone.ts +3 -2
  472. package/src/broadcast/BaseCacheInvalidationBroadcastProvider.ts +674 -0
  473. package/src/broadcast/index.ts +5 -0
  474. package/src/broadcast/providers/AWSIoTCoreBroadcastProvider.ts +180 -0
  475. package/src/broadcast/providers/AzureWebPubSubBroadcastProvider.ts +182 -0
  476. package/src/broadcast/providers/GCPPubSubBroadcastProvider.ts +169 -0
  477. package/src/broadcast/providers/SequencedRoleBucketBroadcastProvider.ts +57 -0
  478. package/src/cache.ts +2 -1
  479. package/src/config.ts +115 -5
  480. package/src/context.ts +32 -8
  481. package/src/coreRoutes.ts +181 -0
  482. package/src/generated/graphql-schemas/__mj.ts +3684 -284
  483. package/src/generic/CacheInvalidationResolver.ts +172 -60
  484. package/src/generic/OrphanedConversationDetailReconciler.ts +4 -2
  485. package/src/generic/PubSubManager.ts +54 -1
  486. package/src/generic/PushStatusResolver.ts +109 -12
  487. package/src/generic/ResolverBase.ts +540 -431
  488. package/src/generic/RunViewResolver.ts +97 -15
  489. package/src/generic/actionOutputFieldSecurity.ts +75 -0
  490. package/src/generic/fieldSecurityTransport.ts +62 -0
  491. package/src/globalCors.ts +71 -0
  492. package/src/index.ts +239 -238
  493. package/src/integration/CustomColumnPromoter.ts +6 -1
  494. package/src/logging/variablesLoggingMiddleware.ts +59 -3
  495. package/src/multiTenancy/index.ts +24 -2
  496. package/src/realtimeSessions/README.md +7 -3
  497. package/src/realtimeSessions/RealtimeSessionVerificationService.ts +2 -1
  498. package/src/realtimeSessions/RealtimeVerifyRouter.ts +2 -1
  499. package/src/realtimeSessions/RecordingAssemblyScheduler.ts +234 -0
  500. package/src/realtimeSessions/SessionVerificationPortsBase.ts +1 -0
  501. package/src/realtimeSessions/index.ts +2 -0
  502. package/src/realtimeSessions/ownedRealtimeSession.ts +69 -0
  503. package/src/realtimeSessions/sessionAccess.ts +183 -23
  504. package/src/realtimeSessions/sessionConfigStamps.ts +1 -1
  505. package/src/realtimeSessions/subscriptionAuthorization.ts +4 -2
  506. package/src/realtimeSessions/verificationWorkflow.ts +3 -1
  507. package/src/realtimeWidget/WidgetRouter.ts +22 -4
  508. package/src/realtimeWidget/WidgetSessionService.ts +252 -17
  509. package/src/realtimeWidget/host-identity.ts +1 -1
  510. package/src/realtimeWidget/widgetCore.ts +30 -1
  511. package/src/realtimeWidget/widgetGuestElevation.ts +2 -1
  512. package/src/resolvers/ActionResolver.ts +78 -15
  513. package/src/resolvers/AdhocQueryResolver.ts +1 -0
  514. package/src/resolvers/AgentRunStatusPublisher.ts +36 -8
  515. package/src/resolvers/AgentSessionResolver.ts +46 -18
  516. package/src/resolvers/ArtifactFileResolver.ts +9 -8
  517. package/src/resolvers/ConversationRunEventsResolver.ts +15 -11
  518. package/src/resolvers/DatasetResolver.ts +70 -10
  519. package/src/resolvers/EntityCommunicationsResolver.ts +56 -15
  520. package/src/resolvers/EntityRecordNameResolver.ts +3 -2
  521. package/src/resolvers/FetchEntityVectorsResolver.ts +248 -55
  522. package/src/resolvers/FileCategoryResolver.ts +1 -0
  523. package/src/resolvers/FileResolver.ts +334 -109
  524. package/src/resolvers/GetDataContextDataResolver.ts +139 -41
  525. package/src/resolvers/GetDataResolver.ts +6 -3
  526. package/src/resolvers/IntegrationDiscoveryResolver.ts +53 -9
  527. package/src/resolvers/MergeRecordsResolver.ts +23 -2
  528. package/src/resolvers/PipelineProgressResolver.ts +12 -3
  529. package/src/resolvers/QueryResolver.ts +31 -6
  530. package/src/resolvers/QuerySystemUserResolver.ts +15 -6
  531. package/src/resolvers/RSUResolver.ts +12 -0
  532. package/src/resolvers/RealtimeClientSessionResolver.ts +114 -66
  533. package/src/resolvers/RemoteBrowserActionResolver.ts +15 -10
  534. package/src/resolvers/RunAIAgentResolver.ts +296 -85
  535. package/src/resolvers/RunTemplateResolver.ts +6 -4
  536. package/src/resolvers/RunTestResolver.ts +3 -1
  537. package/src/resolvers/SearchKnowledgeStreamResolver.ts +19 -3
  538. package/src/resolvers/SqlLoggingConfigResolver.ts +2 -4
  539. package/src/resolvers/SyncDataResolver.ts +4 -0
  540. package/src/resolvers/TaskGraphFrameResolver.ts +33 -1
  541. package/src/resolvers/TestQuerySQLResolver.ts +69 -13
  542. package/src/resolvers/TransactionGroupResolver.ts +185 -30
  543. package/src/resolvers/UserViewResolver.ts +2 -1
  544. package/src/resolvers/__tests__/GetDataResolver.validation.test.ts +95 -0
  545. package/src/resolvers/__tests__/MergeRecordsResolver.test.ts +43 -0
  546. package/src/resolvers/agent-run-data-guard.ts +89 -0
  547. package/src/rest/EntityCRUDHandler.ts +22 -5
  548. package/src/rest/RESTEndpointHandler.ts +8 -5
  549. package/src/rest/RealtimeRecordingHandler.ts +467 -0
  550. package/src/rest/ViewOperationsHandler.ts +52 -18
  551. package/src/rest/setupRESTEndpoints.ts +6 -0
  552. package/src/serverExtensionReservedRoots.ts +14 -17
  553. package/src/serverRoleConfigUnits.ts +48 -0
  554. package/src/services/MJStorageBlobStore.ts +31 -30
  555. package/src/services/StartTaskGraphDispatcher.ts +2 -2
  556. package/src/services/TaskGraphActionRunner.ts +25 -5
  557. package/src/services/TaskGraphAgentRunner.ts +188 -11
  558. package/src/services/TaskGraphContinuationDeliverer.ts +738 -16
  559. package/src/sharedCache.ts +3 -0
  560. package/src/types.ts +23 -1
@@ -9,40 +9,69 @@
9
9
  * compare-and-swap that marks a completion delivered; an escaping error would either abort that
10
10
  * guard or leave the graph looking undelivered and re-notifying on every later sweep.
11
11
  */
12
+ import 'reflect-metadata';
12
13
  import { describe, it, expect, vi, beforeEach } from 'vitest';
13
14
 
15
+ const { fromMetadataProvider, runAgent, processAgentArtifacts } = vi.hoisted(() => ({
16
+ fromMetadataProvider: vi.fn(),
17
+ runAgent: vi.fn(),
18
+ processAgentArtifacts: vi.fn(),
19
+ }));
20
+
14
21
  vi.mock('@memberjunction/core', () => ({
15
22
  LogError: vi.fn(),
16
23
  LogStatus: vi.fn(),
24
+ RunView: {
25
+ FromMetadataProvider: fromMetadataProvider,
26
+ },
27
+ }));
28
+
29
+ const { OWNER, SUBMITTER } = vi.hoisted(() => ({ OWNER: { ID: 'owner-1' }, SUBMITTER: { ID: 'submitter-1' } }));
30
+ vi.mock('@memberjunction/generic-database-provider', () => ({
31
+ UserCache: {
32
+ Instance: { Users: [OWNER, SUBMITTER, { ID: 'owner-user-99', Email: 'owner@example.com' }] },
33
+ Users: [OWNER, SUBMITTER, { ID: 'owner-user-99', Email: 'owner@example.com' }],
34
+ },
17
35
  }));
18
36
 
19
37
  vi.mock('@memberjunction/core-entities', () => ({
20
38
  MJConversationDetailEntity: class {},
39
+ MJConversationDetailEntityExtended: class {},
40
+ MJConversationEntity: class {},
21
41
  MJAIAgentRunEntity: class {},
22
42
  }));
23
43
 
24
44
  vi.mock('@memberjunction/ai-core-plus', () => ({ MJAIAgentEntityExtended: class {} }));
25
45
  vi.mock('@memberjunction/ai', () => ({ ChatMessageRole: { user: 'user' } }));
26
46
 
27
- const runAgent = vi.fn().mockResolvedValue({ success: true });
28
47
  vi.mock('@memberjunction/ai-agents', () => ({
29
- AgentRunner: class { RunAgent = runAgent; },
48
+ AgentRunner: class {
49
+ RunAgent = runAgent;
50
+ ProcessAgentArtifacts = processAgentArtifacts;
51
+ },
30
52
  }));
31
53
 
32
54
  import { TaskGraphContinuationDeliverer } from '../services/TaskGraphContinuationDeliverer';
33
55
  import type { TaskContinuationParams } from '@memberjunction/task-graph';
34
56
  import type { UserInfo } from '@memberjunction/core';
57
+ import type { PubSubEngine } from 'type-graphql';
35
58
 
36
59
  /** A conversation-detail row that can be loaded (the source) and saved (the reply). */
37
60
  function detailRow(over: Partial<{ loads: boolean; saves: boolean; conversationID: string; branchID: string | null }> = {}) {
38
61
  const { loads = true, saves = true, conversationID = 'conv-1', branchID = null } = over;
62
+ let marked = false;
39
63
  return {
64
+ ID: 'reply-detail-1',
40
65
  ConversationID: conversationID,
41
66
  BranchID: branchID as string | null,
67
+ UserID: 'owner-1',
42
68
  Role: '', Status: '', HiddenToUser: true, Message: '',
69
+ AgentID: null as string | null,
43
70
  NewRecord: vi.fn(),
71
+ MarkServerAuthoredReply: vi.fn(() => { marked = true; }),
44
72
  Load: vi.fn().mockResolvedValue(loads),
45
- Save: vi.fn().mockResolvedValue(saves),
73
+ // Like MJConversationDetailEntityExtended, refuses to save an unmarked AI reply.
74
+ Save: vi.fn().mockImplementation(async () => saves && marked),
46
75
  LatestResult: { CompleteMessage: 'FK violation' },
47
76
  };
48
77
  }
@@ -60,13 +89,15 @@ function harness(over: Parameters<typeof detailRow>[0] = {}) {
60
89
  }),
61
90
  };
62
91
  const providerFactory = { CreateProvider: vi.fn().mockResolvedValue(provider) };
92
+ const pubSub = { publish: vi.fn().mockResolvedValue(undefined) } as unknown as PubSubEngine;
63
93
  const deliverer = new TaskGraphContinuationDeliverer(
64
94
  providerFactory as never,
65
95
  { ID: 'user-1' } as UserInfo,
96
+ pubSub,
66
97
  );
67
- // First row is the source detail (Load), second is the reply (Save). Every reply row starts on a
68
- // 'stale' fork, so a test sees the deliverer set it.
69
- return { deliverer, providerFactory, provider, rows, reply: () => rows[1] };
98
+ // Rows in order: the source detail (Load), the reply (Save). The reply starts on a 'stale' fork, so a test sees
99
+ // the deliverer set it.
100
+ return { deliverer, providerFactory, provider, rows, pubSub, reply: () => rows[1] };
70
101
  }
71
102
 
72
103
  const params = (over: Partial<TaskContinuationParams> = {}): TaskContinuationParams => ({
@@ -74,6 +105,7 @@ const params = (over: Partial<TaskContinuationParams> = {}): TaskContinuationPar
74
105
  WorkflowName: 'Weekly digest',
75
106
  ConversationDetailID: 'detail-1',
76
107
  SubmittedByAgentRunID: 'run-1',
108
+ SubmittedByUserID: 'submitter-1',
77
109
  ReinvokeDepth: 0,
78
110
  Tasks: [
79
111
  { TaskID: 't1', Name: 'Gather', Status: 'Complete', Summary: '412 rows' },
@@ -83,10 +115,21 @@ const params = (over: Partial<TaskContinuationParams> = {}): TaskContinuationPar
83
115
  ...over,
84
116
  });
85
117
 
86
- beforeEach(() => vi.clearAllMocks());
118
+ beforeEach(() => {
119
+ vi.clearAllMocks();
120
+ fromMetadataProvider.mockReturnValue({
121
+ RunView: vi.fn().mockResolvedValue({ Success: false, Results: [] }),
122
+ });
123
+ runAgent.mockResolvedValue({
124
+ success: true,
125
+ payload: 'Synthesized workflow outcome',
126
+ agentRun: { ID: 'cont-run-1', Message: 'Synthesized workflow outcome' },
127
+ });
128
+ processAgentArtifacts.mockResolvedValue(undefined);
129
+ });
87
130
 
88
131
  describe('posting the outcome', () => {
89
- it('writes an AI-role message into the graph\'s conversation', async () => {
132
+ it('writes an AI-role message into the graph\'s conversation and broadcasts completion via pubSub', async () => {
90
133
  const h = harness();
91
134
  await h.deliverer.PostMessage(params());
92
135
 
@@ -96,6 +139,52 @@ describe('posting the outcome', () => {
96
139
  expect(reply.Role).toBe('AI');
97
140
  expect(reply.Status).toBe('Complete');
98
141
  expect(reply.HiddenToUser).toBe(false);
142
+ expect(h.pubSub.publish).toHaveBeenCalledTimes(2);
143
+ });
144
+
145
+ it("writes it as the graph's submitter, not the conversation's owner, marked as the server's reply", async () => {
146
+ // TaskGraph.Submit takes any conversation detail ID. Written as the owner, the gate would pass for a
147
+ // conversation the submitter cannot reach; written as the submitter, the gate checks their access.
148
+ const h = harness();
149
+ await h.deliverer.PostMessage(params());
150
+
151
+ expect(h.provider.GetEntityObject.mock.calls[0]).toEqual(['MJ: Conversation Details', SUBMITTER]);
152
+ expect(h.provider.GetEntityObject.mock.calls[1]).toEqual(['MJ: Conversation Details', SUBMITTER]);
153
+ expect(h.provider.GetEntityObject.mock.calls.some((call) => call[1] === OWNER)).toBe(false);
154
+ expect(h.rows[0].MarkServerAuthoredReply).toHaveBeenCalledOnce();
155
+ expect(h.reply().MarkServerAuthoredReply).toHaveBeenCalledOnce();
156
+ });
157
+
158
+ it("updates the originating message in-place as the graph's submitter, marked as the server's reply, when IsLatest is true", async () => {
159
+ const { RunView } = await import('@memberjunction/core');
160
+ vi.mocked(RunView.FromMetadataProvider).mockReturnValue({
161
+ RunView: vi.fn().mockImplementation(async (rvParams: { EntityName: string }) => {
162
+ if (rvParams.EntityName === 'MJ: Conversation Details') {
163
+ return { Success: true, Results: [{ ID: 'detail-1' }] };
164
+ }
165
+ return { Success: false, Results: [] };
166
+ }),
167
+ } as never);
168
+
169
+ const h = harness();
170
+ await h.deliverer.PostMessage(params());
171
+
172
+ expect(h.rows.length).toBe(1);
173
+ expect(h.provider.GetEntityObject.mock.calls[0]).toEqual(['MJ: Conversation Details', SUBMITTER]);
174
+ expect(h.rows[0].MarkServerAuthoredReply).toHaveBeenCalledOnce();
175
+ expect(h.rows[0].Save).toHaveBeenCalledOnce();
176
+ expect(h.rows[0].Status).toBe('Complete');
177
+ expect(h.rows[0].Message).toContain('Weekly digest');
178
+ expect(h.pubSub.publish).toHaveBeenCalledTimes(1);
179
+ });
180
+
181
+ it("falls back to the deliverer's own user when the graph records no submitter it knows", async () => {
182
+ for (const submitter of [null, 'stranger-1']) {
183
+ const h = harness();
184
+ await h.deliverer.PostMessage(params({ SubmittedByUserID: submitter }));
185
+ expect(h.provider.GetEntityObject.mock.calls[0]).toEqual(['MJ: Conversation Details', { ID: 'user-1' }]);
186
+ expect(h.provider.GetEntityObject.mock.calls[1]).toEqual(['MJ: Conversation Details', { ID: 'user-1' }]);
187
+ }
99
188
  });
100
189
 
101
190
  it('names the workflow and carries the roll-up', async () => {
@@ -106,8 +195,6 @@ describe('posting the outcome', () => {
106
195
  });
107
196
 
108
197
  it('lists each step, not just an aggregate status', async () => {
109
- // A graph where nine of ten steps succeeded is a materially different message from one that
110
- // failed outright, and the roll-up alone cannot say which step went wrong.
111
198
  const h = harness();
112
199
  await h.deliverer.PostMessage(params({
113
200
  Tasks: [
@@ -130,7 +217,6 @@ describe('posting the outcome', () => {
130
217
  const message = h.reply().Message;
131
218
  expect(message).toContain('Step 0');
132
219
  expect(message).not.toContain('Step 49');
133
- // The count is stated rather than silently dropped — the task rows remain the full record.
134
220
  expect(message).toContain('30 more');
135
221
  });
136
222
 
@@ -147,8 +233,6 @@ describe('posting the outcome', () => {
147
233
  });
148
234
 
149
235
  it('mints a fresh provider per delivery', async () => {
150
- // Deliveries run outside any request and concurrently with task execution; a shared provider
151
- // would share one transaction scope across unrelated work.
152
236
  const h = harness();
153
237
  await h.deliverer.PostMessage(params());
154
238
  expect(h.providerFactory.CreateProvider).toHaveBeenCalledTimes(1);
@@ -157,8 +241,6 @@ describe('posting the outcome', () => {
157
241
 
158
242
  describe('it never throws — the dispatcher marks delivery inside a CAS guard', () => {
159
243
  it('does nothing for a headless graph, without treating it as an error', async () => {
160
- // A graph submitted by a schedule, an entity-change trigger or an API call has no
161
- // conversation to answer. Most workflows are in this shape.
162
244
  const h = harness();
163
245
  await expect(h.deliverer.PostMessage(params({ ConversationDetailID: null }))).resolves.toBeUndefined();
164
246
  expect(h.providerFactory.CreateProvider).not.toHaveBeenCalled();
@@ -167,7 +249,7 @@ describe('it never throws — the dispatcher marks delivery inside a CAS guard',
167
249
  it('survives a conversation detail that will not load', async () => {
168
250
  const h = harness({ loads: false });
169
251
  await expect(h.deliverer.PostMessage(params())).resolves.toBeUndefined();
170
- expect(h.rows.length).toBe(1); // never got as far as building a reply
252
+ expect(h.rows.length).toBe(1);
171
253
  });
172
254
 
173
255
  it('survives a failed save', async () => {
@@ -185,7 +267,6 @@ describe('it never throws — the dispatcher marks delivery inside a CAS guard',
185
267
  });
186
268
 
187
269
  describe('Reinvoke — restarting the submitting agent', () => {
188
- /** A provider that hands out loadable agent-run and agent rows, then the reply detail. */
189
270
  function reinvokeHarness(over: { runLoads?: boolean; agentLoads?: boolean } = {}) {
190
271
  const { runLoads = true, agentLoads = true } = over;
191
272
  const rows: Array<Record<string, unknown>> = [];
@@ -208,14 +289,16 @@ describe('Reinvoke — restarting the submitting agent', () => {
208
289
  return detail;
209
290
  }),
210
291
  };
292
+ const pubSub = { publish: vi.fn().mockResolvedValue(undefined) } as unknown as PubSubEngine;
211
293
  const deliverer = new TaskGraphContinuationDeliverer(
212
294
  { CreateProvider: vi.fn().mockResolvedValue(provider) } as never,
213
295
  { ID: 'user-1' } as UserInfo,
296
+ pubSub,
214
297
  );
215
- return { deliverer, provider, rows };
298
+ return { deliverer, provider, rows, pubSub };
216
299
  }
217
300
 
218
- it('starts the submitting agent a fresh turn carrying the outcome', async () => {
301
+ it('starts the submitting agent a fresh turn carrying the outcome, saves reply detail, processes artifacts, and publishes completion', async () => {
219
302
  const h = reinvokeHarness();
220
303
  await h.deliverer.Reinvoke(params());
221
304
 
@@ -223,11 +306,17 @@ describe('Reinvoke — restarting the submitting agent', () => {
223
306
  const call = runAgent.mock.calls[0][0];
224
307
  expect(call.agent.ID).toBe('agent-1');
225
308
  expect(call.conversationMessages[0].content).toContain('Weekly digest');
309
+ expect(call.conversationDetailId).toBe('reply-detail-1');
310
+
311
+ const reply = h.rows[3] as ReturnType<typeof detailRow>;
312
+ expect(reply.Role).toBe('AI');
313
+ expect(reply.Status).toBe('Complete');
314
+ expect(reply.Message).toBe('Synthesized workflow outcome');
315
+ expect(processAgentArtifacts).toHaveBeenCalledTimes(1);
316
+ expect(h.pubSub.publish).toHaveBeenCalledTimes(2);
226
317
  });
227
318
 
228
319
  it('stamps depth + 1 — the value that makes MAX_REINVOKE_DEPTH real', async () => {
229
- // Without this the next graph the restarted run submits begins the chain at zero again, and
230
- // the cap can never fire. It is the whole reason ContinuationDepth exists as a column.
231
320
  const h = reinvokeHarness();
232
321
  await h.deliverer.Reinvoke(params({ ReinvokeDepth: 3 }));
233
322
  expect(runAgent.mock.calls[0][0].continuationDepth).toBe(4);
@@ -240,7 +329,6 @@ describe('Reinvoke — restarting the submitting agent', () => {
240
329
  });
241
330
 
242
331
  it('falls back to posting when the graph records no submitting run', async () => {
243
- // A schedule- or trigger-started graph has no turn to continue.
244
332
  const h = reinvokeHarness();
245
333
  await h.deliverer.Reinvoke(params({ SubmittedByAgentRunID: null }));
246
334
  expect(runAgent).not.toHaveBeenCalled();
@@ -266,7 +354,6 @@ describe('Reinvoke — restarting the submitting agent', () => {
266
354
  });
267
355
 
268
356
  describe('Reinvoke — on the fork of the message that started the graph', () => {
269
- /** A provider whose agent run and agent load, and whose origin detail sits on `originBranch` (null is Main). */
270
357
  function forkHarness(originBranch: string | null) {
271
358
  const provider = {
272
359
  GetEntityObject: vi.fn().mockImplementation(async (name: string) => {
@@ -291,6 +378,364 @@ describe('Reinvoke — on the fork of the message that started the graph', () =>
291
378
  it('leaves the branch unset when that message is in Main', async () => {
292
379
  await forkHarness(null).Reinvoke(params());
293
380
 
381
+ expect(runAgent).toHaveBeenCalledTimes(1);
294
382
  expect(runAgent.mock.calls[0][0].ConversationBranchID).toBeUndefined();
295
383
  });
384
+
385
+ it('enriches placeholder "output available (...)" task summaries with OutputPayload excerpts from MJ: Tasks', async () => {
386
+ const { RunView } = await import('@memberjunction/core');
387
+ vi.mocked(RunView.FromMetadataProvider).mockReturnValue({
388
+ RunView: vi.fn().mockImplementation(async (rvParams: { EntityName: string }) => {
389
+ if (rvParams.EntityName === 'MJ: Tasks') {
390
+ return {
391
+ Success: true,
392
+ Results: [
393
+ {
394
+ ID: 't1',
395
+ Name: 'Generate Schema Count Query',
396
+ OutputPayload: JSON.stringify({
397
+ title: 'Entity Counts by Schema',
398
+ request: 'SELECT SchemaName, COUNT(*) AS EntityCount FROM __mj.vwEntities GROUP BY SchemaName',
399
+ }),
400
+ },
401
+ ],
402
+ };
403
+ }
404
+ return { Success: false, Results: [] };
405
+ }),
406
+ } as never);
407
+
408
+ await forkHarness(null).Reinvoke(
409
+ params({
410
+ Tasks: [
411
+ { TaskID: 't1', Name: 'Generate Schema Count Query', Status: 'Complete', Summary: 'output available (180 chars)' },
412
+ ],
413
+ }),
414
+ );
415
+
416
+ expect(runAgent).toHaveBeenCalledTimes(1);
417
+ const sentContent = runAgent.mock.calls[0][0].conversationMessages[0].content as string;
418
+ expect(sentContent).toContain('Title: Entity Counts by Schema');
419
+ expect(sentContent).toContain('SELECT SchemaName, COUNT(*) AS EntityCount FROM __mj.vwEntities GROUP BY SchemaName');
420
+ });
421
+
422
+ it('updates the originating message in-place when no intervening messages were sent (IsLatest = true)', async () => {
423
+ const { RunView } = await import('@memberjunction/core');
424
+ vi.mocked(RunView.FromMetadataProvider).mockReturnValue({
425
+ RunView: vi.fn().mockImplementation(async (rvParams: { EntityName: string }) => {
426
+ if (rvParams.EntityName === 'MJ: Conversation Details') {
427
+ return {
428
+ Success: true,
429
+ Results: [{ ID: 'detail-1' }],
430
+ };
431
+ }
432
+ return { Success: false, Results: [] };
433
+ }),
434
+ } as never);
435
+
436
+ const originDetail = {
437
+ ...detailRow(),
438
+ ID: 'detail-1',
439
+ Message: "Started **Weekly digest** — 2 task(s) running. I'll follow up when it finishes.",
440
+ };
441
+ const createdDetails: Array<ReturnType<typeof detailRow>> = [];
442
+ const provider = {
443
+ GetEntityObject: vi.fn().mockImplementation(async (name: string) => {
444
+ if (name === 'MJ: AI Agent Runs') return { AgentID: 'agent-1', Load: vi.fn().mockResolvedValue(true) };
445
+ if (name === 'MJ: AI Agents') return { ID: 'agent-1', Load: vi.fn().mockResolvedValue(true) };
446
+ if (createdDetails.length === 0) {
447
+ createdDetails.push(originDetail);
448
+ return originDetail;
449
+ }
450
+ const next = detailRow();
451
+ createdDetails.push(next);
452
+ return next;
453
+ }),
454
+ };
455
+ const pubSub = { publish: vi.fn().mockResolvedValue(undefined) } as unknown as PubSubEngine;
456
+ const deliverer = new TaskGraphContinuationDeliverer(
457
+ { CreateProvider: vi.fn().mockResolvedValue(provider) } as never,
458
+ { ID: 'user-1' } as UserInfo,
459
+ pubSub,
460
+ );
461
+
462
+ await deliverer.Reinvoke(params());
463
+
464
+ // Only the originating detail was loaded and updated in-place — no second detail row created!
465
+ expect(createdDetails.length).toBe(1);
466
+ expect(originDetail.NewRecord).not.toHaveBeenCalled();
467
+ expect(originDetail.MarkServerAuthoredReply).toHaveBeenCalledOnce();
468
+ expect(originDetail.Save).toHaveBeenCalledOnce();
469
+ expect(originDetail.Message).toBe('Synthesized workflow outcome');
470
+ expect(originDetail.Status).toBe('Complete');
471
+ expect(runAgent.mock.calls[0][0].conversationDetailId).toBe('detail-1');
472
+ expect(runAgent.mock.calls[0][0].inputArtifacts).toEqual([]);
473
+ expect(pubSub.publish).toHaveBeenCalledTimes(1);
474
+ });
475
+
476
+ it('creates a bottom continuation reply with ParentID = originDetailId and updates the origin message note when intervening messages exist (IsLatest = false)', async () => {
477
+ const { RunView } = await import('@memberjunction/core');
478
+ vi.mocked(RunView.FromMetadataProvider).mockReturnValue({
479
+ RunView: vi.fn().mockImplementation(async (rvParams: { EntityName: string }) => {
480
+ if (rvParams.EntityName === 'MJ: Conversation Details') {
481
+ return {
482
+ Success: true,
483
+ Results: [{ ID: 'intervening-user-msg-2' }],
484
+ };
485
+ }
486
+ return { Success: false, Results: [] };
487
+ }),
488
+ } as never);
489
+
490
+ const originDetail = {
491
+ ...detailRow(),
492
+ ID: 'detail-1',
493
+ ParentID: null as string | null,
494
+ Message: "Started **Weekly digest** — 2 task(s) running. I'll follow up when it finishes.",
495
+ };
496
+ const replyDetail = {
497
+ ...detailRow(),
498
+ ID: 'bottom-reply-3',
499
+ ParentID: null as string | null,
500
+ };
501
+ let detailCallCount = 0;
502
+ const provider = {
503
+ GetEntityObject: vi.fn().mockImplementation(async (name: string) => {
504
+ if (name === 'MJ: AI Agent Runs') return { AgentID: 'agent-1', Load: vi.fn().mockResolvedValue(true) };
505
+ if (name === 'MJ: AI Agents') return { ID: 'agent-1', Load: vi.fn().mockResolvedValue(true) };
506
+ detailCallCount++;
507
+ return detailCallCount === 1 ? originDetail : replyDetail;
508
+ }),
509
+ };
510
+ const pubSub = { publish: vi.fn().mockResolvedValue(undefined) } as unknown as PubSubEngine;
511
+ const deliverer = new TaskGraphContinuationDeliverer(
512
+ { CreateProvider: vi.fn().mockResolvedValue(provider) } as never,
513
+ { ID: 'user-1' } as UserInfo,
514
+ pubSub,
515
+ );
516
+
517
+ await deliverer.Reinvoke(params());
518
+
519
+ expect(replyDetail.NewRecord).toHaveBeenCalledTimes(1);
520
+ expect(replyDetail.MarkServerAuthoredReply).toHaveBeenCalledOnce();
521
+ expect(replyDetail.ParentID).toBe('detail-1');
522
+ expect(replyDetail.Message).toBe('Synthesized workflow outcome');
523
+ expect(originDetail.MarkServerAuthoredReply).toHaveBeenCalledOnce();
524
+ expect(originDetail.Save).toHaveBeenCalledOnce();
525
+ expect(originDetail.Message).toContain('*(✅ **Weekly digest** completed — synthesized results posted below.)*');
526
+ expect(originDetail.Message).not.toContain("I'll follow up when it finishes");
527
+ expect(pubSub.publish).toHaveBeenCalledTimes(2);
528
+ });
529
+
530
+ it('strips inherited upstream payload keys across DAG steps and extracts nested synthesis and report fields', async () => {
531
+ const { RunView } = await import('@memberjunction/core');
532
+ const step1Payload = {
533
+ queryName: 'Annual Order Counts',
534
+ sql: 'SELECT YEAR(OrderDate) AS OrderYear, COUNT(*) AS OrderCount FROM Orders GROUP BY YEAR(OrderDate)',
535
+ explanation: 'Counts orders grouped by year.',
536
+ };
537
+ const step2Payload = {
538
+ ...step1Payload,
539
+ synthesis: {
540
+ executiveSummary: 'Order volume grew 22% YoY between 2022 and 2025.',
541
+ keyFindings: ['2024 peak growth', 'Steady enterprise retention'],
542
+ },
543
+ };
544
+ const step3Payload = {
545
+ ...step2Payload,
546
+ report: {
547
+ name: 'Annual Order Trend Executive Report',
548
+ description: 'Board-ready HTML report covering annual order volume and YoY trajectory.',
549
+ html: '<h1>Annual Order Trend</h1><p>Executive overview of multi-year order growth.</p>',
550
+ },
551
+ };
552
+
553
+ vi.mocked(RunView.FromMetadataProvider).mockReturnValue({
554
+ RunView: vi.fn().mockImplementation(async (rvParams: { EntityName: string }) => {
555
+ if (rvParams.EntityName === 'MJ: Tasks') {
556
+ return {
557
+ Success: true,
558
+ Results: [
559
+ { ID: 't1', Name: 'Step 1: Query', OutputPayload: JSON.stringify(step1Payload) },
560
+ { ID: 't2', Name: 'Step 2: Strategy', OutputPayload: JSON.stringify(step2Payload) },
561
+ { ID: 't3', Name: 'Step 3: Report', OutputPayload: JSON.stringify(step3Payload) },
562
+ ],
563
+ };
564
+ }
565
+ return { Success: false, Results: [] };
566
+ }),
567
+ } as never);
568
+
569
+ await forkHarness(null).Reinvoke(
570
+ params({
571
+ Tasks: [
572
+ { TaskID: 't1', Name: 'Step 1: Query', Status: 'Complete', Summary: 'output available (180 chars)' },
573
+ { TaskID: 't2', Name: 'Step 2: Strategy', Status: 'Complete', Summary: 'output available (320 chars)' },
574
+ { TaskID: 't3', Name: 'Step 3: Report', Status: 'Complete', Summary: 'output available (540 chars)' },
575
+ ],
576
+ }),
577
+ );
578
+
579
+ const sentContent = runAgent.mock.calls[0][0].conversationMessages[0].content as string;
580
+ expect(sentContent).toContain('Title: Annual Order Counts');
581
+ expect(sentContent).toContain('Executive Summary: Order volume grew 22% YoY between 2022 and 2025.');
582
+ expect(sentContent).toContain('Report Title: Annual Order Trend Executive Report');
583
+ expect(sentContent).toContain('Report Summary: Board-ready HTML report covering annual order volume and YoY trajectory.');
584
+ // Step 1's SQL should only appear once (under Step 1), not duplicated under Step 2 and Step 3!
585
+ const sqlOccurrences = sentContent.split('SELECT YEAR(OrderDate) AS OrderYear').length - 1;
586
+ expect(sqlOccurrences).toBe(1);
587
+ });
588
+
589
+ it('walks up ParentRunID so a sub-agent (Workflow Planner) submission reinvokes the root conversation agent (Sage) as the conversation owner', async () => {
590
+ const subAgentRun = {
591
+ ID: 'subagent-planner-run',
592
+ AgentID: 'workflow-planner-agent-id',
593
+ ParentRunID: 'root-sage-run',
594
+ UserID: null as string | null,
595
+ Load: vi.fn().mockResolvedValue(true),
596
+ };
597
+ const rootSageRun = {
598
+ ID: 'root-sage-run',
599
+ AgentID: 'sage-agent-id',
600
+ ParentRunID: null as string | null,
601
+ UserID: 'owner-user-99',
602
+ Load: vi.fn().mockResolvedValue(true),
603
+ };
604
+ const sageAgent = {
605
+ ID: 'sage-agent-id',
606
+ Name: 'Sage',
607
+ Load: vi.fn().mockResolvedValue(true),
608
+ };
609
+ const detail = detailRow();
610
+ let runCallCount = 0;
611
+ const detailUsers: Array<UserInfo | undefined> = [];
612
+
613
+ const provider = {
614
+ GetEntityObject: vi.fn().mockImplementation(async (name: string, user?: UserInfo) => {
615
+ if (name === 'MJ: AI Agent Runs') {
616
+ runCallCount++;
617
+ return runCallCount === 1 ? subAgentRun : rootSageRun;
618
+ }
619
+ if (name === 'MJ: AI Agents') {
620
+ return sageAgent;
621
+ }
622
+ detailUsers.push(user);
623
+ return detail;
624
+ }),
625
+ };
626
+
627
+ const deliverer = new TaskGraphContinuationDeliverer(
628
+ { CreateProvider: vi.fn().mockResolvedValue(provider) } as never,
629
+ { ID: 'system-user' } as UserInfo,
630
+ );
631
+
632
+ await deliverer.Reinvoke(params({ SubmittedByAgentRunID: 'subagent-planner-run' }));
633
+
634
+ expect(subAgentRun.Load).toHaveBeenCalledWith('subagent-planner-run');
635
+ expect(rootSageRun.Load).toHaveBeenCalledWith('root-sage-run');
636
+ expect(sageAgent.Load).toHaveBeenCalledWith('sage-agent-id');
637
+ expect(runAgent).toHaveBeenCalledTimes(1);
638
+ expect(runAgent.mock.calls[0][0].agent.ID).toBe('sage-agent-id');
639
+ expect(runAgent.mock.calls[0][0].contextUser.ID).toBe('owner-user-99');
640
+ expect(detailUsers[0]?.ID).toBe('owner-user-99');
641
+ });
642
+
643
+ it('enriches Skipped steps with their unmet dependency Condition from MJ: Task Dependencies', async () => {
644
+ const { RunView } = await import('@memberjunction/core');
645
+ vi.mocked(RunView.FromMetadataProvider).mockReturnValue({
646
+ RunView: vi.fn().mockImplementation(async (rvParams: { EntityName: string }) => {
647
+ if (rvParams.EntityName === 'MJ: Tasks') {
648
+ return {
649
+ Success: true,
650
+ Results: [
651
+ { ID: 't1', Name: 'Build Query', Status: 'Complete', OutputPayload: JSON.stringify({ queryName: 'Users by Role' }) },
652
+ { ID: 't2', Name: 'Run Query', Status: 'Complete', OutputPayload: JSON.stringify({ summary: 'Built query blueprint without live execution' }) },
653
+ { ID: 't3', Name: 'Analyze Results', Status: 'Skipped', OutputPayload: null },
654
+ ],
655
+ };
656
+ }
657
+ if (rvParams.EntityName === 'MJ: Task Dependencies') {
658
+ return {
659
+ Success: true,
660
+ Results: [
661
+ {
662
+ TaskID: 't3',
663
+ DependsOnTaskID: 't2',
664
+ Condition: 'output.rowCount > 0',
665
+ },
666
+ ],
667
+ };
668
+ }
669
+ return { Success: false, Results: [] };
670
+ }),
671
+ } as never);
672
+
673
+ await forkHarness(null).Reinvoke(
674
+ params({
675
+ Tasks: [
676
+ { TaskID: 't1', Name: 'Build Query', Status: 'Complete' },
677
+ { TaskID: 't2', Name: 'Run Query', Status: 'Complete' },
678
+ { TaskID: 't3', Name: 'Analyze Results', Status: 'Skipped' },
679
+ ],
680
+ Summary: '2 of 3 steps completed (1 skipped).',
681
+ }),
682
+ );
683
+
684
+ const sentContent = runAgent.mock.calls[0][0].conversationMessages[0].content as string;
685
+ expect(sentContent).toContain('- ⏭️ **Analyze Results** — Skipped: branch condition `output.rowCount > 0` on "Run Query" evaluated to false');
686
+ expect(sentContent).toContain('briefly explaining any conditional steps that were skipped');
687
+ });
688
+
689
+ it('logs an error and does not publish completion when an in-place (IsLatest = true) PostMessage save fails', async () => {
690
+ const { LogError, RunView } = await import('@memberjunction/core');
691
+ vi.mocked(RunView.FromMetadataProvider).mockReturnValue({
692
+ RunView: vi.fn().mockResolvedValue({
693
+ Success: true,
694
+ Results: [{ ID: 'detail-1' }],
695
+ }),
696
+ } as never);
697
+
698
+ const h = harness({ saves: false });
699
+ await h.deliverer.PostMessage(params());
700
+
701
+ expect(h.rows[0].Save).toHaveBeenCalledOnce();
702
+ expect(LogError).toHaveBeenCalledWith(expect.stringContaining('Could not update in-place outcome of "Weekly digest"'));
703
+ expect(h.pubSub.publish).not.toHaveBeenCalled();
704
+ });
705
+
706
+ it('loads the originating detail as SubmittedByUserID in Reinvoke when both run UserIDs are null', async () => {
707
+ const runRow = {
708
+ ID: 'run-1',
709
+ AgentID: 'agent-1',
710
+ ParentRunID: null as string | null,
711
+ UserID: null as string | null,
712
+ Load: vi.fn().mockResolvedValue(true),
713
+ };
714
+ const agentRow = {
715
+ ID: 'agent-1',
716
+ Name: 'Sage',
717
+ Load: vi.fn().mockResolvedValue(true),
718
+ };
719
+ const detail = detailRow();
720
+ const detailUsers: Array<UserInfo | undefined> = [];
721
+ const provider = {
722
+ GetEntityObject: vi.fn().mockImplementation(async (name: string, user?: UserInfo) => {
723
+ if (name === 'MJ: AI Agent Runs') return runRow;
724
+ if (name === 'MJ: AI Agents') return agentRow;
725
+ detailUsers.push(user);
726
+ return detail;
727
+ }),
728
+ };
729
+ const deliverer = new TaskGraphContinuationDeliverer(
730
+ { CreateProvider: vi.fn().mockResolvedValue(provider) } as never,
731
+ { ID: 'system-user' } as UserInfo,
732
+ );
733
+
734
+ await deliverer.Reinvoke(params({ SubmittedByUserID: SUBMITTER.ID }));
735
+
736
+ expect(detailUsers[0]).toBe(SUBMITTER);
737
+ expect(runAgent.mock.calls[0][0].contextUser).toBe(SUBMITTER);
738
+ });
296
739
  });
740
+
741
+
@@ -133,4 +133,26 @@ describe('TaskGraphFrameBroadcaster', () => {
133
133
  expect(p.CompletedCount).toBe(7);
134
134
  expect(p.TotalCount).toBe(7);
135
135
  });
136
+
137
+ it('bridges frames onto PUSH_STATUS_UPDATES_TOPIC when bridgeToPushStatus is enabled', () => {
138
+ new TaskGraphFrameBroadcaster(pubSub, true).OnFrame(
139
+ frame({ Kind: 'TaskCompleted', Status: 'Complete', CompletedCount: 1, TotalCount: 2 }),
140
+ );
141
+ expect(published).toHaveLength(2);
142
+ expect(published[0][0]).toBe(TASK_GRAPH_FRAMES_TOPIC);
143
+ expect(published[1][0]).toBe('PUSH_STATUS_UPDATES');
144
+ const pushPayload = published[1][1] as { sessionId: string; ownerUserId: string; message: string };
145
+ expect(pushPayload.sessionId).toBe('*');
146
+ expect(pushPayload.ownerUserId).toBe(OWNER);
147
+ const parsed = JSON.parse(pushPayload.message) as {
148
+ type: string;
149
+ status: string;
150
+ data: { Status: string; TaskID: string };
151
+ };
152
+ expect(parsed.type).toBe('TaskGraphFrame');
153
+ expect(parsed.status).toBe('ok');
154
+ expect(parsed.data.Status).toBe('Complete');
155
+ expect(parsed.data.TaskID).toBe('task-1');
156
+ });
136
157
  });
158
+