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

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 (459) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/agentSessions/ReturningVisitorRecap.d.ts +2 -0
  3. package/dist/agentSessions/ReturningVisitorRecap.d.ts.map +1 -1
  4. package/dist/agentSessions/ReturningVisitorRecap.js +5 -1
  5. package/dist/agentSessions/ReturningVisitorRecap.js.map +1 -1
  6. package/dist/agentSessions/SessionManager.js +2 -2
  7. package/dist/agentSessions/remoteBrowserGoalEngine.d.ts +8 -0
  8. package/dist/agentSessions/remoteBrowserGoalEngine.d.ts.map +1 -1
  9. package/dist/agentSessions/remoteBrowserGoalEngine.js +21 -5
  10. package/dist/agentSessions/remoteBrowserGoalEngine.js.map +1 -1
  11. package/dist/auth/AuthProviderCatalogRouter.d.ts +2 -0
  12. package/dist/auth/AuthProviderCatalogRouter.d.ts.map +1 -1
  13. package/dist/auth/AuthProviderCatalogRouter.js +5 -1
  14. package/dist/auth/AuthProviderCatalogRouter.js.map +1 -1
  15. package/dist/auth/index.d.ts +20 -1
  16. package/dist/auth/index.d.ts.map +1 -1
  17. package/dist/auth/index.js +20 -10
  18. package/dist/auth/index.js.map +1 -1
  19. package/dist/auth/initializeProviders.d.ts +8 -0
  20. package/dist/auth/initializeProviders.d.ts.map +1 -1
  21. package/dist/auth/initializeProviders.js +21 -5
  22. package/dist/auth/initializeProviders.js.map +1 -1
  23. package/dist/auth/magicLink/MagicLinkRouter.d.ts +9 -0
  24. package/dist/auth/magicLink/MagicLinkRouter.d.ts.map +1 -1
  25. package/dist/auth/magicLink/MagicLinkRouter.js +22 -10
  26. package/dist/auth/magicLink/MagicLinkRouter.js.map +1 -1
  27. package/dist/auth/magicLink/MagicLinkService.d.ts +17 -15
  28. package/dist/auth/magicLink/MagicLinkService.d.ts.map +1 -1
  29. package/dist/auth/magicLink/MagicLinkService.js +65 -51
  30. package/dist/auth/magicLink/MagicLinkService.js.map +1 -1
  31. package/dist/auth/magicLink/index.d.ts +2 -2
  32. package/dist/auth/magicLink/index.d.ts.map +1 -1
  33. package/dist/auth/magicLink/index.js +2 -2
  34. package/dist/auth/magicLink/index.js.map +1 -1
  35. package/dist/auth/magicLink/magicLinkCore.d.ts +54 -33
  36. package/dist/auth/magicLink/magicLinkCore.d.ts.map +1 -1
  37. package/dist/auth/magicLink/magicLinkCore.js +61 -61
  38. package/dist/auth/magicLink/magicLinkCore.js.map +1 -1
  39. package/dist/auth/magicLink/redeemLanding.d.ts +4 -0
  40. package/dist/auth/magicLink/redeemLanding.d.ts.map +1 -1
  41. package/dist/auth/magicLink/redeemLanding.js +12 -4
  42. package/dist/auth/magicLink/redeemLanding.js.map +1 -1
  43. package/dist/auth/magicLink/types.d.ts +4 -4
  44. package/dist/auth/principals.d.ts +2 -0
  45. package/dist/auth/principals.d.ts.map +1 -1
  46. package/dist/auth/principals.js +6 -2
  47. package/dist/auth/principals.js.map +1 -1
  48. package/dist/cache.d.ts +2 -0
  49. package/dist/cache.d.ts.map +1 -1
  50. package/dist/cache.js +3 -1
  51. package/dist/cache.js.map +1 -1
  52. package/dist/config.d.ts +346 -2
  53. package/dist/config.d.ts.map +1 -1
  54. package/dist/config.js +34 -4
  55. package/dist/config.js.map +1 -1
  56. package/dist/context.d.ts +20 -0
  57. package/dist/context.d.ts.map +1 -1
  58. package/dist/context.js +27 -19
  59. package/dist/context.js.map +1 -1
  60. package/dist/directives/Public.d.ts +2 -0
  61. package/dist/directives/Public.d.ts.map +1 -1
  62. package/dist/directives/Public.js +3 -1
  63. package/dist/directives/Public.js.map +1 -1
  64. package/dist/directives/RequireSystemUser.d.ts +2 -0
  65. package/dist/directives/RequireSystemUser.d.ts.map +1 -1
  66. package/dist/directives/RequireSystemUser.js +3 -1
  67. package/dist/directives/RequireSystemUser.js.map +1 -1
  68. package/dist/generated/graphql-schemas/__mj.d.ts +1021 -0
  69. package/dist/generated/graphql-schemas/__mj.d.ts.map +1 -1
  70. package/dist/generated/graphql-schemas/__mj.js +7368 -2145
  71. package/dist/generated/graphql-schemas/__mj.js.map +1 -1
  72. package/dist/generic/CacheInvalidationResolver.d.ts +94 -4
  73. package/dist/generic/CacheInvalidationResolver.d.ts.map +1 -1
  74. package/dist/generic/CacheInvalidationResolver.js +122 -3
  75. package/dist/generic/CacheInvalidationResolver.js.map +1 -1
  76. package/dist/generic/DeleteOptionsInput.d.ts +8 -1
  77. package/dist/generic/DeleteOptionsInput.d.ts.map +1 -1
  78. package/dist/generic/DeleteOptionsInput.js +1 -1
  79. package/dist/generic/DeleteOptionsInput.js.map +1 -1
  80. package/dist/generic/FireAndForgetHeartbeat.d.ts +18 -2
  81. package/dist/generic/FireAndForgetHeartbeat.d.ts.map +1 -1
  82. package/dist/generic/FireAndForgetHeartbeat.js +24 -6
  83. package/dist/generic/FireAndForgetHeartbeat.js.map +1 -1
  84. package/dist/generic/OrphanedConversationDetailReconciler.d.ts +31 -0
  85. package/dist/generic/OrphanedConversationDetailReconciler.d.ts.map +1 -0
  86. package/dist/generic/OrphanedConversationDetailReconciler.js +215 -0
  87. package/dist/generic/OrphanedConversationDetailReconciler.js.map +1 -0
  88. package/dist/generic/PushStatusResolver.d.ts +48 -1
  89. package/dist/generic/PushStatusResolver.d.ts.map +1 -1
  90. package/dist/generic/PushStatusResolver.js +95 -4
  91. package/dist/generic/PushStatusResolver.js.map +1 -1
  92. package/dist/generic/ResolverBase.d.ts +18 -2
  93. package/dist/generic/ResolverBase.d.ts.map +1 -1
  94. package/dist/generic/ResolverBase.js +64 -55
  95. package/dist/generic/ResolverBase.js.map +1 -1
  96. package/dist/index.d.ts +9 -0
  97. package/dist/index.d.ts.map +1 -1
  98. package/dist/index.js +120 -11
  99. package/dist/index.js.map +1 -1
  100. package/dist/integration/CustomColumnPromoter.d.ts +2 -0
  101. package/dist/integration/CustomColumnPromoter.d.ts.map +1 -1
  102. package/dist/integration/CustomColumnPromoter.js +5 -1
  103. package/dist/integration/CustomColumnPromoter.js.map +1 -1
  104. package/dist/integration/EntityMapLifecycle.d.ts +4 -0
  105. package/dist/integration/EntityMapLifecycle.d.ts.map +1 -1
  106. package/dist/integration/EntityMapLifecycle.js +10 -2
  107. package/dist/integration/EntityMapLifecycle.js.map +1 -1
  108. package/dist/logging/NoLog.d.ts +4 -0
  109. package/dist/logging/NoLog.d.ts.map +1 -1
  110. package/dist/logging/NoLog.js +10 -2
  111. package/dist/logging/NoLog.js.map +1 -1
  112. package/dist/logging/StartupLogger.d.ts +2 -0
  113. package/dist/logging/StartupLogger.d.ts.map +1 -1
  114. package/dist/logging/StartupLogger.js +5 -1
  115. package/dist/logging/StartupLogger.js.map +1 -1
  116. package/dist/logging/bootAudit.d.ts +11 -7
  117. package/dist/logging/bootAudit.d.ts.map +1 -1
  118. package/dist/logging/bootAudit.js +15 -7
  119. package/dist/logging/bootAudit.js.map +1 -1
  120. package/dist/logging/boundaryLogPayload.d.ts +4 -0
  121. package/dist/logging/boundaryLogPayload.d.ts.map +1 -1
  122. package/dist/logging/boundaryLogPayload.js +5 -1
  123. package/dist/logging/boundaryLogPayload.js.map +1 -1
  124. package/dist/logging/secretRedactor.d.ts +2 -0
  125. package/dist/logging/secretRedactor.d.ts.map +1 -1
  126. package/dist/logging/secretRedactor.js +8 -4
  127. package/dist/logging/secretRedactor.js.map +1 -1
  128. package/dist/logging/shortenForLog.d.ts +2 -0
  129. package/dist/logging/shortenForLog.d.ts.map +1 -1
  130. package/dist/logging/shortenForLog.js +7 -3
  131. package/dist/logging/shortenForLog.js.map +1 -1
  132. package/dist/logging/variablesLoggingMiddleware.d.ts +2 -0
  133. package/dist/logging/variablesLoggingMiddleware.d.ts.map +1 -1
  134. package/dist/logging/variablesLoggingMiddleware.js +8 -6
  135. package/dist/logging/variablesLoggingMiddleware.js.map +1 -1
  136. package/dist/metadataRefreshSignal.d.ts +19 -0
  137. package/dist/metadataRefreshSignal.d.ts.map +1 -0
  138. package/dist/metadataRefreshSignal.js +45 -0
  139. package/dist/metadataRefreshSignal.js.map +1 -0
  140. package/dist/middleware/MJTenantFilterMiddleware.js +4 -4
  141. package/dist/multiTenancy/index.d.ts +8 -0
  142. package/dist/multiTenancy/index.d.ts.map +1 -1
  143. package/dist/multiTenancy/index.js +21 -5
  144. package/dist/multiTenancy/index.js.map +1 -1
  145. package/dist/realtimeWidget/WidgetRouter.d.ts +5 -0
  146. package/dist/realtimeWidget/WidgetRouter.d.ts.map +1 -1
  147. package/dist/realtimeWidget/WidgetRouter.js +14 -10
  148. package/dist/realtimeWidget/WidgetRouter.js.map +1 -1
  149. package/dist/realtimeWidget/WidgetSessionService.d.ts +6 -6
  150. package/dist/realtimeWidget/WidgetSessionService.js +27 -27
  151. package/dist/realtimeWidget/host-identity.d.ts +5 -1
  152. package/dist/realtimeWidget/host-identity.d.ts.map +1 -1
  153. package/dist/realtimeWidget/host-identity.js +11 -3
  154. package/dist/realtimeWidget/host-identity.js.map +1 -1
  155. package/dist/realtimeWidget/index.d.ts +2 -2
  156. package/dist/realtimeWidget/index.d.ts.map +1 -1
  157. package/dist/realtimeWidget/index.js +2 -2
  158. package/dist/realtimeWidget/index.js.map +1 -1
  159. package/dist/realtimeWidget/visitorIdentity.d.ts +21 -1
  160. package/dist/realtimeWidget/visitorIdentity.d.ts.map +1 -1
  161. package/dist/realtimeWidget/visitorIdentity.js +16 -4
  162. package/dist/realtimeWidget/visitorIdentity.js.map +1 -1
  163. package/dist/realtimeWidget/widgetCore.d.ts +48 -0
  164. package/dist/realtimeWidget/widgetCore.d.ts.map +1 -1
  165. package/dist/realtimeWidget/widgetCore.js +38 -10
  166. package/dist/realtimeWidget/widgetCore.js.map +1 -1
  167. package/dist/realtimeWidget/widgetGuestElevation.d.ts +10 -6
  168. package/dist/realtimeWidget/widgetGuestElevation.d.ts.map +1 -1
  169. package/dist/realtimeWidget/widgetGuestElevation.js +14 -6
  170. package/dist/realtimeWidget/widgetGuestElevation.js.map +1 -1
  171. package/dist/resolvers/AdhocQueryResolver.js +3 -3
  172. package/dist/resolvers/AgentRunStatusPublisher.d.ts +55 -0
  173. package/dist/resolvers/AgentRunStatusPublisher.d.ts.map +1 -0
  174. package/dist/resolvers/AgentRunStatusPublisher.js +141 -0
  175. package/dist/resolvers/AgentRunStatusPublisher.js.map +1 -0
  176. package/dist/resolvers/ConversationRunEventsResolver.d.ts +90 -0
  177. package/dist/resolvers/ConversationRunEventsResolver.d.ts.map +1 -0
  178. package/dist/resolvers/ConversationRunEventsResolver.js +283 -0
  179. package/dist/resolvers/ConversationRunEventsResolver.js.map +1 -0
  180. package/dist/resolvers/DuplicateEntryCheckResolver.d.ts +98 -0
  181. package/dist/resolvers/DuplicateEntryCheckResolver.d.ts.map +1 -0
  182. package/dist/resolvers/DuplicateEntryCheckResolver.js +227 -0
  183. package/dist/resolvers/DuplicateEntryCheckResolver.js.map +1 -0
  184. package/dist/resolvers/FetchEntityVectorsResolver.d.ts.map +1 -1
  185. package/dist/resolvers/FetchEntityVectorsResolver.js +2 -1
  186. package/dist/resolvers/FetchEntityVectorsResolver.js.map +1 -1
  187. package/dist/resolvers/FileResolver.js +3 -3
  188. package/dist/resolvers/GeoResolver.d.ts +2 -2
  189. package/dist/resolvers/GeoResolver.js +4 -4
  190. package/dist/resolvers/GetDataResolver.d.ts +14 -0
  191. package/dist/resolvers/GetDataResolver.d.ts.map +1 -1
  192. package/dist/resolvers/GetDataResolver.js +43 -15
  193. package/dist/resolvers/GetDataResolver.js.map +1 -1
  194. package/dist/resolvers/IntegrationDiscoveryResolver.js +2 -2
  195. package/dist/resolvers/ListOperationsResolver.d.ts +20 -0
  196. package/dist/resolvers/ListOperationsResolver.d.ts.map +1 -1
  197. package/dist/resolvers/ListOperationsResolver.js +68 -28
  198. package/dist/resolvers/ListOperationsResolver.js.map +1 -1
  199. package/dist/resolvers/MCPResolver.d.ts +11 -1
  200. package/dist/resolvers/MCPResolver.d.ts.map +1 -1
  201. package/dist/resolvers/MCPResolver.js +7 -3
  202. package/dist/resolvers/MCPResolver.js.map +1 -1
  203. package/dist/resolvers/MergeRecordsResolver.d.ts +7 -0
  204. package/dist/resolvers/MergeRecordsResolver.d.ts.map +1 -1
  205. package/dist/resolvers/MergeRecordsResolver.js +16 -2
  206. package/dist/resolvers/MergeRecordsResolver.js.map +1 -1
  207. package/dist/resolvers/RealtimeBridgeResolver.js +3 -3
  208. package/dist/resolvers/RealtimeClientSessionResolver.d.ts +44 -6
  209. package/dist/resolvers/RealtimeClientSessionResolver.d.ts.map +1 -1
  210. package/dist/resolvers/RealtimeClientSessionResolver.js +93 -37
  211. package/dist/resolvers/RealtimeClientSessionResolver.js.map +1 -1
  212. package/dist/resolvers/RemoteBrowserActionResolver.js +5 -5
  213. package/dist/resolvers/RunAIAgentResolver.d.ts +8 -18
  214. package/dist/resolvers/RunAIAgentResolver.d.ts.map +1 -1
  215. package/dist/resolvers/RunAIAgentResolver.js +85 -184
  216. package/dist/resolvers/RunAIAgentResolver.js.map +1 -1
  217. package/dist/resolvers/RunAIPromptResolver.d.ts +1 -1
  218. package/dist/resolvers/RunAIPromptResolver.js +2 -2
  219. package/dist/resolvers/RunDecisionResolver.d.ts +149 -0
  220. package/dist/resolvers/RunDecisionResolver.d.ts.map +1 -0
  221. package/dist/resolvers/RunDecisionResolver.js +396 -0
  222. package/dist/resolvers/RunDecisionResolver.js.map +1 -0
  223. package/dist/resolvers/RunTestResolver.js +5 -5
  224. package/dist/resolvers/SqlLoggingConfigResolver.d.ts +8 -4
  225. package/dist/resolvers/SqlLoggingConfigResolver.d.ts.map +1 -1
  226. package/dist/resolvers/SqlLoggingConfigResolver.js +5 -5
  227. package/dist/resolvers/TaskGraphFrameResolver.d.ts +8 -1
  228. package/dist/resolvers/TaskGraphFrameResolver.d.ts.map +1 -1
  229. package/dist/resolvers/TaskGraphFrameResolver.js +6 -2
  230. package/dist/resolvers/TaskGraphFrameResolver.js.map +1 -1
  231. package/dist/resolvers/VectorizeEntityResolver.d.ts +1 -1
  232. package/dist/resolvers/VectorizeEntityResolver.d.ts.map +1 -1
  233. package/dist/resolvers/VectorizeEntityResolver.js +14 -10
  234. package/dist/resolvers/VectorizeEntityResolver.js.map +1 -1
  235. package/dist/resolvers/adhoc-query-helpers.d.ts +6 -0
  236. package/dist/resolvers/adhoc-query-helpers.d.ts.map +1 -1
  237. package/dist/resolvers/adhoc-query-helpers.js +10 -2
  238. package/dist/resolvers/adhoc-query-helpers.js.map +1 -1
  239. package/dist/resolvers/artifact-routing.d.ts +8 -8
  240. package/dist/resolvers/artifact-routing.js +2 -2
  241. package/dist/resolvers/artifact-routing.js.map +1 -1
  242. package/dist/resolvers/meetingRecordingRegistration.d.ts +10 -2
  243. package/dist/resolvers/meetingRecordingRegistration.d.ts.map +1 -1
  244. package/dist/resolvers/meetingRecordingRegistration.js +24 -8
  245. package/dist/resolvers/meetingRecordingRegistration.js.map +1 -1
  246. package/dist/resolvers/peaksSidecar.d.ts +4 -0
  247. package/dist/resolvers/peaksSidecar.d.ts.map +1 -1
  248. package/dist/resolvers/peaksSidecar.js +10 -2
  249. package/dist/resolvers/peaksSidecar.js.map +1 -1
  250. package/dist/rest/EntityCRUDHandler.d.ts +28 -0
  251. package/dist/rest/EntityCRUDHandler.d.ts.map +1 -1
  252. package/dist/rest/EntityCRUDHandler.js +20 -4
  253. package/dist/rest/EntityCRUDHandler.js.map +1 -1
  254. package/dist/rest/MediaStreamHandler.d.ts +2 -0
  255. package/dist/rest/MediaStreamHandler.d.ts.map +1 -1
  256. package/dist/rest/MediaStreamHandler.js +10 -6
  257. package/dist/rest/MediaStreamHandler.js.map +1 -1
  258. package/dist/rest/OAuthCallbackHandler.d.ts +9 -0
  259. package/dist/rest/OAuthCallbackHandler.d.ts.map +1 -1
  260. package/dist/rest/OAuthCallbackHandler.js +15 -3
  261. package/dist/rest/OAuthCallbackHandler.js.map +1 -1
  262. package/dist/rest/RESTEndpointHandler.d.ts +6 -4
  263. package/dist/rest/RESTEndpointHandler.d.ts.map +1 -1
  264. package/dist/rest/RESTEndpointHandler.js +15 -11
  265. package/dist/rest/RESTEndpointHandler.js.map +1 -1
  266. package/dist/rest/RealtimeSdpBrokerHandler.d.ts +5 -1
  267. package/dist/rest/RealtimeSdpBrokerHandler.d.ts.map +1 -1
  268. package/dist/rest/RealtimeSdpBrokerHandler.js +12 -4
  269. package/dist/rest/RealtimeSdpBrokerHandler.js.map +1 -1
  270. package/dist/rest/SignatureWebhookHandler.d.ts +2 -0
  271. package/dist/rest/SignatureWebhookHandler.d.ts.map +1 -1
  272. package/dist/rest/SignatureWebhookHandler.js +5 -1
  273. package/dist/rest/SignatureWebhookHandler.js.map +1 -1
  274. package/dist/rest/UploadTokenManager.d.ts +24 -8
  275. package/dist/rest/UploadTokenManager.d.ts.map +1 -1
  276. package/dist/rest/UploadTokenManager.js +53 -21
  277. package/dist/rest/UploadTokenManager.js.map +1 -1
  278. package/dist/rest/ViewOperationsHandler.d.ts +20 -0
  279. package/dist/rest/ViewOperationsHandler.d.ts.map +1 -1
  280. package/dist/rest/ViewOperationsHandler.js +20 -4
  281. package/dist/rest/ViewOperationsHandler.js.map +1 -1
  282. package/dist/rest/mediaRange.d.ts +4 -0
  283. package/dist/rest/mediaRange.d.ts.map +1 -1
  284. package/dist/rest/mediaRange.js +10 -2
  285. package/dist/rest/mediaRange.js.map +1 -1
  286. package/dist/rest/setupRESTEndpoints.d.ts +4 -0
  287. package/dist/rest/setupRESTEndpoints.d.ts.map +1 -1
  288. package/dist/rest/setupRESTEndpoints.js +13 -7
  289. package/dist/rest/setupRESTEndpoints.js.map +1 -1
  290. package/dist/serverExtensionReservedRoots.d.ts +2 -0
  291. package/dist/serverExtensionReservedRoots.d.ts.map +1 -1
  292. package/dist/serverExtensionReservedRoots.js +5 -1
  293. package/dist/serverExtensionReservedRoots.js.map +1 -1
  294. package/dist/services/TaskGraphActionRunner.d.ts +13 -8
  295. package/dist/services/TaskGraphActionRunner.d.ts.map +1 -1
  296. package/dist/services/TaskGraphActionRunner.js +16 -15
  297. package/dist/services/TaskGraphActionRunner.js.map +1 -1
  298. package/dist/types.d.ts +2 -0
  299. package/dist/types.d.ts.map +1 -1
  300. package/dist/types.js +7 -3
  301. package/dist/types.js.map +1 -1
  302. package/dist/util.d.ts +6 -0
  303. package/dist/util.d.ts.map +1 -1
  304. package/dist/util.js +13 -5
  305. package/dist/util.js.map +1 -1
  306. package/package.json +94 -92
  307. package/src/__tests__/AgentRunStatusPublisher.test.ts +175 -0
  308. package/src/__tests__/DeleteOptionsInput.wireShape.test.ts +62 -0
  309. package/src/__tests__/DuplicateEntryCheckResolver.test.ts +300 -0
  310. package/src/__tests__/FileResolverPeaks.test.ts +13 -13
  311. package/src/__tests__/ListOperationsResolver.test.ts +17 -17
  312. package/src/__tests__/MediaStreamHandler.test.ts +28 -28
  313. package/src/__tests__/NoLog.test.ts +11 -11
  314. package/src/__tests__/PrimaryKeyAlwaysMapped.test.ts +10 -10
  315. package/src/__tests__/RESTEndpointHandler.test.ts +14 -14
  316. package/src/__tests__/RealtimeBridgeResolver.test.ts +4 -2
  317. package/src/__tests__/RealtimeClientSessionResolver.test.ts +216 -2
  318. package/src/__tests__/RealtimeSdpBrokerHandler.test.ts +6 -6
  319. package/src/__tests__/RefreshAdoptsNewColumns.test.ts +8 -8
  320. package/src/__tests__/RemoteBrowserActionRecovery.test.ts +7 -1
  321. package/src/__tests__/RemoteBrowserAudioStream.test.ts +7 -1
  322. package/src/__tests__/RemoteBrowserGoalEngine.test.ts +18 -18
  323. package/src/__tests__/RemoteBrowserSnapshot.test.ts +7 -1
  324. package/src/__tests__/ResolverBase.clientOldValues.test.ts +52 -0
  325. package/src/__tests__/RunAIAgentResolver.historyFrom.test.ts +398 -0
  326. package/src/__tests__/RunAIAgentResolver.streaming.test.ts +18 -27
  327. package/src/__tests__/RunDecisionResolver.test.ts +699 -0
  328. package/src/__tests__/TaskGraphActionRunner.durablePayload.test.ts +131 -0
  329. package/src/__tests__/TaskGraphFrameResolver.test.ts +2 -2
  330. package/src/__tests__/VectorizeEntityResolver.test.ts +106 -0
  331. package/src/__tests__/WidgetSessionService.test.ts +8 -4
  332. package/src/__tests__/adhoc-query-helpers.test.ts +21 -21
  333. package/src/__tests__/bootAudit.test.ts +11 -11
  334. package/src/__tests__/boundaryLogPayload.test.ts +6 -6
  335. package/src/__tests__/cacheInvalidationRecordData.test.ts +177 -0
  336. package/src/__tests__/conversationRunEvents.test.ts +399 -0
  337. package/src/__tests__/databaseAbstraction.test.ts +12 -6
  338. package/src/__tests__/getDataTokenRedaction.test.ts +7 -7
  339. package/src/__tests__/initializeProviders.refresh.test.ts +4 -4
  340. package/src/__tests__/magicLink.test.ts +73 -134
  341. package/src/__tests__/magicLinkService.consume.test.ts +224 -0
  342. package/src/__tests__/meetingRecordingRegistration.test.ts +12 -12
  343. package/src/__tests__/metadataRefreshSignal.test.ts +78 -0
  344. package/src/__tests__/multiTenancy.security.test.ts +40 -40
  345. package/src/__tests__/multiTenancy.test.ts +18 -18
  346. package/src/__tests__/newUsers.test.ts +24 -23
  347. package/src/__tests__/orphanedConversationDetailReconciler.test.ts +283 -0
  348. package/src/__tests__/principals.test.ts +22 -22
  349. package/src/__tests__/pushStatusFanOut.test.ts +206 -0
  350. package/src/__tests__/pushStatusResolver.filter.test.ts +8 -8
  351. package/src/__tests__/secretRedactor.failOpen.test.ts +12 -12
  352. package/src/__tests__/secretRedactor.test.ts +12 -12
  353. package/src/__tests__/serverExtensionReservedRoots.test.ts +7 -7
  354. package/src/__tests__/subscriptionRedaction.test.ts +5 -5
  355. package/src/__tests__/unifiedAuth.test.ts +15 -9
  356. package/src/__tests__/visitorIdentity.resolve.test.ts +6 -6
  357. package/src/__tests__/widget.test.ts +45 -45
  358. package/src/__tests__/widgetGuestElevation.test.ts +7 -7
  359. package/src/__tests__/widgetHostIdentity.test.ts +14 -14
  360. package/src/agentSessions/ReturningVisitorRecap.ts +12 -1
  361. package/src/agentSessions/SessionManager.ts +2 -2
  362. package/src/agentSessions/remoteBrowserGoalEngine.ts +30 -5
  363. package/src/auth/AuthProviderCatalogRouter.ts +6 -1
  364. package/src/auth/__tests__/backward-compatibility.test.ts +4 -3
  365. package/src/auth/index.ts +43 -28
  366. package/src/auth/initializeProviders.ts +25 -5
  367. package/src/auth/magicLink/MagicLinkRouter.ts +28 -10
  368. package/src/auth/magicLink/MagicLinkService.ts +71 -52
  369. package/src/auth/magicLink/index.ts +7 -7
  370. package/src/auth/magicLink/magicLinkCore.ts +96 -64
  371. package/src/auth/magicLink/redeemLanding.ts +14 -4
  372. package/src/auth/magicLink/types.ts +54 -54
  373. package/src/auth/newUsers.ts +1 -1
  374. package/src/auth/principals.ts +11 -2
  375. package/src/cache.ts +4 -1
  376. package/src/config.ts +37 -4
  377. package/src/context.ts +37 -24
  378. package/src/directives/Public.ts +4 -1
  379. package/src/directives/RequireSystemUser.ts +4 -1
  380. package/src/generated/graphql-schemas/__mj.ts +3674 -4
  381. package/src/generic/CacheInvalidationResolver.ts +148 -4
  382. package/src/generic/DeleteOptionsInput.ts +9 -2
  383. package/src/generic/FireAndForgetHeartbeat.ts +35 -16
  384. package/src/generic/OrphanedConversationDetailReconciler.ts +267 -0
  385. package/src/generic/PushStatusResolver.ts +118 -8
  386. package/src/generic/ResolverBase.ts +65 -57
  387. package/src/generic/RunViewResolver.ts +22 -22
  388. package/src/generic/__tests__/FireAndForgetHeartbeat.test.ts +7 -7
  389. package/src/index.ts +137 -11
  390. package/src/integration/CustomColumnPromoter.ts +6 -1
  391. package/src/integration/EntityMapLifecycle.ts +20 -2
  392. package/src/logging/NoLog.ts +16 -2
  393. package/src/logging/StartupLogger.ts +6 -1
  394. package/src/logging/bootAudit.ts +26 -16
  395. package/src/logging/boundaryLogPayload.ts +8 -1
  396. package/src/logging/secretRedactor.ts +14 -9
  397. package/src/logging/shortenForLog.ts +8 -3
  398. package/src/logging/variablesLoggingMiddleware.ts +9 -6
  399. package/src/metadataRefreshSignal.ts +45 -0
  400. package/src/middleware/MJTenantFilterMiddleware.ts +4 -4
  401. package/src/multiTenancy/index.ts +29 -5
  402. package/src/realtimeWidget/WidgetRouter.ts +15 -10
  403. package/src/realtimeWidget/WidgetSessionService.ts +76 -76
  404. package/src/realtimeWidget/host-identity.ts +24 -10
  405. package/src/realtimeWidget/index.ts +3 -3
  406. package/src/realtimeWidget/visitorIdentity.ts +39 -8
  407. package/src/realtimeWidget/widgetCore.ts +75 -10
  408. package/src/realtimeWidget/widgetGuestElevation.ts +25 -12
  409. package/src/resolvers/AdhocQueryResolver.ts +3 -3
  410. package/src/resolvers/AgentRunStatusPublisher.ts +175 -0
  411. package/src/resolvers/AgentSessionResolver.ts +3 -3
  412. package/src/resolvers/ColorResolver.ts +6 -6
  413. package/src/resolvers/ComponentRegistryResolver.ts +36 -36
  414. package/src/resolvers/ConversationRunEventsResolver.ts +308 -0
  415. package/src/resolvers/DuplicateEntryCheckResolver.ts +232 -0
  416. package/src/resolvers/EntityCommunicationsResolver.ts +4 -4
  417. package/src/resolvers/ExecuteRemoteOperationResolver.ts +9 -9
  418. package/src/resolvers/FetchEntityVectorsResolver.ts +2 -1
  419. package/src/resolvers/FileResolver.ts +42 -42
  420. package/src/resolvers/GeoResolver.ts +4 -4
  421. package/src/resolvers/GetDataResolver.ts +50 -15
  422. package/src/resolvers/IntegrationDiscoveryResolver.ts +2 -2
  423. package/src/resolvers/ListOperationsResolver.ts +78 -28
  424. package/src/resolvers/MCPResolver.ts +30 -15
  425. package/src/resolvers/MergeRecordsResolver.ts +14 -2
  426. package/src/resolvers/QueryResolver.ts +13 -13
  427. package/src/resolvers/RealtimeBridgeResolver.ts +3 -3
  428. package/src/resolvers/RealtimeClientSessionResolver.ts +96 -38
  429. package/src/resolvers/RemoteBrowserActionResolver.ts +5 -5
  430. package/src/resolvers/RunAIAgentResolver.ts +134 -239
  431. package/src/resolvers/RunAIPromptResolver.ts +22 -22
  432. package/src/resolvers/RunDecisionResolver.ts +435 -0
  433. package/src/resolvers/RunTemplateResolver.ts +4 -4
  434. package/src/resolvers/RunTestResolver.ts +25 -25
  435. package/src/resolvers/SqlLoggingConfigResolver.ts +56 -56
  436. package/src/resolvers/TaskGraphFrameResolver.ts +37 -28
  437. package/src/resolvers/TelemetryResolver.ts +79 -79
  438. package/src/resolvers/VectorizeEntityResolver.ts +16 -11
  439. package/src/resolvers/__tests__/GetDataResolver.tokens.test.ts +40 -38
  440. package/src/resolvers/__tests__/MergeRecordsResolver.test.ts +93 -0
  441. package/src/resolvers/__tests__/artifact-routing.test.ts +23 -23
  442. package/src/resolvers/adhoc-query-helpers.ts +19 -2
  443. package/src/resolvers/artifact-routing.ts +19 -19
  444. package/src/resolvers/meetingRecordingRegistration.ts +44 -10
  445. package/src/resolvers/peaksSidecar.ts +12 -2
  446. package/src/rest/EntityCRUDHandler.ts +24 -4
  447. package/src/rest/MediaStreamHandler.ts +11 -6
  448. package/src/rest/OAuthCallbackHandler.ts +25 -7
  449. package/src/rest/RESTEndpointHandler.ts +20 -15
  450. package/src/rest/RealtimeSdpBrokerHandler.ts +14 -4
  451. package/src/rest/SignatureWebhookHandler.ts +6 -1
  452. package/src/rest/UploadTokenManager.ts +66 -30
  453. package/src/rest/ViewOperationsHandler.ts +24 -4
  454. package/src/rest/mediaRange.ts +16 -6
  455. package/src/rest/setupRESTEndpoints.ts +24 -12
  456. package/src/serverExtensionReservedRoots.ts +6 -1
  457. package/src/services/TaskGraphActionRunner.ts +16 -15
  458. package/src/types.ts +21 -16
  459. package/src/util.ts +16 -6
