@memberjunction/server 6.2.0-edge.5 → 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 (401) hide show
  1. package/README.md +27 -1
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/agentSessions/SessionJanitor.d.ts +3 -3
  4. package/dist/agentSessions/SessionJanitor.js +3 -3
  5. package/dist/agentSessions/SessionManager.d.ts +15 -5
  6. package/dist/agentSessions/SessionManager.d.ts.map +1 -1
  7. package/dist/agentSessions/SessionManager.js +34 -12
  8. package/dist/agentSessions/SessionManager.js.map +1 -1
  9. package/dist/auth/AuthProviderCatalogRouter.d.ts.map +1 -1
  10. package/dist/auth/AuthProviderCatalogRouter.js +2 -0
  11. package/dist/auth/AuthProviderCatalogRouter.js.map +1 -1
  12. package/dist/auth/index.d.ts.map +1 -1
  13. package/dist/auth/index.js +51 -10
  14. package/dist/auth/index.js.map +1 -1
  15. package/dist/auth/initializeProviders.d.ts +10 -0
  16. package/dist/auth/initializeProviders.d.ts.map +1 -1
  17. package/dist/auth/initializeProviders.js +37 -1
  18. package/dist/auth/initializeProviders.js.map +1 -1
  19. package/dist/auth/localDevAuth.d.ts +79 -0
  20. package/dist/auth/localDevAuth.d.ts.map +1 -0
  21. package/dist/auth/localDevAuth.js +439 -0
  22. package/dist/auth/localDevAuth.js.map +1 -0
  23. package/dist/auth/magicLink/MagicLinkKeys.d.ts +2 -2
  24. package/dist/auth/magicLink/MagicLinkKeys.d.ts.map +1 -1
  25. package/dist/auth/magicLink/MagicLinkKeys.js +1 -1
  26. package/dist/auth/magicLink/MagicLinkKeys.js.map +1 -1
  27. package/dist/auth/magicLink/types.d.ts +12 -0
  28. package/dist/auth/magicLink/types.d.ts.map +1 -1
  29. package/dist/auth/sessionUserClone.d.ts +1 -1
  30. package/dist/auth/sessionUserClone.d.ts.map +1 -1
  31. package/dist/auth/sessionUserClone.js +3 -2
  32. package/dist/auth/sessionUserClone.js.map +1 -1
  33. package/dist/broadcast/BaseCacheInvalidationBroadcastProvider.d.ts +292 -0
  34. package/dist/broadcast/BaseCacheInvalidationBroadcastProvider.d.ts.map +1 -0
  35. package/dist/broadcast/BaseCacheInvalidationBroadcastProvider.js +442 -0
  36. package/dist/broadcast/BaseCacheInvalidationBroadcastProvider.js.map +1 -0
  37. package/dist/broadcast/index.d.ts +6 -0
  38. package/dist/broadcast/index.d.ts.map +1 -0
  39. package/dist/broadcast/index.js +6 -0
  40. package/dist/broadcast/index.js.map +1 -0
  41. package/dist/broadcast/providers/AWSIoTCoreBroadcastProvider.d.ts +43 -0
  42. package/dist/broadcast/providers/AWSIoTCoreBroadcastProvider.d.ts.map +1 -0
  43. package/dist/broadcast/providers/AWSIoTCoreBroadcastProvider.js +144 -0
  44. package/dist/broadcast/providers/AWSIoTCoreBroadcastProvider.js.map +1 -0
  45. package/dist/broadcast/providers/AzureWebPubSubBroadcastProvider.d.ts +46 -0
  46. package/dist/broadcast/providers/AzureWebPubSubBroadcastProvider.d.ts.map +1 -0
  47. package/dist/broadcast/providers/AzureWebPubSubBroadcastProvider.js +149 -0
  48. package/dist/broadcast/providers/AzureWebPubSubBroadcastProvider.js.map +1 -0
  49. package/dist/broadcast/providers/GCPPubSubBroadcastProvider.d.ts +49 -0
  50. package/dist/broadcast/providers/GCPPubSubBroadcastProvider.d.ts.map +1 -0
  51. package/dist/broadcast/providers/GCPPubSubBroadcastProvider.js +131 -0
  52. package/dist/broadcast/providers/GCPPubSubBroadcastProvider.js.map +1 -0
  53. package/dist/broadcast/providers/SequencedRoleBucketBroadcastProvider.d.ts +24 -0
  54. package/dist/broadcast/providers/SequencedRoleBucketBroadcastProvider.d.ts.map +1 -0
  55. package/dist/broadcast/providers/SequencedRoleBucketBroadcastProvider.js +51 -0
  56. package/dist/broadcast/providers/SequencedRoleBucketBroadcastProvider.js.map +1 -0
  57. package/dist/cache.d.ts +3 -2
  58. package/dist/cache.d.ts.map +1 -1
  59. package/dist/cache.js.map +1 -1
  60. package/dist/config.d.ts +496 -0
  61. package/dist/config.d.ts.map +1 -1
  62. package/dist/config.js +61 -0
  63. package/dist/config.js.map +1 -1
  64. package/dist/context.d.ts +3 -1
  65. package/dist/context.d.ts.map +1 -1
  66. package/dist/context.js +29 -8
  67. package/dist/context.js.map +1 -1
  68. package/dist/coreRoutes.d.ts.map +1 -1
  69. package/dist/coreRoutes.js +14 -0
  70. package/dist/coreRoutes.js.map +1 -1
  71. package/dist/generated/graphql-schemas/__mj.d.ts +635 -14
  72. package/dist/generated/graphql-schemas/__mj.d.ts.map +1 -1
  73. package/dist/generated/graphql-schemas/__mj.js +3366 -418
  74. package/dist/generated/graphql-schemas/__mj.js.map +1 -1
  75. package/dist/generic/CacheInvalidationResolver.d.ts +50 -30
  76. package/dist/generic/CacheInvalidationResolver.d.ts.map +1 -1
  77. package/dist/generic/CacheInvalidationResolver.js +154 -79
  78. package/dist/generic/CacheInvalidationResolver.js.map +1 -1
  79. package/dist/generic/OrphanedConversationDetailReconciler.d.ts.map +1 -1
  80. package/dist/generic/OrphanedConversationDetailReconciler.js +2 -0
  81. package/dist/generic/OrphanedConversationDetailReconciler.js.map +1 -1
  82. package/dist/generic/PubSubManager.d.ts +10 -0
  83. package/dist/generic/PubSubManager.d.ts.map +1 -1
  84. package/dist/generic/PubSubManager.js +44 -1
  85. package/dist/generic/PubSubManager.js.map +1 -1
  86. package/dist/generic/PushStatusResolver.d.ts +39 -6
  87. package/dist/generic/PushStatusResolver.d.ts.map +1 -1
  88. package/dist/generic/PushStatusResolver.js +93 -11
  89. package/dist/generic/PushStatusResolver.js.map +1 -1
  90. package/dist/generic/ResolverBase.d.ts +65 -25
  91. package/dist/generic/ResolverBase.d.ts.map +1 -1
  92. package/dist/generic/ResolverBase.js +201 -101
  93. package/dist/generic/ResolverBase.js.map +1 -1
  94. package/dist/generic/RunViewResolver.d.ts +11 -3
  95. package/dist/generic/RunViewResolver.d.ts.map +1 -1
  96. package/dist/generic/RunViewResolver.js +79 -13
  97. package/dist/generic/RunViewResolver.js.map +1 -1
  98. package/dist/generic/actionOutputFieldSecurity.d.ts +26 -0
  99. package/dist/generic/actionOutputFieldSecurity.d.ts.map +1 -0
  100. package/dist/generic/actionOutputFieldSecurity.js +47 -0
  101. package/dist/generic/actionOutputFieldSecurity.js.map +1 -0
  102. package/dist/generic/fieldSecurityTransport.d.ts +30 -0
  103. package/dist/generic/fieldSecurityTransport.d.ts.map +1 -0
  104. package/dist/generic/fieldSecurityTransport.js +30 -0
  105. package/dist/generic/fieldSecurityTransport.js.map +1 -0
  106. package/dist/index.d.ts +3 -0
  107. package/dist/index.d.ts.map +1 -1
  108. package/dist/index.js +122 -66
  109. package/dist/index.js.map +1 -1
  110. package/dist/integration/CustomColumnPromoter.d.ts.map +1 -1
  111. package/dist/integration/CustomColumnPromoter.js +6 -1
  112. package/dist/integration/CustomColumnPromoter.js.map +1 -1
  113. package/dist/logging/variablesLoggingMiddleware.d.ts +12 -0
  114. package/dist/logging/variablesLoggingMiddleware.d.ts.map +1 -1
  115. package/dist/logging/variablesLoggingMiddleware.js +50 -1
  116. package/dist/logging/variablesLoggingMiddleware.js.map +1 -1
  117. package/dist/realtimeSessions/SessionVerificationPortsBase.d.ts.map +1 -1
  118. package/dist/realtimeSessions/SessionVerificationPortsBase.js +1 -0
  119. package/dist/realtimeSessions/SessionVerificationPortsBase.js.map +1 -1
  120. package/dist/realtimeSessions/ownedRealtimeSession.d.ts +8 -6
  121. package/dist/realtimeSessions/ownedRealtimeSession.d.ts.map +1 -1
  122. package/dist/realtimeSessions/ownedRealtimeSession.js +15 -6
  123. package/dist/realtimeSessions/ownedRealtimeSession.js.map +1 -1
  124. package/dist/realtimeSessions/sessionAccess.d.ts +88 -11
  125. package/dist/realtimeSessions/sessionAccess.d.ts.map +1 -1
  126. package/dist/realtimeSessions/sessionAccess.js +125 -22
  127. package/dist/realtimeSessions/sessionAccess.js.map +1 -1
  128. package/dist/realtimeSessions/sessionConfigStamps.js +1 -1
  129. package/dist/realtimeSessions/sessionConfigStamps.js.map +1 -1
  130. package/dist/realtimeSessions/subscriptionAuthorization.d.ts.map +1 -1
  131. package/dist/realtimeSessions/subscriptionAuthorization.js +5 -2
  132. package/dist/realtimeSessions/subscriptionAuthorization.js.map +1 -1
  133. package/dist/realtimeSessions/verificationWorkflow.d.ts +2 -0
  134. package/dist/realtimeSessions/verificationWorkflow.d.ts.map +1 -1
  135. package/dist/realtimeSessions/verificationWorkflow.js +1 -1
  136. package/dist/realtimeSessions/verificationWorkflow.js.map +1 -1
  137. package/dist/realtimeWidget/WidgetRouter.d.ts.map +1 -1
  138. package/dist/realtimeWidget/WidgetRouter.js +19 -3
  139. package/dist/realtimeWidget/WidgetRouter.js.map +1 -1
  140. package/dist/realtimeWidget/WidgetSessionService.d.ts +67 -7
  141. package/dist/realtimeWidget/WidgetSessionService.d.ts.map +1 -1
  142. package/dist/realtimeWidget/WidgetSessionService.js +201 -19
  143. package/dist/realtimeWidget/WidgetSessionService.js.map +1 -1
  144. package/dist/realtimeWidget/host-identity.d.ts +1 -1
  145. package/dist/realtimeWidget/host-identity.js +1 -1
  146. package/dist/realtimeWidget/widgetCore.d.ts +20 -1
  147. package/dist/realtimeWidget/widgetCore.d.ts.map +1 -1
  148. package/dist/realtimeWidget/widgetCore.js +17 -1
  149. package/dist/realtimeWidget/widgetCore.js.map +1 -1
  150. package/dist/realtimeWidget/widgetGuestElevation.d.ts +1 -1
  151. package/dist/realtimeWidget/widgetGuestElevation.d.ts.map +1 -1
  152. package/dist/realtimeWidget/widgetGuestElevation.js +2 -1
  153. package/dist/realtimeWidget/widgetGuestElevation.js.map +1 -1
  154. package/dist/resolvers/ActionResolver.d.ts +19 -1
  155. package/dist/resolvers/ActionResolver.d.ts.map +1 -1
  156. package/dist/resolvers/ActionResolver.js +63 -12
  157. package/dist/resolvers/ActionResolver.js.map +1 -1
  158. package/dist/resolvers/AdhocQueryResolver.d.ts.map +1 -1
  159. package/dist/resolvers/AdhocQueryResolver.js +1 -0
  160. package/dist/resolvers/AdhocQueryResolver.js.map +1 -1
  161. package/dist/resolvers/AgentRunStatusPublisher.d.ts +18 -4
  162. package/dist/resolvers/AgentRunStatusPublisher.d.ts.map +1 -1
  163. package/dist/resolvers/AgentRunStatusPublisher.js +32 -8
  164. package/dist/resolvers/AgentRunStatusPublisher.js.map +1 -1
  165. package/dist/resolvers/AgentSessionResolver.d.ts +10 -4
  166. package/dist/resolvers/AgentSessionResolver.d.ts.map +1 -1
  167. package/dist/resolvers/AgentSessionResolver.js +40 -17
  168. package/dist/resolvers/AgentSessionResolver.js.map +1 -1
  169. package/dist/resolvers/EntityCommunicationsResolver.d.ts +13 -1
  170. package/dist/resolvers/EntityCommunicationsResolver.d.ts.map +1 -1
  171. package/dist/resolvers/EntityCommunicationsResolver.js +50 -14
  172. package/dist/resolvers/EntityCommunicationsResolver.js.map +1 -1
  173. package/dist/resolvers/FetchEntityVectorsResolver.d.ts +28 -0
  174. package/dist/resolvers/FetchEntityVectorsResolver.d.ts.map +1 -1
  175. package/dist/resolvers/FetchEntityVectorsResolver.js +117 -21
  176. package/dist/resolvers/FetchEntityVectorsResolver.js.map +1 -1
  177. package/dist/resolvers/FileCategoryResolver.d.ts.map +1 -1
  178. package/dist/resolvers/FileCategoryResolver.js +1 -0
  179. package/dist/resolvers/FileCategoryResolver.js.map +1 -1
  180. package/dist/resolvers/FileResolver.d.ts +5 -0
  181. package/dist/resolvers/FileResolver.d.ts.map +1 -1
  182. package/dist/resolvers/FileResolver.js +13 -4
  183. package/dist/resolvers/FileResolver.js.map +1 -1
  184. package/dist/resolvers/IntegrationDiscoveryResolver.d.ts.map +1 -1
  185. package/dist/resolvers/IntegrationDiscoveryResolver.js +45 -7
  186. package/dist/resolvers/IntegrationDiscoveryResolver.js.map +1 -1
  187. package/dist/resolvers/MergeRecordsResolver.d.ts +8 -1
  188. package/dist/resolvers/MergeRecordsResolver.d.ts.map +1 -1
  189. package/dist/resolvers/MergeRecordsResolver.js +31 -3
  190. package/dist/resolvers/MergeRecordsResolver.js.map +1 -1
  191. package/dist/resolvers/PipelineProgressResolver.d.ts +6 -0
  192. package/dist/resolvers/PipelineProgressResolver.d.ts.map +1 -1
  193. package/dist/resolvers/PipelineProgressResolver.js +5 -3
  194. package/dist/resolvers/PipelineProgressResolver.js.map +1 -1
  195. package/dist/resolvers/QueryResolver.d.ts.map +1 -1
  196. package/dist/resolvers/QueryResolver.js +20 -6
  197. package/dist/resolvers/QueryResolver.js.map +1 -1
  198. package/dist/resolvers/QuerySystemUserResolver.d.ts +2 -0
  199. package/dist/resolvers/QuerySystemUserResolver.d.ts.map +1 -1
  200. package/dist/resolvers/QuerySystemUserResolver.js +15 -6
  201. package/dist/resolvers/QuerySystemUserResolver.js.map +1 -1
  202. package/dist/resolvers/RSUResolver.d.ts.map +1 -1
  203. package/dist/resolvers/RSUResolver.js +12 -0
  204. package/dist/resolvers/RSUResolver.js.map +1 -1
  205. package/dist/resolvers/RealtimeClientSessionResolver.d.ts +16 -2
  206. package/dist/resolvers/RealtimeClientSessionResolver.d.ts.map +1 -1
  207. package/dist/resolvers/RealtimeClientSessionResolver.js +82 -28
  208. package/dist/resolvers/RealtimeClientSessionResolver.js.map +1 -1
  209. package/dist/resolvers/RemoteBrowserActionResolver.d.ts.map +1 -1
  210. package/dist/resolvers/RemoteBrowserActionResolver.js +11 -9
  211. package/dist/resolvers/RemoteBrowserActionResolver.js.map +1 -1
  212. package/dist/resolvers/RunAIAgentResolver.d.ts +56 -8
  213. package/dist/resolvers/RunAIAgentResolver.d.ts.map +1 -1
  214. package/dist/resolvers/RunAIAgentResolver.js +209 -64
  215. package/dist/resolvers/RunAIAgentResolver.js.map +1 -1
  216. package/dist/resolvers/RunTemplateResolver.d.ts.map +1 -1
  217. package/dist/resolvers/RunTemplateResolver.js +4 -4
  218. package/dist/resolvers/RunTemplateResolver.js.map +1 -1
  219. package/dist/resolvers/RunTestResolver.d.ts.map +1 -1
  220. package/dist/resolvers/RunTestResolver.js +3 -1
  221. package/dist/resolvers/RunTestResolver.js.map +1 -1
  222. package/dist/resolvers/SyncDataResolver.d.ts.map +1 -1
  223. package/dist/resolvers/SyncDataResolver.js +4 -0
  224. package/dist/resolvers/SyncDataResolver.js.map +1 -1
  225. package/dist/resolvers/TestQuerySQLResolver.d.ts.map +1 -1
  226. package/dist/resolvers/TestQuerySQLResolver.js +1 -0
  227. package/dist/resolvers/TestQuerySQLResolver.js.map +1 -1
  228. package/dist/resolvers/TransactionGroupResolver.d.ts +17 -2
  229. package/dist/resolvers/TransactionGroupResolver.d.ts.map +1 -1
  230. package/dist/resolvers/TransactionGroupResolver.js +60 -15
  231. package/dist/resolvers/TransactionGroupResolver.js.map +1 -1
  232. package/dist/resolvers/UserViewResolver.d.ts +1 -1
  233. package/dist/resolvers/UserViewResolver.d.ts.map +1 -1
  234. package/dist/resolvers/UserViewResolver.js +2 -1
  235. package/dist/resolvers/UserViewResolver.js.map +1 -1
  236. package/dist/rest/EntityCRUDHandler.d.ts +6 -0
  237. package/dist/rest/EntityCRUDHandler.d.ts.map +1 -1
  238. package/dist/rest/EntityCRUDHandler.js +19 -5
  239. package/dist/rest/EntityCRUDHandler.js.map +1 -1
  240. package/dist/rest/RESTEndpointHandler.d.ts.map +1 -1
  241. package/dist/rest/RESTEndpointHandler.js +8 -5
  242. package/dist/rest/RESTEndpointHandler.js.map +1 -1
  243. package/dist/rest/RealtimeRecordingHandler.d.ts +3 -3
  244. package/dist/rest/RealtimeRecordingHandler.d.ts.map +1 -1
  245. package/dist/rest/RealtimeRecordingHandler.js +7 -7
  246. package/dist/rest/RealtimeRecordingHandler.js.map +1 -1
  247. package/dist/rest/ViewOperationsHandler.d.ts +6 -0
  248. package/dist/rest/ViewOperationsHandler.d.ts.map +1 -1
  249. package/dist/rest/ViewOperationsHandler.js +22 -5
  250. package/dist/rest/ViewOperationsHandler.js.map +1 -1
  251. package/dist/serverRoleConfigUnits.d.ts +29 -0
  252. package/dist/serverRoleConfigUnits.d.ts.map +1 -0
  253. package/dist/serverRoleConfigUnits.js +33 -0
  254. package/dist/serverRoleConfigUnits.js.map +1 -0
  255. package/dist/services/TaskGraphContinuationDeliverer.d.ts +5 -0
  256. package/dist/services/TaskGraphContinuationDeliverer.d.ts.map +1 -1
  257. package/dist/services/TaskGraphContinuationDeliverer.js +42 -15
  258. package/dist/services/TaskGraphContinuationDeliverer.js.map +1 -1
  259. package/dist/types.d.ts +23 -1
  260. package/dist/types.d.ts.map +1 -1
  261. package/dist/types.js.map +1 -1
  262. package/package.json +98 -98
  263. package/src/__tests__/ActionResolver.fieldSecurity.test.ts +237 -0
  264. package/src/__tests__/AdhocQueryResolver.dialect.test.ts +137 -0
  265. package/src/__tests__/AgentRunStatusPublisher.test.ts +49 -0
  266. package/src/__tests__/AgentSessionResolver.ownership.test.ts +137 -0
  267. package/src/__tests__/CustomColumnPromoterOnePass.test.ts +15 -1
  268. package/src/__tests__/EntityCommunicationsResolver.actingUser.test.ts +151 -0
  269. package/src/__tests__/EvolutionActsOnWhatItDetects.test.ts +113 -0
  270. package/src/__tests__/FetchEntityVectorsResolver.test.ts +206 -3
  271. package/src/__tests__/FileResolver.fieldSecurity.test.ts +82 -0
  272. package/src/__tests__/PipelineProgressResolver.filter.test.ts +58 -0
  273. package/src/__tests__/QuerySystemUserResolver.fieldSecurity.test.ts +49 -0
  274. package/src/__tests__/RESTEndpointHandler.test.ts +25 -0
  275. package/src/__tests__/RealtimeClientSessionResolver.configTamper.test.ts +23 -3
  276. package/src/__tests__/RealtimeClientSessionResolver.test.ts +324 -46
  277. package/src/__tests__/RemoteBrowserActionResolver.ownership.test.ts +98 -0
  278. package/src/__tests__/ResolverBase.clientOldValues.test.ts +37 -4
  279. package/src/__tests__/ResolverBase.deleteReturnProjection.test.ts +52 -0
  280. package/src/__tests__/ResolverBase.entityMessageRelay.test.ts +176 -0
  281. package/src/__tests__/ResolverBase.includeBinaryFields.test.ts +23 -1
  282. package/src/__tests__/ResolverBase.publishStatusUpdate.test.ts +68 -0
  283. package/src/__tests__/ResolverBase.userViewCacheAndDedup.test.ts +130 -0
  284. package/src/__tests__/RunAIAgentResolver.branch.test.ts +68 -13
  285. package/src/__tests__/RunAIAgentResolver.conversationWriter.test.ts +210 -0
  286. package/src/__tests__/RunAIAgentResolver.fireAndForgetCompletion.test.ts +209 -0
  287. package/src/__tests__/RunAIAgentResolver.historyFrom.test.ts +17 -27
  288. package/src/__tests__/RunAIAgentResolver.runDataGuard.test.ts +8 -2
  289. package/src/__tests__/RunAIAgentResolver.serverReply.test.ts +358 -0
  290. package/src/__tests__/RunAIAgentResolver.stoppedPredecessor.test.ts +4 -1
  291. package/src/__tests__/RunTemplateResolver.test.ts +35 -2
  292. package/src/__tests__/RunViewResolver.cacheCheckForwarding.test.ts +11 -0
  293. package/src/__tests__/SessionManager.test.ts +95 -0
  294. package/src/__tests__/TaskGraphContinuationDeliverer.test.ts +114 -3
  295. package/src/__tests__/TransactionGroupResolver.fieldSecurity.test.ts +199 -0
  296. package/src/__tests__/UserViewResolver.updateWhereClause.test.ts +15 -0
  297. package/src/__tests__/ViewOperationsHandler.test.ts +7 -2
  298. package/src/__tests__/WidgetSessionService.test.ts +583 -4
  299. package/src/__tests__/apiRootBoot.test.ts +1 -1
  300. package/src/__tests__/buildMagicLinkSessionUser.test.ts +96 -0
  301. package/src/__tests__/cacheBroadcastProviders.test.ts +403 -0
  302. package/src/__tests__/cacheInvalidationRecordData.test.ts +45 -0
  303. package/src/__tests__/fieldSecurityFixtures.ts +91 -0
  304. package/src/__tests__/globalCors.test.ts +3 -3
  305. package/src/__tests__/localDevAuth.test.ts +196 -0
  306. package/src/__tests__/orphanedConversationDetailReconciler.test.ts +10 -0
  307. package/src/__tests__/pushStatusResolver.filter.test.ts +57 -1
  308. package/src/__tests__/realtimeRecordingHandler.test.ts +19 -2
  309. package/src/__tests__/realtimeSessions/RealtimeSessionEventsResolver.test.ts +29 -1
  310. package/src/__tests__/realtimeSessions/ownedRealtimeSession.anonymous.test.ts +31 -0
  311. package/src/__tests__/realtimeSessions/ownedRealtimeSession.namedScoped.test.ts +37 -0
  312. package/src/__tests__/realtimeSessions/sessionAccess.test.ts +146 -7
  313. package/src/__tests__/realtimeSessions/sessionConfigStamps.test.ts +1 -1
  314. package/src/__tests__/realtimeSessions/verificationWorkflow.test.ts +25 -4
  315. package/src/__tests__/resolverBase.cloudEventChangedFields.test.ts +157 -0
  316. package/src/__tests__/resolverBase.fieldSecurityTransport.test.ts +222 -0
  317. package/src/__tests__/resolverBase.fls.test.ts +146 -97
  318. package/src/__tests__/restTransport.fieldSecurity.test.ts +148 -0
  319. package/src/__tests__/runParamsTimeZone.test.ts +179 -0
  320. package/src/__tests__/runStreams.fieldSecurity.test.ts +100 -0
  321. package/src/__tests__/runViewProperties.test.ts +114 -0
  322. package/src/__tests__/scalabilityBenchmarks.test.ts +765 -0
  323. package/src/__tests__/scalabilityDatabaseIntegration.test.ts +207 -0
  324. package/src/__tests__/sessionUserClone.test.ts +5 -1
  325. package/src/__tests__/startupSweepOrder.test.ts +40 -0
  326. package/src/__tests__/unifiedAuth.test.ts +28 -0
  327. package/src/__tests__/widgetGuestElevation.test.ts +2 -0
  328. package/src/agentSessions/SessionJanitor.ts +3 -3
  329. package/src/agentSessions/SessionManager.ts +35 -12
  330. package/src/auth/AuthProviderCatalogRouter.ts +3 -0
  331. package/src/auth/index.ts +56 -12
  332. package/src/auth/initializeProviders.ts +43 -1
  333. package/src/auth/localDevAuth.ts +528 -0
  334. package/src/auth/magicLink/MagicLinkKeys.ts +2 -2
  335. package/src/auth/magicLink/types.ts +10 -0
  336. package/src/auth/sessionUserClone.ts +3 -2
  337. package/src/broadcast/BaseCacheInvalidationBroadcastProvider.ts +674 -0
  338. package/src/broadcast/index.ts +5 -0
  339. package/src/broadcast/providers/AWSIoTCoreBroadcastProvider.ts +180 -0
  340. package/src/broadcast/providers/AzureWebPubSubBroadcastProvider.ts +182 -0
  341. package/src/broadcast/providers/GCPPubSubBroadcastProvider.ts +169 -0
  342. package/src/broadcast/providers/SequencedRoleBucketBroadcastProvider.ts +57 -0
  343. package/src/cache.ts +2 -1
  344. package/src/config.ts +69 -0
  345. package/src/context.ts +32 -8
  346. package/src/coreRoutes.ts +15 -0
  347. package/src/generated/graphql-schemas/__mj.ts +2239 -102
  348. package/src/generic/CacheInvalidationResolver.ts +135 -78
  349. package/src/generic/OrphanedConversationDetailReconciler.ts +4 -2
  350. package/src/generic/PubSubManager.ts +54 -1
  351. package/src/generic/PushStatusResolver.ts +108 -11
  352. package/src/generic/ResolverBase.ts +237 -107
  353. package/src/generic/RunViewResolver.ts +80 -15
  354. package/src/generic/actionOutputFieldSecurity.ts +75 -0
  355. package/src/generic/fieldSecurityTransport.ts +62 -0
  356. package/src/index.ts +127 -68
  357. package/src/integration/CustomColumnPromoter.ts +6 -1
  358. package/src/logging/variablesLoggingMiddleware.ts +59 -3
  359. package/src/realtimeSessions/README.md +7 -3
  360. package/src/realtimeSessions/SessionVerificationPortsBase.ts +1 -0
  361. package/src/realtimeSessions/ownedRealtimeSession.ts +20 -6
  362. package/src/realtimeSessions/sessionAccess.ts +181 -25
  363. package/src/realtimeSessions/sessionConfigStamps.ts +1 -1
  364. package/src/realtimeSessions/subscriptionAuthorization.ts +4 -2
  365. package/src/realtimeSessions/verificationWorkflow.ts +3 -1
  366. package/src/realtimeWidget/WidgetRouter.ts +22 -4
  367. package/src/realtimeWidget/WidgetSessionService.ts +252 -17
  368. package/src/realtimeWidget/host-identity.ts +1 -1
  369. package/src/realtimeWidget/widgetCore.ts +30 -1
  370. package/src/realtimeWidget/widgetGuestElevation.ts +2 -1
  371. package/src/resolvers/ActionResolver.ts +78 -15
  372. package/src/resolvers/AdhocQueryResolver.ts +1 -0
  373. package/src/resolvers/AgentRunStatusPublisher.ts +36 -8
  374. package/src/resolvers/AgentSessionResolver.ts +46 -18
  375. package/src/resolvers/EntityCommunicationsResolver.ts +56 -15
  376. package/src/resolvers/FetchEntityVectorsResolver.ts +132 -21
  377. package/src/resolvers/FileCategoryResolver.ts +1 -0
  378. package/src/resolvers/FileResolver.ts +14 -4
  379. package/src/resolvers/IntegrationDiscoveryResolver.ts +49 -7
  380. package/src/resolvers/MergeRecordsResolver.ts +23 -2
  381. package/src/resolvers/PipelineProgressResolver.ts +12 -3
  382. package/src/resolvers/QueryResolver.ts +20 -6
  383. package/src/resolvers/QuerySystemUserResolver.ts +15 -6
  384. package/src/resolvers/RSUResolver.ts +12 -0
  385. package/src/resolvers/RealtimeClientSessionResolver.ts +104 -33
  386. package/src/resolvers/RemoteBrowserActionResolver.ts +15 -10
  387. package/src/resolvers/RunAIAgentResolver.ts +258 -82
  388. package/src/resolvers/RunTemplateResolver.ts +6 -4
  389. package/src/resolvers/RunTestResolver.ts +3 -1
  390. package/src/resolvers/SyncDataResolver.ts +4 -0
  391. package/src/resolvers/TestQuerySQLResolver.ts +1 -0
  392. package/src/resolvers/TransactionGroupResolver.ts +66 -15
  393. package/src/resolvers/UserViewResolver.ts +2 -1
  394. package/src/resolvers/__tests__/MergeRecordsResolver.test.ts +43 -0
  395. package/src/rest/EntityCRUDHandler.ts +22 -5
  396. package/src/rest/RESTEndpointHandler.ts +8 -5
  397. package/src/rest/RealtimeRecordingHandler.ts +13 -10
  398. package/src/rest/ViewOperationsHandler.ts +24 -6
  399. package/src/serverRoleConfigUnits.ts +48 -0
  400. package/src/services/TaskGraphContinuationDeliverer.ts +52 -20
  401. package/src/types.ts +23 -1
