@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.
- package/README.md +69 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/agentSessions/BridgeHostInstance.d.ts +8 -3
- package/dist/agentSessions/BridgeHostInstance.d.ts.map +1 -1
- package/dist/agentSessions/BridgeHostInstance.js +14 -4
- package/dist/agentSessions/BridgeHostInstance.js.map +1 -1
- package/dist/agentSessions/HandoffOfferExpiry.d.ts +10 -0
- package/dist/agentSessions/HandoffOfferExpiry.d.ts.map +1 -0
- package/dist/agentSessions/HandoffOfferExpiry.js +18 -0
- package/dist/agentSessions/HandoffOfferExpiry.js.map +1 -0
- package/dist/agentSessions/ReturningVisitorRecap.js +1 -0
- package/dist/agentSessions/ReturningVisitorRecap.js.map +1 -1
- package/dist/agentSessions/SessionJanitor.d.ts +31 -8
- package/dist/agentSessions/SessionJanitor.d.ts.map +1 -1
- package/dist/agentSessions/SessionJanitor.js +85 -41
- package/dist/agentSessions/SessionJanitor.js.map +1 -1
- package/dist/agentSessions/SessionManager.d.ts +14 -4
- package/dist/agentSessions/SessionManager.d.ts.map +1 -1
- package/dist/agentSessions/SessionManager.js +28 -4
- package/dist/agentSessions/SessionManager.js.map +1 -1
- package/dist/agentSessions/conversationBrowsers.d.ts +61 -0
- package/dist/agentSessions/conversationBrowsers.d.ts.map +1 -0
- package/dist/agentSessions/conversationBrowsers.js +118 -0
- package/dist/agentSessions/conversationBrowsers.js.map +1 -0
- package/dist/agentSessions/sessionDeadline.d.ts +43 -0
- package/dist/agentSessions/sessionDeadline.d.ts.map +1 -0
- package/dist/agentSessions/sessionDeadline.js +68 -0
- package/dist/agentSessions/sessionDeadline.js.map +1 -0
- package/dist/auth/APIKeyScopeAuth.d.ts.map +1 -1
- package/dist/auth/APIKeyScopeAuth.js +5 -4
- package/dist/auth/APIKeyScopeAuth.js.map +1 -1
- package/dist/auth/loginEmailResolution.d.ts +41 -0
- package/dist/auth/loginEmailResolution.d.ts.map +1 -0
- package/dist/auth/loginEmailResolution.js +47 -0
- package/dist/auth/loginEmailResolution.js.map +1 -0
- package/dist/auth/magicLink/MagicLinkKeys.d.ts +50 -2
- package/dist/auth/magicLink/MagicLinkKeys.d.ts.map +1 -1
- package/dist/auth/magicLink/MagicLinkKeys.js +129 -12
- package/dist/auth/magicLink/MagicLinkKeys.js.map +1 -1
- package/dist/auth/magicLink/MagicLinkRouter.d.ts +3 -0
- package/dist/auth/magicLink/MagicLinkRouter.d.ts.map +1 -1
- package/dist/auth/magicLink/MagicLinkRouter.js +23 -5
- package/dist/auth/magicLink/MagicLinkRouter.js.map +1 -1
- package/dist/auth/magicLink/MagicLinkService.d.ts +39 -5
- package/dist/auth/magicLink/MagicLinkService.d.ts.map +1 -1
- package/dist/auth/magicLink/MagicLinkService.js +221 -9
- package/dist/auth/magicLink/MagicLinkService.js.map +1 -1
- package/dist/auth/magicLink/index.d.ts +1 -1
- package/dist/auth/magicLink/index.d.ts.map +1 -1
- package/dist/auth/magicLink/index.js +1 -1
- package/dist/auth/magicLink/index.js.map +1 -1
- package/dist/auth/magicLink/redeemLanding.d.ts +2 -2
- package/dist/auth/magicLink/redeemLanding.d.ts.map +1 -1
- package/dist/auth/magicLink/redeemLanding.js +7 -4
- package/dist/auth/magicLink/redeemLanding.js.map +1 -1
- package/dist/auth/magicLink/types.d.ts +27 -3
- package/dist/auth/magicLink/types.d.ts.map +1 -1
- package/dist/auth/magicLink/types.js +0 -4
- package/dist/auth/magicLink/types.js.map +1 -1
- package/dist/auth/newUsers.d.ts.map +1 -1
- package/dist/auth/newUsers.js +1 -0
- package/dist/auth/newUsers.js.map +1 -1
- package/dist/backgroundSweepConfigUnits.d.ts +231 -0
- package/dist/backgroundSweepConfigUnits.d.ts.map +1 -0
- package/dist/backgroundSweepConfigUnits.js +180 -0
- package/dist/backgroundSweepConfigUnits.js.map +1 -0
- package/dist/config.d.ts +906 -8
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +59 -0
- package/dist/config.js.map +1 -1
- package/dist/context.d.ts +2 -0
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +35 -4
- package/dist/context.js.map +1 -1
- package/dist/coreRoutes.d.ts +3 -1
- package/dist/coreRoutes.d.ts.map +1 -1
- package/dist/coreRoutes.js +6 -4
- package/dist/coreRoutes.js.map +1 -1
- package/dist/generated/graphql-schemas/__mj.d.ts +228 -0
- package/dist/generated/graphql-schemas/__mj.d.ts.map +1 -1
- package/dist/generated/graphql-schemas/__mj.js +1163 -6
- package/dist/generated/graphql-schemas/__mj.js.map +1 -1
- package/dist/generic/OrphanedConversationDetailReconciler.d.ts +11 -0
- package/dist/generic/OrphanedConversationDetailReconciler.d.ts.map +1 -1
- package/dist/generic/OrphanedConversationDetailReconciler.js +27 -1
- package/dist/generic/OrphanedConversationDetailReconciler.js.map +1 -1
- package/dist/generic/ResolverBase.d.ts +50 -5
- package/dist/generic/ResolverBase.d.ts.map +1 -1
- package/dist/generic/ResolverBase.js +321 -132
- package/dist/generic/ResolverBase.js.map +1 -1
- package/dist/generic/RunViewResolver.d.ts +4 -0
- package/dist/generic/RunViewResolver.d.ts.map +1 -1
- package/dist/generic/RunViewResolver.js +47 -7
- package/dist/generic/RunViewResolver.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +157 -35
- package/dist/index.js.map +1 -1
- package/dist/integration/ConnectionPause.d.ts +121 -0
- package/dist/integration/ConnectionPause.d.ts.map +1 -0
- package/dist/integration/ConnectionPause.js +183 -0
- package/dist/integration/ConnectionPause.js.map +1 -0
- package/dist/integration/CustomColumnPromoter.d.ts +72 -6
- package/dist/integration/CustomColumnPromoter.d.ts.map +1 -1
- package/dist/integration/CustomColumnPromoter.js +87 -46
- package/dist/integration/CustomColumnPromoter.js.map +1 -1
- package/dist/integration/EntityMapLifecycle.d.ts +78 -4
- package/dist/integration/EntityMapLifecycle.d.ts.map +1 -1
- package/dist/integration/EntityMapLifecycle.js +199 -5
- package/dist/integration/EntityMapLifecycle.js.map +1 -1
- package/dist/integration/InactiveRowWarnings.d.ts +31 -0
- package/dist/integration/InactiveRowWarnings.d.ts.map +1 -1
- package/dist/integration/InactiveRowWarnings.js +29 -0
- package/dist/integration/InactiveRowWarnings.js.map +1 -1
- package/dist/integration/ObjectNamesByID.d.ts +28 -0
- package/dist/integration/ObjectNamesByID.d.ts.map +1 -0
- package/dist/integration/ObjectNamesByID.js +87 -0
- package/dist/integration/ObjectNamesByID.js.map +1 -0
- package/dist/integration/PostRestartIntrospect.d.ts +26 -0
- package/dist/integration/PostRestartIntrospect.d.ts.map +1 -0
- package/dist/integration/PostRestartIntrospect.js +27 -0
- package/dist/integration/PostRestartIntrospect.js.map +1 -0
- package/dist/integration/RSUPostRestartProgress.d.ts +176 -0
- package/dist/integration/RSUPostRestartProgress.d.ts.map +1 -0
- package/dist/integration/RSUPostRestartProgress.js +323 -0
- package/dist/integration/RSUPostRestartProgress.js.map +1 -0
- package/dist/integration/RSUProgressBridge.d.ts +41 -2
- package/dist/integration/RSUProgressBridge.d.ts.map +1 -1
- package/dist/integration/RSUProgressBridge.js +84 -1
- package/dist/integration/RSUProgressBridge.js.map +1 -1
- package/dist/integration/RunArtifactAuthorization.d.ts +39 -0
- package/dist/integration/RunArtifactAuthorization.d.ts.map +1 -0
- package/dist/integration/RunArtifactAuthorization.js +45 -0
- package/dist/integration/RunArtifactAuthorization.js.map +1 -0
- package/dist/integration/SchemaRefreshLaunch.d.ts +9 -0
- package/dist/integration/SchemaRefreshLaunch.d.ts.map +1 -1
- package/dist/integration/SchemaRefreshLaunch.js +3 -2
- package/dist/integration/SchemaRefreshLaunch.js.map +1 -1
- package/dist/integration/ScopedFieldsForBuild.d.ts +46 -0
- package/dist/integration/ScopedFieldsForBuild.d.ts.map +1 -0
- package/dist/integration/ScopedFieldsForBuild.js +91 -0
- package/dist/integration/ScopedFieldsForBuild.js.map +1 -0
- package/dist/integration/TargetConfigGuard.d.ts +40 -0
- package/dist/integration/TargetConfigGuard.d.ts.map +1 -0
- package/dist/integration/TargetConfigGuard.js +40 -0
- package/dist/integration/TargetConfigGuard.js.map +1 -0
- package/dist/realtimeSessions/ownedRealtimeSession.d.ts.map +1 -1
- package/dist/realtimeSessions/ownedRealtimeSession.js +2 -3
- package/dist/realtimeSessions/ownedRealtimeSession.js.map +1 -1
- package/dist/realtimeSessions/sessionAccess.d.ts +15 -0
- package/dist/realtimeSessions/sessionAccess.d.ts.map +1 -1
- package/dist/realtimeSessions/sessionAccess.js +22 -0
- package/dist/realtimeSessions/sessionAccess.js.map +1 -1
- package/dist/realtimeWidget/WidgetSessionService.d.ts.map +1 -1
- package/dist/realtimeWidget/WidgetSessionService.js +2 -0
- package/dist/realtimeWidget/WidgetSessionService.js.map +1 -1
- package/dist/realtimeWidget/visitorIdentity.d.ts.map +1 -1
- package/dist/realtimeWidget/visitorIdentity.js +1 -0
- package/dist/realtimeWidget/visitorIdentity.js.map +1 -1
- package/dist/realtimeWidget/widgetCore.d.ts.map +1 -1
- package/dist/realtimeWidget/widgetCore.js +4 -7
- package/dist/realtimeWidget/widgetCore.js.map +1 -1
- package/dist/realtimeWidget/widgetGuestElevation.js +1 -0
- package/dist/realtimeWidget/widgetGuestElevation.js.map +1 -1
- package/dist/requestOrigin.d.ts +22 -0
- package/dist/requestOrigin.d.ts.map +1 -0
- package/dist/requestOrigin.js +60 -0
- package/dist/requestOrigin.js.map +1 -0
- package/dist/resolvers/AgentSessionResolver.d.ts.map +1 -1
- package/dist/resolvers/AgentSessionResolver.js +6 -2
- package/dist/resolvers/AgentSessionResolver.js.map +1 -1
- package/dist/resolvers/AutotagPipelineResolver.d.ts.map +1 -1
- package/dist/resolvers/AutotagPipelineResolver.js +2 -1
- package/dist/resolvers/AutotagPipelineResolver.js.map +1 -1
- package/dist/resolvers/ConversationRunEventsResolver.d.ts.map +1 -1
- package/dist/resolvers/ConversationRunEventsResolver.js +2 -0
- package/dist/resolvers/ConversationRunEventsResolver.js.map +1 -1
- package/dist/resolvers/ExecuteRemoteOperationResolver.d.ts +6 -0
- package/dist/resolvers/ExecuteRemoteOperationResolver.d.ts.map +1 -1
- package/dist/resolvers/ExecuteRemoteOperationResolver.js +30 -7
- package/dist/resolvers/ExecuteRemoteOperationResolver.js.map +1 -1
- package/dist/resolvers/GetDataResolver.d.ts.map +1 -1
- package/dist/resolvers/GetDataResolver.js +34 -13
- package/dist/resolvers/GetDataResolver.js.map +1 -1
- package/dist/resolvers/IntegrationDiscoveryResolver.d.ts +401 -11
- package/dist/resolvers/IntegrationDiscoveryResolver.d.ts.map +1 -1
- package/dist/resolvers/IntegrationDiscoveryResolver.js +2690 -1305
- package/dist/resolvers/IntegrationDiscoveryResolver.js.map +1 -1
- package/dist/resolvers/MCPResolver.d.ts.map +1 -1
- package/dist/resolvers/MCPResolver.js +13 -2
- package/dist/resolvers/MCPResolver.js.map +1 -1
- package/dist/resolvers/QuerySystemUserResolver.d.ts +36 -0
- package/dist/resolvers/QuerySystemUserResolver.d.ts.map +1 -1
- package/dist/resolvers/QuerySystemUserResolver.js +174 -87
- package/dist/resolvers/QuerySystemUserResolver.js.map +1 -1
- package/dist/resolvers/RealtimeBridgeResolver.d.ts.map +1 -1
- package/dist/resolvers/RealtimeBridgeResolver.js +1 -0
- package/dist/resolvers/RealtimeBridgeResolver.js.map +1 -1
- package/dist/resolvers/RealtimeClientSessionResolver.d.ts +6 -0
- package/dist/resolvers/RealtimeClientSessionResolver.d.ts.map +1 -1
- package/dist/resolvers/RealtimeClientSessionResolver.js +36 -5
- package/dist/resolvers/RealtimeClientSessionResolver.js.map +1 -1
- package/dist/resolvers/RemoteBrowserActionResolver.d.ts +62 -10
- package/dist/resolvers/RemoteBrowserActionResolver.d.ts.map +1 -1
- package/dist/resolvers/RemoteBrowserActionResolver.js +217 -34
- package/dist/resolvers/RemoteBrowserActionResolver.js.map +1 -1
- package/dist/resolvers/RunAIAgentResolver.d.ts +24 -8
- package/dist/resolvers/RunAIAgentResolver.d.ts.map +1 -1
- package/dist/resolvers/RunAIAgentResolver.js +185 -67
- package/dist/resolvers/RunAIAgentResolver.js.map +1 -1
- package/dist/resolvers/RunAIPromptResolver.d.ts +5 -3
- package/dist/resolvers/RunAIPromptResolver.d.ts.map +1 -1
- package/dist/resolvers/RunAIPromptResolver.js +19 -18
- package/dist/resolvers/RunAIPromptResolver.js.map +1 -1
- package/dist/resolvers/RunTemplateResolver.d.ts.map +1 -1
- package/dist/resolvers/RunTemplateResolver.js +3 -1
- package/dist/resolvers/RunTemplateResolver.js.map +1 -1
- package/dist/resolvers/meetingRecordingRegistration.d.ts.map +1 -1
- package/dist/resolvers/meetingRecordingRegistration.js +2 -0
- package/dist/resolvers/meetingRecordingRegistration.js.map +1 -1
- package/dist/rest/MediaAccessKeys.d.ts.map +1 -1
- package/dist/rest/MediaAccessKeys.js +6 -2
- package/dist/rest/MediaAccessKeys.js.map +1 -1
- package/dist/rest/OAuthCallbackHandler.d.ts.map +1 -1
- package/dist/rest/OAuthCallbackHandler.js +11 -5
- package/dist/rest/OAuthCallbackHandler.js.map +1 -1
- package/dist/rest/RealtimeRecordingHandler.d.ts +3 -3
- package/dist/rest/RealtimeRecordingHandler.d.ts.map +1 -1
- package/dist/rest/RealtimeRecordingHandler.js +2 -4
- package/dist/rest/RealtimeRecordingHandler.js.map +1 -1
- package/dist/rest/ViewOperationsHandler.d.ts.map +1 -1
- package/dist/rest/ViewOperationsHandler.js +2 -1
- package/dist/rest/ViewOperationsHandler.js.map +1 -1
- package/dist/rest/setupRESTEndpoints.d.ts +3 -1
- package/dist/rest/setupRESTEndpoints.d.ts.map +1 -1
- package/dist/rest/setupRESTEndpoints.js +11 -2
- package/dist/rest/setupRESTEndpoints.js.map +1 -1
- package/dist/services/DurableEntityActionTaskSubmitter.d.ts.map +1 -1
- package/dist/services/DurableEntityActionTaskSubmitter.js +6 -1
- package/dist/services/DurableEntityActionTaskSubmitter.js.map +1 -1
- package/dist/services/TaskGraphActionRunner.d.ts.map +1 -1
- package/dist/services/TaskGraphActionRunner.js +2 -26
- package/dist/services/TaskGraphActionRunner.js.map +1 -1
- package/dist/services/TaskGraphAgentRunner.d.ts +6 -0
- package/dist/services/TaskGraphAgentRunner.d.ts.map +1 -1
- package/dist/services/TaskGraphAgentRunner.js +38 -0
- package/dist/services/TaskGraphAgentRunner.js.map +1 -1
- package/dist/services/TaskGraphContinuationDeliverer.d.ts.map +1 -1
- package/dist/services/TaskGraphContinuationDeliverer.js +1 -0
- package/dist/services/TaskGraphContinuationDeliverer.js.map +1 -1
- package/dist/services/WorkQueueHostService.d.ts +2 -1
- package/dist/services/WorkQueueHostService.d.ts.map +1 -1
- package/dist/services/WorkQueueHostService.js +19 -4
- package/dist/services/WorkQueueHostService.js.map +1 -1
- package/dist/services/workQueueConfig.d.ts +2 -2
- package/dist/services/workQueueConfig.js +5 -5
- package/dist/services/workQueueConfig.js.map +1 -1
- package/dist/sharedCache.js +1 -1
- package/dist/sharedCache.js.map +1 -1
- package/dist/types.d.ts +17 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +98 -98
- package/src/__tests__/APIKeyScopeAuth.test.ts +4 -8
- package/src/__tests__/ActiveOperations.test.ts +68 -0
- package/src/__tests__/AgentSessionResolver.ownership.test.ts +13 -0
- package/src/__tests__/AssertTargetConfigs.test.ts +75 -0
- package/src/__tests__/BatchApplyParity.test.ts +109 -0
- package/src/__tests__/BridgeHostInstance.test.ts +42 -0
- package/src/__tests__/CollectInactiveRowWarnings.test.ts +115 -0
- package/src/__tests__/ConnectionPause.test.ts +192 -0
- package/src/__tests__/ConnectionPauseResolver.test.ts +166 -0
- package/src/__tests__/ConnectionPauseSave.test.ts +143 -0
- package/src/__tests__/CustomColumnPromoterCompletion.test.ts +142 -0
- package/src/__tests__/DeleteConnectionRemovesPerConnectionCatalog.test.ts +51 -0
- package/src/__tests__/DetachedDiscoveryStart.test.ts +65 -0
- package/src/__tests__/DurableEntityActionTaskSubmitter.test.ts +73 -0
- package/src/__tests__/EntityMapLifecycle.rekey.test.ts +252 -0
- package/src/__tests__/ExecuteRemoteOperationResolver.test.ts +213 -0
- package/src/__tests__/HandoffOfferExpiry.test.ts +40 -0
- package/src/__tests__/IntegrationRunArtifactAuthorization.test.ts +126 -0
- package/src/__tests__/MagicLinkKeys.test.ts +102 -0
- package/src/__tests__/MediaAccessKeys.test.ts +57 -10
- package/src/__tests__/NewArrivalsDefaultDisabled.test.ts +50 -0
- package/src/__tests__/ObjectNamesByID.test.ts +176 -0
- package/src/__tests__/PostRestartMapsInCatalogScope.test.ts +146 -0
- package/src/__tests__/QuerySystemUserResolver.childRows.test.ts +80 -0
- package/src/__tests__/QuerySystemUserResolver.collision.test.ts +200 -0
- package/src/__tests__/QuerySystemUserResolver.permissions.test.ts +132 -0
- package/src/__tests__/RSUPostRestartProgress.test.ts +343 -0
- package/src/__tests__/RSUProgressBridge.test.ts +188 -5
- package/src/__tests__/RSUStartupSweepWiring.test.ts +30 -0
- package/src/__tests__/ReactivateRefreshMessage.test.ts +10 -3
- package/src/__tests__/RealtimeClientSessionResolver.test.ts +22 -0
- package/src/__tests__/{RefreshAdoptsNewColumns.test.ts → RefreshReportsNewColumns.test.ts} +25 -16
- package/src/__tests__/RemoteBrowserActionRecovery.test.ts +287 -0
- package/src/__tests__/RemoteBrowserActionResolver.goalRunLink.test.ts +3 -0
- package/src/__tests__/RemoteBrowserActionResolver.ownership.test.ts +6 -4
- package/src/__tests__/RemoteBrowserAudioStream.test.ts +3 -0
- package/src/__tests__/RemoteBrowserSnapshot.test.ts +3 -0
- package/src/__tests__/ResolverBase.clientOldValues.test.ts +323 -26
- package/src/__tests__/ResolverBase.encryptedApiZeroReencrypt.test.ts +307 -0
- package/src/__tests__/ResolverBase.entityMessageRelay.test.ts +53 -2
- package/src/__tests__/ResolverBase.includeBinaryFields.test.ts +60 -0
- package/src/__tests__/RunAIAgentResolver.branch.test.ts +4 -0
- package/src/__tests__/RunAIAgentResolver.consultPredecessor.test.ts +289 -0
- package/src/__tests__/RunAIAgentResolver.handoff.test.ts +649 -0
- package/src/__tests__/RunAIAgentResolver.historyFrom.test.ts +2 -0
- package/src/__tests__/RunAIAgentResolver.runDataGuard.test.ts +2 -0
- package/src/__tests__/RunAIAgentResolver.stoppedPredecessor.test.ts +87 -12
- package/src/__tests__/SchemaEvolutionCustomColumns.test.ts +119 -0
- package/src/__tests__/SchemaRefreshLaunch.test.ts +24 -2
- package/src/__tests__/ScopedFieldsForBuild.test.ts +192 -0
- package/src/__tests__/SessionJanitor.test.ts +195 -4
- package/src/__tests__/SessionManager.test.ts +69 -0
- package/src/__tests__/TaskGraphActionRunner.durablePayload.test.ts +2 -2
- package/src/__tests__/TaskGraphAgentRunner.test.ts +272 -16
- package/src/__tests__/ViewOperationsHandler.test.ts +2 -5
- package/src/__tests__/WorkQueueHostService.test.ts +25 -7
- package/src/__tests__/backgroundSweepConfigUnits.test.ts +153 -0
- package/src/__tests__/contextRequestOrigin.test.ts +105 -0
- package/src/__tests__/conversationBrowsers.test.ts +62 -0
- package/src/__tests__/magicLinkExtensionCapabilities.test.ts +413 -0
- package/src/__tests__/orphanedConversationDetailReconciler.start.test.ts +82 -0
- package/src/__tests__/ownedRealtimeSession.test.ts +14 -0
- package/src/__tests__/realtimeRecordingHandler.test.ts +7 -2
- package/src/__tests__/realtimeSessions/sessionAccess.test.ts +79 -1
- package/src/__tests__/requestOrigin.test.ts +104 -0
- package/src/__tests__/securityHardeningPr6034.test.ts +120 -0
- package/src/__tests__/sessionDeadline.test.ts +51 -0
- package/src/__tests__/sharedCache.test.ts +11 -0
- package/src/__tests__/unifiedAuth.test.ts +73 -1
- package/src/agentSessions/BridgeHostInstance.ts +20 -5
- package/src/agentSessions/HandoffOfferExpiry.ts +18 -0
- package/src/agentSessions/ReturningVisitorRecap.ts +1 -0
- package/src/agentSessions/SessionJanitor.ts +92 -42
- package/src/agentSessions/SessionManager.ts +38 -8
- package/src/agentSessions/conversationBrowsers.ts +143 -0
- package/src/agentSessions/sessionDeadline.ts +81 -0
- package/src/auth/APIKeyScopeAuth.ts +5 -4
- package/src/auth/__tests__/loginEmailResolution.test.ts +67 -0
- package/src/auth/loginEmailResolution.ts +67 -0
- package/src/auth/magicLink/MagicLinkKeys.ts +146 -14
- package/src/auth/magicLink/MagicLinkRouter.ts +33 -6
- package/src/auth/magicLink/MagicLinkService.ts +250 -10
- package/src/auth/magicLink/index.ts +1 -1
- package/src/auth/magicLink/redeemLanding.ts +7 -4
- package/src/auth/magicLink/types.ts +28 -3
- package/src/auth/newUsers.ts +1 -0
- package/src/backgroundSweepConfigUnits.ts +213 -0
- package/src/config.ts +69 -0
- package/src/context.ts +39 -6
- package/src/coreRoutes.ts +14 -7
- package/src/generated/graphql-schemas/__mj.ts +822 -7
- package/src/generic/OrphanedConversationDetailReconciler.ts +32 -1
- package/src/generic/ResolverBase.ts +414 -143
- package/src/generic/RunViewResolver.ts +96 -49
- package/src/index.ts +201 -35
- package/src/integration/ConnectionPause.ts +222 -0
- package/src/integration/CustomColumnPromoter.ts +123 -53
- package/src/integration/EntityMapLifecycle.ts +229 -6
- package/src/integration/InactiveRowWarnings.ts +50 -0
- package/src/integration/ObjectNamesByID.ts +97 -0
- package/src/integration/PostRestartIntrospect.ts +49 -0
- package/src/integration/RSUPostRestartProgress.ts +359 -0
- package/src/integration/RSUProgressBridge.ts +85 -2
- package/src/integration/RunArtifactAuthorization.ts +65 -0
- package/src/integration/SchemaRefreshLaunch.ts +12 -2
- package/src/integration/ScopedFieldsForBuild.ts +113 -0
- package/src/integration/TargetConfigGuard.ts +71 -0
- package/src/realtimeSessions/ownedRealtimeSession.ts +2 -6
- package/src/realtimeSessions/sessionAccess.ts +30 -0
- package/src/realtimeWidget/WidgetSessionService.ts +2 -0
- package/src/realtimeWidget/visitorIdentity.ts +1 -0
- package/src/realtimeWidget/widgetCore.ts +4 -8
- package/src/realtimeWidget/widgetGuestElevation.ts +1 -0
- package/src/requestOrigin.ts +64 -0
- package/src/resolvers/AgentSessionResolver.ts +6 -2
- package/src/resolvers/AutotagPipelineResolver.ts +2 -1
- package/src/resolvers/ConversationRunEventsResolver.ts +2 -0
- package/src/resolvers/ExecuteRemoteOperationResolver.ts +41 -9
- package/src/resolvers/GetDataResolver.ts +35 -13
- package/src/resolvers/IntegrationDiscoveryResolver.ts +1522 -203
- package/src/resolvers/MCPResolver.ts +15 -2
- package/src/resolvers/QuerySystemUserResolver.ts +197 -98
- package/src/resolvers/RealtimeBridgeResolver.ts +1 -0
- package/src/resolvers/RealtimeClientSessionResolver.ts +40 -7
- package/src/resolvers/RemoteBrowserActionResolver.ts +242 -32
- package/src/resolvers/RunAIAgentResolver.ts +265 -86
- package/src/resolvers/RunAIPromptResolver.ts +18 -18
- package/src/resolvers/RunTemplateResolver.ts +3 -1
- package/src/resolvers/__tests__/GetDataResolver.tokens.test.ts +52 -0
- package/src/resolvers/meetingRecordingRegistration.ts +2 -0
- package/src/rest/MediaAccessKeys.ts +6 -2
- package/src/rest/OAuthCallbackHandler.ts +13 -5
- package/src/rest/RealtimeRecordingHandler.ts +5 -9
- package/src/rest/ViewOperationsHandler.ts +2 -1
- package/src/rest/setupRESTEndpoints.ts +11 -2
- package/src/services/DurableEntityActionTaskSubmitter.ts +10 -2
- package/src/services/TaskGraphActionRunner.ts +2 -23
- package/src/services/TaskGraphAgentRunner.ts +43 -0
- package/src/services/TaskGraphContinuationDeliverer.ts +1 -0
- package/src/services/WorkQueueHostService.ts +26 -4
- package/src/services/workQueueConfig.ts +5 -5
- package/src/sharedCache.ts +1 -1
- package/src/types.ts +18 -0
- package/src/services/TaskOrchestration-Integration.md +0 -188
|
@@ -1,19 +1,54 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Tests for `TaskGraphAgentRunner
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* via `AgentRunner.ProcessAgentArtifacts`.
|
|
2
|
+
* Tests for `TaskGraphAgentRunner`:
|
|
3
|
+
* - VS-CON-7 preset resolution (`ConfigurationPresetName`)
|
|
4
|
+
* - VS-INV-2b / VS-QA-3 #9 `parentAgentHierarchy` from submitted task
|
|
5
|
+
* - Specialist agent artifact persistence (`ProcessAgentArtifacts`), `CanUserRunAgent` permission check,
|
|
6
|
+
* task Name/Description prompt formatting, and output normalization.
|
|
8
7
|
*/
|
|
9
8
|
import 'reflect-metadata';
|
|
10
9
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
10
|
+
import type { IMetadataProvider, UserInfo } from '@memberjunction/core';
|
|
11
|
+
import type { TaskAgentRunParams } from '@memberjunction/task-graph';
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
const {
|
|
14
|
+
runAgent,
|
|
15
|
+
processAgentArtifacts,
|
|
16
|
+
canUserRunAgent,
|
|
17
|
+
mockEngineAgents,
|
|
18
|
+
mockGetAgentConfigurationPresets,
|
|
19
|
+
mockEngineConfig,
|
|
20
|
+
mockRunView,
|
|
21
|
+
mockLogError,
|
|
22
|
+
} = vi.hoisted(() => ({
|
|
23
|
+
runAgent: vi.fn(),
|
|
24
|
+
processAgentArtifacts: vi.fn(),
|
|
25
|
+
canUserRunAgent: vi.fn().mockResolvedValue(true),
|
|
26
|
+
mockEngineAgents: [
|
|
27
|
+
{ ID: 'agent-1', Name: 'Storyboard Artist' },
|
|
28
|
+
{ ID: 'qb-agent' },
|
|
29
|
+
{ ID: 'writer-agent' },
|
|
30
|
+
] as Array<{ ID: string; Name?: string }>,
|
|
31
|
+
mockGetAgentConfigurationPresets: vi.fn(),
|
|
32
|
+
mockEngineConfig: vi.fn(),
|
|
33
|
+
mockRunView: vi.fn(),
|
|
34
|
+
mockLogError: vi.fn(),
|
|
15
35
|
}));
|
|
16
36
|
|
|
37
|
+
const mockRunAgent = runAgent;
|
|
38
|
+
|
|
39
|
+
vi.mock('@memberjunction/core', async (importOriginal) => {
|
|
40
|
+
const actual = await importOriginal<typeof import('@memberjunction/core')>();
|
|
41
|
+
return {
|
|
42
|
+
...actual,
|
|
43
|
+
LogError: (...args: unknown[]) => mockLogError(...args),
|
|
44
|
+
LogStatus: vi.fn(),
|
|
45
|
+
RunView: class {
|
|
46
|
+
static FromMetadataProvider = () => ({ RunView: mockRunView });
|
|
47
|
+
RunView = mockRunView;
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
});
|
|
51
|
+
|
|
17
52
|
vi.mock('@memberjunction/generic-database-provider', () => ({
|
|
18
53
|
UserCache: {
|
|
19
54
|
Instance: { Users: [] },
|
|
@@ -31,31 +66,251 @@ vi.mock('@memberjunction/ai-core-plus', () => ({
|
|
|
31
66
|
}));
|
|
32
67
|
vi.mock('@memberjunction/ai', () => ({ ChatMessageRole: { user: 'user' } }));
|
|
33
68
|
|
|
34
|
-
const { runAgent, processAgentArtifacts, canUserRunAgent, mockEngineAgents } = vi.hoisted(() => ({
|
|
35
|
-
runAgent: vi.fn(),
|
|
36
|
-
processAgentArtifacts: vi.fn(),
|
|
37
|
-
canUserRunAgent: vi.fn().mockResolvedValue(true),
|
|
38
|
-
mockEngineAgents: [{ ID: 'qb-agent' }, { ID: 'writer-agent' }] as Array<{ ID: string }>,
|
|
39
|
-
}));
|
|
40
69
|
vi.mock('@memberjunction/ai-agents', () => ({
|
|
41
70
|
AgentRunner: class {
|
|
42
71
|
RunAgent = runAgent;
|
|
43
72
|
ProcessAgentArtifacts = processAgentArtifacts;
|
|
44
73
|
},
|
|
45
74
|
}));
|
|
75
|
+
|
|
46
76
|
vi.mock('@memberjunction/aiengine', () => ({
|
|
47
77
|
AIEngine: {
|
|
48
78
|
get Instance() {
|
|
49
79
|
return {
|
|
80
|
+
Config: mockEngineConfig,
|
|
50
81
|
Agents: mockEngineAgents,
|
|
51
82
|
CanUserRunAgent: canUserRunAgent,
|
|
83
|
+
GetAgentConfigurationPresets: mockGetAgentConfigurationPresets,
|
|
84
|
+
FindActiveAgentConfigurationPreset: (agentId: string, presetName: string) => {
|
|
85
|
+
const target = presetName.trim().toLowerCase();
|
|
86
|
+
if (!target) return undefined;
|
|
87
|
+
const presets = (mockGetAgentConfigurationPresets(agentId, true) ?? []) as Array<{
|
|
88
|
+
Name?: string;
|
|
89
|
+
DisplayName?: string;
|
|
90
|
+
}>;
|
|
91
|
+
return presets.find((p) => p.Name?.trim().toLowerCase() === target)
|
|
92
|
+
?? presets.find((p) => p.DisplayName?.trim().toLowerCase() === target);
|
|
93
|
+
},
|
|
52
94
|
};
|
|
53
95
|
},
|
|
54
96
|
},
|
|
55
97
|
}));
|
|
56
98
|
|
|
57
99
|
import { TaskGraphAgentRunner } from '../services/TaskGraphAgentRunner';
|
|
58
|
-
|
|
100
|
+
|
|
101
|
+
interface SubmittingRunOverrides {
|
|
102
|
+
ID?: string;
|
|
103
|
+
ConfigurationID?: string | null;
|
|
104
|
+
Agent?: string | null;
|
|
105
|
+
AgentID?: string | null;
|
|
106
|
+
ParentRunID?: string | null;
|
|
107
|
+
LoadSuccess?: boolean;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function makeParams(
|
|
111
|
+
overrides: Partial<TaskAgentRunParams> = {},
|
|
112
|
+
parentConfigurationID: string | null = 'parent-cfg-1',
|
|
113
|
+
submittingRunOverrides: SubmittingRunOverrides = {},
|
|
114
|
+
): TaskAgentRunParams {
|
|
115
|
+
const loadSuccess = submittingRunOverrides.LoadSuccess ?? true;
|
|
116
|
+
const provider = {
|
|
117
|
+
GetEntityObject: vi.fn().mockImplementation(async (entityName: string) => {
|
|
118
|
+
if (entityName === 'MJ: AI Agents') {
|
|
119
|
+
return {
|
|
120
|
+
Load: vi.fn().mockResolvedValue(true),
|
|
121
|
+
ID: overrides.AgentID ?? 'agent-1',
|
|
122
|
+
Name: 'Storyboard Artist',
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
if (entityName === 'MJ: Tasks') {
|
|
126
|
+
return {
|
|
127
|
+
Load: vi.fn().mockResolvedValue(false),
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
return {
|
|
131
|
+
Load: vi.fn().mockResolvedValue(loadSuccess),
|
|
132
|
+
ID: submittingRunOverrides.ID ?? 'submitting-run-1',
|
|
133
|
+
ConfigurationID:
|
|
134
|
+
'ConfigurationID' in submittingRunOverrides
|
|
135
|
+
? submittingRunOverrides.ConfigurationID
|
|
136
|
+
: parentConfigurationID,
|
|
137
|
+
Agent: submittingRunOverrides.Agent ?? null,
|
|
138
|
+
AgentID: submittingRunOverrides.AgentID ?? null,
|
|
139
|
+
ParentRunID: submittingRunOverrides.ParentRunID ?? null,
|
|
140
|
+
};
|
|
141
|
+
}),
|
|
142
|
+
} as unknown as IMetadataProvider;
|
|
143
|
+
|
|
144
|
+
return {
|
|
145
|
+
TaskID: 'task-1',
|
|
146
|
+
AgentID: 'agent-1',
|
|
147
|
+
InputPayload: 'Draw the opening shot',
|
|
148
|
+
DependencyOutputs: new Map(),
|
|
149
|
+
SubmittingAgentRunID: 'submitting-run-1',
|
|
150
|
+
Provider: provider,
|
|
151
|
+
ContextUser: { ID: 'user-1' } as unknown as UserInfo,
|
|
152
|
+
...overrides,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
describe('VS-CON-7: TaskGraphAgentRunner preset resolution', () => {
|
|
157
|
+
beforeEach(() => {
|
|
158
|
+
vi.clearAllMocks();
|
|
159
|
+
canUserRunAgent.mockResolvedValue(true);
|
|
160
|
+
processAgentArtifacts.mockResolvedValue(undefined);
|
|
161
|
+
mockEngineConfig.mockResolvedValue(undefined);
|
|
162
|
+
mockRunAgent.mockResolvedValue({
|
|
163
|
+
success: true,
|
|
164
|
+
agentRun: { ID: 'child-run-1', Message: 'Done' },
|
|
165
|
+
payload: { result: 'ok' },
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it('resolves ConfigurationPresetName to the matching preset AIConfigurationID', async () => {
|
|
170
|
+
mockGetAgentConfigurationPresets.mockReturnValue([
|
|
171
|
+
{
|
|
172
|
+
ID: 'preset-draft',
|
|
173
|
+
Name: 'Draft',
|
|
174
|
+
DisplayName: 'Draft Mode',
|
|
175
|
+
AIConfigurationID: 'cfg-draft-1',
|
|
176
|
+
Status: 'Active',
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
ID: 'preset-high',
|
|
180
|
+
Name: 'High',
|
|
181
|
+
DisplayName: 'High Fidelity',
|
|
182
|
+
AIConfigurationID: 'cfg-high-1',
|
|
183
|
+
Status: 'Active',
|
|
184
|
+
},
|
|
185
|
+
]);
|
|
186
|
+
|
|
187
|
+
const runner = new TaskGraphAgentRunner();
|
|
188
|
+
const result = await runner.RunAgentForTask(
|
|
189
|
+
makeParams({ ConfigurationPresetName: 'high fidelity' })
|
|
190
|
+
);
|
|
191
|
+
|
|
192
|
+
expect(result.Success).toBe(true);
|
|
193
|
+
expect(mockRunAgent).toHaveBeenCalledTimes(1);
|
|
194
|
+
expect(mockRunAgent.mock.calls[0][0].configurationId).toBe('cfg-high-1');
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it('passes configurationId: undefined when the matched preset has NULL AIConfigurationID, even if the submitting run has a ConfigurationID', async () => {
|
|
198
|
+
mockGetAgentConfigurationPresets.mockReturnValue([
|
|
199
|
+
{
|
|
200
|
+
ID: 'preset-default',
|
|
201
|
+
Name: 'SystemDefault',
|
|
202
|
+
DisplayName: 'System Default',
|
|
203
|
+
AIConfigurationID: null,
|
|
204
|
+
Status: 'Active',
|
|
205
|
+
},
|
|
206
|
+
]);
|
|
207
|
+
|
|
208
|
+
const runner = new TaskGraphAgentRunner();
|
|
209
|
+
const result = await runner.RunAgentForTask(
|
|
210
|
+
makeParams({ ConfigurationPresetName: 'SystemDefault' }, 'parent-cfg-1')
|
|
211
|
+
);
|
|
212
|
+
|
|
213
|
+
expect(result.Success).toBe(true);
|
|
214
|
+
expect(mockRunAgent).toHaveBeenCalledTimes(1);
|
|
215
|
+
expect(mockRunAgent.mock.calls[0][0].configurationId).toBeUndefined();
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
it('falls back to the submitting run ConfigurationID when ConfigurationPresetName is not specified', async () => {
|
|
219
|
+
const runner = new TaskGraphAgentRunner();
|
|
220
|
+
const result = await runner.RunAgentForTask(makeParams({}, 'parent-cfg-99'));
|
|
221
|
+
|
|
222
|
+
expect(result.Success).toBe(true);
|
|
223
|
+
expect(mockRunAgent).toHaveBeenCalledTimes(1);
|
|
224
|
+
expect(mockRunAgent.mock.calls[0][0].configurationId).toBe('parent-cfg-99');
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
it('fails the task with a clear message when ConfigurationPresetName does not match any active preset at run time', async () => {
|
|
228
|
+
mockGetAgentConfigurationPresets.mockReturnValue([
|
|
229
|
+
{
|
|
230
|
+
ID: 'preset-draft',
|
|
231
|
+
Name: 'Draft',
|
|
232
|
+
DisplayName: 'Draft Mode',
|
|
233
|
+
AIConfigurationID: 'cfg-draft-1',
|
|
234
|
+
Status: 'Active',
|
|
235
|
+
},
|
|
236
|
+
]);
|
|
237
|
+
|
|
238
|
+
const runner = new TaskGraphAgentRunner();
|
|
239
|
+
const result = await runner.RunAgentForTask(
|
|
240
|
+
makeParams({ ConfigurationPresetName: 'DeletedPreset' })
|
|
241
|
+
);
|
|
242
|
+
|
|
243
|
+
expect(result.Success).toBe(false);
|
|
244
|
+
expect(result.ErrorMessage).toBe(
|
|
245
|
+
"Agent 'Storyboard Artist' has no active preset 'DeletedPreset'. Available: Draft."
|
|
246
|
+
);
|
|
247
|
+
expect(mockRunAgent).not.toHaveBeenCalled();
|
|
248
|
+
});
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
describe('VS-INV-2b / VS-QA-3 #9: TaskGraphAgentRunner parentAgentHierarchy from submitted task', () => {
|
|
252
|
+
const RUN_B_ID = '22222222-2222-4222-8222-222222222222';
|
|
253
|
+
const RUN_C_ID = '33333333-3333-4333-8333-333333333333';
|
|
254
|
+
|
|
255
|
+
beforeEach(() => {
|
|
256
|
+
vi.clearAllMocks();
|
|
257
|
+
canUserRunAgent.mockResolvedValue(true);
|
|
258
|
+
processAgentArtifacts.mockResolvedValue(undefined);
|
|
259
|
+
mockEngineConfig.mockResolvedValue(undefined);
|
|
260
|
+
mockRunAgent.mockResolvedValue({
|
|
261
|
+
success: true,
|
|
262
|
+
agentRun: { ID: 'child-run-1', Message: 'Done' },
|
|
263
|
+
payload: { result: 'ok' },
|
|
264
|
+
});
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
it('reads root-first ParentAgentHierarchy carried from the submitted task without running RunView in a loop (VS-QA-3 #9)', async () => {
|
|
268
|
+
const runner = new TaskGraphAgentRunner();
|
|
269
|
+
const params = makeParams(
|
|
270
|
+
{
|
|
271
|
+
SubmittingAgentRunID: RUN_C_ID,
|
|
272
|
+
ParentAgentHierarchy: ['A', 'B', 'C'],
|
|
273
|
+
},
|
|
274
|
+
'parent-cfg-1',
|
|
275
|
+
{ ID: RUN_C_ID, Agent: 'C', ParentRunID: RUN_B_ID },
|
|
276
|
+
);
|
|
277
|
+
|
|
278
|
+
const result = await runner.RunAgentForTask(params);
|
|
279
|
+
|
|
280
|
+
expect(result.Success).toBe(true);
|
|
281
|
+
expect(mockRunView).not.toHaveBeenCalled();
|
|
282
|
+
expect(mockRunAgent).toHaveBeenCalledTimes(1);
|
|
283
|
+
expect(mockRunAgent.mock.calls[0][0].parentAgentHierarchy).toEqual(['A', 'B', 'C']);
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
it('falls back to the loaded parentRun agent name when ParentAgentHierarchy is omitted, with zero RunView calls', async () => {
|
|
287
|
+
const runner = new TaskGraphAgentRunner();
|
|
288
|
+
const params = makeParams(
|
|
289
|
+
{ SubmittingAgentRunID: RUN_C_ID },
|
|
290
|
+
'parent-cfg-1',
|
|
291
|
+
{ ID: RUN_C_ID, Agent: 'C', ParentRunID: RUN_B_ID },
|
|
292
|
+
);
|
|
293
|
+
|
|
294
|
+
const result = await runner.RunAgentForTask(params);
|
|
295
|
+
|
|
296
|
+
expect(result.Success).toBe(true);
|
|
297
|
+
expect(mockRunView).not.toHaveBeenCalled();
|
|
298
|
+
expect(mockRunAgent).toHaveBeenCalledTimes(1);
|
|
299
|
+
expect(mockRunAgent.mock.calls[0][0].parentAgentHierarchy).toEqual(['C']);
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
it('passes undefined parentAgentHierarchy and performs no RunView reads when there is no parentRun and no ParentAgentHierarchy', async () => {
|
|
303
|
+
const runner = new TaskGraphAgentRunner();
|
|
304
|
+
const result = await runner.RunAgentForTask(
|
|
305
|
+
makeParams({ SubmittingAgentRunID: undefined }),
|
|
306
|
+
);
|
|
307
|
+
|
|
308
|
+
expect(result.Success).toBe(true);
|
|
309
|
+
expect(mockRunView).not.toHaveBeenCalled();
|
|
310
|
+
expect(mockRunAgent).toHaveBeenCalledTimes(1);
|
|
311
|
+
expect(mockRunAgent.mock.calls[0][0].parentAgentHierarchy).toBeUndefined();
|
|
312
|
+
});
|
|
313
|
+
});
|
|
59
314
|
|
|
60
315
|
describe('TaskGraphAgentRunner', () => {
|
|
61
316
|
beforeEach(() => {
|
|
@@ -264,3 +519,4 @@ describe('TaskGraphAgentRunner', () => {
|
|
|
264
519
|
});
|
|
265
520
|
});
|
|
266
521
|
|
|
522
|
+
|
|
@@ -267,16 +267,13 @@ describe('ViewOperationsHandler.getEntityViews', () => {
|
|
|
267
267
|
expect(outcome.error).toBe('timeout talking to DB');
|
|
268
268
|
});
|
|
269
269
|
|
|
270
|
-
it('
|
|
271
|
-
// Reachable only for names registered in metadata, so a hostile value requires a
|
|
272
|
-
// hostile entity name — but an entity legitimately named with an apostrophe
|
|
273
|
-
// (e.g. "O'Brien Records") already produces a broken/injectable filter today.
|
|
270
|
+
it('escapes single quotes in the entity name when building ExtraFilter', async () => {
|
|
274
271
|
registerEntity("O'Brien Records", true);
|
|
275
272
|
mockRunViewFn.mockResolvedValue({ Success: true, Results: [] });
|
|
276
273
|
|
|
277
274
|
await ViewOperationsHandler.getEntityViews("O'Brien Records", makeUser());
|
|
278
275
|
|
|
279
276
|
const executed = mockRunViewFn.mock.calls[0][0] as RunViewParams;
|
|
280
|
-
expect(executed.ExtraFilter).toBe(`Entity = 'O'Brien Records'`);
|
|
277
|
+
expect(executed.ExtraFilter).toBe(`Entity = 'O''Brien Records'`);
|
|
281
278
|
});
|
|
282
279
|
});
|
|
@@ -56,9 +56,9 @@ function enabled(overrides: Partial<WorkQueueConfig> = {}): WorkQueueConfig {
|
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
describe('workQueue configuration', () => {
|
|
59
|
-
it('defaults to
|
|
59
|
+
it('defaults to enabled, running every MJWorker subscription out of the box', () => {
|
|
60
60
|
expect(WorkQueueSchema.parse({})).toEqual({
|
|
61
|
-
enabled:
|
|
61
|
+
enabled: true, systemUserEmail: 'system@memberjunction.org', subscriptions: [{ name: '*', concurrency: 4 }],
|
|
62
62
|
idlePollMinMs: 250, idlePollMaxMs: 5000, shutdownDrainMs: 8000, sweeperEnabled: true, sweeperIntervalMs: 60000,
|
|
63
63
|
reconcileIntervalMs: 30000,
|
|
64
64
|
});
|
|
@@ -94,7 +94,7 @@ describe('host configuration helpers', () => {
|
|
|
94
94
|
describe('StartWorkQueueHost', () => {
|
|
95
95
|
it('starts nothing when the section is disabled', async () => {
|
|
96
96
|
const rec = recorder();
|
|
97
|
-
expect(await StartWorkQueueHost(WorkQueueSchema.parse({}), PROVIDER, PROVIDER_SOURCE, rec.Dependencies)).toBeNull();
|
|
97
|
+
expect(await StartWorkQueueHost(WorkQueueSchema.parse({ enabled: false }), PROVIDER, PROVIDER_SOURCE, rec.Dependencies)).toBeNull();
|
|
98
98
|
expect(rec.EngineCalls).toBe(0);
|
|
99
99
|
});
|
|
100
100
|
|
|
@@ -109,9 +109,18 @@ describe('StartWorkQueueHost', () => {
|
|
|
109
109
|
await expect(StartWorkQueueHost(enabled(), PROVIDER, PROVIDER_SOURCE, rec.Dependencies)).rejects.toThrow('System user not found with email: system@memberjunction.org');
|
|
110
110
|
});
|
|
111
111
|
|
|
112
|
-
it('
|
|
113
|
-
const rec = recorder();
|
|
114
|
-
|
|
112
|
+
it('falls back to FindSystemUser when default systemUserEmail is not literal in UserCache', async () => {
|
|
113
|
+
const rec = recorder([]);
|
|
114
|
+
rec.Dependencies.FindSystemUser = () => SYSTEM_USER;
|
|
115
|
+
const host = await StartWorkQueueHost(WorkQueueSchema.parse({}), PROVIDER, PROVIDER_SOURCE, rec.Dependencies);
|
|
116
|
+
expect(host).not.toBeNull();
|
|
117
|
+
expect(rec.EngineCalls).toBe(1);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('names the setting to fix when an explicit custom email is not found even if FindSystemUser exists', async () => {
|
|
121
|
+
const rec = recorder([]);
|
|
122
|
+
rec.Dependencies.FindSystemUser = () => SYSTEM_USER;
|
|
123
|
+
await expect(StartWorkQueueHost(enabled({ systemUserEmail: 'missing-worker@example.com' }), PROVIDER, PROVIDER_SOURCE, rec.Dependencies))
|
|
115
124
|
.rejects.toThrow('set workQueue.systemUserEmail');
|
|
116
125
|
});
|
|
117
126
|
|
|
@@ -126,7 +135,16 @@ describe('StartWorkQueueHost', () => {
|
|
|
126
135
|
});
|
|
127
136
|
|
|
128
137
|
describe('MJServerWorkQueueProviderSource', () => {
|
|
129
|
-
it('
|
|
138
|
+
it('mints an independent provider instance when fallback implements CreateIndependentInstance (e.g. PostgreSQL)', async () => {
|
|
139
|
+
const independent = { Name: 'independent-pg-provider' } as IMetadataProvider;
|
|
140
|
+
const createIndependent = vi.fn().mockResolvedValue(independent);
|
|
141
|
+
const pgFallback = Object.assign({}, PROVIDER, { CreateIndependentInstance: createIndependent });
|
|
142
|
+
const source = new MJServerWorkQueueProviderSource(null, pgFallback);
|
|
143
|
+
expect(await source.CreateProvider()).toBe(independent);
|
|
144
|
+
expect(createIndependent).toHaveBeenCalledTimes(1);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it('falls back to the shared server provider when there is no SQL Server pool and no CreateIndependentInstance', async () => {
|
|
130
148
|
const source = new MJServerWorkQueueProviderSource(null, PROVIDER);
|
|
131
149
|
expect(await source.CreateProvider()).toBe(PROVIDER);
|
|
132
150
|
});
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config contract for the two background sweeps an idle MJAPI runs against its database: the AI
|
|
3
|
+
* Agent Session janitor (`agentSessions.janitor`) and the agent-run watchdog (`agentRunWatchdog`).
|
|
4
|
+
*
|
|
5
|
+
* Pins three things: the shipped defaults are exactly the values MJAPI always ran with (so existing
|
|
6
|
+
* deployments see no change), each sweep can be turned off the documented way, and the env-var
|
|
7
|
+
* readers that feed `DEFAULT_SERVER_CONFIG` reject typos instead of silently running a default or
|
|
8
|
+
* a zero-delay timer.
|
|
9
|
+
*/
|
|
10
|
+
import { describe, it, expect } from 'vitest';
|
|
11
|
+
import {
|
|
12
|
+
AgentRunWatchdogDefaultsFromEnv,
|
|
13
|
+
AgentRunWatchdogSchema,
|
|
14
|
+
AgentSessionsDefaultsFromEnv,
|
|
15
|
+
AgentSessionsSchema,
|
|
16
|
+
ConversationDetailReconcilerDefaultsFromEnv,
|
|
17
|
+
ConversationDetailReconcilerSchema,
|
|
18
|
+
EnabledFromEnv,
|
|
19
|
+
IntervalMsFromEnv,
|
|
20
|
+
} from '../backgroundSweepConfigUnits.js';
|
|
21
|
+
|
|
22
|
+
describe('agentSessions.janitor schema', () => {
|
|
23
|
+
it('defaults to what MJAPI has always run: janitor on every 60s (15-minute idle close), bridge reconcile on every 10 min', () => {
|
|
24
|
+
expect(AgentSessionsSchema.parse({})).toEqual({
|
|
25
|
+
janitor: { enabled: true, sweepIntervalMs: 60_000, closeThresholdMinutes: 15 },
|
|
26
|
+
bridgeReconciler: { enabled: true, sweepIntervalMs: 600_000 },
|
|
27
|
+
handoffOfferExpiry: { enabled: true, sweepIntervalMs: 15_000 },
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('accepts enabled: false and a longer interval', () => {
|
|
32
|
+
const parsed = AgentSessionsSchema.parse({ janitor: { enabled: false, sweepIntervalMs: 3_600_000 }, bridgeReconciler: { enabled: false } });
|
|
33
|
+
expect(parsed.janitor).toEqual({ enabled: false, sweepIntervalMs: 3_600_000, closeThresholdMinutes: 15 });
|
|
34
|
+
expect(parsed.bridgeReconciler).toEqual({ enabled: false, sweepIntervalMs: 600_000 });
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('rejects a zero or negative interval (turn the tick off with enabled: false instead)', () => {
|
|
38
|
+
expect(AgentSessionsSchema.safeParse({ janitor: { sweepIntervalMs: 0 } }).success).toBe(false);
|
|
39
|
+
expect(AgentSessionsSchema.safeParse({ janitor: { closeThresholdMinutes: -1 } }).success).toBe(false);
|
|
40
|
+
expect(AgentSessionsSchema.safeParse({ bridgeReconciler: { sweepIntervalMs: 0 } }).success).toBe(false);
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
describe('conversationDetailReconciler schema', () => {
|
|
45
|
+
it('defaults to what MJAPI has always run: on, every 5 minutes', () => {
|
|
46
|
+
expect(ConversationDetailReconcilerSchema.parse({})).toEqual({ enabled: true, sweepIntervalMs: 300_000 });
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('accepts enabled: false and rejects a zero interval', () => {
|
|
50
|
+
expect(ConversationDetailReconcilerSchema.parse({ enabled: false }).enabled).toBe(false);
|
|
51
|
+
expect(ConversationDetailReconcilerSchema.safeParse({ sweepIntervalMs: 0 }).success).toBe(false);
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
describe('DEFAULT_SERVER_CONFIG blocks from the environment', () => {
|
|
56
|
+
it('an empty environment gives exactly the shipped defaults', () => {
|
|
57
|
+
expect(AgentSessionsDefaultsFromEnv({})).toEqual(AgentSessionsSchema.parse({}));
|
|
58
|
+
expect(ConversationDetailReconcilerDefaultsFromEnv({})).toEqual(ConversationDetailReconcilerSchema.parse({}));
|
|
59
|
+
expect(AgentRunWatchdogDefaultsFromEnv({})).toEqual(AgentRunWatchdogSchema.parse({}));
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('reads every documented variable', () => {
|
|
63
|
+
const env = {
|
|
64
|
+
MJ_SESSION_JANITOR_ENABLED: 'false',
|
|
65
|
+
MJ_SESSION_JANITOR_SWEEP_INTERVAL_MS: '120000',
|
|
66
|
+
MJ_BRIDGE_RECONCILER_ENABLED: 'off',
|
|
67
|
+
MJ_BRIDGE_RECONCILER_SWEEP_INTERVAL_MS: '1200000',
|
|
68
|
+
MJ_CONVERSATION_DETAIL_RECONCILER_ENABLED: '0',
|
|
69
|
+
MJ_CONVERSATION_DETAIL_RECONCILER_SWEEP_INTERVAL_MS: '900000',
|
|
70
|
+
MJ_HANDOFF_OFFER_EXPIRY_ENABLED: 'no',
|
|
71
|
+
MJ_HANDOFF_OFFER_EXPIRY_SWEEP_INTERVAL_MS: '60000',
|
|
72
|
+
MJ_AGENT_RUN_WATCHDOG_SWEEP_INTERVAL_MS: '0',
|
|
73
|
+
};
|
|
74
|
+
expect(AgentSessionsDefaultsFromEnv(env)).toEqual({
|
|
75
|
+
janitor: { enabled: false, sweepIntervalMs: 120_000, closeThresholdMinutes: 15 },
|
|
76
|
+
bridgeReconciler: { enabled: false, sweepIntervalMs: 1_200_000 },
|
|
77
|
+
handoffOfferExpiry: { enabled: false, sweepIntervalMs: 60_000 },
|
|
78
|
+
});
|
|
79
|
+
expect(ConversationDetailReconcilerDefaultsFromEnv(env)).toEqual({ enabled: false, sweepIntervalMs: 900_000 });
|
|
80
|
+
expect(AgentRunWatchdogDefaultsFromEnv(env).sweepIntervalMs).toBe(0);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('a bad value fails, naming the variable', () => {
|
|
84
|
+
expect(() => AgentSessionsDefaultsFromEnv({ MJ_BRIDGE_RECONCILER_ENABLED: 'nope' }))
|
|
85
|
+
.toThrow('Invalid MJ_BRIDGE_RECONCILER_ENABLED "nope". Expected true or false.');
|
|
86
|
+
expect(() => ConversationDetailReconcilerDefaultsFromEnv({ MJ_CONVERSATION_DETAIL_RECONCILER_SWEEP_INTERVAL_MS: '0' }))
|
|
87
|
+
.toThrow(/Invalid MJ_CONVERSATION_DETAIL_RECONCILER_SWEEP_INTERVAL_MS "0"/);
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
describe('agentRunWatchdog schema', () => {
|
|
92
|
+
it('defaults to the watchdog MJAPI has always run: 5-min sweep, 30s heartbeat, 5-min stale threshold', () => {
|
|
93
|
+
expect(AgentRunWatchdogSchema.parse({})).toEqual({
|
|
94
|
+
sweepIntervalMs: 300_000,
|
|
95
|
+
heartbeatIntervalMs: 30_000,
|
|
96
|
+
staleThresholdMinutes: 5,
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it('accepts sweepIntervalMs: 0 (startup sweep only)', () => {
|
|
101
|
+
expect(AgentRunWatchdogSchema.parse({ sweepIntervalMs: 0 }).sweepIntervalMs).toBe(0);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('rejects a zero heartbeat (other instances would force-fail this one\'s runs) and negative values', () => {
|
|
105
|
+
expect(AgentRunWatchdogSchema.safeParse({ heartbeatIntervalMs: 0 }).success).toBe(false);
|
|
106
|
+
expect(AgentRunWatchdogSchema.safeParse({ staleThresholdMinutes: 0 }).success).toBe(false);
|
|
107
|
+
expect(AgentRunWatchdogSchema.safeParse({ sweepIntervalMs: -1 }).success).toBe(false);
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
describe('EnabledFromEnv', () => {
|
|
112
|
+
it('returns the fallback when the variable is unset or blank', () => {
|
|
113
|
+
expect(EnabledFromEnv('X', undefined, true)).toBe(true);
|
|
114
|
+
expect(EnabledFromEnv('X', null, false)).toBe(false);
|
|
115
|
+
expect(EnabledFromEnv('X', ' ', true)).toBe(true);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it.each(['false', 'FALSE', '0', 'no', 'off', 'n', 'f'])('%j turns the switch off', value => {
|
|
119
|
+
expect(EnabledFromEnv('X', value, true)).toBe(false);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it.each(['true', '1', 'yes', 'on', 'Y', 't'])('%j turns it on', value => {
|
|
123
|
+
expect(EnabledFromEnv('X', value, false)).toBe(true);
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it('fails fast on anything else, naming the variable (a typo must not silently turn a sweep off)', () => {
|
|
127
|
+
expect(() => EnabledFromEnv('MJ_SESSION_JANITOR_ENABLED', 'flase', true))
|
|
128
|
+
.toThrow('Invalid MJ_SESSION_JANITOR_ENABLED "flase". Expected true or false.');
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
describe('IntervalMsFromEnv', () => {
|
|
133
|
+
it('returns the fallback when the variable is unset or blank', () => {
|
|
134
|
+
expect(IntervalMsFromEnv('X', undefined, 60_000, false)).toBe(60_000);
|
|
135
|
+
expect(IntervalMsFromEnv('X', '', 60_000, false)).toBe(60_000);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it('reads a number of milliseconds', () => {
|
|
139
|
+
expect(IntervalMsFromEnv('X', ' 3600000 ', 60_000, false)).toBe(3_600_000);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it('accepts 0 only where 0 means off', () => {
|
|
143
|
+
expect(IntervalMsFromEnv('MJ_AGENT_RUN_WATCHDOG_SWEEP_INTERVAL_MS', '0', 300_000, true)).toBe(0);
|
|
144
|
+
expect(() => IntervalMsFromEnv('MJ_SESSION_JANITOR_SWEEP_INTERVAL_MS', '0', 60_000, false))
|
|
145
|
+
.toThrow('Invalid MJ_SESSION_JANITOR_SWEEP_INTERVAL_MS "0". Expected a number of milliseconds greater than 0.');
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it('fails fast on a typo, naming the variable', () => {
|
|
149
|
+
expect(() => IntervalMsFromEnv('MJ_AGENT_RUN_WATCHDOG_SWEEP_INTERVAL_MS', '5m', 300_000, true))
|
|
150
|
+
.toThrow('Invalid MJ_AGENT_RUN_WATCHDOG_SWEEP_INTERVAL_MS "5m". Expected a number of milliseconds, 0 or greater.');
|
|
151
|
+
expect(() => IntervalMsFromEnv('X', '-5', 60_000, true)).toThrow(/Invalid X/);
|
|
152
|
+
});
|
|
153
|
+
});
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests that ContextFunction surfaces the request's normalized Origin header on AppContext as
|
|
3
|
+
* `RequestOrigin`. Database-facing dependencies are mocked; no connection is opened.
|
|
4
|
+
*/
|
|
5
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
6
|
+
import { BehaviorSubject } from 'rxjs';
|
|
7
|
+
|
|
8
|
+
const { mockProviderConfig } = vi.hoisted(() => ({
|
|
9
|
+
mockProviderConfig: vi.fn(),
|
|
10
|
+
}));
|
|
11
|
+
|
|
12
|
+
vi.mock('../util.js', () => ({
|
|
13
|
+
GetReadOnlyDataSource: vi.fn(() => undefined),
|
|
14
|
+
GetReadWriteDataSource: vi.fn(() => undefined),
|
|
15
|
+
}));
|
|
16
|
+
|
|
17
|
+
vi.mock('../config.js', () => ({
|
|
18
|
+
configInfo: { databaseSettings: { metadataCacheRefreshInterval: 0 } },
|
|
19
|
+
userEmailMap: {},
|
|
20
|
+
apiKey: 'test-api-key',
|
|
21
|
+
mj_core_schema: '__mj',
|
|
22
|
+
}));
|
|
23
|
+
|
|
24
|
+
vi.mock('@memberjunction/sqlserver-dataprovider', () => ({
|
|
25
|
+
SQLServerDataProvider: class {
|
|
26
|
+
Config = mockProviderConfig;
|
|
27
|
+
},
|
|
28
|
+
SQLServerProviderConfigData: class {},
|
|
29
|
+
}));
|
|
30
|
+
|
|
31
|
+
vi.mock('@memberjunction/postgresql-dataprovider', () => ({
|
|
32
|
+
PostgreSQLDataProvider: class {
|
|
33
|
+
Config = mockProviderConfig;
|
|
34
|
+
},
|
|
35
|
+
PostgreSQLProviderConfigData: class {},
|
|
36
|
+
}));
|
|
37
|
+
|
|
38
|
+
vi.mock('@memberjunction/generic-database-provider', async (importOriginal) => {
|
|
39
|
+
const actual = await importOriginal<typeof import('@memberjunction/generic-database-provider')>();
|
|
40
|
+
return {
|
|
41
|
+
...actual,
|
|
42
|
+
resolveDbPlatformFromEnv: () => 'sqlserver' as const,
|
|
43
|
+
UserCache: { Instance: {} } as typeof actual.UserCache,
|
|
44
|
+
};
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
vi.mock('@memberjunction/api-keys', () => ({
|
|
48
|
+
GetAPIKeyEngine: vi.fn(),
|
|
49
|
+
}));
|
|
50
|
+
|
|
51
|
+
vi.mock('@memberjunction/core', async (importOriginal) => {
|
|
52
|
+
const actual = await importOriginal<typeof import('@memberjunction/core')>();
|
|
53
|
+
return { ...actual, Metadata: { Provider: { Entities: [{}] } } };
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
import { ContextFunction } from '../context.js';
|
|
57
|
+
import type { IncomingMessage } from 'http';
|
|
58
|
+
import type { ConnectionPool } from 'mssql';
|
|
59
|
+
import type { UserPayload } from '../types.js';
|
|
60
|
+
|
|
61
|
+
const MOCK_POOL = {} as ConnectionPool;
|
|
62
|
+
const MOCK_PAYLOAD = { email: 'user@example.com' } as UserPayload;
|
|
63
|
+
|
|
64
|
+
function makeReq(headers: IncomingMessage['headers']): IncomingMessage {
|
|
65
|
+
return { headers, body: {}, ip: '127.0.0.1', userPayload: MOCK_PAYLOAD } as unknown as IncomingMessage;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async function contextFor(headers: IncomingMessage['headers']) {
|
|
69
|
+
const build = ContextFunction({ setupComplete$: new BehaviorSubject<unknown>(true), dataSource: MOCK_POOL, dataSources: [] });
|
|
70
|
+
return build({ req: makeReq(headers) });
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
describe('ContextFunction RequestOrigin', () => {
|
|
74
|
+
beforeEach(() => {
|
|
75
|
+
vi.clearAllMocks();
|
|
76
|
+
mockProviderConfig.mockResolvedValue(true);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('carries the normalized Origin header', async () => {
|
|
80
|
+
const ctx = await contextFor({ origin: 'https://Embed.Example.com/' });
|
|
81
|
+
expect(ctx.RequestOrigin).toBe('https://embed.example.com');
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('keeps an explicit port', async () => {
|
|
85
|
+
const ctx = await contextFor({ origin: 'http://localhost:4200' });
|
|
86
|
+
expect(ctx.RequestOrigin).toBe('http://localhost:4200');
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('is undefined when the request sent no Origin header', async () => {
|
|
90
|
+
const ctx = await contextFor({});
|
|
91
|
+
expect(ctx.RequestOrigin).toBeUndefined();
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('is undefined for a malformed or opaque Origin header', async () => {
|
|
95
|
+
expect((await contextFor({ origin: 'null' })).RequestOrigin).toBeUndefined();
|
|
96
|
+
expect((await contextFor({ origin: 'https://a.com/path' })).RequestOrigin).toBeUndefined();
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('leaves the existing context fields in place', async () => {
|
|
100
|
+
const ctx = await contextFor({ origin: 'https://a.com' });
|
|
101
|
+
expect(ctx.userPayload).toBe(MOCK_PAYLOAD);
|
|
102
|
+
expect(ctx.ClientIp).toBe('127.0.0.1');
|
|
103
|
+
expect(ctx.providers).toHaveLength(1);
|
|
104
|
+
});
|
|
105
|
+
});
|