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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (560) hide show
  1. package/README.md +47 -1
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/agentSessions/SessionJanitor.d.ts +91 -30
  4. package/dist/agentSessions/SessionJanitor.d.ts.map +1 -1
  5. package/dist/agentSessions/SessionJanitor.js +311 -81
  6. package/dist/agentSessions/SessionJanitor.js.map +1 -1
  7. package/dist/agentSessions/SessionManager.d.ts +17 -3
  8. package/dist/agentSessions/SessionManager.d.ts.map +1 -1
  9. package/dist/agentSessions/SessionManager.js +44 -10
  10. package/dist/agentSessions/SessionManager.js.map +1 -1
  11. package/dist/apiRoot.d.ts +32 -0
  12. package/dist/apiRoot.d.ts.map +1 -0
  13. package/dist/apiRoot.js +67 -0
  14. package/dist/apiRoot.js.map +1 -0
  15. package/dist/auth/AuthProviderCatalogRouter.d.ts.map +1 -1
  16. package/dist/auth/AuthProviderCatalogRouter.js +27 -0
  17. package/dist/auth/AuthProviderCatalogRouter.js.map +1 -1
  18. package/dist/auth/LoginScreenEngine.d.ts +22 -0
  19. package/dist/auth/LoginScreenEngine.d.ts.map +1 -0
  20. package/dist/auth/LoginScreenEngine.js +57 -0
  21. package/dist/auth/LoginScreenEngine.js.map +1 -0
  22. package/dist/auth/index.d.ts +1 -0
  23. package/dist/auth/index.d.ts.map +1 -1
  24. package/dist/auth/index.js +52 -10
  25. package/dist/auth/index.js.map +1 -1
  26. package/dist/auth/initializeProviders.d.ts +10 -0
  27. package/dist/auth/initializeProviders.d.ts.map +1 -1
  28. package/dist/auth/initializeProviders.js +37 -1
  29. package/dist/auth/initializeProviders.js.map +1 -1
  30. package/dist/auth/localDevAuth.d.ts +79 -0
  31. package/dist/auth/localDevAuth.d.ts.map +1 -0
  32. package/dist/auth/localDevAuth.js +439 -0
  33. package/dist/auth/localDevAuth.js.map +1 -0
  34. package/dist/auth/magicLink/MagicLinkKeys.d.ts +2 -2
  35. package/dist/auth/magicLink/MagicLinkKeys.d.ts.map +1 -1
  36. package/dist/auth/magicLink/MagicLinkKeys.js +1 -1
  37. package/dist/auth/magicLink/MagicLinkKeys.js.map +1 -1
  38. package/dist/auth/magicLink/MagicLinkRouter.d.ts.map +1 -1
  39. package/dist/auth/magicLink/MagicLinkRouter.js +3 -2
  40. package/dist/auth/magicLink/MagicLinkRouter.js.map +1 -1
  41. package/dist/auth/magicLink/types.d.ts +12 -0
  42. package/dist/auth/magicLink/types.d.ts.map +1 -1
  43. package/dist/auth/sessionUserClone.d.ts +1 -1
  44. package/dist/auth/sessionUserClone.d.ts.map +1 -1
  45. package/dist/auth/sessionUserClone.js +3 -2
  46. package/dist/auth/sessionUserClone.js.map +1 -1
  47. package/dist/broadcast/BaseCacheInvalidationBroadcastProvider.d.ts +292 -0
  48. package/dist/broadcast/BaseCacheInvalidationBroadcastProvider.d.ts.map +1 -0
  49. package/dist/broadcast/BaseCacheInvalidationBroadcastProvider.js +442 -0
  50. package/dist/broadcast/BaseCacheInvalidationBroadcastProvider.js.map +1 -0
  51. package/dist/broadcast/index.d.ts +6 -0
  52. package/dist/broadcast/index.d.ts.map +1 -0
  53. package/dist/broadcast/index.js +6 -0
  54. package/dist/broadcast/index.js.map +1 -0
  55. package/dist/broadcast/providers/AWSIoTCoreBroadcastProvider.d.ts +43 -0
  56. package/dist/broadcast/providers/AWSIoTCoreBroadcastProvider.d.ts.map +1 -0
  57. package/dist/broadcast/providers/AWSIoTCoreBroadcastProvider.js +144 -0
  58. package/dist/broadcast/providers/AWSIoTCoreBroadcastProvider.js.map +1 -0
  59. package/dist/broadcast/providers/AzureWebPubSubBroadcastProvider.d.ts +46 -0
  60. package/dist/broadcast/providers/AzureWebPubSubBroadcastProvider.d.ts.map +1 -0
  61. package/dist/broadcast/providers/AzureWebPubSubBroadcastProvider.js +149 -0
  62. package/dist/broadcast/providers/AzureWebPubSubBroadcastProvider.js.map +1 -0
  63. package/dist/broadcast/providers/GCPPubSubBroadcastProvider.d.ts +49 -0
  64. package/dist/broadcast/providers/GCPPubSubBroadcastProvider.d.ts.map +1 -0
  65. package/dist/broadcast/providers/GCPPubSubBroadcastProvider.js +131 -0
  66. package/dist/broadcast/providers/GCPPubSubBroadcastProvider.js.map +1 -0
  67. package/dist/broadcast/providers/SequencedRoleBucketBroadcastProvider.d.ts +24 -0
  68. package/dist/broadcast/providers/SequencedRoleBucketBroadcastProvider.d.ts.map +1 -0
  69. package/dist/broadcast/providers/SequencedRoleBucketBroadcastProvider.js +51 -0
  70. package/dist/broadcast/providers/SequencedRoleBucketBroadcastProvider.js.map +1 -0
  71. package/dist/cache.d.ts +3 -2
  72. package/dist/cache.d.ts.map +1 -1
  73. package/dist/cache.js.map +1 -1
  74. package/dist/config.d.ts +632 -22
  75. package/dist/config.d.ts.map +1 -1
  76. package/dist/config.js +104 -4
  77. package/dist/config.js.map +1 -1
  78. package/dist/context.d.ts +3 -1
  79. package/dist/context.d.ts.map +1 -1
  80. package/dist/context.js +29 -8
  81. package/dist/context.js.map +1 -1
  82. package/dist/coreRoutes.d.ts +29 -0
  83. package/dist/coreRoutes.d.ts.map +1 -0
  84. package/dist/coreRoutes.js +156 -0
  85. package/dist/coreRoutes.js.map +1 -0
  86. package/dist/generated/graphql-schemas/__mj.d.ts +1016 -29
  87. package/dist/generated/graphql-schemas/__mj.d.ts.map +1 -1
  88. package/dist/generated/graphql-schemas/__mj.js +5125 -434
  89. package/dist/generated/graphql-schemas/__mj.js.map +1 -1
  90. package/dist/generic/CacheInvalidationResolver.d.ts +85 -30
  91. package/dist/generic/CacheInvalidationResolver.d.ts.map +1 -1
  92. package/dist/generic/CacheInvalidationResolver.js +175 -60
  93. package/dist/generic/CacheInvalidationResolver.js.map +1 -1
  94. package/dist/generic/OrphanedConversationDetailReconciler.d.ts.map +1 -1
  95. package/dist/generic/OrphanedConversationDetailReconciler.js +2 -0
  96. package/dist/generic/OrphanedConversationDetailReconciler.js.map +1 -1
  97. package/dist/generic/PubSubManager.d.ts +10 -0
  98. package/dist/generic/PubSubManager.d.ts.map +1 -1
  99. package/dist/generic/PubSubManager.js +44 -1
  100. package/dist/generic/PubSubManager.js.map +1 -1
  101. package/dist/generic/PushStatusResolver.d.ts +39 -6
  102. package/dist/generic/PushStatusResolver.d.ts.map +1 -1
  103. package/dist/generic/PushStatusResolver.js +94 -12
  104. package/dist/generic/PushStatusResolver.js.map +1 -1
  105. package/dist/generic/ResolverBase.d.ts +168 -69
  106. package/dist/generic/ResolverBase.d.ts.map +1 -1
  107. package/dist/generic/ResolverBase.js +464 -405
  108. package/dist/generic/ResolverBase.js.map +1 -1
  109. package/dist/generic/RunViewResolver.d.ts +11 -3
  110. package/dist/generic/RunViewResolver.d.ts.map +1 -1
  111. package/dist/generic/RunViewResolver.js +91 -13
  112. package/dist/generic/RunViewResolver.js.map +1 -1
  113. package/dist/generic/actionOutputFieldSecurity.d.ts +26 -0
  114. package/dist/generic/actionOutputFieldSecurity.d.ts.map +1 -0
  115. package/dist/generic/actionOutputFieldSecurity.js +47 -0
  116. package/dist/generic/actionOutputFieldSecurity.js.map +1 -0
  117. package/dist/generic/fieldSecurityTransport.d.ts +30 -0
  118. package/dist/generic/fieldSecurityTransport.d.ts.map +1 -0
  119. package/dist/generic/fieldSecurityTransport.js +30 -0
  120. package/dist/generic/fieldSecurityTransport.js.map +1 -0
  121. package/dist/globalCors.d.ts +33 -0
  122. package/dist/globalCors.d.ts.map +1 -0
  123. package/dist/globalCors.js +58 -0
  124. package/dist/globalCors.js.map +1 -0
  125. package/dist/index.d.ts +14 -0
  126. package/dist/index.d.ts.map +1 -1
  127. package/dist/index.js +230 -222
  128. package/dist/index.js.map +1 -1
  129. package/dist/integration/CustomColumnPromoter.d.ts.map +1 -1
  130. package/dist/integration/CustomColumnPromoter.js +6 -1
  131. package/dist/integration/CustomColumnPromoter.js.map +1 -1
  132. package/dist/logging/variablesLoggingMiddleware.d.ts +12 -0
  133. package/dist/logging/variablesLoggingMiddleware.d.ts.map +1 -1
  134. package/dist/logging/variablesLoggingMiddleware.js +50 -1
  135. package/dist/logging/variablesLoggingMiddleware.js.map +1 -1
  136. package/dist/multiTenancy/index.d.ts.map +1 -1
  137. package/dist/multiTenancy/index.js +22 -2
  138. package/dist/multiTenancy/index.js.map +1 -1
  139. package/dist/realtimeSessions/RealtimeSessionVerificationService.d.ts.map +1 -1
  140. package/dist/realtimeSessions/RealtimeSessionVerificationService.js +2 -1
  141. package/dist/realtimeSessions/RealtimeSessionVerificationService.js.map +1 -1
  142. package/dist/realtimeSessions/RealtimeVerifyRouter.d.ts.map +1 -1
  143. package/dist/realtimeSessions/RealtimeVerifyRouter.js +2 -1
  144. package/dist/realtimeSessions/RealtimeVerifyRouter.js.map +1 -1
  145. package/dist/realtimeSessions/RecordingAssemblyScheduler.d.ts +100 -0
  146. package/dist/realtimeSessions/RecordingAssemblyScheduler.d.ts.map +1 -0
  147. package/dist/realtimeSessions/RecordingAssemblyScheduler.js +173 -0
  148. package/dist/realtimeSessions/RecordingAssemblyScheduler.js.map +1 -0
  149. package/dist/realtimeSessions/SessionVerificationPortsBase.d.ts.map +1 -1
  150. package/dist/realtimeSessions/SessionVerificationPortsBase.js +1 -0
  151. package/dist/realtimeSessions/SessionVerificationPortsBase.js.map +1 -1
  152. package/dist/realtimeSessions/index.d.ts +2 -0
  153. package/dist/realtimeSessions/index.d.ts.map +1 -1
  154. package/dist/realtimeSessions/index.js +2 -0
  155. package/dist/realtimeSessions/index.js.map +1 -1
  156. package/dist/realtimeSessions/ownedRealtimeSession.d.ts +32 -0
  157. package/dist/realtimeSessions/ownedRealtimeSession.d.ts.map +1 -0
  158. package/dist/realtimeSessions/ownedRealtimeSession.js +56 -0
  159. package/dist/realtimeSessions/ownedRealtimeSession.js.map +1 -0
  160. package/dist/realtimeSessions/sessionAccess.d.ts +91 -8
  161. package/dist/realtimeSessions/sessionAccess.d.ts.map +1 -1
  162. package/dist/realtimeSessions/sessionAccess.js +127 -20
  163. package/dist/realtimeSessions/sessionAccess.js.map +1 -1
  164. package/dist/realtimeSessions/sessionConfigStamps.js +1 -1
  165. package/dist/realtimeSessions/sessionConfigStamps.js.map +1 -1
  166. package/dist/realtimeSessions/subscriptionAuthorization.d.ts.map +1 -1
  167. package/dist/realtimeSessions/subscriptionAuthorization.js +5 -2
  168. package/dist/realtimeSessions/subscriptionAuthorization.js.map +1 -1
  169. package/dist/realtimeSessions/verificationWorkflow.d.ts +2 -0
  170. package/dist/realtimeSessions/verificationWorkflow.d.ts.map +1 -1
  171. package/dist/realtimeSessions/verificationWorkflow.js +1 -1
  172. package/dist/realtimeSessions/verificationWorkflow.js.map +1 -1
  173. package/dist/realtimeWidget/WidgetRouter.d.ts.map +1 -1
  174. package/dist/realtimeWidget/WidgetRouter.js +19 -3
  175. package/dist/realtimeWidget/WidgetRouter.js.map +1 -1
  176. package/dist/realtimeWidget/WidgetSessionService.d.ts +67 -7
  177. package/dist/realtimeWidget/WidgetSessionService.d.ts.map +1 -1
  178. package/dist/realtimeWidget/WidgetSessionService.js +201 -19
  179. package/dist/realtimeWidget/WidgetSessionService.js.map +1 -1
  180. package/dist/realtimeWidget/host-identity.d.ts +1 -1
  181. package/dist/realtimeWidget/host-identity.js +1 -1
  182. package/dist/realtimeWidget/widgetCore.d.ts +20 -1
  183. package/dist/realtimeWidget/widgetCore.d.ts.map +1 -1
  184. package/dist/realtimeWidget/widgetCore.js +17 -1
  185. package/dist/realtimeWidget/widgetCore.js.map +1 -1
  186. package/dist/realtimeWidget/widgetGuestElevation.d.ts +1 -1
  187. package/dist/realtimeWidget/widgetGuestElevation.d.ts.map +1 -1
  188. package/dist/realtimeWidget/widgetGuestElevation.js +2 -1
  189. package/dist/realtimeWidget/widgetGuestElevation.js.map +1 -1
  190. package/dist/resolvers/ActionResolver.d.ts +19 -1
  191. package/dist/resolvers/ActionResolver.d.ts.map +1 -1
  192. package/dist/resolvers/ActionResolver.js +63 -12
  193. package/dist/resolvers/ActionResolver.js.map +1 -1
  194. package/dist/resolvers/AdhocQueryResolver.d.ts.map +1 -1
  195. package/dist/resolvers/AdhocQueryResolver.js +1 -0
  196. package/dist/resolvers/AdhocQueryResolver.js.map +1 -1
  197. package/dist/resolvers/AgentRunStatusPublisher.d.ts +18 -4
  198. package/dist/resolvers/AgentRunStatusPublisher.d.ts.map +1 -1
  199. package/dist/resolvers/AgentRunStatusPublisher.js +32 -8
  200. package/dist/resolvers/AgentRunStatusPublisher.js.map +1 -1
  201. package/dist/resolvers/AgentSessionResolver.d.ts +10 -4
  202. package/dist/resolvers/AgentSessionResolver.d.ts.map +1 -1
  203. package/dist/resolvers/AgentSessionResolver.js +40 -17
  204. package/dist/resolvers/AgentSessionResolver.js.map +1 -1
  205. package/dist/resolvers/ArtifactFileResolver.d.ts +5 -1
  206. package/dist/resolvers/ArtifactFileResolver.d.ts.map +1 -1
  207. package/dist/resolvers/ArtifactFileResolver.js +9 -7
  208. package/dist/resolvers/ArtifactFileResolver.js.map +1 -1
  209. package/dist/resolvers/ConversationRunEventsResolver.d.ts +8 -4
  210. package/dist/resolvers/ConversationRunEventsResolver.d.ts.map +1 -1
  211. package/dist/resolvers/ConversationRunEventsResolver.js +6 -6
  212. package/dist/resolvers/ConversationRunEventsResolver.js.map +1 -1
  213. package/dist/resolvers/DatasetResolver.d.ts +24 -3
  214. package/dist/resolvers/DatasetResolver.d.ts.map +1 -1
  215. package/dist/resolvers/DatasetResolver.js +57 -8
  216. package/dist/resolvers/DatasetResolver.js.map +1 -1
  217. package/dist/resolvers/EntityCommunicationsResolver.d.ts +13 -1
  218. package/dist/resolvers/EntityCommunicationsResolver.d.ts.map +1 -1
  219. package/dist/resolvers/EntityCommunicationsResolver.js +50 -14
  220. package/dist/resolvers/EntityCommunicationsResolver.js.map +1 -1
  221. package/dist/resolvers/EntityRecordNameResolver.d.ts +2 -1
  222. package/dist/resolvers/EntityRecordNameResolver.d.ts.map +1 -1
  223. package/dist/resolvers/EntityRecordNameResolver.js +3 -2
  224. package/dist/resolvers/EntityRecordNameResolver.js.map +1 -1
  225. package/dist/resolvers/FetchEntityVectorsResolver.d.ts +46 -3
  226. package/dist/resolvers/FetchEntityVectorsResolver.d.ts.map +1 -1
  227. package/dist/resolvers/FetchEntityVectorsResolver.js +211 -50
  228. package/dist/resolvers/FetchEntityVectorsResolver.js.map +1 -1
  229. package/dist/resolvers/FileCategoryResolver.d.ts.map +1 -1
  230. package/dist/resolvers/FileCategoryResolver.js +1 -0
  231. package/dist/resolvers/FileCategoryResolver.js.map +1 -1
  232. package/dist/resolvers/FileResolver.d.ts +87 -11
  233. package/dist/resolvers/FileResolver.d.ts.map +1 -1
  234. package/dist/resolvers/FileResolver.js +292 -105
  235. package/dist/resolvers/FileResolver.js.map +1 -1
  236. package/dist/resolvers/GetDataContextDataResolver.d.ts +33 -7
  237. package/dist/resolvers/GetDataContextDataResolver.d.ts.map +1 -1
  238. package/dist/resolvers/GetDataContextDataResolver.js +117 -38
  239. package/dist/resolvers/GetDataContextDataResolver.js.map +1 -1
  240. package/dist/resolvers/GetDataResolver.d.ts.map +1 -1
  241. package/dist/resolvers/GetDataResolver.js +6 -3
  242. package/dist/resolvers/GetDataResolver.js.map +1 -1
  243. package/dist/resolvers/IntegrationDiscoveryResolver.d.ts.map +1 -1
  244. package/dist/resolvers/IntegrationDiscoveryResolver.js +49 -9
  245. package/dist/resolvers/IntegrationDiscoveryResolver.js.map +1 -1
  246. package/dist/resolvers/MergeRecordsResolver.d.ts +8 -1
  247. package/dist/resolvers/MergeRecordsResolver.d.ts.map +1 -1
  248. package/dist/resolvers/MergeRecordsResolver.js +31 -3
  249. package/dist/resolvers/MergeRecordsResolver.js.map +1 -1
  250. package/dist/resolvers/PipelineProgressResolver.d.ts +6 -0
  251. package/dist/resolvers/PipelineProgressResolver.d.ts.map +1 -1
  252. package/dist/resolvers/PipelineProgressResolver.js +5 -3
  253. package/dist/resolvers/PipelineProgressResolver.js.map +1 -1
  254. package/dist/resolvers/QueryResolver.d.ts +2 -0
  255. package/dist/resolvers/QueryResolver.d.ts.map +1 -1
  256. package/dist/resolvers/QueryResolver.js +33 -6
  257. package/dist/resolvers/QueryResolver.js.map +1 -1
  258. package/dist/resolvers/QuerySystemUserResolver.d.ts +2 -0
  259. package/dist/resolvers/QuerySystemUserResolver.d.ts.map +1 -1
  260. package/dist/resolvers/QuerySystemUserResolver.js +15 -6
  261. package/dist/resolvers/QuerySystemUserResolver.js.map +1 -1
  262. package/dist/resolvers/RSUResolver.d.ts.map +1 -1
  263. package/dist/resolvers/RSUResolver.js +12 -0
  264. package/dist/resolvers/RSUResolver.js.map +1 -1
  265. package/dist/resolvers/RealtimeClientSessionResolver.d.ts +18 -10
  266. package/dist/resolvers/RealtimeClientSessionResolver.d.ts.map +1 -1
  267. package/dist/resolvers/RealtimeClientSessionResolver.js +92 -54
  268. package/dist/resolvers/RealtimeClientSessionResolver.js.map +1 -1
  269. package/dist/resolvers/RemoteBrowserActionResolver.d.ts.map +1 -1
  270. package/dist/resolvers/RemoteBrowserActionResolver.js +11 -9
  271. package/dist/resolvers/RemoteBrowserActionResolver.js.map +1 -1
  272. package/dist/resolvers/RunAIAgentResolver.d.ts +56 -8
  273. package/dist/resolvers/RunAIAgentResolver.d.ts.map +1 -1
  274. package/dist/resolvers/RunAIAgentResolver.js +241 -67
  275. package/dist/resolvers/RunAIAgentResolver.js.map +1 -1
  276. package/dist/resolvers/RunTemplateResolver.d.ts.map +1 -1
  277. package/dist/resolvers/RunTemplateResolver.js +4 -4
  278. package/dist/resolvers/RunTemplateResolver.js.map +1 -1
  279. package/dist/resolvers/RunTestResolver.d.ts.map +1 -1
  280. package/dist/resolvers/RunTestResolver.js +3 -1
  281. package/dist/resolvers/RunTestResolver.js.map +1 -1
  282. package/dist/resolvers/SearchKnowledgeStreamResolver.d.ts +12 -1
  283. package/dist/resolvers/SearchKnowledgeStreamResolver.d.ts.map +1 -1
  284. package/dist/resolvers/SearchKnowledgeStreamResolver.js +15 -2
  285. package/dist/resolvers/SearchKnowledgeStreamResolver.js.map +1 -1
  286. package/dist/resolvers/SqlLoggingConfigResolver.d.ts.map +1 -1
  287. package/dist/resolvers/SqlLoggingConfigResolver.js +2 -3
  288. package/dist/resolvers/SqlLoggingConfigResolver.js.map +1 -1
  289. package/dist/resolvers/SyncDataResolver.d.ts.map +1 -1
  290. package/dist/resolvers/SyncDataResolver.js +4 -0
  291. package/dist/resolvers/SyncDataResolver.js.map +1 -1
  292. package/dist/resolvers/TaskGraphFrameResolver.d.ts +2 -1
  293. package/dist/resolvers/TaskGraphFrameResolver.d.ts.map +1 -1
  294. package/dist/resolvers/TaskGraphFrameResolver.js +28 -1
  295. package/dist/resolvers/TaskGraphFrameResolver.js.map +1 -1
  296. package/dist/resolvers/TestQuerySQLResolver.d.ts +24 -0
  297. package/dist/resolvers/TestQuerySQLResolver.d.ts.map +1 -1
  298. package/dist/resolvers/TestQuerySQLResolver.js +66 -13
  299. package/dist/resolvers/TestQuerySQLResolver.js.map +1 -1
  300. package/dist/resolvers/TransactionGroupResolver.d.ts +34 -2
  301. package/dist/resolvers/TransactionGroupResolver.d.ts.map +1 -1
  302. package/dist/resolvers/TransactionGroupResolver.js +150 -27
  303. package/dist/resolvers/TransactionGroupResolver.js.map +1 -1
  304. package/dist/resolvers/UserViewResolver.d.ts +1 -1
  305. package/dist/resolvers/UserViewResolver.d.ts.map +1 -1
  306. package/dist/resolvers/UserViewResolver.js +2 -1
  307. package/dist/resolvers/UserViewResolver.js.map +1 -1
  308. package/dist/resolvers/agent-run-data-guard.d.ts +31 -0
  309. package/dist/resolvers/agent-run-data-guard.d.ts.map +1 -0
  310. package/dist/resolvers/agent-run-data-guard.js +72 -0
  311. package/dist/resolvers/agent-run-data-guard.js.map +1 -0
  312. package/dist/rest/EntityCRUDHandler.d.ts +6 -0
  313. package/dist/rest/EntityCRUDHandler.d.ts.map +1 -1
  314. package/dist/rest/EntityCRUDHandler.js +19 -5
  315. package/dist/rest/EntityCRUDHandler.js.map +1 -1
  316. package/dist/rest/RESTEndpointHandler.d.ts.map +1 -1
  317. package/dist/rest/RESTEndpointHandler.js +8 -5
  318. package/dist/rest/RESTEndpointHandler.js.map +1 -1
  319. package/dist/rest/RealtimeRecordingHandler.d.ts +49 -0
  320. package/dist/rest/RealtimeRecordingHandler.d.ts.map +1 -0
  321. package/dist/rest/RealtimeRecordingHandler.js +383 -0
  322. package/dist/rest/RealtimeRecordingHandler.js.map +1 -0
  323. package/dist/rest/ViewOperationsHandler.d.ts +9 -1
  324. package/dist/rest/ViewOperationsHandler.d.ts.map +1 -1
  325. package/dist/rest/ViewOperationsHandler.js +43 -17
  326. package/dist/rest/ViewOperationsHandler.js.map +1 -1
  327. package/dist/rest/setupRESTEndpoints.d.ts +6 -0
  328. package/dist/rest/setupRESTEndpoints.d.ts.map +1 -1
  329. package/dist/rest/setupRESTEndpoints.js +6 -0
  330. package/dist/rest/setupRESTEndpoints.js.map +1 -1
  331. package/dist/serverExtensionReservedRoots.d.ts +12 -10
  332. package/dist/serverExtensionReservedRoots.d.ts.map +1 -1
  333. package/dist/serverExtensionReservedRoots.js +14 -17
  334. package/dist/serverExtensionReservedRoots.js.map +1 -1
  335. package/dist/serverRoleConfigUnits.d.ts +29 -0
  336. package/dist/serverRoleConfigUnits.d.ts.map +1 -0
  337. package/dist/serverRoleConfigUnits.js +33 -0
  338. package/dist/serverRoleConfigUnits.js.map +1 -0
  339. package/dist/services/MJStorageBlobStore.d.ts +8 -1
  340. package/dist/services/MJStorageBlobStore.d.ts.map +1 -1
  341. package/dist/services/MJStorageBlobStore.js +25 -19
  342. package/dist/services/MJStorageBlobStore.js.map +1 -1
  343. package/dist/services/StartTaskGraphDispatcher.js +2 -2
  344. package/dist/services/StartTaskGraphDispatcher.js.map +1 -1
  345. package/dist/services/TaskGraphActionRunner.d.ts +5 -3
  346. package/dist/services/TaskGraphActionRunner.d.ts.map +1 -1
  347. package/dist/services/TaskGraphActionRunner.js +27 -5
  348. package/dist/services/TaskGraphActionRunner.js.map +1 -1
  349. package/dist/services/TaskGraphAgentRunner.d.ts +14 -2
  350. package/dist/services/TaskGraphAgentRunner.d.ts.map +1 -1
  351. package/dist/services/TaskGraphAgentRunner.js +157 -9
  352. package/dist/services/TaskGraphAgentRunner.js.map +1 -1
  353. package/dist/services/TaskGraphContinuationDeliverer.d.ts +59 -2
  354. package/dist/services/TaskGraphContinuationDeliverer.d.ts.map +1 -1
  355. package/dist/services/TaskGraphContinuationDeliverer.js +626 -16
  356. package/dist/services/TaskGraphContinuationDeliverer.js.map +1 -1
  357. package/dist/sharedCache.d.ts.map +1 -1
  358. package/dist/sharedCache.js +3 -0
  359. package/dist/sharedCache.js.map +1 -1
  360. package/dist/types.d.ts +23 -1
  361. package/dist/types.d.ts.map +1 -1
  362. package/dist/types.js.map +1 -1
  363. package/package.json +99 -98
  364. package/src/__tests__/ActionResolver.fieldSecurity.test.ts +237 -0
  365. package/src/__tests__/AdhocQueryResolver.dialect.test.ts +137 -0
  366. package/src/__tests__/AgentRunStatusPublisher.test.ts +49 -0
  367. package/src/__tests__/AgentSessionResolver.ownership.test.ts +137 -0
  368. package/src/__tests__/CustomColumnPromoterOnePass.test.ts +15 -1
  369. package/src/__tests__/DatasetResolver.itemFilters.test.ts +201 -0
  370. package/src/__tests__/EntityCommunicationsResolver.actingUser.test.ts +151 -0
  371. package/src/__tests__/EntityRecordNameResolver.rowSecurity.test.ts +152 -0
  372. package/src/__tests__/EvolutionActsOnWhatItDetects.test.ts +113 -0
  373. package/src/__tests__/FetchEntityVectorsResolver.test.ts +369 -18
  374. package/src/__tests__/FileResolver.fieldSecurity.test.ts +82 -0
  375. package/src/__tests__/FileResolver.storageAccess.test.ts +562 -0
  376. package/src/__tests__/GetDataContextDataResolver.sqlItems.test.ts +416 -0
  377. package/src/__tests__/ListOperationsResolver.adhocScreen.test.ts +137 -0
  378. package/src/__tests__/LoginScreenEngine.test.ts +86 -0
  379. package/src/__tests__/MJStorageBlobStore.storageGate.test.ts +63 -0
  380. package/src/__tests__/PipelineProgressResolver.filter.test.ts +58 -0
  381. package/src/__tests__/QuerySystemUserResolver.fieldSecurity.test.ts +49 -0
  382. package/src/__tests__/RESTEndpointHandler.test.ts +25 -0
  383. package/src/__tests__/RealtimeClientSessionResolver.configTamper.test.ts +23 -3
  384. package/src/__tests__/RealtimeClientSessionResolver.test.ts +324 -46
  385. package/src/__tests__/RecordingAssemblyScheduler.test.ts +178 -0
  386. package/src/__tests__/RemoteBrowserActionResolver.ownership.test.ts +98 -0
  387. package/src/__tests__/ResolverBase.adhocReadScope.test.ts +133 -2
  388. package/src/__tests__/ResolverBase.balancedClause.test.ts +155 -0
  389. package/src/__tests__/ResolverBase.clauseUnscopedRead.test.ts +127 -0
  390. package/src/__tests__/ResolverBase.clientOldValues.test.ts +243 -7
  391. package/src/__tests__/ResolverBase.deleteReturnProjection.test.ts +52 -0
  392. package/src/__tests__/ResolverBase.entityMessageRelay.test.ts +176 -0
  393. package/src/__tests__/ResolverBase.filterEscaping.test.ts +5 -2
  394. package/src/__tests__/ResolverBase.includeBinaryFields.test.ts +23 -1
  395. package/src/__tests__/ResolverBase.publishStatusUpdate.test.ts +68 -0
  396. package/src/__tests__/ResolverBase.userViewCacheAndDedup.test.ts +130 -0
  397. package/src/__tests__/RunAIAgentResolver.branch.test.ts +69 -13
  398. package/src/__tests__/RunAIAgentResolver.conversationWriter.test.ts +210 -0
  399. package/src/__tests__/RunAIAgentResolver.fireAndForgetCompletion.test.ts +209 -0
  400. package/src/__tests__/RunAIAgentResolver.historyFrom.test.ts +20 -28
  401. package/src/__tests__/RunAIAgentResolver.runDataGuard.test.ts +264 -0
  402. package/src/__tests__/RunAIAgentResolver.serverReply.test.ts +358 -0
  403. package/src/__tests__/RunAIAgentResolver.stoppedPredecessor.test.ts +4 -1
  404. package/src/__tests__/RunTemplateResolver.test.ts +35 -2
  405. package/src/__tests__/RunViewResolver.cacheCheckForwarding.test.ts +11 -0
  406. package/src/__tests__/RunViewResolver.cacheCheckScreen.test.ts +165 -0
  407. package/src/__tests__/SearchKnowledgeStreamResolver.test.ts +161 -0
  408. package/src/__tests__/SessionJanitor.test.ts +365 -10
  409. package/src/__tests__/SessionManager.test.ts +122 -0
  410. package/src/__tests__/TaskGraphActionRunner.durablePayload.test.ts +25 -0
  411. package/src/__tests__/TaskGraphAgentRunner.test.ts +266 -0
  412. package/src/__tests__/TaskGraphContinuationDeliverer.test.ts +468 -23
  413. package/src/__tests__/TaskGraphFrameResolver.test.ts +22 -0
  414. package/src/__tests__/TestQuerySQLResolver.test.ts +274 -0
  415. package/src/__tests__/TransactionGroupResolver.fieldSecurity.test.ts +199 -0
  416. package/src/__tests__/TransactionGroupResolver.refusals.test.ts +98 -1
  417. package/src/__tests__/UpdateMJDataContextItem.oldValues.test.ts +220 -0
  418. package/src/__tests__/UserViewResolver.updateWhereClause.test.ts +15 -0
  419. package/src/__tests__/ViewOperationsHandler.clauseScreen.test.ts +157 -0
  420. package/src/__tests__/ViewOperationsHandler.test.ts +7 -2
  421. package/src/__tests__/WidgetSessionService.test.ts +583 -4
  422. package/src/__tests__/agent-run-data-guard.test.ts +130 -0
  423. package/src/__tests__/apiRootBoot.test.ts +202 -0
  424. package/src/__tests__/buildMagicLinkSessionUser.test.ts +96 -0
  425. package/src/__tests__/cacheBroadcastProviders.test.ts +403 -0
  426. package/src/__tests__/cacheInvalidationRecordData.test.ts +109 -0
  427. package/src/__tests__/conversationRunEvents.test.ts +56 -14
  428. package/src/__tests__/fieldSecurityFixtures.ts +91 -0
  429. package/src/__tests__/globalCors.test.ts +217 -0
  430. package/src/__tests__/localDevAuth.test.ts +196 -0
  431. package/src/__tests__/multiTenancy.postgresRewrite.test.ts +181 -0
  432. package/src/__tests__/multiTenancy.security.test.ts +51 -0
  433. package/src/__tests__/multiTenancy.test.ts +1 -1
  434. package/src/__tests__/orphanedConversationDetailReconciler.test.ts +10 -0
  435. package/src/__tests__/ownedRealtimeSession.test.ts +39 -0
  436. package/src/__tests__/pushStatusResolver.filter.test.ts +64 -1
  437. package/src/__tests__/realtimeRecordingHandler.test.ts +669 -0
  438. package/src/__tests__/realtimeSessions/RealtimeSessionEventsResolver.test.ts +29 -1
  439. package/src/__tests__/realtimeSessions/ownedRealtimeSession.anonymous.test.ts +31 -0
  440. package/src/__tests__/realtimeSessions/ownedRealtimeSession.namedScoped.test.ts +37 -0
  441. package/src/__tests__/realtimeSessions/sessionAccess.test.ts +146 -7
  442. package/src/__tests__/realtimeSessions/sessionConfigStamps.test.ts +1 -1
  443. package/src/__tests__/realtimeSessions/verificationWorkflow.test.ts +25 -4
  444. package/src/__tests__/resolverBase.cloudEventChangedFields.test.ts +157 -0
  445. package/src/__tests__/resolverBase.fieldSecurityTransport.test.ts +222 -0
  446. package/src/__tests__/resolverBase.fls.test.ts +146 -97
  447. package/src/__tests__/restTransport.fieldSecurity.test.ts +148 -0
  448. package/src/__tests__/runParamsTimeZone.test.ts +179 -0
  449. package/src/__tests__/runStreams.fieldSecurity.test.ts +100 -0
  450. package/src/__tests__/runViewProperties.test.ts +114 -0
  451. package/src/__tests__/scalabilityBenchmarks.test.ts +765 -0
  452. package/src/__tests__/scalabilityDatabaseIntegration.test.ts +207 -0
  453. package/src/__tests__/serverExtensionHostOverlay.test.ts +66 -0
  454. package/src/__tests__/serverExtensionReservedRoots.test.ts +11 -98
  455. package/src/__tests__/sessionUserClone.test.ts +5 -1
  456. package/src/__tests__/sharedCache.test.ts +5 -3
  457. package/src/__tests__/startupSweepOrder.test.ts +40 -0
  458. package/src/__tests__/unifiedAuth.test.ts +28 -0
  459. package/src/__tests__/widgetGuestElevation.test.ts +2 -0
  460. package/src/agentSessions/SessionJanitor.ts +369 -93
  461. package/src/agentSessions/SessionManager.ts +45 -10
  462. package/src/apiRoot.ts +78 -0
  463. package/src/auth/AuthProviderCatalogRouter.ts +29 -0
  464. package/src/auth/LoginScreenEngine.ts +50 -0
  465. package/src/auth/index.ts +57 -12
  466. package/src/auth/initializeProviders.ts +43 -1
  467. package/src/auth/localDevAuth.ts +528 -0
  468. package/src/auth/magicLink/MagicLinkKeys.ts +2 -2
  469. package/src/auth/magicLink/MagicLinkRouter.ts +3 -2
  470. package/src/auth/magicLink/types.ts +10 -0
  471. package/src/auth/sessionUserClone.ts +3 -2
  472. package/src/broadcast/BaseCacheInvalidationBroadcastProvider.ts +674 -0
  473. package/src/broadcast/index.ts +5 -0
  474. package/src/broadcast/providers/AWSIoTCoreBroadcastProvider.ts +180 -0
  475. package/src/broadcast/providers/AzureWebPubSubBroadcastProvider.ts +182 -0
  476. package/src/broadcast/providers/GCPPubSubBroadcastProvider.ts +169 -0
  477. package/src/broadcast/providers/SequencedRoleBucketBroadcastProvider.ts +57 -0
  478. package/src/cache.ts +2 -1
  479. package/src/config.ts +115 -5
  480. package/src/context.ts +32 -8
  481. package/src/coreRoutes.ts +181 -0
  482. package/src/generated/graphql-schemas/__mj.ts +3684 -284
  483. package/src/generic/CacheInvalidationResolver.ts +172 -60
  484. package/src/generic/OrphanedConversationDetailReconciler.ts +4 -2
  485. package/src/generic/PubSubManager.ts +54 -1
  486. package/src/generic/PushStatusResolver.ts +109 -12
  487. package/src/generic/ResolverBase.ts +540 -431
  488. package/src/generic/RunViewResolver.ts +97 -15
  489. package/src/generic/actionOutputFieldSecurity.ts +75 -0
  490. package/src/generic/fieldSecurityTransport.ts +62 -0
  491. package/src/globalCors.ts +71 -0
  492. package/src/index.ts +239 -238
  493. package/src/integration/CustomColumnPromoter.ts +6 -1
  494. package/src/logging/variablesLoggingMiddleware.ts +59 -3
  495. package/src/multiTenancy/index.ts +24 -2
  496. package/src/realtimeSessions/README.md +7 -3
  497. package/src/realtimeSessions/RealtimeSessionVerificationService.ts +2 -1
  498. package/src/realtimeSessions/RealtimeVerifyRouter.ts +2 -1
  499. package/src/realtimeSessions/RecordingAssemblyScheduler.ts +234 -0
  500. package/src/realtimeSessions/SessionVerificationPortsBase.ts +1 -0
  501. package/src/realtimeSessions/index.ts +2 -0
  502. package/src/realtimeSessions/ownedRealtimeSession.ts +69 -0
  503. package/src/realtimeSessions/sessionAccess.ts +183 -23
  504. package/src/realtimeSessions/sessionConfigStamps.ts +1 -1
  505. package/src/realtimeSessions/subscriptionAuthorization.ts +4 -2
  506. package/src/realtimeSessions/verificationWorkflow.ts +3 -1
  507. package/src/realtimeWidget/WidgetRouter.ts +22 -4
  508. package/src/realtimeWidget/WidgetSessionService.ts +252 -17
  509. package/src/realtimeWidget/host-identity.ts +1 -1
  510. package/src/realtimeWidget/widgetCore.ts +30 -1
  511. package/src/realtimeWidget/widgetGuestElevation.ts +2 -1
  512. package/src/resolvers/ActionResolver.ts +78 -15
  513. package/src/resolvers/AdhocQueryResolver.ts +1 -0
  514. package/src/resolvers/AgentRunStatusPublisher.ts +36 -8
  515. package/src/resolvers/AgentSessionResolver.ts +46 -18
  516. package/src/resolvers/ArtifactFileResolver.ts +9 -8
  517. package/src/resolvers/ConversationRunEventsResolver.ts +15 -11
  518. package/src/resolvers/DatasetResolver.ts +70 -10
  519. package/src/resolvers/EntityCommunicationsResolver.ts +56 -15
  520. package/src/resolvers/EntityRecordNameResolver.ts +3 -2
  521. package/src/resolvers/FetchEntityVectorsResolver.ts +248 -55
  522. package/src/resolvers/FileCategoryResolver.ts +1 -0
  523. package/src/resolvers/FileResolver.ts +334 -109
  524. package/src/resolvers/GetDataContextDataResolver.ts +139 -41
  525. package/src/resolvers/GetDataResolver.ts +6 -3
  526. package/src/resolvers/IntegrationDiscoveryResolver.ts +53 -9
  527. package/src/resolvers/MergeRecordsResolver.ts +23 -2
  528. package/src/resolvers/PipelineProgressResolver.ts +12 -3
  529. package/src/resolvers/QueryResolver.ts +31 -6
  530. package/src/resolvers/QuerySystemUserResolver.ts +15 -6
  531. package/src/resolvers/RSUResolver.ts +12 -0
  532. package/src/resolvers/RealtimeClientSessionResolver.ts +114 -66
  533. package/src/resolvers/RemoteBrowserActionResolver.ts +15 -10
  534. package/src/resolvers/RunAIAgentResolver.ts +296 -85
  535. package/src/resolvers/RunTemplateResolver.ts +6 -4
  536. package/src/resolvers/RunTestResolver.ts +3 -1
  537. package/src/resolvers/SearchKnowledgeStreamResolver.ts +19 -3
  538. package/src/resolvers/SqlLoggingConfigResolver.ts +2 -4
  539. package/src/resolvers/SyncDataResolver.ts +4 -0
  540. package/src/resolvers/TaskGraphFrameResolver.ts +33 -1
  541. package/src/resolvers/TestQuerySQLResolver.ts +69 -13
  542. package/src/resolvers/TransactionGroupResolver.ts +185 -30
  543. package/src/resolvers/UserViewResolver.ts +2 -1
  544. package/src/resolvers/__tests__/GetDataResolver.validation.test.ts +95 -0
  545. package/src/resolvers/__tests__/MergeRecordsResolver.test.ts +43 -0
  546. package/src/resolvers/agent-run-data-guard.ts +89 -0
  547. package/src/rest/EntityCRUDHandler.ts +22 -5
  548. package/src/rest/RESTEndpointHandler.ts +8 -5
  549. package/src/rest/RealtimeRecordingHandler.ts +467 -0
  550. package/src/rest/ViewOperationsHandler.ts +52 -18
  551. package/src/rest/setupRESTEndpoints.ts +6 -0
  552. package/src/serverExtensionReservedRoots.ts +14 -17
  553. package/src/serverRoleConfigUnits.ts +48 -0
  554. package/src/services/MJStorageBlobStore.ts +31 -30
  555. package/src/services/StartTaskGraphDispatcher.ts +2 -2
  556. package/src/services/TaskGraphActionRunner.ts +25 -5
  557. package/src/services/TaskGraphAgentRunner.ts +188 -11
  558. package/src/services/TaskGraphContinuationDeliverer.ts +738 -16
  559. package/src/sharedCache.ts +3 -0
  560. package/src/types.ts +23 -1