@@ -33,7 +33,7 @@
33
33
  */
34
34
  import { Resolver, Mutation, Arg, Ctx, Int, Float, ObjectType, Field, PubSub, PubSubEngine } from 'type-graphql';
35
35
  import { AppContext, UserPayload } from '../types.js';
36
- import { AuthorizationEvaluator, UserInfo, IMetadataProvider, LogError, LogErrorEx, LogStatus, RunView, BaseEntity } from '@memberjunction/core';
36
+ import { AuthorizationEvaluator, UserInfo, IMetadataProvider, DatabaseProviderBase, LogError, LogErrorEx, LogStatus, RunView, BaseEntity } from '@memberjunction/core';
37
37
  import { UUIDsEqual, IsValidUUID } from '@memberjunction/global';
38
38
  import {
39
39
  MJAIAgentEntity,
@@ -44,6 +44,8 @@ import {
44
44
  MJConversationDetailArtifactEntity,
45
45
  MJConversationDetailEntity,
46
46
  ConversationEngine,
47
+ MJConversationDetailEntityExtended,
48
+ MJConversationEntity,
47
49
  } from '@memberjunction/core-entities';
48
50
  import { AIEngine } from '@memberjunction/aiengine';
49
51
  import { AIAgentPermissionHelper, AIEngineBase, HasRealtimeUsage, ParseRealtimeUsageRecord, type RealtimeUsageRecord } from '@memberjunction/ai-engine-base';
@@ -62,6 +64,7 @@ import {
62
64
  RealtimeAllowedAgent,
63
65
  RealtimeDirectActionsConfig,
64
66
  REALTIME_ADVANCED_SESSION_CONTROLS_AUTHORIZATION,
67
+ SqlRealtimeRecordingLedger,
65
68
  resolveRecordingStorageAccountID,
66
69
  storeRealtimeRecording,
67
70
  writeRealtimeRecordingSegment,
@@ -88,6 +91,7 @@ import { RunWithTrustedSessionConfigWrites } from '@memberjunction/core-entities
88
91
  import { BuildMintConfigStamps, LoadInheritedVerifiedIdentity } from '../realtimeSessions/sessionConfigStamps.js';
89
92
  import { ParseConfigObject } from '../realtimeSessions/verificationCore.js';
90
93
  import { LoadOwnedRealtimeSession } from '../realtimeSessions/ownedRealtimeSession.js';
94
+ import { AuthorizeSessionAccess, LoadSessionForAccess } from '../realtimeSessions/sessionAccess.js';
91
95
 
92
96
  /**
93
97
  * Progress steps worth narrating to the realtime model — mirrors the normal agent-run path's filter
@@ -103,7 +107,6 @@ const SIGNIFICANT_PROGRESS_STEPS = ['prompt_execution', 'action_execution', 'sub
103
107
  const MAX_USAGE_DETAILS_JSON_LENGTH = 4096;
104
108
 
105
109
  /** Entity name — centralised so the `MJ:`-prefix convention is applied in exactly one place. */
106
- const SESSION_ENTITY = 'MJ: AI Agent Sessions';
107
110
  const CO_AGENT_ENTITY = 'MJ: AI Agent Co Agents';
108
111
  const CONVERSATION_DETAIL_ENTITY = 'MJ: Conversation Details';
109
112
  const CHANNEL_ENTITY = 'MJ: AI Agent Channels';
@@ -596,7 +599,7 @@ export class RealtimeClientSessionResolver extends ResolverBase {
596
599
  );
597
600
 
598
601
  // Best-effort: stamp recording-start metadata when the browser captured (with consent) at start.
599
- await this.stampRecordingStart(session, recordingConsent, recordingStartedAt);
602
+ await this.stampRecordingStart(session, recordingConsent, recordingStartedAt, contextUser, provider);
600
603
 
601
604
  const clientTools = this.parseClientTools(clientToolsJson);
602
605
  const channelCandidates = this.parseChannelCandidates(channelCandidatesJson);
@@ -665,10 +668,18 @@ export class RealtimeClientSessionResolver extends ResolverBase {
665
668
  contextUser: UserInfo,
666
669
  provider: IMetadataProvider,
667
670
  ): Promise<void> {
671
+ let inheritedVerified: Awaited<ReturnType<typeof LoadInheritedVerifiedIdentity>> = undefined;
672
+ try {
673
+ inheritedVerified = await LoadInheritedVerifiedIdentity(lastSessionId, contextUser, provider);
674
+ } catch (error) {
675
+ LogError(
676
+ `StartRealtimeClientSession: failed to load inherited verified identity for prior session ${lastSessionId}: ${(error as Error).message}`,
677
+ );
678
+ }
668
679
  const plan = BuildMintConfigStamps({
669
680
  EffectiveRealtime: this.readEffectiveRealtime(effectiveConfigJson),
670
681
  ExistingConfigRaw: session.Config_,
671
- InheritedVerified: await LoadInheritedVerifiedIdentity(lastSessionId, contextUser, provider),
682
+ InheritedVerified: inheritedVerified,
672
683
  NowMs: Date.now(),
673
684
  });
674
685
  if (!plan) {
@@ -903,12 +914,15 @@ export class RealtimeClientSessionResolver extends ResolverBase {
903
914
  ): Promise<boolean> {
904
915
  const { contextUser, provider } = this.requireUserAndProvider(userPayload, providers);
905
916
  const session = await this.loadOwnedActiveSession(agentSessionId, contextUser, provider);
906
-
907
- const saved = replacesPrevious
908
- ? await this.replacePreviousTranscriptTurn(session, role, text, contextUser, provider, utteranceStartMs, utteranceEndMs)
909
- : await this.persistTranscriptTurn(session, role, text, contextUser, provider, utteranceStartMs, utteranceEndMs);
910
- if (!saved) {
911
- return false;
917
+ const persistDetail =
918
+ this.mapTranscriptRole(role) === 'User' || (await this.callerOwnsConversation(session, contextUser, provider));
919
+ if (persistDetail) {
920
+ const saved = replacesPrevious
921
+ ? await this.replacePreviousTranscriptTurn(session, role, text, contextUser, provider, utteranceStartMs, utteranceEndMs)
922
+ : await this.persistTranscriptTurn(session, role, text, contextUser, provider, utteranceStartMs, utteranceEndMs);
923
+ if (!saved) {
924
+ return false;
925
+ }
912
926
  }
913
927
  // Mirror the turn onto the co-agent's long-lived prompt run so its Messages capture the full
914
928
  // conversation (run-viewer observability parity). Best-effort — never fails the transcript relay.
@@ -927,7 +941,7 @@ export class RealtimeClientSessionResolver extends ResolverBase {
927
941
  );
928
942
  }
929
943
  await this.sessionManager.Heartbeat(agentSessionId, contextUser, provider);
930
- return true;
944
+ return persistDetail;
931
945
  }
932
946
 
933
947
  /**
@@ -1016,16 +1030,21 @@ export class RealtimeClientSessionResolver extends ResolverBase {
1016
1030
  });
1017
1031
 
1018
1032
  // Canonical consolidated file written — drop the crash-recovery shards (best-effort).
1019
- if (stored.FileID) {
1033
+ // A FileID with an ErrorMessage is an uploaded file the session was not stamped with: the
1034
+ // shards are then the only recording the janitor could still recover, so keep them.
1035
+ const storedAndStamped = !!stored.FileID && !stored.ErrorMessage;
1036
+ if (storedAndStamped) {
1020
1037
  await deleteRealtimeRecordingSegments(agentSessionId, accountID, runUser);
1038
+ } else if (stored.FileID) {
1039
+ LogError(`RealtimeClientSessionResolver.UploadRealtimeRecording: session ${agentSessionId} has file ${stored.FileID} but it is not stamped (${stored.ErrorMessage}); shards kept`);
1021
1040
  }
1022
1041
 
1023
1042
  return {
1024
- Success: !!stored.FileID,
1043
+ Success: storedAndStamped,
1025
1044
  FileID: stored.FileID ?? undefined,
1026
1045
  // Report the reason the storage layer knew (e.g. Drive's "Service Accounts do not have
1027
1046
  // storage quota"); the generic sentence is only for when no layer supplied one.
1028
- ErrorMessage: stored.FileID ? undefined : (stored.ErrorMessage ?? 'Storage upload failed.'),
1047
+ ErrorMessage: storedAndStamped ? undefined : (stored.ErrorMessage ?? 'Storage upload failed.'),
1029
1048
  };
1030
1049
  } catch (error) {
1031
1050
  const message = error instanceof Error ? error.message : String(error);
@@ -1477,7 +1496,7 @@ export class RealtimeClientSessionResolver extends ResolverBase {
1477
1496
  private requireUserAndProvider(
1478
1497
  userPayload: AppContext['userPayload'],
1479
1498
  providers: AppContext['providers'],
1480
- ): { contextUser: UserInfo; provider: IMetadataProvider } {
1499
+ ): { contextUser: UserInfo; provider: DatabaseProviderBase } {
1481
1500
  const contextUser = this.GetUserFromPayload(userPayload);
1482
1501
  if (!contextUser) {
1483
1502
  throw new Error('Not authenticated: no user context for realtime session operation');
@@ -2064,14 +2083,18 @@ export class RealtimeClientSessionResolver extends ResolverBase {
2064
2083
  return null;
2065
2084
  }
2066
2085
  try {
2067
- const prior = await provider.GetEntityObject<MJAIAgentSessionEntity>(SESSION_ENTITY, contextUser);
2068
- if (!(await prior.Load(lastSessionId))) {
2086
+ const loaded = await LoadSessionForAccess(lastSessionId, contextUser, provider);
2087
+ if (!loaded) {
2069
2088
  LogError(`StartRealtimeClientSession: prior session ${lastSessionId} not found — skipping channel-state restore.`);
2070
2089
  return null;
2071
2090
  }
2072
- if (!UUIDsEqual(prior.UserID, contextUser.ID)) {
2091
+ const access = AuthorizeSessionAccess(
2092
+ { SessionUserID: loaded.Session.UserID, ConversationExternalID: loaded.ConversationExternalID, ConversationReadable: loaded.ConversationReadable },
2093
+ contextUser,
2094
+ );
2095
+ if (!access.Allowed) {
2073
2096
  LogError(
2074
- `StartRealtimeClientSession: prior session ${lastSessionId} is not owned by user ${contextUser.ID} — ` +
2097
+ `StartRealtimeClientSession: prior session ${lastSessionId} is not owned by user ${contextUser.ID} (${access.Reason}) — ` +
2075
2098
  'skipping channel-state restore.',
2076
2099
  );
2077
2100
  return null;
@@ -2278,24 +2301,28 @@ export class RealtimeClientSessionResolver extends ResolverBase {
2278
2301
  break;
2279
2302
  }
2280
2303
  visited.add(key);
2281
- const leg = await provider.GetEntityObject<MJAIAgentSessionEntity>(SESSION_ENTITY, contextUser);
2282
- if (!(await leg.Load(cursor))) {
2304
+ const loaded = await LoadSessionForAccess(cursor, contextUser, provider);
2305
+ if (!loaded) {
2283
2306
  if (legIDs.length === 0) {
2284
2307
  LogError(`StartRealtimeClientSession: prior session ${cursor} not found — skipping transcript hydration.`);
2285
2308
  }
2286
2309
  break;
2287
2310
  }
2288
- if (!UUIDsEqual(leg.UserID, contextUser.ID)) {
2311
+ const access = AuthorizeSessionAccess(
2312
+ { SessionUserID: loaded.Session.UserID, ConversationExternalID: loaded.ConversationExternalID, ConversationReadable: loaded.ConversationReadable },
2313
+ contextUser,
2314
+ );
2315
+ if (!access.Allowed) {
2289
2316
  if (legIDs.length === 0) {
2290
2317
  LogError(
2291
- `StartRealtimeClientSession: prior session ${cursor} is not owned by user ${contextUser.ID} — ` +
2318
+ `StartRealtimeClientSession: prior session ${cursor} is not owned by user ${contextUser.ID} (${access.Reason}) — ` +
2292
2319
  'skipping transcript hydration.',
2293
2320
  );
2294
2321
  }
2295
2322
  break;
2296
2323
  }
2297
- legIDs.push(leg.ID);
2298
- cursor = leg.LastSessionID ?? null;
2324
+ legIDs.push(loaded.Session.ID);
2325
+ cursor = loaded.Session.LastSessionID ?? null;
2299
2326
  }
2300
2327
  return legIDs;
2301
2328
  }
@@ -2576,8 +2603,9 @@ export class RealtimeClientSessionResolver extends ResolverBase {
2576
2603
  callerUser: UserInfo,
2577
2604
  provider: IMetadataProvider,
2578
2605
  ): Promise<string | null> {
2579
- const detail = await provider.GetEntityObject<MJConversationDetailEntity>(CONVERSATION_DETAIL_ENTITY, callerUser);
2606
+ const detail = await provider.GetEntityObject<MJConversationDetailEntityExtended>(CONVERSATION_DETAIL_ENTITY, callerUser);
2580
2607
  detail.NewRecord();
2608
+ detail.MarkServerAuthoredReply(); // a server-written system anchor, not the caller's words
2581
2609
  detail.ConversationID = session.ConversationID;
2582
2610
  detail.BranchID = this.sessionBranchIdOf(session);
2583
2611
  detail.Role = 'AI';
@@ -2845,17 +2873,26 @@ export class RealtimeClientSessionResolver extends ResolverBase {
2845
2873
 
2846
2874
  /**
2847
2875
  * Stamps `RecordingStartedAt` (the recording `t0` alignment origin) + `RecordingMedia` on a
2848
- * just-started session when the browser captured WITH consent. Best-effort: a parse/save failure
2849
- * is logged and swallowed — a recording-metadata problem must never fail the session start.
2876
+ * just-started session when the browser captured WITH consent. `RecordingStartedAt` goes through
2877
+ * the entity save (and stays set on the in-memory session, so a later save of it cannot clear it);
2878
+ * `RecordingMedia` is a recording-ledger column that an entity save cannot write (#6010), so it goes
2879
+ * through the ledger's `spStampAIAgentSessionRecordingFile` proc. The proc stamps `t0` as well, so it
2880
+ * lands even when the entity save fails: the janitor recovers only sessions that carry a
2881
+ * `RecordingStartedAt`. Best-effort: a parse/save/stamp failure is logged and swallowed — a
2882
+ * recording-metadata problem must never fail the session start.
2850
2883
  *
2851
2884
  * @param session The freshly created/loaded session.
2852
2885
  * @param recordingConsent Whether the user consented to recording — only `true` stamps anything.
2853
2886
  * @param recordingStartedAt ISO-8601 recording start timestamp from the browser.
2887
+ * @param contextUser The caller, on whose behalf the proc runs.
2888
+ * @param provider The server-side database provider the proc runs through.
2854
2889
  */
2855
2890
  private async stampRecordingStart(
2856
2891
  session: MJAIAgentSessionEntity,
2857
2892
  recordingConsent: boolean | undefined,
2858
2893
  recordingStartedAt: string | undefined,
2894
+ contextUser: UserInfo,
2895
+ provider: DatabaseProviderBase,
2859
2896
  ): Promise<void> {
2860
2897
  if (recordingConsent !== true || !recordingStartedAt) {
2861
2898
  return;
@@ -2866,12 +2903,19 @@ export class RealtimeClientSessionResolver extends ResolverBase {
2866
2903
  return;
2867
2904
  }
2868
2905
  session.RecordingStartedAt = startedAt;
2869
- session.RecordingMedia = 'Audio';
2870
2906
  if (!(await session.Save())) {
2871
2907
  LogError(
2872
2908
  `RealtimeClientSessionResolver.stampRecordingStart save failed for session ${session.ID}: ${this.describeSaveFailure(session)}`,
2873
2909
  );
2874
2910
  }
2911
+ try {
2912
+ await new SqlRealtimeRecordingLedger(provider, contextUser).StampFile(session.ID, { media: 'Audio', startedAt });
2913
+ } catch (error) {
2914
+ LogError(
2915
+ `RealtimeClientSessionResolver.stampRecordingStart media stamp failed for session ${session.ID}: ` +
2916
+ `${error instanceof Error ? error.message : String(error)}`,
2917
+ );
2918
+ }
2875
2919
  }
2876
2920
 
2877
2921
  /**
@@ -2890,11 +2934,14 @@ export class RealtimeClientSessionResolver extends ResolverBase {
2890
2934
  utteranceStartMs?: number,
2891
2935
  utteranceEndMs?: number,
2892
2936
  ): Promise<boolean> {
2893
- const detail = await provider.GetEntityObject<MJConversationDetailEntity>(
2937
+ const detail = await provider.GetEntityObject<MJConversationDetailEntityExtended>(
2894
2938
  CONVERSATION_DETAIL_ENTITY,
2895
2939
  contextUser,
2896
2940
  );
2897
2941
  detail.NewRecord();
2942
+ // The agent's side of the session's transcript is written here, on the server, for the session's owner
2943
+ // (the user's side is theirs and the marker does not touch it).
2944
+ detail.MarkServerAuthoredReply();
2898
2945
  detail.ConversationID = session.ConversationID;
2899
2946
  detail.BranchID = this.sessionBranchIdOf(session);
2900
2947
  detail.Role = this.mapTranscriptRole(role);
@@ -2983,10 +3030,11 @@ export class RealtimeClientSessionResolver extends ResolverBase {
2983
3030
  // failure here looked like before the re-load. The insert path beside this one has
2984
3031
  // always used `GetEntityObject`; this now matches it, which is also why they now succeed
2985
3032
  // and fail for the same reasons.
2986
- const previous = await provider.GetEntityObject<MJConversationDetailEntity>(
3033
+ const previous = await provider.GetEntityObject<MJConversationDetailEntityExtended>(
2987
3034
  CONVERSATION_DETAIL_ENTITY,
2988
3035
  writeUser,
2989
3036
  );
3037
+ previous.MarkServerAuthoredReply(); // as persistTranscriptTurn: the session's own transcript turn
2990
3038
  if (!(await previous.Load(found.ID))) {
2991
3039
  LogError(
2992
3040
  `RealtimeClientSessionResolver.replacePreviousTranscriptTurn could not re-load turn `
@@ -3027,6 +3075,28 @@ export class RealtimeClientSessionResolver extends ResolverBase {
3027
3075
  return role.trim().toLowerCase() === 'user' ? 'User' : 'AI';
3028
3076
  }
3029
3077
 
3078
+ /**
3079
+ * True when the session's conversation belongs to the caller. In client-direct mode the agent's
3080
+ * words and tool facts reach the server only from the browser, so the server can't vouch for them:
3081
+ * they are stored as the agent's reply only in the caller's own conversation (A19). In a
3082
+ * conversation shared with the caller, only the caller's own side of the session is kept.
3083
+ */
3084
+ private async callerOwnsConversation(
3085
+ session: MJAIAgentSessionEntity,
3086
+ contextUser: UserInfo,
3087
+ provider: IMetadataProvider,
3088
+ ): Promise<boolean> {
3089
+ if (!session.ConversationID) {
3090
+ return false;
3091
+ }
3092
+ const conversation = await provider.GetEntityObject<MJConversationEntity>('MJ: Conversations', contextUser);
3093
+ const owned = (await conversation.Load(session.ConversationID)) && UUIDsEqual(conversation.UserID, contextUser.ID);
3094
+ if (!owned) {
3095
+ LogStatus(`RealtimeClientSessionResolver: session ${session.ID} relays the agent's side only into the caller's own conversation; conversation ${session.ConversationID} is not the caller's, so the agent's turn is not stored.`);
3096
+ }
3097
+ return owned;
3098
+ }
3099
+
3030
3100
  /**
3031
3101
  * Persists a direct action or channel tool execution as a hidden ConversationDetail turn.
3032
3102
  * Stored as stable facts (Role: 'AI', HiddenToUser: true, ExternalID: callId, CompletionTime: durationMs,
@@ -3060,15 +3130,16 @@ export class RealtimeClientSessionResolver extends ResolverBase {
3060
3130
  contextUser: UserInfo,
3061
3131
  provider: IMetadataProvider,
3062
3132
  ): Promise<boolean> {
3063
- if (!session.ConversationID) {
3133
+ if (!(await this.callerOwnsConversation(session, contextUser, provider))) {
3064
3134
  return false;
3065
3135
  }
3066
3136
  try {
3067
- const detail = await provider.GetEntityObject<MJConversationDetailEntity>(
3137
+ const detail = await provider.GetEntityObject<MJConversationDetailEntityExtended>(
3068
3138
  CONVERSATION_DETAIL_ENTITY,
3069
3139
  contextUser,
3070
3140
  );
3071
3141
  detail.NewRecord();
3142
+ detail.MarkServerAuthoredReply(); // the tool's facts are recorded by the server, as the session's owner
3072
3143
  detail.ConversationID = session.ConversationID;
3073
3144
  detail.BranchID = this.sessionBranchIdOf(session);
3074
3145
  detail.Role = 'AI';
@@ -19,7 +19,6 @@
19
19
  import { Resolver, Mutation, Query, Arg, Ctx, Float, Int, ObjectType, Field, PubSub, PubSubEngine } from 'type-graphql';
20
20
  import { AppContext, UserPayload } from '../types.js';
21
21
  import { UserInfo, IMetadataProvider, LogError } from '@memberjunction/core';
22
- import { UUIDsEqual } from '@memberjunction/global';
23
22
  import { MJAIAgentSessionEntity, MJAIAgentEntity } from '@memberjunction/core-entities';
24
23
  import { NormalizeInstanceKey, RemoteBrowserEngine } from '@memberjunction/remote-browser-server';
25
24
  import { BeginBrowserGoalStep, FinalizeBrowserGoalStep, ExtractCoAgentRunID } from '../agentSessions/remoteBrowserGoalEngine.js';
@@ -35,13 +34,16 @@ import {
35
34
  } from '@memberjunction/remote-browser-base';
36
35
  import { ResolverBase } from '../generic/ResolverBase.js';
37
36
  import { GetReadWriteProvider } from '../util.js';
37
+ import {
38
+ LoadOwnedRealtimeSession,
39
+ RealtimeSessionNotFoundError,
40
+ RealtimeSessionOwnershipError,
41
+ } from '../realtimeSessions/ownedRealtimeSession.js';
38
42
  import { PUSH_STATUS_UPDATES_TOPIC } from '../generic/PushStatusResolver.js';
39
43
  import { AIEngine } from '@memberjunction/aiengine';
40
44
  import { AIPromptRunner } from '@memberjunction/ai-prompts';
41
45
  import { AIPromptParams } from '@memberjunction/ai-core-plus';
42
46
 
43
- /** Entity name — centralised so the `MJ:`-prefix convention is applied in exactly one place. */
44
- const SESSION_ENTITY = 'MJ: AI Agent Sessions';
45
47
  /** Entity name for the agent whose `TypeConfiguration` carries the remote-browser provider preference. */
46
48
  const AGENT_ENTITY = 'MJ: AI Agents';
47
49
  /**
@@ -1084,14 +1086,17 @@ export class RemoteBrowserActionResolver extends ResolverBase {
1084
1086
  * @returns The loaded, owned session entity.
1085
1087
  */
1086
1088
  protected async loadOwnedSession(agentSessionID: string, contextUser: UserInfo, provider: IMetadataProvider): Promise<MJAIAgentSessionEntity> {
1087
- const session = await provider.GetEntityObject<MJAIAgentSessionEntity>(SESSION_ENTITY, contextUser);
1088
- if (!(await session.Load(agentSessionID))) {
1089
- throw new Error(`Remote-browser session ${agentSessionID} not found.`);
1090
- }
1091
- if (!UUIDsEqual(session.UserID, contextUser.ID)) {
1092
- throw new Error(`Not authorized: remote-browser session ${agentSessionID} is not owned by you.`);
1089
+ try {
1090
+ return await LoadOwnedRealtimeSession(agentSessionID, contextUser, provider);
1091
+ } catch (err) {
1092
+ if (err instanceof RealtimeSessionNotFoundError) {
1093
+ throw new Error(`Remote-browser session ${agentSessionID} not found.`);
1094
+ }
1095
+ if (err instanceof RealtimeSessionOwnershipError) {
1096
+ throw new Error(`Not authorized: remote-browser session ${agentSessionID} is not owned by you.`);
1097
+ }
1098
+ throw err;
1093
1099
  }
1094
- return session;
1095
1100
  }
1096
1101
 
1097
1102
  /**