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

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 (463) hide show
  1. package/README.md +69 -0
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/agentSessions/BridgeHostInstance.d.ts +8 -3
  4. package/dist/agentSessions/BridgeHostInstance.d.ts.map +1 -1
  5. package/dist/agentSessions/BridgeHostInstance.js +14 -4
  6. package/dist/agentSessions/BridgeHostInstance.js.map +1 -1
  7. package/dist/agentSessions/HandoffOfferExpiry.d.ts +10 -0
  8. package/dist/agentSessions/HandoffOfferExpiry.d.ts.map +1 -0
  9. package/dist/agentSessions/HandoffOfferExpiry.js +18 -0
  10. package/dist/agentSessions/HandoffOfferExpiry.js.map +1 -0
  11. package/dist/agentSessions/ReturningVisitorRecap.js +1 -0
  12. package/dist/agentSessions/ReturningVisitorRecap.js.map +1 -1
  13. package/dist/agentSessions/SessionJanitor.d.ts +31 -8
  14. package/dist/agentSessions/SessionJanitor.d.ts.map +1 -1
  15. package/dist/agentSessions/SessionJanitor.js +85 -41
  16. package/dist/agentSessions/SessionJanitor.js.map +1 -1
  17. package/dist/agentSessions/SessionManager.d.ts +14 -4
  18. package/dist/agentSessions/SessionManager.d.ts.map +1 -1
  19. package/dist/agentSessions/SessionManager.js +28 -4
  20. package/dist/agentSessions/SessionManager.js.map +1 -1
  21. package/dist/agentSessions/conversationBrowsers.d.ts +61 -0
  22. package/dist/agentSessions/conversationBrowsers.d.ts.map +1 -0
  23. package/dist/agentSessions/conversationBrowsers.js +118 -0
  24. package/dist/agentSessions/conversationBrowsers.js.map +1 -0
  25. package/dist/agentSessions/sessionDeadline.d.ts +43 -0
  26. package/dist/agentSessions/sessionDeadline.d.ts.map +1 -0
  27. package/dist/agentSessions/sessionDeadline.js +68 -0
  28. package/dist/agentSessions/sessionDeadline.js.map +1 -0
  29. package/dist/auth/APIKeyScopeAuth.d.ts.map +1 -1
  30. package/dist/auth/APIKeyScopeAuth.js +5 -4
  31. package/dist/auth/APIKeyScopeAuth.js.map +1 -1
  32. package/dist/auth/loginEmailResolution.d.ts +41 -0
  33. package/dist/auth/loginEmailResolution.d.ts.map +1 -0
  34. package/dist/auth/loginEmailResolution.js +47 -0
  35. package/dist/auth/loginEmailResolution.js.map +1 -0
  36. package/dist/auth/magicLink/MagicLinkKeys.d.ts +50 -2
  37. package/dist/auth/magicLink/MagicLinkKeys.d.ts.map +1 -1
  38. package/dist/auth/magicLink/MagicLinkKeys.js +129 -12
  39. package/dist/auth/magicLink/MagicLinkKeys.js.map +1 -1
  40. package/dist/auth/magicLink/MagicLinkRouter.d.ts +3 -0
  41. package/dist/auth/magicLink/MagicLinkRouter.d.ts.map +1 -1
  42. package/dist/auth/magicLink/MagicLinkRouter.js +23 -5
  43. package/dist/auth/magicLink/MagicLinkRouter.js.map +1 -1
  44. package/dist/auth/magicLink/MagicLinkService.d.ts +39 -5
  45. package/dist/auth/magicLink/MagicLinkService.d.ts.map +1 -1
  46. package/dist/auth/magicLink/MagicLinkService.js +221 -9
  47. package/dist/auth/magicLink/MagicLinkService.js.map +1 -1
  48. package/dist/auth/magicLink/index.d.ts +1 -1
  49. package/dist/auth/magicLink/index.d.ts.map +1 -1
  50. package/dist/auth/magicLink/index.js +1 -1
  51. package/dist/auth/magicLink/index.js.map +1 -1
  52. package/dist/auth/magicLink/redeemLanding.d.ts +2 -2
  53. package/dist/auth/magicLink/redeemLanding.d.ts.map +1 -1
  54. package/dist/auth/magicLink/redeemLanding.js +7 -4
  55. package/dist/auth/magicLink/redeemLanding.js.map +1 -1
  56. package/dist/auth/magicLink/types.d.ts +27 -3
  57. package/dist/auth/magicLink/types.d.ts.map +1 -1
  58. package/dist/auth/magicLink/types.js +0 -4
  59. package/dist/auth/magicLink/types.js.map +1 -1
  60. package/dist/auth/newUsers.d.ts.map +1 -1
  61. package/dist/auth/newUsers.js +1 -0
  62. package/dist/auth/newUsers.js.map +1 -1
  63. package/dist/backgroundSweepConfigUnits.d.ts +231 -0
  64. package/dist/backgroundSweepConfigUnits.d.ts.map +1 -0
  65. package/dist/backgroundSweepConfigUnits.js +180 -0
  66. package/dist/backgroundSweepConfigUnits.js.map +1 -0
  67. package/dist/broadcast/BaseCacheInvalidationBroadcastProvider.d.ts.map +1 -1
  68. package/dist/broadcast/BaseCacheInvalidationBroadcastProvider.js +2 -1
  69. package/dist/broadcast/BaseCacheInvalidationBroadcastProvider.js.map +1 -1
  70. package/dist/config.d.ts +906 -8
  71. package/dist/config.d.ts.map +1 -1
  72. package/dist/config.js +59 -0
  73. package/dist/config.js.map +1 -1
  74. package/dist/context.d.ts +2 -0
  75. package/dist/context.d.ts.map +1 -1
  76. package/dist/context.js +41 -12
  77. package/dist/context.js.map +1 -1
  78. package/dist/coreRoutes.d.ts +3 -1
  79. package/dist/coreRoutes.d.ts.map +1 -1
  80. package/dist/coreRoutes.js +6 -4
  81. package/dist/coreRoutes.js.map +1 -1
  82. package/dist/generated/graphql-schemas/__mj.d.ts +1072 -5
  83. package/dist/generated/graphql-schemas/__mj.d.ts.map +1 -1
  84. package/dist/generated/graphql-schemas/__mj.js +10174 -4618
  85. package/dist/generated/graphql-schemas/__mj.js.map +1 -1
  86. package/dist/generic/OrphanedConversationDetailReconciler.d.ts +11 -0
  87. package/dist/generic/OrphanedConversationDetailReconciler.d.ts.map +1 -1
  88. package/dist/generic/OrphanedConversationDetailReconciler.js +27 -1
  89. package/dist/generic/OrphanedConversationDetailReconciler.js.map +1 -1
  90. package/dist/generic/ResolverBase.d.ts +50 -5
  91. package/dist/generic/ResolverBase.d.ts.map +1 -1
  92. package/dist/generic/ResolverBase.js +329 -132
  93. package/dist/generic/ResolverBase.js.map +1 -1
  94. package/dist/generic/RunViewResolver.d.ts +4 -0
  95. package/dist/generic/RunViewResolver.d.ts.map +1 -1
  96. package/dist/generic/RunViewResolver.js +47 -7
  97. package/dist/generic/RunViewResolver.js.map +1 -1
  98. package/dist/globalCors.d.ts.map +1 -1
  99. package/dist/globalCors.js +1 -0
  100. package/dist/globalCors.js.map +1 -1
  101. package/dist/index.d.ts +3 -0
  102. package/dist/index.d.ts.map +1 -1
  103. package/dist/index.js +201 -43
  104. package/dist/index.js.map +1 -1
  105. package/dist/integration/ConnectionPause.d.ts +121 -0
  106. package/dist/integration/ConnectionPause.d.ts.map +1 -0
  107. package/dist/integration/ConnectionPause.js +183 -0
  108. package/dist/integration/ConnectionPause.js.map +1 -0
  109. package/dist/integration/CustomColumnPromoter.d.ts +72 -6
  110. package/dist/integration/CustomColumnPromoter.d.ts.map +1 -1
  111. package/dist/integration/CustomColumnPromoter.js +87 -46
  112. package/dist/integration/CustomColumnPromoter.js.map +1 -1
  113. package/dist/integration/EntityMapLifecycle.d.ts +78 -4
  114. package/dist/integration/EntityMapLifecycle.d.ts.map +1 -1
  115. package/dist/integration/EntityMapLifecycle.js +199 -5
  116. package/dist/integration/EntityMapLifecycle.js.map +1 -1
  117. package/dist/integration/InactiveRowWarnings.d.ts +31 -0
  118. package/dist/integration/InactiveRowWarnings.d.ts.map +1 -1
  119. package/dist/integration/InactiveRowWarnings.js +29 -0
  120. package/dist/integration/InactiveRowWarnings.js.map +1 -1
  121. package/dist/integration/ObjectNamesByID.d.ts +28 -0
  122. package/dist/integration/ObjectNamesByID.d.ts.map +1 -0
  123. package/dist/integration/ObjectNamesByID.js +87 -0
  124. package/dist/integration/ObjectNamesByID.js.map +1 -0
  125. package/dist/integration/PostRestartIntrospect.d.ts +26 -0
  126. package/dist/integration/PostRestartIntrospect.d.ts.map +1 -0
  127. package/dist/integration/PostRestartIntrospect.js +27 -0
  128. package/dist/integration/PostRestartIntrospect.js.map +1 -0
  129. package/dist/integration/RSUPostRestartProgress.d.ts +176 -0
  130. package/dist/integration/RSUPostRestartProgress.d.ts.map +1 -0
  131. package/dist/integration/RSUPostRestartProgress.js +323 -0
  132. package/dist/integration/RSUPostRestartProgress.js.map +1 -0
  133. package/dist/integration/RSUProgressBridge.d.ts +41 -2
  134. package/dist/integration/RSUProgressBridge.d.ts.map +1 -1
  135. package/dist/integration/RSUProgressBridge.js +84 -1
  136. package/dist/integration/RSUProgressBridge.js.map +1 -1
  137. package/dist/integration/RunArtifactAuthorization.d.ts +39 -0
  138. package/dist/integration/RunArtifactAuthorization.d.ts.map +1 -0
  139. package/dist/integration/RunArtifactAuthorization.js +45 -0
  140. package/dist/integration/RunArtifactAuthorization.js.map +1 -0
  141. package/dist/integration/SchemaRefreshLaunch.d.ts +9 -0
  142. package/dist/integration/SchemaRefreshLaunch.d.ts.map +1 -1
  143. package/dist/integration/SchemaRefreshLaunch.js +3 -2
  144. package/dist/integration/SchemaRefreshLaunch.js.map +1 -1
  145. package/dist/integration/ScopedFieldsForBuild.d.ts +46 -0
  146. package/dist/integration/ScopedFieldsForBuild.d.ts.map +1 -0
  147. package/dist/integration/ScopedFieldsForBuild.js +91 -0
  148. package/dist/integration/ScopedFieldsForBuild.js.map +1 -0
  149. package/dist/integration/TargetConfigGuard.d.ts +40 -0
  150. package/dist/integration/TargetConfigGuard.d.ts.map +1 -0
  151. package/dist/integration/TargetConfigGuard.js +40 -0
  152. package/dist/integration/TargetConfigGuard.js.map +1 -0
  153. package/dist/logging/StartupLogger.d.ts +50 -0
  154. package/dist/logging/StartupLogger.d.ts.map +1 -1
  155. package/dist/logging/StartupLogger.js +15 -22
  156. package/dist/logging/StartupLogger.js.map +1 -1
  157. package/dist/middleware/BaseServerMiddleware.d.ts +21 -3
  158. package/dist/middleware/BaseServerMiddleware.d.ts.map +1 -1
  159. package/dist/middleware/BaseServerMiddleware.js +4 -2
  160. package/dist/middleware/BaseServerMiddleware.js.map +1 -1
  161. package/dist/realtimeSessions/ownedRealtimeSession.d.ts.map +1 -1
  162. package/dist/realtimeSessions/ownedRealtimeSession.js +2 -3
  163. package/dist/realtimeSessions/ownedRealtimeSession.js.map +1 -1
  164. package/dist/realtimeSessions/sessionAccess.d.ts +15 -0
  165. package/dist/realtimeSessions/sessionAccess.d.ts.map +1 -1
  166. package/dist/realtimeSessions/sessionAccess.js +22 -0
  167. package/dist/realtimeSessions/sessionAccess.js.map +1 -1
  168. package/dist/realtimeWidget/WidgetSessionService.d.ts.map +1 -1
  169. package/dist/realtimeWidget/WidgetSessionService.js +2 -0
  170. package/dist/realtimeWidget/WidgetSessionService.js.map +1 -1
  171. package/dist/realtimeWidget/visitorIdentity.d.ts.map +1 -1
  172. package/dist/realtimeWidget/visitorIdentity.js +1 -0
  173. package/dist/realtimeWidget/visitorIdentity.js.map +1 -1
  174. package/dist/realtimeWidget/widgetCore.d.ts.map +1 -1
  175. package/dist/realtimeWidget/widgetCore.js +4 -7
  176. package/dist/realtimeWidget/widgetCore.js.map +1 -1
  177. package/dist/realtimeWidget/widgetGuestElevation.js +1 -0
  178. package/dist/realtimeWidget/widgetGuestElevation.js.map +1 -1
  179. package/dist/requestOrigin.d.ts +22 -0
  180. package/dist/requestOrigin.d.ts.map +1 -0
  181. package/dist/requestOrigin.js +60 -0
  182. package/dist/requestOrigin.js.map +1 -0
  183. package/dist/resolvers/AgentRunStatusPublisher.d.ts +10 -0
  184. package/dist/resolvers/AgentRunStatusPublisher.d.ts.map +1 -1
  185. package/dist/resolvers/AgentRunStatusPublisher.js +18 -2
  186. package/dist/resolvers/AgentRunStatusPublisher.js.map +1 -1
  187. package/dist/resolvers/AgentSessionResolver.d.ts.map +1 -1
  188. package/dist/resolvers/AgentSessionResolver.js +6 -2
  189. package/dist/resolvers/AgentSessionResolver.js.map +1 -1
  190. package/dist/resolvers/AutotagPipelineResolver.d.ts +1 -1
  191. package/dist/resolvers/AutotagPipelineResolver.d.ts.map +1 -1
  192. package/dist/resolvers/AutotagPipelineResolver.js +61 -16
  193. package/dist/resolvers/AutotagPipelineResolver.js.map +1 -1
  194. package/dist/resolvers/ConversationRunEventsResolver.d.ts.map +1 -1
  195. package/dist/resolvers/ConversationRunEventsResolver.js +2 -0
  196. package/dist/resolvers/ConversationRunEventsResolver.js.map +1 -1
  197. package/dist/resolvers/ExecuteRemoteOperationResolver.d.ts +6 -0
  198. package/dist/resolvers/ExecuteRemoteOperationResolver.d.ts.map +1 -1
  199. package/dist/resolvers/ExecuteRemoteOperationResolver.js +30 -7
  200. package/dist/resolvers/ExecuteRemoteOperationResolver.js.map +1 -1
  201. package/dist/resolvers/GetDataResolver.d.ts.map +1 -1
  202. package/dist/resolvers/GetDataResolver.js +34 -13
  203. package/dist/resolvers/GetDataResolver.js.map +1 -1
  204. package/dist/resolvers/InfoResolver.js +1 -1
  205. package/dist/resolvers/InfoResolver.js.map +1 -1
  206. package/dist/resolvers/IntegrationDiscoveryResolver.d.ts +401 -11
  207. package/dist/resolvers/IntegrationDiscoveryResolver.d.ts.map +1 -1
  208. package/dist/resolvers/IntegrationDiscoveryResolver.js +2690 -1305
  209. package/dist/resolvers/IntegrationDiscoveryResolver.js.map +1 -1
  210. package/dist/resolvers/MCPResolver.d.ts.map +1 -1
  211. package/dist/resolvers/MCPResolver.js +13 -2
  212. package/dist/resolvers/MCPResolver.js.map +1 -1
  213. package/dist/resolvers/QuerySystemUserResolver.d.ts +38 -1
  214. package/dist/resolvers/QuerySystemUserResolver.d.ts.map +1 -1
  215. package/dist/resolvers/QuerySystemUserResolver.js +181 -88
  216. package/dist/resolvers/QuerySystemUserResolver.js.map +1 -1
  217. package/dist/resolvers/RealtimeBridgeResolver.d.ts.map +1 -1
  218. package/dist/resolvers/RealtimeBridgeResolver.js +1 -0
  219. package/dist/resolvers/RealtimeBridgeResolver.js.map +1 -1
  220. package/dist/resolvers/RealtimeClientSessionResolver.d.ts +6 -0
  221. package/dist/resolvers/RealtimeClientSessionResolver.d.ts.map +1 -1
  222. package/dist/resolvers/RealtimeClientSessionResolver.js +36 -5
  223. package/dist/resolvers/RealtimeClientSessionResolver.js.map +1 -1
  224. package/dist/resolvers/RemoteBrowserActionResolver.d.ts +62 -10
  225. package/dist/resolvers/RemoteBrowserActionResolver.d.ts.map +1 -1
  226. package/dist/resolvers/RemoteBrowserActionResolver.js +217 -34
  227. package/dist/resolvers/RemoteBrowserActionResolver.js.map +1 -1
  228. package/dist/resolvers/RunAIAgentResolver.d.ts +24 -8
  229. package/dist/resolvers/RunAIAgentResolver.d.ts.map +1 -1
  230. package/dist/resolvers/RunAIAgentResolver.js +185 -67
  231. package/dist/resolvers/RunAIAgentResolver.js.map +1 -1
  232. package/dist/resolvers/RunAIPromptResolver.d.ts +5 -3
  233. package/dist/resolvers/RunAIPromptResolver.d.ts.map +1 -1
  234. package/dist/resolvers/RunAIPromptResolver.js +19 -18
  235. package/dist/resolvers/RunAIPromptResolver.js.map +1 -1
  236. package/dist/resolvers/RunTemplateResolver.d.ts.map +1 -1
  237. package/dist/resolvers/RunTemplateResolver.js +3 -1
  238. package/dist/resolvers/RunTemplateResolver.js.map +1 -1
  239. package/dist/resolvers/SqlLoggingConfigResolver.d.ts.map +1 -1
  240. package/dist/resolvers/SqlLoggingConfigResolver.js +7 -8
  241. package/dist/resolvers/SqlLoggingConfigResolver.js.map +1 -1
  242. package/dist/resolvers/TagGovernanceResolver.d.ts +12 -0
  243. package/dist/resolvers/TagGovernanceResolver.d.ts.map +1 -1
  244. package/dist/resolvers/TagGovernanceResolver.js +84 -0
  245. package/dist/resolvers/TagGovernanceResolver.js.map +1 -1
  246. package/dist/resolvers/TelemetryResolver.d.ts +13 -8
  247. package/dist/resolvers/TelemetryResolver.d.ts.map +1 -1
  248. package/dist/resolvers/TelemetryResolver.js +40 -9
  249. package/dist/resolvers/TelemetryResolver.js.map +1 -1
  250. package/dist/resolvers/meetingRecordingRegistration.d.ts.map +1 -1
  251. package/dist/resolvers/meetingRecordingRegistration.js +2 -0
  252. package/dist/resolvers/meetingRecordingRegistration.js.map +1 -1
  253. package/dist/resolvers/meetings/meetingMutations.d.ts.map +1 -1
  254. package/dist/resolvers/meetings/meetingMutations.js +34 -4
  255. package/dist/resolvers/meetings/meetingMutations.js.map +1 -1
  256. package/dist/rest/MediaAccessKeys.d.ts.map +1 -1
  257. package/dist/rest/MediaAccessKeys.js +6 -2
  258. package/dist/rest/MediaAccessKeys.js.map +1 -1
  259. package/dist/rest/OAuthCallbackHandler.d.ts.map +1 -1
  260. package/dist/rest/OAuthCallbackHandler.js +11 -5
  261. package/dist/rest/OAuthCallbackHandler.js.map +1 -1
  262. package/dist/rest/RealtimeRecordingHandler.d.ts +3 -3
  263. package/dist/rest/RealtimeRecordingHandler.d.ts.map +1 -1
  264. package/dist/rest/RealtimeRecordingHandler.js +2 -4
  265. package/dist/rest/RealtimeRecordingHandler.js.map +1 -1
  266. package/dist/rest/ViewOperationsHandler.d.ts.map +1 -1
  267. package/dist/rest/ViewOperationsHandler.js +2 -1
  268. package/dist/rest/ViewOperationsHandler.js.map +1 -1
  269. package/dist/rest/setupRESTEndpoints.d.ts +3 -1
  270. package/dist/rest/setupRESTEndpoints.d.ts.map +1 -1
  271. package/dist/rest/setupRESTEndpoints.js +11 -2
  272. package/dist/rest/setupRESTEndpoints.js.map +1 -1
  273. package/dist/services/DurableEntityActionTaskSubmitter.d.ts.map +1 -1
  274. package/dist/services/DurableEntityActionTaskSubmitter.js +6 -1
  275. package/dist/services/DurableEntityActionTaskSubmitter.js.map +1 -1
  276. package/dist/services/TaskGraphActionRunner.d.ts.map +1 -1
  277. package/dist/services/TaskGraphActionRunner.js +2 -26
  278. package/dist/services/TaskGraphActionRunner.js.map +1 -1
  279. package/dist/services/TaskGraphAgentRunner.d.ts +6 -0
  280. package/dist/services/TaskGraphAgentRunner.d.ts.map +1 -1
  281. package/dist/services/TaskGraphAgentRunner.js +38 -0
  282. package/dist/services/TaskGraphAgentRunner.js.map +1 -1
  283. package/dist/services/TaskGraphContinuationDeliverer.d.ts.map +1 -1
  284. package/dist/services/TaskGraphContinuationDeliverer.js +1 -0
  285. package/dist/services/TaskGraphContinuationDeliverer.js.map +1 -1
  286. package/dist/services/WorkQueueHostService.d.ts +2 -1
  287. package/dist/services/WorkQueueHostService.d.ts.map +1 -1
  288. package/dist/services/WorkQueueHostService.js +19 -4
  289. package/dist/services/WorkQueueHostService.js.map +1 -1
  290. package/dist/services/workQueueConfig.d.ts +2 -2
  291. package/dist/services/workQueueConfig.js +5 -5
  292. package/dist/services/workQueueConfig.js.map +1 -1
  293. package/dist/sharedCache.js +1 -1
  294. package/dist/sharedCache.js.map +1 -1
  295. package/dist/types.d.ts +17 -0
  296. package/dist/types.d.ts.map +1 -1
  297. package/dist/types.js.map +1 -1
  298. package/dist/util.d.ts.map +1 -1
  299. package/dist/util.js +55 -2
  300. package/dist/util.js.map +1 -1
  301. package/package.json +107 -100
  302. package/src/__tests__/APIKeyScopeAuth.test.ts +4 -8
  303. package/src/__tests__/ActiveOperations.test.ts +68 -0
  304. package/src/__tests__/AgentSessionResolver.ownership.test.ts +13 -0
  305. package/src/__tests__/AssertTargetConfigs.test.ts +75 -0
  306. package/src/__tests__/BatchApplyParity.test.ts +109 -0
  307. package/src/__tests__/BridgeHostInstance.test.ts +42 -0
  308. package/src/__tests__/CollectInactiveRowWarnings.test.ts +115 -0
  309. package/src/__tests__/ConnectionPause.test.ts +192 -0
  310. package/src/__tests__/ConnectionPauseResolver.test.ts +166 -0
  311. package/src/__tests__/ConnectionPauseSave.test.ts +143 -0
  312. package/src/__tests__/CustomColumnPromoterCompletion.test.ts +142 -0
  313. package/src/__tests__/DeleteConnectionRemovesPerConnectionCatalog.test.ts +51 -0
  314. package/src/__tests__/DetachedDiscoveryStart.test.ts +65 -0
  315. package/src/__tests__/DurableEntityActionTaskSubmitter.test.ts +73 -0
  316. package/src/__tests__/EntityMapLifecycle.rekey.test.ts +252 -0
  317. package/src/__tests__/ExecuteRemoteOperationResolver.test.ts +213 -0
  318. package/src/__tests__/HandoffOfferExpiry.test.ts +40 -0
  319. package/src/__tests__/IntegrationRunArtifactAuthorization.test.ts +126 -0
  320. package/src/__tests__/MagicLinkKeys.test.ts +102 -0
  321. package/src/__tests__/MediaAccessKeys.test.ts +57 -10
  322. package/src/__tests__/NewArrivalsDefaultDisabled.test.ts +50 -0
  323. package/src/__tests__/ObjectNamesByID.test.ts +176 -0
  324. package/src/__tests__/PostRestartMapsInCatalogScope.test.ts +146 -0
  325. package/src/__tests__/QuerySystemUserResolver.childRows.test.ts +80 -0
  326. package/src/__tests__/QuerySystemUserResolver.collision.test.ts +200 -0
  327. package/src/__tests__/QuerySystemUserResolver.permissions.test.ts +132 -0
  328. package/src/__tests__/RSUPostRestartProgress.test.ts +343 -0
  329. package/src/__tests__/RSUProgressBridge.test.ts +188 -5
  330. package/src/__tests__/RSUStartupSweepWiring.test.ts +30 -0
  331. package/src/__tests__/ReactivateRefreshMessage.test.ts +10 -3
  332. package/src/__tests__/RealtimeClientSessionResolver.test.ts +22 -0
  333. package/src/__tests__/{RefreshAdoptsNewColumns.test.ts → RefreshReportsNewColumns.test.ts} +25 -16
  334. package/src/__tests__/RemoteBrowserActionRecovery.test.ts +287 -0
  335. package/src/__tests__/RemoteBrowserActionResolver.goalRunLink.test.ts +3 -0
  336. package/src/__tests__/RemoteBrowserActionResolver.ownership.test.ts +6 -4
  337. package/src/__tests__/RemoteBrowserAudioStream.test.ts +3 -0
  338. package/src/__tests__/RemoteBrowserSnapshot.test.ts +3 -0
  339. package/src/__tests__/ResolverBase.clientOldValues.test.ts +327 -26
  340. package/src/__tests__/ResolverBase.diagnosticSenderRegistrations.test.ts +26 -0
  341. package/src/__tests__/ResolverBase.encryptedApiZeroReencrypt.test.ts +307 -0
  342. package/src/__tests__/ResolverBase.entityMessageRelay.test.ts +53 -2
  343. package/src/__tests__/ResolverBase.includeBinaryFields.test.ts +60 -0
  344. package/src/__tests__/RunAIAgentResolver.branch.test.ts +4 -0
  345. package/src/__tests__/RunAIAgentResolver.consultPredecessor.test.ts +289 -0
  346. package/src/__tests__/RunAIAgentResolver.handoff.test.ts +649 -0
  347. package/src/__tests__/RunAIAgentResolver.historyFrom.test.ts +2 -0
  348. package/src/__tests__/RunAIAgentResolver.runDataGuard.test.ts +2 -0
  349. package/src/__tests__/RunAIAgentResolver.stoppedPredecessor.test.ts +87 -12
  350. package/src/__tests__/RunAIAgentResolver.streaming.test.ts +28 -4
  351. package/src/__tests__/SchemaEvolutionCustomColumns.test.ts +119 -0
  352. package/src/__tests__/SchemaRefreshLaunch.test.ts +24 -2
  353. package/src/__tests__/ScopedFieldsForBuild.test.ts +192 -0
  354. package/src/__tests__/SessionJanitor.test.ts +195 -4
  355. package/src/__tests__/SessionManager.test.ts +69 -0
  356. package/src/__tests__/TagGovernanceAndAutotagResolvers.test.ts +261 -0
  357. package/src/__tests__/TagGovernanceResolver.test.ts +60 -2
  358. package/src/__tests__/TaskGraphActionRunner.durablePayload.test.ts +2 -2
  359. package/src/__tests__/TaskGraphAgentRunner.test.ts +272 -16
  360. package/src/__tests__/ViewOperationsHandler.test.ts +2 -5
  361. package/src/__tests__/WorkQueueHostService.test.ts +25 -7
  362. package/src/__tests__/backgroundSweepConfigUnits.test.ts +153 -0
  363. package/src/__tests__/contextRequestOrigin.test.ts +105 -0
  364. package/src/__tests__/conversationBrowsers.test.ts +62 -0
  365. package/src/__tests__/globalCors.test.ts +12 -0
  366. package/src/__tests__/magicLinkExtensionCapabilities.test.ts +413 -0
  367. package/src/__tests__/orphanedConversationDetailReconciler.start.test.ts +82 -0
  368. package/src/__tests__/ownedRealtimeSession.test.ts +14 -0
  369. package/src/__tests__/realtimeRecordingHandler.test.ts +7 -2
  370. package/src/__tests__/realtimeSessions/sessionAccess.test.ts +79 -1
  371. package/src/__tests__/requestOrigin.test.ts +104 -0
  372. package/src/__tests__/review-capture-valid-token-log.test.ts +98 -0
  373. package/src/__tests__/runStreams.fieldSecurity.test.ts +5 -5
  374. package/src/__tests__/securityHardeningPr6034.test.ts +120 -0
  375. package/src/__tests__/sessionDeadline.test.ts +51 -0
  376. package/src/__tests__/sharedCache.test.ts +11 -0
  377. package/src/__tests__/unifiedAuth.test.ts +73 -1
  378. package/src/agentSessions/BridgeHostInstance.ts +20 -5
  379. package/src/agentSessions/HandoffOfferExpiry.ts +18 -0
  380. package/src/agentSessions/ReturningVisitorRecap.ts +1 -0
  381. package/src/agentSessions/SessionJanitor.ts +92 -42
  382. package/src/agentSessions/SessionManager.ts +38 -8
  383. package/src/agentSessions/conversationBrowsers.ts +143 -0
  384. package/src/agentSessions/sessionDeadline.ts +81 -0
  385. package/src/auth/APIKeyScopeAuth.ts +5 -4
  386. package/src/auth/__tests__/loginEmailResolution.test.ts +67 -0
  387. package/src/auth/loginEmailResolution.ts +67 -0
  388. package/src/auth/magicLink/MagicLinkKeys.ts +146 -14
  389. package/src/auth/magicLink/MagicLinkRouter.ts +33 -6
  390. package/src/auth/magicLink/MagicLinkService.ts +250 -10
  391. package/src/auth/magicLink/index.ts +1 -1
  392. package/src/auth/magicLink/redeemLanding.ts +7 -4
  393. package/src/auth/magicLink/types.ts +28 -3
  394. package/src/auth/newUsers.ts +1 -0
  395. package/src/backgroundSweepConfigUnits.ts +213 -0
  396. package/src/broadcast/BaseCacheInvalidationBroadcastProvider.ts +2 -1
  397. package/src/config.ts +69 -0
  398. package/src/context.ts +46 -15
  399. package/src/coreRoutes.ts +14 -7
  400. package/src/generated/graphql-schemas/__mj.ts +10360 -6479
  401. package/src/generic/OrphanedConversationDetailReconciler.ts +32 -1
  402. package/src/generic/ResolverBase.ts +422 -143
  403. package/src/generic/RunViewResolver.ts +96 -49
  404. package/src/globalCors.ts +1 -0
  405. package/src/index.ts +246 -44
  406. package/src/integration/ConnectionPause.ts +222 -0
  407. package/src/integration/CustomColumnPromoter.ts +123 -53
  408. package/src/integration/EntityMapLifecycle.ts +229 -6
  409. package/src/integration/InactiveRowWarnings.ts +50 -0
  410. package/src/integration/ObjectNamesByID.ts +97 -0
  411. package/src/integration/PostRestartIntrospect.ts +49 -0
  412. package/src/integration/RSUPostRestartProgress.ts +359 -0
  413. package/src/integration/RSUProgressBridge.ts +85 -2
  414. package/src/integration/RunArtifactAuthorization.ts +65 -0
  415. package/src/integration/SchemaRefreshLaunch.ts +12 -2
  416. package/src/integration/ScopedFieldsForBuild.ts +113 -0
  417. package/src/integration/TargetConfigGuard.ts +71 -0
  418. package/src/logging/StartupLogger.ts +24 -0
  419. package/src/middleware/BaseServerMiddleware.ts +20 -3
  420. package/src/realtimeSessions/ownedRealtimeSession.ts +2 -6
  421. package/src/realtimeSessions/sessionAccess.ts +30 -0
  422. package/src/realtimeWidget/WidgetSessionService.ts +2 -0
  423. package/src/realtimeWidget/visitorIdentity.ts +1 -0
  424. package/src/realtimeWidget/widgetCore.ts +4 -8
  425. package/src/realtimeWidget/widgetGuestElevation.ts +1 -0
  426. package/src/requestOrigin.ts +64 -0
  427. package/src/resolvers/AgentRunStatusPublisher.ts +27 -2
  428. package/src/resolvers/AgentSessionResolver.ts +6 -2
  429. package/src/resolvers/AutotagPipelineResolver.ts +59 -14
  430. package/src/resolvers/ConversationRunEventsResolver.ts +2 -0
  431. package/src/resolvers/ExecuteRemoteOperationResolver.ts +41 -9
  432. package/src/resolvers/GetDataResolver.ts +35 -13
  433. package/src/resolvers/InfoResolver.ts +1 -1
  434. package/src/resolvers/IntegrationDiscoveryResolver.ts +1522 -203
  435. package/src/resolvers/MCPResolver.ts +15 -2
  436. package/src/resolvers/QuerySystemUserResolver.ts +211 -100
  437. package/src/resolvers/RealtimeBridgeResolver.ts +1 -0
  438. package/src/resolvers/RealtimeClientSessionResolver.ts +40 -7
  439. package/src/resolvers/RemoteBrowserActionResolver.ts +242 -32
  440. package/src/resolvers/RunAIAgentResolver.ts +265 -86
  441. package/src/resolvers/RunAIPromptResolver.ts +18 -18
  442. package/src/resolvers/RunTemplateResolver.ts +3 -1
  443. package/src/resolvers/SqlLoggingConfigResolver.ts +7 -9
  444. package/src/resolvers/TagGovernanceResolver.ts +65 -0
  445. package/src/resolvers/TelemetryResolver.ts +44 -9
  446. package/src/resolvers/__tests__/GetDataResolver.tokens.test.ts +52 -0
  447. package/src/resolvers/meetingRecordingRegistration.ts +2 -0
  448. package/src/resolvers/meetings/meetingMutations.ts +37 -7
  449. package/src/rest/MediaAccessKeys.ts +6 -2
  450. package/src/rest/OAuthCallbackHandler.ts +13 -5
  451. package/src/rest/RealtimeRecordingHandler.ts +5 -9
  452. package/src/rest/ViewOperationsHandler.ts +2 -1
  453. package/src/rest/setupRESTEndpoints.ts +11 -2
  454. package/src/services/DurableEntityActionTaskSubmitter.ts +10 -2
  455. package/src/services/TaskGraphActionRunner.ts +2 -23
  456. package/src/services/TaskGraphAgentRunner.ts +43 -0
  457. package/src/services/TaskGraphContinuationDeliverer.ts +1 -0
  458. package/src/services/WorkQueueHostService.ts +26 -4
  459. package/src/services/workQueueConfig.ts +5 -5
  460. package/src/sharedCache.ts +1 -1
  461. package/src/types.ts +18 -0
  462. package/src/util.ts +55 -3
  463. package/src/services/TaskOrchestration-Integration.md +0 -188
