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

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 (407) 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/config.d.ts +906 -8
  68. package/dist/config.d.ts.map +1 -1
  69. package/dist/config.js +59 -0
  70. package/dist/config.js.map +1 -1
  71. package/dist/context.d.ts +2 -0
  72. package/dist/context.d.ts.map +1 -1
  73. package/dist/context.js +35 -4
  74. package/dist/context.js.map +1 -1
  75. package/dist/coreRoutes.d.ts +3 -1
  76. package/dist/coreRoutes.d.ts.map +1 -1
  77. package/dist/coreRoutes.js +6 -4
  78. package/dist/coreRoutes.js.map +1 -1
  79. package/dist/generated/graphql-schemas/__mj.d.ts +228 -0
  80. package/dist/generated/graphql-schemas/__mj.d.ts.map +1 -1
  81. package/dist/generated/graphql-schemas/__mj.js +1163 -6
  82. package/dist/generated/graphql-schemas/__mj.js.map +1 -1
  83. package/dist/generic/OrphanedConversationDetailReconciler.d.ts +11 -0
  84. package/dist/generic/OrphanedConversationDetailReconciler.d.ts.map +1 -1
  85. package/dist/generic/OrphanedConversationDetailReconciler.js +27 -1
  86. package/dist/generic/OrphanedConversationDetailReconciler.js.map +1 -1
  87. package/dist/generic/ResolverBase.d.ts +50 -5
  88. package/dist/generic/ResolverBase.d.ts.map +1 -1
  89. package/dist/generic/ResolverBase.js +321 -132
  90. package/dist/generic/ResolverBase.js.map +1 -1
  91. package/dist/generic/RunViewResolver.d.ts +4 -0
  92. package/dist/generic/RunViewResolver.d.ts.map +1 -1
  93. package/dist/generic/RunViewResolver.js +47 -7
  94. package/dist/generic/RunViewResolver.js.map +1 -1
  95. package/dist/index.d.ts +1 -0
  96. package/dist/index.d.ts.map +1 -1
  97. package/dist/index.js +157 -35
  98. package/dist/index.js.map +1 -1
  99. package/dist/integration/ConnectionPause.d.ts +121 -0
  100. package/dist/integration/ConnectionPause.d.ts.map +1 -0
  101. package/dist/integration/ConnectionPause.js +183 -0
  102. package/dist/integration/ConnectionPause.js.map +1 -0
  103. package/dist/integration/CustomColumnPromoter.d.ts +72 -6
  104. package/dist/integration/CustomColumnPromoter.d.ts.map +1 -1
  105. package/dist/integration/CustomColumnPromoter.js +87 -46
  106. package/dist/integration/CustomColumnPromoter.js.map +1 -1
  107. package/dist/integration/EntityMapLifecycle.d.ts +78 -4
  108. package/dist/integration/EntityMapLifecycle.d.ts.map +1 -1
  109. package/dist/integration/EntityMapLifecycle.js +199 -5
  110. package/dist/integration/EntityMapLifecycle.js.map +1 -1
  111. package/dist/integration/InactiveRowWarnings.d.ts +31 -0
  112. package/dist/integration/InactiveRowWarnings.d.ts.map +1 -1
  113. package/dist/integration/InactiveRowWarnings.js +29 -0
  114. package/dist/integration/InactiveRowWarnings.js.map +1 -1
  115. package/dist/integration/ObjectNamesByID.d.ts +28 -0
  116. package/dist/integration/ObjectNamesByID.d.ts.map +1 -0
  117. package/dist/integration/ObjectNamesByID.js +87 -0
  118. package/dist/integration/ObjectNamesByID.js.map +1 -0
  119. package/dist/integration/PostRestartIntrospect.d.ts +26 -0
  120. package/dist/integration/PostRestartIntrospect.d.ts.map +1 -0
  121. package/dist/integration/PostRestartIntrospect.js +27 -0
  122. package/dist/integration/PostRestartIntrospect.js.map +1 -0
  123. package/dist/integration/RSUPostRestartProgress.d.ts +176 -0
  124. package/dist/integration/RSUPostRestartProgress.d.ts.map +1 -0
  125. package/dist/integration/RSUPostRestartProgress.js +323 -0
  126. package/dist/integration/RSUPostRestartProgress.js.map +1 -0
  127. package/dist/integration/RSUProgressBridge.d.ts +41 -2
  128. package/dist/integration/RSUProgressBridge.d.ts.map +1 -1
  129. package/dist/integration/RSUProgressBridge.js +84 -1
  130. package/dist/integration/RSUProgressBridge.js.map +1 -1
  131. package/dist/integration/RunArtifactAuthorization.d.ts +39 -0
  132. package/dist/integration/RunArtifactAuthorization.d.ts.map +1 -0
  133. package/dist/integration/RunArtifactAuthorization.js +45 -0
  134. package/dist/integration/RunArtifactAuthorization.js.map +1 -0
  135. package/dist/integration/SchemaRefreshLaunch.d.ts +9 -0
  136. package/dist/integration/SchemaRefreshLaunch.d.ts.map +1 -1
  137. package/dist/integration/SchemaRefreshLaunch.js +3 -2
  138. package/dist/integration/SchemaRefreshLaunch.js.map +1 -1
  139. package/dist/integration/ScopedFieldsForBuild.d.ts +46 -0
  140. package/dist/integration/ScopedFieldsForBuild.d.ts.map +1 -0
  141. package/dist/integration/ScopedFieldsForBuild.js +91 -0
  142. package/dist/integration/ScopedFieldsForBuild.js.map +1 -0
  143. package/dist/integration/TargetConfigGuard.d.ts +40 -0
  144. package/dist/integration/TargetConfigGuard.d.ts.map +1 -0
  145. package/dist/integration/TargetConfigGuard.js +40 -0
  146. package/dist/integration/TargetConfigGuard.js.map +1 -0
  147. package/dist/realtimeSessions/ownedRealtimeSession.d.ts.map +1 -1
  148. package/dist/realtimeSessions/ownedRealtimeSession.js +2 -3
  149. package/dist/realtimeSessions/ownedRealtimeSession.js.map +1 -1
  150. package/dist/realtimeSessions/sessionAccess.d.ts +15 -0
  151. package/dist/realtimeSessions/sessionAccess.d.ts.map +1 -1
  152. package/dist/realtimeSessions/sessionAccess.js +22 -0
  153. package/dist/realtimeSessions/sessionAccess.js.map +1 -1
  154. package/dist/realtimeWidget/WidgetSessionService.d.ts.map +1 -1
  155. package/dist/realtimeWidget/WidgetSessionService.js +2 -0
  156. package/dist/realtimeWidget/WidgetSessionService.js.map +1 -1
  157. package/dist/realtimeWidget/visitorIdentity.d.ts.map +1 -1
  158. package/dist/realtimeWidget/visitorIdentity.js +1 -0
  159. package/dist/realtimeWidget/visitorIdentity.js.map +1 -1
  160. package/dist/realtimeWidget/widgetCore.d.ts.map +1 -1
  161. package/dist/realtimeWidget/widgetCore.js +4 -7
  162. package/dist/realtimeWidget/widgetCore.js.map +1 -1
  163. package/dist/realtimeWidget/widgetGuestElevation.js +1 -0
  164. package/dist/realtimeWidget/widgetGuestElevation.js.map +1 -1
  165. package/dist/requestOrigin.d.ts +22 -0
  166. package/dist/requestOrigin.d.ts.map +1 -0
  167. package/dist/requestOrigin.js +60 -0
  168. package/dist/requestOrigin.js.map +1 -0
  169. package/dist/resolvers/AgentSessionResolver.d.ts.map +1 -1
  170. package/dist/resolvers/AgentSessionResolver.js +6 -2
  171. package/dist/resolvers/AgentSessionResolver.js.map +1 -1
  172. package/dist/resolvers/AutotagPipelineResolver.d.ts.map +1 -1
  173. package/dist/resolvers/AutotagPipelineResolver.js +2 -1
  174. package/dist/resolvers/AutotagPipelineResolver.js.map +1 -1
  175. package/dist/resolvers/ConversationRunEventsResolver.d.ts.map +1 -1
  176. package/dist/resolvers/ConversationRunEventsResolver.js +2 -0
  177. package/dist/resolvers/ConversationRunEventsResolver.js.map +1 -1
  178. package/dist/resolvers/ExecuteRemoteOperationResolver.d.ts +6 -0
  179. package/dist/resolvers/ExecuteRemoteOperationResolver.d.ts.map +1 -1
  180. package/dist/resolvers/ExecuteRemoteOperationResolver.js +30 -7
  181. package/dist/resolvers/ExecuteRemoteOperationResolver.js.map +1 -1
  182. package/dist/resolvers/GetDataResolver.d.ts.map +1 -1
  183. package/dist/resolvers/GetDataResolver.js +34 -13
  184. package/dist/resolvers/GetDataResolver.js.map +1 -1
  185. package/dist/resolvers/IntegrationDiscoveryResolver.d.ts +401 -11
  186. package/dist/resolvers/IntegrationDiscoveryResolver.d.ts.map +1 -1
  187. package/dist/resolvers/IntegrationDiscoveryResolver.js +2690 -1305
  188. package/dist/resolvers/IntegrationDiscoveryResolver.js.map +1 -1
  189. package/dist/resolvers/MCPResolver.d.ts.map +1 -1
  190. package/dist/resolvers/MCPResolver.js +13 -2
  191. package/dist/resolvers/MCPResolver.js.map +1 -1
  192. package/dist/resolvers/QuerySystemUserResolver.d.ts +36 -0
  193. package/dist/resolvers/QuerySystemUserResolver.d.ts.map +1 -1
  194. package/dist/resolvers/QuerySystemUserResolver.js +174 -87
  195. package/dist/resolvers/QuerySystemUserResolver.js.map +1 -1
  196. package/dist/resolvers/RealtimeBridgeResolver.d.ts.map +1 -1
  197. package/dist/resolvers/RealtimeBridgeResolver.js +1 -0
  198. package/dist/resolvers/RealtimeBridgeResolver.js.map +1 -1
  199. package/dist/resolvers/RealtimeClientSessionResolver.d.ts +6 -0
  200. package/dist/resolvers/RealtimeClientSessionResolver.d.ts.map +1 -1
  201. package/dist/resolvers/RealtimeClientSessionResolver.js +36 -5
  202. package/dist/resolvers/RealtimeClientSessionResolver.js.map +1 -1
  203. package/dist/resolvers/RemoteBrowserActionResolver.d.ts +62 -10
  204. package/dist/resolvers/RemoteBrowserActionResolver.d.ts.map +1 -1
  205. package/dist/resolvers/RemoteBrowserActionResolver.js +217 -34
  206. package/dist/resolvers/RemoteBrowserActionResolver.js.map +1 -1
  207. package/dist/resolvers/RunAIAgentResolver.d.ts +24 -8
  208. package/dist/resolvers/RunAIAgentResolver.d.ts.map +1 -1
  209. package/dist/resolvers/RunAIAgentResolver.js +185 -67
  210. package/dist/resolvers/RunAIAgentResolver.js.map +1 -1
  211. package/dist/resolvers/RunAIPromptResolver.d.ts +5 -3
  212. package/dist/resolvers/RunAIPromptResolver.d.ts.map +1 -1
  213. package/dist/resolvers/RunAIPromptResolver.js +19 -18
  214. package/dist/resolvers/RunAIPromptResolver.js.map +1 -1
  215. package/dist/resolvers/RunTemplateResolver.d.ts.map +1 -1
  216. package/dist/resolvers/RunTemplateResolver.js +3 -1
  217. package/dist/resolvers/RunTemplateResolver.js.map +1 -1
  218. package/dist/resolvers/meetingRecordingRegistration.d.ts.map +1 -1
  219. package/dist/resolvers/meetingRecordingRegistration.js +2 -0
  220. package/dist/resolvers/meetingRecordingRegistration.js.map +1 -1
  221. package/dist/rest/MediaAccessKeys.d.ts.map +1 -1
  222. package/dist/rest/MediaAccessKeys.js +6 -2
  223. package/dist/rest/MediaAccessKeys.js.map +1 -1
  224. package/dist/rest/OAuthCallbackHandler.d.ts.map +1 -1
  225. package/dist/rest/OAuthCallbackHandler.js +11 -5
  226. package/dist/rest/OAuthCallbackHandler.js.map +1 -1
  227. package/dist/rest/RealtimeRecordingHandler.d.ts +3 -3
  228. package/dist/rest/RealtimeRecordingHandler.d.ts.map +1 -1
  229. package/dist/rest/RealtimeRecordingHandler.js +2 -4
  230. package/dist/rest/RealtimeRecordingHandler.js.map +1 -1
  231. package/dist/rest/ViewOperationsHandler.d.ts.map +1 -1
  232. package/dist/rest/ViewOperationsHandler.js +2 -1
  233. package/dist/rest/ViewOperationsHandler.js.map +1 -1
  234. package/dist/rest/setupRESTEndpoints.d.ts +3 -1
  235. package/dist/rest/setupRESTEndpoints.d.ts.map +1 -1
  236. package/dist/rest/setupRESTEndpoints.js +11 -2
  237. package/dist/rest/setupRESTEndpoints.js.map +1 -1
  238. package/dist/services/DurableEntityActionTaskSubmitter.d.ts.map +1 -1
  239. package/dist/services/DurableEntityActionTaskSubmitter.js +6 -1
  240. package/dist/services/DurableEntityActionTaskSubmitter.js.map +1 -1
  241. package/dist/services/TaskGraphActionRunner.d.ts.map +1 -1
  242. package/dist/services/TaskGraphActionRunner.js +2 -26
  243. package/dist/services/TaskGraphActionRunner.js.map +1 -1
  244. package/dist/services/TaskGraphAgentRunner.d.ts +6 -0
  245. package/dist/services/TaskGraphAgentRunner.d.ts.map +1 -1
  246. package/dist/services/TaskGraphAgentRunner.js +38 -0
  247. package/dist/services/TaskGraphAgentRunner.js.map +1 -1
  248. package/dist/services/TaskGraphContinuationDeliverer.d.ts.map +1 -1
  249. package/dist/services/TaskGraphContinuationDeliverer.js +1 -0
  250. package/dist/services/TaskGraphContinuationDeliverer.js.map +1 -1
  251. package/dist/services/WorkQueueHostService.d.ts +2 -1
  252. package/dist/services/WorkQueueHostService.d.ts.map +1 -1
  253. package/dist/services/WorkQueueHostService.js +19 -4
  254. package/dist/services/WorkQueueHostService.js.map +1 -1
  255. package/dist/services/workQueueConfig.d.ts +2 -2
  256. package/dist/services/workQueueConfig.js +5 -5
  257. package/dist/services/workQueueConfig.js.map +1 -1
  258. package/dist/sharedCache.js +1 -1
  259. package/dist/sharedCache.js.map +1 -1
  260. package/dist/types.d.ts +17 -0
  261. package/dist/types.d.ts.map +1 -1
  262. package/dist/types.js.map +1 -1
  263. package/package.json +98 -98
  264. package/src/__tests__/APIKeyScopeAuth.test.ts +4 -8
  265. package/src/__tests__/ActiveOperations.test.ts +68 -0
  266. package/src/__tests__/AgentSessionResolver.ownership.test.ts +13 -0
  267. package/src/__tests__/AssertTargetConfigs.test.ts +75 -0
  268. package/src/__tests__/BatchApplyParity.test.ts +109 -0
  269. package/src/__tests__/BridgeHostInstance.test.ts +42 -0
  270. package/src/__tests__/CollectInactiveRowWarnings.test.ts +115 -0
  271. package/src/__tests__/ConnectionPause.test.ts +192 -0
  272. package/src/__tests__/ConnectionPauseResolver.test.ts +166 -0
  273. package/src/__tests__/ConnectionPauseSave.test.ts +143 -0
  274. package/src/__tests__/CustomColumnPromoterCompletion.test.ts +142 -0
  275. package/src/__tests__/DeleteConnectionRemovesPerConnectionCatalog.test.ts +51 -0
  276. package/src/__tests__/DetachedDiscoveryStart.test.ts +65 -0
  277. package/src/__tests__/DurableEntityActionTaskSubmitter.test.ts +73 -0
  278. package/src/__tests__/EntityMapLifecycle.rekey.test.ts +252 -0
  279. package/src/__tests__/ExecuteRemoteOperationResolver.test.ts +213 -0
  280. package/src/__tests__/HandoffOfferExpiry.test.ts +40 -0
  281. package/src/__tests__/IntegrationRunArtifactAuthorization.test.ts +126 -0
  282. package/src/__tests__/MagicLinkKeys.test.ts +102 -0
  283. package/src/__tests__/MediaAccessKeys.test.ts +57 -10
  284. package/src/__tests__/NewArrivalsDefaultDisabled.test.ts +50 -0
  285. package/src/__tests__/ObjectNamesByID.test.ts +176 -0
  286. package/src/__tests__/PostRestartMapsInCatalogScope.test.ts +146 -0
  287. package/src/__tests__/QuerySystemUserResolver.childRows.test.ts +80 -0
  288. package/src/__tests__/QuerySystemUserResolver.collision.test.ts +200 -0
  289. package/src/__tests__/QuerySystemUserResolver.permissions.test.ts +132 -0
  290. package/src/__tests__/RSUPostRestartProgress.test.ts +343 -0
  291. package/src/__tests__/RSUProgressBridge.test.ts +188 -5
  292. package/src/__tests__/RSUStartupSweepWiring.test.ts +30 -0
  293. package/src/__tests__/ReactivateRefreshMessage.test.ts +10 -3
  294. package/src/__tests__/RealtimeClientSessionResolver.test.ts +22 -0
  295. package/src/__tests__/{RefreshAdoptsNewColumns.test.ts → RefreshReportsNewColumns.test.ts} +25 -16
  296. package/src/__tests__/RemoteBrowserActionRecovery.test.ts +287 -0
  297. package/src/__tests__/RemoteBrowserActionResolver.goalRunLink.test.ts +3 -0
  298. package/src/__tests__/RemoteBrowserActionResolver.ownership.test.ts +6 -4
  299. package/src/__tests__/RemoteBrowserAudioStream.test.ts +3 -0
  300. package/src/__tests__/RemoteBrowserSnapshot.test.ts +3 -0
  301. package/src/__tests__/ResolverBase.clientOldValues.test.ts +323 -26
  302. package/src/__tests__/ResolverBase.encryptedApiZeroReencrypt.test.ts +307 -0
  303. package/src/__tests__/ResolverBase.entityMessageRelay.test.ts +53 -2
  304. package/src/__tests__/ResolverBase.includeBinaryFields.test.ts +60 -0
  305. package/src/__tests__/RunAIAgentResolver.branch.test.ts +4 -0
  306. package/src/__tests__/RunAIAgentResolver.consultPredecessor.test.ts +289 -0
  307. package/src/__tests__/RunAIAgentResolver.handoff.test.ts +649 -0
  308. package/src/__tests__/RunAIAgentResolver.historyFrom.test.ts +2 -0
  309. package/src/__tests__/RunAIAgentResolver.runDataGuard.test.ts +2 -0
  310. package/src/__tests__/RunAIAgentResolver.stoppedPredecessor.test.ts +87 -12
  311. package/src/__tests__/SchemaEvolutionCustomColumns.test.ts +119 -0
  312. package/src/__tests__/SchemaRefreshLaunch.test.ts +24 -2
  313. package/src/__tests__/ScopedFieldsForBuild.test.ts +192 -0
  314. package/src/__tests__/SessionJanitor.test.ts +195 -4
  315. package/src/__tests__/SessionManager.test.ts +69 -0
  316. package/src/__tests__/TaskGraphActionRunner.durablePayload.test.ts +2 -2
  317. package/src/__tests__/TaskGraphAgentRunner.test.ts +272 -16
  318. package/src/__tests__/ViewOperationsHandler.test.ts +2 -5
  319. package/src/__tests__/WorkQueueHostService.test.ts +25 -7
  320. package/src/__tests__/backgroundSweepConfigUnits.test.ts +153 -0
  321. package/src/__tests__/contextRequestOrigin.test.ts +105 -0
  322. package/src/__tests__/conversationBrowsers.test.ts +62 -0
  323. package/src/__tests__/magicLinkExtensionCapabilities.test.ts +413 -0
  324. package/src/__tests__/orphanedConversationDetailReconciler.start.test.ts +82 -0
  325. package/src/__tests__/ownedRealtimeSession.test.ts +14 -0
  326. package/src/__tests__/realtimeRecordingHandler.test.ts +7 -2
  327. package/src/__tests__/realtimeSessions/sessionAccess.test.ts +79 -1
  328. package/src/__tests__/requestOrigin.test.ts +104 -0
  329. package/src/__tests__/securityHardeningPr6034.test.ts +120 -0
  330. package/src/__tests__/sessionDeadline.test.ts +51 -0
  331. package/src/__tests__/sharedCache.test.ts +11 -0
  332. package/src/__tests__/unifiedAuth.test.ts +73 -1
  333. package/src/agentSessions/BridgeHostInstance.ts +20 -5
  334. package/src/agentSessions/HandoffOfferExpiry.ts +18 -0
  335. package/src/agentSessions/ReturningVisitorRecap.ts +1 -0
  336. package/src/agentSessions/SessionJanitor.ts +92 -42
  337. package/src/agentSessions/SessionManager.ts +38 -8
  338. package/src/agentSessions/conversationBrowsers.ts +143 -0
  339. package/src/agentSessions/sessionDeadline.ts +81 -0
  340. package/src/auth/APIKeyScopeAuth.ts +5 -4
  341. package/src/auth/__tests__/loginEmailResolution.test.ts +67 -0
  342. package/src/auth/loginEmailResolution.ts +67 -0
  343. package/src/auth/magicLink/MagicLinkKeys.ts +146 -14
  344. package/src/auth/magicLink/MagicLinkRouter.ts +33 -6
  345. package/src/auth/magicLink/MagicLinkService.ts +250 -10
  346. package/src/auth/magicLink/index.ts +1 -1
  347. package/src/auth/magicLink/redeemLanding.ts +7 -4
  348. package/src/auth/magicLink/types.ts +28 -3
  349. package/src/auth/newUsers.ts +1 -0
  350. package/src/backgroundSweepConfigUnits.ts +213 -0
  351. package/src/config.ts +69 -0
  352. package/src/context.ts +39 -6
  353. package/src/coreRoutes.ts +14 -7
  354. package/src/generated/graphql-schemas/__mj.ts +822 -7
  355. package/src/generic/OrphanedConversationDetailReconciler.ts +32 -1
  356. package/src/generic/ResolverBase.ts +414 -143
  357. package/src/generic/RunViewResolver.ts +96 -49
  358. package/src/index.ts +201 -35
  359. package/src/integration/ConnectionPause.ts +222 -0
  360. package/src/integration/CustomColumnPromoter.ts +123 -53
  361. package/src/integration/EntityMapLifecycle.ts +229 -6
  362. package/src/integration/InactiveRowWarnings.ts +50 -0
  363. package/src/integration/ObjectNamesByID.ts +97 -0
  364. package/src/integration/PostRestartIntrospect.ts +49 -0
  365. package/src/integration/RSUPostRestartProgress.ts +359 -0
  366. package/src/integration/RSUProgressBridge.ts +85 -2
  367. package/src/integration/RunArtifactAuthorization.ts +65 -0
  368. package/src/integration/SchemaRefreshLaunch.ts +12 -2
  369. package/src/integration/ScopedFieldsForBuild.ts +113 -0
  370. package/src/integration/TargetConfigGuard.ts +71 -0
  371. package/src/realtimeSessions/ownedRealtimeSession.ts +2 -6
  372. package/src/realtimeSessions/sessionAccess.ts +30 -0
  373. package/src/realtimeWidget/WidgetSessionService.ts +2 -0
  374. package/src/realtimeWidget/visitorIdentity.ts +1 -0
  375. package/src/realtimeWidget/widgetCore.ts +4 -8
  376. package/src/realtimeWidget/widgetGuestElevation.ts +1 -0
  377. package/src/requestOrigin.ts +64 -0
  378. package/src/resolvers/AgentSessionResolver.ts +6 -2
  379. package/src/resolvers/AutotagPipelineResolver.ts +2 -1
  380. package/src/resolvers/ConversationRunEventsResolver.ts +2 -0
  381. package/src/resolvers/ExecuteRemoteOperationResolver.ts +41 -9
  382. package/src/resolvers/GetDataResolver.ts +35 -13
  383. package/src/resolvers/IntegrationDiscoveryResolver.ts +1522 -203
  384. package/src/resolvers/MCPResolver.ts +15 -2
  385. package/src/resolvers/QuerySystemUserResolver.ts +197 -98
  386. package/src/resolvers/RealtimeBridgeResolver.ts +1 -0
  387. package/src/resolvers/RealtimeClientSessionResolver.ts +40 -7
  388. package/src/resolvers/RemoteBrowserActionResolver.ts +242 -32
  389. package/src/resolvers/RunAIAgentResolver.ts +265 -86
  390. package/src/resolvers/RunAIPromptResolver.ts +18 -18
  391. package/src/resolvers/RunTemplateResolver.ts +3 -1
  392. package/src/resolvers/__tests__/GetDataResolver.tokens.test.ts +52 -0
  393. package/src/resolvers/meetingRecordingRegistration.ts +2 -0
  394. package/src/rest/MediaAccessKeys.ts +6 -2
  395. package/src/rest/OAuthCallbackHandler.ts +13 -5
  396. package/src/rest/RealtimeRecordingHandler.ts +5 -9
  397. package/src/rest/ViewOperationsHandler.ts +2 -1
  398. package/src/rest/setupRESTEndpoints.ts +11 -2
  399. package/src/services/DurableEntityActionTaskSubmitter.ts +10 -2
  400. package/src/services/TaskGraphActionRunner.ts +2 -23
  401. package/src/services/TaskGraphAgentRunner.ts +43 -0
  402. package/src/services/TaskGraphContinuationDeliverer.ts +1 -0
  403. package/src/services/WorkQueueHostService.ts +26 -4
  404. package/src/services/workQueueConfig.ts +5 -5
  405. package/src/sharedCache.ts +1 -1
  406. package/src/types.ts +18 -0
  407. package/src/services/TaskOrchestration-Integration.md +0 -188
