@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
|
@@ -81,6 +81,8 @@ interface FakeSession {
|
|
|
81
81
|
LatestResult?: { CompleteMessage?: string };
|
|
82
82
|
ClosedAt?: Date | null;
|
|
83
83
|
CloseReason?: string | null;
|
|
84
|
+
Config_?: string | null;
|
|
85
|
+
LastActiveAt?: Date | string | null;
|
|
84
86
|
}
|
|
85
87
|
|
|
86
88
|
function makeUser(): UserInfo {
|
|
@@ -111,6 +113,10 @@ function makeProvider(store: Map<string, 'Active' | 'Idle' | 'Closed'>): {
|
|
|
111
113
|
if (status == null) return false;
|
|
112
114
|
entity.ID = id;
|
|
113
115
|
entity.Status = status;
|
|
116
|
+
// CloseSession verifies a TimeLimit against the loaded row's stored deadline, so the
|
|
117
|
+
// fake row carries the swept row's Config_ like the real table row does.
|
|
118
|
+
entity.Config_ = sweptRows.get(id)?.Config_ ?? null;
|
|
119
|
+
entity.LastActiveAt = sweptRows.get(id)?.LastActiveAt ?? null;
|
|
114
120
|
return true;
|
|
115
121
|
}),
|
|
116
122
|
Save: vi.fn(async () => {
|
|
@@ -130,6 +136,9 @@ function makeProvider(store: Map<string, 'Active' | 'Idle' | 'Closed'>): {
|
|
|
130
136
|
return { provider, closedIds, closedReasons };
|
|
131
137
|
}
|
|
132
138
|
|
|
139
|
+
/** Config_/LastActiveAt of rows a test swept, by session ID: sessionPages is consumed by the sweep before CloseSession loads the row. */
|
|
140
|
+
const sweptRows = new Map<string, { Config_?: string | null; LastActiveAt?: Date | string | null }>();
|
|
141
|
+
|
|
133
142
|
/**
|
|
134
143
|
* Queue of result-sets for the *session* sweep pages (entity 'MJ: AI Agent Sessions'). Channel
|
|
135
144
|
* sweeps (entity 'MJ: AI Agent Session Channels', issued by CloseSession) always resolve empty so
|
|
@@ -145,6 +154,7 @@ function sessionSweepCalls(): Array<[{ EntityName: string; ExtraFilter: string;
|
|
|
145
154
|
}
|
|
146
155
|
|
|
147
156
|
beforeEach(() => {
|
|
157
|
+
sweptRows.clear();
|
|
148
158
|
runViewMock.mockReset();
|
|
149
159
|
logErrorMock.mockReset();
|
|
150
160
|
logStatusMock.mockReset();
|
|
@@ -292,9 +302,114 @@ describe('SessionJanitor.RunStartupRecovery with two MJAPIs on one host (#5309)'
|
|
|
292
302
|
});
|
|
293
303
|
});
|
|
294
304
|
|
|
305
|
+
/** An ISO moment `minutes` before now, for a row's `LastActiveAt` / deadline. */
|
|
306
|
+
function minutesAgo(minutes: number): string {
|
|
307
|
+
return new Date(Date.now() - minutes * 60_000).toISOString();
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/** Config_ JSON carrying an authored hard deadline `minutes` from now (negative = already passed). */
|
|
311
|
+
function deadlineConfig(minutesFromNow: number): string {
|
|
312
|
+
return JSON.stringify({ maxSessionDeadlineIso: new Date(Date.now() + minutesFromNow * 60_000).toISOString() });
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
describe('SessionJanitor close reasons (#6182): sweeps stamp TimeLimit / Idle via ExpiryCloseReason', () => {
|
|
316
|
+
// Idle threshold is 15 min (the janitor default); each row below is placed relative to it.
|
|
317
|
+
beforeEach(() => {
|
|
318
|
+
SessionJanitor.Instance.Configure({ closeThresholdMinutes: 15 });
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
async function runSweep(
|
|
322
|
+
sweep: 'RunStalenessSweep' | 'RunMaxDurationSweep',
|
|
323
|
+
row: Record<string, unknown>,
|
|
324
|
+
): Promise<{ count: number; reason: string | null | undefined; closed: boolean }> {
|
|
325
|
+
const id = row.ID as string;
|
|
326
|
+
sweptRows.set(id, { Config_: row.Config_ as string | null, LastActiveAt: row.LastActiveAt as Date | string | null });
|
|
327
|
+
sessionPages = [{ Success: true, Results: [row] }];
|
|
328
|
+
const { provider, closedIds, closedReasons } = makeProvider(new Map([[id, 'Active']]));
|
|
329
|
+
const count = await SessionJanitor.Instance[sweep](provider, makeUser());
|
|
330
|
+
return { count, reason: closedReasons.get(id), closed: closedIds.includes(id) };
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
it('the staleness sweep stamps Idle for a quiet row without a deadline', async () => {
|
|
334
|
+
const r = await runSweep('RunStalenessSweep', { ID: 'q1', Status: 'Active', LastActiveAt: minutesAgo(60), Config_: null });
|
|
335
|
+
expect(r.reason).toBe('Idle');
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
it('the max-duration sweep stamps TimeLimit for an expired row', async () => {
|
|
339
|
+
const r = await runSweep('RunMaxDurationSweep', {
|
|
340
|
+
ID: 'd1', Status: 'Active', LastActiveAt: minutesAgo(1), Config_: deadlineConfig(-5),
|
|
341
|
+
});
|
|
342
|
+
expect(r.reason).toBe('TimeLimit');
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
it('the idle sweep stamps TimeLimit when the deadline came first', async () => {
|
|
346
|
+
// Idle moment = 60-15 = 45 min ago; deadline 50 min ago is earlier.
|
|
347
|
+
const r = await runSweep('RunStalenessSweep', {
|
|
348
|
+
ID: 'both1', Status: 'Active', LastActiveAt: minutesAgo(60), Config_: deadlineConfig(-50),
|
|
349
|
+
});
|
|
350
|
+
expect(r.reason).toBe('TimeLimit');
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
it('the deadline sweep stamps Idle when the idle moment came first', async () => {
|
|
354
|
+
// Idle moment = 60-15 = 45 min ago; deadline 5 min ago is later.
|
|
355
|
+
const r = await runSweep('RunMaxDurationSweep', {
|
|
356
|
+
ID: 'both2', Status: 'Active', LastActiveAt: minutesAgo(60), Config_: deadlineConfig(-5),
|
|
357
|
+
});
|
|
358
|
+
expect(r.reason).toBe('Idle');
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
/*
|
|
362
|
+
* The SQL already judged this row stale (LastActiveAt < cutoff), so an unparseable LastActiveAt
|
|
363
|
+
* must not make it immortal: it closes as Idle, and the fallback is logged with the session ID.
|
|
364
|
+
*/
|
|
365
|
+
it('the staleness sweep closes a stale row with an unparseable LastActiveAt as Idle and LogErrors the fallback', async () => {
|
|
366
|
+
logErrorMock.mockClear();
|
|
367
|
+
const r = await runSweep('RunStalenessSweep', { ID: 'garbled1', Status: 'Active', LastActiveAt: 'not-a-date', Config_: null });
|
|
368
|
+
expect(r.closed).toBe(true);
|
|
369
|
+
expect(r.reason).toBe('Idle');
|
|
370
|
+
const messages = logErrorMock.mock.calls.map((c) => String(c[0]));
|
|
371
|
+
expect(messages.some((m) => m.includes('garbled1') && m.includes('LastActiveAt unparseable; closing as Idle'))).toBe(true);
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
it('the staleness sweep does not LogError for a row ExpiryCloseReason decides', async () => {
|
|
375
|
+
logErrorMock.mockClear();
|
|
376
|
+
await runSweep('RunStalenessSweep', { ID: 'q2', Status: 'Active', LastActiveAt: minutesAgo(60), Config_: null });
|
|
377
|
+
expect(logErrorMock).not.toHaveBeenCalled();
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
it('skips rows the callback returns null for, without loading their channels', async () => {
|
|
381
|
+
const row = { ID: 'future1', Status: 'Active', LastActiveAt: minutesAgo(1), Config_: deadlineConfig(30) };
|
|
382
|
+
sessionPages = [{ Success: true, Results: [row] }];
|
|
383
|
+
const { provider, closedIds } = makeProvider(new Map([['future1', 'Active']]));
|
|
384
|
+
|
|
385
|
+
const count = await SessionJanitor.Instance.RunMaxDurationSweep(provider, makeUser());
|
|
386
|
+
|
|
387
|
+
expect(count).toBe(0);
|
|
388
|
+
expect(closedIds).toEqual([]);
|
|
389
|
+
const channelReads = runViewMock.mock.calls.filter(
|
|
390
|
+
(c) => (c[0] as { EntityName: string }).EntityName === 'MJ: AI Agent Session Channels',
|
|
391
|
+
);
|
|
392
|
+
expect(channelReads).toHaveLength(0);
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
it('startup recovery still stamps Janitor and the shutdown drain Shutdown', async () => {
|
|
396
|
+
const ours = GetCurrentHostInstance();
|
|
397
|
+
const orphan = { ID: 'orphan1', Status: 'Active', HostInstanceID: `${ours.GetInstancePrefix()}31337:boot-before` };
|
|
398
|
+
sessionPages = [{ Success: true, Results: [orphan] }];
|
|
399
|
+
const recovery = makeProvider(new Map([['orphan1', 'Active']]));
|
|
400
|
+
await SessionJanitor.Instance.RunStartupRecovery(recovery.provider, makeUser());
|
|
401
|
+
expect(recovery.closedReasons.get('orphan1')).toBe('Janitor');
|
|
402
|
+
|
|
403
|
+
sessionPages = [{ Success: true, Results: [{ ID: 'live1', Status: 'Active' }] }];
|
|
404
|
+
const drain = makeProvider(new Map([['live1', 'Active']]));
|
|
405
|
+
await SessionJanitor.Instance.RunShutdownDrain(drain.provider, makeUser());
|
|
406
|
+
expect(drain.closedReasons.get('live1')).toBe('Shutdown');
|
|
407
|
+
});
|
|
408
|
+
});
|
|
409
|
+
|
|
295
410
|
describe('SessionJanitor.RunStalenessSweep', () => {
|
|
296
411
|
it('closes only past-threshold sessions (filter is staleness-scoped)', async () => {
|
|
297
|
-
const stale = { ID: 'stale-1', Status: 'Idle' };
|
|
412
|
+
const stale = { ID: 'stale-1', Status: 'Idle', LastActiveAt: minutesAgo(60) };
|
|
298
413
|
sessionPages = [{ Success: true, Results: [stale] }];
|
|
299
414
|
|
|
300
415
|
const store = new Map<string, 'Active' | 'Idle' | 'Closed'>([['stale-1', 'Idle']]);
|
|
@@ -304,8 +419,8 @@ describe('SessionJanitor.RunStalenessSweep', () => {
|
|
|
304
419
|
|
|
305
420
|
expect(count).toBe(1);
|
|
306
421
|
expect(closedIds).toContain('stale-1');
|
|
307
|
-
//
|
|
308
|
-
expect(closedReasons.get('stale-1')).toBe('
|
|
422
|
+
// A quiet row without a deadline closes as Idle.
|
|
423
|
+
expect(closedReasons.get('stale-1')).toBe('Idle');
|
|
309
424
|
|
|
310
425
|
const filter = sessionSweepCalls()[0][0].ExtraFilter as string;
|
|
311
426
|
expect(filter).toContain("Status IN ('Active','Idle')");
|
|
@@ -313,7 +428,7 @@ describe('SessionJanitor.RunStalenessSweep', () => {
|
|
|
313
428
|
});
|
|
314
429
|
|
|
315
430
|
it('is idempotent — re-closing already-Closed rows is a harmless no-op', async () => {
|
|
316
|
-
const alreadyClosed = { ID: 'done-1', Status: 'Closed' };
|
|
431
|
+
const alreadyClosed = { ID: 'done-1', Status: 'Closed', LastActiveAt: minutesAgo(60) };
|
|
317
432
|
sessionPages = [{ Success: true, Results: [alreadyClosed] }];
|
|
318
433
|
|
|
319
434
|
const store = new Map<string, 'Active' | 'Idle' | 'Closed'>([['done-1', 'Closed']]);
|
|
@@ -1414,3 +1529,79 @@ describe('SessionJanitor.Configure', () => {
|
|
|
1414
1529
|
expect(sessionSweepCalls()).toHaveLength(0);
|
|
1415
1530
|
});
|
|
1416
1531
|
});
|
|
1532
|
+
|
|
1533
|
+
describe('SessionJanitor.StartWithSettings (agentSessions.janitor)', () => {
|
|
1534
|
+
const HOUR = 60 * 60_000;
|
|
1535
|
+
const DEFAULTS = { enabled: true, sweepIntervalMs: 60_000, closeThresholdMinutes: 15 };
|
|
1536
|
+
|
|
1537
|
+
beforeEach(() => {
|
|
1538
|
+
vi.useFakeTimers();
|
|
1539
|
+
});
|
|
1540
|
+
afterEach(() => {
|
|
1541
|
+
SessionJanitor.Instance.Stop();
|
|
1542
|
+
SessionJanitor.Instance.Configure({ sweepIntervalMs: DEFAULTS.sweepIntervalMs, closeThresholdMinutes: DEFAULTS.closeThresholdMinutes });
|
|
1543
|
+
vi.clearAllTimers();
|
|
1544
|
+
vi.useRealTimers();
|
|
1545
|
+
});
|
|
1546
|
+
|
|
1547
|
+
it('enabled: runs startup recovery, then ticks on the configured interval with the configured threshold', async () => {
|
|
1548
|
+
const { provider } = makeProvider(new Map());
|
|
1549
|
+
await SessionJanitor.Instance.StartWithSettings({ ...DEFAULTS, sweepIntervalMs: 120_000, closeThresholdMinutes: 30 }, provider, makeUser());
|
|
1550
|
+
expect(sessionSweepCalls()).toHaveLength(1); // startup recovery
|
|
1551
|
+
expect(SessionJanitor.Instance.IsSweepScheduled).toBe(true);
|
|
1552
|
+
|
|
1553
|
+
vi.setSystemTime(new Date('2026-10-29T12:00:00.000Z'));
|
|
1554
|
+
await vi.advanceTimersByTimeAsync(120_000);
|
|
1555
|
+
|
|
1556
|
+
const staleness = sessionSweepCalls().map(c => c[0].ExtraFilter).find(f => f.includes('LastActiveAt <'));
|
|
1557
|
+
expect(staleness).toBeTruthy();
|
|
1558
|
+
// 30 minutes before the tick, not the default 15.
|
|
1559
|
+
expect(staleness).toContain('2026-10-29T11:32:00.000Z');
|
|
1560
|
+
});
|
|
1561
|
+
|
|
1562
|
+
it('disabled: runs startup recovery once and then issues no queries at all', async () => {
|
|
1563
|
+
const { provider } = makeProvider(new Map());
|
|
1564
|
+
await SessionJanitor.Instance.StartWithSettings({ ...DEFAULTS, enabled: false }, provider, makeUser());
|
|
1565
|
+
expect(sessionSweepCalls()).toHaveLength(1);
|
|
1566
|
+
runViewMock.mockClear();
|
|
1567
|
+
|
|
1568
|
+
await vi.advanceTimersByTimeAsync(HOUR);
|
|
1569
|
+
|
|
1570
|
+
expect(runViewMock).not.toHaveBeenCalled();
|
|
1571
|
+
expect(ledgerMock.PurgeClosedBefore).not.toHaveBeenCalled();
|
|
1572
|
+
expect(SessionJanitor.Instance.IsSweepScheduled).toBe(false);
|
|
1573
|
+
});
|
|
1574
|
+
|
|
1575
|
+
it('disabled: still drains this host\'s live sessions on graceful shutdown', async () => {
|
|
1576
|
+
sessionPages = [
|
|
1577
|
+
{ Success: true, Results: [] }, // startup recovery
|
|
1578
|
+
{ Success: true, Results: [{ ID: 'mine-3', Status: 'Active' }] }, // shutdown drain
|
|
1579
|
+
];
|
|
1580
|
+
const store = new Map<string, 'Active' | 'Idle' | 'Closed'>([['mine-3', 'Active']]);
|
|
1581
|
+
const { provider, closedIds, closedReasons } = makeProvider(store);
|
|
1582
|
+
|
|
1583
|
+
await SessionJanitor.Instance.StartWithSettings({ ...DEFAULTS, enabled: false }, provider, makeUser());
|
|
1584
|
+
await SessionJanitor.Instance.Shutdown();
|
|
1585
|
+
|
|
1586
|
+
expect(closedIds).toContain('mine-3');
|
|
1587
|
+
expect(closedReasons.get('mine-3')).toBe('Shutdown');
|
|
1588
|
+
});
|
|
1589
|
+
|
|
1590
|
+
it('disabled after an earlier Start stops the tick that Start scheduled', async () => {
|
|
1591
|
+
const { provider } = makeProvider(new Map());
|
|
1592
|
+
await SessionJanitor.Instance.Start(provider, makeUser());
|
|
1593
|
+
expect(SessionJanitor.Instance.IsSweepScheduled).toBe(true);
|
|
1594
|
+
|
|
1595
|
+
await SessionJanitor.Instance.StartWithSettings({ ...DEFAULTS, enabled: false }, provider, makeUser());
|
|
1596
|
+
|
|
1597
|
+
expect(SessionJanitor.Instance.IsSweepScheduled).toBe(false);
|
|
1598
|
+
});
|
|
1599
|
+
|
|
1600
|
+
it('rejects an invalid interval before doing any work', async () => {
|
|
1601
|
+
const { provider } = makeProvider(new Map());
|
|
1602
|
+
await expect(SessionJanitor.Instance.StartWithSettings({ ...DEFAULTS, sweepIntervalMs: 0 }, provider, makeUser()))
|
|
1603
|
+
.rejects.toThrow(/sweepIntervalMs must be a finite number greater than 0/);
|
|
1604
|
+
expect(sessionSweepCalls()).toHaveLength(0);
|
|
1605
|
+
expect(SessionJanitor.Instance.IsSweepScheduled).toBe(false);
|
|
1606
|
+
});
|
|
1607
|
+
});
|
|
@@ -42,10 +42,12 @@ vi.mock('../realtimeSessions/RecordingAssemblyScheduler.js', () => ({
|
|
|
42
42
|
// --- Mock RunView.FromMetadataProvider so channel sweeps and run-id lookups are controllable,
|
|
43
43
|
// while leaving the rest of @memberjunction/core intact. RunViews runs each view through runViewMock. ---
|
|
44
44
|
const runViewMock = vi.fn();
|
|
45
|
+
const logStatusMock = vi.fn();
|
|
45
46
|
vi.mock('@memberjunction/core', async (importOriginal) => {
|
|
46
47
|
const actual = await importOriginal<typeof import('@memberjunction/core')>();
|
|
47
48
|
return {
|
|
48
49
|
...actual,
|
|
50
|
+
LogStatus: (...args: unknown[]) => logStatusMock(...args),
|
|
49
51
|
RunView: {
|
|
50
52
|
FromMetadataProvider: () => ({
|
|
51
53
|
RunView: runViewMock,
|
|
@@ -71,6 +73,7 @@ vi.mock('@memberjunction/generic-database-provider', async (importOriginal) => {
|
|
|
71
73
|
});
|
|
72
74
|
|
|
73
75
|
import { SessionManager, SessionAuthorizationError } from '../agentSessions/SessionManager.js';
|
|
76
|
+
import { IsTrustedSessionConfigWriteActive } from '@memberjunction/core-entities-server';
|
|
74
77
|
import type { UserInfo, IMetadataProvider } from '@memberjunction/core';
|
|
75
78
|
|
|
76
79
|
/** Minimal fake BaseEntity-shaped record with the fields/methods SessionManager touches. */
|
|
@@ -336,6 +339,24 @@ describe('SessionManager.CreateSession', () => {
|
|
|
336
339
|
});
|
|
337
340
|
|
|
338
341
|
describe('SessionManager.CloseSession', () => {
|
|
342
|
+
// The session entity refuses a server-only CloseReason (TimeLimit, Idle, Janitor, Shutdown) from an untrusted save,
|
|
343
|
+
// so the one server path that stamps it must save inside the trusted session-write scope.
|
|
344
|
+
it('stamps the close reason inside the trusted session-write scope', async () => {
|
|
345
|
+
runViewMock.mockResolvedValue({ Success: true, Results: [] });
|
|
346
|
+
let trustedAtSave: boolean | null = null;
|
|
347
|
+
const session = makeSessionEntity({ ID: 'session-1', Status: 'Active' });
|
|
348
|
+
session.Save = vi.fn(async () => {
|
|
349
|
+
trustedAtSave = IsTrustedSessionConfigWriteActive();
|
|
350
|
+
return true;
|
|
351
|
+
});
|
|
352
|
+
const { provider } = makeProvider(() => session);
|
|
353
|
+
|
|
354
|
+
expect(await new SessionManager().CloseSession('session-1', makeUser(), provider, 'Janitor')).toBe(true);
|
|
355
|
+
|
|
356
|
+
expect(session.CloseReason).toBe('Janitor');
|
|
357
|
+
expect(trustedAtSave).toBe(true);
|
|
358
|
+
});
|
|
359
|
+
|
|
339
360
|
it('sets Closed + ClosedAt, disconnects channels', async () => {
|
|
340
361
|
const channel = makeSessionEntity({ ID: 'chan-1', Status: 'Connected' });
|
|
341
362
|
runViewMock.mockResolvedValue({ Success: true, Results: [channel] });
|
|
@@ -529,6 +550,54 @@ describe('SessionManager.CloseSession', () => {
|
|
|
529
550
|
},
|
|
530
551
|
);
|
|
531
552
|
|
|
553
|
+
describe('a TimeLimit close is verified against the stored deadline', () => {
|
|
554
|
+
beforeEach(() => logStatusMock.mockClear());
|
|
555
|
+
|
|
556
|
+
it('is downgraded to Explicit and logged when the stored deadline is far away', async () => {
|
|
557
|
+
const deadline = new Date(Date.now() + 10 * 60_000).toISOString();
|
|
558
|
+
const session = makeSessionEntity({ ID: 'session-far', Status: 'Active', Config_: JSON.stringify({ maxSessionDeadlineIso: deadline }) });
|
|
559
|
+
const { provider } = makeProvider(() => session);
|
|
560
|
+
|
|
561
|
+
const ok = await new SessionManager().CloseSession('session-far', makeUser(), provider, 'TimeLimit');
|
|
562
|
+
|
|
563
|
+
expect(ok).toBe(true);
|
|
564
|
+
expect(session.CloseReason).toBe('Explicit');
|
|
565
|
+
const logged = logStatusMock.mock.calls.map((c) => String(c[0])).join('\n');
|
|
566
|
+
expect(logged).toContain('session-far');
|
|
567
|
+
expect(logged).toContain(deadline);
|
|
568
|
+
});
|
|
569
|
+
|
|
570
|
+
it('is stamped TimeLimit when the stored deadline has passed', async () => {
|
|
571
|
+
const deadline = new Date(Date.now() - 1_000).toISOString();
|
|
572
|
+
const session = makeSessionEntity({ ID: 'session-due', Status: 'Active', Config_: JSON.stringify({ maxSessionDeadlineIso: deadline }) });
|
|
573
|
+
const { provider } = makeProvider(() => session);
|
|
574
|
+
|
|
575
|
+
await new SessionManager().CloseSession('session-due', makeUser(), provider, 'TimeLimit');
|
|
576
|
+
|
|
577
|
+
expect(session.CloseReason).toBe('TimeLimit');
|
|
578
|
+
expect(logStatusMock).not.toHaveBeenCalled();
|
|
579
|
+
});
|
|
580
|
+
|
|
581
|
+
it('tells channel plugins the verified reason: Explicit for a downgraded claim, TimeLimit for a backed one', async () => {
|
|
582
|
+
const far = makeSessionEntity({ ID: 'session-far2', Status: 'Active', Config_: JSON.stringify({ maxSessionDeadlineIso: new Date(Date.now() + 10 * 60_000).toISOString() }) });
|
|
583
|
+
await new SessionManager().CloseSession('session-far2', makeUser(), makeProvider(() => far).provider, 'TimeLimit');
|
|
584
|
+
expect(hostSessionClosedMock).toHaveBeenLastCalledWith('session-far2', 'Explicit');
|
|
585
|
+
|
|
586
|
+
const due = makeSessionEntity({ ID: 'session-due2', Status: 'Active', Config_: JSON.stringify({ maxSessionDeadlineIso: new Date(Date.now() - 1_000).toISOString() }) });
|
|
587
|
+
await new SessionManager().CloseSession('session-due2', makeUser(), makeProvider(() => due).provider, 'TimeLimit');
|
|
588
|
+
expect(hostSessionClosedMock).toHaveBeenLastCalledWith('session-due2', 'TimeLimit');
|
|
589
|
+
});
|
|
590
|
+
|
|
591
|
+
it('is downgraded to Explicit when the session stores no deadline', async () => {
|
|
592
|
+
const session = makeSessionEntity({ ID: 'session-none', Status: 'Active', Config_: null });
|
|
593
|
+
const { provider } = makeProvider(() => session);
|
|
594
|
+
|
|
595
|
+
await new SessionManager().CloseSession('session-none', makeUser(), provider, 'TimeLimit');
|
|
596
|
+
|
|
597
|
+
expect(session.CloseReason).toBe('Explicit');
|
|
598
|
+
});
|
|
599
|
+
});
|
|
600
|
+
|
|
532
601
|
it('does not overwrite the original CloseReason on an idempotent re-close', async () => {
|
|
533
602
|
const session = makeSessionEntity({ ID: 'session-1', Status: 'Closed', CloseReason: 'Janitor' });
|
|
534
603
|
const { provider } = makeProvider(() => session);
|
|
@@ -170,7 +170,7 @@ describe('TaskGraphActionRunner: outputs must be storable', () => {
|
|
|
170
170
|
expect(result).toMatchObject({ Success: true, Output: { AgentRunID: 'RUN-1' }, ActionLogID: 'LOG-2' });
|
|
171
171
|
});
|
|
172
172
|
|
|
173
|
-
it('merges structured JSON Message properties into Output
|
|
173
|
+
it('merges structured JSON Message properties into Output without synthesizing handle/Handle aliases', async () => {
|
|
174
174
|
vi.mocked(ActionEngineServer.Instance.RunAction).mockResolvedValue({
|
|
175
175
|
Success: true,
|
|
176
176
|
Message: JSON.stringify({
|
|
@@ -188,10 +188,10 @@ describe('TaskGraphActionRunner: outputs must be storable', () => {
|
|
|
188
188
|
expect(result.Success).toBe(true);
|
|
189
189
|
expect(result.Output).toMatchObject({
|
|
190
190
|
handle: 'doc-handle-99',
|
|
191
|
-
Handle: 'doc-handle-99',
|
|
192
191
|
documentType: 'pdf',
|
|
193
192
|
fileName: 'Sales_Demo_Report.pdf',
|
|
194
193
|
});
|
|
194
|
+
expect(result.Output).not.toHaveProperty('Handle');
|
|
195
195
|
});
|
|
196
196
|
});
|
|
197
197
|
|