@@ -0,0 +1,131 @@
1
+ /**
2
+ * End-to-end-in-miniature regression test for #4794.
3
+ *
4
+ * The bug: `BuildDurableDeferral` persisted a durable entity action's redacted params as a
5
+ * `LoggedParam[]` ARRAY (`RedactParamsToJSON`'s shape), while `TaskGraphActionRunner.buildParams`
6
+ * reads `Task.InputPayload` back as a name→value RECORD. Every released build with durable dispatch
7
+ * (v6.1.0 onward, including 6.1.4) hit the same real-world failure: `TaskGraphDispatcher`'s
8
+ * `mergedPayload` only merges plain objects, so it silently dropped the array before `buildParams`
9
+ * ever saw it, and the action ran with NONE of its declared inputs. `buildParams` itself has no such
10
+ * guard — `Object.assign(merged, arrayValue)` treats an array's indices as keys — so params named
11
+ * `'0'`, `'1'`, ... would only appear if the array reached it directly, bypassing the dispatcher's
12
+ * drop. That narrower path is exactly what this test exercises, by calling `RunActionForTask`
13
+ * on its own rather than through the dispatcher.
14
+ *
15
+ * This test proves the whole pipe, not just the writer or the reader in isolation: build the
16
+ * payload exactly as the deferral does (`RedactParamsToRecord`), push it through the same
17
+ * `JSON.stringify` / `JSON.parse` round trip `TaskGraphService` performs to persist and reload
18
+ * `Task.InputPayload`, then run it through the real `TaskGraphActionRunner` and assert the action
19
+ * receives its declared parameters BY NAME.
20
+ */
21
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
22
+
23
+ vi.mock('@memberjunction/actions', () => ({
24
+ ActionEngineServer: {
25
+ Instance: {
26
+ Config: vi.fn(),
27
+ Actions: [{ ID: 'A1', Name: 'Log Activity' }],
28
+ RunAction: vi.fn(),
29
+ },
30
+ },
31
+ }));
32
+
33
+ import { ActionEngineServer } from '@memberjunction/actions';
34
+ import { RedactParamsToRecord, ActionParam } from '@memberjunction/actions-base';
35
+ import type { MJActionExecutionLogEntity, MJActionParamEntity, MJEntityActionParamEntity } from '@memberjunction/core-entities';
36
+ import type { IMetadataProvider, UserInfo } from '@memberjunction/core';
37
+ import type { TaskActionRunParams } from '@memberjunction/task-graph';
38
+ import { TaskGraphActionRunner } from '../services/TaskGraphActionRunner';
39
+
40
+ // ── Test fixture builders — same shape as packages/Actions/Base/src/__tests__/ParamRedaction.test.ts ──
41
+
42
+ function actionParam(name: string, value: unknown): ActionParam {
43
+ return { Name: name, Value: value, Type: 'Input' } as ActionParam;
44
+ }
45
+
46
+ function definition(id: string, name: string, logValue: boolean = true): MJActionParamEntity {
47
+ return { ID: id, Name: name, LogValue: logValue } as MJActionParamEntity;
48
+ }
49
+
50
+ function binding(actionParamID: string, valueType: string, logValue: boolean | null = null): MJEntityActionParamEntity {
51
+ return { ActionParamID: actionParamID, ValueType: valueType, LogValue: logValue } as MJEntityActionParamEntity;
52
+ }
53
+
54
+ // The declared parameters for the durable entity action under test: three that log normally, and
55
+ // one ("InternalNotes") whose binding opts out of logging (rule 2 in ParamRedaction.ts).
56
+ const RUNTIME_PARAMS: ActionParam[] = [
57
+ actionParam('TypeCode', 'SystemEvent'),
58
+ actionParam('Title', 'Person created'),
59
+ actionParam('RecordID', 'REC-123'),
60
+ actionParam('InternalNotes', 'do not persist this'),
61
+ ];
62
+ const ACTION_PARAMS: MJActionParamEntity[] = [
63
+ definition('p1', 'TypeCode'),
64
+ definition('p2', 'Title'),
65
+ definition('p3', 'RecordID'),
66
+ definition('p4', 'InternalNotes'),
67
+ ];
68
+ const ENTITY_ACTION_PARAMS: MJEntityActionParamEntity[] = [binding('p4', 'Static', false)];
69
+
70
+ function baseRunParams(inputPayload: unknown): TaskActionRunParams {
71
+ return {
72
+ TaskID: 'T1',
73
+ ActionID: 'A1',
74
+ InputPayload: inputPayload,
75
+ DependencyOutputs: new Map(),
76
+ Provider: {} as IMetadataProvider,
77
+ ContextUser: {} as UserInfo,
78
+ };
79
+ }
80
+
81
+ describe('TaskGraphActionRunner — durable payload round-trips by param name (#4794)', () => {
82
+ beforeEach(() => {
83
+ // vitest's `restoreMocks: true` clears mock implementations before every test, including
84
+ // the ones assigned inside the `vi.mock` factory above — so the return value is (re)armed here.
85
+ // Call history on a vi.fn created inside vi.mock survives that restore, so clear it too.
86
+ vi.mocked(ActionEngineServer.Instance.Config).mockResolvedValue(undefined);
87
+ vi.mocked(ActionEngineServer.Instance.RunAction, { partial: true }).mockClear();
88
+ vi.mocked(ActionEngineServer.Instance.RunAction, { partial: true }).mockResolvedValue({
89
+ Success: true,
90
+ Params: [],
91
+ LogEntry: { ID: 'L1' } as MJActionExecutionLogEntity,
92
+ });
93
+ });
94
+
95
+ it('delivers RedactParamsToRecord\'s output to the action by name, after a JSON round trip', async () => {
96
+ // Exactly what the deferral writes, then exactly what TaskGraphService's JSON column does to it.
97
+ const stored = JSON.parse(JSON.stringify(RedactParamsToRecord(RUNTIME_PARAMS, ACTION_PARAMS, ENTITY_ACTION_PARAMS)));
98
+
99
+ const result = await new TaskGraphActionRunner().RunActionForTask(baseRunParams(stored));
100
+
101
+ expect(result.Success).toBe(true);
102
+ expect(result.ActionLogID).toBe('L1');
103
+
104
+ const runActionCall = vi.mocked(ActionEngineServer.Instance.RunAction).mock.calls[0][0];
105
+ const sentParams = runActionCall.Params as ActionParam[];
106
+
107
+ // The three logged declared names arrive, order-insensitive, with their values intact.
108
+ expect(sentParams.map((p) => p.Name).sort()).toEqual(['RecordID', 'Title', 'TypeCode']);
109
+ expect(sentParams.find((p) => p.Name === 'TypeCode')?.Value).toBe('SystemEvent');
110
+ expect(sentParams.find((p) => p.Name === 'Title')?.Value).toBe('Person created');
111
+ expect(sentParams.find((p) => p.Name === 'RecordID')?.Value).toBe('REC-123');
112
+
113
+ // The binding-suppressed parameter never reaches the action — absent, not present-with-undefined.
114
+ expect(sentParams.some((p) => p.Name === 'InternalNotes')).toBe(false);
115
+ });
116
+
117
+ it('does not turn dependency outputs into params named by the upstream task ID', async () => {
118
+ // The dispatcher keys DependencyOutputs by the upstream task's ID and has ALREADY merged their
119
+ // values into InputPayload (TaskGraphDispatcher.mergedPayload). A runner that also spread the
120
+ // map handed the action one extra param per dependency, named by a GUID and holding that
121
+ // task's whole output — which then landed, unredacted, in ActionExecutionLog.Params.
122
+ const upstreamID = '20924BD7-5128-4150-8404-FB44A55AEA0F';
123
+ const params = baseRunParams({ EntityName: 'MJ: Entities', Record: { ID: 'R1', Name: 'MJ: Tags' } });
124
+ params.DependencyOutputs = new Map([[upstreamID, { Record: { ID: 'R1', Name: 'MJ: Tags' } }]]);
125
+
126
+ await new TaskGraphActionRunner().RunActionForTask(params);
127
+
128
+ const sentParams = vi.mocked(ActionEngineServer.Instance.RunAction).mock.calls[0][0].Params as ActionParam[];
129
+ expect(sentParams.map((p) => p.Name).sort()).toEqual(['EntityName', 'Record']);
130
+ });
131
+ });
@@ -19,7 +19,7 @@ vi.mock('@memberjunction/core', () => ({ LogError: vi.fn() }));
19
19
  import {
20
20
  TASK_GRAPH_FRAMES_TOPIC,
21
21
  TaskGraphFrameBroadcaster,
22
- taskGraphFrameFilter,
22
+ TaskGraphFrameFilter,
23
23
  type TaskGraphFramePayload,
24
24
  } from '../resolvers/TaskGraphFrameResolver';
