@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
@@ -15,70 +15,70 @@ import { GetReadWriteProvider } from '../util.js';
15
15
  @ObjectType()
16
16
  export class AIPromptRunResult {
17
17
  @Field()
18
- success: boolean;
18
+ success: boolean; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name — renaming it breaks every client query
19
19
 
20
20
  @Field({ nullable: true })
21
- output?: string;
21
+ output?: string; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name — renaming it breaks every client query
22
22
 
23
23
  @Field({ nullable: true })
24
- parsedResult?: string;
24
+ parsedResult?: string; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name — renaming it breaks every client query
25
25
 
26
26
  @Field({ nullable: true })
27
- error?: string;
27
+ error?: string; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name — renaming it breaks every client query
28
28
 
29
29
  @Field({ nullable: true })
30
- executionTimeMs?: number;
30
+ executionTimeMs?: number; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name — renaming it breaks every client query
31
31
 
32
32
  @Field({ nullable: true })
33
- tokensUsed?: number;
33
+ tokensUsed?: number; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name — renaming it breaks every client query
34
34
 
35
35
  @Field({ nullable: true })
36
- promptRunId?: string;
36
+ promptRunId?: string; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name — renaming it breaks every client query
37
37
 
38
38
  @Field({ nullable: true })
39
- rawResult?: string;
39
+ rawResult?: string; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name — renaming it breaks every client query
40
40
 
41
41
  @Field({ nullable: true })
42
- validationResult?: string;
42
+ validationResult?: string; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name — renaming it breaks every client query
43
43
 
44
44
  @Field({ nullable: true })
45
- chatResult?: string;
45
+ chatResult?: string; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name — renaming it breaks every client query
46
46
  }
47
47
 
48
48
  @ObjectType()
49
49
  export class SimplePromptResult {
50
50
  @Field()
51
- success: boolean;
51
+ success: boolean; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name — renaming it breaks every client query
52
52
 
53
53
  @Field({ nullable: true })
54
- result?: string;
54
+ result?: string; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name — renaming it breaks every client query
55
55
 
56
56
  @Field({ nullable: true })
57
- resultObject?: string; // JSON stringified object
57
+ resultObject?: string; // JSON stringified object — case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name — renaming it breaks every client query
58
58
 
59
59
  @Field()
60
- modelName: string;
60
+ modelName: string; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name — renaming it breaks every client query
61
61
 
62
62
  @Field({ nullable: true })
63
- error?: string;
63
+ error?: string; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name — renaming it breaks every client query
64
64
 
65
65
  @Field({ nullable: true })
66
- executionTimeMs?: number;
66
+ executionTimeMs?: number; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name — renaming it breaks every client query
67
67
  }
68
68
 
69
69
  @ObjectType()
70
70
  export class EmbedTextResult {
71
71
  @Field(() => [[Number]])
72
- embeddings: number[][];
72
+ embeddings: number[][]; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name — renaming it breaks every client query
73
73
 
74
74
  @Field()
75
- modelName: string;
75
+ modelName: string; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name — renaming it breaks every client query
76
76
 
77
77
  @Field(() => Int)
78
- vectorDimensions: number;
78
+ vectorDimensions: number; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name — renaming it breaks every client query
79
79
 
80
80
  @Field({ nullable: true })
81
- error?: string;
81
+ error?: string; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name — renaming it breaks every client query
82
82
  }
83
83
 
84
84
  /**
@@ -418,7 +418,7 @@ export class RunAIPromptResolver extends ResolverBase {
418
418
  }
419
419
 
420
420
  /** The `AI Model Types.Name` that means "a chat LLM", compared lowercased. */
421
- private static readonly SimplePromptLLMTypeName = 'llm';
421
+ private static readonly simplePromptLLMTypeName = 'llm';
422
422
 
423
423
  /**
424
424
  * Selects a runnable model + vendor for simple prompt execution.
@@ -551,7 +551,7 @@ export class RunAIPromptResolver extends ResolverBase {
551
551
  */