package/src/index.ts CHANGED
@@ -4,13 +4,16 @@ dotenv.config({ quiet: true });
4
4
 
5
5
  import { expressMiddleware } from '@as-integrations/express5';
6
6
  import { mergeSchemas } from '@graphql-tools/schema';
7
- import { Metadata, DatabasePlatform, SetProvider, StartupManager as StartupManagerImport, BaseEntity, BaseEntityEvent, RunView, DatabaseProviderBase, ProviderBase, ResolveStartupMode, UserInfo } from '@memberjunction/core';
8
- import { UserCache, resolveDbPlatformFromEnv } from '@memberjunction/generic-database-provider';
7
+ import { Metadata, DatabasePlatform, SetProvider, StartupManager as StartupManagerImport, BaseEntity, BaseEntityEvent, RunView, DatabaseProviderBase, ProviderBase, ResolveStartupMode, UserInfo, GetDiagnosticContext, IsDiagnosticCaptureSuppressed } from '@memberjunction/core';
8
+ import { UserCache, resolveDbPlatformFromEnv, GenericDatabaseProvider, SummarizeSqlParameters } from '@memberjunction/generic-database-provider';
9
9
  import { MJGlobal, MJEventType, UUIDsEqual, ShutdownRegistry } from '@memberjunction/global';