@@ -9,20 +9,22 @@
9
9
  * widget guest is ephemeral). Forensics ride the opaque per-session id (`mj_sid`)
10
10
  * carried in the token, plus best-effort structured audit logging. The minted
11
11
  * token is validated by the SAME `magic-link` auth provider (same issuer/audience/
12
- * JWKS) and synthesized into a constrained guest principal by `buildMagicLinkSessionUser`.
12
+ * JWKS) and synthesized into a constrained guest principal by `BuildMagicLinkSessionUser`.
13
13
  *
14
14
  * @module @memberjunction/server/widget
15
15
  */
16
16
 
17
+ import { createPublicKey } from 'node:crypto';
18
+ import jwt from 'jsonwebtoken';
17
19
  import { Metadata, RunView, UserInfo, LogError, LogStatus } from '@memberjunction/core';
18
- import { MJLruCache, UUIDsEqual } from '@memberjunction/global';
20
+ import { ComputeJwkThumbprint, MJLruCache, ToProofPublicJwk, UUIDsEqual, VerifyProofOfPossessionJwt, type ProofPublicJwk } from '@memberjunction/global';
19
21
  import type { MJConversationWidgetInstanceEntity, MJConversationEntity } from '@memberjunction/core-entities';
20
22
  import { ResolveConfiguredPrincipal } from '../auth/principals.js';
