@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,300 @@
1
+ // type-graphql decorators call `Reflect.getMetadata`, which only exists once this polyfill is
2
+ // loaded. MUST precede any import that pulls in the resolver file.
3
+ import 'reflect-metadata';
4
+
5
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
6
+
7
+ /** The slice of `APIKeyEngine.Authorize` that ResolverBase.CheckAPIKeyScopeAuthorization calls. */
8
+ type AuthorizeFn = (
9
+ apiKeyHash: string,
10
+ application: string,
11
+ scopePath: string,
12
+ resource: string
13
+ ) => Promise<{ Allowed: boolean; Reason: string }>;
14
+
15
+ const { mockAuthorize, mockLogError } = vi.hoisted(() => ({
16
+ mockAuthorize: vi.fn<AuthorizeFn>(),
17
+ mockLogError: vi.fn<(message: string) => void>(),
18
+ }));
19
+
20
+ // As in RunDecisionResolver.test.ts: vitest's esbuild transform does not apply
21
+ // `emitDecoratorMetadata`, so the decorators are no-ops and the resolver runs as a plain class.
22
+ vi.mock('type-graphql', () => {
23
+ const noopDecorator = () => () => undefined;
24
+ return {
25
+ Resolver: noopDecorator, Mutation: noopDecorator, Query: noopDecorator, Subscription: noopDecorator,
26
+ ObjectType: noopDecorator, InputType: noopDecorator, Field: noopDecorator, Arg: noopDecorator,
27
+ Args: noopDecorator, Ctx: noopDecorator, PubSub: noopDecorator, Root: noopDecorator,
28
+ Directive: noopDecorator, Authorized: noopDecorator, UseMiddleware: noopDecorator,
29
+ createUnionType: () => class {},
30
+ AuthorizationError: class AuthorizationError extends Error {
31
+ constructor(message?: string) {
32
+ super(message);
33
+ this.name = 'AuthorizationError';
34
+ }
35
+ },
36
+ Float: class {}, Int: class {}, ID: class {},
37
+ };
38
+ });
39
+
40
+ // Only logging is replaced, so a test can tell a logged fault from a quiet answer.
41
+ vi.mock('@memberjunction/core', async (importOriginal) => {
42
+ const actual = await importOriginal<Record<string, unknown>>();
43
+ return { ...actual, LogError: mockLogError };
44
+ });
45
+
46
+ // Only the API-key engine is replaced; ResolverBase's scope check itself is the production code.
47
+ vi.mock('@memberjunction/api-keys', async (importOriginal) => {
48
+ const actual = await importOriginal<Record<string, unknown>>();
49
+ return { ...actual, GetAPIKeyEngine: () => ({ Authorize: mockAuthorize }) };
50
+ });
51
+
52
+ // The resolver's tests replace the detector through CreateEntryChecker, so the detector package
53
+ // is never exercised here; it has its own specs.
54
+ vi.mock('@memberjunction/ai-vector-dupe', () => ({ DuplicateRecordDetector: class {} }));
55
+
56
+ import { EntityInfo, Metadata, UserInfo } from '@memberjunction/core';
57
+ import { UserCache } from '@memberjunction/generic-database-provider';
58
+ import type { DuplicateEntryCheckResult } from '@memberjunction/ai-vector-dupe';
59
+ import {
60
+ DUPLICATE_ENTRY_CHECK_MAX_VALUES_JSON_LENGTH,
61
+ DuplicateEntryCheckResolver,
62
+ type DuplicateEntryChecker,
63
+ } from '../resolvers/DuplicateEntryCheckResolver.js';
64
+ import type { UserPayload } from '../types.js';
65
+
66
+ // ─── Fixtures ────────────────────────────────────────────────────────────────
67
+
68
+ const USER = new UserInfo(null, {
69
+ ID: 'user-1',
70
+ Name: 'Entry Person',
71
+ Email: 'person@example.com',
72
+ UserRoles: [{ UserID: 'user-1', RoleID: 'role-ui' }],
73
+ });
74
+ const SYSTEM_USER = new UserInfo(null, { ID: 'user-system', Name: 'System', Email: 'system@example.com' });
75
+
76
+ /** An entity the user's role may read. */
77
+ const ACCOUNTS = new EntityInfo({
78
+ ID: 'entity-accounts',
79
+ Name: 'Accounts',
80
+ Status: 'Active',
81
+ Fields: [
82
+ { Name: 'ID', Type: 'uniqueidentifier', IsPrimaryKey: true },
83
+ { Name: 'Name', Type: 'nvarchar', IsNameField: true, AllowUpdateAPI: true },
84
+ { Name: 'City', Type: 'nvarchar', AllowUpdateAPI: true },
85
+ { Name: 'Owner', Type: 'nvarchar', AllowUpdateAPI: false },
86
+ { Name: '__mj_CreatedAt', Type: 'datetimeoffset', AllowUpdateAPI: false },
87
+ ],
88
+ EntityPermissions: [{ RoleID: 'role-ui', CanRead: true }],
89
+ });
90
+
91
+ /** An entity only another role may read. */
92
+ const PAYROLL = new EntityInfo({
93
+ ID: 'entity-payroll',
94
+ Name: 'Payroll',
95
+ Status: 'Active',
96
+ Fields: [{ Name: 'ID', Type: 'uniqueidentifier', IsPrimaryKey: true }],
97
+ EntityPermissions: [{ RoleID: 'role-finance', CanRead: true }],
98
+ });
99
+
100
+ const CHECKED: DuplicateEntryCheckResult = {
101
+ Status: 'Checked',
102
+ Candidates: [{ RecordID: 'acct-7', DisplayName: 'Acme Corp', VectorScore: 0.93, Probability: 0.81 }],
103
+ ElapsedMs: 212,
104
+ };
105
+
106
+ /** A session authenticated by JWT: no API key, so no scope check. */
107
+ const sessionPayload = (): UserPayload => ({ email: USER.Email, userRecord: USER, sessionId: 'session-1' });
108
+ /** A session authenticated by an MJ API key: scope-checked. */
109
+ const apiKeyPayload = (): UserPayload => ({ ...sessionPayload(), apiKeyId: 'key-1', apiKeyHash: 'hash-1' });
110
+
111
+ /** The resolver with its detector replaced by a double. */
112
+ class TestResolver extends DuplicateEntryCheckResolver {
113
+ public readonly Checker = { CheckRecordValues: vi.fn<DuplicateEntryChecker['CheckRecordValues']>() };
114
+
115
+ protected override CreateEntryChecker(): DuplicateEntryChecker {
116
+ return this.Checker;
117
+ }
118
+ }
119
+
120
+ let resolver: TestResolver;
121
+
122
+ const check = (entityName: string, valuesJSON: string, payload: UserPayload = sessionPayload()) =>
123
+ resolver.RunEntryCheck(entityName, valuesJSON, payload, null);
124
+
125
+ beforeEach(() => {
126
+ vi.restoreAllMocks();
127
+ mockAuthorize.mockReset();
128
+ mockLogError.mockReset();
129
+ vi.spyOn(Metadata.prototype, 'EntityByName').mockImplementation((name: string) =>
130
+ [ACCOUNTS, PAYROLL].find(e => e.Name.toLowerCase() === name.trim().toLowerCase())
131
+ );
132
+ vi.spyOn(UserCache.prototype, 'GetSystemUser').mockReturnValue(SYSTEM_USER);
133
+ resolver = new TestResolver();
134
+ resolver.Checker.CheckRecordValues.mockResolvedValue(CHECKED);
135
+ });
136
+
137
+ // ─── Authorization ───────────────────────────────────────────────────────────
138
+
139
+ /** The scope checks made, other than the full_access fast path, as [scope, resource]. */
140
+ const scopeChecks = () => mockAuthorize.mock.calls.filter(call => call[2] !== 'full_access').map(call => [call[2], call[3]]);
141
+
142
+ describe('CheckDuplicateEntry: authorization', () => {
143
+ it('answers NotAuthorized, without logging, for a user who cannot read the entity', async () => {
144
+ const result = await check('Payroll', '{"ID":"x"}');
145
+
146
+ expect(result.Status).toBe('NotAuthorized');
147
+ expect(result.ErrorMessage).toContain('does not have read permissions on Payroll');
148
+ expect(result.Candidates).toEqual([]);
149
+ expect(resolver.Checker.CheckRecordValues).not.toHaveBeenCalled();
150
+ expect(mockLogError).not.toHaveBeenCalled();
151
+ });
152
+
153
+ it('fails an unknown entity without running the check', async () => {
154
+ const result = await check('No Such Entity', '{}');
155
+
156
+ expect(result).toMatchObject({ Status: 'Failed', ErrorMessage: 'Entity not found in metadata' });
157
+ expect(resolver.Checker.CheckRecordValues).not.toHaveBeenCalled();
158
+ });
159
+
160
+ it('applies the view:run API-key scope for the entity, and a denial is a status', async () => {
161
+ mockAuthorize.mockResolvedValue({ Allowed: false, Reason: 'scope not granted' });
162
+
163
+ const result = await check('Accounts', '{"Name":"Acme"}', apiKeyPayload());
164
+
165
+ expect(scopeChecks()).toEqual([['view:run', 'Accounts']]);
166
+ expect(result.Status).toBe('NotAuthorized');
167
+ expect(result.ErrorMessage).toContain("requires the 'view:run' scope");
168
+ expect(resolver.Checker.CheckRecordValues).not.toHaveBeenCalled();
169
+ expect(mockLogError).not.toHaveBeenCalled();
170
+ });
171
+
172
+ it('also requires prompt:execute, so a read-only key cannot spend on model calls', async () => {
173
+ mockAuthorize.mockImplementation(async (_hash, _app, scopePath) =>
174
+ scopePath === 'view:run' ? { Allowed: true, Reason: '' } : { Allowed: false, Reason: 'scope not granted' }
175
+ );
176
+
177
+ const result = await check('Accounts', '{"Name":"Acme"}', apiKeyPayload());
178
+
179
+ expect(scopeChecks()).toEqual([['view:run', 'Accounts'], ['prompt:execute', '*']]);
180
+ expect(result.Status).toBe('NotAuthorized');
181
+ expect(result.ErrorMessage).toContain("requires the 'prompt:execute' scope");
182
+ expect(resolver.Checker.CheckRecordValues).not.toHaveBeenCalled();
183
+ });
184
+
185
+ it('runs the check for a key holding both scopes', async () => {
186
+ mockAuthorize.mockImplementation(async (_hash, _app, scopePath) =>
187
+ ({ Allowed: scopePath !== 'full_access', Reason: '' })
188
+ );
189
+
190
+ const result = await check('Accounts', '{"Name":"Acme"}', apiKeyPayload());
191
+
192
+ expect(scopeChecks()).toEqual([['view:run', 'Accounts'], ['prompt:execute', '*']]);
193
+ expect(result.Status).toBe('Checked');
194
+ });
195
+ });
196
+
197
+ // ─── The values ──────────────────────────────────────────────────────────────
198
+
199
+ describe('CheckDuplicateEntry: the values', () => {
200
+ it('returns an error status, not a throw, for values that are not JSON', async () => {
201
+ const result = await check('Accounts', '{ Name: ');
202
+
203
+ expect(result.Status).toBe('Failed');
204
+ expect(result.ErrorMessage).toMatch(/^valuesJSON is not valid JSON: /);
205
+ expect(resolver.Checker.CheckRecordValues).not.toHaveBeenCalled();
206
+ });
207
+
208
+ it('returns an error status for JSON that is not an object', async () => {
209
+ const result = await check('Accounts', '["Acme"]');
210
+
211
+ expect(result).toMatchObject({ Status: 'Failed', ErrorMessage: 'valuesJSON must be the JSON of an object of field values' });
212
+ });
213
+
214
+ it('ignores the fields the entity does not have, and keys the rest by the real field name', async () => {
215
+ await check('Accounts', JSON.stringify({ name: 'Acme', City: 'Boston', Revenue: 5, NotAField: 'x' }));
216
+
217
+ expect(resolver.Checker.CheckRecordValues).toHaveBeenCalledWith('Accounts', { Name: 'Acme', City: 'Boston' }, USER);
218
+ });
219
+
220
+ it('ignores primary keys, read-only fields and MJ system fields', async () => {
221
+ await check('Accounts', JSON.stringify({ ID: 'acct-7', Name: 'Acme', Owner: 'someone', __mj_CreatedAt: '2026-01-01' }));
222
+
223
+ expect(resolver.Checker.CheckRecordValues).toHaveBeenCalledWith('Accounts', { Name: 'Acme' }, USER);
224
+ });
225
+
226
+ it('accepts strings, numbers, booleans and null', async () => {
227
+ await check('Accounts', JSON.stringify({ Name: 'Acme', City: null, Revenue: 5, Active: true }));
228
+
229
+ expect(resolver.Checker.CheckRecordValues).toHaveBeenCalledWith('Accounts', { Name: 'Acme', City: null }, USER);
230
+ });
231
+
232
+ it.each([
233
+ ['an array', { Name: ['Acme', 'Corp'] }],
234
+ ['an object', { Name: { first: 'Acme' } }],
235
+ ])('refuses a value that is %s', async (_kind, values) => {
236
+ const result = await check('Accounts', JSON.stringify(values));
237
+
238
+ expect(result).toMatchObject({ Status: 'Failed', ErrorMessage: "valuesJSON field 'Name' must be a string, number, boolean or null" });
239
+ expect(resolver.Checker.CheckRecordValues).not.toHaveBeenCalled();
240
+ });
241
+
242
+ it('refuses a value of an unknown field that is not a scalar', async () => {
243
+ const result = await check('Accounts', JSON.stringify({ Name: 'Acme', Extra: [1, 2, 3] }));
244
+
245
+ expect(result.Status).toBe('Failed');
246
+ expect(resolver.Checker.CheckRecordValues).not.toHaveBeenCalled();
247
+ });
248
+
249
+ it('accepts valuesJSON up to DUPLICATE_ENTRY_CHECK_MAX_VALUES_JSON_LENGTH characters and refuses one more', async () => {
250
+ const padding = DUPLICATE_ENTRY_CHECK_MAX_VALUES_JSON_LENGTH - JSON.stringify({ Name: '' }).length;
251
+ const atLimit = JSON.stringify({ Name: 'x'.repeat(padding) });
252
+ const overLimit = JSON.stringify({ Name: 'x'.repeat(padding + 1) });
253
+ expect(atLimit).toHaveLength(DUPLICATE_ENTRY_CHECK_MAX_VALUES_JSON_LENGTH);
254
+
255
+ expect((await check('Accounts', atLimit)).Status).toBe('Checked');
256
+ const refused = await check('Accounts', overLimit);
257
+
258
+ expect(refused).toMatchObject({
259
+ Status: 'Failed',
260
+ ErrorMessage: `valuesJSON is ${DUPLICATE_ENTRY_CHECK_MAX_VALUES_JSON_LENGTH + 1} characters; the limit is ${DUPLICATE_ENTRY_CHECK_MAX_VALUES_JSON_LENGTH}`,
261
+ });
262
+ expect(resolver.Checker.CheckRecordValues).toHaveBeenCalledTimes(1);
263
+ });
264
+
265
+ it('keeps the limit to a few KB', () => {
266
+ expect(DUPLICATE_ENTRY_CHECK_MAX_VALUES_JSON_LENGTH).toBeLessThanOrEqual(32 * 1024);
267
+ });
268
+ });
269
+
270
+ // ─── The result ──────────────────────────────────────────────────────────────
271
+
272
+ describe('CheckDuplicateEntry: the result', () => {
273
+ it('returns the detector result', async () => {
274
+ const result = await check('Accounts', '{"Name":"Acme"}');
275
+
276
+ expect(result).toEqual({
277
+ Status: 'Checked',
278
+ ErrorMessage: undefined,
279
+ Candidates: [{ RecordID: 'acct-7', DisplayName: 'Acme Corp', VectorScore: 0.93, Probability: 0.81 }],
280
+ ElapsedMs: 212,
281
+ });
282
+ });
283
+
284
+ it('passes NotConfigured through', async () => {
285
+ resolver.Checker.CheckRecordValues.mockResolvedValue({ Status: 'NotConfigured', Candidates: [], ElapsedMs: 3 });
286
+
287
+ const result = await check('Accounts', '{"Name":"Acme"}');
288
+
289
+ expect(result).toMatchObject({ Status: 'NotConfigured', Candidates: [] });
290
+ });
291
+
292
+ it('returns Failed, not a throw, when the check throws, and logs it', async () => {
293
+ resolver.Checker.CheckRecordValues.mockRejectedValue(new Error('vector index unreachable'));
294
+
295
+ const result = await check('Accounts', '{"Name":"Acme"}');
296
+
297
+ expect(result).toMatchObject({ Status: 'Failed', ErrorMessage: 'vector index unreachable', Candidates: [] });
298
+ expect(mockLogError).toHaveBeenCalledTimes(1);
299
+ });
300
+ });
@@ -1,5 +1,5 @@
1
1
  import { describe, it, expect } from 'vitest';