552
552
  private isLLMModel(model: MJAIModelEntityExtended): boolean {
553
553
  const typeName = AIEngine.Instance.ModelTypesByID.get(model.AIModelTypeID)?.Name ?? model.AIModelType;
554
- return typeName?.trim().toLowerCase() === RunAIPromptResolver.SimplePromptLLMTypeName;
554
+ return typeName?.trim().toLowerCase() === RunAIPromptResolver.simplePromptLLMTypeName;
555
555
  }
556
556
 
557
557
  /**
@@ -0,0 +1,435 @@
1
+ import { Resolver, Mutation, Arg, Ctx, ObjectType, Field, Int } from 'type-graphql';
2
+ import { AppContext, UserPayload } from '../types.js';
3
+ import { LogError, LogStatus, UserInfo } from '@memberjunction/core';
4
+ import { UUIDsEqual } from '@memberjunction/global';
5
+ import { MJAIPromptEntityExtended } from '@memberjunction/ai-core-plus';
6
+ import { AIDecisionRunner, AIDecisionParams, AIDecisionRunResult, ParseDecisionQuestions } from '@memberjunction/ai-prompts';
7
+ import { DecisionQuestion } from '@memberjunction/ai';
8
+ import { AIEngine } from '@memberjunction/aiengine';
9
+ import { ResolverBase } from '../generic/ResolverBase.js';
10
+ import { IsScopeLimitedPrincipal } from '../auth/scopeLimitedPrincipal.js';
11
+
12
+ /**
13
+ * The result of the `RunDecision` mutation. Every failure, an authorization denial included, comes
14
+ * back as `success: false` with an `errorMessage`: the mutation never throws to the client.
15
+ */
16
+ @ObjectType()
17
+ export class DecisionRunResult {
18
+ @Field()
19
+ success: boolean; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name, camelCase like AIPromptRunResult's — clients query it by this name
20
+
21
+ @Field({ nullable: true })
22
+ errorMessage?: string; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name, camelCase like AIPromptRunResult's — clients query it by this name
23
+
24
+ /** The `DecisionAnswer` map by question key, as JSON. Set only on success. */
25
+ @Field({ nullable: true })
26
+ answersJSON?: string; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name, camelCase like AIPromptRunResult's — clients query it by this name
27
+
28
+ @Field({ nullable: true })
29
+ promptRunId?: string; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name, camelCase like AIPromptRunResult's — clients query it by this name
30
+
31
+ /** The model that answered, after any failover, or the one selected when the call failed. */
32
+ @Field({ nullable: true })
33
+ modelName?: string; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name, camelCase like AIPromptRunResult's — clients query it by this name
34
+
35
+ /**
36
+ * The exact model behind `modelName`, as its driver reports it (`DecisionResult.ResolvedModel`):
37
+ * the vendor's dated model for a vendor decision model, the chat model for LLM Decision. A
38
+ * consumer that calibrates per model needs it: a calibration holds only for the model it was
39
+ * fitted on. Absent when the driver reports none.
40
+ */
41
+ @Field({ nullable: true })
42
+ resolvedModel?: string; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name, camelCase like AIPromptRunResult's — clients query it by this name
43
+
44
+ @Field({ nullable: true })
45
+ executionTimeMs?: number; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name, camelCase like AIPromptRunResult's — clients query it by this name
46
+ }
47
+
48
+ /** The arguments of one `RunDecision` call. */
49
+ interface DecisionRequest {
50
+ State: string;
51
+ Questions: string;
52
+ PromptID?: string;
53
+ PromptName?: string;
54
+ TimeoutMS?: number;
55
+ }
56
+
57
+ /** The prompt a request names: by ID, or by name. */
58
+ interface DecisionPromptReference {
59
+ By: 'ID' | 'Name';
60
+ Value: string;
61
+ }
62
+
63
+ /** The validated state and questions of one request, and the model-call timeout to use. */
64
+ interface DecisionInputs {
65
+ State: string | Record<string, unknown>;
66
+ Questions: Record<string, DecisionQuestion>;
67
+ TimeoutMS: number;
68
+ }
69
+
70
+ /**
71
+ * Runs typed decisions (Likelihood, Choice, Score) for clients in one round trip, through
72
+ * `AIDecisionRunner`. It is the direct path for latency-sensitive browser callers: the `Run Decision`
73
+ * action does the same work with action-execution overhead on top.
74
+ *
75
+ * The request path adds no entity load: the prompt comes from `AIEngine`'s cache.
76
+ */
77
+ @Resolver()
78
+ export class RunDecisionResolver extends ResolverBase {
79
+ /** The prompt used when the caller names none, as for the `Run Decision` action. */
80
+ public static readonly DEFAULT_PROMPT_NAME = 'Default Decision';
81
+
82
+ // Server-side bounds on a request. They are cheap backstops, checked before the model is
83
+ // called. Each decision model's own declared limits are the runner's to check.
84
+
85
+ /**
86
+ * The most characters the state may have: about 32,000 tokens at four characters a token, which
87
+ * is Jev's declared input limit. Checked before the state is parsed.
88
+ */
89
+ public static readonly MAX_STATE_CHARACTERS = 128_000;
90
+
91
+ /** The most characters the questions' JSON may have. Checked before it is parsed. */
92
+ public static readonly MAX_QUESTIONS_CHARACTERS = 128_000;
93
+
94
+ /** The most questions one request may carry. */
95
+ public static readonly MAX_QUESTIONS = 32;
96
+
97
+ /**
98
+ * The most options a Choice question, or levels a Score question, may list: Jev's declared
99
+ * `MaxChoiceOptions`.
100
+ */
101
+ public static readonly MAX_OPTIONS_PER_QUESTION = 255;
102
+
103
+ /** The model-call timeout used when the caller sends none, or one that is not positive. */
104
+ public static readonly DEFAULT_TIMEOUT_MS = 30_000;
105
+
106
+ /** The longest model-call timeout a caller may ask for. A longer one is cut to it. */
107
+ public static readonly MAX_TIMEOUT_MS = 120_000;
108
+
109
+ /**
110
+ * Answers typed questions about a state with a Decision-typed prompt.
111
+ *
112
+ * Authorization is `RunAIPrompt`'s: the API-key `prompt:execute` scope check, before any other
113
+ * work (a session without an API key skips it). As `RunAIPrompt` and `RunAIAgent` do, it checks
114
+ * the ID of the prompt that will run, whether the caller named it by ID or by name, so a rule on
115
+ * a prompt's ID holds on both. A denial is returned as `success: false`, not thrown.
116
+ *
117
+ * Scope-limited sessions (magic-link guests and resource-scoped sessions) are refused. The
118
+ * prompt is read from `AIEngine`'s cache, around entity permissions and row-level security, so
119
+ * the confinement those sessions rely on would not apply here. For the same reason, a prompt
120
+ * that cannot run gets one neutral message, whatever the reason, that names nothing the caller
121
+ * did not send.
122
+ *
123
+ * @param state The state the questions are about: text, or the JSON text of an object.
124
+ * @param questions The `DecisionQuestion` map by question key, as JSON: the shape `Run Decision` accepts.
125
+ * @param promptId The decision prompt's ID. Takes precedence over `promptName`.
126
+ * @param promptName The decision prompt's name, matched case-insensitively. Defaults to `Default Decision`.
127
+ * @param timeoutMS Bounds each model call, as the runner's `timeoutMS`. Unset or not positive, it is
128
+ * `DEFAULT_TIMEOUT_MS`; above `MAX_TIMEOUT_MS`, it is cut to it. A call is never unbounded.
129
+ */
130
+ @Mutation(() => DecisionRunResult)
131
+ async RunDecision(
132
+ @Arg('state') state: string,
133
+ @Arg('questions') questions: string,
134
+ @Ctx() { userPayload }: AppContext,
135
+ @Arg('promptId', { nullable: true }) promptId?: string,
136
+ @Arg('promptName', { nullable: true }) promptName?: string,
137
+ @Arg('timeoutMS', () => Int, { nullable: true }) timeoutMS?: number
138
+ ): Promise<DecisionRunResult> {
139
+ const startTime = Date.now();
140
+ try {
141
+ const request: DecisionRequest = { State: state, Questions: questions, PromptID: promptId, PromptName: promptName, TimeoutMS: timeoutMS };
142
+ return await this.runDecision(request, userPayload, startTime);
143
+ } catch (error) {
144
+ const message = error instanceof Error ? error.message : String(error);
145
+ LogError(`RunDecision failed: ${message}`, undefined, error);
146
+ return this.failure(message || 'Unknown error occurred', startTime);
147
+ }
148
+ }
149
+
150
+ /** Authorizes, validates, resolves the prompt, and runs the decision. Throws only on unexpected errors. */
151
+ private async runDecision(request: DecisionRequest, userPayload: UserPayload, startTime: number): Promise<DecisionRunResult> {
152
+ const reference = this.promptReference(request);
153
+ const authorized = await this.authorizePrompt(reference, userPayload);
154
+
155
+ const currentUser = this.GetUserFromPayload(userPayload);
156
+ if (!currentUser) {
157
+ return this.failure('Unable to determine current user', startTime);
158
+ }
159
+ // A scope-limited session is confined only by entity permissions and RLS, and the prompt comes
160
+ // from the cache, around both. There is no narrower read to fall back to, so it is refused.
161
+ if (IsScopeLimitedPrincipal(currentUser)) {
162
+ return this.failure('RunDecision is not permitted for scope-limited sessions', startTime);
163
+ }
164
+ const inputs = this.validateInputs(request);
165
+ if ('Error' in inputs) {
166
+ return this.failure(inputs.Error, startTime);
167
+ }
168
+ const runner = new AIDecisionRunner();
169
+ const prompt = await this.resolvePrompt(authorized, reference, runner, currentUser, userPayload);
170
+ if (typeof prompt === 'string') {
171
+ return this.failure(prompt, startTime);
172
+ }
173
+ const result = await runner.ExecuteDecision(this.buildDecisionParams(prompt, inputs, currentUser));
174
+ return this.mapRunResult(result, prompt, startTime);
175
+ }
176
+
177
+ /** The prompt the request names: its ID when given, otherwise its name, otherwise the default. */
178
+ private promptReference(request: DecisionRequest): DecisionPromptReference {
179
+ const id = request.PromptID?.trim();
180
+ if (id) {
181
+ return { By: 'ID', Value: id };
182
+ }
183
+ const name = request.PromptName?.trim();
184
+ return { By: 'Name', Value: name || RunDecisionResolver.DEFAULT_PROMPT_NAME };
185
+ }
186
+
187
+ /**
188
+ * The API-key `prompt:execute` scope check, made before any other work. The prompt is looked up
189
+ * in `AIEngine`'s cache as it stands, with nothing loaded or logged, and the check is made against
190
+ * its ID. A prompt that is not there is checked against the value the caller sent, so a denied
191
+ * caller learns nothing about which prompts exist: that it was not found is reported only after
192
+ * the check passes.
193
+ *
194
+ * @returns The prompt found, which was authorized by its ID, or undefined when none was found.
195
+ */
196
+ private async authorizePrompt(
197
+ reference: DecisionPromptReference,
198
+ userPayload: UserPayload
199
+ ): Promise<MJAIPromptEntityExtended | undefined> {
200
+ const cached = this.findCachedPrompt(reference);
201
+ await this.CheckAPIKeyScopeAuthorization('prompt:execute', cached?.ID ?? reference.Value, userPayload);
202
+ return cached;
203
+ }
204
+
205
+ /**
206
+ * Looks the prompt up in the cache without loading it. A cache that cannot be read counts as not
207
+ * found here, so the error surfaces only after authorization, when the lookup is made again.
208
+ */
209
+ private findCachedPrompt(reference: DecisionPromptReference): MJAIPromptEntityExtended | undefined {
210
+ try {
211
+ return this.findPrompt(reference);
212
+ } catch {
213
+ return undefined;
214
+ }
215
+ }
216
+
217
+ /**
218
+ * Validates the state and the questions and bounds their size, or returns the first problem
219
+ * found. Settles the model-call timeout too.
220
+ */
221
+ private validateInputs(request: DecisionRequest): DecisionInputs | { Error: string } {
222
+ const tooLong = this.checkInputLengths(request);
223
+ if (tooLong) {
224
+ return { Error: tooLong };
225
+ }
226
+ const state = this.parseState(request.State);
227
+ if ('Error' in state) {
228
+ return state;
229
+ }
230
+ const questions = ParseDecisionQuestions(request.Questions);
231
+ if (!questions.Valid) {
232
+ return { Error: questions.Message };
233
+ }
234
+ const tooMany = this.checkQuestionCounts(questions.Questions);
235
+ if (tooMany) {
236
+ return { Error: tooMany };
237
+ }
238
+ return { State: state.State, Questions: questions.Questions, TimeoutMS: this.effectiveTimeoutMS(request.TimeoutMS) };
239
+ }
240
+
241
+ /** Refuses a state or questions text over its character limit, before either is parsed. */
242
+ private checkInputLengths(request: DecisionRequest): string | undefined {
243
+ const stateLength = typeof request.State === 'string' ? request.State.length : 0;
244
+ if (stateLength > RunDecisionResolver.MAX_STATE_CHARACTERS) {
245
+ return `State has ${stateLength} characters, over the limit of ${RunDecisionResolver.MAX_STATE_CHARACTERS}`;
246
+ }
247
+ const questionsLength = typeof request.Questions === 'string' ? request.Questions.length : 0;
248
+ if (questionsLength > RunDecisionResolver.MAX_QUESTIONS_CHARACTERS) {
249
+ return `Questions JSON has ${questionsLength} characters, over the limit of ${RunDecisionResolver.MAX_QUESTIONS_CHARACTERS}`;
250
+ }
251
+ return undefined;
252
+ }
253
+
254
+ /** Refuses more questions than one request may carry, or more options or levels than one question may list. */
255
+ private checkQuestionCounts(questions: Record<string, DecisionQuestion>): string | undefined {
256
+ const questionCount = Object.keys(questions).length;
257
+ if (questionCount > RunDecisionResolver.MAX_QUESTIONS) {
258
+ return `${questionCount} questions exceed the limit of ${RunDecisionResolver.MAX_QUESTIONS} per request`;
259
+ }
260
+ const maxOptions = RunDecisionResolver.MAX_OPTIONS_PER_QUESTION;
261
+ for (const [key, question] of Object.entries(questions)) {
262
+ if (question.Kind === 'Choice' && question.Options.length > maxOptions) {
263
+ return `Choice '${key}' has ${question.Options.length} options, over the limit of ${maxOptions}`;
264
+ }
265
+ if (question.Kind === 'Score' && question.Levels.length > maxOptions) {
266
+ return `Score '${key}' has ${question.Levels.length} levels, over the limit of ${maxOptions}`;
267
+ }
268
+ }
269
+ return undefined;
270
+ }
271
+
272
+ /**
273
+ * The caller's timeout, cut to `MAX_TIMEOUT_MS`, or `DEFAULT_TIMEOUT_MS` when it sent none or one
274
+ * that is not positive.
275
+ */
276
+ private effectiveTimeoutMS(requested: number | undefined): number {
277
+ if (requested == null || !(requested > 0)) {
278
+ return RunDecisionResolver.DEFAULT_TIMEOUT_MS;
279
+ }
280
+ return Math.min(requested, RunDecisionResolver.MAX_TIMEOUT_MS);
281
+ }
282
+
283
+ /**
284
+ * Reads the state: the object, when the text is the JSON of a non-empty object, otherwise the text
285
+ * itself. Empty text and an empty object are refused, as the `Run Decision` action refuses them.
286
+ */
287
+ private parseState(state: string): { State: string | Record<string, unknown> } | { Error: string } {
288
+ const trimmed = typeof state === 'string' ? state.trim() : '';
289
+ if (trimmed.length === 0) {
290
+ return { Error: 'State is required and cannot be empty' };
291
+ }
292
+ const parsed = this.parseJSONObject(trimmed);
293
+ if (!parsed) {
294
+ return { State: trimmed };
295
+ }
296
+ return Object.keys(parsed).length > 0 ? { State: parsed } : { Error: 'State object cannot be empty' };
297
+ }
298
+
299
+ /** The text parsed as a JSON object, or undefined when it is not the JSON of an object. */
300
+ private parseJSONObject(text: string): Record<string, unknown> | undefined {
301
+ if (!text.startsWith('{')) {
302
+ return undefined;
303
+ }
304
+ try {
305
+ const parsed: unknown = JSON.parse(text);
306
+ return this.isPlainObject(parsed) ? parsed : undefined;
307
+ } catch {
308
+ return undefined;
309
+ }
310
+ }
311
+
312
+ private isPlainObject(value: unknown): value is Record<string, unknown> {
313
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
314
+ }
315
+
316
+ /**
317
+ * The prompt to run, checked that it can run a decision: that it is Decision-typed and Active.
318
+ * Returns the reason when it cannot.
319
+ *
320
+ * The prompt authorized before is the one used. When there was none, the engine is loaded (a
321
+ * no-op once it is) and the prompt looked up again: one that appears only then is authorized by
322
+ * its ID too, so a request that reaches a cold cache cannot get past a rule on that ID by name.
323
+ */
324
+ private async resolvePrompt(
325
+ authorized: MJAIPromptEntityExtended | undefined,
326
+ reference: DecisionPromptReference,
327
+ runner: AIDecisionRunner,
328
+ contextUser: UserInfo,
329
+ userPayload: UserPayload
330
+ ): Promise<MJAIPromptEntityExtended | string> {
331
+ await AIEngine.Instance.Config(false, contextUser);
332
+ const prompt = authorized ?? (await this.findAndAuthorizeLoadedPrompt(reference, userPayload));
333
+ if (!prompt || !this.canRunDecision(prompt, runner)) {
334
+ return this.unavailablePromptMessage(reference);
335
+ }
336
+ return prompt;
337
+ }
338
+
339
+ /**
340
+ * Whether the prompt can run a decision: Decision-typed and Active. When it cannot, the reason,
341
+ * which names the prompt and its status, goes to the server log only.
342
+ */
343
+ private canRunDecision(prompt: MJAIPromptEntityExtended, runner: AIDecisionRunner): boolean {
344
+ if (!this.isDecisionPrompt(prompt, runner)) {
345
+ LogStatus(`RunDecision: AI Prompt '${prompt.Name}' (${prompt.ID}) is not a Decision prompt: its AI model type must be '${runner.RequiredModelType}'`);
346
+ return false;
347
+ }
348
+ if (prompt.Status !== 'Active') {
349
+ LogStatus(`RunDecision: AI Prompt '${prompt.Name}' (${prompt.ID}) is not active (Status: ${prompt.Status})`);
350
+ return false;
351
+ }
352
+ return true;
353
+ }
354
+
355
+ /**
356
+ * The one message for a prompt that cannot run, whether it is missing, not Decision-typed or not
357
+ * Active. It repeats only what the caller sent: this path reads the cache around entity
358
+ * permissions, so it must not tell a caller the name or status of a prompt it may not read.
359
+ */
360
+ private unavailablePromptMessage(reference: DecisionPromptReference): string {
361
+ const named = reference.By === 'ID' ? `with ID ${reference.Value}` : `'${reference.Value}'`;
362
+ return `AI Prompt ${named} was not found or is not an active Decision prompt`;
363
+ }
364
+
365
+ /** Looks the prompt up in the loaded cache, and authorizes it by its ID when it is found. */
366
+ private async findAndAuthorizeLoadedPrompt(
367
+ reference: DecisionPromptReference,
368
+ userPayload: UserPayload
369
+ ): Promise<MJAIPromptEntityExtended | undefined> {
370
+ const prompt = this.findPrompt(reference);
371
+ if (prompt) {
372
+ await this.CheckAPIKeyScopeAuthorization('prompt:execute', prompt.ID, userPayload);
373
+ }
374
+ return prompt;
375
+ }
376
+
377
+ /** Looks the prompt up by ID, or by name case-insensitively, as the `Run Decision` action does. */
378
+ private findPrompt(reference: DecisionPromptReference): MJAIPromptEntityExtended | undefined {
379
+ const prompts = AIEngine.Instance.Prompts;
380
+ if (reference.By === 'ID') {
381
+ return prompts.find(p => UUIDsEqual(p.ID, reference.Value));
382
+ }
383
+ const target = reference.Value.toLowerCase();
384
+ return prompts.find(p => p.Name?.trim().toLowerCase() === target);
385
+ }
386
+
387
+ /**
388
+ * Whether the prompt's AI model type is the one `AIDecisionRunner` requires. A prompt with no model
389
+ * type is refused too: the runner would accept it, but nothing marks it as a decision prompt.
390
+ */
391
+ private isDecisionPrompt(prompt: MJAIPromptEntityExtended, runner: AIDecisionRunner): boolean {
392
+ if (!prompt.AIModelTypeID) {
393
+ return false;
394
+ }
395
+ const required = runner.RequiredModelType.trim().toLowerCase();
396
+ const decisionType = AIEngine.Instance.ModelTypes.find(mt => mt.Name?.trim().toLowerCase() === required);
397
+ return !!decisionType && UUIDsEqual(prompt.AIModelTypeID, decisionType.ID);
398
+ }
399
+
400
+ private buildDecisionParams(prompt: MJAIPromptEntityExtended, inputs: DecisionInputs, contextUser: UserInfo): AIDecisionParams {
401
+ const params = new AIDecisionParams();
402
+ params.prompt = prompt;
403
+ params.contextUser = contextUser;
404
+ params.State = inputs.State;
405
+ params.Questions = inputs.Questions;
406
+ params.timeoutMS = inputs.TimeoutMS;
407
+ return params;
408
+ }
409
+
410
+ /** Maps the runner's result. The answers are sent only on success, so a caller never acts on partial ones. */
411
+ private mapRunResult(result: AIDecisionRunResult, prompt: MJAIPromptEntityExtended, startTime: number): DecisionRunResult {
412
+ const mapped: DecisionRunResult = {
413
+ success: result.success,
414
+ promptRunId: result.promptRun?.ID,
415
+ modelName: result.modelInfo?.modelName,
416
+ resolvedModel: result.DecisionResult?.ResolvedModel,
417
+ executionTimeMs: Date.now() - startTime,
418
+ };
419
+ if (result.success) {
420
+ mapped.answersJSON = JSON.stringify(result.Answers ?? {});
421
+ } else {
422
+ mapped.errorMessage = result.errorMessage || 'Decision execution failed';
423
+ LogError(`RunDecision failed for prompt '${prompt.Name}': ${mapped.errorMessage}`);
424
+ }
425
+ return mapped;
426
+ }
427
+
428
+ private failure(errorMessage: string, startTime: number): DecisionRunResult {
429
+ return {
430
+ success: false,
431
+ errorMessage,
432
+ executionTimeMs: Date.now() - startTime,
433
+ };
434
+ }
435
+ }
@@ -9,16 +9,16 @@ import { GetReadWriteProvider } from '../util.js';
9
9
  @ObjectType()
10
10
  export class TemplateRunResult {
11
11
  @Field()
12
- success: boolean;
12
+ success: boolean; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name — renaming it breaks every client query
13
13
 
14
14
  @Field({ nullable: true })
15
- output?: string;
15
+ output?: string; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name — renaming it breaks every client query
16
16
 
17
17
  @Field({ nullable: true })
18
- error?: string;
18
+ error?: string; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name — renaming it breaks every client query
19
19
 
20
20
  @Field({ nullable: true })
21
- executionTimeMs?: number;
21
+ executionTimeMs?: number; // case-violation-ok-legacy-back-compat: the property name is the GraphQL schema field name — renaming it breaks every client query
22
22
  }
23
23
 
24
24
  /**