21
23
  import { MagicLinkKeyManager } from '../auth/magicLink/MagicLinkKeys.js';
22
24
  import { GenerateSessionId } from '../auth/magicLink/magicLinkCore.js';
23
25
  import { MagicLinkService } from '../auth/magicLink/MagicLinkService.js';
24
26
  import { configInfo, type WidgetConfig } from '../config.js';
25
- import { BuildWidgetGuestClaims, EvaluateWidgetMint, ParseEnabledChannels, type WidgetMintErrorCode } from './widgetCore.js';
27
+ import { BuildWidgetGuestClaims, EvaluateWidgetMint, IsIsolatedGuestRole, ParseEnabledChannels, type GuestRolePolicy, type WidgetMintErrorCode } from './widgetCore.js';
26
28
  import { VerifyHostAssertion, type HostAssertedIdentity } from './host-identity.js';
27
29
  import { WriteReturningVisitorRecap } from '../agentSessions/ReturningVisitorRecap.js';
28
30
  import { ResolveIdentityByEmail, MergeVisitorIdentity, ForgetVisitor, type ResolvedVisitorIdentity } from './visitorIdentity.js';
@@ -33,6 +35,43 @@ const CONVERSATIONS_ENTITY = 'MJ: Conversations';
33
35
  /** Shape of the durable visitor anchor key (opaque base64url, same alphabet as generateSessionId). */
