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

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 (435) hide show
  1. package/README.md +30 -0
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/agentSessions/BridgeHostInstance.d.ts +25 -0
  4. package/dist/agentSessions/BridgeHostInstance.d.ts.map +1 -0
  5. package/dist/agentSessions/BridgeHostInstance.js +30 -0
  6. package/dist/agentSessions/BridgeHostInstance.js.map +1 -0
  7. package/dist/agentSessions/HostInstance.d.ts +75 -11
  8. package/dist/agentSessions/HostInstance.d.ts.map +1 -1
  9. package/dist/agentSessions/HostInstance.js +99 -28
  10. package/dist/agentSessions/HostInstance.js.map +1 -1
  11. package/dist/agentSessions/ReturningVisitorRecap.d.ts.map +1 -1
  12. package/dist/agentSessions/ReturningVisitorRecap.js +7 -3
  13. package/dist/agentSessions/ReturningVisitorRecap.js.map +1 -1
  14. package/dist/agentSessions/SessionJanitor.d.ts +173 -25
  15. package/dist/agentSessions/SessionJanitor.d.ts.map +1 -1
  16. package/dist/agentSessions/SessionJanitor.js +452 -54
  17. package/dist/agentSessions/SessionJanitor.js.map +1 -1
  18. package/dist/agentSessions/SessionManager.d.ts +43 -2
  19. package/dist/agentSessions/SessionManager.d.ts.map +1 -1
  20. package/dist/agentSessions/SessionManager.js +99 -8
  21. package/dist/agentSessions/SessionManager.js.map +1 -1
  22. package/dist/agentSessions/SessionRunIDVerifier.d.ts +63 -0
  23. package/dist/agentSessions/SessionRunIDVerifier.d.ts.map +1 -0
  24. package/dist/agentSessions/SessionRunIDVerifier.js +129 -0
  25. package/dist/agentSessions/SessionRunIDVerifier.js.map +1 -0
  26. package/dist/agentSessions/index.d.ts +2 -0
  27. package/dist/agentSessions/index.d.ts.map +1 -1
  28. package/dist/agentSessions/index.js +10 -3
  29. package/dist/agentSessions/index.js.map +1 -1
  30. package/dist/auth/actionAuthorization.d.ts +40 -0
  31. package/dist/auth/actionAuthorization.d.ts.map +1 -0
  32. package/dist/auth/actionAuthorization.js +94 -0
  33. package/dist/auth/actionAuthorization.js.map +1 -0
  34. package/dist/auth/index.d.ts.map +1 -1
  35. package/dist/auth/index.js +3 -10
  36. package/dist/auth/index.js.map +1 -1
  37. package/dist/auth/magicLink/MagicLinkService.d.ts.map +1 -1
  38. package/dist/auth/magicLink/MagicLinkService.js +6 -3
  39. package/dist/auth/magicLink/MagicLinkService.js.map +1 -1
  40. package/dist/auth/newUsers.d.ts +10 -0
  41. package/dist/auth/newUsers.d.ts.map +1 -1
  42. package/dist/auth/newUsers.js +80 -11
  43. package/dist/auth/newUsers.js.map +1 -1
  44. package/dist/config.d.ts +4567 -71
  45. package/dist/config.d.ts.map +1 -1
  46. package/dist/config.js +246 -3
  47. package/dist/config.js.map +1 -1
  48. package/dist/context.d.ts +8 -0
  49. package/dist/context.d.ts.map +1 -1
  50. package/dist/context.js +25 -34
  51. package/dist/context.js.map +1 -1
  52. package/dist/generated/graphql-schemas/__mj.d.ts +1073 -10
  53. package/dist/generated/graphql-schemas/__mj.d.ts.map +1 -1
  54. package/dist/generated/graphql-schemas/__mj.js +9188 -3649
  55. package/dist/generated/graphql-schemas/__mj.js.map +1 -1
  56. package/dist/generic/OrphanedConversationDetailReconciler.js +3 -3
  57. package/dist/generic/OrphanedConversationDetailReconciler.js.map +1 -1
  58. package/dist/generic/ResolverBase.d.ts +62 -6
  59. package/dist/generic/ResolverBase.d.ts.map +1 -1
  60. package/dist/generic/ResolverBase.js +179 -35
  61. package/dist/generic/ResolverBase.js.map +1 -1
  62. package/dist/generic/RunViewResolver.d.ts +4 -0
  63. package/dist/generic/RunViewResolver.d.ts.map +1 -1
  64. package/dist/generic/RunViewResolver.js +37 -1
  65. package/dist/generic/RunViewResolver.js.map +1 -1
  66. package/dist/index.d.ts +7 -0
  67. package/dist/index.d.ts.map +1 -1
  68. package/dist/index.js +214 -159
  69. package/dist/index.js.map +1 -1
  70. package/dist/isolatedProvider.d.ts +20 -0
  71. package/dist/isolatedProvider.d.ts.map +1 -0
  72. package/dist/isolatedProvider.js +22 -0
  73. package/dist/isolatedProvider.js.map +1 -0
  74. package/dist/postgresqlCompat.d.ts +8 -0
  75. package/dist/postgresqlCompat.d.ts.map +1 -0
  76. package/dist/postgresqlCompat.js +19 -0
  77. package/dist/postgresqlCompat.js.map +1 -0
  78. package/dist/postgresqlPoolSettings.d.ts +108 -0
  79. package/dist/postgresqlPoolSettings.d.ts.map +1 -0
  80. package/dist/postgresqlPoolSettings.js +134 -0
  81. package/dist/postgresqlPoolSettings.js.map +1 -0
  82. package/dist/realtimeProxy/RealtimeProxyServer.d.ts +44 -4
  83. package/dist/realtimeProxy/RealtimeProxyServer.d.ts.map +1 -1
  84. package/dist/realtimeProxy/RealtimeProxyServer.js +121 -16
  85. package/dist/realtimeProxy/RealtimeProxyServer.js.map +1 -1
  86. package/dist/realtimeProxy/RealtimeRelayTunnel.d.ts +171 -0
  87. package/dist/realtimeProxy/RealtimeRelayTunnel.d.ts.map +1 -0
  88. package/dist/realtimeProxy/RealtimeRelayTunnel.js +532 -0
  89. package/dist/realtimeProxy/RealtimeRelayTunnel.js.map +1 -0
  90. package/dist/realtimeSessions/RealtimeSessionEventService.d.ts +148 -0
  91. package/dist/realtimeSessions/RealtimeSessionEventService.d.ts.map +1 -0
  92. package/dist/realtimeSessions/RealtimeSessionEventService.js +191 -0
  93. package/dist/realtimeSessions/RealtimeSessionEventService.js.map +1 -0
  94. package/dist/realtimeSessions/RealtimeSessionVerificationService.d.ts +66 -0
  95. package/dist/realtimeSessions/RealtimeSessionVerificationService.d.ts.map +1 -0
  96. package/dist/realtimeSessions/RealtimeSessionVerificationService.js +138 -0
  97. package/dist/realtimeSessions/RealtimeSessionVerificationService.js.map +1 -0
  98. package/dist/realtimeSessions/RealtimeVerifyRouter.d.ts +38 -0
  99. package/dist/realtimeSessions/RealtimeVerifyRouter.d.ts.map +1 -0
  100. package/dist/realtimeSessions/RealtimeVerifyRouter.js +98 -0
  101. package/dist/realtimeSessions/RealtimeVerifyRouter.js.map +1 -0
  102. package/dist/realtimeSessions/SessionVerificationPortsBase.d.ts +61 -0
  103. package/dist/realtimeSessions/SessionVerificationPortsBase.d.ts.map +1 -0
  104. package/dist/realtimeSessions/SessionVerificationPortsBase.js +149 -0
  105. package/dist/realtimeSessions/SessionVerificationPortsBase.js.map +1 -0
  106. package/dist/realtimeSessions/SlidingWindowRateLimiter.d.ts +57 -0
  107. package/dist/realtimeSessions/SlidingWindowRateLimiter.d.ts.map +1 -0
  108. package/dist/realtimeSessions/SlidingWindowRateLimiter.js +69 -0
  109. package/dist/realtimeSessions/SlidingWindowRateLimiter.js.map +1 -0
  110. package/dist/realtimeSessions/index.d.ts +17 -0
  111. package/dist/realtimeSessions/index.d.ts.map +1 -0
  112. package/dist/realtimeSessions/index.js +17 -0
  113. package/dist/realtimeSessions/index.js.map +1 -0
  114. package/dist/realtimeSessions/sessionAccess.d.ts +86 -0
  115. package/dist/realtimeSessions/sessionAccess.d.ts.map +1 -0
  116. package/dist/realtimeSessions/sessionAccess.js +90 -0
  117. package/dist/realtimeSessions/sessionAccess.js.map +1 -0
  118. package/dist/realtimeSessions/sessionConfigStamps.d.ts +70 -0
  119. package/dist/realtimeSessions/sessionConfigStamps.d.ts.map +1 -0
  120. package/dist/realtimeSessions/sessionConfigStamps.js +93 -0
  121. package/dist/realtimeSessions/sessionConfigStamps.js.map +1 -0
  122. package/dist/realtimeSessions/subscriptionAuthorization.d.ts +65 -0
  123. package/dist/realtimeSessions/subscriptionAuthorization.d.ts.map +1 -0
  124. package/dist/realtimeSessions/subscriptionAuthorization.js +71 -0
  125. package/dist/realtimeSessions/subscriptionAuthorization.js.map +1 -0
  126. package/dist/realtimeSessions/verificationCore.d.ts +243 -0
  127. package/dist/realtimeSessions/verificationCore.d.ts.map +1 -0
  128. package/dist/realtimeSessions/verificationCore.js +356 -0
  129. package/dist/realtimeSessions/verificationCore.js.map +1 -0
  130. package/dist/realtimeSessions/verificationPages.d.ts +66 -0
  131. package/dist/realtimeSessions/verificationPages.d.ts.map +1 -0
  132. package/dist/realtimeSessions/verificationPages.js +110 -0
  133. package/dist/realtimeSessions/verificationPages.js.map +1 -0
  134. package/dist/realtimeSessions/verificationPolicy.d.ts +147 -0
  135. package/dist/realtimeSessions/verificationPolicy.d.ts.map +1 -0
  136. package/dist/realtimeSessions/verificationPolicy.js +249 -0
  137. package/dist/realtimeSessions/verificationPolicy.js.map +1 -0
  138. package/dist/realtimeSessions/verificationWorkflow.d.ts +263 -0
  139. package/dist/realtimeSessions/verificationWorkflow.d.ts.map +1 -0
  140. package/dist/realtimeSessions/verificationWorkflow.js +435 -0
  141. package/dist/realtimeSessions/verificationWorkflow.js.map +1 -0
  142. package/dist/realtimeWidget/widgetGuestElevation.d.ts +20 -2
  143. package/dist/realtimeWidget/widgetGuestElevation.d.ts.map +1 -1
  144. package/dist/realtimeWidget/widgetGuestElevation.js +31 -2
  145. package/dist/realtimeWidget/widgetGuestElevation.js.map +1 -1
  146. package/dist/resolvers/ActionResolver.d.ts +31 -5
  147. package/dist/resolvers/ActionResolver.d.ts.map +1 -1
  148. package/dist/resolvers/ActionResolver.js +75 -14
  149. package/dist/resolvers/ActionResolver.js.map +1 -1
  150. package/dist/resolvers/AdhocQueryResolver.d.ts +35 -17
  151. package/dist/resolvers/AdhocQueryResolver.d.ts.map +1 -1
  152. package/dist/resolvers/AdhocQueryResolver.js +92 -166
  153. package/dist/resolvers/AdhocQueryResolver.js.map +1 -1
  154. package/dist/resolvers/CacheStatsResolver.d.ts +27 -0
  155. package/dist/resolvers/CacheStatsResolver.d.ts.map +1 -1
  156. package/dist/resolvers/CacheStatsResolver.js +113 -2
  157. package/dist/resolvers/CacheStatsResolver.js.map +1 -1
  158. package/dist/resolvers/ClientToolRequestResolver.d.ts +4 -2
  159. package/dist/resolvers/ClientToolRequestResolver.d.ts.map +1 -1
  160. package/dist/resolvers/ClientToolRequestResolver.js +28 -10
  161. package/dist/resolvers/ClientToolRequestResolver.js.map +1 -1
  162. package/dist/resolvers/EntityRecordNameResolver.d.ts +7 -23
  163. package/dist/resolvers/EntityRecordNameResolver.d.ts.map +1 -1
  164. package/dist/resolvers/EntityRecordNameResolver.js +9 -47
  165. package/dist/resolvers/EntityRecordNameResolver.js.map +1 -1
  166. package/dist/resolvers/FetchEntityVectorsResolver.d.ts +12 -1
  167. package/dist/resolvers/FetchEntityVectorsResolver.d.ts.map +1 -1
  168. package/dist/resolvers/FetchEntityVectorsResolver.js +83 -2
  169. package/dist/resolvers/FetchEntityVectorsResolver.js.map +1 -1
  170. package/dist/resolvers/GetDataResolver.d.ts.map +1 -1
  171. package/dist/resolvers/GetDataResolver.js +9 -0
  172. package/dist/resolvers/GetDataResolver.js.map +1 -1
  173. package/dist/resolvers/HumanHandoffResolver.d.ts +107 -0
  174. package/dist/resolvers/HumanHandoffResolver.d.ts.map +1 -0
  175. package/dist/resolvers/HumanHandoffResolver.js +330 -0
  176. package/dist/resolvers/HumanHandoffResolver.js.map +1 -0
  177. package/dist/resolvers/MCPResolver.d.ts.map +1 -1
  178. package/dist/resolvers/MCPResolver.js +9 -4
  179. package/dist/resolvers/MCPResolver.js.map +1 -1
  180. package/dist/resolvers/MeetingResolver.d.ts +69 -0
  181. package/dist/resolvers/MeetingResolver.d.ts.map +1 -0
  182. package/dist/resolvers/MeetingResolver.js +381 -0
  183. package/dist/resolvers/MeetingResolver.js.map +1 -0
  184. package/dist/resolvers/RealtimeBridgeResolver.d.ts +88 -3
  185. package/dist/resolvers/RealtimeBridgeResolver.d.ts.map +1 -1
  186. package/dist/resolvers/RealtimeBridgeResolver.js +352 -12
  187. package/dist/resolvers/RealtimeBridgeResolver.js.map +1 -1
  188. package/dist/resolvers/RealtimeClientSessionResolver.d.ts +156 -108
  189. package/dist/resolvers/RealtimeClientSessionResolver.d.ts.map +1 -1
  190. package/dist/resolvers/RealtimeClientSessionResolver.js +395 -293
  191. package/dist/resolvers/RealtimeClientSessionResolver.js.map +1 -1
  192. package/dist/resolvers/RealtimeSessionEventsResolver.d.ts +61 -0
  193. package/dist/resolvers/RealtimeSessionEventsResolver.d.ts.map +1 -0
  194. package/dist/resolvers/RealtimeSessionEventsResolver.js +130 -0
  195. package/dist/resolvers/RealtimeSessionEventsResolver.js.map +1 -0
  196. package/dist/resolvers/RealtimeSessionVerificationResolver.d.ts +85 -0
  197. package/dist/resolvers/RealtimeSessionVerificationResolver.d.ts.map +1 -0
  198. package/dist/resolvers/RealtimeSessionVerificationResolver.js +188 -0
  199. package/dist/resolvers/RealtimeSessionVerificationResolver.js.map +1 -0
  200. package/dist/resolvers/RemoteBrowserActionResolver.d.ts +2 -0
  201. package/dist/resolvers/RemoteBrowserActionResolver.d.ts.map +1 -1
  202. package/dist/resolvers/RemoteBrowserActionResolver.js +5 -1
  203. package/dist/resolvers/RemoteBrowserActionResolver.js.map +1 -1
  204. package/dist/resolvers/RunAIAgentResolver.d.ts +10 -0
  205. package/dist/resolvers/RunAIAgentResolver.d.ts.map +1 -1
  206. package/dist/resolvers/RunAIAgentResolver.js +68 -11
  207. package/dist/resolvers/RunAIAgentResolver.js.map +1 -1
  208. package/dist/resolvers/RunTemplateResolver.d.ts.map +1 -1
  209. package/dist/resolvers/RunTemplateResolver.js +12 -11
  210. package/dist/resolvers/RunTemplateResolver.js.map +1 -1
  211. package/dist/resolvers/SyncDataResolver.d.ts.map +1 -1
  212. package/dist/resolvers/SyncDataResolver.js +6 -2
  213. package/dist/resolvers/SyncDataResolver.js.map +1 -1
  214. package/dist/resolvers/SyncRolesUsersResolver.d.ts +2 -0
  215. package/dist/resolvers/SyncRolesUsersResolver.d.ts.map +1 -1
  216. package/dist/resolvers/SyncRolesUsersResolver.js +23 -6
  217. package/dist/resolvers/SyncRolesUsersResolver.js.map +1 -1
  218. package/dist/resolvers/UserAvatarResolver.d.ts +16 -0
  219. package/dist/resolvers/UserAvatarResolver.d.ts.map +1 -0
  220. package/dist/resolvers/UserAvatarResolver.js +124 -0
  221. package/dist/resolvers/UserAvatarResolver.js.map +1 -0
  222. package/dist/resolvers/UserResolver.d.ts.map +1 -1
  223. package/dist/resolvers/UserResolver.js +2 -17
  224. package/dist/resolvers/UserResolver.js.map +1 -1
  225. package/dist/resolvers/adhocTimeout.d.ts +7 -0
  226. package/dist/resolvers/adhocTimeout.d.ts.map +1 -0
  227. package/dist/resolvers/adhocTimeout.js +12 -0
  228. package/dist/resolvers/adhocTimeout.js.map +1 -0
  229. package/dist/resolvers/agentVisionConsentAudit.d.ts +37 -0
  230. package/dist/resolvers/agentVisionConsentAudit.d.ts.map +1 -0
  231. package/dist/resolvers/agentVisionConsentAudit.js +63 -0
  232. package/dist/resolvers/agentVisionConsentAudit.js.map +1 -0
  233. package/dist/resolvers/avatarInputValidation.d.ts +40 -0
  234. package/dist/resolvers/avatarInputValidation.d.ts.map +1 -0
  235. package/dist/resolvers/avatarInputValidation.js +97 -0
  236. package/dist/resolvers/avatarInputValidation.js.map +1 -0
  237. package/dist/resolvers/currentUserRoles.d.ts +29 -0
  238. package/dist/resolvers/currentUserRoles.d.ts.map +1 -1
  239. package/dist/resolvers/currentUserRoles.js +30 -0
  240. package/dist/resolvers/currentUserRoles.js.map +1 -1
  241. package/dist/resolvers/meetings/index.d.ts +5 -0
  242. package/dist/resolvers/meetings/index.d.ts.map +1 -0
  243. package/dist/resolvers/meetings/index.js +5 -0
  244. package/dist/resolvers/meetings/index.js.map +1 -0
  245. package/dist/resolvers/meetings/meetingHelpers.d.ts +17 -0
  246. package/dist/resolvers/meetings/meetingHelpers.d.ts.map +1 -0
  247. package/dist/resolvers/meetings/meetingHelpers.js +212 -0
  248. package/dist/resolvers/meetings/meetingHelpers.js.map +1 -0
  249. package/dist/resolvers/meetings/meetingMutations.d.ts +18 -0
  250. package/dist/resolvers/meetings/meetingMutations.d.ts.map +1 -0
  251. package/dist/resolvers/meetings/meetingMutations.js +439 -0
  252. package/dist/resolvers/meetings/meetingMutations.js.map +1 -0
  253. package/dist/resolvers/meetings/meetingQueries.d.ts +7 -0
  254. package/dist/resolvers/meetings/meetingQueries.d.ts.map +1 -0
  255. package/dist/resolvers/meetings/meetingQueries.js +113 -0
  256. package/dist/resolvers/meetings/meetingQueries.js.map +1 -0
  257. package/dist/resolvers/meetings/meetingTypes.d.ts +89 -0
  258. package/dist/resolvers/meetings/meetingTypes.d.ts.map +1 -0
  259. package/dist/resolvers/meetings/meetingTypes.js +345 -0
  260. package/dist/resolvers/meetings/meetingTypes.js.map +1 -0
  261. package/dist/rest/ViewOperationsHandler.d.ts.map +1 -1
  262. package/dist/rest/ViewOperationsHandler.js +8 -5
  263. package/dist/rest/ViewOperationsHandler.js.map +1 -1
  264. package/dist/services/TaskGraphActionRunner.d.ts +8 -0
  265. package/dist/services/TaskGraphActionRunner.d.ts.map +1 -1
  266. package/dist/services/TaskGraphActionRunner.js +27 -1
  267. package/dist/services/TaskGraphActionRunner.js.map +1 -1
  268. package/dist/services/TaskGraphContinuationDeliverer.d.ts +4 -3
  269. package/dist/services/TaskGraphContinuationDeliverer.d.ts.map +1 -1
  270. package/dist/services/TaskGraphContinuationDeliverer.js +13 -7
  271. package/dist/services/TaskGraphContinuationDeliverer.js.map +1 -1
  272. package/dist/services/WorkQueueHostService.d.ts +36 -0
  273. package/dist/services/WorkQueueHostService.d.ts.map +1 -0
  274. package/dist/services/WorkQueueHostService.js +97 -0
  275. package/dist/services/WorkQueueHostService.js.map +1 -0
  276. package/dist/services/workQueueConfig.d.ts +103 -0
  277. package/dist/services/workQueueConfig.d.ts.map +1 -0
  278. package/dist/services/workQueueConfig.js +48 -0
  279. package/dist/services/workQueueConfig.js.map +1 -0
  280. package/dist/sharedCache.d.ts +105 -0
  281. package/dist/sharedCache.d.ts.map +1 -0
  282. package/dist/sharedCache.js +276 -0
  283. package/dist/sharedCache.js.map +1 -0
  284. package/dist/types.d.ts +11 -0
  285. package/dist/types.d.ts.map +1 -1
  286. package/dist/types.js.map +1 -1
  287. package/package.json +97 -94
  288. package/src/__tests__/ActionResolver.authorization.test.ts +353 -0
  289. package/src/__tests__/AdhocQueryResolver.bugs.test.ts +14 -35
  290. package/src/__tests__/AdhocQueryResolver.pagination.test.ts +6 -2
  291. package/src/__tests__/AdhocQueryResolver.scopeGuard.test.ts +3 -3
  292. package/src/__tests__/AdhocQueryResolver.sqlAuthorizer.test.ts +104 -0
  293. package/src/__tests__/BridgeHostInstance.test.ts +232 -0
  294. package/src/__tests__/ClientToolRequestResolver.test.ts +116 -0
  295. package/src/__tests__/EntityRecordNameResolver.fieldSecurity.test.ts +27 -72
  296. package/src/__tests__/FetchEntityVectorsResolver.test.ts +285 -0
  297. package/src/__tests__/HostInstance.test.ts +84 -0
  298. package/src/__tests__/HumanHandoffResolver.test.ts +250 -0
  299. package/src/__tests__/MeetingResolver.test.ts +448 -0
  300. package/src/__tests__/RealtimeBridgeResolver.test.ts +651 -4
  301. package/src/__tests__/RealtimeClientSessionResolver.configTamper.test.ts +383 -0
  302. package/src/__tests__/RealtimeClientSessionResolver.test.ts +682 -58
  303. package/src/__tests__/RealtimeProxyServer.test.ts +16 -1
  304. package/src/__tests__/RealtimeRelay.test.ts +876 -0
  305. package/src/__tests__/RemoteBrowserActionResolver.goalRunLink.test.ts +129 -0
  306. package/src/__tests__/ResolverBase.adhocReadScope.test.ts +96 -0
  307. package/src/__tests__/ResolverBase.aggregateScreen.test.ts +174 -0
  308. package/src/__tests__/ResolverBase.clientOldValues.test.ts +6 -3
  309. package/src/__tests__/ResolverBase.filterEscaping.test.ts +21 -2
  310. package/src/__tests__/ResolverBase.includeBinaryFields.test.ts +291 -0
  311. package/src/__tests__/ReturningVisitorRecap.test.ts +115 -0
  312. package/src/__tests__/RunAIAgentResolver.branch.test.ts +169 -0
  313. package/src/__tests__/RunAIAgentResolver.historyFrom.test.ts +4 -4
  314. package/src/__tests__/RunAIAgentResolver.stoppedPredecessor.test.ts +166 -0
  315. package/src/__tests__/RunTemplateResolver.test.ts +132 -0
  316. package/src/__tests__/RunViewResolver.cacheCheckForwarding.test.ts +63 -0
  317. package/src/__tests__/SessionJanitor.test.ts +845 -18
  318. package/src/__tests__/SessionManager.test.ts +213 -17
  319. package/src/__tests__/SessionRunIDVerifier.test.ts +251 -0
  320. package/src/__tests__/SyncRolesUsersResolver.userRoles.test.ts +97 -0
  321. package/src/__tests__/TaskGraphActionRunner.durablePayload.test.ts +41 -0
  322. package/src/__tests__/TaskGraphContinuationDeliverer.test.ts +50 -3
  323. package/src/__tests__/UserAvatarResolver.test.ts +255 -0
  324. package/src/__tests__/UserResolver.currentUser.test.ts +16 -1
  325. package/src/__tests__/WorkQueueHostService.test.ts +133 -0
  326. package/src/__tests__/actionAuthorization.test.ts +130 -0
  327. package/src/__tests__/adhocTimeoutClamp.test.ts +26 -0
  328. package/src/__tests__/agentVisionConsentAudit.test.ts +118 -0
  329. package/src/__tests__/avatarInputValidation.test.ts +160 -0
  330. package/src/__tests__/isolatedProviderTransactions.test.ts +169 -0
  331. package/src/__tests__/magicLinkService.consume.test.ts +6 -0
  332. package/src/__tests__/magicLinkService.provisionLog.test.ts +5 -0
  333. package/src/__tests__/newUsers.template.test.ts +151 -0
  334. package/src/__tests__/newUsers.test.ts +74 -5
  335. package/src/__tests__/orphanedConversationDetailReconciler.test.ts +17 -2
  336. package/src/__tests__/postgresqlPoolSettings.test.ts +131 -0
  337. package/src/__tests__/realtimeSessions/RealtimeSessionEventService.test.ts +201 -0
  338. package/src/__tests__/realtimeSessions/RealtimeSessionEventsResolver.test.ts +215 -0
  339. package/src/__tests__/realtimeSessions/RealtimeSessionVerificationResolver.test.ts +102 -0
  340. package/src/__tests__/realtimeSessions/RealtimeSessionVerificationService.test.ts +349 -0
  341. package/src/__tests__/realtimeSessions/RealtimeVerifyRouter.test.ts +131 -0
  342. package/src/__tests__/realtimeSessions/SlidingWindowRateLimiter.test.ts +56 -0
  343. package/src/__tests__/realtimeSessions/helpers.ts +4 -0
  344. package/src/__tests__/realtimeSessions/sessionAccess.test.ts +129 -0
  345. package/src/__tests__/realtimeSessions/sessionConfigStamps.test.ts +124 -0
  346. package/src/__tests__/realtimeSessions/verificationCore.test.ts +355 -0
  347. package/src/__tests__/realtimeSessions/verificationPages.test.ts +84 -0
  348. package/src/__tests__/realtimeSessions/verificationPolicy.test.ts +226 -0
  349. package/src/__tests__/realtimeSessions/verificationWorkflow.test.ts +633 -0
  350. package/src/__tests__/resolverBase.fls.test.ts +87 -4
  351. package/src/__tests__/serverExtensionReservedRoots.test.ts +2 -0
  352. package/src/__tests__/sharedCache.test.ts +310 -0
  353. package/src/__tests__/translateBracketsToPG.test.ts +20 -0
  354. package/src/__tests__/widgetGuestElevation.test.ts +44 -0
  355. package/src/agentSessions/BridgeHostInstance.ts +32 -0
  356. package/src/agentSessions/HostInstance.ts +124 -28
  357. package/src/agentSessions/ReturningVisitorRecap.ts +7 -3
  358. package/src/agentSessions/SessionJanitor.ts +543 -57
  359. package/src/agentSessions/SessionManager.ts +125 -25
  360. package/src/agentSessions/SessionRunIDVerifier.ts +171 -0
  361. package/src/agentSessions/index.ts +10 -3
  362. package/src/auth/actionAuthorization.ts +116 -0
  363. package/src/auth/index.ts +3 -8
  364. package/src/auth/magicLink/MagicLinkService.ts +6 -3
  365. package/src/auth/newUsers.ts +99 -11
  366. package/src/config.ts +255 -3
  367. package/src/context.ts +26 -34
  368. package/src/generated/graphql-schemas/__mj.ts +22701 -18838
  369. package/src/generic/OrphanedConversationDetailReconciler.ts +3 -3
  370. package/src/generic/ResolverBase.ts +210 -36
  371. package/src/generic/RunViewResolver.ts +37 -2
  372. package/src/index.ts +236 -170
  373. package/src/isolatedProvider.ts +22 -0
  374. package/src/postgresqlCompat.ts +21 -0
  375. package/src/postgresqlPoolSettings.ts +213 -0
  376. package/src/realtimeProxy/RealtimeProxyServer.ts +148 -16
  377. package/src/realtimeProxy/RealtimeRelayTunnel.ts +645 -0
  378. package/src/realtimeSessions/README.md +179 -0
  379. package/src/realtimeSessions/RealtimeSessionEventService.ts +274 -0
  380. package/src/realtimeSessions/RealtimeSessionVerificationService.ts +167 -0
  381. package/src/realtimeSessions/RealtimeVerifyRouter.ts +108 -0
  382. package/src/realtimeSessions/SessionVerificationPortsBase.ts +189 -0
  383. package/src/realtimeSessions/SlidingWindowRateLimiter.ts +92 -0
  384. package/src/realtimeSessions/index.ts +16 -0
  385. package/src/realtimeSessions/sessionAccess.ts +141 -0
  386. package/src/realtimeSessions/sessionConfigStamps.ts +123 -0
  387. package/src/realtimeSessions/subscriptionAuthorization.ts +116 -0
  388. package/src/realtimeSessions/verificationCore.ts +502 -0
  389. package/src/realtimeSessions/verificationPages.ts +149 -0
  390. package/src/realtimeSessions/verificationPolicy.ts +321 -0
  391. package/src/realtimeSessions/verificationWorkflow.ts +702 -0
  392. package/src/realtimeWidget/widgetGuestElevation.ts +34 -2
  393. package/src/resolvers/ActionResolver.ts +84 -21
  394. package/src/resolvers/AdhocQueryResolver.ts +105 -187
  395. package/src/resolvers/CacheStatsResolver.ts +89 -2
  396. package/src/resolvers/ClientToolRequestResolver.ts +25 -7
  397. package/src/resolvers/EntityRecordNameResolver.ts +9 -51
  398. package/src/resolvers/FetchEntityVectorsResolver.ts +97 -2
  399. package/src/resolvers/GetDataResolver.ts +10 -0
  400. package/src/resolvers/HumanHandoffResolver.ts +312 -0
  401. package/src/resolvers/MCPResolver.ts +8 -5
  402. package/src/resolvers/MeetingResolver.ts +438 -0
  403. package/src/resolvers/RealtimeBridgeResolver.ts +385 -19
  404. package/src/resolvers/RealtimeClientSessionResolver.ts +503 -344
  405. package/src/resolvers/RealtimeSessionEventsResolver.ts +133 -0
  406. package/src/resolvers/RealtimeSessionVerificationResolver.ts +174 -0
  407. package/src/resolvers/RemoteBrowserActionResolver.ts +11 -1
  408. package/src/resolvers/RunAIAgentResolver.ts +78 -11
  409. package/src/resolvers/RunTemplateResolver.ts +13 -12
  410. package/src/resolvers/SyncDataResolver.ts +6 -2
  411. package/src/resolvers/SyncRolesUsersResolver.ts +24 -6
  412. package/src/resolvers/UserAvatarResolver.ts +111 -0
  413. package/src/resolvers/UserResolver.ts +2 -16
  414. package/src/resolvers/adhocTimeout.ts +12 -0
  415. package/src/resolvers/agentVisionConsentAudit.ts +82 -0
  416. package/src/resolvers/avatarInputValidation.ts +123 -0
  417. package/src/resolvers/currentUserRoles.ts +32 -1
  418. package/src/resolvers/meetings/index.ts +4 -0
  419. package/src/resolvers/meetings/meetingHelpers.ts +307 -0
  420. package/src/resolvers/meetings/meetingMutations.ts +556 -0
  421. package/src/resolvers/meetings/meetingQueries.ts +172 -0
  422. package/src/resolvers/meetings/meetingTypes.ts +238 -0
  423. package/src/rest/ViewOperationsHandler.ts +8 -5
  424. package/src/services/TaskGraphActionRunner.ts +29 -1
  425. package/src/services/TaskGraphContinuationDeliverer.ts +13 -7
  426. package/src/services/WorkQueueHostService.ts +129 -0
  427. package/src/services/workQueueConfig.ts +52 -0
  428. package/src/sharedCache.ts +302 -0
  429. package/src/types.ts +12 -0
  430. package/dist/resolvers/adhoc-query-helpers.d.ts +0 -33
  431. package/dist/resolvers/adhoc-query-helpers.d.ts.map +0 -1
  432. package/dist/resolvers/adhoc-query-helpers.js +0 -50
  433. package/dist/resolvers/adhoc-query-helpers.js.map +0 -1
  434. package/src/__tests__/adhoc-query-helpers.test.ts +0 -50
  435. package/src/resolvers/adhoc-query-helpers.ts +0 -67