10
10
  import { setupSQLServerClient, SQLServerDataProvider, SQLServerProviderConfigData } from '@memberjunction/sqlserver-dataprovider';
11
11
  import { extendConnectionPoolWithQuery } from './util.js';
12
12
  import { registerIntegrationCustomColumnPromoter, IntegrationCustomColumnPromoter } from './integration/CustomColumnPromoter.js';
13
13
  import { DisableUnselectedEntityMaps, ReenableFieldMapsForEntityMap, selectFieldsToMap } from './integration/EntityMapLifecycle.js';
14
+ import { RSUPostRestartProgressSession } from './integration/RSUPostRestartProgress.js';
15
+ import type { RSUPostRestartProgress } from './integration/RSUPostRestartProgress.js';
16
+ import { IntrospectInCatalogScope } from './integration/PostRestartIntrospect.js';
14
17
  import { default as BodyParser } from 'body-parser';
15
18
  import compression from 'compression'; // Add compression middleware
16
19
  import cors from 'cors';
@@ -31,7 +34,8 @@ import sql from 'mssql';
31
34
  import { WebSocketServer } from 'ws';
32
35
  import { RealtimeProxyServer } from './realtimeProxy/RealtimeProxyServer.js';
33
36
  import buildApolloServer from './apolloServer/index.js';