25
25
  import type { TaskGraphFrame } from '@memberjunction/task-graph';
@@ -44,7 +44,7 @@ const payload = (over: Partial<TaskGraphFramePayload> = {}): TaskGraphFramePaylo
44
44
  const context = (userId: string | null) => (userId ? { userPayload: { userRecord: { ID: userId } } } : {});
45
45
 
46
46
  const check = (over: Partial<TaskGraphFramePayload> = {}, args = GRAPH, userId: string | null = OWNER) =>
47
- taskGraphFrameFilter({ payload: payload(over), args: { parentTaskId: args }, context: context(userId) });
47
+ TaskGraphFrameFilter({ payload: payload(over), args: { parentTaskId: args }, context: context(userId) });
48
48
 
49
49
  describe('taskGraphFrameFilter — the delivery gate', () => {
50
50
  it('delivers a frame for the watched graph to its owner', () => {
@@ -0,0 +1,106 @@
1
+ import 'reflect-metadata';
2
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
3
+ import { DatabaseProviderBase, UserInfo, type IMetadataProvider } from '@memberjunction/core';
4
+ import sql from 'mssql';
5
+ import { VectorizeEntityResolver } from '../resolvers/VectorizeEntityResolver.js';
6
+ import type { AppContext, ProviderInfo } from '../types.js';
7
+
8
+ const mockSyncerConstructedWith: (IMetadataProvider | undefined)[] = [];
9
+
10
+ vi.mock('@memberjunction/ai-vector-sync', () => {
11
+ return {
12
+ EntityVectorSyncer: class {
13
+ constructor(provider?: IMetadataProvider) {
14
+ mockSyncerConstructedWith.push(provider);
15
+ }
16
+ Config() {
17
+ return Promise.resolve(undefined);
18
+ }
19
+ VectorizeEntity() {
20
+ return Promise.resolve({ success: true, status: 'Completed' });
21
+ }
22
+ },
23
+ };
24
+ });
25
+
26
+ vi.mock('../generic/PubSubManager.js', () => ({
27
+ PubSubManager: {
28
+ Instance: {
29
+ Publish: vi.fn(),
30
+ },
31
+ },
32
+ }));
33
+
34
+ function createAppContext(providers?: ProviderInfo[]): AppContext {
35
+ return {
36
+ dataSource: Object.create(sql.ConnectionPool.prototype) as sql.ConnectionPool,
37
+ dataSources: [],
38
+ providers: providers ?? [],
39
+ userPayload: {
40
+ email: 'test@example.com',
41
+ sessionId: 'test-session',
42
+ userRecord: new UserInfo(),
43
+ },
44
+ };
45
+ }
46
+
47
+ describe('VectorizeEntityResolver — provider propagation', () => {
48
+ beforeEach(() => {
49
+ mockSyncerConstructedWith.length = 0;
50
+ });
51
+
52
+ it('passes request-scoped Read-Write provider from AppContext to EntityVectorSyncer', async () => {
53
+ const mockProvider = Object.create(DatabaseProviderBase.prototype) as DatabaseProviderBase;
54
+ const providerInfo: ProviderInfo = {
55
+ provider: mockProvider,
56
+ type: 'Read-Write',
57
+ };
58
+
59
+ const resolver = new VectorizeEntityResolver();
60
+ const result = await resolver.VectorizeEntity(
61
+ 'doc-1',
62
+ 'entity-1',
63
+ 10,
64
+ createAppContext([providerInfo])
65
+ );
66
+
67
+ expect(result.Success).toBe(true);
68
+ expect(result.Status).toBe('Started');
69
+ expect(mockSyncerConstructedWith.length).toBe(1);
70
+ expect(mockSyncerConstructedWith[0]).toBe(mockProvider);
71
+ });
72
+
73
+ it('falls back to Read-Only provider when no Read-Write provider exists', async () => {
74
+ const readOnlyProvider = Object.create(DatabaseProviderBase.prototype) as DatabaseProviderBase;
75
+ const providerInfo: ProviderInfo = {
76
+ provider: readOnlyProvider,
77
+ type: 'Read-Only',
78
+ };
79
+
80
+ const resolver = new VectorizeEntityResolver();
81
+ const result = await resolver.VectorizeEntity(
82
+ 'doc-2',
83
+ 'entity-2',
84
+ 10,
85
+ createAppContext([providerInfo])
86
+ );
87
+
88
+ expect(result.Success).toBe(true);
89
+ expect(mockSyncerConstructedWith.length).toBe(1);
90
+ expect(mockSyncerConstructedWith[0]).toBe(readOnlyProvider);
91
+ });
92
+
93
+ it('passes undefined provider to EntityVectorSyncer when no providers in AppContext', async () => {
94
+ const resolver = new VectorizeEntityResolver();
95
+ const result = await resolver.VectorizeEntity(
96
+ 'doc-3',
97
+ 'entity-3',
98
+ 10,
99
+ createAppContext([])
100
+ );
101
+
102
+ expect(result.Success).toBe(true);
103
+ expect(mockSyncerConstructedWith.length).toBe(1);
104
+ expect(mockSyncerConstructedWith[0]).toBeUndefined();
105
+ });
106
+ });
@@ -21,12 +21,16 @@ vi.mock('../auth/magicLink/MagicLinkService.js', () => ({
21
21
  MagicLinkService: class {},
22
22
  }));
23
23
  vi.mock('../agentSessions/ReturningVisitorRecap.js', () => ({
24
- writeReturningVisitorRecap: async () => undefined,
24
+ WriteReturningVisitorRecap: async () => undefined,
25
+ get writeReturningVisitorRecap() { return this.WriteReturningVisitorRecap; },
25
26
  }));
26
27
  vi.mock('../realtimeWidget/visitorIdentity.js', () => ({
27
- resolveIdentityByEmail: async () => null,
28
- mergeVisitorIdentity: async () => 0,
29
- forgetVisitor: async () => ({ notesArchived: 0, conversationsCleared: 0 }),
28
+ ResolveIdentityByEmail: async () => null,
29
+ get resolveIdentityByEmail() { return this.ResolveIdentityByEmail; },
30
+ MergeVisitorIdentity: async () => 0,
31
+ get mergeVisitorIdentity() { return this.MergeVisitorIdentity; },
32
+ ForgetVisitor: async () => ({ notesArchived: 0, conversationsCleared: 0 }),
33
+ get forgetVisitor() { return this.ForgetVisitor; },
30
34
  }));
31
35
 
32
36
  import { WidgetSessionService } from '../realtimeWidget/WidgetSessionService.js';
@@ -1,50 +1,50 @@
1
1
  import { describe, it, expect } from 'vitest';
2
- import { exactTotalFromPage, resolveAdhocTotalRowCount } from '../resolvers/adhoc-query-helpers';
2
+ import { ExactTotalFromPage, ResolveAdhocTotalRowCount } from '../resolvers/adhoc-query-helpers';
3
3
 
4
4
  describe('exactTotalFromPage', () => {
5
5
  it('returns the row count when not paging (maxRows null) — the query was uncapped', () => {
6
- expect(exactTotalFromPage(0, 47, null)).toBe(47);
7
- expect(exactTotalFromPage(0, 0, null)).toBe(0);
6
+ expect(ExactTotalFromPage(0, 47, null)).toBe(47);
7
+ expect(ExactTotalFromPage(0, 0, null)).toBe(0);
8
8
  });
9
9
 
10
10
  it('returns startRow + pageLength for a SHORT page (fewer rows than the page size)', () => {
11
- expect(exactTotalFromPage(0, 47, 100)).toBe(47); // page 1, short → exact total
12
- expect(exactTotalFromPage(200, 30, 100)).toBe(230); // page 3, short last page
13
- expect(exactTotalFromPage(100, 0, 100)).toBe(100); // empty page past the end
11
+ expect(ExactTotalFromPage(0, 47, 100)).toBe(47); // page 1, short → exact total
12
+ expect(ExactTotalFromPage(200, 30, 100)).toBe(230); // page 3, short last page
13
+ expect(ExactTotalFromPage(100, 0, 100)).toBe(100); // empty page past the end
14
14
  });
15
15
 
16
16
  it('returns null for a FULL page — a COUNT is required because more rows may exist', () => {
17
- expect(exactTotalFromPage(0, 100, 100)).toBeNull();
18
- expect(exactTotalFromPage(500, 100, 100)).toBeNull();
17
+ expect(ExactTotalFromPage(0, 100, 100)).toBeNull();
18
+ expect(ExactTotalFromPage(500, 100, 100)).toBeNull();
19
19
  });
20
20
 
21
21
  it('treats an over-full page defensively as "needs count" (should not occur with OFFSET/FETCH)', () => {
22
- expect(exactTotalFromPage(0, 150, 100)).toBeNull();
22
+ expect(ExactTotalFromPage(0, 150, 100)).toBeNull();
23
23
  });
24
24
  });
25
25
 
26
26
  describe('resolveAdhocTotalRowCount', () => {
27
27
  it('reads TotalRowCount from the count recordset', () => {
28
- expect(resolveAdhocTotalRowCount([{ TotalRowCount: 2087 }], 100)).toBe(2087);
29
- expect(resolveAdhocTotalRowCount([{ TotalRowCount: 0 }], 100)).toBe(0);
28
+ expect(ResolveAdhocTotalRowCount([{ TotalRowCount: 2087 }], 100)).toBe(2087);
29
+ expect(ResolveAdhocTotalRowCount([{ TotalRowCount: 0 }], 100)).toBe(0);
30
30
  });
31
31
 
32
32
  it('floors a fractional/stringified count', () => {
33
- expect(resolveAdhocTotalRowCount([{ TotalRowCount: 42.9 }], 0)).toBe(42);
34
- expect(resolveAdhocTotalRowCount([{ TotalRowCount: '2087' as unknown as number }], 0)).toBe(2087);
33
+ expect(ResolveAdhocTotalRowCount([{ TotalRowCount: 42.9 }], 0)).toBe(42);
34
+ expect(ResolveAdhocTotalRowCount([{ TotalRowCount: '2087' as unknown as number }], 0)).toBe(2087);
35
35
  });
36
36
 
37
37
  it('falls back when the count is absent, empty, null, or malformed', () => {
38
- expect(resolveAdhocTotalRowCount(null, 100)).toBe(100);
39
- expect(resolveAdhocTotalRowCount(undefined, 100)).toBe(100);
40
- expect(resolveAdhocTotalRowCount([], 100)).toBe(100);
41
- expect(resolveAdhocTotalRowCount([{}], 100)).toBe(100);
42
- expect(resolveAdhocTotalRowCount([{ TotalRowCount: null }], 100)).toBe(100);
38
+ expect(ResolveAdhocTotalRowCount(null, 100)).toBe(100);
39
+ expect(ResolveAdhocTotalRowCount(undefined, 100)).toBe(100);
40
+ expect(ResolveAdhocTotalRowCount([], 100)).toBe(100);
41
+ expect(ResolveAdhocTotalRowCount([{}], 100)).toBe(100);
42
+ expect(ResolveAdhocTotalRowCount([{ TotalRowCount: null }], 100)).toBe(100);
43
43
  });
44
44
 
45
45
  it('falls back on non-finite or negative counts (never reports a misleading total)', () => {
46
- expect(resolveAdhocTotalRowCount([{ TotalRowCount: Number.NaN }], 100)).toBe(100);
47
- expect(resolveAdhocTotalRowCount([{ TotalRowCount: -5 }], 100)).toBe(100);
48
- expect(resolveAdhocTotalRowCount([{ TotalRowCount: Infinity }], 100)).toBe(100);
46
+ expect(ResolveAdhocTotalRowCount([{ TotalRowCount: Number.NaN }], 100)).toBe(100);
47
+ expect(ResolveAdhocTotalRowCount([{ TotalRowCount: -5 }], 100)).toBe(100);
48
+ expect(ResolveAdhocTotalRowCount([{ TotalRowCount: Infinity }], 100)).toBe(100);
49
49
  });
50
50
  });
@@ -18,7 +18,7 @@ vi.mock('../config.js', () => ({
18
18
  },
19
19
  }));
20
20
 
21
- import { auditResolverList } from '../logging/bootAudit.js';
21
+ import { AuditResolverList } from '../logging/bootAudit.js';
22
22
  import type { AuditArgParam, AuditResolver } from '../logging/bootAudit.js';
23
23
  import { NoLog } from '../logging/NoLog.js';
24
24
 
@@ -37,12 +37,12 @@ function makeArgParam(opts: {
37
37
  type: Function;
38
38
  }): AuditArgParam {
39
39
  return {
40
- target: opts.target,
41
- methodName: opts.methodName,
42
- index: opts.index,
40
+ Target: opts.target,
41
+ MethodName: opts.methodName,
42
+ Index: opts.index,
43
43
  kind: 'arg',
44
44
  name: opts.name,
45
- getType: () => opts.type,
45
+ GetType: () => opts.type,
46
46
  };
47
47
  }
48
48
 
@@ -52,8 +52,8 @@ function makeResolver(opts: {
52
52
  params: AuditArgParam[];
53
53
  }): AuditResolver {
54
54
  return {
55
- target: opts.target,
56
- methodName: opts.methodName,
55
+ Target: opts.target,
56
+ MethodName: opts.methodName,
57
57
  params: opts.params,
58
58
  };
59
59
  }
@@ -93,7 +93,7 @@ describe('auditResolverList', () => {
93
93
  ],
94
94
  });
95
95
 
96
- auditResolverList([resolver]);
96
+ AuditResolverList([resolver]);
97
97
  expect(warnSpy).not.toHaveBeenCalled();
98
98
  });