@@ -4,7 +4,8 @@
4
4
  * Selection removal DISABLES (never deletes — data is kept), re-selection
5
5
  * re-enables, and a refresh's new objects arrive disabled-by-default.
6
6
  */
7
- import { CompositeKey, IMetadataProvider, LogError, RunView, UserInfo } from '@memberjunction/core';
7
+ import { CompositeKey, IMetadataProvider, LogError, RunView, UserInfo, type DatabaseProviderBase } from '@memberjunction/core';
8
+ import { EscapeSQLString } from '@memberjunction/global';
8
9
  import type {
9
10
  MJCompanyIntegrationEntityMapEntity,
10
11
  MJCompanyIntegrationFieldMapEntity,
@@ -284,9 +285,9 @@ export interface FieldMapReconcilePlan {
284
285
  * `decideAbsentDeactivations` in the engine.
285
286
  *
286
287
  * The rules:
287
- * - **New column → `Active`.** A refresh is an explicit request to bring the source's current shape
288
- * in, so a column it finds is adopted rather than queued for approval. `autoEnableNewColumns:
289
- * false` gates it for a connection that wants to review first.
288
+ * - **New column → `Inactive` (default).** A column the refresh finds gets a field map, disabled,
289
+ * and the user turns it on. `autoEnableNewColumns: true` adopts it as `Active` instead, for a
290
+ * connection that wants a refresh to bring the source's current shape straight in.
290
291
  *
291
292
  * This is REFRESH ONLY. A column first seen mid-SYNC is never auto-created — it is captured as a
292
293
  * candidate with its statistics and needs acceptance before any DDL runs (see
@@ -301,7 +302,9 @@ export function DecideFieldMapReconcile(
301
302
  activeFieldNames: readonly string[],
302
303
  existing: readonly ExistingFieldMapRead[],
303
304
  mapEnabled: boolean,
304
- autoEnableNewColumns = true,
305
+ // Defaults to the CONTRACT (everything.txt): a refresh's new columns arrive disabled and
306
+ // the user turns them on. An omitted argument must not silently adopt.
307
+ autoEnableNewColumns = false,
305
308
  ): FieldMapReconcilePlan {
306
309
  const plan: FieldMapReconcilePlan = { Create: [], Enable: [], Disable: [] };
307
310
  const existingByLower = new Map(
@@ -334,7 +337,227 @@ export function decideFieldMapReconcile(
334
337
  activeFieldNames: readonly string[],
335
338
  existing: readonly ExistingFieldMapRead[],
336
339
  mapEnabled: boolean,
337
- autoEnableNewColumns = true,
340
+ autoEnableNewColumns = false,
338
341
  ): FieldMapReconcilePlan {
339
342
  return DecideFieldMapReconcile(activeFieldNames, existing, mapEnabled, autoEnableNewColumns);
340
343
  }
344
+
345
+ // ── Re-keying: when a connector upgrade changes what identifies a row ────────────────────────
346
+ //
347
+ // A connector release can change an object's primary key — PheedLoop 1.4.6 makes Attendees
348
+ // `code + eventCode` because the object is fetched once per event and an attendee at two events
349
+ // comes back twice with the same `code`.
350
+ //
351
+ // That is not an ordinary schema change. `BaseRESTIntegrationConnector.ToExternalRecord` builds
352
+ // `ExternalID` by joining every IsPrimaryKey field with '|' in Sequence order, so changing the key
353
+ // changes the identity of every row the source will ever send again. Nothing can match a row
354
+ // already stored: the RecordMap is keyed `EntityID|ExternalID`, and the fallback
355
+ // (`MatchEngine.FindByKeyFields`) queries the destination table by key fields that are NULL on
356
+ // rows written before the change. The next sync therefore inserts the whole source ALONGSIDE the
357
+ // rows already there, leaving two copies of everything and nothing to say which is current.
358
+ //
359
+ // So a re-key means the object's stored data has to go, and the source reloaded under the new
360
+ // identity. This is the same reasoning as U10's watermark reset one step further: not just
361
+ // "re-fetch everything", but "re-fetch everything into a table that is not holding rows the
362
+ // re-fetch can never reconcile with".
363
+
364
+ const ENTITY_RECORD_MAPS = 'MJ: Company Integration Record Maps';
365
+
366
+ /** A catalog or entity field, as much of one as the key decision needs. */
367
+ export interface KeyCandidateField {
368
+ Name: string;
369
+ IsPrimaryKey: boolean | null;
370
+ Sequence: number | null;
371
+ }
372
+
373
+ /**
374
+ * The key that decides identity, in the order identity uses.
375
+ *
376
+ * Deliberately NOT `SourceObjectInfo.PrimaryKeyFields`. That is built in
377
+ * `buildSourceSchemaFromPersistedRows` as `fields.filter(f => f.IsPrimaryKey).map(f => f.Name)`
378
+ * over `GetIntegrationObjectFields`, which returns rows in load order with NO Sequence sort — so
379
+ * its order is not the order `ToExternalRecord` joins in, and comparing against it would miss a
380
+ * reorder and could invent one.
381
+ */
382
+ export function IdentityKeyFields(fields: ReadonlyArray<KeyCandidateField>): string[] {
383
+ return fields
384
+ .filter(f => f.IsPrimaryKey === true)
385
+ .slice()
386
+ .sort((a, b) => (a.Sequence ?? 0) - (b.Sequence ?? 0))
387
+ .map(f => f.Name);
388
+ }
389
+
390
+ /**
391
+ * The key the catalog declares for an object, or `null` when its field rows were not read.
392
+ *
393
+ * An object with no Active field rows is unread, not keyless: a per-connection object whose fields
394
+ * were never warmed answers `[]`, and a continuing object with a built table had columns when it
395
+ * was built. Reporting that as "no key" would make {@link DecideRekeyed} see every keyed object as
396
+ * re-keyed, and the evolution would delete its record maps and rows.
397
+ */
398
+ export function CatalogIdentityKey(
399
+ fields: ReadonlyArray<KeyCandidateField & { Status: string | null }>,
400
+ ): string[] | null {
401
+ const active = fields.filter(f => f.Status === 'Active');
402
+ return active.length === 0 ? null : IdentityKeyFields(active);
403
+ }
404
+
405
+ /**
406
+ * Has the identity changed between the key the tables were BUILT with and the key the catalog
407
+ * now declares?
408
+ *
409
+ * Ordered, not set-based: `code|eventCode` and `eventCode|code` are different identity strings,
410
+ * so a key that keeps its columns and reorders them strands rows exactly like one that gains a
411
+ * column.
412
+ *
413
+ * Returns false when the built key is EMPTY. That is "we could not read it", not "it had no key" —
414
+ * an object genuinely without a key never had stable identities to strand, and treating unknown as
415
+ * empty would re-key every table on a workspace whose entity metadata failed to load.
416
+ *
417
+ * Returns false when the catalog key is `null` — the catalog side could not be read (see
418
+ * {@link CatalogIdentityKey}). An empty ARRAY is different: the catalog was read and declares no
419
+ * key, so the object moves to content-hash identity, and that is a re-key.
420
+ */
421
+ export function DecideRekeyed(builtKey: readonly string[], catalogKey: readonly string[] | null): boolean {
422
+ if (builtKey.length === 0 || catalogKey === null) return false;
423
+ const norm = (s: string) => (s ?? '').trim().toLowerCase();
424
+ if (builtKey.length !== catalogKey.length) return true;
425
+ return builtKey.some((n, i) => norm(n) !== norm(catalogKey[i]));
426
+ }
427
+
428
+ /** Record maps per chunk. Each chunk is one read and one transaction, so this bounds both. */
429
+ export const REKEY_CLEAR_CHUNK = 500;
430
+
431
+ /**
432
+ * The key values a record map's `EntityRecordID` names, or `null` when it cannot name exactly one
433
+ * row. The inverse of the engine's `composeEntityRecordID`: a single-column key is the value
434
+ * itself; a composite one is '|'-joined in PrimaryKeys order.
435
+ *
436
+ * A composite id that splits into more parts than the key has columns held a value that itself
437
+ * contained '|', and its split would name some other row. An empty part is a null key value. Both
438
+ * are refused rather than matched.
439
+ */
440
+ function keyValuesOf(entityRecordID: string | null | undefined, keyColumns: number): string[] | null {
441
+ if (!entityRecordID) return null;
442
+ const parts = keyColumns === 1 ? [entityRecordID] : entityRecordID.split('|');
443
+ return parts.length === keyColumns && parts.every(p => p.length > 0) ? parts : null;
444
+ }
445
+
446
+ /**
447
+ * Clear what ties a re-keyed object's stored rows to the source, so the next sync rebuilds it:
448
+ * this connection's rows, and the record maps that point at them.
449
+ *
450
+ * Scoped by the record maps, never the table. Two connections to the same vendor resolve to one
451
+ * schema and therefore one table, and nothing on the table records which connection wrote a row.
452
+ * The connection's record maps are the only thing that does, so they decide which rows go: each
453
+ * map's `EntityRecordID` is the row's key, and the delete names exactly those keys. A row no map
454
+ * of this connection points at is left alone.
455
+ *
456
+ * In chunks of {@link REKEY_CLEAR_CHUNK} maps, read in ID order and resumed after the last ID, so
457
+ * neither the read nor a statement grows with the table. Each chunk deletes its rows and then its
458
+ * maps in ONE transaction: the rows have to go while the maps still say which rows they are, and a
459
+ * failure between the two must not leave maps pointing at deleted rows (the next sync would try to
460
+ * UPDATE them, and fail per record). Set-based, like the engine's `touchLastReconciledAt`, whose
461
+ * `IN` list of dialect-quoted key literals this follows.
462
+ *
463
+ * Returns the object names fully cleared. A failed chunk rolls back, is logged, and leaves its
464
+ * object out. So does a map whose id cannot name one row (see {@link keyValuesOf}): it stays in
465
+ * place, and so does its row. A table that could not be cleared must not look like one that was.
466
+ */
467
+ export async function ClearRekeyedObjectData(
468
+ targets: ReadonlyArray<{
469
+ ExternalObjectName: string;
470
+ EntityMapID: string;
471
+ EntityID: string;
472
+ SchemaName: string;
473
+ BaseTable: string;
474
+ }>,
475
+ companyIntegrationID: string,
476
+ contextUser: UserInfo,
477
+ provider: DatabaseProviderBase,
478
+ chunkSize = REKEY_CLEAR_CHUNK,
479
+ ): Promise<string[]> {
480
+ const cleared: string[] = [];
481
+ if (targets.length === 0) return cleared;
482
+
483
+ // Resolved from metadata, never spelled out. A hardcoded `__mj.CompanyIntegrationRecordMap`
484
+ // would be a second place the schema is declared, and the one place nothing would update.
485
+ const rmEntity = provider.EntityByName(ENTITY_RECORD_MAPS);
486
+ if (!rmEntity?.SchemaName || !rmEntity.BaseTable) {
487
+ LogError(`[EntityMapLifecycle] Cannot clear re-keyed objects: '${ENTITY_RECORD_MAPS}' is not registered`);
488
+ return cleared;
489
+ }
490
+ const d = provider.Dialect;
491
+ const recordMaps = `${d.QuoteIdentifier(rmEntity.SchemaName)}.${d.QuoteIdentifier(rmEntity.BaseTable)}`;
492
+ const literal = (value: string) => d.QuoteStringLiteral(value);
493
+
494
+ for (const t of targets) {
495
+ const key = t.EntityID ? provider.EntityByID(t.EntityID)?.PrimaryKeys ?? [] : [];
496
+ if (!t.SchemaName || !t.BaseTable || key.length === 0) {
497
+ LogError(`[EntityMapLifecycle] Skipping re-key clear for ${t.ExternalObjectName}: no resolved table or key`);
498
+ continue;
499
+ }
500
+ const table = `${d.QuoteIdentifier(t.SchemaName)}.${d.QuoteIdentifier(t.BaseTable)}`;
501
+ const scope = `CompanyIntegrationID='${EscapeSQLString(companyIntegrationID)}' AND EntityID='${EscapeSQLString(t.EntityID)}'`;
502
+ const mapScope = `${d.QuoteIdentifier('CompanyIntegrationID')}=${literal(companyIntegrationID)} ` +
503
+ `AND ${d.QuoteIdentifier('EntityID')}=${literal(t.EntityID)}`;
504
+ let unmatched = 0;
505
+ let after: string | null = null;
506
+ try {
507
+ for (;;) {
508
+ const page = await new RunView().RunView<{ ID: string; EntityRecordID: string }>({
509
+ EntityName: ENTITY_RECORD_MAPS,
510
+ ExtraFilter: after ? `${scope} AND ID > '${EscapeSQLString(after)}'` : scope,
511
+ Fields: ['ID', 'EntityRecordID'],
512
+ OrderBy: 'ID',
513
+ MaxRows: chunkSize,
514
+ ResultType: 'simple',
515
+ BypassCache: true,
516
+ SkipTotalRowCount: true,
517
+ }, contextUser);
518
+ if (!page.Success) throw new Error(`record maps could not be read: ${page.ErrorMessage ?? 'unknown error'}`);
519
+ if (page.Results.length === 0) break;
520
+ after = page.Results[page.Results.length - 1].ID;
521
+
522
+ const matched = page.Results
523
+ .map(m => ({ MapID: m.ID, Values: keyValuesOf(m.EntityRecordID, key.length) }))
524
+ .filter((m): m is { MapID: string; Values: string[] } => m.Values !== null);
525
+ unmatched += page.Results.length - matched.length;
526
+ if (matched.length > 0) {
527
+ const rows = key.length === 1
528
+ ? `${d.QuoteIdentifier(key[0].Name)} IN (${matched.map(m => literal(m.Values[0])).join(',')})`
529
+ : matched
530
+ .map(m => `(${key.map((k, i) => `${d.QuoteIdentifier(k.Name)}=${literal(m.Values[i])}`).join(' AND ')})`)
531
+ .join(' OR ');
532
+ await provider.BeginTransaction();
533
+ try {
534
+ await provider.ExecuteSQL(`DELETE FROM ${table} WHERE ${rows}`, undefined, undefined, contextUser);
535
+ await provider.ExecuteSQL(
536
+ `DELETE FROM ${recordMaps} WHERE ${mapScope} AND ${d.QuoteIdentifier('ID')} IN (${matched.map(m => literal(m.MapID)).join(',')})`,
537
+ undefined, undefined, contextUser
538
+ );
539
+ await provider.CommitTransaction();
540
+ } catch (err) {
541
+ await provider.RollbackTransaction();
542
+ throw err;
543
+ }
544
+ }
545
+ if (page.Results.length < chunkSize) break;
546
+ }
547
+ if (unmatched > 0) {
548
+ LogError(
549
+ `[EntityMapLifecycle] Re-key clear of ${t.ExternalObjectName} left ${unmatched} record map(s) ` +
550
+ `whose id does not name one row of its ${key.length}-column key; those rows were kept`
551
+ );
552
+ continue;
553
+ }
554
+ cleared.push(t.ExternalObjectName);
555
+ } catch (err) {
556
+ LogError(
557
+ `[EntityMapLifecycle] Failed to clear re-keyed object ${t.ExternalObjectName}: ` +
558
+ `${err instanceof Error ? err.message : String(err)}`
559
+ );
560
+ }
561
+ }
562
+ return cleared;
563
+ }
@@ -51,6 +51,56 @@ const isActive = (row: NamedStatusRow): boolean => row.Status === 'Active';
51
51
  * Returns an empty array when everything declared and in scope is Active.
52
52
  */
53
53
  export function ComputeInactiveRowWarnings(input: InactiveRowWarningInput): string[] {
54
+ return computeInactiveRowWarnings(input);
55
+ }
56
+
57
+ /**
58
+ * The catalog, reduced to the three reads this warning needs. `IntegrationEngineBase` satisfies it
59
+ * structurally, so the resolver passes its engine instance and a test passes a literal — which is the
60
+ * point: the collection used to live inside the resolver's schema REBUILD, and the one apply path that
61
+ * skips the rebuild (the batch, which prefetches its schema) therefore lost the warnings entirely.
62
+ * They never depended on the rebuild; they are the catalog's own Status rows.
63
+ */
64
+ export interface CatalogStatusReader {
65
+ /** Active objects of this integration — the ones an apply materializes. */
66
+ GetActiveIntegrationObjects(integrationID: string): ReadonlyArray<{ ID: string; Name: string }>;
67
+ /** EVERY object of this integration, Active or not. */
68
+ GetIntegrationObjectsByIntegrationID(integrationID: string): ReadonlyArray<{ Name: string; Status: string | null }>;
69
+ /** Every field of one object, Active or not. */
70
+ GetIntegrationObjectFields(objectID: string): ReadonlyArray<{ Name: string; Status: string | null }>;
71
+ }
72
+
73
+ /**
74
+ * Gathers the rows {@link ComputeInactiveRowWarnings} needs from the catalog and returns its verdict.
75
+ *
76
+ * `requestedNames` empty/undefined means "everything active", which deliberately does not report
77
+ * deactivated OBJECTS — see {@link InactiveRowWarningInput.RequestedNames}.
78
+ */
79
+ export function CollectInactiveRowWarnings(
80
+ catalog: CatalogStatusReader,
81
+ integrationID: string,
82
+ requestedNames?: string[] | null,
83
+ ): string[] {
84
+ const filter = requestedNames && requestedNames.length > 0
85
+ ? new Set(requestedNames.map(n => n.toLowerCase()))
86
+ : null;
87
+ // Fields only for the objects this apply materializes: a non-materialized object is reported by
88
+ // the object warning, not by one line per field it also lost.
89
+ const FieldsByObjectName: Record<string, NamedStatusRow[]> = {};
90
+ for (const io of catalog.GetActiveIntegrationObjects(integrationID)) {
91
+ if (filter && !filter.has(io.Name.toLowerCase())) continue;
92
+ FieldsByObjectName[io.Name] = catalog.GetIntegrationObjectFields(io.ID)
93
+ .map(f => ({ Name: f.Name, Status: f.Status }));
94
+ }
95
+ return computeInactiveRowWarnings({
96
+ RequestedNames: requestedNames ?? null,
97
+ AllObjects: catalog.GetIntegrationObjectsByIntegrationID(integrationID)
98
+ .map(io => ({ Name: io.Name, Status: io.Status })),
99
+ FieldsByObjectName,
100
+ });
101
+ }
102
+
103
+ function computeInactiveRowWarnings(input: InactiveRowWarningInput): string[] {
54
104
  const warnings: string[] = [];
55
105
  const requested = input.RequestedNames && input.RequestedNames.length > 0
56
106
  ? new Set(input.RequestedNames.map(n => n.toLowerCase()))
@@ -0,0 +1,97 @@
1
+ /**
2
+ * A table selection's object ids, resolved to object names — against the CONNECTION's catalog first.
3
+ *
4
+ * Inside a catalog scope, `IntegrationListSourceObjects` hands the picker per-connection
5
+ * (CompanyIntegrationObject) ids. The apply paths looked ids up only in the shared
6
+ * `MJ: Integration Objects` catalog, so an id-only selection matched nothing: every pick was dropped
7
+ * with a LogError, the migration ran with an empty table list, CodeGen and the restart still ran,
8
+ * and the apply reported Success with 0 tables.
9
+ *
10
+ * Three tiers, cheapest first:
11
+ * 1. the scope's loaded catalog, no query — every per-connection object, keyed by its own id AND
12
+ * by the shared IntegrationObjectID it carries, so an id from either catalog resolves;
13
+ * 2. a direct, uncached read of `MJ: Company Integration Objects` for this connection, for ids the
14
+ * loaded catalog does not hold yet (a row written earlier in the same run);
15
+ * 3. the shared catalog, exactly as before — and the only tier outside a catalog scope.
16
+ *
17
+ * Keys are upper-cased ids; values are object names. An id no tier resolves is simply absent: the
18
+ * caller decides whether an empty resolution is fatal (an apply refuses it).
19
+ */
20
+ import { RunView, type UserInfo } from '@memberjunction/core';
21
+ import { EscapeSQLString } from '@memberjunction/global';
22
+ import {
23
+ IntegrationEngineBase,
24
+ ENTITY_COMPANY_INTEGRATION_OBJECTS,
25
+ type CompanyIntegrationObjectRow,
26
+ } from '@memberjunction/integration-engine-base';
27
+ import { CurrentCatalogCI } from '@memberjunction/integration-engine';
28
+
29
+ /** Ids per per-connection read. Each read is one `IN (…)` list, so this bounds the filter's length. */
30
+ export const OBJECT_ID_LOOKUP_CHUNK = 200;
31
+
32
+ /** What the lookup reads off a per-connection object. */
33
+ type CatalogIdentity = Pick<CompanyIntegrationObjectRow, 'ID' | 'Name' | 'IntegrationObjectID'>;
34
+
35
+ const quote = (value: string): string => `'${EscapeSQLString(value)}'`;
36
+
37
+ /**
38
+ * Resolves object ids to names for the connection in catalog scope (or the shared catalog when
39
+ * there is none). Never throws for a missing id; a failed read leaves its ids unresolved.
40
+ */
41
+ export async function LookupObjectNamesByID(
42
+ ids: ReadonlyArray<string | null | undefined> | undefined,
43
+ user: UserInfo
44
+ ): Promise<Map<string, string>> {
45
+ const map = new Map<string, string>();
46
+ const wanted = [...new Set((ids ?? [])
47
+ .filter((id): id is string => typeof id === 'string' && id.length > 0)
48
+ .map(id => id.toUpperCase()))];
49
+ if (wanted.length === 0) return map;
50
+
51
+ const ciID = CurrentCatalogCI();
52
+ if (ciID) {
53
+ const engine = IntegrationEngineBase.Instance;
54
+ if (engine.HasCompanyIntegrationCatalog(ciID)) {
55
+ // GetCompanyIntegrationObjects presents CompanyIntegrationObjectRow projections typed as
56
+ // the shared entity (asReadOnlyObject); the per-connection columns are on every row.
57
+ const rows = engine.GetCompanyIntegrationObjects(ciID) as unknown as CatalogIdentity[];
58
+ for (const row of rows) {
59
+ if (row.ID) map.set(String(row.ID).toUpperCase(), row.Name);
60
+ if (row.IntegrationObjectID) map.set(String(row.IntegrationObjectID).toUpperCase(), row.Name);
61
+ }
62
+ }
63
+ }
64
+
65
+ const rv = new RunView();
66
+ let missing = wanted.filter(id => !map.has(id));
67
+ if (missing.length > 0 && ciID) {
68
+ for (let i = 0; i < missing.length; i += OBJECT_ID_LOOKUP_CHUNK) {
69
+ const chunk = missing.slice(i, i + OBJECT_ID_LOOKUP_CHUNK);
70
+ const result = await rv.RunView<{ ID: string; Name: string }>({
71
+ EntityName: ENTITY_COMPANY_INTEGRATION_OBJECTS,
72
+ ExtraFilter: `CompanyIntegrationID=${quote(ciID)} AND ID IN (${chunk.map(quote).join(',')})`,
73
+ ResultType: 'simple',
74
+ Fields: ['ID', 'Name'],
75
+ BypassCache: true,
76
+ IgnoreMaxRows: true,
77
+ }, user);
78
+ if (result.Success) {
79
+ for (const r of result.Results) map.set(String(r.ID).toUpperCase(), r.Name);
80
+ }
81
+ }
82
+ missing = wanted.filter(id => !map.has(id));
83
+ }
84
+
85
+ if (missing.length > 0) {
86
+ const result = await rv.RunView<{ ID: string; Name: string }>({
87
+ EntityName: 'MJ: Integration Objects',
88
+ ExtraFilter: missing.map(id => `ID=${quote(id)}`).join(' OR '),
89
+ ResultType: 'simple',
90
+ Fields: ['ID', 'Name'],
91
+ }, user);
92
+ if (result.Success) {
93
+ for (const r of result.Results) map.set(String(r.ID).toUpperCase(), r.Name);
94
+ }
95
+ }
96
+ return map;
97
+ }
@@ -0,0 +1,49 @@
1
+ /**
2
+ * The post-restart introspection, run against the connection's own catalog with its fields warm.
3
+ *
4
+ * After the RSU restarts the process, the consumer introspects the connector to build the entity
5
+ * and field maps. That runs at process start, outside any request, so nothing has entered a scope
6
+ * for it, and nothing has loaded this connection's catalog either. Two things have to be true for
7
+ * the connector to see the connection's fields:
8
+ *
9
+ * - the scope must be entered ASYNC (`WithCatalogScope`), which loads the connection's objects;
10
+ * a synchronous `RunInCatalogScope` loads nothing, so on a fresh process the reads fall back to
11
+ * the shared catalog and every column this connection's discovery sampled gets no field map;
12
+ * - each object's FIELD rows must be warm. A scope loads objects, not fields: only the sync loop
13
+ * warms fields, so a connector reading them here (`GetCachedFields`) gets per-connection objects
14
+ * with no fields at all, and the consumer creates no field maps.
15
+ *
16
+ * So this enters the scope, warms and pins every per-connection object the pending work names,
17
+ * introspects, and releases the pins whether or not the introspection succeeded.
18
+ */
19
+ import type { UserInfo } from '@memberjunction/core';
20
+ import { IntegrationEngineBase } from '@memberjunction/integration-engine-base';
21
+ import { UnpinCatalogObjects, WarmCatalogObject, WithCatalogScope } from '@memberjunction/integration-engine';
22
+
23
+ /**
24
+ * Run `introspect` in `companyIntegrationID`'s catalog scope, with the fields of each named object
25
+ * warm. A name the connection has no object of its own for is skipped: it reads the shared catalog,
26
+ * as it always did. A failed warm throws; it is never read as an object with no fields.
27
+ */
28
+ export async function IntrospectInCatalogScope<T>(
29
+ companyIntegrationID: string,
30
+ sourceObjectNames: readonly string[],
31
+ introspect: () => Promise<T>,
32
+ user: UserInfo,
33
+ ): Promise<T> {
34
+ return WithCatalogScope(companyIntegrationID, async () => {
35
+ const engine = IntegrationEngineBase.Instance;
36
+ const pinned: string[] = [];
37
+ try {
38
+ for (const name of sourceObjectNames) {
39
+ const own = engine.GetCompanyIntegrationObject(companyIntegrationID, name);
40
+ if (!own) continue;
41
+ await WarmCatalogObject(own.ID, user);
42
+ pinned.push(own.ID);
43
+ }
44
+ return await introspect();
45
+ } finally {
46
+ UnpinCatalogObjects(pinned);
47
+ }
48
+ }, user);
49
+ }