@@ -0,0 +1,291 @@
1
+ // ResolverBase / RunViewResolver transitively pull in type-graphql decorators, which need the
2
+ // Reflect.metadata polyfill at import time.
3
+ import 'reflect-metadata';
4
+ import { describe, it, expect } from 'vitest';
5
+ import type {
6
+ DatabaseProviderBase,
7
+ EntityInfo,
8
+ IMetadataProvider,
9
+ RunViewParams,
10
+ RunViewResult,
11
+ RunViewWithCacheCheckParams,
12
+ RunViewsWithCacheCheckResponse,
13
+ UserInfo,
14
+ } from '@memberjunction/core';
15
+ import type { MJUserViewEntityExtended } from '@memberjunction/core-entities';
16
+ import { ResolverBase } from '../generic/ResolverBase.js';
17
+ import {
18
+ RunViewResolver,
19
+ type RunDynamicViewInput,
20
+ type RunViewByIDInput,
21
+ type RunViewByNameInput,
22
+ type RunViewResultRow,
23
+ type RunViewWithCacheCheckInput,
24
+ } from '../generic/RunViewResolver.js';
25
+ import type { AppContext, UserPayload } from '../types.js';
26
+
27
+ /**
28
+ * Binary DB fields (varbinary / bytea) are base64 strings in JS and on the wire, and RunView
29
+ * omits them unless `IncludeBinaryFields: true`. These tests pin the server half:
30
+ *
31
+ * 1. the GraphQL flag reaches the provider's RunView / RunViews / RunViewsWithCacheCheck params
32
+ * on every resolver path (single by-ID / by-name / dynamic, batch, and the cache-check batch);
33
+ * 2. any byte array that still reaches a resolver is serialized as base64 — never as the
34
+ * `{"type":"Buffer","data":[...]}` that `JSON.stringify` produces for a Node Buffer.
35
+ */
36
+
37
+ const ENTITY_NAME = 'MJ: Vector Things';
38
+ const ENTITY_ID = 'ent-1';
39
+
40
+ /** Bytes whose base64 form is easy to recognise: [1,2,3,4] → "AQIDBA==". */
41
+ const BYTES = [1, 2, 3, 4];
42
+ const BYTES_BASE64 = 'AQIDBA==';
43
+
44
+ const fakePayload = () =>
45
+ ({ email: 'tester@example.com', userRecord: { Email: 'tester@example.com' } as UserInfo } as UserPayload);
46
+
47
+ function entityStub() {
48
+ return {
49
+ ID: ENTITY_ID,
50
+ Name: ENTITY_NAME,
51
+ BaseView: 'vwVectorThings',
52
+ PrimaryKeys: [{ Name: 'ID' }],
53
+ Fields: [
54
+ { Name: 'ID', CodeName: 'ID' },
55
+ { Name: 'Embedding', CodeName: 'Embedding' },
56
+ ],
57
+ EncryptedFields: [],
58
+ };
59
+ }
60
+
61
+ /** Provider that records every RunView / RunViews call and returns the given rows. */
62
+ function recordingProvider(rows: Record<string, unknown>[] = []) {
63
+ const runViewCalls: RunViewParams[] = [];
64
+ const runViewsCalls: RunViewParams[][] = [];
65
+ const viewInfo = { ID: 'view-1', Name: 'Saved View', Entity: ENTITY_NAME, EntityID: ENTITY_ID };
66
+ const provider = {
67
+ Entities: [entityStub()],
68
+ EntityByName: (name: string) => (name === ENTITY_NAME ? entityStub() : undefined),
69
+ RunView: async (params: RunViewParams): Promise<RunViewResult> => {
70
+ // RunViewByNameGeneric looks the saved view up first — answer that lookup with the view row.
71
+ if (params.EntityName === 'MJ: User Views') {
72
+ return { Success: true, Results: [viewInfo], RowCount: 1, TotalRowCount: 1, ErrorMessage: '' } as RunViewResult;
73
+ }
74
+ runViewCalls.push(params);
75
+ return { Success: true, Results: rows, RowCount: rows.length, TotalRowCount: rows.length, ErrorMessage: '' } as RunViewResult;
76
+ },
77
+ RunViews: async (params: RunViewParams[]): Promise<RunViewResult[]> => {
78
+ runViewsCalls.push(params);
79
+ return params.map(() => ({ Success: true, Results: rows, RowCount: rows.length, TotalRowCount: rows.length, ErrorMessage: '' } as RunViewResult));
80
+ },
81
+ GetEntityObject: async () => ({ ...viewInfo, Load: async () => true }),
82
+ } as unknown as DatabaseProviderBase;
83
+ return { provider, runViewCalls, runViewsCalls };
84
+ }
85
+
86
+ /** Skips the encrypted-field filter (it needs live Metadata) — irrelevant to these assertions. */
87
+ class Probe extends ResolverBase {
88
+ protected override async ArrayFilterEncryptedFieldsForAPI(
89
+ _entityName: string,
90
+ dataObjectArray: Record<string, unknown>[]
91
+ ): Promise<Record<string, unknown>[]> {
92
+ return dataObjectArray;
93
+ }
94
+
95
+ public MapOne(entityName: string, row: unknown, provider: IMetadataProvider) {
96
+ return this.MapFieldNamesToCodeNames(entityName, row, undefined, provider);
97
+ }
98
+ }
99
+
100
+ describe('IncludeBinaryFields forwarding — single-view resolver paths', () => {
101
+ it('RunDynamicViewGeneric forwards IncludeBinaryFields: true to provider.RunView', async () => {
102
+ const { provider, runViewCalls } = recordingProvider();
103
+ await new Probe().RunDynamicViewGeneric(
104
+ { EntityName: ENTITY_NAME, ExtraFilter: '', OrderBy: '', IncludeBinaryFields: true } as RunDynamicViewInput,
105
+ provider, fakePayload(), undefined as never,
106
+ );
107
+
108
+ expect(runViewCalls).toHaveLength(1);
109
+ expect(runViewCalls[0].IncludeBinaryFields).toBe(true);
110
+ });
111
+
112
+ it('RunDynamicViewGeneric leaves IncludeBinaryFields undefined when the caller did not set it', async () => {
113
+ const { provider, runViewCalls } = recordingProvider();
114
+ await new Probe().RunDynamicViewGeneric(
115
+ { EntityName: ENTITY_NAME, ExtraFilter: '', OrderBy: '' } as RunDynamicViewInput,
116
+ provider, fakePayload(), undefined as never,
117
+ );
118
+
119
+ expect(runViewCalls).toHaveLength(1);
120
+ expect(runViewCalls[0].IncludeBinaryFields).toBeUndefined();
121
+ });
122
+
123
+ it('RunViewByNameGeneric forwards IncludeBinaryFields to provider.RunView', async () => {
124
+ const { provider, runViewCalls } = recordingProvider();
125
+ await new Probe().RunViewByNameGeneric(
126
+ { ViewName: 'Saved View', ExtraFilter: '', OrderBy: '', IncludeBinaryFields: true } as RunViewByNameInput,
127
+ provider, fakePayload(), undefined as never,
128
+ );
129
+
130
+ expect(runViewCalls).toHaveLength(1);
131
+ expect(runViewCalls[0].EntityName).toBe(ENTITY_NAME);
132
+ expect(runViewCalls[0].IncludeBinaryFields).toBe(true);
133
+ });
134
+
135
+ it('RunViewByIDGeneric forwards IncludeBinaryFields to provider.RunView', async () => {
136
+ const { provider, runViewCalls } = recordingProvider();
137
+ await new Probe().RunViewByIDGeneric(
138
+ { ViewID: 'view-1', ExtraFilter: '', OrderBy: '', IncludeBinaryFields: false } as RunViewByIDInput,
139
+ provider, fakePayload(), undefined as never,
140
+ );
141
+
142
+ expect(runViewCalls).toHaveLength(1);
143
+ expect(runViewCalls[0].IncludeBinaryFields).toBe(false);
144
+ });
145
+
146
+ it('RunViewGenericInternal passes binary values through as the provider returned them (base64 strings)', async () => {
147
+ const { provider } = recordingProvider([{ ID: 'r1', Embedding: BYTES_BASE64 }]);
148
+ const result = await new Probe().RunDynamicViewGeneric(
149
+ { EntityName: ENTITY_NAME, ExtraFilter: '', OrderBy: '', IncludeBinaryFields: true } as RunDynamicViewInput,
150
+ provider, fakePayload(), undefined as never,
151
+ );
152
+
153
+ expect((result?.Results as Record<string, unknown>[])[0].Embedding).toBe(BYTES_BASE64);
154
+ });
155
+ });
156
+
157
+ describe('IncludeBinaryFields forwarding — batch resolver path', () => {
158
+ it('RunViewsGeneric → RunViewsGenericInternal forwards the per-view flag to provider.RunViews', async () => {
159
+ const { provider, runViewsCalls } = recordingProvider();
160
+ const inputs = [
161
+ { EntityName: ENTITY_NAME, ExtraFilter: '', OrderBy: '', IncludeBinaryFields: true },
162
+ { EntityName: ENTITY_NAME, ExtraFilter: '', OrderBy: '' },
163
+ ] as (RunViewByNameInput & RunViewByIDInput & RunDynamicViewInput)[];
164
+
165
+ await new Probe().RunViewsGeneric(inputs, provider, fakePayload());
166
+
167
+ expect(runViewsCalls).toHaveLength(1);
168
+ expect(runViewsCalls[0]).toHaveLength(2);
169
+ expect(runViewsCalls[0][0].IncludeBinaryFields).toBe(true);
170
+ expect(runViewsCalls[0][1].IncludeBinaryFields).toBeUndefined();
171
+ });
172
+ });
173
+
174
+ describe('MapFieldNamesToCodeNames — byte arrays become base64', () => {
175
+ const provider = {
176
+ EntityByName: (name: string) => (name === ENTITY_NAME ? (entityStub() as unknown as EntityInfo) : undefined),
177
+ } as unknown as IMetadataProvider;
178
+
179
+ it('converts a Buffer value to its base64 string', async () => {
180
+ const mapped = (await new Probe().MapOne(ENTITY_NAME, { ID: 'r1', Embedding: Buffer.from(BYTES) }, provider)) as Record<string, unknown>;
181
+
182
+ expect(mapped.Embedding).toBe(BYTES_BASE64);
183
+ expect(mapped.ID).toBe('r1');
184
+ });
185
+
186
+ it('converts a plain Uint8Array value too', async () => {
187
+ const mapped = (await new Probe().MapOne(ENTITY_NAME, { ID: 'r1', Embedding: new Uint8Array(BYTES) }, provider)) as Record<string, unknown>;
188
+
189
+ expect(mapped.Embedding).toBe(BYTES_BASE64);
190
+ });
191
+
192
+ it('leaves an already-base64 string untouched', async () => {
193
+ const mapped = (await new Probe().MapOne(ENTITY_NAME, { ID: 'r1', Embedding: BYTES_BASE64 }, provider)) as Record<string, unknown>;
194
+
195
+ expect(mapped.Embedding).toBe(BYTES_BASE64);
196
+ });
197
+
198
+ it('does not mutate the caller\'s row (it may be a frozen cache entry)', async () => {
199
+ const buffer = Buffer.from(BYTES);
200
+ const source = Object.freeze({ ID: 'r1', Embedding: buffer }) as Record<string, unknown>;
201
+
202
+ const mapped = (await new Probe().MapOne(ENTITY_NAME, source, provider)) as Record<string, unknown>;
203
+
204
+ expect(mapped.Embedding).toBe(BYTES_BASE64);
205
+ expect(source.Embedding).toBe(buffer);
206
+ });
207
+ });
208
+
209
+ /** Exposes the protected serializer. */
210
+ class ResolverProbe extends RunViewResolver {
211
+ public Process(rows: Record<string, unknown>[]): RunViewResultRow[] {
212
+ return this.processRawData(rows, ENTITY_ID, entityStub() as unknown as EntityInfo);
213
+ }
214
+ }
215
+
216
+ describe('RunViewResolver.processRawData — Buffer → base64 in the Data JSON', () => {
217
+ it('serializes a Buffer value as base64, not {type:"Buffer",data:[...]}', () => {
218
+ const [row] = new ResolverProbe().Process([{ ID: 'r1', Embedding: Buffer.from(BYTES) }]);
219
+ const data = JSON.parse(row.Data) as Record<string, unknown>;
220
+
221
+ expect(data.Embedding).toBe(BYTES_BASE64);
222
+ expect(row.Data).not.toContain('"type":"Buffer"');
223
+ expect(row.PrimaryKey).toEqual([{ FieldName: 'ID', Value: 'r1' }]);
224
+ expect(row.EntityID).toBe(ENTITY_ID);
225
+ });
226
+
227
+ it('serializes a Uint8Array value as base64 (not an index-keyed object)', () => {
228
+ const [row] = new ResolverProbe().Process([{ ID: 'r1', Embedding: new Uint8Array(BYTES) }]);
229
+
230
+ expect((JSON.parse(row.Data) as Record<string, unknown>).Embedding).toBe(BYTES_BASE64);
231
+ });
232
+
233
+ it('leaves rows without byte arrays serialized exactly as before', () => {
234
+ const source = { ID: 'r1', Name: 'Plain', Embedding: BYTES_BASE64, Count: 3 };
235
+ const [row] = new ResolverProbe().Process([source]);
236
+
237
+ expect(row.Data).toBe(JSON.stringify(source));
238
+ });
239
+
240
+ it('does not mutate the source row', () => {
241
+ const buffer = Buffer.from(BYTES);
242
+ const source: Record<string, unknown> = { ID: 'r1', Embedding: buffer };
243
+
244
+ new ResolverProbe().Process([source]);
245
+
246
+ expect(source.Embedding).toBe(buffer);
247
+ });
248
+ });
249
+
250
+ describe('RunViewResolver.RunViewsWithCacheCheck — IncludeBinaryFields + Buffer serialization', () => {
251
+ function cacheCheckContext(rows: Record<string, unknown>[]) {
252
+ const received: RunViewWithCacheCheckParams[][] = [];
253
+ const provider = {
254
+ EntityByName: (name: string) => (name === ENTITY_NAME ? entityStub() : undefined),
255
+ RunViewsWithCacheCheck: async (params: RunViewWithCacheCheckParams[]): Promise<RunViewsWithCacheCheckResponse> => {
256
+ received.push(params);
257
+ return {
258
+ success: true,
259
+ results: params.map((_p, i) => ({ viewIndex: i, status: 'stale', results: rows, maxUpdatedAt: 'T', rowCount: rows.length })),
260
+ } as RunViewsWithCacheCheckResponse;
261
+ },
262
+ };
263
+ const ctx = { providers: [{ type: 'Read-Only', provider }], userPayload: fakePayload() } as unknown as AppContext;
264
+ return { ctx, received };
265
+ }
266
+
267
+ it('forwards IncludeBinaryFields into the core params (true, false and unset)', async () => {
268
+ const { ctx, received } = cacheCheckContext([]);
269
+ const input = [
270
+ { params: { EntityName: ENTITY_NAME, IncludeBinaryFields: true } },
271
+ { params: { EntityName: ENTITY_NAME, IncludeBinaryFields: false } },
272
+ { params: { EntityName: ENTITY_NAME } },
273
+ ] as RunViewWithCacheCheckInput[];
274
+
275
+ const out = await new RunViewResolver().RunViewsWithCacheCheck(input, ctx);
276
+
277
+ expect(out.success).toBe(true);
278
+ expect(received).toHaveLength(1);
279
+ expect(received[0].map(p => p.params.IncludeBinaryFields)).toEqual([true, false, undefined]);
280
+ });
281
+
282
+ it('serializes Buffers in stale results as base64', async () => {
283
+ const { ctx } = cacheCheckContext([{ ID: 'r1', Embedding: Buffer.from(BYTES) }]);
284
+ const input = [{ params: { EntityName: ENTITY_NAME, IncludeBinaryFields: true } }] as RunViewWithCacheCheckInput[];
285
+
286
+ const out = await new RunViewResolver().RunViewsWithCacheCheck(input, ctx);
287
+ const rows = out.results[0].Results as RunViewResultRow[];
288
+
289
+ expect((JSON.parse(rows[0].Data) as Record<string, unknown>).Embedding).toBe(BYTES_BASE64);
290
+ });
291
+ });
@@ -0,0 +1,115 @@
1
+ /**
2
+ * @fileoverview The returning-visitor recap transcript reads Main.
3
+ *
4
+ * The transcript query filters with `ConversationEngine.ScopeFilter(ConversationEngine.TrunkScope(id))`
5
+ * and takes the newest turns by `Sequence`. It reads no branch or conversation scope first.
6
+ */
7
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
8
+ import type { IMetadataProvider, UserInfo } from '@memberjunction/core';
9
+
10
+ interface ViewCall {
11
+ EntityName: string;
12
+ ExtraFilter?: string;
13
+ OrderBy?: string;
14
+ MaxRows?: number;
15
+ }
16
+
17
+ const hoisted = vi.hoisted(() => ({
18
+ views: [] as ViewCall[],
19
+ detailRows: [] as Array<{ Role: string; Message: string }>,
20
+ transcripts: [] as string[],
21
+ logError: vi.fn(),
22
+ logStatus: vi.fn(),
23
+ aiConfig: vi.fn(),
24
+ }));
25
+
26
+ vi.mock('@memberjunction/core', async (importOriginal) => {
27
+ const actual = await importOriginal<typeof import('@memberjunction/core')>();
28
+ return {
29
+ ...actual,
30
+ LogError: hoisted.logError,
31
+ LogStatus: hoisted.logStatus,
32
+ RunView: class {
33
+ async RunView(params: ViewCall) {
34
+ hoisted.views.push(params);
35
+ if (params.EntityName === 'MJ: Conversation Details') {
36
+ return { Success: true, Results: hoisted.detailRows };
37
+ }
38
+ return { Success: true, Results: [] };
39
+ }
40
+ },
41
+ };
42
+ });
43
+
44
+ vi.mock('@memberjunction/aiengine', () => ({
45
+ AIEngine: {
46
+ Instance: {
47
+ Config: hoisted.aiConfig,
48
+ Prompts: [{ Name: 'Returning-Visitor Recap', SelectionStrategy: 'Default', Status: 'Active' }],
49
+ },
50
+ },
51
+ }));
52
+
53
+ vi.mock('@memberjunction/ai-core-plus', () => ({
54
+ AIPromptParams: class {},
55
+ }));
56
+
57
+ vi.mock('@memberjunction/ai-prompts', () => ({
58
+ AIPromptRunner: class {
59
+ async ExecutePrompt(params: { data?: { transcript?: string } }) {
60
+ hoisted.transcripts.push(params.data?.transcript ?? '');
61
+ return { success: true, rawResult: 'NO_RECAP' };
62
+ }
63
+ },
64
+ }));
65
+
66
+ import { ConversationEngine } from '@memberjunction/core-entities';
67
+ import { WriteReturningVisitorRecap } from '../agentSessions/ReturningVisitorRecap.js';
68
+
69
+ const USER = { ID: 'user-1' } as unknown as UserInfo;
70
+
71
+ function makeProvider(): IMetadataProvider {
72
+ const conversation = {
73
+ ID: 'conv-1',
74
+ LinkedEntityID: 'entity-1',
75
+ LinkedRecordID: 'record-1',
76
+ VisitorKey: null,
77
+ Load: vi.fn().mockResolvedValue(true),
78
+ };
79
+ return {
80
+ Entities: [],
81
+ GetEntityObject: vi.fn().mockResolvedValue(conversation),
82
+ } as unknown as IMetadataProvider;
83
+ }
84
+
85
+ function detailView(): ViewCall | undefined {
86
+ return hoisted.views.find((v) => v.EntityName === 'MJ: Conversation Details');
87
+ }
88
+
89
+ describe('WriteReturningVisitorRecap — transcript scope', () => {
90
+ beforeEach(() => {
91
+ hoisted.views.length = 0;
92
+ hoisted.transcripts.length = 0;
93
+ hoisted.detailRows = [
94
+ { Role: 'AI', Message: 'second' },
95
+ { Role: 'User', Message: 'first' },
96
+ ];
97
+ hoisted.logError.mockReset();
98
+ hoisted.logStatus.mockReset();
99
+ hoisted.aiConfig.mockReset();
100
+ });
101
+
102
+ it('reads the newest turns in Main with the trunk predicate, in chronological order', async () => {
103
+ const provider = makeProvider();
104
+
105
+ await WriteReturningVisitorRecap('conv-1', 'agent-1', USER, provider);
106
+
107
+ const view = detailView();
108
+ expect(view?.ExtraFilter).toBe(ConversationEngine.LiveRowsFilter(ConversationEngine.ScopeFilter(ConversationEngine.TrunkScope('conv-1'))));
109
+ expect(view?.ExtraFilter).toBe("[ConversationID]='conv-1' AND [BranchID] IS NULL AND [ReplacedAt] IS NULL");
110
+ expect(view?.OrderBy).toBe('Sequence DESC');
111
+ expect(view?.MaxRows).toBe(60);
112
+ expect(hoisted.views.some((v) => v.EntityName === 'MJ: Conversation Branches' || v.EntityName === 'MJ: Conversations')).toBe(false);
113
+ expect(hoisted.transcripts).toEqual(['User: first\nAI: second']);
114
+ });
115
+ });
@@ -0,0 +1,169 @@
1
+ /**
2
+ * @fileoverview The conversation branch on `RunAIAgentFromConversationDetail`.
3
+ *
4
+ * The branch comes from the placeholder row the mutation is given, never from a request argument.
5
+ * These tests pin that the mutation loads history along that branch's path, hands the branch to the
6
+ * agent run on both the synchronous and fire-and-forget paths, and reads the trunk when the row has
7
+ * no branch; and that `executeAIAgent` puts the branch on the run's params only when there is one.
8
+ */
9
+ import 'reflect-metadata'; // must precede any type-graphql decorator evaluation
10
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
11
+ import type { PubSubEngine } from 'type-graphql';
12
+
13
+ // type-graphql's real decorators need emitDecoratorMetadata, which vitest's esbuild transform
14
+ // does not emit; the schema is irrelevant here, so every decorator is a no-op.
15
+ vi.mock('type-graphql', () => {
16
+ const decoratorFactory = (..._args: unknown[]) => (..._decorated: unknown[]) => undefined;
17
+ const exportNames = [
18
+ 'Resolver', 'Query', 'Mutation', 'Subscription', 'Arg', 'Args', 'ArgsType', 'Ctx', 'Root',
19
+ 'Info', 'Field', 'FieldResolver', 'ObjectType', 'InputType', 'InterfaceType', 'Authorized',
20
+ 'UseMiddleware', 'Extensions', 'Directive', 'ID', 'Int', 'Float', 'GraphQLISODateTime',
21
+ 'GraphQLTimestamp', 'registerEnumType', 'createMethodDecorator', 'createParamDecorator',
22
+ 'buildSchema', 'buildSchemaSync', 'PubSub',
23
+ ];
24
+ return Object.fromEntries(exportNames.map((name) => [name, decoratorFactory]));
25
+ });
26
+
27
+ const hoisted = vi.hoisted(() => ({
28
+ runAgentInConversation: vi.fn(),
29
+ }));
30
+
31
+ vi.mock('@memberjunction/ai-agents', () => ({
32
+ AgentRunner: class {
33
+ RunAgentInConversation(...args: unknown[]) {
34
+ return hoisted.runAgentInConversation(...args);
35
+ }
36
+ },
37
+ ArtifactToolManager: class {},
38
+ }));
39
+
40
+ vi.mock('../realtimeWidget/widgetGuestElevation.js', () => ({
41
+ ResolveWidgetGuestRunContext: vi.fn().mockResolvedValue(null),
42
+ ElevateUserPayload: vi.fn(),
43
+ }));
44
+
45
+ import { ConversationEngine } from '@memberjunction/core-entities';
46
+ import { RunAIAgentResolver } from '../resolvers/RunAIAgentResolver.js';
47
+ import type { AppContext, UserPayload } from '../types.js';
48
+
49
+ const USER = { ID: 'user-1', Email: 'user@example.com' };
50
+
51
+ type Fn = ReturnType<typeof vi.fn>;
52
+
53
+ /** The private members this test reaches, through an explicit shape (no `any`). */
54
+ interface ResolverSeams {
55
+ CheckAPIKeyScopeAuthorization: Fn;
56
+ GetUserFromPayload: Fn;
57
+ loadConversationHistoryWithAttachments: Fn;
58
+ executeAIAgent: Fn;
59
+ executeAgentInBackground: Fn;
60
+ loadInputArtifactsBatch: Fn;
61
+ validateAgent: Fn;
62
+ persistInFlightAgentFailure: Fn;
63
+ }
64
+
65
+ function makeResolver(): { resolver: RunAIAgentResolver; seams: ResolverSeams } {
66
+ const resolver = new RunAIAgentResolver();
67
+ const seams = resolver as unknown as ResolverSeams;
68
+ seams.CheckAPIKeyScopeAuthorization = vi.fn().mockResolvedValue(undefined);
69
+ seams.GetUserFromPayload = vi.fn().mockReturnValue(USER);
70
+ return { resolver, seams };
71
+ }
72
+
73
+ function makeContext(branchId: string | null): AppContext {
74
+ const provider = {
75
+ GetEntityObject: vi.fn().mockResolvedValue({
76
+ ConversationID: 'conv-1',
77
+ BranchID: branchId,
78
+ Load: vi.fn().mockResolvedValue(true),
79
+ }),
80
+ };
81
+ return {
82
+ userPayload: { sessionId: 'session-1', userRecord: USER } as unknown as UserPayload,
83
+ providers: [{ type: 'Read-Write', provider }],
84
+ dataSource: {},
85
+ } as unknown as AppContext;
86
+ }
87
+
88
+ const pubSub = { publish: vi.fn() } as unknown as PubSubEngine;
89
+
90
+ async function runMutation(resolver: RunAIAgentResolver, branchId: string | null, fireAndForget?: boolean) {
91
+ return resolver.RunAIAgentFromConversationDetail(
92
+ 'detail-1', 'agent-1', makeContext(branchId), 'session-1', pubSub,
93
+ undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined,
94
+ undefined, undefined, fireAndForget, undefined, undefined, undefined
95
+ );
96
+ }
97
+
98
+ afterEach(() => {
99
+ vi.restoreAllMocks();
100
+ });
101
+
102
+ describe('RunAIAgentFromConversationDetail — branch', () => {
103
+ let resolver: RunAIAgentResolver;
104
+ let seams: ResolverSeams;
105
+
106
+ beforeEach(() => {
107
+ ({ resolver, seams } = makeResolver());
108
+ seams.loadConversationHistoryWithAttachments = vi.fn().mockResolvedValue([]);
109
+ seams.executeAIAgent = vi.fn().mockResolvedValue({ success: true, result: '{}' });
110
+ seams.executeAgentInBackground = vi.fn();
111
+ });
112
+
113
+ it('loads history on the placeholder row\'s branch and hands the branch to the run', async () => {
114
+ await runMutation(resolver, 'branch-b');
115
+ expect(seams.loadConversationHistoryWithAttachments.mock.calls[0][6]).toBe('branch-b');
116
+ expect(seams.executeAIAgent.mock.calls[0].at(-1)).toBe('branch-b');
117
+ });
118
+
119
+ it('passes the branch to the background path too', async () => {
120
+ await runMutation(resolver, 'branch-b', true);
121
+ expect(seams.executeAgentInBackground.mock.calls[0].at(-1)).toBe('branch-b');
122
+ });
123
+
124
+ it('reads the trunk when the placeholder has no branch (control)', async () => {
125
+ await runMutation(resolver, null);
126
+ expect(seams.loadConversationHistoryWithAttachments.mock.calls[0][6]).toBeNull();
127
+ expect(seams.executeAIAgent.mock.calls[0].at(-1)).toBeNull();
128
+ });
129
+ });
130
+
131
+ describe('loadConversationHistoryWithAttachments — branch', () => {
132
+ it('passes the branch to the fresh loader', async () => {
133
+ const { resolver, seams } = makeResolver();
134
+ seams.loadInputArtifactsBatch = vi.fn().mockResolvedValue(new Map());
135
+ const loadRows = vi.spyOn(ConversationEngine, 'LoadWindowRowsFresh').mockResolvedValue([]);
136
+ const provider = {};
137
+ const load = (resolver as unknown as {
138
+ loadConversationHistoryWithAttachments(
139
+ conversationId: string, user: unknown, max: number, provider: unknown,
140
+ exclude?: string[], historyFrom?: Date, branchId?: string | null
141
+ ): Promise<unknown[]>;
142
+ }).loadConversationHistoryWithAttachments.bind(resolver);
143
+ await load('conv-1', USER, 20, provider, ['detail-1'], undefined, 'branch-b');
144
+ expect(loadRows).toHaveBeenCalledWith('conv-1', USER, provider, undefined, 'branch-b');
145
+ });
146
+ });
147
+
148
+ describe('executeAIAgent — ConversationBranchID', () => {
149
+ it('puts the branch on the run\'s params, and leaves it unset for the trunk', async () => {
150
+ const { resolver, seams } = makeResolver();
151
+ seams.validateAgent = vi.fn().mockResolvedValue({ ID: 'agent-1', Name: 'Test Agent' });
152
+ seams.persistInFlightAgentFailure = vi.fn().mockResolvedValue(undefined);
153
+ hoisted.runAgentInConversation.mockReset().mockRejectedValue(new Error('stop here'));
154
+ vi.spyOn(console, 'error').mockImplementation(() => undefined);
155
+ vi.spyOn(console, 'log').mockImplementation(() => undefined);
156
+ const execute = (resolver as unknown as { executeAIAgent(...args: unknown[]): Promise<unknown> }).executeAIAgent.bind(resolver);
157
+ const userPayload = { sessionId: 'session-1', userRecord: USER };
158
+ const base = [
159
+ {}, {}, 'agent-1', userPayload, '[{"role":"user","content":"hi"}]', 'session-1', pubSub,
160
+ undefined, undefined, undefined, undefined, undefined, undefined, 'detail-1', false, false,
161
+ undefined, undefined, 'conv-1', undefined, undefined, undefined, undefined, undefined,
162
+ ];
163
+ await execute(...base, 'branch-b');
164
+ await execute(...base, null);
165
+ const [withBranch, trunk] = hoisted.runAgentInConversation.mock.calls.map(c => c[0] as Record<string, unknown>);
166
+ expect(withBranch.ConversationBranchID).toBe('branch-b');
167
+ expect(trunk).not.toHaveProperty('ConversationBranchID');
168
+ });
169
+ });
@@ -124,7 +124,7 @@ describe('RunAIAgentFromConversationDetail — agentHistoryFrom', () => {
124
124
  expect(loaderArgs[0]).toBe('conv-1');
125
125
  expect(loaderArgs[4]).toEqual(['detail-1']);
126
126
  expect((loaderArgs[5] as Date).toISOString()).toBe(FLOOR_ISO);
127
- const runFloor = seams.executeAIAgent.mock.calls[0].at(-1) as Date;
127
+ const runFloor = seams.executeAIAgent.mock.calls[0].at(-2) as Date;
128
128
  expect(runFloor.toISOString()).toBe(FLOOR_ISO);
129
129
  });