99
99
 
@@ -117,7 +117,7 @@ describe('auditResolverList', () => {
117
117
  ],
118
118
  });
119
119
 
120
- auditResolverList([resolver]);
120
+ AuditResolverList([resolver]);
121
121
  expect(warnSpy).toHaveBeenCalledTimes(1);
122
122
  const message = warnSpy.mock.calls[0][0];
123
123
  expect(typeof message).toBe('string');
@@ -148,7 +148,7 @@ describe('auditResolverList', () => {
148
148
  ],
149
149
  });
150
150
 
151
- auditResolverList([resolver]);
151
+ AuditResolverList([resolver]);
152
152
  expect(warnSpy).not.toHaveBeenCalled();
153
153
  });
154
154
 
@@ -179,7 +179,7 @@ describe('auditResolverList', () => {
179
179
  ],
180
180
  });
181
181
 
182
- auditResolverList([resolver]);
182
+ AuditResolverList([resolver]);
183
183
  expect(warnSpy).toHaveBeenCalledTimes(1);
184
184
  const message = warnSpy.mock.calls[0][0];
185
185
  expect(message).toContain("'custom'");
@@ -1,5 +1,5 @@
1
1
  import { describe, it, expect } from 'vitest';
2
- import { buildBoundaryLogPayload } from '../logging/boundaryLogPayload.js';
2
+ import { BuildBoundaryLogPayload } from '../logging/boundaryLogPayload.js';
3
3
 