34
36
  const VISITOR_KEY_PATTERN = /^[A-Za-z0-9_-]{16,128}$/;
35
37
 
38
+ /**
39
+ * Maximum clock-skew / late-timer grace window (seconds) after `exp` during which
40
+ * `RefreshGuestSession` still accepts a widget guest Bearer token and preserves its `mj_sid`.
41
+ */
42
+ export const REFRESH_GRACE_SECONDS = 300;
43
+
44
+ /**
45
+ * Hard end of a widget guest session (seconds after its first mint, `mj_sid_iat`). Refresh keeps the
46
+ * visitor's `mj_sid`, so without an end a token captured once could be renewed forever and keep reading
47
+ * that visitor's conversations; past this point refresh is refused and no token outlives it.
48
+ */
49
+ export const MAX_GUEST_SESSION_SECONDS = 12 * 3600;
50
+
51
+ /**
52
+ * The least lifetime a refreshed token may have. Refresh is refused once less than this remains before the hard end,
53
+ * so the last refresh gets the 403 that makes the widget start a new session. It must exceed the widget's refresh
54
+ * lead (60 s before `exp`): a token issued with less would be due for refresh at once, every time, until the rate
55
+ * limiter answered 429 instead. It also keeps a re-minted token's `exp` after its `iat`.
56
+ */
57
+ export const MIN_REFRESHED_TOKEN_SECONDS = 120;
58
+
59
+ /** The refresh route's path under the widget mount; the refresh proof must name it (`htu`). */
60
+ export const WIDGET_REFRESH_PATH = '/session/refresh';
61
+
62
+ /** How far a refresh proof's signing time (`iat`) may be from the server clock, either way. */
63
+ export const REFRESH_PROOF_MAX_SKEW_SECONDS = 60;
64
+
65
+ /** The session a valid refresh token belongs to, carried into the re-minted token unchanged. */
66
+ interface RefreshableGuestSession {
67
+ /** `mj_sid`. */
68
+ SessionId: string;
69
+ /** `mj_sid_iat`: when the session was first minted, epoch seconds. */
70
+ StartedAtSeconds: number;
71
+ /** `cnf.jkt`: the thumbprint of the key the session is bound to. */
72
+ KeyThumbprint: string;
73
+ }
74
+
36
75
  /** Resolved returning-visitor anchor for a mint: the durable key + the prior conversation to chain from. */