2
- import { deriveSidecarPath, parsePeaksSidecar, MAX_PEAKS } from '../resolvers/peaksSidecar.js';
2
+ import { DeriveSidecarPath, ParsePeaksSidecar, MAX_PEAKS } from '../resolvers/peaksSidecar.js';
3
3
 
4
4
  /**
5
5
  * Tests for the pure `peaks.json` sidecar helpers that back FileResolver.CreateMediaAccessToken's
@@ -14,51 +14,51 @@ import { deriveSidecarPath, parsePeaksSidecar, MAX_PEAKS } from '../resolvers/pe
14
14
 
15
15
  describe('deriveSidecarPath', () => {
16
16
  it('replaces the final path segment with peaks.json (recording in a session folder)', () => {
17
- expect(deriveSidecarPath('realtime-recordings/sess-1/recording.wav')).toBe('realtime-recordings/sess-1/peaks.json');
17
+ expect(DeriveSidecarPath('realtime-recordings/sess-1/recording.wav')).toBe('realtime-recordings/sess-1/peaks.json');
18
18
  });
19
19
 
20
20
  it('uses a bare peaks.json when the key has no folder', () => {
21
- expect(deriveSidecarPath('recording.wav')).toBe('peaks.json');
21
+ expect(DeriveSidecarPath('recording.wav')).toBe('peaks.json');
22
22
  });
23
23
 
24
24
  it('returns null when there is no ProviderKey (cannot derive a folder)', () => {
25
- expect(deriveSidecarPath(null)).toBeNull();
26
- expect(deriveSidecarPath(undefined)).toBeNull();
27
- expect(deriveSidecarPath('')).toBeNull();
25
+ expect(DeriveSidecarPath(null)).toBeNull();
26
+ expect(DeriveSidecarPath(undefined)).toBeNull();
27
+ expect(DeriveSidecarPath('')).toBeNull();
28
28
  });
29
29
  });
30
30
 
31
31
  describe('parsePeaksSidecar', () => {
32
32
  it('returns sanitized peaks from a valid JSON array (clamped to 0..1)', () => {
33
33
  const bytes = Buffer.from(JSON.stringify([0, 0.5, 1, 1.7, -0.3]), 'utf8');
34
- expect(parsePeaksSidecar(bytes)).toEqual([0, 0.5, 1, 1, 0]);
34
+ expect(ParsePeaksSidecar(bytes)).toEqual([0, 0.5, 1, 1, 0]);
35
35
  });
36
36
 
37
37
  it('returns undefined for non-JSON garbage (never throws)', () => {
38
- expect(parsePeaksSidecar(Buffer.from('this is not json', 'utf8'))).toBeUndefined();
38
+ expect(ParsePeaksSidecar(Buffer.from('this is not json', 'utf8'))).toBeUndefined();
39
39
  });
40
40
 
41
41
  it('returns undefined when the JSON is not an array', () => {
42
- expect(parsePeaksSidecar(Buffer.from(JSON.stringify({ not: 'an array' }), 'utf8'))).toBeUndefined();
42
+ expect(ParsePeaksSidecar(Buffer.from(JSON.stringify({ not: 'an array' }), 'utf8'))).toBeUndefined();
43
43
  });
44
44
 
45
45
  it('returns undefined for an empty array', () => {
46
- expect(parsePeaksSidecar(Buffer.from('[]', 'utf8'))).toBeUndefined();
46
+ expect(ParsePeaksSidecar(Buffer.from('[]', 'utf8'))).toBeUndefined();
47
47
  });
48
48
 
49
49
  it('drops non-finite / non-number entries, keeping the finite numbers', () => {
50
50
  const bytes = Buffer.from(JSON.stringify([0.2, 'x', null, NaN, 0.8]), 'utf8');
51
51
  // NaN serializes to null in JSON; both 'x' and the nulls are dropped, leaving the two numbers.
52
- expect(parsePeaksSidecar(bytes)).toEqual([0.2, 0.8]);
52
+ expect(ParsePeaksSidecar(bytes)).toEqual([0.2, 0.8]);
53
53
  });
54
54
 
55
55
  it('returns undefined when nothing finite survives sanitization', () => {
56
- expect(parsePeaksSidecar(Buffer.from(JSON.stringify(['a', 'b', null]), 'utf8'))).toBeUndefined();
56
+ expect(ParsePeaksSidecar(Buffer.from(JSON.stringify(['a', 'b', null]), 'utf8'))).toBeUndefined();
57
57
  });
58
58
 
59
59
  it('caps the array length at MAX_PEAKS', () => {
60
60
  const huge = new Array(MAX_PEAKS + 500).fill(0.5);
61
- const result = parsePeaksSidecar(Buffer.from(JSON.stringify(huge), 'utf8'));
61
+ const result = ParsePeaksSidecar(Buffer.from(JSON.stringify(huge), 'utf8'));
62
62
  expect(result).toHaveLength(MAX_PEAKS);
63
63
  });
64
64
  });
@@ -22,24 +22,24 @@ import type { ApplyResult, ListDelta } from '@memberjunction/lists-base';
22
22
  import {
23
23
  ApplyDeltaInput,
24
24
  ListSourceInput,
25
- fromCoreApplyResult,
26
- fromCoreDelta,
27
- fromCoreWarning,
28
- rebuildDeltaFromInput,
29
- toCoreSource,
25
+ FromCoreApplyResult,
26
+ FromCoreDelta,
27
+ FromCoreWarning,
28
+ RebuildDeltaFromInput,
29
+ ToCoreSource,
30
30
  } from '../resolvers/ListOperationsResolver.js';
31
31
 
32
32
  describe('ListOperationsResolver — boundary converters', () => {
33
33
  describe('toCoreSource', () => {
34
34
  it('maps a list-kind input to a core ListSource', () => {
35
35
  const input = Object.assign(new ListSourceInput(), { Kind: 'list', ListID: 'list-1' });
36
- const result = toCoreSource(input);
36
+ const result = ToCoreSource(input);
37
37
  expect(result).toEqual({ kind: 'list', listId: 'list-1' });
38
38
  });
39
39
 
40
40
  it('maps a view-kind input to a core ListSource', () => {
41
41
  const input = Object.assign(new ListSourceInput(), { Kind: 'view', ViewID: 'view-1' });
42
- expect(toCoreSource(input)).toEqual({ kind: 'view', viewId: 'view-1' });
42
+ expect(ToCoreSource(input)).toEqual({ kind: 'view', viewId: 'view-1' });
43
43
  });
44
44
 
45
45
  it('maps an adhoc-kind input to a core ListSource', () => {
@@ -48,7 +48,7 @@ describe('ListOperationsResolver — boundary converters', () => {
48
48
  EntityName: 'Contacts',
49
49
  ExtraFilter: "Status='Active'",
50
50
  });
51
- expect(toCoreSource(input)).toEqual({
51
+ expect(ToCoreSource(input)).toEqual({
52
52
  kind: 'adhoc',
53
53
  entityName: 'Contacts',
54
54
  extraFilter: "Status='Active'",
@@ -57,22 +57,22 @@ describe('ListOperationsResolver — boundary converters', () => {
57
57
 
58
58
  it('throws when list-kind input has no ListID', () => {
59
59
  const input = Object.assign(new ListSourceInput(), { Kind: 'list' });
60
- expect(() => toCoreSource(input)).toThrow(/ListID is required/);
60
+ expect(() => ToCoreSource(input)).toThrow(/ListID is required/);
61
61
  });
62
62
 
63
63
  it('throws when view-kind input has no ViewID', () => {
64
64
  const input = Object.assign(new ListSourceInput(), { Kind: 'view' });
65
- expect(() => toCoreSource(input)).toThrow(/ViewID is required/);
65
+ expect(() => ToCoreSource(input)).toThrow(/ViewID is required/);
66
66
  });
67
67
 
68
68
  it('throws when adhoc-kind input lacks EntityName or ExtraFilter', () => {
69
69
  const input = Object.assign(new ListSourceInput(), { Kind: 'adhoc', EntityName: 'X' });
70
- expect(() => toCoreSource(input)).toThrow(/EntityName and ExtraFilter/);
70
+ expect(() => ToCoreSource(input)).toThrow(/EntityName and ExtraFilter/);
71
71
  });
72
72
 
73
73
  it('throws on an unknown discriminator', () => {
74
74
  const input = Object.assign(new ListSourceInput(), { Kind: 'mystery' as never });
75
- expect(() => toCoreSource(input)).toThrow(/Unknown ListSourceInput\.Kind/);
75
+ expect(() => ToCoreSource(input)).toThrow(/Unknown ListSourceInput\.Kind/);
76
76
  });
77
77
  });
78
78
 
@@ -90,7 +90,7 @@ describe('ListOperationsResolver — boundary converters', () => {
90
90
  ],
91
91
  DeltaToken: 'abc.def',
92
92
  };
93
- const output = fromCoreDelta(delta);
93
+ const output = FromCoreDelta(delta);
94
94
  expect(output).toMatchObject({
95
95
  TargetListId: 'list-1',
96
96
  EntityName: 'Contacts',
@@ -111,7 +111,7 @@ describe('ListOperationsResolver — boundary converters', () => {
111
111
 
112
112
  describe('fromCoreWarning', () => {
113
113
  it('leaves DetailsJSON undefined when no details supplied', () => {
114
- const output = fromCoreWarning({ Code: 'EMPTY_SOURCE', Message: 'No records' });
114
+ const output = FromCoreWarning({ Code: 'EMPTY_SOURCE', Message: 'No records' });
115
115
  expect(output.DetailsJSON).toBeUndefined();
116
116
  });
117
117
  });
@@ -126,7 +126,7 @@ describe('ListOperationsResolver — boundary converters', () => {
126
126
  CreatedListId: 'list-1',
127
127
  Counts: { Added: 5, Removed: 2, Failed: 0 },
128
128
  };
129
- const output = fromCoreApplyResult(result);
129
+ const output = FromCoreApplyResult(result);
130
130
  expect(output).toMatchObject({
131
131
  Success: true,
132
132
  ResultCode: 'SUCCESS',
@@ -145,7 +145,7 @@ describe('ListOperationsResolver — boundary converters', () => {
145
145
  Message: 'partial',
146
146
  Errors: ['failed record a'],
147
147
  };
148
- expect(fromCoreApplyResult(result).Errors).toEqual(['failed record a']);
148
+ expect(FromCoreApplyResult(result).Errors).toEqual(['failed record a']);
149
149
  });
150
150
  });
151
151
 
@@ -165,7 +165,7 @@ describe('ListOperationsResolver — boundary converters', () => {
165
165
  DeltaToken: 'tok',
166
166
  ConfirmDrops: true,
167
167
  });
168
- const out = rebuildDeltaFromInput(input);
168
+ const out = RebuildDeltaFromInput(input);
169
169
  expect(out).toMatchObject({
170
170
  TargetListId: 'list-1',
171
171
  EntityName: 'Contacts',
@@ -1,5 +1,5 @@
1
1
  import { describe, it, expect } from 'vitest';
2
- import { parseRangeHeaderLoose, parseRange } from '../rest/mediaRange.js';
2
+ import { ParseRangeHeaderLoose, ParseRange } from '../rest/mediaRange.js';
3
3
 
4
4
  /**
5
5
  * Tests for the pure HTTP-Range parsing helpers behind the authenticated `/media/:fileId`
@@ -16,34 +16,34 @@ import { parseRangeHeaderLoose, parseRange } from '../rest/mediaRange.js';
16
16
 
17
17
  describe('parseRangeHeaderLoose (streaming path — no known total)', () => {
18
18
  it('parses a closed range bytes=start-end into inclusive offsets', () => {
19
- expect(parseRangeHeaderLoose('bytes=0-499')).toEqual({ start: 0, end: 499 });
20
- expect(parseRangeHeaderLoose('bytes=200-1023')).toEqual({ start: 200, end: 1023 });
19
+ expect(ParseRangeHeaderLoose('bytes=0-499')).toEqual({ start: 0, end: 499 });
20
+ expect(ParseRangeHeaderLoose('bytes=200-1023')).toEqual({ start: 200, end: 1023 });
21
21
  });
22
22
 
23
23
  it('leaves end undefined for an open-ended range bytes=start- (stream to EOF)', () => {
24
- expect(parseRangeHeaderLoose('bytes=500-')).toEqual({ start: 500 });
25
- expect(parseRangeHeaderLoose('bytes=0-')).toEqual({ start: 0 });
24
+ expect(ParseRangeHeaderLoose('bytes=500-')).toEqual({ start: 500 });
25
+ expect(ParseRangeHeaderLoose('bytes=0-')).toEqual({ start: 0 });
26
26
  });
27
27
 
28
28
  it('tolerates surrounding whitespace', () => {
29
- expect(parseRangeHeaderLoose(' bytes=10-20 ')).toEqual({ start: 10, end: 20 });
29
+ expect(ParseRangeHeaderLoose(' bytes=10-20 ')).toEqual({ start: 10, end: 20 });
30
30
  });
31
31
 
32
32
  it('returns undefined when end < start (nonsensical range)', () => {
33
- expect(parseRangeHeaderLoose('bytes=500-100')).toBeUndefined();
33
+ expect(ParseRangeHeaderLoose('bytes=500-100')).toBeUndefined();
34
34
  });
35
35
 
36
36
  it('returns undefined for malformed / multi-range / suffix-only headers', () => {
37
- expect(parseRangeHeaderLoose('bytes=abc-def')).toBeUndefined();
38
- expect(parseRangeHeaderLoose('bytes=-500')).toBeUndefined(); // suffix range — left to a full read
39
- expect(parseRangeHeaderLoose('bytes=0-100,200-300')).toBeUndefined(); // multi-range
40
- expect(parseRangeHeaderLoose('items=0-100')).toBeUndefined(); // wrong unit
41
- expect(parseRangeHeaderLoose('bytes=')).toBeUndefined();
42
- expect(parseRangeHeaderLoose('')).toBeUndefined();
37
+ expect(ParseRangeHeaderLoose('bytes=abc-def')).toBeUndefined();
38
+ expect(ParseRangeHeaderLoose('bytes=-500')).toBeUndefined(); // suffix range — left to a full read
39
+ expect(ParseRangeHeaderLoose('bytes=0-100,200-300')).toBeUndefined(); // multi-range
40
+ expect(ParseRangeHeaderLoose('items=0-100')).toBeUndefined(); // wrong unit
41
+ expect(ParseRangeHeaderLoose('bytes=')).toBeUndefined();
42
+ expect(ParseRangeHeaderLoose('')).toBeUndefined();
43
43
  });
44
44
 
45
45
  it('accepts a zero-length point range bytes=N-N', () => {
46
- expect(parseRangeHeaderLoose('bytes=42-42')).toEqual({ start: 42, end: 42 });
46
+ expect(ParseRangeHeaderLoose('bytes=42-42')).toEqual({ start: 42, end: 42 });
47
47
  });
48
48
  });
49
49
 
@@ -51,41 +51,41 @@ describe('parseRange (buffer path — known total)', () => {
51
51
  const TOTAL = 1000;
52
52
 
53
53
  it('parses a closed range within bounds', () => {
54
- expect(parseRange('bytes=0-499', TOTAL)).toEqual({ start: 0, end: 499 });
54
+ expect(ParseRange('bytes=0-499', TOTAL)).toEqual({ start: 0, end: 499 });
55
55
  });
56
56
 
57
57
  it('clamps end to the last byte when the requested end exceeds total', () => {
58
58
  // bytes=500-99999 against a 1000-byte file → end clamps to 999.
59
- expect(parseRange('bytes=500-99999', TOTAL)).toEqual({ start: 500, end: 999 });
59
+ expect(ParseRange('bytes=500-99999', TOTAL)).toEqual({ start: 500, end: 999 });
60
60
  });
61
61
 
62
62
  it('resolves an open-ended range to the last byte', () => {
63
- expect(parseRange('bytes=200-', TOTAL)).toEqual({ start: 200, end: 999 });
63
+ expect(ParseRange('bytes=200-', TOTAL)).toEqual({ start: 200, end: 999 });
64
64
  });
65
65
 
66
66
  it('returns undefined when start is at or past EOF (unsatisfiable → 416)', () => {
67
- expect(parseRange('bytes=1000-1100', TOTAL)).toBeUndefined(); // start === total
68
- expect(parseRange('bytes=2000-', TOTAL)).toBeUndefined(); // start > total
67
+ expect(ParseRange('bytes=1000-1100', TOTAL)).toBeUndefined(); // start === total
68
+ expect(ParseRange('bytes=2000-', TOTAL)).toBeUndefined(); // start > total
69
69
  });
70
70
 
71
71
  it('returns undefined when end < start after parsing', () => {
72
- expect(parseRange('bytes=600-100', TOTAL)).toBeUndefined();
72
+ expect(ParseRange('bytes=600-100', TOTAL)).toBeUndefined();
73
73
  });
74
74
 
75
75
  it('returns undefined for malformed / multi-range / suffix-only headers', () => {
76
- expect(parseRange('bytes=abc-', TOTAL)).toBeUndefined();
77
- expect(parseRange('bytes=-200', TOTAL)).toBeUndefined();
78
- expect(parseRange('bytes=0-100,200-300', TOTAL)).toBeUndefined();
79
- expect(parseRange('items=0-100', TOTAL)).toBeUndefined();
80
- expect(parseRange('', TOTAL)).toBeUndefined();
76
+ expect(ParseRange('bytes=abc-', TOTAL)).toBeUndefined();
77
+ expect(ParseRange('bytes=-200', TOTAL)).toBeUndefined();
78
+ expect(ParseRange('bytes=0-100,200-300', TOTAL)).toBeUndefined();
79
+ expect(ParseRange('items=0-100', TOTAL)).toBeUndefined();
80
+ expect(ParseRange('', TOTAL)).toBeUndefined();
81
81
  });
82
82
 
83
83
  it('handles the very first byte and the very last byte exactly', () => {
84
- expect(parseRange('bytes=0-0', TOTAL)).toEqual({ start: 0, end: 0 });
85
- expect(parseRange('bytes=999-999', TOTAL)).toEqual({ start: 999, end: 999 });
84
+ expect(ParseRange('bytes=0-0', TOTAL)).toEqual({ start: 0, end: 0 });
85
+ expect(ParseRange('bytes=999-999', TOTAL)).toEqual({ start: 999, end: 999 });
86
86
  });
87
87
 
88
88
  it('tolerates surrounding whitespace', () => {
89
- expect(parseRange(' bytes=10-20 ', TOTAL)).toEqual({ start: 10, end: 20 });
89
+ expect(ParseRange(' bytes=10-20 ', TOTAL)).toEqual({ start: 10, end: 20 });
90
90
  });
91
91
  });
@@ -1,6 +1,6 @@
1
1
  import 'reflect-metadata';
2
2
  import { describe, it, expect } from 'vitest';
3
- import { NoLog, hasNoLogParameter, getNoLogFields } from '../logging/NoLog.js';
3
+ import { NoLog, HasNoLogParameter, GetNoLogFields } from '../logging/NoLog.js';
4
4
 
5
5
  describe('NoLog decorator', () => {
6
6
  it('marks a resolver method parameter (3-arg call) and is readable via hasNoLogParameter', () => {
@@ -11,9 +11,9 @@ describe('NoLog decorator', () => {
11
11
  }
12
12
  NoLog(MyResolver.prototype, 'doThing', 1);
13
13
 
14
- expect(hasNoLogParameter(MyResolver, 'doThing', 1)).toBe(true);
15
- expect(hasNoLogParameter(MyResolver, 'doThing', 0)).toBe(false);
16
- expect(hasNoLogParameter(MyResolver, 'unknownMethod', 0)).toBe(false);
14
+ expect(HasNoLogParameter(MyResolver, 'doThing', 1)).toBe(true);
15
+ expect(HasNoLogParameter(MyResolver, 'doThing', 0)).toBe(false);
16
+ expect(HasNoLogParameter(MyResolver, 'unknownMethod', 0)).toBe(false);
17
17
  });
18
18
 
19
19
  it('marks a field on an input class (2-arg call) and is readable via getNoLogFields', () => {
@@ -24,7 +24,7 @@ describe('NoLog decorator', () => {
24
24
  }
25
25
  NoLog(MyInput.prototype, 'Token');
26
26
 
27
- const fields = getNoLogFields(MyInput);
27
+ const fields = GetNoLogFields(MyInput);
28
28
  expect(fields.has('Token')).toBe(true);
29
29
  expect(fields.has('Queries')).toBe(false);
30
30
  expect(fields.size).toBe(1);
@@ -41,8 +41,8 @@ describe('NoLog decorator', () => {
41
41
  B: string = '';
42
42
  }
43
43
 
44
- expect(hasNoLogParameter(UndecoratedResolver, 'doNothing', 0)).toBe(false);
45
- expect(getNoLogFields(UndecoratedInput).size).toBe(0);
44
+ expect(HasNoLogParameter(UndecoratedResolver, 'doNothing', 0)).toBe(false);
45
+ expect(GetNoLogFields(UndecoratedInput).size).toBe(0);
46
46
  });
47
47
 
48
48
  it('supports multiple parameter marks on the same method', () => {
@@ -54,9 +54,9 @@ describe('NoLog decorator', () => {
54
54
  NoLog(TwoSecrets.prototype, 'handle', 0);
55
55
  NoLog(TwoSecrets.prototype, 'handle', 2);
56
56
 
57
- expect(hasNoLogParameter(TwoSecrets, 'handle', 0)).toBe(true);
58
- expect(hasNoLogParameter(TwoSecrets, 'handle', 1)).toBe(false);
59
- expect(hasNoLogParameter(TwoSecrets, 'handle', 2)).toBe(true);
57
+ expect(HasNoLogParameter(TwoSecrets, 'handle', 0)).toBe(true);
58
+ expect(HasNoLogParameter(TwoSecrets, 'handle', 1)).toBe(false);
59
+ expect(HasNoLogParameter(TwoSecrets, 'handle', 2)).toBe(true);
60
60
  });
61
61
 
62
62
  it('supports multiple field marks on the same input class', () => {
@@ -68,7 +68,7 @@ describe('NoLog decorator', () => {
68
68
  NoLog(TwoFieldSecrets.prototype, 'A');
69
69
  NoLog(TwoFieldSecrets.prototype, 'C');
70
70
 
71
- const fields = getNoLogFields(TwoFieldSecrets);
71
+ const fields = GetNoLogFields(TwoFieldSecrets);
72
72
  expect(fields.has('A')).toBe(true);
73
73
  expect(fields.has('B')).toBe(false);
74
74
  expect(fields.has('C')).toBe(true);