4
4
  /**
5
5
  * Guards the load-bearing #2638 fix: the always-on GraphQL boundary log line emits the
@@ -10,22 +10,22 @@ import { buildBoundaryLogPayload } from '../logging/boundaryLogPayload.js';
10
10
  */
11
11
  describe('buildBoundaryLogPayload', () => {
12
12
  it('returns operation name only', () => {
13
- expect(buildBoundaryLogPayload('CreateMJCredential')).toEqual({ operationName: 'CreateMJCredential' });
13
+ expect(BuildBoundaryLogPayload('CreateMJCredential')).toEqual({ operationName: 'CreateMJCredential' });
14
14
  });
15
15
 
16
16
  it('never includes a `variables` key', () => {
17
- const payload = buildBoundaryLogPayload('RunViewsWithCacheCheck');
17
+ const payload = BuildBoundaryLogPayload('RunViewsWithCacheCheck');
18
18
  expect('variables' in payload).toBe(false);
19
19
  });
20
20
 
21
21
  it('serialized form contains no value content — only the operation name', () => {
22
22
  // Even if someone passes a secret-shaped operation name, nothing but the name is emitted.
23
- const serialized = JSON.stringify(buildBoundaryLogPayload('SomeOp'));
23
+ const serialized = JSON.stringify(BuildBoundaryLogPayload('SomeOp'));
24
24
  expect(serialized).toBe('{"operationName":"SomeOp"}');
25
25
  });
26
26
 
27
27
  it('handles undefined operation name (non-named operations)', () => {
28
- expect(buildBoundaryLogPayload(undefined)).toEqual({ operationName: undefined });
29
- expect('variables' in buildBoundaryLogPayload(undefined)).toBe(false);
28
+ expect(BuildBoundaryLogPayload(undefined)).toEqual({ operationName: undefined });
29
+ expect('variables' in BuildBoundaryLogPayload(undefined)).toBe(false);
30
30
  });
31
31
  });