34
- import { configInfo, configFilePath, dbDatabase, dbHost, dbPort, dbUsername, graphqlPort, graphqlRootPath, mj_core_schema, websiteRunFromPackage, RESTApiOptions } from './config.js';
37
+ import { configInfo, configFilePath, dbDatabase, dbHost, dbPort, dbUsername, graphqlPort, graphqlRootPath, mj_core_schema, websiteRunFromPackage, RESTApiOptions, userEmailMap } from './config.js';
38
+ import { DescribeUserEmailMap } from './auth/loginEmailResolution.js';
35
39
  import { TranslateBracketsToPG } from './postgresqlCompat.js';
36
40
  import { BuildPostgreSQLConnectionConfig, DescribeReadOnlyLoginOverreach, PostgreSQLReadOnlyPool, ResolvePostgreSQLEndpoint, ResolvePostgreSQLReadOnlyCredentials, ToPGPoolConfig } from './postgresqlPoolSettings.js';
37
41
  import { default as jwt } from 'jsonwebtoken';
@@ -46,7 +50,7 @@ import createMSSQLConfig from './orm.js';
46
50
  import { setupRESTEndpoints } from './rest/setupRESTEndpoints.js';
47
51
  import { CreateRealtimeRecordingRouter, REALTIME_RECORDING_MOUNT_PATH } from './rest/RealtimeRecordingHandler.js';