130
130
 
@@ -133,7 +133,7 @@ describe('RunAIAgentFromConversationDetail — agentHistoryFrom', () => {
133
133
 
134
134
  expect(result.success).toBe(true);
135
135
  expect(seams.executeAIAgent).not.toHaveBeenCalled();
136
- const runFloor = seams.executeAgentInBackground.mock.calls[0].at(-1) as Date;
136
+ const runFloor = seams.executeAgentInBackground.mock.calls[0].at(-2) as Date;
137
137
  expect(runFloor.toISOString()).toBe(FLOOR_ISO);
138
138
  });
139
139
 
@@ -141,7 +141,7 @@ describe('RunAIAgentFromConversationDetail — agentHistoryFrom', () => {
141
141
  await runMutation(resolver, {});
142
142
 
143
143
  expect(seams.loadConversationHistoryWithAttachments.mock.calls[0][5]).toBeUndefined();
144
- expect(seams.executeAIAgent.mock.calls[0].at(-1)).toBeUndefined();
144
+ expect(seams.executeAIAgent.mock.calls[0].at(-2)).toBeUndefined();
145
145
  });
146
146
 
147
147
  it('fails the request on an unreadable floor, before loading or running anything', async () => {
@@ -178,7 +178,7 @@ describe('loadConversationHistoryWithAttachments — history floor', () => {
178
178
  }).loadConversationHistoryWithAttachments.bind(resolver);
179
179
  await load('conv-1', USER, 20, provider, ['detail-1'], floor);
180
180
 
181
- expect(loadRows).toHaveBeenCalledWith('conv-1', USER, provider, floor);
181
+ expect(loadRows).toHaveBeenCalledWith('conv-1', USER, provider, floor, undefined);
182
182
  expect(assemble.mock.calls[0][1]).toEqual({ maxTailMessages: 20, excludeDetailIds: ['detail-1'], historyFrom: floor });
183
183
  });
184
184
  });