@memberjunction/server 6.2.0-edge.2 → 6.2.0-edge.4
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 +30 -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 +173 -25
- package/dist/agentSessions/SessionJanitor.d.ts.map +1 -1
- package/dist/agentSessions/SessionJanitor.js +452 -54
- package/dist/agentSessions/SessionJanitor.js.map +1 -1
- package/dist/agentSessions/SessionManager.d.ts +43 -2
- package/dist/agentSessions/SessionManager.d.ts.map +1 -1
- package/dist/agentSessions/SessionManager.js +99 -8
- 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/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.map +1 -1
- package/dist/auth/index.js +3 -10
- package/dist/auth/index.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 +4567 -71
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +246 -3
- 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 +25 -34
- package/dist/context.js.map +1 -1
- package/dist/generated/graphql-schemas/__mj.d.ts +1073 -10
- package/dist/generated/graphql-schemas/__mj.d.ts.map +1 -1
- package/dist/generated/graphql-schemas/__mj.js +9188 -3649
- package/dist/generated/graphql-schemas/__mj.js.map +1 -1
- package/dist/generic/OrphanedConversationDetailReconciler.js +3 -3
- package/dist/generic/OrphanedConversationDetailReconciler.js.map +1 -1
- package/dist/generic/ResolverBase.d.ts +62 -6
- package/dist/generic/ResolverBase.d.ts.map +1 -1
- package/dist/generic/ResolverBase.js +179 -35
- 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 +37 -1
- package/dist/generic/RunViewResolver.js.map +1 -1
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +214 -159
- 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/postgresqlCompat.d.ts +8 -0
- package/dist/postgresqlCompat.d.ts.map +1 -0
- package/dist/postgresqlCompat.js +19 -0
- package/dist/postgresqlCompat.js.map +1 -0
- package/dist/postgresqlPoolSettings.d.ts +108 -0
- package/dist/postgresqlPoolSettings.d.ts.map +1 -0
- package/dist/postgresqlPoolSettings.js +134 -0
- package/dist/postgresqlPoolSettings.js.map +1 -0
- 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 +138 -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 +98 -0
- package/dist/realtimeSessions/RealtimeVerifyRouter.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 +17 -0
- package/dist/realtimeSessions/index.d.ts.map +1 -0
- package/dist/realtimeSessions/index.js +17 -0
- package/dist/realtimeSessions/index.js.map +1 -0
- package/dist/realtimeSessions/sessionAccess.d.ts +86 -0
- package/dist/realtimeSessions/sessionAccess.d.ts.map +1 -0
- package/dist/realtimeSessions/sessionAccess.js +90 -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 +35 -17
- package/dist/resolvers/AdhocQueryResolver.d.ts.map +1 -1
- package/dist/resolvers/AdhocQueryResolver.js +92 -166
- package/dist/resolvers/AdhocQueryResolver.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/EntityRecordNameResolver.d.ts +7 -23
- package/dist/resolvers/EntityRecordNameResolver.d.ts.map +1 -1
- package/dist/resolvers/EntityRecordNameResolver.js +9 -47
- package/dist/resolvers/EntityRecordNameResolver.js.map +1 -1
- package/dist/resolvers/FetchEntityVectorsResolver.d.ts +12 -1
- package/dist/resolvers/FetchEntityVectorsResolver.d.ts.map +1 -1
- package/dist/resolvers/FetchEntityVectorsResolver.js +83 -2
- package/dist/resolvers/FetchEntityVectorsResolver.js.map +1 -1
- package/dist/resolvers/GetDataResolver.d.ts.map +1 -1
- package/dist/resolvers/GetDataResolver.js +9 -0
- package/dist/resolvers/GetDataResolver.js.map +1 -1
- package/dist/resolvers/HumanHandoffResolver.d.ts +107 -0
- package/dist/resolvers/HumanHandoffResolver.d.ts.map +1 -0
- package/dist/resolvers/HumanHandoffResolver.js +330 -0
- package/dist/resolvers/HumanHandoffResolver.js.map +1 -0
- 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/MeetingResolver.d.ts +69 -0
- package/dist/resolvers/MeetingResolver.d.ts.map +1 -0
- package/dist/resolvers/MeetingResolver.js +381 -0
- package/dist/resolvers/MeetingResolver.js.map +1 -0
- package/dist/resolvers/RealtimeBridgeResolver.d.ts +88 -3
- package/dist/resolvers/RealtimeBridgeResolver.d.ts.map +1 -1
- package/dist/resolvers/RealtimeBridgeResolver.js +352 -12
- package/dist/resolvers/RealtimeBridgeResolver.js.map +1 -1
- package/dist/resolvers/RealtimeClientSessionResolver.d.ts +156 -108
- package/dist/resolvers/RealtimeClientSessionResolver.d.ts.map +1 -1
- package/dist/resolvers/RealtimeClientSessionResolver.js +395 -293
- 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 +68 -11
- 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/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/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/adhocTimeout.d.ts +7 -0
- package/dist/resolvers/adhocTimeout.d.ts.map +1 -0
- package/dist/resolvers/adhocTimeout.js +12 -0
- package/dist/resolvers/adhocTimeout.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/index.d.ts +5 -0
- package/dist/resolvers/meetings/index.d.ts.map +1 -0
- package/dist/resolvers/meetings/index.js +5 -0
- package/dist/resolvers/meetings/index.js.map +1 -0
- package/dist/resolvers/meetings/meetingHelpers.d.ts +17 -0
- package/dist/resolvers/meetings/meetingHelpers.d.ts.map +1 -0
- package/dist/resolvers/meetings/meetingHelpers.js +212 -0
- package/dist/resolvers/meetings/meetingHelpers.js.map +1 -0
- package/dist/resolvers/meetings/meetingMutations.d.ts +18 -0
- package/dist/resolvers/meetings/meetingMutations.d.ts.map +1 -0
- package/dist/resolvers/meetings/meetingMutations.js +439 -0
- package/dist/resolvers/meetings/meetingMutations.js.map +1 -0
- package/dist/resolvers/meetings/meetingQueries.d.ts +7 -0
- package/dist/resolvers/meetings/meetingQueries.d.ts.map +1 -0
- package/dist/resolvers/meetings/meetingQueries.js +113 -0
- package/dist/resolvers/meetings/meetingQueries.js.map +1 -0
- package/dist/resolvers/meetings/meetingTypes.d.ts +89 -0
- package/dist/resolvers/meetings/meetingTypes.d.ts.map +1 -0
- package/dist/resolvers/meetings/meetingTypes.js +345 -0
- package/dist/resolvers/meetings/meetingTypes.js.map +1 -0
- package/dist/rest/ViewOperationsHandler.d.ts.map +1 -1
- package/dist/rest/ViewOperationsHandler.js +8 -5
- package/dist/rest/ViewOperationsHandler.js.map +1 -1
- package/dist/services/TaskGraphActionRunner.d.ts +8 -0
- package/dist/services/TaskGraphActionRunner.d.ts.map +1 -1
- package/dist/services/TaskGraphActionRunner.js +27 -1
- package/dist/services/TaskGraphActionRunner.js.map +1 -1
- package/dist/services/TaskGraphContinuationDeliverer.d.ts +4 -3
- package/dist/services/TaskGraphContinuationDeliverer.d.ts.map +1 -1
- package/dist/services/TaskGraphContinuationDeliverer.js +13 -7
- package/dist/services/TaskGraphContinuationDeliverer.js.map +1 -1
- package/dist/services/WorkQueueHostService.d.ts +36 -0
- package/dist/services/WorkQueueHostService.d.ts.map +1 -0
- package/dist/services/WorkQueueHostService.js +97 -0
- package/dist/services/WorkQueueHostService.js.map +1 -0
- package/dist/services/workQueueConfig.d.ts +103 -0
- package/dist/services/workQueueConfig.d.ts.map +1 -0
- package/dist/services/workQueueConfig.js +48 -0
- package/dist/services/workQueueConfig.js.map +1 -0
- package/dist/sharedCache.d.ts +105 -0
- package/dist/sharedCache.d.ts.map +1 -0
- package/dist/sharedCache.js +276 -0
- package/dist/sharedCache.js.map +1 -0
- package/dist/types.d.ts +11 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +97 -94
- package/src/__tests__/ActionResolver.authorization.test.ts +353 -0
- package/src/__tests__/AdhocQueryResolver.bugs.test.ts +14 -35
- package/src/__tests__/AdhocQueryResolver.pagination.test.ts +6 -2
- package/src/__tests__/AdhocQueryResolver.scopeGuard.test.ts +3 -3
- 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__/EntityRecordNameResolver.fieldSecurity.test.ts +27 -72
- package/src/__tests__/FetchEntityVectorsResolver.test.ts +285 -0
- package/src/__tests__/HostInstance.test.ts +84 -0
- package/src/__tests__/HumanHandoffResolver.test.ts +250 -0
- package/src/__tests__/MeetingResolver.test.ts +448 -0
- package/src/__tests__/RealtimeBridgeResolver.test.ts +651 -4
- 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__/RemoteBrowserActionResolver.goalRunLink.test.ts +129 -0
- package/src/__tests__/ResolverBase.adhocReadScope.test.ts +96 -0
- package/src/__tests__/ResolverBase.aggregateScreen.test.ts +174 -0
- package/src/__tests__/ResolverBase.clientOldValues.test.ts +6 -3
- package/src/__tests__/ResolverBase.filterEscaping.test.ts +21 -2
- package/src/__tests__/ResolverBase.includeBinaryFields.test.ts +291 -0
- package/src/__tests__/ReturningVisitorRecap.test.ts +115 -0
- package/src/__tests__/RunAIAgentResolver.branch.test.ts +169 -0
- package/src/__tests__/RunAIAgentResolver.historyFrom.test.ts +4 -4
- 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__/SessionJanitor.test.ts +845 -18
- package/src/__tests__/SessionManager.test.ts +213 -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 +41 -0
- package/src/__tests__/TaskGraphContinuationDeliverer.test.ts +50 -3
- package/src/__tests__/UserAvatarResolver.test.ts +255 -0
- package/src/__tests__/UserResolver.currentUser.test.ts +16 -1
- package/src/__tests__/WorkQueueHostService.test.ts +133 -0
- package/src/__tests__/actionAuthorization.test.ts +130 -0
- package/src/__tests__/adhocTimeoutClamp.test.ts +26 -0
- package/src/__tests__/agentVisionConsentAudit.test.ts +118 -0
- package/src/__tests__/avatarInputValidation.test.ts +160 -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__/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__/postgresqlPoolSettings.test.ts +131 -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__/serverExtensionReservedRoots.test.ts +2 -0
- package/src/__tests__/sharedCache.test.ts +310 -0
- package/src/__tests__/translateBracketsToPG.test.ts +20 -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 +543 -57
- package/src/agentSessions/SessionManager.ts +125 -25
- package/src/agentSessions/SessionRunIDVerifier.ts +171 -0
- package/src/agentSessions/index.ts +10 -3
- package/src/auth/actionAuthorization.ts +116 -0
- package/src/auth/index.ts +3 -8
- package/src/auth/magicLink/MagicLinkService.ts +6 -3
- package/src/auth/newUsers.ts +99 -11
- package/src/config.ts +255 -3
- package/src/context.ts +26 -34
- package/src/generated/graphql-schemas/__mj.ts +22701 -18838
- package/src/generic/OrphanedConversationDetailReconciler.ts +3 -3
- package/src/generic/ResolverBase.ts +210 -36
- package/src/generic/RunViewResolver.ts +37 -2
- package/src/index.ts +236 -170
- package/src/isolatedProvider.ts +22 -0
- package/src/postgresqlCompat.ts +21 -0
- package/src/postgresqlPoolSettings.ts +213 -0
- 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 +167 -0
- package/src/realtimeSessions/RealtimeVerifyRouter.ts +108 -0
- package/src/realtimeSessions/SessionVerificationPortsBase.ts +189 -0
- package/src/realtimeSessions/SlidingWindowRateLimiter.ts +92 -0
- package/src/realtimeSessions/index.ts +16 -0
- package/src/realtimeSessions/sessionAccess.ts +141 -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 +105 -187
- package/src/resolvers/CacheStatsResolver.ts +89 -2
- package/src/resolvers/ClientToolRequestResolver.ts +25 -7
- package/src/resolvers/EntityRecordNameResolver.ts +9 -51
- package/src/resolvers/FetchEntityVectorsResolver.ts +97 -2
- package/src/resolvers/GetDataResolver.ts +10 -0
- package/src/resolvers/HumanHandoffResolver.ts +312 -0
- package/src/resolvers/MCPResolver.ts +8 -5
- package/src/resolvers/MeetingResolver.ts +438 -0
- package/src/resolvers/RealtimeBridgeResolver.ts +385 -19
- package/src/resolvers/RealtimeClientSessionResolver.ts +503 -344
- 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 +78 -11
- package/src/resolvers/RunTemplateResolver.ts +13 -12
- package/src/resolvers/SyncDataResolver.ts +6 -2
- package/src/resolvers/SyncRolesUsersResolver.ts +24 -6
- package/src/resolvers/UserAvatarResolver.ts +111 -0
- package/src/resolvers/UserResolver.ts +2 -16
- package/src/resolvers/adhocTimeout.ts +12 -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/index.ts +4 -0
- package/src/resolvers/meetings/meetingHelpers.ts +307 -0
- package/src/resolvers/meetings/meetingMutations.ts +556 -0
- package/src/resolvers/meetings/meetingQueries.ts +172 -0
- package/src/resolvers/meetings/meetingTypes.ts +238 -0
- package/src/rest/ViewOperationsHandler.ts +8 -5
- package/src/services/TaskGraphActionRunner.ts +29 -1
- package/src/services/TaskGraphContinuationDeliverer.ts +13 -7
- package/src/services/WorkQueueHostService.ts +129 -0
- package/src/services/workQueueConfig.ts +52 -0
- package/src/sharedCache.ts +302 -0
- package/src/types.ts +12 -0
- package/dist/resolvers/adhoc-query-helpers.d.ts +0 -33
- package/dist/resolvers/adhoc-query-helpers.d.ts.map +0 -1
- package/dist/resolvers/adhoc-query-helpers.js +0 -50
- package/dist/resolvers/adhoc-query-helpers.js.map +0 -1
- package/src/__tests__/adhoc-query-helpers.test.ts +0 -50
- package/src/resolvers/adhoc-query-helpers.ts +0 -67
|
@@ -1,15 +1,30 @@
|
|
|
1
1
|
import { Resolver, Mutation, Query, Arg, Ctx, ObjectType, InputType, Field } from 'type-graphql';
|
|
2
2
|
import { randomUUID } from 'crypto';
|
|
3
|
-
import { LogError, LogStatusEx, UserInfo, IMetadataProvider } from '@memberjunction/core';
|
|
4
|
-
import {
|
|
3
|
+
import { LogError, LogStatusEx, UserInfo, IMetadataProvider, RunView } from '@memberjunction/core';
|
|
4
|
+
import { EscapeSQLString } from '@memberjunction/global';
|
|
5
|
+
import type { TurnAddressingMode } from '@memberjunction/ai-bridge-base';
|
|
6
|
+
import {
|
|
7
|
+
LiveKitTokenService,
|
|
8
|
+
LiveKitAgentRoomCoordinator,
|
|
9
|
+
LiveKitEgressService,
|
|
10
|
+
LiveKitParticipantService,
|
|
11
|
+
LiveKitUserIdentity,
|
|
12
|
+
RoomHandoffEngine,
|
|
13
|
+
type AgentRoomHostOptions,
|
|
14
|
+
type AgentRoomSession,
|
|
15
|
+
type ParticipantUpdateResult,
|
|
16
|
+
type StartAgentRoomSessionParams,
|
|
17
|
+
} from '@memberjunction/livekit-room-server';
|
|
5
18
|
import { AppContext } from '../types.js';
|
|
6
19
|
import { ResolverBase } from '../generic/ResolverBase.js';
|
|
7
20
|
import { GetReadWriteProvider } from '../util.js';
|
|
8
|
-
import { CreateBridgeRealtimeSession, FinalizeBridgeCoAgentRuns, GetRealtimeModelVoices, CreateBridgeRoomTranscriptSink, RealtimeTurnModeratorDecision } from '@memberjunction/ai-agents';
|
|
21
|
+
import { CreateBridgeRealtimeSession, FinalizeBridgeCoAgentRuns, GetRealtimeModelVoices, CreateBridgeRoomTranscriptSink, RealtimeTurnModeratorDecision, GetBridgeRealtimeRuntime } from '@memberjunction/ai-agents';
|
|
9
22
|
import { AIBridgeEngine } from '@memberjunction/ai-bridge-server';
|
|
10
23
|
import { SessionManager } from '../agentSessions/SessionManager.js';
|
|
11
24
|
import { NotificationEngine } from '@memberjunction/notifications';
|
|
12
25
|
import { RegisterMeetingRecordingFile, CorrelateRecordingStart } from './meetingRecordingRegistration.js';
|
|
26
|
+
import { WriteAgentVisionConsentAudit } from './agentVisionConsentAudit.js';
|
|
27
|
+
import { RoomAuthorizationService, type RoomAuthorizationResult } from '@memberjunction/livekit-room-server';
|
|
13
28
|
|
|
14
29
|
/**
|
|
15
30
|
* Binds the agent realtime-session factory onto the LiveKit room coordinator's model-session creation seam.
|
|
@@ -21,6 +36,37 @@ import { RegisterMeetingRecordingFile, CorrelateRecordingStart } from './meeting
|
|
|
21
36
|
*/
|
|
22
37
|
LiveKitAgentRoomCoordinator.Instance.SetSessionFactory(CreateBridgeRealtimeSession);
|
|
23
38
|
|
|
39
|
+
/**
|
|
40
|
+
* Binds the turn-taking tool handler seam (same module-load rationale as the factory above). A full-duplex model
|
|
41
|
+
* in a shared room calls `i_am_addressed` / `yield_turn`; the bridge engine owns what those mean, and this installs
|
|
42
|
+
* the engine's handler as the model session runtime's local tool handler (`@memberjunction/ai-agents`).
|
|
43
|
+
*/
|
|
44
|
+
LiveKitAgentRoomCoordinator.Instance.SetTurnToolBinder((session, handler) => {
|
|
45
|
+
const runtime = GetBridgeRealtimeRuntime(session);
|
|
46
|
+
if (!runtime) {
|
|
47
|
+
LogError('[RealtimeBridge] the model session has no bridge runtime; i_am_addressed / yield_turn will not execute for it.');
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
runtime.SetLocalToolHandler(handler);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Binds whether an agent watches meetings (same module-load rationale as the factory above). The coordinator asks per
|
|
55
|
+
* model session; the answer is the agent's `realtime.video.watchMeetings` setting, which the session runtime read from
|
|
56
|
+
* its effective configuration (`@memberjunction/ai-agents`). The coordinator also requires a model that takes video.
|
|
57
|
+
*/
|
|
58
|
+
LiveKitAgentRoomCoordinator.Instance.SetAgentVisionResolver((session) => GetBridgeRealtimeRuntime(session)?.WatchesMeetingVideo === true);
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Binds how a failed agent start is recorded on the agent's co-agent run (same module-load rationale as the factory
|
|
62
|
+
* above). The coordinator closes the model session of a start that fails before the bridge engine takes it; that close
|
|
63
|
+
* alone finalizes the run as Completed, so the coordinator first has the session's runtime finalize it as Failed, with the
|
|
64
|
+
* start's error.
|
|
65
|
+
*/
|
|
66
|
+
LiveKitAgentRoomCoordinator.Instance.SetFailedStartRecorder(async (session, error) => {
|
|
67
|
+
await GetBridgeRealtimeRuntime(session)?.Finalize(false, error);
|
|
68
|
+
});
|
|
69
|
+
|
|
24
70
|
/**
|
|
25
71
|
* Binds the co-agent run finalizer onto the bridge engine (same module-load rationale as the factory above).
|
|
26
72
|
* Lets the engine finalize a session's dangling co-agent observability run when it reaps a bridge WITHOUT a
|
|
@@ -127,6 +173,35 @@ export class StartLiveKitAgentRoomSessionInput {
|
|
|
127
173
|
|
|
128
174
|
@Field(() => String, { nullable: true })
|
|
129
175
|
TurnMode?: string;
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Start the agent able to bring someone into this room: a person (who is offered the conversation and may accept), a
|
|
179
|
+
* phone number, or another agent. Opt-in, and honoured only when this server has the handoff collaborators configured
|
|
180
|
+
* (the LiveKit SIP extension); otherwise the agent starts as it always did.
|
|
181
|
+
*/
|
|
182
|
+
@Field(() => Boolean, { nullable: true })
|
|
183
|
+
EnableHandoff?: boolean;
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* How this agent decides it was addressed: `Auto` (default — the model's own judgement when it is full-duplex,
|
|
187
|
+
* name matching otherwise), `ModelSide`, or `Regex`.
|
|
188
|
+
*/
|
|
189
|
+
@Field(() => String, { nullable: true })
|
|
190
|
+
TurnAddressing?: string;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/** The live turn-taking state of a room (floor holder, human speaking, hand-off, loop cap, recent events, seated agents). */
|
|
194
|
+
@ObjectType()
|
|
195
|
+
export class LiveKitRoomTurnStateResult {
|
|
196
|
+
@Field(() => Boolean)
|
|
197
|
+
Success: boolean;
|
|
198
|
+
|
|
199
|
+
@Field(() => String, { nullable: true })
|
|
200
|
+
ErrorMessage?: string;
|
|
201
|
+
|
|
202
|
+
/** JSON of the room's `RoomTurnSnapshot`; `null` when the room holds no agents. Parsed by the typed client. */
|
|
203
|
+
@Field(() => String, { nullable: true })
|
|
204
|
+
StateJSON?: string;
|
|
130
205
|
}
|
|
131
206
|
|
|
132
207
|
@ObjectType()
|
|
@@ -181,7 +256,30 @@ export class LiveKitRecordingResult {
|
|
|
181
256
|
RecordingFileID?: string;
|
|
182
257
|
}
|
|
183
258
|
|
|
184
|
-
/** A
|
|
259
|
+
/** A person's choice of whether agents may see their camera and shared screen in a room. */
|
|
260
|
+
@InputType()
|
|
261
|
+
export class SetLiveKitAgentVisionInput {
|
|
262
|
+
@Field(() => String)
|
|
263
|
+
RoomName: string;
|
|
264
|
+
|
|
265
|
+
/** `true` to let agents see, `false` to stop. */
|
|
266
|
+
@Field(() => Boolean)
|
|
267
|
+
Allow: boolean;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
@ObjectType()
|
|
271
|
+
export class LiveKitAgentVisionResult {
|
|
272
|
+
@Field(() => Boolean)
|
|
273
|
+
Success: boolean;
|
|
274
|
+
|
|
275
|
+
@Field(() => String, { nullable: true })
|
|
276
|
+
ErrorMessage?: string;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* A selectable provider-native voice for the dev voice picker: one per persona, or one per voice only the driver declares.
|
|
281
|
+
* Two personas can share an `ID` (a voice, and the same voice with a face); `PersonaID` tells them apart.
|
|
282
|
+
*/
|
|
185
283
|
@ObjectType()
|
|
186
284
|
export class RealtimeVoiceOptionResult {
|
|
187
285
|
@Field(() => String)
|
|
@@ -189,6 +287,22 @@ export class RealtimeVoiceOptionResult {
|
|
|
189
287
|
|
|
190
288
|
@Field(() => String)
|
|
191
289
|
Name: string;
|
|
290
|
+
|
|
291
|
+
/** The persona this voice belongs to (`MJ: AI Personas.ID`). Null for a voice only the driver declares. */
|
|
292
|
+
@Field(() => String, { nullable: true })
|
|
293
|
+
PersonaID?: string;
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* The avatar that comes with this voice: the `APIName` of its persona's preset Video binding on the model's vendor,
|
|
297
|
+
* which is what `realtime.video.avatarId` takes. Null for a voice without one, and for every voice only the driver
|
|
298
|
+
* declares.
|
|
299
|
+
*/
|
|
300
|
+
@Field(() => String, { nullable: true })
|
|
301
|
+
AvatarID?: string;
|
|
302
|
+
|
|
303
|
+
/** The persona's preview image URL, or null when it has none. */
|
|
304
|
+
@Field(() => String, { nullable: true })
|
|
305
|
+
PreviewImageURL?: string;
|
|
192
306
|
}
|
|
193
307
|
|
|
194
308
|
/** An active Realtime model with the voices its driver supports — feeds the dev model/voice picker. */
|
|
@@ -231,6 +345,11 @@ export class RealtimeBridgeResolver extends ResolverBase {
|
|
|
231
345
|
if (!user) {
|
|
232
346
|
return failure('Unable to determine current user.');
|
|
233
347
|
}
|
|
348
|
+
const provider = GetReadWriteProvider(context.providers) as IMetadataProvider;
|
|
349
|
+
const auth = await RoomAuthorizationService.Instance.AuthorizeRoomAccess(input.RoomName, user, provider);
|
|
350
|
+
if (!auth.Authorized) {
|
|
351
|
+
return failure(auth.Reason ?? 'Unauthorized room access.');
|
|
352
|
+
}
|
|
234
353
|
const tokenService = new LiveKitTokenService();
|
|
235
354
|
const minted = await tokenService.MintClientToken(input.RoomName, this.participantIdentity(user), input.DisplayName ?? user.Name ?? user.Email);
|
|
236
355
|
return { Success: true, ...minted };
|
|
@@ -243,7 +362,9 @@ export class RealtimeBridgeResolver extends ResolverBase {
|
|
|
243
362
|
|
|
244
363
|
/**
|
|
245
364
|
* Starts (or reuses) an agent's presence in a LiveKit room and returns a client token so the calling
|
|
246
|
-
* user can immediately join the same room.
|
|
365
|
+
* user can immediately join the same room. The token is minted before anything starts, so a start that can't give the
|
|
366
|
+
* user one fails with nothing started. When no `AgentSessionID` is passed, an agent session is created for the
|
|
367
|
+
* agent; if the agent then fails to start, that session is closed (`Error`) before the failure is returned.
|
|
247
368
|
*/
|
|
248
369
|
@Mutation(() => LiveKitAgentRoomSessionResult)
|
|
249
370
|
async StartLiveKitAgentRoomSession(
|
|
@@ -264,14 +385,44 @@ export class RealtimeBridgeResolver extends ResolverBase {
|
|
|
264
385
|
if (!user) {
|
|
265
386
|
return failure('Unable to determine current user.');
|
|
266
387
|
}
|
|
267
|
-
const provider = GetReadWriteProvider(context.providers) as
|
|
388
|
+
const provider = GetReadWriteProvider(context.providers) as IMetadataProvider;
|
|
268
389
|
const roomName = input.RoomName?.trim() || `mj-${randomUUID()}`;
|
|
269
390
|
|
|
391
|
+
if (input.RoomName?.trim()) {
|
|
392
|
+
const auth = await RoomAuthorizationService.Instance.AuthorizeRoomAccess(roomName, user, provider);
|
|
393
|
+
if (!auth.Authorized) {
|
|
394
|
+
return failure(auth.Reason ?? 'Unauthorized room access.', roomName);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
// The user's token first: a start that can't let the user into the room fails before anything starts there. Minted
|
|
399
|
+
// after the agent joined, a failure left the agent in a room the user couldn't enter and gave the UI no bridge id to
|
|
400
|
+
// stop it by.
|
|
401
|
+
const clientToken = await new LiveKitTokenService().MintClientToken(roomName, this.participantIdentity(user), user.Name ?? user.Email);
|
|
402
|
+
|
|
403
|
+
// Opt-in: an agent that can bring a person, a number or another agent into this room (the same room, so a visitor
|
|
404
|
+
// is escalated without leaving it). Falls through to the standard start when the server cannot do handoffs.
|
|
405
|
+
const handoffSessionBridgeID = await this.startWithHandoff(input, roomName, user, provider);
|
|
406
|
+
if (handoffSessionBridgeID) {
|
|
407
|
+
return {
|
|
408
|
+
Success: true,
|
|
409
|
+
SessionBridgeID: handoffSessionBridgeID,
|
|
410
|
+
RoomName: roomName,
|
|
411
|
+
ServerUrl: clientToken.ServerUrl,
|
|
412
|
+
ClientToken: clientToken.Token,
|
|
413
|
+
Identity: clientToken.Identity,
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
|
|
270
417
|
// Resolve the AIAgentSession the bridge will reference. The bridge row FK-references
|
|
271
418
|
// AIAgentSession(ID), so we must use an EXISTING session — either one the caller supplied, or a
|
|
272
419
|
// freshly-created one. Previously this minted a bare random UUID with no backing row, so the
|
|
273
420
|
// bridge INSERT failed the FK_AIAgentSessionBridge_Session constraint.
|
|
274
421
|
let agentSessionID = input.AgentSessionID?.trim();
|
|
422
|
+
// A session created here exists for this agent's time in the room alone, so it closes when the agent leaves, however
|
|
423
|
+
// it leaves, or at once if the agent fails to start (see startAgentInRoom). A session the caller supplied is the
|
|
424
|
+
// caller's to close.
|
|
425
|
+
let createdSessionID: string | undefined;
|
|
275
426
|
if (!agentSessionID) {
|
|
276
427
|
if (!input.AgentID?.trim()) {
|
|
277
428
|
return failure('An AgentID is required to start an agent room session.', roomName);
|
|
@@ -282,9 +433,10 @@ export class RealtimeBridgeResolver extends ResolverBase {
|
|
|
282
433
|
provider,
|
|
283
434
|
);
|
|
284
435
|
agentSessionID = createdSession.ID;
|
|
436
|
+
createdSessionID = createdSession.ID;
|
|
285
437
|
}
|
|
286
438
|
|
|
287
|
-
const session = await
|
|
439
|
+
const session = await this.startAgentInRoom(createdSessionID, user, provider, {
|
|
288
440
|
AgentSessionID: agentSessionID,
|
|
289
441
|
RoomName: roomName,
|
|
290
442
|
AgentID: input.AgentID,
|
|
@@ -293,13 +445,11 @@ export class RealtimeBridgeResolver extends ResolverBase {
|
|
|
293
445
|
RealtimeModelID: input.RealtimeModelID,
|
|
294
446
|
RealtimeVoice: input.RealtimeVoice,
|
|
295
447
|
TurnMode: this.normalizeTurnMode(input.TurnMode),
|
|
448
|
+
TurnAddressing: this.normalizeTurnAddressing(input.TurnAddressing),
|
|
296
449
|
ContextUser: user,
|
|
297
450
|
MetadataProvider: provider,
|
|
298
451
|
});
|
|
299
452
|
|
|
300
|
-
const tokenService = new LiveKitTokenService();
|
|
301
|
-
const clientToken = await tokenService.MintClientToken(roomName, this.participantIdentity(user), user.Name ?? user.Email);
|
|
302
|
-
|
|
303
453
|
return {
|
|
304
454
|
Success: true,
|
|
305
455
|
SessionBridgeID: session.SessionBridgeID,
|
|
@@ -319,6 +469,7 @@ export class RealtimeBridgeResolver extends ResolverBase {
|
|
|
319
469
|
* Stops one agent's presence in a room (the bot leaves) — the remove half of in-room agent management.
|
|
320
470
|
* Identified by the `SessionBridgeID` returned from {@link StartLiveKitAgentRoomSession}. Returns `true`
|
|
321
471
|
* when the bridge was stopped. Best-effort: a missing/already-stopped bridge or any error resolves `false`.
|
|
472
|
+
* The agent session the start created for the agent is closed (`Explicit`) before this returns.
|
|
322
473
|
*
|
|
323
474
|
* @param sessionBridgeID The `MJ: AI Agent Session Bridges` row id of the agent to remove.
|
|
324
475
|
*/
|
|
@@ -332,7 +483,15 @@ export class RealtimeBridgeResolver extends ResolverBase {
|
|
|
332
483
|
if (!user) {
|
|
333
484
|
return false;
|
|
334
485
|
}
|
|
335
|
-
const provider = GetReadWriteProvider(context.providers) as
|
|
486
|
+
const provider = GetReadWriteProvider(context.providers) as IMetadataProvider;
|
|
487
|
+
const roomName = LiveKitAgentRoomCoordinator.Instance.GetRoomForBridge(sessionBridgeID);
|
|
488
|
+
if (roomName) {
|
|
489
|
+
const auth = await RoomAuthorizationService.Instance.AuthorizeRoomAccess(roomName, user, provider);
|
|
490
|
+
if (!auth.Authorized) {
|
|
491
|
+
LogError(`StopLiveKitAgentRoomSession unauthorized: user ${user.ID} cannot access room ${roomName} (${auth.Reason})`);
|
|
492
|
+
return false;
|
|
493
|
+
}
|
|
494
|
+
}
|
|
336
495
|
return await LiveKitAgentRoomCoordinator.Instance.StopAgentRoomSession(sessionBridgeID, 'Explicit', user, provider);
|
|
337
496
|
} catch (error) {
|
|
338
497
|
LogError(`StopLiveKitAgentRoomSession failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -345,6 +504,7 @@ export class RealtimeBridgeResolver extends ResolverBase {
|
|
|
345
504
|
* coordinator's server-side roster). This is the "End meeting" half of the Zoom-style leave control —
|
|
346
505
|
* usable by any participant, including one who only *joined* the room and never tracked the bridge ids.
|
|
347
506
|
* Returns `true` when the teardown ran (even if the room held zero agents). Best-effort: any error → `false`.
|
|
507
|
+
* The agent sessions the starts created for the agents are closed (`Explicit`) as each agent leaves.
|
|
348
508
|
*
|
|
349
509
|
* @param roomName The LiveKit room to end.
|
|
350
510
|
*/
|
|
@@ -358,7 +518,12 @@ export class RealtimeBridgeResolver extends ResolverBase {
|
|
|
358
518
|
if (!user) {
|
|
359
519
|
return false;
|
|
360
520
|
}
|
|
361
|
-
const provider = GetReadWriteProvider(context.providers) as
|
|
521
|
+
const provider = GetReadWriteProvider(context.providers) as IMetadataProvider;
|
|
522
|
+
const auth = await RoomAuthorizationService.Instance.AuthorizeRoomAccess(roomName, user, provider);
|
|
523
|
+
if (!auth.Authorized) {
|
|
524
|
+
LogError(`EndLiveKitRoom unauthorized: user ${user.ID} cannot access room ${roomName} (${auth.Reason})`);
|
|
525
|
+
return false;
|
|
526
|
+
}
|
|
362
527
|
await LiveKitAgentRoomCoordinator.Instance.StopAllAgentsInRoom(roomName, 'Explicit', user, provider);
|
|
363
528
|
return true;
|
|
364
529
|
} catch (error) {
|
|
@@ -367,6 +532,37 @@ export class RealtimeBridgeResolver extends ResolverBase {
|
|
|
367
532
|
}
|
|
368
533
|
}
|
|
369
534
|
|
|
535
|
+
/**
|
|
536
|
+
* A room's live turn-taking state — who holds the floor, whether a person is speaking, any pending hand-off,
|
|
537
|
+
* the agent-to-agent loop-cap progress, the most recent floor/backchannel/yield events, and who is seated. The
|
|
538
|
+
* agent test bed polls it. Read-only. `StateJSON` is `null` when no agent is in the room.
|
|
539
|
+
*
|
|
540
|
+
* @param roomName The LiveKit room.
|
|
541
|
+
*/
|
|
542
|
+
@Query(() => LiveKitRoomTurnStateResult)
|
|
543
|
+
async GetLiveKitRoomTurnState(
|
|
544
|
+
@Arg('roomName', () => String) roomName: string,
|
|
545
|
+
@Ctx() context: AppContext = {} as AppContext,
|
|
546
|
+
): Promise<LiveKitRoomTurnStateResult> {
|
|
547
|
+
try {
|
|
548
|
+
const user = this.GetUserFromPayload(context.userPayload);
|
|
549
|
+
if (!user) {
|
|
550
|
+
return { Success: false, ErrorMessage: 'Unable to determine current user.' };
|
|
551
|
+
}
|
|
552
|
+
const provider = GetReadWriteProvider(context.providers) as IMetadataProvider;
|
|
553
|
+
const auth = await RoomAuthorizationService.Instance.AuthorizeRoomAccess(roomName, user, provider);
|
|
554
|
+
if (!auth.Authorized) {
|
|
555
|
+
return { Success: false, ErrorMessage: auth.Reason ?? 'Unauthorized room access.' };
|
|
556
|
+
}
|
|
557
|
+
const snapshot = LiveKitAgentRoomCoordinator.Instance.GetRoomTurnState(roomName);
|
|
558
|
+
return { Success: true, StateJSON: snapshot ? JSON.stringify(snapshot) : undefined };
|
|
559
|
+
} catch (error) {
|
|
560
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
561
|
+
LogError(`GetLiveKitRoomTurnState failed: ${msg}`);
|
|
562
|
+
return { Success: false, ErrorMessage: msg };
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
|
|
370
566
|
/**
|
|
371
567
|
* Lists active Realtime models with the voices each driver supports — the source for the dev model/voice
|
|
372
568
|
* picker (gated client-side by the `Realtime: Advanced Session Controls` authorization). Read-only; returns
|
|
@@ -381,7 +577,7 @@ export class RealtimeBridgeResolver extends ResolverBase {
|
|
|
381
577
|
if (!user) {
|
|
382
578
|
return [];
|
|
383
579
|
}
|
|
384
|
-
const provider = GetReadWriteProvider(context.providers) as
|
|
580
|
+
const provider = GetReadWriteProvider(context.providers) as IMetadataProvider;
|
|
385
581
|
return await GetRealtimeModelVoices(user, provider);
|
|
386
582
|
} catch (error) {
|
|
387
583
|
LogError(`GetRealtimeModelVoices failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -411,7 +607,12 @@ export class RealtimeBridgeResolver extends ResolverBase {
|
|
|
411
607
|
if (!user) {
|
|
412
608
|
return false;
|
|
413
609
|
}
|
|
414
|
-
const provider = GetReadWriteProvider(context.providers) as
|
|
610
|
+
const provider = GetReadWriteProvider(context.providers) as IMetadataProvider;
|
|
611
|
+
const auth = await RoomAuthorizationService.Instance.AuthorizeRoomAccess(roomName, user, provider);
|
|
612
|
+
if (!auth.Authorized) {
|
|
613
|
+
LogError(`InviteUsersToLiveKitRoom unauthorized: user ${user.ID} cannot access room ${roomName} (${auth.Reason})`);
|
|
614
|
+
return false;
|
|
615
|
+
}
|
|
415
616
|
await NotificationEngine.Instance.Config(false, user, provider);
|
|
416
617
|
|
|
417
618
|
const inviter = user.Name?.trim() || user.Email || 'Someone';
|
|
@@ -453,11 +654,15 @@ export class RealtimeBridgeResolver extends ResolverBase {
|
|
|
453
654
|
if (!user) {
|
|
454
655
|
return { Success: false, ErrorMessage: 'Unable to determine current user.', EgressID: '', Status: '' };
|
|
455
656
|
}
|
|
657
|
+
const provider = GetReadWriteProvider(context.providers) as IMetadataProvider;
|
|
658
|
+
const auth = await RoomAuthorizationService.Instance.AuthorizeRoomAccess(input.RoomName, user, provider);
|
|
659
|
+
if (!auth.Authorized) {
|
|
660
|
+
return { Success: false, ErrorMessage: auth.Reason ?? 'Unauthorized room access.', EgressID: '', Status: '' };
|
|
661
|
+
}
|
|
456
662
|
const info = await new LiveKitEgressService().StartRoomRecording({ RoomName: input.RoomName, Layout: input.Layout });
|
|
457
663
|
|
|
458
664
|
// Best-effort: correlate the live recording with the room's Meeting-Room Conversation (if it exists
|
|
459
665
|
// yet) by stamping its EgressID. Never fail the start on this — the stop-flow resolves/creates it.
|
|
460
|
-
const provider = GetReadWriteProvider(context.providers) as unknown as IMetadataProvider;
|
|
461
666
|
void CorrelateRecordingStart(input.RoomName, info.EgressID, user, provider);
|
|
462
667
|
|
|
463
668
|
return { Success: true, EgressID: info.EgressID, Status: info.Status };
|
|
@@ -481,8 +686,43 @@ export class RealtimeBridgeResolver extends ResolverBase {
|
|
|
481
686
|
if (!user) {
|
|
482
687
|
return { Success: false, ErrorMessage: 'Unable to determine current user.', EgressID: egressID, Status: '' };
|
|
483
688
|
}
|
|
484
|
-
const
|
|
485
|
-
|
|
689
|
+
const provider = GetReadWriteProvider(context.providers) as IMetadataProvider;
|
|
690
|
+
|
|
691
|
+
// Map egress ID to room name: check LiveKit egress service first, fallback to Conversation if available.
|
|
692
|
+
const egressService = new LiveKitEgressService();
|
|
693
|
+
let roomName = await egressService.GetRoomForEgress(egressID);
|
|
694
|
+
if (!roomName && provider) {
|
|
695
|
+
try {
|
|
696
|
+
const rv = RunView.FromMetadataProvider(provider);
|
|
697
|
+
const convResult = await rv.RunView<{ ExternalID: string }>(
|
|
698
|
+
{
|
|
699
|
+
EntityName: 'MJ: Conversations',
|
|
700
|
+
ExtraFilter: `EgressID='${EscapeSQLString(egressID)}' AND (IsArchived IS NULL OR IsArchived=0)`,
|
|
701
|
+
Fields: ['ExternalID'],
|
|
702
|
+
OrderBy: '__mj_CreatedAt DESC',
|
|
703
|
+
MaxRows: 1,
|
|
704
|
+
ResultType: 'simple',
|
|
705
|
+
},
|
|
706
|
+
user,
|
|
707
|
+
);
|
|
708
|
+
if (convResult.Success && convResult.Results.length > 0 && convResult.Results[0].ExternalID) {
|
|
709
|
+
roomName = convResult.Results[0].ExternalID;
|
|
710
|
+
}
|
|
711
|
+
} catch (err) {
|
|
712
|
+
LogError(`StopLiveKitRecording: error looking up Conversation for egress ID '${egressID}'`, undefined, err);
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
if (roomName) {
|
|
717
|
+
const auth = await RoomAuthorizationService.Instance.AuthorizeRoomAccess(roomName, user, provider);
|
|
718
|
+
if (!auth.Authorized) {
|
|
719
|
+
return { Success: false, ErrorMessage: auth.Reason ?? 'Unauthorized room access.', EgressID: egressID, Status: '' };
|
|
720
|
+
}
|
|
721
|
+
} else {
|
|
722
|
+
return { Success: false, ErrorMessage: `Unable to determine room for egress ID '${egressID}'.`, EgressID: egressID, Status: '' };
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
const info = await egressService.StopRecording(egressID);
|
|
486
726
|
|
|
487
727
|
// Register the completed egress MP4 as a Files row on the Meeting-Room Conversation. Best-effort:
|
|
488
728
|
// any failure (e.g. storage provider not configured) leaves RecordingFileID unset but still
|
|
@@ -504,9 +744,135 @@ export class RealtimeBridgeResolver extends ResolverBase {
|
|
|
504
744
|
}
|
|
505
745
|
}
|
|
506
746
|
|
|
507
|
-
/**
|
|
747
|
+
/**
|
|
748
|
+
* Records whether the current user lets agents see their camera and shared screen in a room. The participant is
|
|
749
|
+
* worked out from the authenticated user, never sent by the client, so a person can only answer for themselves. To
|
|
750
|
+
* allow, the room must be one they may enter ({@link RoomAuthorizationService}, as for every room mutation). A
|
|
751
|
+
* withdrawal skips that check: a cancelled meeting or a failed lookup must not keep an agent watching someone who is
|
|
752
|
+
* still in the room, and the identity is always the caller's own. LiveKit refuses either way when they are not in it. The choice is set as their `mj.agentCanSee` attribute through LiveKit's server SDK (a
|
|
753
|
+
* participant's token can't change its own attributes) and audited, applied or not.
|
|
754
|
+
*/
|
|
755
|
+
@Mutation(() => LiveKitAgentVisionResult)
|
|
756
|
+
async SetLiveKitAgentVision(
|
|
757
|
+
@Arg('input', () => SetLiveKitAgentVisionInput) input: SetLiveKitAgentVisionInput,
|
|
758
|
+
@Ctx() context: AppContext = {} as AppContext,
|
|
759
|
+
): Promise<LiveKitAgentVisionResult> {
|
|
760
|
+
try {
|
|
761
|
+
const user = this.GetUserFromPayload(context.userPayload);
|
|
762
|
+
if (!user) {
|
|
763
|
+
return { Success: false, ErrorMessage: 'Unable to determine current user.' };
|
|
764
|
+
}
|
|
765
|
+
const provider = GetReadWriteProvider(context.providers) as unknown as IMetadataProvider;
|
|
766
|
+
const auth: RoomAuthorizationResult = input.Allow
|
|
767
|
+
? await RoomAuthorizationService.Instance.AuthorizeRoomAccess(input.RoomName, user, provider)
|
|
768
|
+
: { Authorized: true };
|
|
769
|
+
const result: ParticipantUpdateResult = auth.Authorized
|
|
770
|
+
? await new LiveKitParticipantService().SetAgentVision(input.RoomName, this.participantIdentity(user), input.Allow)
|
|
771
|
+
: { Success: false, ErrorMessage: auth.Reason ?? 'Unauthorized room access.' };
|
|
772
|
+
await WriteAgentVisionConsentAudit(
|
|
773
|
+
{ User: user, RoomName: input.RoomName, Allow: input.Allow, Applied: result.Success, ErrorMessage: result.ErrorMessage },
|
|
774
|
+
provider,
|
|
775
|
+
);
|
|
776
|
+
if (result.Success) {
|
|
777
|
+
return { Success: true };
|
|
778
|
+
}
|
|
779
|
+
return { Success: false, ErrorMessage: result.NotInRoom ? 'You are not in this room.' : result.ErrorMessage };
|
|
780
|
+
} catch (error) {
|
|
781
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
782
|
+
LogError(`SetLiveKitAgentVision failed: ${msg}`);
|
|
783
|
+
return { Success: false, ErrorMessage: msg };
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
/**
|
|
788
|
+
* Starts the agent through the handoff-capable room starter when the caller asked for it and the server can do it.
|
|
789
|
+
* Returns the bridge id, or `undefined` to mean "use the standard start" (not requested, no starter, no agent named).
|
|
790
|
+
*/
|
|
791
|
+
private async startWithHandoff(
|
|
792
|
+
input: StartLiveKitAgentRoomSessionInput,
|
|
793
|
+
roomName: string,
|
|
794
|
+
user: UserInfo,
|
|
795
|
+
provider: IMetadataProvider,
|
|
796
|
+
): Promise<string | undefined> {
|
|
797
|
+
if (!input.EnableHandoff) {
|
|
798
|
+
return undefined;
|
|
799
|
+
}
|
|
800
|
+
const starter = RoomHandoffEngine.Instance.Deps.AgentStarter;
|
|
801
|
+
const agentID = input.TargetAgentID?.trim() || input.AgentID?.trim();
|
|
802
|
+
if (!starter || !agentID) {
|
|
803
|
+
LogError('StartLiveKitAgentRoomSession: handoff was requested but this server has no handoff-capable agent starter; starting the agent without it.');
|
|
804
|
+
return undefined;
|
|
805
|
+
}
|
|
806
|
+
const started = await starter({
|
|
807
|
+
RoomName: roomName,
|
|
808
|
+
AgentID: agentID,
|
|
809
|
+
AgentName: input.AgentName?.trim() ?? '',
|
|
810
|
+
CallerLabel: user.Name?.trim() || user.Email || 'Web visitor',
|
|
811
|
+
ContextUser: user,
|
|
812
|
+
Provider: provider,
|
|
813
|
+
RealtimeModelID: input.RealtimeModelID,
|
|
814
|
+
RealtimeVoice: input.RealtimeVoice,
|
|
815
|
+
});
|
|
816
|
+
return started.SessionBridgeID;
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
/**
|
|
820
|
+
* Starts the agent in the room through the coordinator. An agent session created for this agent's time in the room
|
|
821
|
+
* (`createdSessionID`) is this start's to close: once the agent has joined, through the end-of-session hook from
|
|
822
|
+
* {@link closeSessionWhenAgentLeaves}; when the start fails, at once, as `Error`, through
|
|
823
|
+
* {@link SessionManager.CloseSessionForFailedStart}, before the error propagates, since the agent never joined and that
|
|
824
|
+
* hook never runs (#5308). By then the coordinator has closed any model session the start opened, its co-agent run
|
|
825
|
+
* finalized as failed. A session the caller supplied gets neither: it is the caller's.
|
|
826
|
+
*/
|
|
827
|
+
private async startAgentInRoom(
|
|
828
|
+
createdSessionID: string | undefined,
|
|
829
|
+
user: UserInfo,
|
|
830
|
+
provider: IMetadataProvider,
|
|
831
|
+
params: Omit<StartAgentRoomSessionParams, 'Host'>,
|
|
832
|
+
): Promise<AgentRoomSession> {
|
|
833
|
+
const coordinator = LiveKitAgentRoomCoordinator.Instance;
|
|
834
|
+
if (!createdSessionID) {
|
|
835
|
+
return coordinator.StartAgentRoomSession(params);
|
|
836
|
+
}
|
|
837
|
+
try {
|
|
838
|
+
return await coordinator.StartAgentRoomSession({ ...params, Host: this.closeSessionWhenAgentLeaves(createdSessionID, user, provider) });
|
|
839
|
+
} catch (error) {
|
|
840
|
+
await this.sessionManager.CloseSessionForFailedStart(createdSessionID, user, provider);
|
|
841
|
+
throw error;
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
/**
|
|
846
|
+
* What the coordinator is given for an agent session created for one agent's time in a room: its end-of-session hook
|
|
847
|
+
* closes the session once the agent's bridge has ended, whatever ended it (the agent stopped, the meeting ended, everyone
|
|
848
|
+
* left, the model session lost), through {@link SessionManager.CloseSessionForEndedBridge}. The close runs as the user
|
|
849
|
+
* who started the agent, whoever stops it: the session is theirs.
|
|
850
|
+
*/
|
|
851
|
+
private closeSessionWhenAgentLeaves(agentSessionID: string, user: UserInfo, provider: IMetadataProvider): AgentRoomHostOptions {
|
|
852
|
+
return {
|
|
853
|
+
OnSessionEnded: async (reason) => {
|
|
854
|
+
await this.sessionManager.CloseSessionForEndedBridge(agentSessionID, reason, user, provider);
|
|
855
|
+
},
|
|
856
|
+
};
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
/** Builds a stable, lowercased participant identity from the authenticated user (shared with the handoff engine, which watches for it). */
|
|
508
860
|
private participantIdentity(user: UserInfo): string {
|
|
509
|
-
return
|
|
861
|
+
return LiveKitUserIdentity(user.ID);
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
/** Normalizes an addressing-mode string; unknown/absent leaves the coordinator's default (`Auto`). */
|
|
865
|
+
private normalizeTurnAddressing(mode?: string): TurnAddressingMode | undefined {
|
|
866
|
+
switch ((mode ?? '').trim().toLowerCase()) {
|
|
867
|
+
case 'auto':
|
|
868
|
+
return 'Auto';
|
|
869
|
+
case 'modelside':
|
|
870
|
+
return 'ModelSide';
|
|
871
|
+
case 'regex':
|
|
872
|
+
return 'Regex';
|
|
873
|
+
default:
|
|
874
|
+
return undefined;
|
|
875
|
+
}
|
|
510
876
|
}
|
|
511
877
|
|
|
512
878
|
/** Normalizes a turn-mode string to the bridge's accepted values. */
|