48
52
  import { LoadOwnedRealtimeSession } from './realtimeSessions/ownedRealtimeSession.js';
49
- import { AuthorizeAnonymousRoomSessions, LoadSessionConversationScope } from './realtimeSessions/sessionAccess.js';
53
+ import { AuthorizeAnonymousRoomSessions, AuthorizeLoadedSession } from './realtimeSessions/sessionAccess.js';
50
54
  import { RecordingAssemblyScheduler } from './realtimeSessions/RecordingAssemblyScheduler.js';
51
55
  import {
52
56
  RealtimeSessionEventService,
@@ -66,7 +70,7 @@ import { ActionEngineServer } from '@memberjunction/actions';
66
70
  import { CreateAdhocSQLAuthorizer } from './resolvers/AdhocQueryResolver.js';
67
71
  import { CacheManagerConfigFromSettings, CreateSharedCacheFromEnvironment, StartEngineSweeper, StartMetadataSweep, StartUserCacheChecks, WarmupLeaseMsFromSettings, WirePushStatusFanOut, WireSharedCacheEvents } from './sharedCache.js';
68
72
  import { PubSubManager } from './generic/PubSubManager.js';
69
- import { ReconcileOrphanedConversationDetails } from './generic/OrphanedConversationDetailReconciler.js';
73
+ import { StartOrphanedConversationDetailReconciler } from './generic/OrphanedConversationDetailReconciler.js';
70
74
  import {
71
75
  HANDOFF_OFFER_FANOUT_CHANNEL,
72
76
  HANDOFF_OFFER_TOPIC,
@@ -82,6 +86,7 @@ import { PublishIntegrationProgress } from './resolvers/IntegrationProgressResol
82
86
  import { RegisterRSUProgressBridge } from './integration/RSUProgressBridge.js';
83
87
  import { ClientToolRequestManager, AgentRunWatchdog, SqlRealtimeRecordingLedger } from '@memberjunction/ai-agents';
84
88
  import { BindBridgeEngineHostInstance, SessionJanitor, SetHostInstancePort, StartBridgeOrphanReconciliation } from './agentSessions/index.js';
89
+ import { ApplyHandoffOfferExpirySettings } from './agentSessions/HandoffOfferExpiry.js';
85
90
  import { StartTaskGraphDispatcher } from './services/StartTaskGraphDispatcher.js';
86
91
  import { MJServerWorkQueueProviderSource, StartWorkQueueHost } from './services/WorkQueueHostService.js';
87
92
  import { GetAttachmentService } from '@memberjunction/aiengine';
@@ -96,7 +101,20 @@ import {
96
101
  MJCompanyIntegrationFieldMapEntity,
97
102
  MJScheduledJobEntity,
98
103
  } from '@memberjunction/core-entities';
99
- import { ServerExtensionLoader, ServerExtensionConfig, mergeServerExtensionConfigs, prepareServerExtensionConfigs, describeServerExtensionMount, InstallMediaUpgradeDispatcher, IsGraphQLWsPath, GetCorsOwningServerExtensionRoots } from '@memberjunction/server-extensions-core';
104
+ import {
105
+ ServerExtensionLoader,
106
+ ServerExtensionConfig,
107
+ SERVER_EXTENSION_CORE_SERVICE_KEYS,
108
+ type IServerExtensionHostRuntimeService,
109
+ mergeServerExtensionConfigs,
110
+ prepareServerExtensionConfigs,
111
+ describeServerExtensionMount,
112
+ InstallMediaUpgradeDispatcher,
113
+ IsGraphQLWsPath,
114
+ GetCorsOwningServerExtensionRoots,
115
+ } from '@memberjunction/server-extensions-core';
116
+ import { CreateIsolatedProvider } from './isolatedProvider.js';
117
+ import { ResolveConfiguredPrincipal } from './auth/principals.js';
100
118
  import { CreateExtensionOwnedPreflightFallback, CreateGlobalCorsMiddleware } from './globalCors.js';
101
119
  import { CoreReservedServerExtensionRoots } from './serverExtensionReservedRoots.js';
102
120
  import { ApiRoute, ApiRootPath, ConfiguredPublicUrl } from './apiRoot.js';
@@ -158,6 +176,7 @@ export * from './directives/index.js';
158
176
  export { NoLog, hasNoLogParameter, getNoLogFields } from './logging/NoLog.js';
159
177
  export * from './entitySubclasses/MJEntityPermissionEntityServer.server.js';
160
178
  export * from './types.js';
179
+ export * from './requestOrigin.js';
161
180
  export {
162
181
  getSystemUser,
163
182
  getSigningKeys,
@@ -280,10 +299,11 @@ export * from './multiTenancy/index.js';
280
299
  export * from './middleware/index.js';
281
300
 
282
301
  import { RegisterDataHook } from '@memberjunction/core';
302
+ import { EnsureAnchoredConversationReadHookRegistered } from '@memberjunction/core-entities-server';
283
303
  import type { RequestHandler, ErrorRequestHandler } from 'express';
284
304
  import type { ApolloServerPlugin } from '@apollo/server';
285
305
  import type { GraphQLSchema } from 'graphql';
286
- import { BaseServerMiddleware } from './middleware/BaseServerMiddleware.js';
306
+ import { BaseServerMiddleware, ServerMiddlewareContext } from './middleware/BaseServerMiddleware.js';
287
307
  import { SuppressTaskGraphSubmission } from '@memberjunction/ai-core-plus';
288
308
 
289
309
  export type MJServerOptions = {
@@ -338,8 +358,6 @@ function resolveServerVersion(): string | undefined {
338
358
  }
339
359
  }
340
360
 
341
- /** How often to re-check for conversation details left behind by finished runs. */
342
- const ORPHAN_DETAIL_SWEEP_INTERVAL_MS = 5 * 60_000;
343
361
 
344
362
  /**
345
363
  * Replicate handoff-offer updates across server instances over Redis.
@@ -482,7 +500,8 @@ const setupComplete$ = new ReplaySubject(1);
482
500
  await WirePushStatusFanOut(sharedCache);
483
501
  await wireHandoffOfferFanOut(sharedCache, startupLog);
484
502
  await wireRealtimeSessionEventFanOut(sharedCache);
485
- startupLog.LogIf('verbose', `Redis cache provider connected: ${process.env.REDIS_URL}`);
503
+ const safeRedisUrl = (process.env.REDIS_URL ?? '').replace(/:\/\/[^@]+@/, '://***@');
504
+ startupLog.LogIf('verbose', `Redis cache provider connected: ${safeRedisUrl}`);
486
505
  }
487
506
  const cacheManagerConfig = CacheManagerConfigFromSettings(configInfo.cacheSettings);
488
507
  const warmupLeaseMs = WarmupLeaseMsFromSettings(configInfo.cacheSettings);
@@ -579,8 +598,38 @@ const setupComplete$ = new ReplaySubject(1);
579
598
  const thePgPool = poolAny._pgPool as import('pg').Pool;
580
599
  // Translate SQL Server bracket syntax to PostgreSQL double-quote syntax
581
600
  const pgQuery = TranslateBracketsToPG(query);
582
- const result = await thePgPool.query(pgQuery);
583
- return result.rows;
601
+ const startTime = performance.now();
602
+ try {
603
+ const result = await thePgPool.query(pgQuery);
604
+ if (!IsDiagnosticCaptureSuppressed() && GenericDatabaseProvider.HasSqlObservers()) {
605
+ GenericDatabaseProvider.NotifySqlObservers({
606
+ ts: Date.now(),
607
+ sql: pgQuery,
608
+ parameterSummaries: SummarizeSqlParameters(parameters),
609
+ durationMs: performance.now() - startTime,
610
+ rowCount: result.rows?.length ?? 0,
611
+ isMutation: false,
612
+ description: 'ExecuteSQLWithPool(PG)',
613
+ diagnosticContext: GetDiagnosticContext(),
614
+ });
615
+ }
616
+ return result.rows;
617
+ } catch (err) {
618
+ if (!IsDiagnosticCaptureSuppressed() && GenericDatabaseProvider.HasSqlObservers()) {
619
+ GenericDatabaseProvider.NotifySqlObservers({
620
+ ts: Date.now(),
621
+ sql: pgQuery,
622
+ parameterSummaries: SummarizeSqlParameters(parameters),
623
+ durationMs: performance.now() - startTime,
624
+ rowCount: 0,
625
+ isMutation: false,
626
+ errorMessage: err instanceof Error ? err.message : String(err),
627
+ description: 'ExecuteSQLWithPool(PG)',
628
+ diagnosticContext: GetDiagnosticContext(),
629
+ });
630
+ }
631
+ throw err;
632
+ }
584
633
  }
585
634
  return origExecuteSQLWithPool.call(this, pool, query, parameters, contextUser);
586
635
  };
@@ -611,10 +660,19 @@ const setupComplete$ = new ReplaySubject(1);
611
660
  codegenTestClient.release();
612
661
 
613
662
  const { RuntimeSchemaManager } = await import('@memberjunction/schema-engine');
663
+ // Adopt the already-loaded global Metadata.Provider catalog (ignoreExistingMetadata = false)
664
+ // so boot does not pay a second full metadata load. The refresh interval stays non-zero on
665
+ // PostgreSQL on purpose: PostgreSQLDataProvider.AllowRefresh is `CheckRefreshIntervalSeconds > 0`,
666
+ // so an interval of 0 would make every later codegenPgProvider.Refresh() — the one RSU CodeGen
667
+ // issues after DDL — return without reloading, leaving this provider frozen at the boot catalog.
668
+ // (SQL Server's AllowRefresh is independent of the interval, so its codegen provider can use 0.)
614
669
  const codegenPgConfigData = new PostgreSQLProviderConfigData(
615
670
  codegenPgConnectionConfig,
616
671
  mj_core_schema,
617
672
  cacheRefreshInterval / 1000, // ms → seconds
673
+ undefined,
674
+ undefined,
675
+ false,
618
676
  );
619
677
  const codegenPgProvider = new PostgreSQLDataProvider();
620
678
  await codegenPgProvider.Config(codegenPgConfigData); // separate pool (per-instance manager); does NOT touch the global API provider
@@ -762,8 +820,18 @@ const setupComplete$ = new ReplaySubject(1);
762
820
  await codegenPool.connect();
763
821
 
764
822
  const { RuntimeSchemaManager } = await import('@memberjunction/schema-engine');
765
- // Same ms→seconds seam as the main provider config above — see providerConfigUnits.ts
766
- const codegenConfig = new SQLServerProviderConfigData(codegenPool, mj_core_schema, MetadataCacheRefreshIntervalSeconds(cacheRefreshInterval));
823
+ // Adopt the already-loaded global Metadata.Provider catalog (ignoreExistingMetadata = false)
824
+ // and disable a duplicate background refresh timer (0): avoids a second full metadata load
825
+ // on boot while explicit codegenProvider.Refresh() after DDL still reloads from the DB
826
+ // (SQLServerDataProvider.AllowRefresh does not depend on the interval; PostgreSQL's does — see above).
827
+ const codegenConfig = new SQLServerProviderConfigData(
828
+ codegenPool,
829
+ mj_core_schema,
830
+ 0,
831
+ undefined,
832
+ undefined,
833
+ false,
834
+ );
767
835
  const codegenProvider = new SQLServerDataProvider();
768
836
  await codegenProvider.Config(codegenConfig);
769
837
  RuntimeSchemaManager.Instance.SetDDLProvider(codegenProvider);
@@ -946,8 +1014,9 @@ const setupComplete$ = new ReplaySubject(1);
946
1014
  }
947
1015
 
948
1016
  // Initialize all middleware
1017
+ const middlewareContext: ServerMiddlewareContext = { ApiRoute: (subpath, options) => ApiRoute(subpath, options) };
949
1018
  for (const mw of middlewares) {
950
- await mw.Initialize();
1019
+ await mw.Initialize(middlewareContext);
951
1020
  startupLog.LogIf('verbose', ` [Middleware] ${mw.Label}`);
952
1021
  }
953
1022
 
@@ -969,7 +1038,7 @@ const setupComplete$ = new ReplaySubject(1);
969
1038
 
970
1039
  // Express app configuration escape hatch
971
1040
  if (mw.ConfigureExpressApp) {
972
- await mw.ConfigureExpressApp(app);
1041
+ await mw.ConfigureExpressApp(app, middlewareContext);
973
1042
  }
974
1043
 
975
1044
  // Extract hook methods and register in the global hook store
@@ -978,6 +1047,7 @@ const setupComplete$ = new ReplaySubject(1);
978
1047
  RegisterDataHook('PostRunView', mw.PostRunView.bind(mw));
979
1048
  RegisterDataHook('PreSave', mw.PreSave.bind(mw));
980
1049
  }
1050
+ EnsureAnchoredConversationReadHookRegistered();
981
1051
 
982
1052
  // ─── Resolve middleware-contributed resolver paths and merge into resolvers ───
983
1053
  let allResolvers = resolvers;
@@ -1270,6 +1340,7 @@ const setupComplete$ = new ReplaySubject(1);
1270
1340
  },
1271
1341
  // context() now just reads the already-validated payload — no I/O, no logging
1272
1342
  context: async (ctx) => {
1343
+ // No RequestOrigin here: the upgrade request's Origin is not carried onto subscription contexts.
1273
1344
  return { userPayload: ctx.extra.userPayload as UserPayload };
1274
1345
  },
1275
1346
  onClose: (ctx) => {
@@ -1319,7 +1390,7 @@ const setupComplete$ = new ReplaySubject(1);
1319
1390
  },
1320
1391
  // High compression level (good balance between CPU and compression ratio)
1321
1392
  level: 6
1322
- }));
1393
+ }) as object as express.RequestHandler);
1323
1394
 
1324
1395
  // Health check — before every middleware contribution and the auth middleware, so cloud platform
1325
1396
  // probes never generate auth noise. Every core route mounts under MJAPI_BASE_PATH (see apiRoot.ts).
@@ -1343,6 +1414,19 @@ const setupComplete$ = new ReplaySubject(1);
1343
1414
  const extensionLoader = new ServerExtensionLoader();
1344
1415
  _currentExtensionLoader = extensionLoader;
1345
1416
 
1417
+ const hostRuntimeService: IServerExtensionHostRuntimeService = {
1418
+ CreateIsolatedProvider,
1419
+ GetSystemUser: () => getSystemUser(),
1420
+ ResolvePrincipal: (configuredEmailOrId, subsystemLabel) => ResolveConfiguredPrincipal(configuredEmailOrId, subsystemLabel),
1421
+ };
1422
+ extensionLoader.Services.RegisterService(SERVER_EXTENSION_CORE_SERVICE_KEYS.HostRuntime, hostRuntimeService);
1423
+ if (coreAuthenticatedRouters.MagicLinkService) {
1424
+ extensionLoader.Services.RegisterService(
1425
+ SERVER_EXTENSION_CORE_SERVICE_KEYS.MagicLink,
1426
+ coreAuthenticatedRouters.MagicLinkService,
1427
+ );
1428
+ }
1429
+
1346
1430
  // Open App packages publish their extensions; host mj.config.cjs overlays by DriverClass
1347
1431
  // Backwards-compatibility shim: synthesize ServerExtensionConfig entries from legacy configInfo.telephony
1348
1432
  const telephonyExtensionConfigs: ServerExtensionConfig[] = [];
@@ -1457,6 +1541,11 @@ const setupComplete$ = new ReplaySubject(1);
1457
1541
  MountAuthCatalogRoute(app, startupLog);
1458
1542
 
1459
1543
  // ─── Unified auth middleware (replaces both REST authMiddleware and contextFunction auth) ─────
1544
+ // Always shown, whatever the log level: a configured map makes logins run as other people's records
1545
+ const userEmailMapWarning = DescribeUserEmailMap(userEmailMap);
1546
+ if (userEmailMapWarning) {
1547
+ console.warn(userEmailMapWarning);
1548
+ }
1460
1549
  app.use(CreateUnifiedAuthMiddleware(dataSources));
1461
1550
 
1462
1551
  // ─── Post-auth middleware from BaseServerMiddleware plugins ─────
@@ -1551,7 +1640,7 @@ const setupComplete$ = new ReplaySubject(1);
1551
1640
  app.use(
1552
1641
  graphqlRootPath,
1553
1642
  cors<cors.CorsRequest>({
1554
- exposedHeaders: ['X-MJ-Cache-Seq', 'X-MJ-Server-ID'],
1643
+ exposedHeaders: ['X-MJ-Cache-Seq', 'X-MJ-Server-ID', 'X-MJ-Trace-ID', 'X-MJ-Diagnostic-Trigger'],
1555
1644
  }),
1556
1645
  BodyParser.json({ limit: '50mb' }),
1557
1646
  // Express 5 leaves req.body as undefined for non-JSON or empty bodies;
@@ -1593,6 +1682,11 @@ const setupComplete$ = new ReplaySubject(1);
1593
1682
  LogStatus(`[ServerRole] Running in '${serverRole}' mode — background worker services are disabled on this replica.`);
1594
1683
  }
1595
1684
 
1685
+ // Every role runs agents, so every role's watchdog takes the configured intervals (before any run starts).
1686
+ AgentRunWatchdog.Instance.Configure(configInfo.agentRunWatchdog);
1687
+ // The handoff offer registry starts its own expiry sweep when it loads, on every role; apply the host's setting.
1688
+ ApplyHandoffOfferExpirySettings(configInfo.agentSessions.handoffOfferExpiry);
1689
+
1596
1690
  // Close out run artifacts a dead process left open, BEFORE anything below can start a new run.
1597
1691
  //
1598
1692
  // A killed process (OOM killer, SIGKILL, host reboot) never writes its run's terminal result, so
@@ -1602,7 +1696,17 @@ const setupComplete$ = new ReplaySubject(1);
1602
1696
  // to a process that no longer exists. That is why it runs here, ahead of the scheduler, the
1603
1697
  // integration sync worker (its Start() polls immediately), the HTTP listener (a request can
1604
1698
  // start a discovery) and pending RSU work, and why it is awaited. It needs none of them.
1605
- await SweepInterruptedRuns(undefined, msg => console.warn(msg));
1699
+ //
1700
+ // One exception: an RSU run killed inside its own RestartMJAPI step is not dead — THIS process is
1701
+ // its continuation, and processRSUPendingWork below re-attaches to it. Those are left in flight
1702
+ // (and named in `Skipped`); whichever of them nothing re-attaches to is closed out afterwards by
1703
+ // RSUPostRestartProgressSession.SweepUnattached. On a replica that runs no background workers
1704
+ // nothing would ever resume them, so there they are swept like any other.
1705
+ const bootSweep = await SweepInterruptedRuns(
1706
+ undefined,
1707
+ msg => console.warn(msg),
1708
+ runBackgroundWorkers ? RSUPostRestartProgressSession.WasKilledAtRestart : undefined
1709
+ );
1606
1710
 
1607
1711
  // Initialize and start scheduled jobs service if enabled
1608
1712
  let scheduledJobsService: ScheduledJobsService | null = null;
@@ -1662,7 +1766,12 @@ const setupComplete$ = new ReplaySubject(1);
1662
1766
 
1663
1767
  if (runBackgroundWorkers) {
1664
1768
  // Process pending RSU work from pre-restart (entity maps, field maps, sync)
1665
- processRSUPendingWork().catch(err => console.warn(`RSU pending work processing failed: ${err}`));
1769
+ processRSUPendingWork().catch(err => console.warn(`RSU pending work processing failed: ${err}`))
1770
+ .finally(() =>
1771
+ RSUPostRestartProgressSession.SweepUnattached(bootSweep.Skipped, undefined, msg => console.warn(msg)).catch(err =>
1772
+ console.warn(`RSU leftover run sweep failed: ${err}`)
1773
+ )
1774
+ );
1666
1775
 
1667
1776
  // Resume any integration syncs that were orphaned by the previous process restart
1668
1777
  if (resumeUser) {
@@ -1677,23 +1786,15 @@ const setupComplete$ = new ReplaySubject(1);
1677
1786
  if (resumeUser && Metadata.Provider instanceof DatabaseProviderBase) { // global-provider-ok: server startup recovery — one-shot orphaned-run sweep at boot
1678
1787
  const sweepUser = resumeUser;
1679
1788
  const sweepProvider = Metadata.Provider; // global-provider-ok: server startup recovery — one-shot orphaned-run sweep at boot
1680
- AgentRunWatchdog.SweepOrphanedRuns(sweepProvider, sweepUser)
1789
+ AgentRunWatchdog.SweepOrphanedRuns(sweepProvider, sweepUser, configInfo.agentRunWatchdog)
1681
1790
  .catch(err => console.warn(`[AgentRunWatchdog] Startup sweep failed: ${err}`));
1682
1791
 
1683
1792
  // The watchdog repairs the RUN; nothing repaired the conversation detail, which is the row the
1684
1793
  // chat actually renders from (MJ #4222). A process that dies mid-run leaves a terminal run
1685
1794
  // beside a message that still claims to be generating, and it spins forever for anyone who
1686
- // opens it. Runs at boot (closes restart orphans) and on a timer (closes mid-life orphans),
1687
- // mirroring the watchdog's own two-phase shape.
1688
- const reconcileOrphans = () =>
1689
- ReconcileOrphanedConversationDetails(sweepProvider, sweepUser)
1690
- .catch(err => console.warn(`[OrphanDetailReconciler] Pass failed: ${err}`));
1691
- void reconcileOrphans();
1692
- const orphanDetailTimer = setInterval(() => void reconcileOrphans(), ORPHAN_DETAIL_SWEEP_INTERVAL_MS);
1693
- ShutdownRegistry.Instance.Register({
1694
- ShutdownName: 'OrphanDetailReconciler',
1695
- Shutdown: () => { clearInterval(orphanDetailTimer); },
1696
- });
1795
+ // opens it. Runs at boot (closes restart orphans) and, unless `conversationDetailReconciler.enabled`
1796
+ // is false, on a timer (closes mid-life orphans), mirroring the watchdog's own two-phase shape.
1797
+ StartOrphanedConversationDetailReconciler(sweepProvider, sweepUser, configInfo.conversationDetailReconciler);
1697
1798
  }
1698
1799
 
1699
1800
  // Launch the AI Agent Session janitor: run own-host orphan recovery once at boot, then a periodic tick
@@ -1701,11 +1802,12 @@ const setupComplete$ = new ReplaySubject(1);
1701
1802
  // crash-recovery shards (storage reads and writes). Self-registers with ShutdownRegistry, so its timer
1702
1803
  // is cleared by the gracefulShutdown drain below (no explicit Stop() wiring needed here).
1703
1804
  if (resumeUser && Metadata.Provider instanceof DatabaseProviderBase) { // global-provider-ok: server startup recovery — boot-time session janitor uses the server's own provider
1704
- SessionJanitor.Instance.Start(Metadata.Provider, resumeUser) // global-provider-ok: server-owned background reconciler runs under the server's provider + system user
1805
+ // `agentSessions.janitor.enabled: false` keeps the boot recovery and shutdown drain but schedules no tick.
1806
+ SessionJanitor.Instance.StartWithSettings(configInfo.agentSessions.janitor, Metadata.Provider, resumeUser) // global-provider-ok: server-owned background reconciler runs under the server's provider + system user
1705
1807
  .catch(err => console.warn(`[SessionJanitor] Startup failed: ${err}`));
1706
1808
  // The bridge engine's orphan reconcile likewise starts only now that this process holds its port, so it can't
1707
1809
  // take the live bridges of another MJAPI still serving that port for its own orphans (#5310).
1708
- StartBridgeOrphanReconciliation(Metadata.Provider, resumeUser); // global-provider-ok: server-owned background reconciler runs under the server's provider + system user
1810
+ StartBridgeOrphanReconciliation(Metadata.Provider, resumeUser, configInfo.agentSessions.bridgeReconciler); // global-provider-ok: server-owned background reconciler runs under the server's provider + system user
1709
1811
  }
1710
1812
  }
1711
1813
 
@@ -1908,9 +2010,18 @@ async function processRSUPendingWork(): Promise<void> {
1908
2010
  // Wait a moment for metadata to be fully loaded
1909
2011
  await new Promise(resolve => setTimeout(resolve, 3000));
1910
2012
 
2013
+ // The RSU run these items belong to is still open: the pre-restart process was killed inside its
2014
+ // own RestartMJAPI step, so it never wrote a terminal result. This session re-attaches to that run
2015
+ // and reports the two steps that only ever happen here — CreateEntityMaps and StartSync — into the
2016
+ // SAME event stream, so a client that has been tailing since before the restart keeps its cursor
2017
+ // and finally learns whether the connector went live. Purely observational: every failure below is
2018
+ // swallowed, and the work proceeds whether or not a run was found to report into.
2019
+ const progressSession = new RSUPostRestartProgressSession();
2020
+
1911
2021
  for (const pending of pendingItems) {
1912
2022
  const pendingWorkID = pending.ID;
1913
2023
  const item = pending.Work;
2024
+ let progress: RSUPostRestartProgress | null = null;
1914
2025
  // Declared outside the try so the catch can narrow a retry to what is still outstanding: what
1915
2026
  // actually got mapped this attempt. Each retry is then strictly smaller, and one poison object
1916
2027
  // cannot keep re-running its healthy siblings.
@@ -1932,6 +2043,10 @@ async function processRSUPendingWork(): Promise<void> {
1932
2043
  continue;
1933
2044
  }
1934
2045
 
2046
+ // Attached only for apply-objects work: promote-columns is a follow-up to a DIFFERENT run
2047
+ // shape that has no CreateEntityMaps/StartSync steps to report.
2048
+ progress = await progressSession.For(item.CompanyIntegrationID);
2049
+
1935
2050
  // Resolve connector
1936
2051
  const rv = new RunView();
1937
2052
  const ciResult = await rv.RunView<MJCompanyIntegrationEntity>({
@@ -1941,8 +2056,10 @@ async function processRSUPendingWork(): Promise<void> {
1941
2056
  }, systemUser);
1942
2057
  const companyIntegration = ciResult.Results[0];
1943
2058
  if (!companyIntegration) {
1944
- await rsm.FailPendingWork(pendingWorkID, `CompanyIntegration ${item.CompanyIntegrationID} not found`, systemUser);
1945
- console.warn(`[RSU] CompanyIntegration ${item.CompanyIntegrationID} not found`);
2059
+ const missingCI = `CompanyIntegration ${item.CompanyIntegrationID} not found`;
2060
+ progress?.FailEntityMaps(missingCI, item.SourceObjectNames ?? []);
2061
+ await rsm.FailPendingWork(pendingWorkID, missingCI, systemUser);
2062
+ console.warn(`[RSU] ${missingCI}`);
1946
2063
  continue;
1947
2064
  }
1948
2065
 
@@ -1954,14 +2071,18 @@ async function processRSUPendingWork(): Promise<void> {
1954
2071
  }, systemUser);
1955
2072
  const integrationEntity = integrationResult.Results[0];
1956
2073
  if (!integrationEntity) {
1957
- await rsm.FailPendingWork(pendingWorkID, `Integration entity for ${integrationName} not found`, systemUser);
1958
- console.warn(`[RSU] Integration entity for ${integrationName} not found`);
2074
+ const missingIntegration = `Integration entity for ${integrationName} not found`;
2075
+ progress?.FailEntityMaps(missingIntegration, item.SourceObjectNames ?? []);
2076
+ await rsm.FailPendingWork(pendingWorkID, missingIntegration, systemUser);
2077
+ console.warn(`[RSU] ${missingIntegration}`);
1959
2078
  continue;
1960
2079
  }
1961
2080
  const connector = ConnectorFactory.Resolve(integrationEntity);
1962
2081
  if (!connector) {
1963
- await rsm.FailPendingWork(pendingWorkID, `Connector for ${integrationName} not found`, systemUser);
1964
- console.warn(`[RSU] Connector for ${integrationName} not found`);
2082
+ const missingConnector = `Connector for ${integrationName} not found`;
2083
+ progress?.FailEntityMaps(missingConnector, item.SourceObjectNames ?? []);
2084
+ await rsm.FailPendingWork(pendingWorkID, missingConnector, systemUser);
2085
+ console.warn(`[RSU] ${missingConnector}`);
1965
2086
  continue;
1966
2087
  }
1967
2088
 
@@ -1970,10 +2091,28 @@ async function processRSUPendingWork(): Promise<void> {
1970
2091
  const rvPending = new RunView();
1971
2092
  const sourceObjectFields: Record<string, string[] | null> = item.SourceObjectFields ?? {};
1972
2093
 
1973
- // Introspect schema ONCE for the entire connector, then reuse per object
2094
+ // Introspect schema ONCE for the entire connector, then reuse per object.
2095
+ //
2096
+ // IN THE CONNECTION'S CATALOG SCOPE. This runs at process start, outside any request, so
2097
+ // nothing upstream has entered a scope for it — and an unscoped catalog read falls back to
2098
+ // the SHARED catalog by design. That would build these field maps from the connector's
2099
+ // declared fields alone: every column this connection's own discovery sampled would get a
2100
+ // table column from the RSU (built in scope, from the per-connection rows) but no field map,
2101
+ // and its values would land in the overflow JSON instead of the column. Observed on the
2102
+ // sandbox 2026-09-11: 487 declared fields, 556 per-connection — 69 columns that this read
2103
+ // would have silently left unmapped. Entering the scope is not enough on a fresh process:
2104
+ // IntrospectInCatalogScope loads the catalog and warms each object's fields first.
1974
2105
  const introspect = connector.IntrospectSchema.bind(connector) as
1975
2106
  (ci: unknown, u: unknown) => Promise<{ Objects: Array<{ ExternalName: string; Fields: Array<{ Name: string; IsPrimaryKey?: boolean; IsRequired?: boolean }> }> }>;
1976
- const schema = await introspect(companyIntegration, systemUser);
2107
+ const schema = await IntrospectInCatalogScope(
2108
+ item.CompanyIntegrationID,
2109
+ item.SourceObjectNames,
2110
+ () => introspect(companyIntegration, systemUser),
2111
+ systemUser,
2112
+ );
2113
+
2114
+ const objectsToMap = item.SourceObjectNames.length;
2115
+ progress?.BeginEntityMaps(objectsToMap);
1977
2116
 
1978
2117
  for (const objName of item.SourceObjectNames) {
1979
2118
  const tableName = objName.replace(/[^A-Za-z0-9_]/g, '_').toLowerCase();
@@ -2079,8 +2218,15 @@ async function processRSUPendingWork(): Promise<void> {
2079
2218
  } catch (fieldErr) {
2080
2219
  console.warn(`[RSU] Field map creation failed for ${objName}: ${fieldErr}`);
2081
2220
  }
2221
+
2222
+ progress?.ObjectMapped(objName, mappedObjectNames.size, objectsToMap);
2082
2223
  }
2083
2224
 
2225
+ // The applied rollup for this half of the run, in OBJECTS. `mappedObjectNames` is the same set
2226
+ // the retry path narrows against, so what is reported succeeded here is exactly what a retry
2227
+ // would NOT redo.
2228
+ progress?.CompleteEntityMaps(objectsToMap, mappedObjectNames.size, objectsToMap - mappedObjectNames.size);
2229
+
2084
2230
  // Remove-as-disable: entity maps whose object is NOT in this apply's selection
2085
2231
  // are disabled (data kept; re-selection re-enables). 'ignore' opts out for subset applies.
2086
2232
  if ((item.UnselectedAction ?? 'disable') !== 'ignore') {
@@ -2096,8 +2242,11 @@ async function processRSUPendingWork(): Promise<void> {
2096
2242
  }
2097
2243
  }
2098
2244
 
2099
- // Start sync if requested
2245
+ // Start sync if requested. This is the step the setup journey is actually waiting on — the
2246
+ // connector is not live until it begins — so it is a stage of its own rather than a footnote
2247
+ // on entity-map creation.
2100
2248
  if (item.StartSync !== false) {
2249
+ progress?.BeginStartSync();
2101
2250
  try {
2102
2251
  await IntegrationEngine.Instance.Config(false, systemUser);
2103
2252
  const syncOptions: IntegrationSyncOptions = {};
@@ -2107,11 +2256,18 @@ async function processRSUPendingWork(): Promise<void> {
2107
2256
  const opts = Object.keys(syncOptions).length > 0 ? syncOptions : undefined;
2108
2257
  IntegrationEngine.Instance.RunSync(item.CompanyIntegrationID, systemUser, 'Manual', undefined, undefined, opts);
2109
2258
  console.log(`[RSU] Sync started for ${item.CompanyIntegrationID} (EntityMaps: ${createdEntityMapIDs.length}, FullSync: ${!!item.FullSync}, SyncDirection: ${item.SyncDirection ?? 'entity-map default'})`);
2259
+ // Looked up rather than returned: RunSync resolves only when the whole sync finishes, and
2260
+ // this stage closes when the sync STARTS. A null id closes the stage anyway — the sync did
2261
+ // start; only the hand-off to its own stream is missing.
2262
+ progress?.CompleteStartSync(await FindStartedSyncRunID(item.CompanyIntegrationID, systemUser));
2110
2263
  } catch (syncErr) {
2111
2264
  console.warn(`[RSU] Sync start failed: ${syncErr}`);
2265
+ progress?.FailStartSync(`Sync start failed: ${syncErr instanceof Error ? syncErr.message : String(syncErr)}`);
2112
2266
  }
2113
2267
  } else {
2114
2268
  console.log(`[RSU] Sync skipped for ${item.CompanyIntegrationID} (StartSync=false)`);
2269
+ progress?.BeginStartSync();
2270
+ progress?.SkipStartSync('the caller asked for no initial sync (StartSync=false)');
2115
2271
  }
2116
2272
 
2117
2273
  // Create or update schedule if CronExpression provided
@@ -2150,6 +2306,7 @@ async function processRSUPendingWork(): Promise<void> {
2150
2306
  EntityName: 'MJ: Scheduled Job Types',
2151
2307
  ExtraFilter: `DriverClass='IntegrationSyncScheduledJobDriver'`,
2152
2308
  MaxRows: 1,
2309
+ SkipTotalRowCount: true,
2153
2310
  ResultType: 'simple',
2154
2311
  Fields: ['ID']
2155
2312
  }, systemUser);
@@ -2198,6 +2355,16 @@ async function processRSUPendingWork(): Promise<void> {
2198
2355
  // Failing terminally on the first error means the objects this item would have mapped are
2199
2356
  // silently never mapped, and the only recovery is someone noticing and re-applying by hand.
2200
2357
  const remaining = (item.SourceObjectNames ?? []).filter(n => !mappedObjectNames.has(n));
2358
+ // Same list the retry narrows to, reported into the run stream: when this half fails, those
2359
+ // objects have tables and no way to sync into them, and this is the client's only signal.
2360
+ //
2361
+ // Reported under CreateEntityMaps because that is where the overwhelming majority of this
2362
+ // block's work — and so its failures — lives. A throw from further down (schedule creation,
2363
+ // say) lands here too, with an empty `remaining`; the stage attribution is then approximate
2364
+ // but the message is the real error and the run is correctly marked failed, which is what the
2365
+ // operator needs. The alternative — inventing a stage that is not in the pipeline's step list
2366
+ // — would break the determinate stepper for the sake of a nicer label.
2367
+ progress?.FailEntityMaps(message, remaining);
2201
2368
  const requeued = await rsm.RetryPendingWork(pendingWorkID, item, remaining, systemUser);
2202
2369
  if (!requeued) {
2203
2370
  // Budget spent, or nothing left to retry. This message is the operator's only signal, so
@@ -2208,9 +2375,42 @@ async function processRSUPendingWork(): Promise<void> {
2208
2375
  }
2209
2376
  }
2210
2377
 
2378
+ // Terminates every RSU run this pass re-attached to. Until this lands, those runs have been
2379
+ // flagged in-flight since before the restart — which is exactly the state this whole mechanism
2380
+ // exists to end.
2381
+ await progressSession.FinishAll();
2382
+
2211
2383
  console.log(`[RSU] Pending work processing complete`);
2212
2384
  }
2213
2385
 
2386
+ /**
2387
+ * The ID of the sync run a just-launched sync created, or null if it is not readable yet.
2388
+ *
2389
+ * `RunSync` resolves only when the entire sync FINISHES, so it cannot be awaited for this — the
2390
+ * StartSync stage closes when the sync begins, not when it ends. The run row is written early in
2391
+ * the sync's own startup, so a short settle plus a newest-first lookup finds it. Null is a normal
2392
+ * outcome under load and is reported as such; it never fails anything.
2393
+ */
2394
+ async function FindStartedSyncRunID(companyIntegrationID: string, systemUser: UserInfo): Promise<string | null> {
2395
+ try {
2396
+ await new Promise(resolve => setTimeout(resolve, 200));
2397
+ const rv = new RunView();
2398
+ const runResult = await rv.RunView<{ ID: string }>({
2399
+ EntityName: 'MJ: Company Integration Runs',
2400
+ ExtraFilter: `CompanyIntegrationID='${companyIntegrationID.replace(/'/g, "''")}' AND Status='In Progress'`,
2401
+ OrderBy: '__mj_CreatedAt DESC',
2402
+ MaxRows: 1,
2403
+ SkipTotalRowCount: true,
2404
+ ResultType: 'simple',
2405
+ Fields: ['ID'],
2406
+ }, systemUser);
2407
+ return runResult.Success && runResult.Results.length > 0 ? runResult.Results[0].ID : null;
2408
+ } catch (e) {
2409
+ console.warn(`[RSU] Could not resolve the started sync run id for ${companyIntegrationID}: ${e}`);
2410
+ return null;
2411
+ }
2412
+ }
2413
+
2214
2414
  /**
2215
2415
  * Creates a MSSQL ConnectionPool-compatible wrapper around a pg.Pool.
2216
2416
  * This allows existing code that references DataSourceInfo.dataSource (typed as sql.ConnectionPool)
@@ -2263,7 +2463,7 @@ function mountRealtimeRecordingRoutes(app: Application): boolean {
2263
2463
  return user ? { ContextUser: user, Provider: provider } : null;
2264
2464
  },
2265
2465
  LoadOwnedSession: LoadOwnedRealtimeSession,
2266
- LoadConversationScope: LoadSessionConversationScope,
2466
+ AuthorizeSession: AuthorizeLoadedSession,
2267
2467
  CreateLedger: (ledgerProvider, contextUser) => new SqlRealtimeRecordingLedger(ledgerProvider, contextUser),
2268
2468
  Scheduler: RecordingAssemblyScheduler.Instance,
2269
2469
  GraceMs: graceMs,
@@ -2281,3 +2481,5 @@ export type { MagicLinkJWTClaims } from './auth/magicLink/index.js';
2281
2481
  export { VerifyHostAssertion } from './realtimeWidget/host-identity.js';
2282
2482
  export type { HostAssertedIdentity, HostAssertionResult } from './realtimeWidget/host-identity.js';
2283
2483
  export { IsScopeLimitedPrincipal } from './auth/scopeLimitedPrincipal.js';
2484
+ export const GetServerStartupSummary = () => StartupLogger.GetLastStartupSnapshot();
2485
+ export type { StartupSummarySnapshot } from './logging/StartupLogger.js';