@memberjunction/server 6.2.0-edge.3 → 6.2.0-edge.5
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 +20 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/agentSessions/BridgeHostInstance.d.ts +25 -0
- package/dist/agentSessions/BridgeHostInstance.d.ts.map +1 -0
- package/dist/agentSessions/BridgeHostInstance.js +30 -0
- package/dist/agentSessions/BridgeHostInstance.js.map +1 -0
- package/dist/agentSessions/HostInstance.d.ts +75 -11
- package/dist/agentSessions/HostInstance.d.ts.map +1 -1
- package/dist/agentSessions/HostInstance.js +99 -28
- package/dist/agentSessions/HostInstance.js.map +1 -1
- package/dist/agentSessions/ReturningVisitorRecap.d.ts.map +1 -1
- package/dist/agentSessions/ReturningVisitorRecap.js +7 -3
- package/dist/agentSessions/ReturningVisitorRecap.js.map +1 -1
- package/dist/agentSessions/SessionJanitor.d.ts +236 -27
- package/dist/agentSessions/SessionJanitor.d.ts.map +1 -1
- package/dist/agentSessions/SessionJanitor.js +682 -54
- package/dist/agentSessions/SessionJanitor.js.map +1 -1
- package/dist/agentSessions/SessionManager.d.ts +48 -3
- package/dist/agentSessions/SessionManager.d.ts.map +1 -1
- package/dist/agentSessions/SessionManager.js +112 -9
- package/dist/agentSessions/SessionManager.js.map +1 -1
- package/dist/agentSessions/SessionRunIDVerifier.d.ts +63 -0
- package/dist/agentSessions/SessionRunIDVerifier.d.ts.map +1 -0
- package/dist/agentSessions/SessionRunIDVerifier.js +129 -0
- package/dist/agentSessions/SessionRunIDVerifier.js.map +1 -0
- package/dist/agentSessions/index.d.ts +2 -0
- package/dist/agentSessions/index.d.ts.map +1 -1
- package/dist/agentSessions/index.js +10 -3
- package/dist/agentSessions/index.js.map +1 -1
- package/dist/apiRoot.d.ts +32 -0
- package/dist/apiRoot.d.ts.map +1 -0
- package/dist/apiRoot.js +67 -0
- package/dist/apiRoot.js.map +1 -0
- package/dist/auth/AuthProviderCatalogRouter.d.ts.map +1 -1
- package/dist/auth/AuthProviderCatalogRouter.js +25 -0
- package/dist/auth/AuthProviderCatalogRouter.js.map +1 -1
- package/dist/auth/LoginScreenEngine.d.ts +22 -0
- package/dist/auth/LoginScreenEngine.d.ts.map +1 -0
- package/dist/auth/LoginScreenEngine.js +57 -0
- package/dist/auth/LoginScreenEngine.js.map +1 -0
- package/dist/auth/actionAuthorization.d.ts +40 -0
- package/dist/auth/actionAuthorization.d.ts.map +1 -0
- package/dist/auth/actionAuthorization.js +94 -0
- package/dist/auth/actionAuthorization.js.map +1 -0
- package/dist/auth/index.d.ts +1 -0
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +4 -10
- package/dist/auth/index.js.map +1 -1
- package/dist/auth/magicLink/MagicLinkRouter.d.ts.map +1 -1
- package/dist/auth/magicLink/MagicLinkRouter.js +3 -2
- package/dist/auth/magicLink/MagicLinkRouter.js.map +1 -1
- package/dist/auth/magicLink/MagicLinkService.d.ts.map +1 -1
- package/dist/auth/magicLink/MagicLinkService.js +6 -3
- package/dist/auth/magicLink/MagicLinkService.js.map +1 -1
- package/dist/auth/newUsers.d.ts +10 -0
- package/dist/auth/newUsers.d.ts.map +1 -1
- package/dist/auth/newUsers.js +80 -11
- package/dist/auth/newUsers.js.map +1 -1
- package/dist/config.d.ts +2514 -22
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +166 -4
- package/dist/config.js.map +1 -1
- package/dist/context.d.ts +8 -0
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +14 -11
- package/dist/context.js.map +1 -1
- package/dist/coreRoutes.d.ts +29 -0
- package/dist/coreRoutes.d.ts.map +1 -0
- package/dist/coreRoutes.js +142 -0
- package/dist/coreRoutes.js.map +1 -0
- package/dist/generated/graphql-schemas/__mj.d.ts +504 -3
- package/dist/generated/graphql-schemas/__mj.d.ts.map +1 -1
- package/dist/generated/graphql-schemas/__mj.js +2456 -7
- package/dist/generated/graphql-schemas/__mj.js.map +1 -1
- package/dist/generic/CacheInvalidationResolver.d.ts +43 -8
- package/dist/generic/CacheInvalidationResolver.d.ts.map +1 -1
- package/dist/generic/CacheInvalidationResolver.js +59 -19
- package/dist/generic/CacheInvalidationResolver.js.map +1 -1
- package/dist/generic/OrphanedConversationDetailReconciler.js +3 -3
- package/dist/generic/OrphanedConversationDetailReconciler.js.map +1 -1
- package/dist/generic/PushStatusResolver.js +1 -1
- package/dist/generic/PushStatusResolver.js.map +1 -1
- package/dist/generic/ResolverBase.d.ts +123 -48
- package/dist/generic/ResolverBase.d.ts.map +1 -1
- package/dist/generic/ResolverBase.js +293 -305
- package/dist/generic/ResolverBase.js.map +1 -1
- package/dist/generic/RunViewResolver.d.ts.map +1 -1
- package/dist/generic/RunViewResolver.js +16 -0
- package/dist/generic/RunViewResolver.js.map +1 -1
- package/dist/globalCors.d.ts +33 -0
- package/dist/globalCors.d.ts.map +1 -0
- package/dist/globalCors.js +58 -0
- package/dist/globalCors.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +219 -278
- package/dist/index.js.map +1 -1
- package/dist/isolatedProvider.d.ts +20 -0
- package/dist/isolatedProvider.d.ts.map +1 -0
- package/dist/isolatedProvider.js +22 -0
- package/dist/isolatedProvider.js.map +1 -0
- package/dist/multiTenancy/index.d.ts.map +1 -1
- package/dist/multiTenancy/index.js +22 -2
- package/dist/multiTenancy/index.js.map +1 -1
- package/dist/realtimeProxy/RealtimeProxyServer.d.ts +44 -4
- package/dist/realtimeProxy/RealtimeProxyServer.d.ts.map +1 -1
- package/dist/realtimeProxy/RealtimeProxyServer.js +121 -16
- package/dist/realtimeProxy/RealtimeProxyServer.js.map +1 -1
- package/dist/realtimeProxy/RealtimeRelayTunnel.d.ts +171 -0
- package/dist/realtimeProxy/RealtimeRelayTunnel.d.ts.map +1 -0
- package/dist/realtimeProxy/RealtimeRelayTunnel.js +532 -0
- package/dist/realtimeProxy/RealtimeRelayTunnel.js.map +1 -0
- package/dist/realtimeSessions/RealtimeSessionEventService.d.ts +148 -0
- package/dist/realtimeSessions/RealtimeSessionEventService.d.ts.map +1 -0
- package/dist/realtimeSessions/RealtimeSessionEventService.js +191 -0
- package/dist/realtimeSessions/RealtimeSessionEventService.js.map +1 -0
- package/dist/realtimeSessions/RealtimeSessionVerificationService.d.ts +66 -0
- package/dist/realtimeSessions/RealtimeSessionVerificationService.d.ts.map +1 -0
- package/dist/realtimeSessions/RealtimeSessionVerificationService.js +139 -0
- package/dist/realtimeSessions/RealtimeSessionVerificationService.js.map +1 -0
- package/dist/realtimeSessions/RealtimeVerifyRouter.d.ts +38 -0
- package/dist/realtimeSessions/RealtimeVerifyRouter.d.ts.map +1 -0
- package/dist/realtimeSessions/RealtimeVerifyRouter.js +99 -0
- package/dist/realtimeSessions/RealtimeVerifyRouter.js.map +1 -0
- package/dist/realtimeSessions/RecordingAssemblyScheduler.d.ts +100 -0
- package/dist/realtimeSessions/RecordingAssemblyScheduler.d.ts.map +1 -0
- package/dist/realtimeSessions/RecordingAssemblyScheduler.js +173 -0
- package/dist/realtimeSessions/RecordingAssemblyScheduler.js.map +1 -0
- package/dist/realtimeSessions/SessionVerificationPortsBase.d.ts +61 -0
- package/dist/realtimeSessions/SessionVerificationPortsBase.d.ts.map +1 -0
- package/dist/realtimeSessions/SessionVerificationPortsBase.js +149 -0
- package/dist/realtimeSessions/SessionVerificationPortsBase.js.map +1 -0
- package/dist/realtimeSessions/SlidingWindowRateLimiter.d.ts +57 -0
- package/dist/realtimeSessions/SlidingWindowRateLimiter.d.ts.map +1 -0
- package/dist/realtimeSessions/SlidingWindowRateLimiter.js +69 -0
- package/dist/realtimeSessions/SlidingWindowRateLimiter.js.map +1 -0
- package/dist/realtimeSessions/index.d.ts +19 -0
- package/dist/realtimeSessions/index.d.ts.map +1 -0
- package/dist/realtimeSessions/index.js +19 -0
- package/dist/realtimeSessions/index.js.map +1 -0
- package/dist/realtimeSessions/ownedRealtimeSession.d.ts +30 -0
- package/dist/realtimeSessions/ownedRealtimeSession.d.ts.map +1 -0
- package/dist/realtimeSessions/ownedRealtimeSession.js +47 -0
- package/dist/realtimeSessions/ownedRealtimeSession.js.map +1 -0
- package/dist/realtimeSessions/sessionAccess.d.ts +92 -0
- package/dist/realtimeSessions/sessionAccess.d.ts.map +1 -0
- package/dist/realtimeSessions/sessionAccess.js +94 -0
- package/dist/realtimeSessions/sessionAccess.js.map +1 -0
- package/dist/realtimeSessions/sessionConfigStamps.d.ts +70 -0
- package/dist/realtimeSessions/sessionConfigStamps.d.ts.map +1 -0
- package/dist/realtimeSessions/sessionConfigStamps.js +93 -0
- package/dist/realtimeSessions/sessionConfigStamps.js.map +1 -0
- package/dist/realtimeSessions/subscriptionAuthorization.d.ts +65 -0
- package/dist/realtimeSessions/subscriptionAuthorization.d.ts.map +1 -0
- package/dist/realtimeSessions/subscriptionAuthorization.js +71 -0
- package/dist/realtimeSessions/subscriptionAuthorization.js.map +1 -0
- package/dist/realtimeSessions/verificationCore.d.ts +243 -0
- package/dist/realtimeSessions/verificationCore.d.ts.map +1 -0
- package/dist/realtimeSessions/verificationCore.js +356 -0
- package/dist/realtimeSessions/verificationCore.js.map +1 -0
- package/dist/realtimeSessions/verificationPages.d.ts +66 -0
- package/dist/realtimeSessions/verificationPages.d.ts.map +1 -0
- package/dist/realtimeSessions/verificationPages.js +110 -0
- package/dist/realtimeSessions/verificationPages.js.map +1 -0
- package/dist/realtimeSessions/verificationPolicy.d.ts +147 -0
- package/dist/realtimeSessions/verificationPolicy.d.ts.map +1 -0
- package/dist/realtimeSessions/verificationPolicy.js +249 -0
- package/dist/realtimeSessions/verificationPolicy.js.map +1 -0
- package/dist/realtimeSessions/verificationWorkflow.d.ts +263 -0
- package/dist/realtimeSessions/verificationWorkflow.d.ts.map +1 -0
- package/dist/realtimeSessions/verificationWorkflow.js +435 -0
- package/dist/realtimeSessions/verificationWorkflow.js.map +1 -0
- package/dist/realtimeWidget/widgetGuestElevation.d.ts +20 -2
- package/dist/realtimeWidget/widgetGuestElevation.d.ts.map +1 -1
- package/dist/realtimeWidget/widgetGuestElevation.js +31 -2
- package/dist/realtimeWidget/widgetGuestElevation.js.map +1 -1
- package/dist/resolvers/ActionResolver.d.ts +31 -5
- package/dist/resolvers/ActionResolver.d.ts.map +1 -1
- package/dist/resolvers/ActionResolver.js +75 -14
- package/dist/resolvers/ActionResolver.js.map +1 -1
- package/dist/resolvers/AdhocQueryResolver.d.ts +14 -1
- package/dist/resolvers/AdhocQueryResolver.d.ts.map +1 -1
- package/dist/resolvers/AdhocQueryResolver.js +21 -5
- package/dist/resolvers/AdhocQueryResolver.js.map +1 -1
- package/dist/resolvers/ArtifactFileResolver.d.ts +5 -1
- package/dist/resolvers/ArtifactFileResolver.d.ts.map +1 -1
- package/dist/resolvers/ArtifactFileResolver.js +9 -7
- package/dist/resolvers/ArtifactFileResolver.js.map +1 -1
- package/dist/resolvers/CacheStatsResolver.d.ts +27 -0
- package/dist/resolvers/CacheStatsResolver.d.ts.map +1 -1
- package/dist/resolvers/CacheStatsResolver.js +113 -2
- package/dist/resolvers/CacheStatsResolver.js.map +1 -1
- package/dist/resolvers/ClientToolRequestResolver.d.ts +4 -2
- package/dist/resolvers/ClientToolRequestResolver.d.ts.map +1 -1
- package/dist/resolvers/ClientToolRequestResolver.js +28 -10
- package/dist/resolvers/ClientToolRequestResolver.js.map +1 -1
- package/dist/resolvers/ConversationRunEventsResolver.d.ts +8 -4
- package/dist/resolvers/ConversationRunEventsResolver.d.ts.map +1 -1
- package/dist/resolvers/ConversationRunEventsResolver.js +6 -6
- package/dist/resolvers/ConversationRunEventsResolver.js.map +1 -1
- package/dist/resolvers/DatasetResolver.d.ts +24 -3
- package/dist/resolvers/DatasetResolver.d.ts.map +1 -1
- package/dist/resolvers/DatasetResolver.js +57 -8
- package/dist/resolvers/DatasetResolver.js.map +1 -1
- package/dist/resolvers/EntityRecordNameResolver.d.ts +2 -1
- package/dist/resolvers/EntityRecordNameResolver.d.ts.map +1 -1
- package/dist/resolvers/EntityRecordNameResolver.js +3 -2
- package/dist/resolvers/EntityRecordNameResolver.js.map +1 -1
- package/dist/resolvers/FetchEntityVectorsResolver.d.ts +27 -1
- package/dist/resolvers/FetchEntityVectorsResolver.d.ts.map +1 -1
- package/dist/resolvers/FetchEntityVectorsResolver.js +148 -2
- package/dist/resolvers/FetchEntityVectorsResolver.js.map +1 -1
- package/dist/resolvers/FileResolver.d.ts +82 -11
- package/dist/resolvers/FileResolver.d.ts.map +1 -1
- package/dist/resolvers/FileResolver.js +279 -101
- package/dist/resolvers/FileResolver.js.map +1 -1
- package/dist/resolvers/GetDataContextDataResolver.d.ts +33 -7
- package/dist/resolvers/GetDataContextDataResolver.d.ts.map +1 -1
- package/dist/resolvers/GetDataContextDataResolver.js +117 -38
- package/dist/resolvers/GetDataContextDataResolver.js.map +1 -1
- package/dist/resolvers/GetDataResolver.d.ts.map +1 -1
- package/dist/resolvers/GetDataResolver.js +6 -3
- package/dist/resolvers/GetDataResolver.js.map +1 -1
- package/dist/resolvers/HumanHandoffResolver.d.ts.map +1 -1
- package/dist/resolvers/HumanHandoffResolver.js +7 -1
- package/dist/resolvers/HumanHandoffResolver.js.map +1 -1
- package/dist/resolvers/IntegrationDiscoveryResolver.d.ts.map +1 -1
- package/dist/resolvers/IntegrationDiscoveryResolver.js +4 -2
- package/dist/resolvers/IntegrationDiscoveryResolver.js.map +1 -1
- package/dist/resolvers/MCPResolver.d.ts.map +1 -1
- package/dist/resolvers/MCPResolver.js +9 -4
- package/dist/resolvers/MCPResolver.js.map +1 -1
- package/dist/resolvers/QueryResolver.d.ts +2 -0
- package/dist/resolvers/QueryResolver.d.ts.map +1 -1
- package/dist/resolvers/QueryResolver.js +13 -0
- package/dist/resolvers/QueryResolver.js.map +1 -1
- package/dist/resolvers/RealtimeBridgeResolver.d.ts +54 -2
- package/dist/resolvers/RealtimeBridgeResolver.d.ts.map +1 -1
- package/dist/resolvers/RealtimeBridgeResolver.js +155 -10
- package/dist/resolvers/RealtimeBridgeResolver.js.map +1 -1
- package/dist/resolvers/RealtimeClientSessionResolver.d.ts +157 -33
- package/dist/resolvers/RealtimeClientSessionResolver.d.ts.map +1 -1
- package/dist/resolvers/RealtimeClientSessionResolver.js +404 -116
- package/dist/resolvers/RealtimeClientSessionResolver.js.map +1 -1
- package/dist/resolvers/RealtimeSessionEventsResolver.d.ts +61 -0
- package/dist/resolvers/RealtimeSessionEventsResolver.d.ts.map +1 -0
- package/dist/resolvers/RealtimeSessionEventsResolver.js +130 -0
- package/dist/resolvers/RealtimeSessionEventsResolver.js.map +1 -0
- package/dist/resolvers/RealtimeSessionVerificationResolver.d.ts +85 -0
- package/dist/resolvers/RealtimeSessionVerificationResolver.d.ts.map +1 -0
- package/dist/resolvers/RealtimeSessionVerificationResolver.js +188 -0
- package/dist/resolvers/RealtimeSessionVerificationResolver.js.map +1 -0
- package/dist/resolvers/RemoteBrowserActionResolver.d.ts +2 -0
- package/dist/resolvers/RemoteBrowserActionResolver.d.ts.map +1 -1
- package/dist/resolvers/RemoteBrowserActionResolver.js +5 -1
- package/dist/resolvers/RemoteBrowserActionResolver.js.map +1 -1
- package/dist/resolvers/RunAIAgentResolver.d.ts +10 -0
- package/dist/resolvers/RunAIAgentResolver.d.ts.map +1 -1
- package/dist/resolvers/RunAIAgentResolver.js +100 -14
- package/dist/resolvers/RunAIAgentResolver.js.map +1 -1
- package/dist/resolvers/RunTemplateResolver.d.ts.map +1 -1
- package/dist/resolvers/RunTemplateResolver.js +12 -11
- package/dist/resolvers/RunTemplateResolver.js.map +1 -1
- package/dist/resolvers/SearchKnowledgeStreamResolver.d.ts +12 -1
- package/dist/resolvers/SearchKnowledgeStreamResolver.d.ts.map +1 -1
- package/dist/resolvers/SearchKnowledgeStreamResolver.js +15 -2
- package/dist/resolvers/SearchKnowledgeStreamResolver.js.map +1 -1
- package/dist/resolvers/SqlLoggingConfigResolver.d.ts.map +1 -1
- package/dist/resolvers/SqlLoggingConfigResolver.js +2 -3
- package/dist/resolvers/SqlLoggingConfigResolver.js.map +1 -1
- package/dist/resolvers/SyncDataResolver.d.ts.map +1 -1
- package/dist/resolvers/SyncDataResolver.js +6 -2
- package/dist/resolvers/SyncDataResolver.js.map +1 -1
- package/dist/resolvers/SyncRolesUsersResolver.d.ts +2 -0
- package/dist/resolvers/SyncRolesUsersResolver.d.ts.map +1 -1
- package/dist/resolvers/SyncRolesUsersResolver.js +23 -6
- package/dist/resolvers/SyncRolesUsersResolver.js.map +1 -1
- package/dist/resolvers/TaskGraphFrameResolver.d.ts +2 -1
- package/dist/resolvers/TaskGraphFrameResolver.d.ts.map +1 -1
- package/dist/resolvers/TaskGraphFrameResolver.js +28 -1
- package/dist/resolvers/TaskGraphFrameResolver.js.map +1 -1
- package/dist/resolvers/TestQuerySQLResolver.d.ts +24 -0
- package/dist/resolvers/TestQuerySQLResolver.d.ts.map +1 -1
- package/dist/resolvers/TestQuerySQLResolver.js +65 -13
- package/dist/resolvers/TestQuerySQLResolver.js.map +1 -1
- package/dist/resolvers/TransactionGroupResolver.d.ts +19 -2
- package/dist/resolvers/TransactionGroupResolver.d.ts.map +1 -1
- package/dist/resolvers/TransactionGroupResolver.js +102 -24
- package/dist/resolvers/TransactionGroupResolver.js.map +1 -1
- package/dist/resolvers/UserAvatarResolver.d.ts +16 -0
- package/dist/resolvers/UserAvatarResolver.d.ts.map +1 -0
- package/dist/resolvers/UserAvatarResolver.js +124 -0
- package/dist/resolvers/UserAvatarResolver.js.map +1 -0
- package/dist/resolvers/UserResolver.d.ts.map +1 -1
- package/dist/resolvers/UserResolver.js +2 -17
- package/dist/resolvers/UserResolver.js.map +1 -1
- package/dist/resolvers/agent-run-data-guard.d.ts +31 -0
- package/dist/resolvers/agent-run-data-guard.d.ts.map +1 -0
- package/dist/resolvers/agent-run-data-guard.js +72 -0
- package/dist/resolvers/agent-run-data-guard.js.map +1 -0
- package/dist/resolvers/agentVisionConsentAudit.d.ts +37 -0
- package/dist/resolvers/agentVisionConsentAudit.d.ts.map +1 -0
- package/dist/resolvers/agentVisionConsentAudit.js +63 -0
- package/dist/resolvers/agentVisionConsentAudit.js.map +1 -0
- package/dist/resolvers/avatarInputValidation.d.ts +40 -0
- package/dist/resolvers/avatarInputValidation.d.ts.map +1 -0
- package/dist/resolvers/avatarInputValidation.js +97 -0
- package/dist/resolvers/avatarInputValidation.js.map +1 -0
- package/dist/resolvers/currentUserRoles.d.ts +29 -0
- package/dist/resolvers/currentUserRoles.d.ts.map +1 -1
- package/dist/resolvers/currentUserRoles.js +30 -0
- package/dist/resolvers/currentUserRoles.js.map +1 -1
- package/dist/resolvers/meetings/meetingMutations.d.ts +6 -0
- package/dist/resolvers/meetings/meetingMutations.d.ts.map +1 -1
- package/dist/resolvers/meetings/meetingMutations.js +21 -0
- package/dist/resolvers/meetings/meetingMutations.js.map +1 -1
- package/dist/rest/RealtimeRecordingHandler.d.ts +49 -0
- package/dist/rest/RealtimeRecordingHandler.d.ts.map +1 -0
- package/dist/rest/RealtimeRecordingHandler.js +383 -0
- package/dist/rest/RealtimeRecordingHandler.js.map +1 -0
- package/dist/rest/ViewOperationsHandler.d.ts +3 -1
- package/dist/rest/ViewOperationsHandler.d.ts.map +1 -1
- package/dist/rest/ViewOperationsHandler.js +21 -12
- package/dist/rest/ViewOperationsHandler.js.map +1 -1
- package/dist/rest/setupRESTEndpoints.d.ts +6 -0
- package/dist/rest/setupRESTEndpoints.d.ts.map +1 -1
- package/dist/rest/setupRESTEndpoints.js +6 -0
- package/dist/rest/setupRESTEndpoints.js.map +1 -1
- package/dist/serverExtensionReservedRoots.d.ts +12 -10
- package/dist/serverExtensionReservedRoots.d.ts.map +1 -1
- package/dist/serverExtensionReservedRoots.js +14 -17
- package/dist/serverExtensionReservedRoots.js.map +1 -1
- package/dist/services/MJStorageBlobStore.d.ts +8 -1
- package/dist/services/MJStorageBlobStore.d.ts.map +1 -1
- package/dist/services/MJStorageBlobStore.js +25 -19
- package/dist/services/MJStorageBlobStore.js.map +1 -1
- package/dist/services/StartTaskGraphDispatcher.js +2 -2
- package/dist/services/StartTaskGraphDispatcher.js.map +1 -1
- package/dist/services/TaskGraphActionRunner.d.ts +5 -3
- package/dist/services/TaskGraphActionRunner.d.ts.map +1 -1
- package/dist/services/TaskGraphActionRunner.js +27 -5
- package/dist/services/TaskGraphActionRunner.js.map +1 -1
- package/dist/services/TaskGraphAgentRunner.d.ts +14 -2
- package/dist/services/TaskGraphAgentRunner.d.ts.map +1 -1
- package/dist/services/TaskGraphAgentRunner.js +157 -9
- package/dist/services/TaskGraphAgentRunner.js.map +1 -1
- package/dist/services/TaskGraphContinuationDeliverer.d.ts +57 -4
- package/dist/services/TaskGraphContinuationDeliverer.d.ts.map +1 -1
- package/dist/services/TaskGraphContinuationDeliverer.js +607 -18
- package/dist/services/TaskGraphContinuationDeliverer.js.map +1 -1
- package/dist/sharedCache.d.ts +105 -0
- package/dist/sharedCache.d.ts.map +1 -0
- package/dist/sharedCache.js +279 -0
- package/dist/sharedCache.js.map +1 -0
- package/dist/types.d.ts +6 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +99 -96
- package/src/__tests__/ActionResolver.authorization.test.ts +353 -0
- package/src/__tests__/AdhocQueryResolver.sqlAuthorizer.test.ts +104 -0
- package/src/__tests__/BridgeHostInstance.test.ts +232 -0
- package/src/__tests__/ClientToolRequestResolver.test.ts +116 -0
- package/src/__tests__/DatasetResolver.itemFilters.test.ts +201 -0
- package/src/__tests__/EntityRecordNameResolver.rowSecurity.test.ts +152 -0
- package/src/__tests__/FetchEntityVectorsResolver.test.ts +433 -0
- package/src/__tests__/FileResolver.storageAccess.test.ts +562 -0
- package/src/__tests__/GetDataContextDataResolver.sqlItems.test.ts +416 -0
- package/src/__tests__/HostInstance.test.ts +84 -0
- package/src/__tests__/HumanHandoffResolver.test.ts +17 -0
- package/src/__tests__/ListOperationsResolver.adhocScreen.test.ts +137 -0
- package/src/__tests__/LoginScreenEngine.test.ts +86 -0
- package/src/__tests__/MJStorageBlobStore.storageGate.test.ts +63 -0
- package/src/__tests__/MeetingResolver.test.ts +75 -1
- package/src/__tests__/RealtimeBridgeResolver.test.ts +415 -6
- package/src/__tests__/RealtimeClientSessionResolver.configTamper.test.ts +383 -0
- package/src/__tests__/RealtimeClientSessionResolver.test.ts +682 -58
- package/src/__tests__/RealtimeProxyServer.test.ts +16 -1
- package/src/__tests__/RealtimeRelay.test.ts +876 -0
- package/src/__tests__/RecordingAssemblyScheduler.test.ts +178 -0
- package/src/__tests__/RemoteBrowserActionResolver.goalRunLink.test.ts +129 -0
- package/src/__tests__/ResolverBase.adhocReadScope.test.ts +133 -2
- package/src/__tests__/ResolverBase.aggregateScreen.test.ts +174 -0
- package/src/__tests__/ResolverBase.balancedClause.test.ts +155 -0
- package/src/__tests__/ResolverBase.clauseUnscopedRead.test.ts +127 -0
- package/src/__tests__/ResolverBase.clientOldValues.test.ts +212 -6
- package/src/__tests__/ResolverBase.filterEscaping.test.ts +5 -2
- package/src/__tests__/ReturningVisitorRecap.test.ts +115 -0
- package/src/__tests__/RunAIAgentResolver.branch.test.ts +170 -0
- package/src/__tests__/RunAIAgentResolver.historyFrom.test.ts +6 -4
- package/src/__tests__/RunAIAgentResolver.runDataGuard.test.ts +258 -0
- package/src/__tests__/RunAIAgentResolver.stoppedPredecessor.test.ts +166 -0
- package/src/__tests__/RunTemplateResolver.test.ts +132 -0
- package/src/__tests__/RunViewResolver.cacheCheckForwarding.test.ts +63 -0
- package/src/__tests__/RunViewResolver.cacheCheckScreen.test.ts +165 -0
- package/src/__tests__/SearchKnowledgeStreamResolver.test.ts +161 -0
- package/src/__tests__/SessionJanitor.test.ts +1203 -21
- package/src/__tests__/SessionManager.test.ts +240 -17
- package/src/__tests__/SessionRunIDVerifier.test.ts +251 -0
- package/src/__tests__/SyncRolesUsersResolver.userRoles.test.ts +97 -0
- package/src/__tests__/TaskGraphActionRunner.durablePayload.test.ts +25 -0
- package/src/__tests__/TaskGraphAgentRunner.test.ts +266 -0
- package/src/__tests__/TaskGraphContinuationDeliverer.test.ts +403 -22
- package/src/__tests__/TaskGraphFrameResolver.test.ts +22 -0
- package/src/__tests__/TestQuerySQLResolver.test.ts +274 -0
- package/src/__tests__/TransactionGroupResolver.refusals.test.ts +98 -1
- package/src/__tests__/UpdateMJDataContextItem.oldValues.test.ts +220 -0
- package/src/__tests__/UserAvatarResolver.test.ts +255 -0
- package/src/__tests__/UserResolver.currentUser.test.ts +16 -1
- package/src/__tests__/ViewOperationsHandler.clauseScreen.test.ts +157 -0
- package/src/__tests__/actionAuthorization.test.ts +130 -0
- package/src/__tests__/agent-run-data-guard.test.ts +130 -0
- package/src/__tests__/agentVisionConsentAudit.test.ts +118 -0
- package/src/__tests__/apiRootBoot.test.ts +202 -0
- package/src/__tests__/avatarInputValidation.test.ts +160 -0
- package/src/__tests__/cacheInvalidationRecordData.test.ts +64 -0
- package/src/__tests__/conversationRunEvents.test.ts +56 -14
- package/src/__tests__/globalCors.test.ts +217 -0
- package/src/__tests__/isolatedProviderTransactions.test.ts +169 -0
- package/src/__tests__/magicLinkService.consume.test.ts +6 -0
- package/src/__tests__/magicLinkService.provisionLog.test.ts +5 -0
- package/src/__tests__/multiTenancy.postgresRewrite.test.ts +181 -0
- package/src/__tests__/multiTenancy.security.test.ts +51 -0
- package/src/__tests__/multiTenancy.test.ts +1 -1
- package/src/__tests__/newUsers.template.test.ts +151 -0
- package/src/__tests__/newUsers.test.ts +74 -5
- package/src/__tests__/orphanedConversationDetailReconciler.test.ts +17 -2
- package/src/__tests__/ownedRealtimeSession.test.ts +39 -0
- package/src/__tests__/pushStatusResolver.filter.test.ts +7 -0
- package/src/__tests__/realtimeRecordingHandler.test.ts +652 -0
- package/src/__tests__/realtimeSessions/RealtimeSessionEventService.test.ts +201 -0
- package/src/__tests__/realtimeSessions/RealtimeSessionEventsResolver.test.ts +215 -0
- package/src/__tests__/realtimeSessions/RealtimeSessionVerificationResolver.test.ts +102 -0
- package/src/__tests__/realtimeSessions/RealtimeSessionVerificationService.test.ts +349 -0
- package/src/__tests__/realtimeSessions/RealtimeVerifyRouter.test.ts +131 -0
- package/src/__tests__/realtimeSessions/SlidingWindowRateLimiter.test.ts +56 -0
- package/src/__tests__/realtimeSessions/helpers.ts +4 -0
- package/src/__tests__/realtimeSessions/sessionAccess.test.ts +129 -0
- package/src/__tests__/realtimeSessions/sessionConfigStamps.test.ts +124 -0
- package/src/__tests__/realtimeSessions/verificationCore.test.ts +355 -0
- package/src/__tests__/realtimeSessions/verificationPages.test.ts +84 -0
- package/src/__tests__/realtimeSessions/verificationPolicy.test.ts +226 -0
- package/src/__tests__/realtimeSessions/verificationWorkflow.test.ts +633 -0
- package/src/__tests__/resolverBase.fls.test.ts +87 -4
- package/src/__tests__/serverExtensionHostOverlay.test.ts +66 -0
- package/src/__tests__/serverExtensionReservedRoots.test.ts +11 -96
- package/src/__tests__/sharedCache.test.ts +312 -0
- package/src/__tests__/widgetGuestElevation.test.ts +44 -0
- package/src/agentSessions/BridgeHostInstance.ts +32 -0
- package/src/agentSessions/HostInstance.ts +124 -28
- package/src/agentSessions/ReturningVisitorRecap.ts +7 -3
- package/src/agentSessions/SessionJanitor.ts +821 -59
- package/src/agentSessions/SessionManager.ts +138 -26
- package/src/agentSessions/SessionRunIDVerifier.ts +171 -0
- package/src/agentSessions/index.ts +10 -3
- package/src/apiRoot.ts +78 -0
- package/src/auth/AuthProviderCatalogRouter.ts +26 -0
- package/src/auth/LoginScreenEngine.ts +50 -0
- package/src/auth/actionAuthorization.ts +116 -0
- package/src/auth/index.ts +4 -8
- package/src/auth/magicLink/MagicLinkRouter.ts +3 -2
- package/src/auth/magicLink/MagicLinkService.ts +6 -3
- package/src/auth/newUsers.ts +99 -11
- package/src/config.ts +171 -5
- package/src/context.ts +15 -10
- package/src/coreRoutes.ts +166 -0
- package/src/generated/graphql-schemas/__mj.ts +1815 -57
- package/src/generic/CacheInvalidationResolver.ts +73 -18
- package/src/generic/OrphanedConversationDetailReconciler.ts +3 -3
- package/src/generic/PushStatusResolver.ts +1 -1
- package/src/generic/ResolverBase.ts +335 -326
- package/src/generic/RunViewResolver.ts +21 -0
- package/src/globalCors.ts +71 -0
- package/src/index.ts +231 -300
- package/src/isolatedProvider.ts +22 -0
- package/src/multiTenancy/index.ts +24 -2
- package/src/realtimeProxy/RealtimeProxyServer.ts +148 -16
- package/src/realtimeProxy/RealtimeRelayTunnel.ts +645 -0
- package/src/realtimeSessions/README.md +179 -0
- package/src/realtimeSessions/RealtimeSessionEventService.ts +274 -0
- package/src/realtimeSessions/RealtimeSessionVerificationService.ts +168 -0
- package/src/realtimeSessions/RealtimeVerifyRouter.ts +109 -0
- package/src/realtimeSessions/RecordingAssemblyScheduler.ts +234 -0
- package/src/realtimeSessions/SessionVerificationPortsBase.ts +189 -0
- package/src/realtimeSessions/SlidingWindowRateLimiter.ts +92 -0
- package/src/realtimeSessions/index.ts +18 -0
- package/src/realtimeSessions/ownedRealtimeSession.ts +55 -0
- package/src/realtimeSessions/sessionAccess.ts +145 -0
- package/src/realtimeSessions/sessionConfigStamps.ts +123 -0
- package/src/realtimeSessions/subscriptionAuthorization.ts +116 -0
- package/src/realtimeSessions/verificationCore.ts +502 -0
- package/src/realtimeSessions/verificationPages.ts +149 -0
- package/src/realtimeSessions/verificationPolicy.ts +321 -0
- package/src/realtimeSessions/verificationWorkflow.ts +702 -0
- package/src/realtimeWidget/widgetGuestElevation.ts +34 -2
- package/src/resolvers/ActionResolver.ts +84 -21
- package/src/resolvers/AdhocQueryResolver.ts +24 -6
- package/src/resolvers/ArtifactFileResolver.ts +9 -8
- package/src/resolvers/CacheStatsResolver.ts +89 -2
- package/src/resolvers/ClientToolRequestResolver.ts +25 -7
- package/src/resolvers/ConversationRunEventsResolver.ts +15 -11
- package/src/resolvers/DatasetResolver.ts +70 -10
- package/src/resolvers/EntityRecordNameResolver.ts +3 -2
- package/src/resolvers/FetchEntityVectorsResolver.ts +179 -2
- package/src/resolvers/FileResolver.ts +321 -106
- package/src/resolvers/GetDataContextDataResolver.ts +139 -41
- package/src/resolvers/GetDataResolver.ts +6 -3
- package/src/resolvers/HumanHandoffResolver.ts +8 -0
- package/src/resolvers/IntegrationDiscoveryResolver.ts +4 -2
- package/src/resolvers/MCPResolver.ts +8 -5
- package/src/resolvers/QueryResolver.ts +11 -0
- package/src/resolvers/RealtimeBridgeResolver.ts +163 -11
- package/src/resolvers/RealtimeClientSessionResolver.ts +511 -129
- package/src/resolvers/RealtimeSessionEventsResolver.ts +133 -0
- package/src/resolvers/RealtimeSessionVerificationResolver.ts +174 -0
- package/src/resolvers/RemoteBrowserActionResolver.ts +11 -1
- package/src/resolvers/RunAIAgentResolver.ts +116 -14
- package/src/resolvers/RunTemplateResolver.ts +13 -12
- package/src/resolvers/SearchKnowledgeStreamResolver.ts +19 -3
- package/src/resolvers/SqlLoggingConfigResolver.ts +2 -4
- package/src/resolvers/SyncDataResolver.ts +6 -2
- package/src/resolvers/SyncRolesUsersResolver.ts +24 -6
- package/src/resolvers/TaskGraphFrameResolver.ts +33 -1
- package/src/resolvers/TestQuerySQLResolver.ts +68 -13
- package/src/resolvers/TransactionGroupResolver.ts +131 -27
- package/src/resolvers/UserAvatarResolver.ts +111 -0
- package/src/resolvers/UserResolver.ts +2 -16
- package/src/resolvers/__tests__/GetDataResolver.validation.test.ts +95 -0
- package/src/resolvers/agent-run-data-guard.ts +89 -0
- package/src/resolvers/agentVisionConsentAudit.ts +82 -0
- package/src/resolvers/avatarInputValidation.ts +123 -0
- package/src/resolvers/currentUserRoles.ts +32 -1
- package/src/resolvers/meetings/meetingMutations.ts +21 -0
- package/src/rest/RealtimeRecordingHandler.ts +464 -0
- package/src/rest/ViewOperationsHandler.ts +29 -13
- package/src/rest/setupRESTEndpoints.ts +6 -0
- package/src/serverExtensionReservedRoots.ts +14 -17
- package/src/services/MJStorageBlobStore.ts +31 -30
- package/src/services/StartTaskGraphDispatcher.ts +2 -2
- package/src/services/TaskGraphActionRunner.ts +25 -5
- package/src/services/TaskGraphAgentRunner.ts +188 -11
- package/src/services/TaskGraphContinuationDeliverer.ts +713 -17
- package/src/sharedCache.ts +305 -0
- package/src/types.ts +7 -0
|
@@ -7,27 +7,18 @@ import {
|
|
|
7
7
|
} from '@memberjunction/core-entities';
|
|
8
8
|
import { AIAgentPermissionHelper } from '@memberjunction/ai-engine-base';
|
|
9
9
|
import { RealtimeClientSessionService, RealtimeChannelServerHost } from '@memberjunction/ai-agents';
|
|
10
|
+
import type { BridgeDisconnectReason } from '@memberjunction/ai-bridge-base';
|
|
10
11
|
import { GetHostInstanceID } from './HostInstance.js';
|
|
11
12
|
import { WriteReturningVisitorRecap } from './ReturningVisitorRecap.js';
|
|
13
|
+
import { SessionRunIDVerifier, SessionRunIDs } from './SessionRunIDVerifier.js';
|
|
12
14
|
import { ResolveScopedAnonymousRunUser } from '../realtimeWidget/widgetGuestElevation.js';
|
|
15
|
+
import { RecordingAssemblyScheduler } from '../realtimeSessions/RecordingAssemblyScheduler.js';
|
|
13
16
|
|
|
14
17
|
/** Entity names — centralised so the `MJ:`-prefix convention is applied in exactly one place. */
|
|
15
18
|
const SESSION_ENTITY = 'MJ: AI Agent Sessions';
|
|
16
19
|
const SESSION_CHANNEL_ENTITY = 'MJ: AI Agent Session Channels';
|
|
17
20
|
const CONVERSATION_ENTITY = 'MJ: Conversations';
|
|
18
21
|
|
|
19
|
-
/**
|
|
20
|
-
* Shape of the observability run ids a realtime voice session persists in `AIAgentSession.Config_`.
|
|
21
|
-
* Read on {@link SessionManager.CloseSession} to finalize the co-agent runs. All fields optional —
|
|
22
|
-
* a non-voice session (or one whose run creation was skipped) carries none of them.
|
|
23
|
-
*/
|
|
24
|
-
interface SessionRunConfig {
|
|
25
|
-
coAgentRunID?: string;
|
|
26
|
-
promptRunID?: string;
|
|
27
|
-
/** The co-agent run's single system-prompt `MJ: AI Agent Run Steps` row id (its Timeline entry). */
|
|
28
|
-
coAgentRunStepID?: string;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
22
|
/**
|
|
32
23
|
* Inputs for {@link SessionManager.CreateSession}. `conversationID`/`lastSessionID`/`config`
|
|
33
24
|
* are optional — when no `conversationID` is supplied a fresh Conversation is created and linked.
|
|
@@ -54,6 +45,24 @@ export interface CreateSessionInput {
|
|
|
54
45
|
*/
|
|
55
46
|
export type SessionCloseReason = 'Explicit' | 'Janitor' | 'Shutdown' | 'Error';
|
|
56
47
|
|
|
48
|
+
/**
|
|
49
|
+
* The {@link SessionCloseReason} for a session whose bridged agent has left (see
|
|
50
|
+
* {@link SessionManager.CloseSessionForEndedBridge}). The bridge's reason carries over where the session has the same one;
|
|
51
|
+
* `HostEnded` (everyone left the room, the call hung up) closes it as `Explicit`, people ending it, as phone calls close
|
|
52
|
+
* theirs.
|
|
53
|
+
*/
|
|
54
|
+
function sessionCloseReasonForBridgeEnd(reason: BridgeDisconnectReason): SessionCloseReason {
|
|
55
|
+
switch (reason) {
|
|
56
|
+
case 'Error':
|
|
57
|
+
case 'Janitor':
|
|
58
|
+
case 'Shutdown':
|
|
59
|
+
return reason;
|
|
60
|
+
case 'Explicit':
|
|
61
|
+
case 'HostEnded':
|
|
62
|
+
return 'Explicit';
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
57
66
|
/**
|
|
58
67
|
* Thrown by {@link SessionManager.CreateSession} when the caller lacks `CanRun` on the target
|
|
59
68
|
* agent. No session row is created — denial happens before any write. Distinct error type so the
|
|
@@ -126,6 +135,9 @@ export class SessionManager {
|
|
|
126
135
|
*/
|
|
127
136
|
private readonly realtimeClientSessionService: RealtimeClientSessionService;
|
|
128
137
|
|
|
138
|
+
/** Checks the run ids read from a session's owner-editable `Config_` before they are used. */
|
|
139
|
+
private readonly runIDVerifier = new SessionRunIDVerifier();
|
|
140
|
+
|
|
129
141
|
/**
|
|
130
142
|
* @param realtimeClientSessionService The shared {@link RealtimeClientSessionService} instance to
|
|
131
143
|
* finalize observability runs through. Pass the SAME instance your resolver/service used to create
|
|
@@ -201,6 +213,13 @@ export class SessionManager {
|
|
|
201
213
|
if (!closed) {
|
|
202
214
|
return false;
|
|
203
215
|
}
|
|
216
|
+
if (session.RecordingStartedAt) {
|
|
217
|
+
// A client-direct recording is assembled only after the grace period while its call is open
|
|
218
|
+
// (a hidden tab must not rewrite recording.wav on every switch; see RealtimeRecordingHandler).
|
|
219
|
+
// The call has ended now, so assemble it right away. The ledger's claim arbitrates instances,
|
|
220
|
+
// and a recording with nothing to assemble (none, or server-bridged) is simply not claimable.
|
|
221
|
+
RecordingAssemblyScheduler.Instance.ScheduleAssembly(agentSessionID, 0, false);
|
|
222
|
+
}
|
|
204
223
|
await this.disconnectChannels(agentSessionID, contextUser, provider, preloadedChannels);
|
|
205
224
|
await this.finalizeObservabilityRuns(session, contextUser, provider);
|
|
206
225
|
await this.notifyChannelPluginsSessionClosed(agentSessionID, closeReason);
|
|
@@ -211,6 +230,68 @@ export class SessionManager {
|
|
|
211
230
|
return true;
|
|
212
231
|
}
|
|
213
232
|
|
|
233
|
+
/**
|
|
234
|
+
* Closes a session that was created for one bridged agent (a bot in a meeting room) once that agent's bridge has
|
|
235
|
+
* ended, whatever ended it: the agent was stopped, the meeting was ended, everyone left, the model session was lost.
|
|
236
|
+
* Without this the session stays `Active` until the janitor's staleness sweep closes it, 15 minutes or more later.
|
|
237
|
+
*
|
|
238
|
+
* The close is {@link CloseSession}, the one the janitor runs, with the bridge's reason: `Explicit` for a stop, an
|
|
239
|
+
* ended meeting or an emptied room (`HostEnded`), otherwise the bridge's own (`Error`, `Janitor`, `Shutdown`). A
|
|
240
|
+
* session already closed (by the janitor, or by its user) keeps its reason.
|
|
241
|
+
*
|
|
242
|
+
* Never throws: it runs as the bridge's end-of-session bookkeeping. A failure is logged and leaves the session to the
|
|
243
|
+
* janitor, as before.
|
|
244
|
+
*
|
|
245
|
+
* @param agentSessionID The session created for the bridged agent.
|
|
246
|
+
* @param reason Why the bridge ended.
|
|
247
|
+
* @param contextUser The user the session was created for.
|
|
248
|
+
* @param provider The metadata provider the session was created through.
|
|
249
|
+
* @returns `true` when the session is (or already was) closed.
|
|
250
|
+
*/
|
|
251
|
+
public async CloseSessionForEndedBridge(
|
|
252
|
+
agentSessionID: string,
|
|
253
|
+
reason: BridgeDisconnectReason,
|
|
254
|
+
contextUser: UserInfo,
|
|
255
|
+
provider: IMetadataProvider,
|
|
256
|
+
): Promise<boolean> {
|
|
257
|
+
try {
|
|
258
|
+
return await this.CloseSession(agentSessionID, contextUser, provider, sessionCloseReasonForBridgeEnd(reason));
|
|
259
|
+
} catch (e) {
|
|
260
|
+
LogError(
|
|
261
|
+
`SessionManager.CloseSessionForEndedBridge could not close agent session ${agentSessionID} after its bridge ended ` +
|
|
262
|
+
`(${reason}); the janitor will: ${e instanceof Error ? e.message : String(e)}`,
|
|
263
|
+
);
|
|
264
|
+
return false;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Closes a session that was created for one agent's time in a room when that agent failed to start: its model session
|
|
270
|
+
* could not open, the bot's token could not be minted, the bridge did not start. The agent never joined, so no
|
|
271
|
+
* end-of-session hook will close the session; without this it stays `Active` until the janitor's staleness sweep.
|
|
272
|
+
*
|
|
273
|
+
* The close is {@link CloseSession} with reason `Error`. A session already closed keeps its reason.
|
|
274
|
+
*
|
|
275
|
+
* Never throws: it runs while the caller handles the failed start, whose error is the one the caller reports. A failure
|
|
276
|
+
* is logged and leaves the session to the janitor.
|
|
277
|
+
*
|
|
278
|
+
* @param agentSessionID The session created for the agent.
|
|
279
|
+
* @param contextUser The user the session was created for.
|
|
280
|
+
* @param provider The metadata provider the session was created through.
|
|
281
|
+
* @returns `true` when the session is (or already was) closed.
|
|
282
|
+
*/
|
|
283
|
+
public async CloseSessionForFailedStart(agentSessionID: string, contextUser: UserInfo, provider: IMetadataProvider): Promise<boolean> {
|
|
284
|
+
try {
|
|
285
|
+
return await this.CloseSession(agentSessionID, contextUser, provider, 'Error');
|
|
286
|
+
} catch (e) {
|
|
287
|
+
LogError(
|
|
288
|
+
`SessionManager.CloseSessionForFailedStart could not close agent session ${agentSessionID} after its agent failed ` +
|
|
289
|
+
`to start; the janitor will: ${e instanceof Error ? e.message : String(e)}`,
|
|
290
|
+
);
|
|
291
|
+
return false;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
214
295
|
/**
|
|
215
296
|
* Notifies the server-side channel-plugin host that a session started, so it can resolve the
|
|
216
297
|
* ACTIVE `MJ: AI Agent Channels` rows' `ServerPluginClass` plugins (one fresh instance per
|
|
@@ -260,7 +341,8 @@ export class SessionManager {
|
|
|
260
341
|
|
|
261
342
|
/**
|
|
262
343
|
* Finalizes the co-agent observability runs a realtime voice session stored in its `Config_`
|
|
263
|
-
* (see `RealtimeClientSessionResolver`).
|
|
344
|
+
* (see `RealtimeClientSessionResolver`). Only run ids that are records of the session are
|
|
345
|
+
* finalized, because the owner can edit `Config_`. No-op when none remain. Tolerant: a
|
|
264
346
|
* malformed config or a finalize failure is swallowed so it can never break session close.
|
|
265
347
|
*/
|
|
266
348
|
private async finalizeObservabilityRuns(
|
|
@@ -268,8 +350,8 @@ export class SessionManager {
|
|
|
268
350
|
contextUser: UserInfo,
|
|
269
351
|
provider: IMetadataProvider,
|
|
270
352
|
): Promise<void> {
|
|
271
|
-
const
|
|
272
|
-
if (!
|
|
353
|
+
const claimed = this.parseSessionRunConfig(session.Config_);
|
|
354
|
+
if (!claimed.CoAgentRunID && !claimed.PromptRunID && !claimed.CoAgentRunStepID) {
|
|
273
355
|
return;
|
|
274
356
|
}
|
|
275
357
|
try {
|
|
@@ -277,36 +359,54 @@ export class SessionManager {
|
|
|
277
359
|
// for a scoped anonymous session, so an owner-initiated (or error) close must finalize
|
|
278
360
|
// under it too — the caller's role holds no grants on the AI run entities. Janitor and
|
|
279
361
|
// shutdown sweeps already close as the system user and pass through unchanged.
|
|
362
|
+
const runUser = ResolveScopedAnonymousRunUser(contextUser);
|
|
363
|
+
const runIDs = await this.runIDVerifier.Verify(session.ID, claimed, runUser, provider);
|
|
364
|
+
if (!runIDs.CoAgentRunID && !runIDs.PromptRunID && !runIDs.CoAgentRunStepID) {
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
280
367
|
await this.realtimeClientSessionService.FinalizeCoAgentRun(
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
368
|
+
runIDs.CoAgentRunID ?? null,
|
|
369
|
+
runIDs.PromptRunID ?? null,
|
|
370
|
+
runUser,
|
|
284
371
|
provider,
|
|
285
372
|
true,
|
|
286
|
-
|
|
373
|
+
runIDs.CoAgentRunStepID ?? null,
|
|
287
374
|
);
|
|
288
375
|
} catch (e) {
|
|
289
376
|
LogError(`SessionManager.finalizeObservabilityRuns failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
290
377
|
}
|
|
291
378
|
}
|
|
292
379
|
|
|
293
|
-
/** Parses the session's `Config_` for observability run ids; returns
|
|
294
|
-
private parseSessionRunConfig(raw: string | null):
|
|
380
|
+
/** Parses the session's `Config_` for observability run ids; returns none on any error. */
|
|
381
|
+
private parseSessionRunConfig(raw: string | null): SessionRunIDs {
|
|
295
382
|
if (!raw) {
|
|
296
383
|
return {};
|
|
297
384
|
}
|
|
298
385
|
try {
|
|
299
|
-
const parsed = JSON.parse(raw) as
|
|
386
|
+
const parsed = JSON.parse(raw) as { coAgentRunID?: unknown; promptRunID?: unknown; coAgentRunStepID?: unknown };
|
|
300
387
|
return {
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
388
|
+
CoAgentRunID: typeof parsed.coAgentRunID === 'string' ? parsed.coAgentRunID : undefined,
|
|
389
|
+
PromptRunID: typeof parsed.promptRunID === 'string' ? parsed.promptRunID : undefined,
|
|
390
|
+
CoAgentRunStepID: typeof parsed.coAgentRunStepID === 'string' ? parsed.coAgentRunStepID : undefined,
|
|
304
391
|
};
|
|
305
392
|
} catch {
|
|
306
393
|
return {};
|
|
307
394
|
}
|
|
308
395
|
}
|
|
309
396
|
|
|
397
|
+
/** The session's co-agent run id from its `Config_`, when it is a run of the session. */
|
|
398
|
+
private async verifiedCoAgentRunID(
|
|
399
|
+
session: MJAIAgentSessionEntity,
|
|
400
|
+
runUser: UserInfo,
|
|
401
|
+
provider: IMetadataProvider,
|
|
402
|
+
): Promise<string | undefined> {
|
|
403
|
+
const { CoAgentRunID } = this.parseSessionRunConfig(session.Config_);
|
|
404
|
+
if (!CoAgentRunID) {
|
|
405
|
+
return undefined;
|
|
406
|
+
}
|
|
407
|
+
return (await this.runIDVerifier.Verify(session.ID, { CoAgentRunID }, runUser, provider)).CoAgentRunID;
|
|
408
|
+
}
|
|
409
|
+
|
|
310
410
|
/**
|
|
311
411
|
* Record activity on a session. Coalesces persisted writes so at most one `LastActiveAt` update
|
|
312
412
|
* lands per session per {@link HEARTBEAT_MIN_WRITE_INTERVAL_MS}; intervening calls return `true`
|
|
@@ -438,7 +538,11 @@ export class SessionManager {
|
|
|
438
538
|
return session;
|
|
439
539
|
}
|
|
440
540
|
|
|
441
|
-
/**
|
|
541
|
+
/**
|
|
542
|
+
* Loads a session entity by ID, returning null when it cannot be loaded. The server entity
|
|
543
|
+
* (`MJAIAgentSessionEntityServer`) keeps the lifecycle saves that follow from writing back the
|
|
544
|
+
* recording ledger's columns (#5294).
|
|
545
|
+
*/
|
|
442
546
|
private async loadSession(
|
|
443
547
|
agentSessionID: string,
|
|
444
548
|
contextUser: UserInfo,
|
|
@@ -565,6 +669,14 @@ export class SessionManager {
|
|
|
565
669
|
const saved = await this.saveOrLog(session, 'Heartbeat');
|
|
566
670
|
if (saved) {
|
|
567
671
|
this.heartbeatLastWrite.Set(agentSessionID.toLowerCase(), Date.now());
|
|
672
|
+
// A live session keeps its co-agent run live too — on whichever instance gets its heartbeats —
|
|
673
|
+
// or the agent-run watchdog force-fails the run mid-call. Same elevation as the finalize path.
|
|
674
|
+
const runUser = ResolveScopedAnonymousRunUser(contextUser);
|
|
675
|
+
this.realtimeClientSessionService.KeepCoAgentRunAlive(
|
|
676
|
+
await this.verifiedCoAgentRunID(session, runUser, provider),
|
|
677
|
+
provider,
|
|
678
|
+
runUser,
|
|
679
|
+
);
|
|
568
680
|
}
|
|
569
681
|
return saved;
|
|
570
682
|
}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Checks the run ids a realtime session keeps in its `Config` before server code
|
|
3
|
+
* acts on them.
|
|
4
|
+
*
|
|
5
|
+
* @module @memberjunction/server
|
|
6
|
+
*/
|
|
7
|
+
import { IMetadataProvider, LogError, RunView, RunViewParams, UserInfo } from '@memberjunction/core';
|
|
8
|
+
import { EscapeSQLString, IsValidUUID, UUIDsEqual } from '@memberjunction/global';
|
|
9
|
+
import { UserCache } from '@memberjunction/generic-database-provider';
|
|
10
|
+
|
|
11
|
+
const AGENT_RUN_ENTITY = 'MJ: AI Agent Runs';
|
|
12
|
+
const AGENT_RUN_STEP_ENTITY = 'MJ: AI Agent Run Steps';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* The run ids a realtime voice session keeps in its `Config` JSON. Server code reads and writes the
|
|
16
|
+
* records they point at, often as an elevated user.
|
|
17
|
+
*/
|
|
18
|
+
export interface SessionRunIDs {
|
|
19
|
+
/** The co-agent observability run (`MJ: AI Agent Runs`). */
|
|
20
|
+
CoAgentRunID?: string;
|
|
21
|
+
/** The co-agent prompt run (`MJ: AI Prompt Runs`), linked through the co-agent run's prompt step. */
|
|
22
|
+
PromptRunID?: string;
|
|
23
|
+
/** The co-agent run's system-prompt step (`MJ: AI Agent Run Steps`). */
|
|
24
|
+
CoAgentRunStepID?: string;
|
|
25
|
+
/** A delegated run (`MJ: AI Agent Runs`) that paused for the user's answer. */
|
|
26
|
+
PendingFeedbackRunID?: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** A row of the run-step lookup. */
|
|
30
|
+
interface RunStepRow {
|
|
31
|
+
ID: string;
|
|
32
|
+
StepType: string;
|
|
33
|
+
TargetLogID: string | null;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** A row of either lookup; the run lookup returns only `ID`. */
|
|
37
|
+
type LookupRow = Partial<RunStepRow> & { ID: string };
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Keeps the run ids from a session's `Config` that are records of that session.
|
|
41
|
+
*
|
|
42
|
+
* The session owner can edit `Config`, so its run ids are claims. A run id is kept when it is the
|
|
43
|
+
* UUID of an `MJ: AI Agent Runs` row whose `AgentSessionID` is the session. The step id and the
|
|
44
|
+
* prompt run id are kept when they belong to that co-agent run: the step's `AgentRunID` is the
|
|
45
|
+
* co-agent run, and the prompt run is the `TargetLogID` of one of its `Prompt` steps.
|
|
46
|
+
*
|
|
47
|
+
* The lookups run as the system user when one is cached, else as the acting user. They are pinned
|
|
48
|
+
* to the session's id and return nothing to the caller, and row-level security can hide a session's
|
|
49
|
+
* own runs from its owner (a web-widget guest's delegated runs carry no `ConversationID`, which the
|
|
50
|
+
* guest's run filter keys on).
|
|
51
|
+
*
|
|
52
|
+
* Each call reads the database again (`BypassCache`) and keeps no result, because the links can
|
|
53
|
+
* change after a lookup: a run's `AgentSessionID` and a step's `AgentRunID` and `TargetLogID` are
|
|
54
|
+
* updatable.
|
|
55
|
+
*/
|
|
56
|
+
export class SessionRunIDVerifier {
|
|
57
|
+
/**
|
|
58
|
+
* Returns the subset of `claimed` that belongs to the session now. Never throws: when a lookup
|
|
59
|
+
* fails, nothing is kept.
|
|
60
|
+
*
|
|
61
|
+
* @param sessionID The `MJ: AI Agent Sessions` id the claims were read from. The caller must have
|
|
62
|
+
* checked that the session is the caller's own.
|
|
63
|
+
* @param claimed The run ids read from the session's `Config`.
|
|
64
|
+
* @param contextUser The acting user; the lookups run as it only when no system user is cached.
|
|
65
|
+
* @param provider The request-scoped metadata provider.
|
|
66
|
+
* @returns The claims that are records of the session.
|
|
67
|
+
*/
|
|
68
|
+
public async Verify(
|
|
69
|
+
sessionID: string,
|
|
70
|
+
claimed: SessionRunIDs,
|
|
71
|
+
contextUser: UserInfo,
|
|
72
|
+
provider: IMetadataProvider,
|
|
73
|
+
): Promise<SessionRunIDs> {
|
|
74
|
+
const candidates = this.keepUUIDs(claimed);
|
|
75
|
+
if (!candidates.CoAgentRunID && !candidates.PendingFeedbackRunID) {
|
|
76
|
+
return {};
|
|
77
|
+
}
|
|
78
|
+
return (await this.lookUpOwned(sessionID.trim(), candidates, contextUser, provider)) ?? {};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** Drops every claim that is not a UUID. The prompt run and step need a co-agent run to hang off. */
|
|
82
|
+
private keepUUIDs(claimed: SessionRunIDs): SessionRunIDs {
|
|
83
|
+
const coAgentRunID = this.uuidOrUndefined(claimed.CoAgentRunID);
|
|
84
|
+
return {
|
|
85
|
+
CoAgentRunID: coAgentRunID,
|
|
86
|
+
PromptRunID: coAgentRunID ? this.uuidOrUndefined(claimed.PromptRunID) : undefined,
|
|
87
|
+
CoAgentRunStepID: coAgentRunID ? this.uuidOrUndefined(claimed.CoAgentRunStepID) : undefined,
|
|
88
|
+
PendingFeedbackRunID: this.uuidOrUndefined(claimed.PendingFeedbackRunID),
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
private uuidOrUndefined(value: string | undefined): string | undefined {
|
|
93
|
+
return value && IsValidUUID(value) ? value.trim() : undefined;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** Runs the lookups; `null` when one of them fails. */
|
|
97
|
+
private async lookUpOwned(
|
|
98
|
+
sessionID: string,
|
|
99
|
+
candidates: SessionRunIDs,
|
|
100
|
+
contextUser: UserInfo,
|
|
101
|
+
provider: IMetadataProvider,
|
|
102
|
+
): Promise<SessionRunIDs | null> {
|
|
103
|
+
const stepsQuery = this.stepsQuery(candidates);
|
|
104
|
+
const queries = stepsQuery ? [this.runsQuery(sessionID, candidates), stepsQuery] : [this.runsQuery(sessionID, candidates)];
|
|
105
|
+
try {
|
|
106
|
+
const lookupUser = UserCache.Instance.GetSystemUser() ?? contextUser;
|
|
107
|
+
const [runs, steps] = await RunView.FromMetadataProvider(provider).RunViews<LookupRow>(queries, lookupUser);
|
|
108
|
+
const failed = [runs, steps].find((result) => result && !result.Success);
|
|
109
|
+
if (!runs || failed) {
|
|
110
|
+
LogError(`SessionRunIDVerifier: run lookup failed for session ${sessionID}: ${failed?.ErrorMessage ?? 'no result'}`);
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
return this.pickOwned(candidates, runs.Results, steps?.Results ?? []);
|
|
114
|
+
} catch (error) {
|
|
115
|
+
LogError(`SessionRunIDVerifier: run lookup failed for session ${sessionID}: ${error instanceof Error ? error.message : String(error)}`);
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/** The claimed runs that carry this session's id. */
|
|
121
|
+
private runsQuery(sessionID: string, candidates: SessionRunIDs): RunViewParams {
|
|
122
|
+
const ids = [candidates.CoAgentRunID, candidates.PendingFeedbackRunID]
|
|
123
|
+
.filter((id): id is string => !!id)
|
|
124
|
+
.map((id) => `'${EscapeSQLString(id)}'`);
|
|
125
|
+
return {
|
|
126
|
+
EntityName: AGENT_RUN_ENTITY,
|
|
127
|
+
ExtraFilter: `AgentSessionID='${EscapeSQLString(sessionID)}' AND ID IN (${ids.join(', ')})`,
|
|
128
|
+
Fields: ['ID'],
|
|
129
|
+
ResultType: 'simple',
|
|
130
|
+
BypassCache: true,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/** The claimed co-agent run's steps that match the claimed step or prompt run; `null` when neither is claimed. */
|
|
135
|
+
private stepsQuery(candidates: SessionRunIDs): RunViewParams | null {
|
|
136
|
+
const matches: string[] = [];
|
|
137
|
+
if (candidates.CoAgentRunStepID) {
|
|
138
|
+
matches.push(`ID='${EscapeSQLString(candidates.CoAgentRunStepID)}'`);
|
|
139
|
+
}
|
|
140
|
+
if (candidates.PromptRunID) {
|
|
141
|
+
matches.push(`TargetLogID='${EscapeSQLString(candidates.PromptRunID)}'`);
|
|
142
|
+
}
|
|
143
|
+
if (!candidates.CoAgentRunID || matches.length === 0) {
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
return {
|
|
147
|
+
EntityName: AGENT_RUN_STEP_ENTITY,
|
|
148
|
+
ExtraFilter: `AgentRunID='${EscapeSQLString(candidates.CoAgentRunID)}' AND (${matches.join(' OR ')})`,
|
|
149
|
+
Fields: ['ID', 'StepType', 'TargetLogID'],
|
|
150
|
+
ResultType: 'simple',
|
|
151
|
+
BypassCache: true,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
private pickOwned(candidates: SessionRunIDs, runs: LookupRow[], steps: LookupRow[]): SessionRunIDs {
|
|
156
|
+
const isOwnedRun = (id: string | undefined): boolean => !!id && runs.some((row) => UUIDsEqual(row.ID, id));
|
|
157
|
+
const coAgentRunID = isOwnedRun(candidates.CoAgentRunID) ? candidates.CoAgentRunID : undefined;
|
|
158
|
+
const ownedSteps = coAgentRunID ? steps : [];
|
|
159
|
+
const stepID = candidates.CoAgentRunStepID;
|
|
160
|
+
const promptRunID = candidates.PromptRunID;
|
|
161
|
+
return {
|
|
162
|
+
CoAgentRunID: coAgentRunID,
|
|
163
|
+
CoAgentRunStepID: stepID && ownedSteps.some((row) => UUIDsEqual(row.ID, stepID)) ? stepID : undefined,
|
|
164
|
+
PromptRunID:
|
|
165
|
+
promptRunID && ownedSteps.some((row) => row.StepType === 'Prompt' && UUIDsEqual(row.TargetLogID, promptRunID))
|
|
166
|
+
? promptRunID
|
|
167
|
+
: undefined,
|
|
168
|
+
PendingFeedbackRunID: isOwnedRun(candidates.PendingFeedbackRunID) ? candidates.PendingFeedbackRunID : undefined,
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
}
|
|
@@ -2,12 +2,14 @@
|
|
|
2
2
|
* @fileoverview AI Agent Session lifecycle substrate (server-side, record + janitor layer).
|
|
3
3
|
*
|
|
4
4
|
* Exposes the session-record lifecycle manager, the orphan-reconciliation janitor, and the
|
|
5
|
-
*
|
|
6
|
-
* realtime
|
|
5
|
+
* host-instance identity (`hostname:port:pid:bootId`) the janitor matches sessions by, which the
|
|
6
|
+
* realtime bridge engine is given for its bridge rows too (`BindBridgeEngineHostInstance`). The
|
|
7
|
+
* audio/media (WebRTC) transport and the long-lived realtime agent run are deliberately **not**
|
|
8
|
+
* part of this layer — they arrive in P5.
|
|
7
9
|
*
|
|
8
10
|
* @module @memberjunction/server
|
|
9
11
|
*/
|
|
10
|
-
import { LoadWhiteboardChannelServer, LoadMeetingControlsChannelServer, LoadMediaChannelServer, LoadClientContextChannelServer } from '@memberjunction/ai-agents';
|
|
12
|
+
import { LoadWhiteboardChannelServer, LoadMeetingControlsChannelServer, LoadMediaChannelServer, LoadClientContextChannelServer, LoadClientOnlyChannelServer, LoadIdentityVerificationChannelServer, LoadInteractiveComponentChannelServer } from '@memberjunction/ai-agents';
|
|
11
13
|
import { LoadRemoteBrowserChannel } from '@memberjunction/remote-browser-server';
|
|
12
14
|
import { LoadSelfHostRemoteBrowser } from '@memberjunction/remote-browser-selfhost';
|
|
13
15
|
import { BindRemoteBrowserGoalEngine } from './remoteBrowserGoalEngine.js';
|
|
@@ -19,6 +21,9 @@ LoadWhiteboardChannelServer();
|
|
|
19
21
|
LoadMeetingControlsChannelServer();
|
|
20
22
|
LoadMediaChannelServer();
|
|
21
23
|
LoadClientContextChannelServer();
|
|
24
|
+
LoadClientOnlyChannelServer();
|
|
25
|
+
LoadIdentityVerificationChannelServer();
|
|
26
|
+
LoadInteractiveComponentChannelServer();
|
|
22
27
|
// Remote Browser native channel (client-direct): the lifecycle-only server channel plugin + the
|
|
23
28
|
// Self-Hosted Chrome backend driver (whose default runner launches a local headless Chromium via
|
|
24
29
|
// Playwright — pulled in transitively through the SelfHost package, documented and acceptable).
|
|
@@ -30,5 +35,7 @@ BindRemoteBrowserGoalEngine();
|
|
|
30
35
|
|
|
31
36
|
export * from './remoteBrowserGoalEngine.js';
|
|
32
37
|
export * from './HostInstance.js';
|
|
38
|
+
export * from './BridgeHostInstance.js';
|
|
33
39
|
export * from './SessionManager.js';
|
|
34
40
|
export * from './SessionJanitor.js';
|
|
41
|
+
export * from './SessionRunIDVerifier.js';
|
package/src/apiRoot.ts
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MJAPI's base path: the single prefix every route MJAPI serves is mounted under (MJ #5674).
|
|
3
|
+
*
|
|
4
|
+
* MJAPI does not know where a proxy exposes it. Behind a proxy that forwards a prefix WITHOUT stripping it
|
|
5
|
+
* (CloudFront `/api/*` → MJAPI), MJAPI must listen under that prefix, so the host sets
|
|
6
|
+
* `MJAPI_BASE_PATH=/api`. Behind a stripping proxy, or with no proxy, it stays `/`. Every mount and every
|
|
7
|
+
* URL handed to a browser, an email or a webhook provider goes through {@link ApiRoute}, so one setting moves
|
|
8
|
+
* them all. CI enforces this (`check:api-root` and `__tests__/apiRootBoot.test.ts`).
|
|
9
|
+
*
|
|
10
|
+
* `GRAPHQL_ROOT_PATH` is a separate thing: only where Apollo listens. Do not derive routes from it.
|
|
11
|
+
*
|
|
12
|
+
* At the default base path `/` every value here is byte-identical to the root-mounted paths MJAPI always used.
|
|
13
|
+
*/
|
|
14
|
+
import { TrimTrailingSlashes } from '@memberjunction/global';
|
|
15
|
+
import { configInfo } from './config.js';
|
|
16
|
+
|
|
17
|
+
/** Options for {@link ApiRoute}. */
|
|
18
|
+
export interface ApiRouteOptions {
|
|
19
|
+
/** Return the public absolute URL (`MJAPI_PUBLIC_URL` + subpath) instead of the server mount path. */
|
|
20
|
+
absolute?: boolean; // case-violation-ok-legacy-back-compat: the `{ absolute: true }` option shape is the documented #5674 contract
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Normalizes a base-path value to a prefix with no trailing slash: `''` for `/`, `'/api'` for `/api/` or
|
|
25
|
+
* `/api`. Throws on a value that does not start with `/`, since Express would mount it nowhere.
|
|
26
|
+
*/
|
|
27
|
+
export function NormalizeApiRootPath(rootPath: string | undefined): string {
|
|
28
|
+
const trimmed = (rootPath ?? '').trim();
|
|
29
|
+
if (trimmed && !trimmed.startsWith('/')) {
|
|
30
|
+
throw new Error(`MJAPI_BASE_PATH must start with '/', got '${trimmed}'`);
|
|
31
|
+
}
|
|
32
|
+
return TrimTrailingSlashes(trimmed);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function assertSubpath(subpath: string): void {
|
|
36
|
+
if (typeof subpath !== 'string' || !subpath.startsWith('/')) {
|
|
37
|
+
throw new Error(`ApiRoute subpath must start with '/', got '${String(subpath)}'`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Joins a base path and a subpath relative to it. Pure, so tests can drive any base path. */
|
|
42
|
+
export function JoinApiRoute(apiRootPath: string, subpath: string): string {
|
|
43
|
+
assertSubpath(subpath);
|
|
44
|
+
return `${NormalizeApiRootPath(apiRootPath)}${subpath}`;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** The running server's base path (`MJAPI_BASE_PATH`, no trailing slash; `''` at `/`). */
|
|
48
|
+
export function ApiRootPath(): string {
|
|
49
|
+
return NormalizeApiRootPath(configInfo.apiBasePath);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* The server's configured public URL, derived exactly as it always has been: `MJAPI_PUBLIC_URL`, else
|
|
54
|
+
* `baseUrl:graphqlPort` + `graphqlRootPath`. Unchanged and untrimmed on purpose: it is the magic-link JWT
|
|
55
|
+
* issuer and the `publicUrl` handed to OAuth and server extensions, and changing it would invalidate issued
|
|
56
|
+
* tokens. Build URLs with `ApiRoute(subpath, { absolute: true })`, not from this.
|
|
57
|
+
*/
|
|
58
|
+
export function ConfiguredPublicUrl(): string {
|
|
59
|
+
return configInfo.publicUrl || `${configInfo.baseUrl}:${configInfo.graphqlPort}${configInfo.graphqlRootPath || ''}`;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* The path (or, with `{ absolute: true }`, the public URL) of a route under MJAPI's base path.
|
|
64
|
+
*
|
|
65
|
+
* `subpath` is relative to the base path and must start with `/`.
|
|
66
|
+
* - `ApiRoute('/media')` → `/media` at base `/`, `/api/media` at `MJAPI_BASE_PATH=/api`.
|
|
67
|
+
* - `ApiRoute('/media/abc', { absolute: true })` → `${MJAPI_PUBLIC_URL}/media/abc`. `MJAPI_PUBLIC_URL` is
|
|
68
|
+
* wherever the world reaches MJAPI (prefix included), so the base path is never added to it. Without it,
|
|
69
|
+
* the local fallback is `baseUrl:graphqlPort` + the base path.
|
|
70
|
+
*/
|
|
71
|
+
export function ApiRoute(subpath: string, options?: ApiRouteOptions): string {
|
|
72
|
+
if (!options?.absolute) {
|
|
73
|
+
return JoinApiRoute(ApiRootPath(), subpath);
|
|
74
|
+
}
|
|
75
|
+
assertSubpath(subpath);
|
|
76
|
+
const base = configInfo.publicUrl || `${configInfo.baseUrl}:${configInfo.graphqlPort}${ApiRootPath()}`;
|
|
77
|
+
return `${TrimTrailingSlashes(base)}${subpath}`;
|
|
78
|
+
}
|
|
@@ -12,6 +12,7 @@ import { Router, type Request, type Response } from 'express';
|
|
|
12
12
|
import { rateLimit } from 'express-rate-limit';
|
|
13
13
|
import { LogError, type PublicAuthProviderCatalog } from '@memberjunction/core';
|
|
14
14
|
import { AuthProviderEngine } from './AuthProviderEngine.js';
|
|
15
|
+
import { EMPTY_PUBLIC_LOGIN_SCREEN, LoginScreenEngine } from './LoginScreenEngine.js';
|
|
15
16
|
|
|
16
17
|
/** Mount path for the public catalog router. */
|
|
17
18
|
export const AUTH_CATALOG_MOUNT_PATH = '/auth';
|
|
@@ -72,6 +73,31 @@ export function CreateAuthProviderCatalogRouter(): Router {
|
|
|
72
73
|
}
|
|
73
74
|
});
|
|
74
75
|
|
|
76
|
+
/**
|
|
77
|
+
* `GET /auth/login-screen`: the default theme's PUBLISHED sign-in page, logos and seeds, for the login
|
|
78
|
+
* screen to draw before anyone signs in. Its own rate-limit budget (a 429 must answer in this route's
|
|
79
|
+
* shape), the catalog's cache window, and the same failure rule: empty, never an error.
|
|
80
|
+
*/
|
|
81
|
+
const loginScreenLimiter = rateLimit({
|
|
82
|
+
windowMs: DEFAULT_RATE_LIMIT_WINDOW_MS,
|
|
83
|
+
limit: DEFAULT_RATE_LIMIT_MAX,
|
|
84
|
+
standardHeaders: 'draft-7',
|
|
85
|
+
legacyHeaders: false,
|
|
86
|
+
message: EMPTY_PUBLIC_LOGIN_SCREEN
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
router.get('/login-screen', loginScreenLimiter, (_req: Request, res: Response) => {
|
|
90
|
+
try {
|
|
91
|
+
const body = LoginScreenEngine.Instance.GetPublicLoginScreen();
|
|
92
|
+
res.set('Cache-Control', `public, max-age=${CACHE_MAX_AGE_SECONDS}`);
|
|
93
|
+
res.status(200).json(body);
|
|
94
|
+
} catch (error) {
|
|
95
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
96
|
+
LogError(`[Auth] Failed to serve the public login screen: ${message}`);
|
|
97
|
+
res.status(200).json(EMPTY_PUBLIC_LOGIN_SCREEN);
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
|
|
75
101
|
return router;
|
|
76
102
|
}
|
|
77
103
|
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Caches the default theme for the public login-screen route.
|
|
3
|
+
*
|
|
4
|
+
* @module @memberjunction/server/auth
|
|
5
|
+
*/
|
|
6
|
+
import { BaseEngine, BaseEnginePropertyConfig, RegisterForStartup, UserInfo, type IMetadataProvider } from '@memberjunction/core';
|
|
7
|
+
import { MJThemeEntity } from '@memberjunction/core-entities';
|
|
8
|
+
import { PublicLoginScreenFromTheme, type PublicLoginScreen } from '@memberjunction/theme-engine';
|
|
9
|
+
|
|
10
|
+
/** What the route serves when there is no default theme, or it cannot be read. */
|
|
11
|
+
export const EMPTY_PUBLIC_LOGIN_SCREEN: Readonly<PublicLoginScreen> = { ThemeName: null, Design: null, Seeds: null, Logos: {} };
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Holds the default Active theme, so `GET /auth/login-screen` answers every anonymous page load from
|
|
15
|
+
* memory. Saving a theme refreshes it, so a publish in Login Studio reaches the login screen without a
|
|
16
|
+
* restart. Severity `warn`: a failed load must not stop the server; the route then serves the stock page.
|
|
17
|
+
*/
|
|
18
|
+
@RegisterForStartup({
|
|
19
|
+
priority: 20,
|
|
20
|
+
severity: 'warn',
|
|
21
|
+
deferred: false,
|
|
22
|
+
description: 'Caches the default theme that GET /auth/login-screen serves to the login screen'
|
|
23
|
+
})
|
|
24
|
+
export class LoginScreenEngine extends BaseEngine<LoginScreenEngine> {
|
|
25
|
+
private _defaultThemes: MJThemeEntity[] = [];
|
|
26
|
+
|
|
27
|
+
public static get Instance(): LoginScreenEngine {
|
|
28
|
+
return super.getInstance<LoginScreenEngine>();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
public async Config(forceRefresh?: boolean, contextUser?: UserInfo, provider?: IMetadataProvider): Promise<void> {
|
|
32
|
+
const configs: Partial<BaseEnginePropertyConfig>[] = [
|
|
33
|
+
{
|
|
34
|
+
PropertyName: '_defaultThemes',
|
|
35
|
+
EntityName: 'MJ: Themes',
|
|
36
|
+
// One default is enforced by the app, not the schema; the most recently changed one wins (as in Login Studio).
|
|
37
|
+
Filter: `IsDefault = 1 AND Status = 'Active'`,
|
|
38
|
+
OrderBy: '__mj_UpdatedAt DESC',
|
|
39
|
+
CacheLocal: true
|
|
40
|
+
}
|
|
41
|
+
];
|
|
42
|
+
await this.Load(configs, provider, forceRefresh, contextUser);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** The default theme's public projection: its PUBLISHED design (never the draft), seeds and logos made safe. */
|
|
46
|
+
public GetPublicLoginScreen(): PublicLoginScreen {
|
|
47
|
+
const theme = this.GetConfigData<MJThemeEntity>('_defaultThemes')[0];
|
|
48
|
+
return theme ? PublicLoginScreenFromTheme(theme) : EMPTY_PUBLIC_LOGIN_SCREEN;
|
|
49
|
+
}
|
|
50
|
+
}
|