@@ -0,0 +1,177 @@
1
+ // The gate lives beside the subscription it protects, and that module carries type-graphql
2
+ // decorators — so the metadata shim has to be in place before it is imported.
3
+ import 'reflect-metadata';
4
+ import { afterEach, describe, expect, it, vi } from 'vitest';
5
+ import {
6
+ ConfigureRecordDataBroadcast,
7
+ MayBroadcastRecordData,
8
+ } from '../generic/CacheInvalidationResolver.js';
9
+
10
+ /**
11
+ * The cache-invalidation subscription is delivered to every connected client with no per-user
12
+ * filter, so anything `MayBroadcastRecordData` lets through is readable by every signed-in session
13
+ * regardless of row-level security or any tenant scoping a consumer applies on the read path.
14
+ *
15
+ * The important case is the DEFAULT: an untouched deployment must broadcast no row data at all,
16
+ * because that is the configuration everyone upgrades into.
17
+ */
18
+ describe('MayBroadcastRecordData', () => {
19
+ afterEach(() => ConfigureRecordDataBroadcast([]));
20
+
21
+ it('broadcasts nothing before anything has configured it', () => {
22
+ // No ConfigureRecordDataBroadcast call at all — the state a process starts in, and the state it
23
+ // stays in if bootstrap ever stops calling it. Failing closed there is the whole point.
24
+ expect(MayBroadcastRecordData('Users')).toBe(false);
25
+ expect(MayBroadcastRecordData('AI Models')).toBe(false);
26
+ });
27
+
28
+ it('broadcasts nothing when the deployment has not opted in', () => {
29
+ ConfigureRecordDataBroadcast([]);
30
+ expect(MayBroadcastRecordData('Users')).toBe(false);
31
+ });
32
+
33
+ it('broadcasts nothing when the config value is absent', () => {
34
+ ConfigureRecordDataBroadcast(undefined);
35
+ expect(MayBroadcastRecordData('Users')).toBe(false);
36
+ });
37
+
38
+ it('allows exactly the entities named, and no others', () => {
39
+ ConfigureRecordDataBroadcast(['AI Models']);
40
+ expect(MayBroadcastRecordData('AI Models')).toBe(true);
41
+ expect(MayBroadcastRecordData('Users')).toBe(false);
42
+ expect(MayBroadcastRecordData('AI Model Vendors')).toBe(false);
43
+ // The allowlisted name as a SUBSTRING of another entity must not carry it in. Written this way
44
+ // deliberately: 'AI Model Vendors' above does not contain 'AI Models', so it passes against a
45
+ // loose `includes` match too and proves nothing — a substring mutation survived it.
46
+ expect(MayBroadcastRecordData('Archived AI Models 2024')).toBe(false);
47
+ // ...and the reverse direction, where the entity name is a substring of the allowlisted one.
48
+ expect(MayBroadcastRecordData('AI Model')).toBe(false);
49
+ });
50
+
51
+ it('matches entity names case- and whitespace-insensitively', () => {
52
+ ConfigureRecordDataBroadcast([' ai models ']);
53
+ expect(MayBroadcastRecordData('AI Models')).toBe(true);
54
+ });
55
+
56
+ it("restores the previous broadcast-everything behaviour only on an explicit '*'", () => {
57
+ ConfigureRecordDataBroadcast(['*']);
58
+ expect(MayBroadcastRecordData('Users')).toBe(true);
59
+ expect(MayBroadcastRecordData('Organization Person Roles')).toBe(true);
60
+ });
61
+ });
62
+
63
+ /**
64
+ * Importing this module must not drag server config loading in with it.
65
+ *
66
+ * The first version of this change read `configInfo` at module scope. `config.ts` runs
67
+ * `loadConfig()` on import, so every test that touched the resolver — directly or through
68
+ * ResolverBase — died at import with "Configuration validation failed". CI caught it; this keeps
69
+ * it caught.
70
+ */
71
+ describe('CacheInvalidationResolver module surface', () => {
72
+ it('imports without any server configuration present', async () => {
73
+ await expect(import('../generic/CacheInvalidationResolver.js')).resolves.toBeDefined();
74
+ });
75
+ });
76
+
77
+ /**
78
+ * The allowlist is normalised where it enters, not where it is compared.
79
+ *
80
+ * Raised in review: the wildcard was matched raw while entity names were trimmed and lowercased,
81
+ * so a hand-edited `[' * ']` matched neither branch and silently opted nothing in — a config that
82
+ * reads as "broadcast everything" while the gate stayed fully closed.
83
+ */
84
+ describe('allowlist normalisation', () => {
85
+ afterEach(() => ConfigureRecordDataBroadcast([]));
86
+
87
+ it("honours a wildcard written with surrounding whitespace", () => {
88
+ ConfigureRecordDataBroadcast([' * ']);
89
+ expect(MayBroadcastRecordData('Users')).toBe(true);
90
+ });
91
+
92
+ it('ignores blank entries rather than letting one match something', () => {
93
+ ConfigureRecordDataBroadcast(['', ' ']);
94
+ expect(MayBroadcastRecordData('Users')).toBe(false);
95
+ // A blank entry must not become a wildcard by accident either.
96
+ expect(MayBroadcastRecordData('')).toBe(false);
97
+ });
98
+
99
+ it('still matches a normal name written with odd casing and padding', () => {
100
+ ConfigureRecordDataBroadcast([' AI MODELS ']);
101
+ expect(MayBroadcastRecordData('ai models')).toBe(true);
102
+ expect(MayBroadcastRecordData('Users')).toBe(false);
103
+ });
104
+ });
105
+
106
+ /**
107
+ * Entity-level delivery filtering, raised in review.
108
+ *
109
+ * An event for an entity a session cannot read at all tells that session the record exists, its
110
+ * stable key and when it changed — and the session could never have read it, so withholding costs
111
+ * nothing. This does NOT close the row-level case: two sessions that both hold read permission on
112
+ * an entity still see each other's keys. That is tracked separately and deliberately not faked
113
+ * green here.
114
+ */
115
+ describe('cacheInvalidationFilter', () => {
116
+ const event = (entityName: string) => ({
117
+ entityName,
118
+ primaryKeyValues: '[{"FieldName":"ID","Value":"r1"}]',
119
+ action: 'save',
120
+ sourceServerId: 's1',
121
+ timestamp: new Date(),
122
+ });
123
+ const session = (userRecord: unknown) => ({ userPayload: { userRecord } });
124
+
125
+ const withEntities = async (entities: Array<{ Name: string; CanRead: boolean }>) => {
126
+ vi.resetModules();
127
+ vi.doMock('@memberjunction/core', () => ({
128
+ Metadata: class {
129
+ get Entities() {
130
+ return entities.map((e) => ({
131
+ Name: e.Name,
132
+ GetUserPermisions: () => ({ CanRead: e.CanRead }),
133
+ }));
134
+ }
135
+ // The real one is case-insensitive and trims — the filter relies on that, so the mock does too.
136
+ EntityByName(name: string) {
137
+ const key = name.trim().toLowerCase();
138
+ return this.Entities.find((e) => e.Name.toLowerCase() === key);
139
+ }
140
+ },
141
+ }));
142
+ return (await import('../generic/CacheInvalidationResolver.js')).cacheInvalidationFilter;
143
+ };
144
+
145
+ afterEach(() => vi.doUnmock('@memberjunction/core'));
146
+
147
+ it('delivers an event for an entity the session may read', async () => {
148
+ const filter = await withEntities([{ Name: 'AI Models', CanRead: true }]);
149
+ expect(filter({ payload: event('AI Models') as never, context: session({ ID: 'u1' }) })).toBe(true);
150
+ });
151
+
152
+ it('withholds an event for an entity the session may NOT read', async () => {
153
+ const filter = await withEntities([{ Name: 'Users', CanRead: false }]);
154
+ expect(filter({ payload: event('Users') as never, context: session({ ID: 'u1' }) })).toBe(false);
155
+ });
156
+
157
+ it('fails closed when the connection carries no user', async () => {
158
+ // onConnect rejects a socket whose token does not validate, so this should not arise — and it
159
+ // is the case least deserving of an unfiltered firehose if it does.
160
+ const filter = await withEntities([{ Name: 'AI Models', CanRead: true }]);
161
+ expect(filter({ payload: event('AI Models') as never, context: undefined })).toBe(false);
162
+ expect(filter({ payload: event('AI Models') as never, context: session(undefined) })).toBe(false);
163
+ });
164
+
165
+ it('delivers when the entity is unknown to this server, rather than silently going stale', async () => {
166
+ // Deliberately the opposite choice: a name absent from metadata cannot be permission-checked,
167
+ // and withholding would stop invalidating a legitimately cacheable entity — a correctness bug
168
+ // in place of a disclosure one.
169
+ const filter = await withEntities([{ Name: 'AI Models', CanRead: true }]);
170
+ expect(filter({ payload: event('Some Entity This Server Never Heard Of') as never, context: session({ ID: 'u1' }) })).toBe(true);
171
+ });
172
+
173
+ it('withholds an event with no entity name', async () => {
174
+ const filter = await withEntities([{ Name: 'AI Models', CanRead: true }]);
175
+ expect(filter({ payload: { ...event(''), entityName: '' } as never, context: session({ ID: 'u1' }) })).toBe(false);
176
+ });
177
+ });