37
76
  interface ReturningVisitorResolution {
38
77
  /** The durable VisitorKey to persist as a cookie (validated-presented or freshly minted). */
@@ -67,6 +106,19 @@ export interface MintGuestSessionInput {
67
106
  * server mints a fresh one. Ignored entirely when remembering is off.
68
107
  */
69
108
  visitorKey?: string; // case-violation-ok-legacy-back-compat: optional, and the old name is also read off a value the checker cannot type; renaming it stays assignable and silently yields undefined
109
+ /**
110
+ * The caller's current guest session JWT (`Authorization: Bearer <token>`), required by
111
+ * `RefreshGuestSession` so a refresh proves possession of the session being renewed and
112
+ * preserves its `mj_sid` (`sessionId`).
113
+ */
114
+ BearerToken?: string;
115
+ /**
116
+ * The widget's proof key (public P-256 JWK, from the mint body's `proofKey`). Its thumbprint is signed into
117
+ * the token as `cnf.jkt`; a token minted without one cannot be refreshed.
118
+ */
119
+ ProofKey?: ProofPublicJwk;
120
+ /** The refresh proof (`DPoP` header), signed by the key registered at mint. Required by `RefreshGuestSession`. */
121
+ Proof?: string;
70
122
  audit?: WidgetMintAuditContext; // case-violation-ok-legacy-back-compat: optional, and the old name is also read off a value the checker cannot type; renaming it stays assignable and silently yields undefined
71
123
  }
72
124
 
@@ -210,6 +262,8 @@ export class WidgetSessionService {
210
262
  constructor(
211
263
  private readonly publicUrl: string,
212
264
  private readonly config: WidgetConfig,
265
+ /** Which roles a widget may hand to an anonymous guest; by default only the scope-isolated `Widget Guest`. */
266
+ private readonly guestRolePolicy: GuestRolePolicy = { GrantableRoleNames: [] },
213
267
  ) {}
214
268
 
215
269
  /**
@@ -237,11 +291,11 @@ export class WidgetSessionService {
237
291
  return this.audited({ success: false, errorCode: eligibility.errorCode, error: 'Widget mint rejected.' }, input, widget);
238
292
  }
239
293
 
240
- const guestRoleName = this.resolveGuestRoleName(widget.GuestRoleID);
241
- if (!guestRoleName) {
242
- LogError(`[Widget] Guest role ${widget.GuestRoleID} for widget ${widget.ID} not found in metadata.`);
243
- return this.audited({ success: false, errorCode: 'server_error', error: 'Guest role not resolvable.' }, input, widget);
294
+ const guestRole = this.resolveIsolatedGuestRole(widget);
295
+ if (guestRole.ok === false) {
296
+ return this.audited(guestRole.refusal, input, widget);
244
297
  }
298
+ const guestRoleName = guestRole.name;
245
299
 
246
300
  // D1 host-identity strategy: a HostIdentity widget MUST present a valid host assertion.
247
301
  let hostIdentity: HostAssertedIdentity | undefined;
@@ -267,7 +321,21 @@ export class WidgetSessionService {
267
321
  // anonymous trail to that record and surface the pair so the client stamps the new conversation.
268
322
  const resolvedIdentity = await this.resolveHostIdentityIfApplicable(widget, hostIdentity, returningVisitor, contextUser);
269
323
 
270
- return this.audited(this.mintToken(widget, guestRoleName, hostIdentity, returningVisitor, resolvedIdentity), input, widget);
324
+ let proofKeyThumbprint: string | undefined;
325
+ if (input.ProofKey !== undefined) {
326
+ const proofKey = ToProofPublicJwk(input.ProofKey);
327
+ if (!proofKey) {
328
+ LogError(`[Widget] Mint for widget ${widget.ID} refused: the proof key is not a public P-256 JWK.`);
329
+ return this.audited({ success: false, errorCode: 'not_found', error: 'Widget mint rejected.' }, input, widget);
330
+ }
331
+ proofKeyThumbprint = await ComputeJwkThumbprint(proofKey);
332
+ }
333
+
334
+ return this.audited(
335
+ this.mintToken(widget, guestRoleName, hostIdentity, returningVisitor, resolvedIdentity, undefined, proofKeyThumbprint),
336
+ input,
337
+ widget,
338
+ );
271
339
  } catch (e) {
272
340
  LogError(e);
273
341
  return { success: false, errorCode: 'server_error', error: e instanceof Error ? e.message : String(e) };
@@ -275,12 +343,147 @@ export class WidgetSessionService {
275
343
  }
276
344
 
277
345
  /**
278
- * Refreshes a live guest session. The widget always holds its public key, so a
279
- * refresh is a fresh mint by the same key + origin — short-TTL tokens with no
280
- * refresh-token machinery (mirrors magic-link's no-refresh-token stance).
346
+ * Refreshes a live guest session while preserving its per-visitor `sessionId` (`mj_sid`).
347
+ * Requires the caller's current widget guest JWT (`input.BearerToken`), verified against the
348
+ * magic-link signing key with a {@link REFRESH_GRACE_SECONDS} post-expiry grace window, and
349
+ * bound to the resolved widget instance (`mj_widget_id === widget.ID`, `mj_anon === true`,
350
+ * `mj_magic_link === true`). Any failure returns the same uniform 403 shape as an unknown widget key.
281
351
  */
282
352
  public async RefreshGuestSession(input: MintGuestSessionInput): Promise<MintGuestSessionResult> {
283
- return this.MintGuestSession(input);
353
+ try {
354
+ const contextUser = this.resolveLookupUser();
355
+ if (!contextUser) {
356
+ LogError('[Widget] No lookup context user available; server not configured.');
357
+ return { success: false, errorCode: 'server_error', error: 'Server not configured for widget sessions.' };
358
+ }
359
+
360
+ const widget = await this.loadWidgetByKey(input.widgetKey, contextUser);
361
+ if (!widget) {
362
+ return this.audited({ success: false, errorCode: 'not_found', error: 'Unknown widget key.' }, input, undefined);
363
+ }
364
+
365
+ const eligibility = EvaluateWidgetMint(
366
+ { Status: widget.Status, AllowedOrigins: widget.AllowedOrigins, Modality: widget.Modality },
367
+ input.origin,
368
+ );
369
+ if (!eligibility.ok) {
370
+ return this.audited({ success: false, errorCode: eligibility.errorCode, error: 'Widget mint rejected.' }, input, widget);
371
+ }
372
+
373
+ const guestRole = this.resolveIsolatedGuestRole(widget);
374
+ if (guestRole.ok === false) {
375
+ return this.audited(guestRole.refusal, input, widget);
376
+ }
377
+ const guestRoleName = guestRole.name;
378
+
379
+ let hostIdentity: HostAssertedIdentity | undefined;
380
+ if (widget.AuthStrategy === 'HostIdentity') {
381
+ const verified = this.verifyHost(widget, input.hostAssertion);
382
+ if (!verified) {
383
+ return this.audited({ success: false, errorCode: 'host_assertion_invalid', error: 'Host identity assertion invalid.' }, input, widget);
384
+ }
385
+ hostIdentity = verified;
386
+ }
387
+
388
+ const existingSession = await this.verifyRefreshRequest(input.BearerToken, input.Proof, widget.ID);
389
+ if (!existingSession) {
390
+ return this.audited({ success: false, errorCode: 'not_found', error: 'Unknown widget key.' }, input, widget);
391
+ }
392
+
393
+ const returningVisitor = await this.resolveReturningVisitor(widget, input.visitorKey, contextUser);
394
+ const resolvedIdentity = await this.resolveHostIdentityIfApplicable(widget, hostIdentity, returningVisitor, contextUser);
395
+
396
+ return this.audited(
397
+ this.mintToken(widget, guestRoleName, hostIdentity, returningVisitor, resolvedIdentity, existingSession, existingSession.KeyThumbprint),
398
+ input,
399
+ widget,
400
+ );
401
+ } catch (e) {
402
+ LogError(e);
403
+ return { success: false, errorCode: 'server_error', error: e instanceof Error ? e.message : String(e) };
404
+ }
405
+ }
406
+
407
+ /**
408
+ * Verifies a `RefreshGuestSession` request: the caller's current widget guest JWT and the proof that the
409
+ * caller holds the key the token is bound to. Returns the session to carry forward, or `null` when the token
410
+ * is missing, tampered, expired past {@link REFRESH_GRACE_SECONDS}, past the session's hard end
411
+ * ({@link MAX_GUEST_SESSION_SECONDS}) or without a session start, non-anonymous, minted for a different
412
+ * widget, issued by another deployment, or not bound to a key; or when the proof is missing or not made by
413
+ * that key for this request and token.
414
+ */
415
+ private async verifyRefreshRequest(bearerToken: string | undefined, proof: string | undefined, widgetId: string): Promise<RefreshableGuestSession | null> {
416
+ const session = this.verifyRefreshBearerToken(bearerToken, widgetId);
417
+ if (!session) {
418
+ return null;
419
+ }
420
+ const verification = await VerifyProofOfPossessionJwt(proof ?? '', {
421
+ Method: 'POST',
422
+ PathSuffix: WIDGET_REFRESH_PATH,
423
+ AccessToken: (bearerToken ?? '').trim(),
424
+ NowSeconds: Math.floor(Date.now() / 1000),
425
+ MaxSkewSeconds: REFRESH_PROOF_MAX_SKEW_SECONDS,
426
+ });
427
+ if (verification.Valid === false) {
428
+ LogError(`[Widget] Refresh proof refused for widget ${widgetId} (${verification.Reason}).`);
429
+ return null;
430
+ }
431
+ if (verification.Thumbprint !== session.KeyThumbprint) {
432
+ LogError(`[Widget] Refresh proof refused for widget ${widgetId}: signed by a key the token is not bound to.`);
433
+ return null;
434
+ }
435
+ return session;
436
+ }
437
+
438
+ /** The token half of {@link verifyRefreshRequest}: everything except the proof. */
439
+ private verifyRefreshBearerToken(bearerToken: string | undefined, widgetId: string): RefreshableGuestSession | null {
440
+ const token = (bearerToken ?? '').trim();
441
+ if (!token) {
442
+ return null;
443
+ }
444
+ try {
445
+ const jwk = MagicLinkKeyManager.Instance.GetJWKS().keys[0];
446
+ if (!jwk) {
447
+ return null;
448
+ }
449
+ const publicKey = createPublicKey({ key: { ...jwk }, format: 'jwk' });
450
+ const verified = jwt.verify(token, publicKey, {
451
+ algorithms: ['RS256'],
452
+ audience: this.config.audience,
453
+ issuer: this.publicUrl,
454
+ ignoreExpiration: true,
455
+ });
456
+ if (typeof verified !== 'object' || verified === null) {
457
+ return null;
458
+ }
459
+ const payload = verified as jwt.JwtPayload;
460
+ const nowSeconds = Math.floor(Date.now() / 1000);
461
+ if (typeof payload.exp !== 'number' || nowSeconds > payload.exp + REFRESH_GRACE_SECONDS) {
462
+ return null;
463
+ }
464
+ if (payload.mj_magic_link !== true || payload.mj_anon !== true) {
465
+ return null;
466
+ }
467
+ if (typeof payload.mj_widget_id !== 'string' || !UUIDsEqual(payload.mj_widget_id, widgetId)) {
468
+ return null;
469
+ }
470
+ const sid = typeof payload.mj_sid === 'string' ? payload.mj_sid.trim() : '';
471
+ if (sid.length === 0) {
472
+ return null;
473
+ }
474
+ const startedAt = payload.mj_sid_iat;
475
+ if (typeof startedAt !== 'number' || !Number.isFinite(startedAt) || startedAt + MAX_GUEST_SESSION_SECONDS - nowSeconds < MIN_REFRESHED_TOKEN_SECONDS) {
476
+ return null;
477
+ }
478
+ const keyThumbprint = typeof payload.cnf?.jkt === 'string' ? payload.cnf.jkt : '';
479
+ if (keyThumbprint.length === 0) {
480
+ return null;
481
+ }
482
+ return { SessionId: sid, StartedAtSeconds: startedAt, KeyThumbprint: keyThumbprint };
483
+ } catch (e) {
484
+ LogError(`[Widget] Refresh token verification failed for widget ${widgetId}: ${e instanceof Error ? e.message : String(e)}`);
485
+ return null;
486
+ }
284
487
  }
285
488
 
286
489
  /**
@@ -343,7 +546,7 @@ export class WidgetSessionService {
343
546
  * clicks the emailed link → the existing public `POST /magic-link/redeem` mints a VERIFIED session
344
547
  * JWT → the widget swaps it in via `transport.UpdateToken`, preserving the live conversationId.
345
548
  *
346
- * This converges on the SAME `AuthProviderFactory` + `buildMagicLinkSessionUser` path as the guest
549
+ * This converges on the SAME `AuthProviderFactory` + `BuildMagicLinkSessionUser` path as the guest
347
550
  * mint (D1), so the verified session is just a more-privileged principal on the one pathway. Never
348
551
  * throws for business failures — returns a structured result.
349
552
  */
@@ -412,12 +615,18 @@ export class WidgetSessionService {
412
615
  hostIdentity?: HostAssertedIdentity,
413
616
  returningVisitor?: ReturningVisitorResolution,
414
617
  resolvedIdentity?: ResolvedVisitorIdentity,
618
+ existingSession?: RefreshableGuestSession,
619
+ proofKeyThumbprint?: string,
415
620
  ): MintGuestSessionResult {
416
621
  const nowSeconds = Math.floor(Date.now() / 1000);
417
622
  const ttlMinutes = widget.SessionTTLMinutes || this.config.defaultSessionTtlMinutes;
418
- // Generated once and returned to the client: the widget stamps Conversation.ExternalID with
419
- // this id so the Widget Guest RLS filters ({{ScopeResourceID}}) isolate this guest's rows.
420
- const sessionId = GenerateSessionId();
623
+ // Generated once on initial mint and preserved across refreshes: the widget (and server-side
624
+ // voice session creation) stamps Conversation.ExternalID with this id so the Widget Guest RLS
625
+ // filters ({{ScopeResourceID}}) and AuthorizeSessionAccess isolate this guest's rows.
626
+ const sessionId = existingSession?.SessionId ?? GenerateSessionId();
627
+ const startedAtSeconds = existingSession?.StartedAtSeconds ?? nowSeconds;
628
+ // No token outlives the session's hard end, so the cap holds for API calls as well as for refresh.
629
+ const ttlSeconds = Math.min(ttlMinutes * 60, startedAtSeconds + MAX_GUEST_SESSION_SECONDS - nowSeconds);
421
630
  const claims = BuildWidgetGuestClaims({
422
631
  issuer: this.publicUrl,
423
632
  audience: this.config.audience,
@@ -427,7 +636,9 @@ export class WidgetSessionService {
427
636
  applicationId: widget.ApplicationID,
428
637
  guestRoleName,
429
638
  nowSeconds,
430
- ttlSeconds: ttlMinutes * 60,
639
+ ttlSeconds,
640
+ sessionStartedAtSeconds: startedAtSeconds,
641
+ proofKeyThumbprint,
431
642
  hostIdentity,
432
643
  // RV1/RV2/RV4: carry the returning-visitor anchor + resolved identity as claims so the voice path
433
644
  // (server-created conversation) stamps the same fields the text path stamps client-side.
@@ -692,6 +903,30 @@ export class WidgetSessionService {
692
903
  return role?.Name ?? null;
693
904
  }
694
905
 
906
+ /**
907
+ * The ONE decision, for mint and refresh alike, of which role a guest token carries: the widget's `GuestRoleID`
908
+ * must resolve, and it must be a role the deployment may hand to an anonymous visitor
909
+ * ({@link IsIsolatedGuestRole}). Both refusals are the admin's to fix, so both are logged with the widget id;
910
+ * the visitor gets a uniform rejection.
911
+ */
912
+ private resolveIsolatedGuestRole(
913
+ widget: MJConversationWidgetInstanceEntity,
914
+ ): { ok: true; name: string } | { ok: false; refusal: MintGuestSessionResult } {
915
+ const name = this.resolveGuestRoleName(widget.GuestRoleID);
916
+ if (!name) {
917
+ LogError(`[Widget] Guest role ${widget.GuestRoleID} for widget ${widget.ID} not found in metadata.`);
918
+ return { ok: false, refusal: { success: false, errorCode: 'server_error', error: 'Guest role not resolvable.' } };
919
+ }
920
+ if (!IsIsolatedGuestRole(name, this.guestRolePolicy)) {
921
+ LogError(
922
+ `[Widget] Widget ${widget.ID} grants guest role '${name}', whose row filters do not isolate anonymous visitors ` +
923
+ `from each other. Use the Widget Guest role, or list '${name}' in magicLink.grantableRoleNames to allow it (MJ#6043).`,
924
+ );
925
+ return { ok: false, refusal: { success: false, errorCode: 'guest_role_not_isolated', error: 'Widget mint rejected.' } };
926
+ }
927
+ return { ok: true, name };
928
+ }
929
+
695
930
  /** Resolves the server-side context user used to READ widget config (not the guest principal). */
696
931
  private resolveLookupUser(): UserInfo | null {
697
932
  return ResolveConfiguredPrincipal(this.config.contextUserForLookup, 'Widget');
@@ -5,7 +5,7 @@
5
5
  * `POST /widget/session`, which verifies it against the host's registered public key
6
6
  * and folds the host-provided identity into the minted guest claims. The minted token
7
7
  * is still validated by the same `magic-link` AuthProviderFactory path + synthesized by
8
- * `buildMagicLinkSessionUser` — host-identity is a MINT-TIME strategy, not a second
8
+ * `BuildMagicLinkSessionUser` — host-identity is a MINT-TIME strategy, not a second
9
9
  * session-validation provider (it converges on the one pathway, per D1).
10
10
  *
11
11
  * Pure + unit-testable: verification takes the PEM as an argument.
@@ -12,7 +12,7 @@
12
12
  * @module @memberjunction/server/widget
13
13
  */
14
14
 
15
- import { BuildSessionClaims } from '../auth/magicLink/magicLinkCore.js';
15
+ import { BuildSessionClaims, IsRoleGrantable } from '../auth/magicLink/magicLinkCore.js';
16
16
  import type { MagicLinkJWTClaims } from '../auth/magicLink/types.js';
17
17
 
18
18
  /**
@@ -31,8 +31,29 @@ export type WidgetMintErrorCode =
31
31
  | 'host_assertion_invalid'
32
32
  | 'upgrade_not_enabled'
33
33
  | 'invalid_email'
34
+ | 'guest_role_not_isolated'
34
35
  | 'server_error';
35
36
 
37
+ /**
38
+ * The one stock role whose row filters key on the per-visitor scope id (`{{ScopeResourceID}}`) rather than on
39
+ * `UserID`. Every anonymous widget guest authenticates as the ONE shared Anonymous user, so a role whose filters
40
+ * compare `UserID` (the stock `UI` role, for instance) lets every guest read and update every other guest's rows
41
+ * through the generic API (MJ#6043). A widget may therefore grant only this role, or a role the deployment has
42
+ * explicitly listed as safe for anonymous visitors — the same opt-in list magic-link invites use.
43
+ */
44
+ export const WIDGET_GUEST_ROLE_NAME = 'Widget Guest';
45
+
46
+ /** Which roles, beyond {@link WIDGET_GUEST_ROLE_NAME}, a deployment allows a widget to hand to an anonymous guest. */
47
+ export interface GuestRolePolicy {
48
+ /** Role names (case-insensitive) the deployment has opted in, normally `magicLink.grantableRoleNames`. */
49
+ GrantableRoleNames: readonly string[];
50
+ }
51
+
52
+ /** Pure check: may a widget grant `roleName` to an anonymous guest under `policy`? See {@link WIDGET_GUEST_ROLE_NAME}. */
53
+ export function IsIsolatedGuestRole(roleName: string | null | undefined, policy: GuestRolePolicy): boolean {
54
+ return IsRoleGrantable(roleName, WIDGET_GUEST_ROLE_NAME, policy.GrantableRoleNames);
55
+ }
56
+
36
57
  /** The minimal widget-instance shape the pure validators need (a subset of the entity). */
37
58
  export interface WidgetInstanceEligibilityInput {
38
59
  Status: string;
@@ -206,6 +227,10 @@ export function BuildWidgetGuestClaims(args: {
206
227
  guestRoleName: string;
207
228
  nowSeconds: number;
208
229
  ttlSeconds: number;
230
+ /** When `sessionId` was first minted (`mj_sid_iat`); a refresh passes the original. Defaults to `nowSeconds`. */
231
+ sessionStartedAtSeconds?: number;
232
+ /** Thumbprint of the widget's proof key (`cnf.jkt`). Without it the token cannot be refreshed. */
233
+ proofKeyThumbprint?: string;
209
234
  /**
210
235
  * Host-asserted identity for a `host-identity` session. Its email/name are carried as
211
236
  * INFORMATIONAL claims only — the principal-resolving `email`/`sub` remain the shared
@@ -248,6 +273,10 @@ export function BuildWidgetGuestClaims(args: {
248
273
  });
249
274
  // Additive widget claim — lets the synthesized principal be bound to one widget.
250
275
  claims.mj_widget_id = args.widgetId;
276
+ claims.mj_sid_iat = args.sessionStartedAtSeconds ?? args.nowSeconds;
277
+ if (args.proofKeyThumbprint) {
278
+ claims.cnf = { jkt: args.proofKeyThumbprint };
279
+ }
251
280
  if (args.hostIdentity) {
252
281
  claims.given_name = args.hostIdentity.firstName ?? claims.given_name;
253
282
  claims.family_name = args.hostIdentity.lastName ?? claims.family_name;
@@ -41,7 +41,7 @@ export interface WidgetGuestRunContext {
41
41
  * Returns elevation context when the request is a public web-widget guest, else `null` (the common
42
42
  * case — every non-widget request). A widget guest is identified by the synthesized principal's
43
43
  * `IsMagicLinkAnonymous` flag plus a `WidgetGuestContext.WidgetID` (sourced from the signed
44
- * `mj_widget_id` claim by `buildMagicLinkSessionUser`). The widget instance is loaded under the
44
+ * `mj_widget_id` claim by `BuildMagicLinkSessionUser`). The widget instance is loaded under the
45
45
  * SYSTEM principal so resolving the pinned agent does not depend on the guest's narrow grants.
46
46
  *
47
47
  * Never throws: a resolution failure (no system user, widget not found, read error) returns `null`,
@@ -169,6 +169,7 @@ export function ElevateUserPayload(userPayload: UserPayload, elevatedUser: UserI
169
169
  email: elevatedUser.Email,
170
170
  userRecord: elevatedUser,
171
171
  isSystemUser: true,
172
+ ElevatedFrom: userPayload.userRecord,
172
173
  };
173
174
  }
174
175
 
@@ -1,17 +1,19 @@
1
1
  import { Resolver, Mutation, Arg, Ctx } from "type-graphql";
2
2
  import { ActionEngineServer } from "@memberjunction/actions";
3
3
  import { EntityActionEngineServer } from "@memberjunction/actions";
4
- import { Metadata, UserInfo, BaseEntity, CompositeKey, KeyValuePair, LogError, RunView, DatabaseProviderBase } from "@memberjunction/core";
5
- import { ActionParam, ActionResult, MJActionEntityExtended } from "@memberjunction/actions-base";
4
+ import { Metadata, UserInfo, BaseEntity, CompositeKey, KeyValuePair, LogError, RunView, DatabaseProviderBase, EntityInfo, IMetadataProvider } from "@memberjunction/core";
5
+ import { ActionParam, ActionResult, MJActionEntityExtended, ProjectActionParamValuesForUser } from "@memberjunction/actions-base";
6
6
  import { UserCache } from "@memberjunction/generic-database-provider";
7
7
  import { Field, InputType, ObjectType } from "type-graphql";
8
8
  import { KeyValuePairInput } from "../generic/KeyValuePairInput.js";
9
9
  import { AppContext, ProviderInfo } from "../types.js";
10
- import { CopyScalarsAndArrays, EscapeSQLString, UUIDsEqual } from "@memberjunction/global";
10
+ import { CopyScalarsAndArrays, EscapeSQLString, IndexByUUID, UUIDsEqual } from "@memberjunction/global";
11
11
  import { GetReadOnlyProvider, GetReadWriteProvider } from "../util.js";
12
12
  import { ResolverBase } from "../generic/ResolverBase.js";
13
13
  import { IsScopeLimitedPrincipal } from "../auth/scopeLimitedPrincipal.js";
14
14
  import { EvaluateActionRunAuthorization, IsOwner } from "../auth/actionAuthorization.js";
15
+ import { EntityObjectDataBinding, ProjectActionParamsForCaller } from "../generic/actionOutputFieldSecurity.js";
16
+ import type { EntityActionResult } from "@memberjunction/actions-base";
15
17
 
16
18
  /**
17
19
  * Input type for action parameters
@@ -213,8 +215,8 @@ export class ActionResolver extends ResolverBase {
213
215
  // params.Provider.SearchEntity) run against the caller's metadata layer.
214
216
  const result = await this.executeAction(action, user, params, ctx.providers);
215
217
 
216
- // Return the result
217
- return this.createActionResult(result);
218
+ // Return the result, its output parameters projected for the caller
219
+ return this.createActionResult(result, user, ctx.providers);
218
220
  } catch (e) {
219
221
  return this.handleActionError(e);
220
222
  }
@@ -357,20 +359,29 @@ export class ActionResolver extends ResolverBase {
357
359
  }
358
360
 
359
361
  /**
360
- * Creates an action result from the execution result
362
+ * Creates an action result from the execution result. The output parameters are projected for
363
+ * the caller first (see {@link ProjectActionParamValuesForUser}): an action may return rows it
364
+ * did not load as the caller, such as engine-cached or system-user rows, so an entity object is
365
+ * sent as its field values projected for the caller and a plain row of a field-secured entity
366
+ * loses the keys the caller is denied. An entity object of an entity the caller cannot read is
367
+ * kept as it is, so `CopyScalarsAndArrays` drops it exactly as it always has.
361
368
  * @param result The execution result
369
+ * @param user The caller the result is sent to
370
+ * @param providers The request's providers, for the entity metadata the projection reads
362
371
  * @returns The formatted action result
363
372
  * @private
364
373
  */
365
- private createActionResult(result: ActionResult): ActionResultOutput {
366
- const x =(result.Params || result.RunParams.Params || [])
374
+ private createActionResult(result: ActionResult, user: UserInfo, providers: Array<ProviderInfo>): ActionResultOutput {
375
+ const outputs = (result.Params || result.RunParams.Params || [])
367
376
  .filter(p => p.Type.trim().toLowerCase() === 'output' ||
368
- p.Type.trim().toLowerCase() === 'both') ;
377
+ p.Type.trim().toLowerCase() === 'both');
378
+ const provider = GetReadOnlyProvider(providers, { allowFallbackToReadWrite: true }) ?? undefined;
379
+ const projected = ProjectActionParamValuesForUser(outputs, user, provider, { UnreadableEntityObjects: 'keep' }) ?? outputs;
369
380
  return {
370
381
  Success: result.Success,
371
382
  Message: result.Message,
372
383
  ResultCode: result.Result?.ResultCode,
373
- ResultData: x && x.length > 0 ? JSON.stringify(CopyScalarsAndArrays(x)) : undefined
384
+ ResultData: projected.length > 0 ? JSON.stringify(CopyScalarsAndArrays(projected)) : undefined
374
385
  };
375
386
  }
376
387
 
@@ -442,11 +453,11 @@ export class ActionResolver extends ResolverBase {
442
453
  };
443
454
  }
444
455
 
445
- // Return the result
456
+ // Return the result, its echoed parameters projected for the caller
446
457
  return {
447
458
  Success: result.Success,
448
459
  Message: result.Message,
449
- ResultData: JSON.stringify(result)
460
+ ResultData: JSON.stringify(this.projectEntityActionResult(result, entityAction, params.EntityObject, user, ctx.providers))
450
461
  };
451
462
  } catch (e) {
452
463
  return this.handleError(e);
@@ -513,13 +524,65 @@ export class ActionResolver extends ResolverBase {
513
524
  throw new Error("Entity information is required");
514
525
  }
515
526
 
516
- // Create a composite key and load the entity object
527
+ // Create a composite key and load the entity object FOR THE CALLER: with no user the load
528
+ // falls back to the provider's current user, which on a server is the system user (every
529
+ // column, and none of the caller's row-level security).
517
530
  const compositeKey = this.createCompositeKey(entity, input.PrimaryKey);
518
- const entityObject = await md.GetEntityObject(entity.Name);
519
- await entityObject.InnerLoad(compositeKey);
531
+ const entityObject = await md.GetEntityObject(entity.Name, user);
532
+ if (!await entityObject.InnerLoad(compositeKey)) {
533
+ // One message whether the record is missing or out of the caller's reach.
534
+ throw new Error('Record not found or access denied');
535
+ }
520
536
  params['EntityObject'] = entityObject;
521
537
  }
522
538
 
539
+ /**
540
+ * The entity action result as it may be sent to `user`: its parameters, which the result echoes
541
+ * (in `Params` and in `RunParams.Params`), projected for the caller wherever their entity is known.
542
+ * That is any entity object among them, and the parameters bound to the record's field values
543
+ * (`'Entity Object Data'`), whose entity is the bound record's. Any other value then passes the
544
+ * general backstop ({@link ProjectActionParamValuesForUser}), which narrows plain objects shaped
545
+ * like a row of a field-secured entity.
546
+ */
547
+ private projectEntityActionResult(
548
+ result: EntityActionResult,
549
+ entityAction: { EntityID?: string; Params?: Array<{ ActionParamID: string; ValueType: string }> },
550
+ entityObject: BaseEntity | undefined,
551
+ user: UserInfo,
552
+ providers: Array<ProviderInfo>
553
+ ): EntityActionResult {
554
+ const provider = GetReadOnlyProvider(providers, { allowFallbackToReadWrite: true }) ?? undefined;
555
+ const binding = this.entityObjectDataBinding(entityAction, entityObject, provider);
556
+ const project = (params: ActionParam[]) =>
557
+ ProjectActionParamValuesForUser(ProjectActionParamsForCaller(params, user, provider, binding), user, provider, { UnreadableEntityObjects: 'keep' });
558
+ const projected: EntityActionResult = { ...result, Params: project(result.Params) };
559
+ if (result.RunParams) {
560
+ projected.RunParams = { ...result.RunParams, Params: project(result.RunParams.Params) };
561
+ }
562
+ return projected;
563
+ }
564
+
565
+ /** The action parameters bound as `'Entity Object Data'`, with the entity their values belong to. */
566
+ private entityObjectDataBinding(
567
+ entityAction: { EntityID?: string; Params?: Array<{ ActionParamID: string; ValueType: string }> },
568
+ entityObject: BaseEntity | undefined,
569
+ provider: IMetadataProvider | undefined
570
+ ): EntityObjectDataBinding | undefined {
571
+ const entityInfo: EntityInfo | undefined = entityObject?.EntityInfo
572
+ ?? provider?.Entities?.find(e => UUIDsEqual(e.ID, entityAction?.EntityID));
573
+ if (!entityInfo) {
574
+ return undefined;
575
+ }
576
+ const names = new Set<string>();
577
+ const dataParams = (entityAction?.Params ?? []).filter(eap => eap.ValueType === 'Entity Object Data');
578
+ const actionParamsById = dataParams.length > 0 ? IndexByUUID(ActionEngineServer.Instance.ActionParams) : null;
579
+ for (const eap of dataParams) {
580
+ const param = actionParamsById?.Get(eap.ActionParamID);
581
+ if (param?.Name) names.add(param.Name.trim().toLowerCase());
582
+ }
583
+ return names.size > 0 ? { EntityInfo: entityInfo, ParamNames: names } : undefined;
584
+ }
585
+
523
586
  /**
524
587
  * Creates a composite key from the input
525
588
  * @param entity The entity information
@@ -139,6 +139,7 @@ export class AdhocQueryResolver extends ResolverBase {
139
139
  QueryID: '',
140
140
  QueryName: 'Ad-Hoc Query',
141
141
  Success: true,
142
+ // fls-guard: query rows; the SQL is refused before it runs if it reads a field the caller is denied
142
143
  Results: JSON.stringify(result.Results),
143
144
  RowCount: result.RowCount,
144
145
  TotalRowCount: result.TotalRowCount,