@memberjunction/server 6.2.0-edge.5 → 6.2.0-edge.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +96 -1
- package/dist/.tsbuildinfo +1 -1
- package/dist/agentSessions/BridgeHostInstance.d.ts +8 -3
- package/dist/agentSessions/BridgeHostInstance.d.ts.map +1 -1
- package/dist/agentSessions/BridgeHostInstance.js +14 -4
- package/dist/agentSessions/BridgeHostInstance.js.map +1 -1
- package/dist/agentSessions/HandoffOfferExpiry.d.ts +10 -0
- package/dist/agentSessions/HandoffOfferExpiry.d.ts.map +1 -0
- package/dist/agentSessions/HandoffOfferExpiry.js +18 -0
- package/dist/agentSessions/HandoffOfferExpiry.js.map +1 -0
- package/dist/agentSessions/ReturningVisitorRecap.js +1 -0
- package/dist/agentSessions/ReturningVisitorRecap.js.map +1 -1
- package/dist/agentSessions/SessionJanitor.d.ts +34 -11
- package/dist/agentSessions/SessionJanitor.d.ts.map +1 -1
- package/dist/agentSessions/SessionJanitor.js +88 -44
- package/dist/agentSessions/SessionJanitor.js.map +1 -1
- package/dist/agentSessions/SessionManager.d.ts +29 -9
- package/dist/agentSessions/SessionManager.d.ts.map +1 -1
- package/dist/agentSessions/SessionManager.js +62 -16
- package/dist/agentSessions/SessionManager.js.map +1 -1
- package/dist/agentSessions/conversationBrowsers.d.ts +61 -0
- package/dist/agentSessions/conversationBrowsers.d.ts.map +1 -0
- package/dist/agentSessions/conversationBrowsers.js +118 -0
- package/dist/agentSessions/conversationBrowsers.js.map +1 -0
- package/dist/agentSessions/sessionDeadline.d.ts +43 -0
- package/dist/agentSessions/sessionDeadline.d.ts.map +1 -0
- package/dist/agentSessions/sessionDeadline.js +68 -0
- package/dist/agentSessions/sessionDeadline.js.map +1 -0
- package/dist/auth/APIKeyScopeAuth.d.ts.map +1 -1
- package/dist/auth/APIKeyScopeAuth.js +5 -4
- package/dist/auth/APIKeyScopeAuth.js.map +1 -1
- package/dist/auth/AuthProviderCatalogRouter.d.ts.map +1 -1
- package/dist/auth/AuthProviderCatalogRouter.js +2 -0
- package/dist/auth/AuthProviderCatalogRouter.js.map +1 -1
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +51 -10
- package/dist/auth/index.js.map +1 -1
- package/dist/auth/initializeProviders.d.ts +10 -0
- package/dist/auth/initializeProviders.d.ts.map +1 -1
- package/dist/auth/initializeProviders.js +37 -1
- package/dist/auth/initializeProviders.js.map +1 -1
- package/dist/auth/localDevAuth.d.ts +79 -0
- package/dist/auth/localDevAuth.d.ts.map +1 -0
- package/dist/auth/localDevAuth.js +439 -0
- package/dist/auth/localDevAuth.js.map +1 -0
- package/dist/auth/loginEmailResolution.d.ts +41 -0
- package/dist/auth/loginEmailResolution.d.ts.map +1 -0
- package/dist/auth/loginEmailResolution.js +47 -0
- package/dist/auth/loginEmailResolution.js.map +1 -0
- package/dist/auth/magicLink/MagicLinkKeys.d.ts +51 -3
- package/dist/auth/magicLink/MagicLinkKeys.d.ts.map +1 -1
- package/dist/auth/magicLink/MagicLinkKeys.js +130 -13
- package/dist/auth/magicLink/MagicLinkKeys.js.map +1 -1
- package/dist/auth/magicLink/MagicLinkRouter.d.ts +3 -0
- package/dist/auth/magicLink/MagicLinkRouter.d.ts.map +1 -1
- package/dist/auth/magicLink/MagicLinkRouter.js +23 -5
- package/dist/auth/magicLink/MagicLinkRouter.js.map +1 -1
- package/dist/auth/magicLink/MagicLinkService.d.ts +39 -5
- package/dist/auth/magicLink/MagicLinkService.d.ts.map +1 -1
- package/dist/auth/magicLink/MagicLinkService.js +221 -9
- package/dist/auth/magicLink/MagicLinkService.js.map +1 -1
- package/dist/auth/magicLink/index.d.ts +1 -1
- package/dist/auth/magicLink/index.d.ts.map +1 -1
- package/dist/auth/magicLink/index.js +1 -1
- package/dist/auth/magicLink/index.js.map +1 -1
- package/dist/auth/magicLink/redeemLanding.d.ts +2 -2
- package/dist/auth/magicLink/redeemLanding.d.ts.map +1 -1
- package/dist/auth/magicLink/redeemLanding.js +7 -4
- package/dist/auth/magicLink/redeemLanding.js.map +1 -1
- package/dist/auth/magicLink/types.d.ts +39 -3
- package/dist/auth/magicLink/types.d.ts.map +1 -1
- package/dist/auth/magicLink/types.js +0 -4
- package/dist/auth/magicLink/types.js.map +1 -1
- package/dist/auth/newUsers.d.ts.map +1 -1
- package/dist/auth/newUsers.js +1 -0
- package/dist/auth/newUsers.js.map +1 -1
- package/dist/auth/sessionUserClone.d.ts +1 -1
- package/dist/auth/sessionUserClone.d.ts.map +1 -1
- package/dist/auth/sessionUserClone.js +3 -2
- package/dist/auth/sessionUserClone.js.map +1 -1
- package/dist/backgroundSweepConfigUnits.d.ts +231 -0
- package/dist/backgroundSweepConfigUnits.d.ts.map +1 -0
- package/dist/backgroundSweepConfigUnits.js +180 -0
- package/dist/backgroundSweepConfigUnits.js.map +1 -0
- package/dist/broadcast/BaseCacheInvalidationBroadcastProvider.d.ts +292 -0
- package/dist/broadcast/BaseCacheInvalidationBroadcastProvider.d.ts.map +1 -0
- package/dist/broadcast/BaseCacheInvalidationBroadcastProvider.js +442 -0
- package/dist/broadcast/BaseCacheInvalidationBroadcastProvider.js.map +1 -0
- package/dist/broadcast/index.d.ts +6 -0
- package/dist/broadcast/index.d.ts.map +1 -0
- package/dist/broadcast/index.js +6 -0
- package/dist/broadcast/index.js.map +1 -0
- package/dist/broadcast/providers/AWSIoTCoreBroadcastProvider.d.ts +43 -0
- package/dist/broadcast/providers/AWSIoTCoreBroadcastProvider.d.ts.map +1 -0
- package/dist/broadcast/providers/AWSIoTCoreBroadcastProvider.js +144 -0
- package/dist/broadcast/providers/AWSIoTCoreBroadcastProvider.js.map +1 -0
- package/dist/broadcast/providers/AzureWebPubSubBroadcastProvider.d.ts +46 -0
- package/dist/broadcast/providers/AzureWebPubSubBroadcastProvider.d.ts.map +1 -0
- package/dist/broadcast/providers/AzureWebPubSubBroadcastProvider.js +149 -0
- package/dist/broadcast/providers/AzureWebPubSubBroadcastProvider.js.map +1 -0
- package/dist/broadcast/providers/GCPPubSubBroadcastProvider.d.ts +49 -0
- package/dist/broadcast/providers/GCPPubSubBroadcastProvider.d.ts.map +1 -0
- package/dist/broadcast/providers/GCPPubSubBroadcastProvider.js +131 -0
- package/dist/broadcast/providers/GCPPubSubBroadcastProvider.js.map +1 -0
- package/dist/broadcast/providers/SequencedRoleBucketBroadcastProvider.d.ts +24 -0
- package/dist/broadcast/providers/SequencedRoleBucketBroadcastProvider.d.ts.map +1 -0
- package/dist/broadcast/providers/SequencedRoleBucketBroadcastProvider.js +51 -0
- package/dist/broadcast/providers/SequencedRoleBucketBroadcastProvider.js.map +1 -0
- package/dist/cache.d.ts +3 -2
- package/dist/cache.d.ts.map +1 -1
- package/dist/cache.js.map +1 -1
- package/dist/config.d.ts +1402 -8
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +120 -0
- package/dist/config.js.map +1 -1
- package/dist/context.d.ts +5 -1
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +64 -12
- package/dist/context.js.map +1 -1
- package/dist/coreRoutes.d.ts +3 -1
- package/dist/coreRoutes.d.ts.map +1 -1
- package/dist/coreRoutes.js +20 -4
- package/dist/coreRoutes.js.map +1 -1
- package/dist/generated/graphql-schemas/__mj.d.ts +863 -14
- package/dist/generated/graphql-schemas/__mj.d.ts.map +1 -1
- package/dist/generated/graphql-schemas/__mj.js +4167 -62
- package/dist/generated/graphql-schemas/__mj.js.map +1 -1
- package/dist/generic/CacheInvalidationResolver.d.ts +50 -30
- package/dist/generic/CacheInvalidationResolver.d.ts.map +1 -1
- package/dist/generic/CacheInvalidationResolver.js +154 -79
- package/dist/generic/CacheInvalidationResolver.js.map +1 -1
- package/dist/generic/OrphanedConversationDetailReconciler.d.ts +11 -0
- package/dist/generic/OrphanedConversationDetailReconciler.d.ts.map +1 -1
- package/dist/generic/OrphanedConversationDetailReconciler.js +29 -1
- package/dist/generic/OrphanedConversationDetailReconciler.js.map +1 -1
- package/dist/generic/PubSubManager.d.ts +10 -0
- package/dist/generic/PubSubManager.d.ts.map +1 -1
- package/dist/generic/PubSubManager.js +44 -1
- package/dist/generic/PubSubManager.js.map +1 -1
- package/dist/generic/PushStatusResolver.d.ts +39 -6
- package/dist/generic/PushStatusResolver.d.ts.map +1 -1
- package/dist/generic/PushStatusResolver.js +93 -11
- package/dist/generic/PushStatusResolver.js.map +1 -1
- package/dist/generic/ResolverBase.d.ts +114 -29
- package/dist/generic/ResolverBase.d.ts.map +1 -1
- package/dist/generic/ResolverBase.js +509 -220
- package/dist/generic/ResolverBase.js.map +1 -1
- package/dist/generic/RunViewResolver.d.ts +15 -3
- package/dist/generic/RunViewResolver.d.ts.map +1 -1
- package/dist/generic/RunViewResolver.js +126 -20
- package/dist/generic/RunViewResolver.js.map +1 -1
- package/dist/generic/actionOutputFieldSecurity.d.ts +26 -0
- package/dist/generic/actionOutputFieldSecurity.d.ts.map +1 -0
- package/dist/generic/actionOutputFieldSecurity.js +47 -0
- package/dist/generic/actionOutputFieldSecurity.js.map +1 -0
- package/dist/generic/fieldSecurityTransport.d.ts +30 -0
- package/dist/generic/fieldSecurityTransport.d.ts.map +1 -0
- package/dist/generic/fieldSecurityTransport.js +30 -0
- package/dist/generic/fieldSecurityTransport.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +262 -84
- package/dist/index.js.map +1 -1
- package/dist/integration/ConnectionPause.d.ts +121 -0
- package/dist/integration/ConnectionPause.d.ts.map +1 -0
- package/dist/integration/ConnectionPause.js +183 -0
- package/dist/integration/ConnectionPause.js.map +1 -0
- package/dist/integration/CustomColumnPromoter.d.ts +72 -6
- package/dist/integration/CustomColumnPromoter.d.ts.map +1 -1
- package/dist/integration/CustomColumnPromoter.js +93 -47
- package/dist/integration/CustomColumnPromoter.js.map +1 -1
- package/dist/integration/EntityMapLifecycle.d.ts +78 -4
- package/dist/integration/EntityMapLifecycle.d.ts.map +1 -1
- package/dist/integration/EntityMapLifecycle.js +199 -5
- package/dist/integration/EntityMapLifecycle.js.map +1 -1
- package/dist/integration/InactiveRowWarnings.d.ts +31 -0
- package/dist/integration/InactiveRowWarnings.d.ts.map +1 -1
- package/dist/integration/InactiveRowWarnings.js +29 -0
- package/dist/integration/InactiveRowWarnings.js.map +1 -1
- package/dist/integration/ObjectNamesByID.d.ts +28 -0
- package/dist/integration/ObjectNamesByID.d.ts.map +1 -0
- package/dist/integration/ObjectNamesByID.js +87 -0
- package/dist/integration/ObjectNamesByID.js.map +1 -0
- package/dist/integration/PostRestartIntrospect.d.ts +26 -0
- package/dist/integration/PostRestartIntrospect.d.ts.map +1 -0
- package/dist/integration/PostRestartIntrospect.js +27 -0
- package/dist/integration/PostRestartIntrospect.js.map +1 -0
- package/dist/integration/RSUPostRestartProgress.d.ts +176 -0
- package/dist/integration/RSUPostRestartProgress.d.ts.map +1 -0
- package/dist/integration/RSUPostRestartProgress.js +323 -0
- package/dist/integration/RSUPostRestartProgress.js.map +1 -0
- package/dist/integration/RSUProgressBridge.d.ts +41 -2
- package/dist/integration/RSUProgressBridge.d.ts.map +1 -1
- package/dist/integration/RSUProgressBridge.js +84 -1
- package/dist/integration/RSUProgressBridge.js.map +1 -1
- package/dist/integration/RunArtifactAuthorization.d.ts +39 -0
- package/dist/integration/RunArtifactAuthorization.d.ts.map +1 -0
- package/dist/integration/RunArtifactAuthorization.js +45 -0
- package/dist/integration/RunArtifactAuthorization.js.map +1 -0
- package/dist/integration/SchemaRefreshLaunch.d.ts +9 -0
- package/dist/integration/SchemaRefreshLaunch.d.ts.map +1 -1
- package/dist/integration/SchemaRefreshLaunch.js +3 -2
- package/dist/integration/SchemaRefreshLaunch.js.map +1 -1
- package/dist/integration/ScopedFieldsForBuild.d.ts +46 -0
- package/dist/integration/ScopedFieldsForBuild.d.ts.map +1 -0
- package/dist/integration/ScopedFieldsForBuild.js +91 -0
- package/dist/integration/ScopedFieldsForBuild.js.map +1 -0
- package/dist/integration/TargetConfigGuard.d.ts +40 -0
- package/dist/integration/TargetConfigGuard.d.ts.map +1 -0
- package/dist/integration/TargetConfigGuard.js +40 -0
- package/dist/integration/TargetConfigGuard.js.map +1 -0
- package/dist/logging/variablesLoggingMiddleware.d.ts +12 -0
- package/dist/logging/variablesLoggingMiddleware.d.ts.map +1 -1
- package/dist/logging/variablesLoggingMiddleware.js +50 -1
- package/dist/logging/variablesLoggingMiddleware.js.map +1 -1
- package/dist/realtimeSessions/SessionVerificationPortsBase.d.ts.map +1 -1
- package/dist/realtimeSessions/SessionVerificationPortsBase.js +1 -0
- package/dist/realtimeSessions/SessionVerificationPortsBase.js.map +1 -1
- package/dist/realtimeSessions/ownedRealtimeSession.d.ts +8 -6
- package/dist/realtimeSessions/ownedRealtimeSession.d.ts.map +1 -1
- package/dist/realtimeSessions/ownedRealtimeSession.js +14 -6
- package/dist/realtimeSessions/ownedRealtimeSession.js.map +1 -1
- package/dist/realtimeSessions/sessionAccess.d.ts +103 -11
- package/dist/realtimeSessions/sessionAccess.d.ts.map +1 -1
- package/dist/realtimeSessions/sessionAccess.js +147 -22
- package/dist/realtimeSessions/sessionAccess.js.map +1 -1
- package/dist/realtimeSessions/sessionConfigStamps.js +1 -1
- package/dist/realtimeSessions/sessionConfigStamps.js.map +1 -1
- package/dist/realtimeSessions/subscriptionAuthorization.d.ts.map +1 -1
- package/dist/realtimeSessions/subscriptionAuthorization.js +5 -2
- package/dist/realtimeSessions/subscriptionAuthorization.js.map +1 -1
- package/dist/realtimeSessions/verificationWorkflow.d.ts +2 -0
- package/dist/realtimeSessions/verificationWorkflow.d.ts.map +1 -1
- package/dist/realtimeSessions/verificationWorkflow.js +1 -1
- package/dist/realtimeSessions/verificationWorkflow.js.map +1 -1
- package/dist/realtimeWidget/WidgetRouter.d.ts.map +1 -1
- package/dist/realtimeWidget/WidgetRouter.js +19 -3
- package/dist/realtimeWidget/WidgetRouter.js.map +1 -1
- package/dist/realtimeWidget/WidgetSessionService.d.ts +67 -7
- package/dist/realtimeWidget/WidgetSessionService.d.ts.map +1 -1
- package/dist/realtimeWidget/WidgetSessionService.js +203 -19
- package/dist/realtimeWidget/WidgetSessionService.js.map +1 -1
- package/dist/realtimeWidget/host-identity.d.ts +1 -1
- package/dist/realtimeWidget/host-identity.js +1 -1
- package/dist/realtimeWidget/visitorIdentity.d.ts.map +1 -1
- package/dist/realtimeWidget/visitorIdentity.js +1 -0
- package/dist/realtimeWidget/visitorIdentity.js.map +1 -1
- package/dist/realtimeWidget/widgetCore.d.ts +20 -1
- package/dist/realtimeWidget/widgetCore.d.ts.map +1 -1
- package/dist/realtimeWidget/widgetCore.js +21 -8
- package/dist/realtimeWidget/widgetCore.js.map +1 -1
- package/dist/realtimeWidget/widgetGuestElevation.d.ts +1 -1
- package/dist/realtimeWidget/widgetGuestElevation.d.ts.map +1 -1
- package/dist/realtimeWidget/widgetGuestElevation.js +3 -1
- package/dist/realtimeWidget/widgetGuestElevation.js.map +1 -1
- package/dist/requestOrigin.d.ts +22 -0
- package/dist/requestOrigin.d.ts.map +1 -0
- package/dist/requestOrigin.js +60 -0
- package/dist/requestOrigin.js.map +1 -0
- package/dist/resolvers/ActionResolver.d.ts +19 -1
- package/dist/resolvers/ActionResolver.d.ts.map +1 -1
- package/dist/resolvers/ActionResolver.js +63 -12
- package/dist/resolvers/ActionResolver.js.map +1 -1
- package/dist/resolvers/AdhocQueryResolver.d.ts.map +1 -1
- package/dist/resolvers/AdhocQueryResolver.js +1 -0
- package/dist/resolvers/AdhocQueryResolver.js.map +1 -1
- package/dist/resolvers/AgentRunStatusPublisher.d.ts +18 -4
- package/dist/resolvers/AgentRunStatusPublisher.d.ts.map +1 -1
- package/dist/resolvers/AgentRunStatusPublisher.js +32 -8
- package/dist/resolvers/AgentRunStatusPublisher.js.map +1 -1
- package/dist/resolvers/AgentSessionResolver.d.ts +10 -4
- package/dist/resolvers/AgentSessionResolver.d.ts.map +1 -1
- package/dist/resolvers/AgentSessionResolver.js +44 -17
- package/dist/resolvers/AgentSessionResolver.js.map +1 -1
- package/dist/resolvers/AutotagPipelineResolver.d.ts.map +1 -1
- package/dist/resolvers/AutotagPipelineResolver.js +2 -1
- package/dist/resolvers/AutotagPipelineResolver.js.map +1 -1
- package/dist/resolvers/ConversationRunEventsResolver.d.ts.map +1 -1
- package/dist/resolvers/ConversationRunEventsResolver.js +2 -0
- package/dist/resolvers/ConversationRunEventsResolver.js.map +1 -1
- package/dist/resolvers/EntityCommunicationsResolver.d.ts +13 -1
- package/dist/resolvers/EntityCommunicationsResolver.d.ts.map +1 -1
- package/dist/resolvers/EntityCommunicationsResolver.js +50 -14
- package/dist/resolvers/EntityCommunicationsResolver.js.map +1 -1
- package/dist/resolvers/ExecuteRemoteOperationResolver.d.ts +6 -0
- package/dist/resolvers/ExecuteRemoteOperationResolver.d.ts.map +1 -1
- package/dist/resolvers/ExecuteRemoteOperationResolver.js +30 -7
- package/dist/resolvers/ExecuteRemoteOperationResolver.js.map +1 -1
- package/dist/resolvers/FetchEntityVectorsResolver.d.ts +28 -0
- package/dist/resolvers/FetchEntityVectorsResolver.d.ts.map +1 -1
- package/dist/resolvers/FetchEntityVectorsResolver.js +117 -21
- package/dist/resolvers/FetchEntityVectorsResolver.js.map +1 -1
- package/dist/resolvers/FileCategoryResolver.d.ts.map +1 -1
- package/dist/resolvers/FileCategoryResolver.js +1 -0
- package/dist/resolvers/FileCategoryResolver.js.map +1 -1
- package/dist/resolvers/FileResolver.d.ts +5 -0
- package/dist/resolvers/FileResolver.d.ts.map +1 -1
- package/dist/resolvers/FileResolver.js +13 -4
- package/dist/resolvers/FileResolver.js.map +1 -1
- package/dist/resolvers/GetDataResolver.d.ts.map +1 -1
- package/dist/resolvers/GetDataResolver.js +34 -13
- package/dist/resolvers/GetDataResolver.js.map +1 -1
- package/dist/resolvers/IntegrationDiscoveryResolver.d.ts +401 -11
- package/dist/resolvers/IntegrationDiscoveryResolver.d.ts.map +1 -1
- package/dist/resolvers/IntegrationDiscoveryResolver.js +2713 -1290
- package/dist/resolvers/IntegrationDiscoveryResolver.js.map +1 -1
- package/dist/resolvers/MCPResolver.d.ts.map +1 -1
- package/dist/resolvers/MCPResolver.js +13 -2
- package/dist/resolvers/MCPResolver.js.map +1 -1
- package/dist/resolvers/MergeRecordsResolver.d.ts +8 -1
- package/dist/resolvers/MergeRecordsResolver.d.ts.map +1 -1
- package/dist/resolvers/MergeRecordsResolver.js +31 -3
- package/dist/resolvers/MergeRecordsResolver.js.map +1 -1
- package/dist/resolvers/PipelineProgressResolver.d.ts +6 -0
- package/dist/resolvers/PipelineProgressResolver.d.ts.map +1 -1
- package/dist/resolvers/PipelineProgressResolver.js +5 -3
- package/dist/resolvers/PipelineProgressResolver.js.map +1 -1
- package/dist/resolvers/QueryResolver.d.ts.map +1 -1
- package/dist/resolvers/QueryResolver.js +20 -6
- package/dist/resolvers/QueryResolver.js.map +1 -1
- package/dist/resolvers/QuerySystemUserResolver.d.ts +38 -0
- package/dist/resolvers/QuerySystemUserResolver.d.ts.map +1 -1
- package/dist/resolvers/QuerySystemUserResolver.js +184 -88
- package/dist/resolvers/QuerySystemUserResolver.js.map +1 -1
- package/dist/resolvers/RSUResolver.d.ts.map +1 -1
- package/dist/resolvers/RSUResolver.js +12 -0
- package/dist/resolvers/RSUResolver.js.map +1 -1
- package/dist/resolvers/RealtimeBridgeResolver.d.ts.map +1 -1
- package/dist/resolvers/RealtimeBridgeResolver.js +1 -0
- package/dist/resolvers/RealtimeBridgeResolver.js.map +1 -1
- package/dist/resolvers/RealtimeClientSessionResolver.d.ts +22 -2
- package/dist/resolvers/RealtimeClientSessionResolver.d.ts.map +1 -1
- package/dist/resolvers/RealtimeClientSessionResolver.js +118 -33
- package/dist/resolvers/RealtimeClientSessionResolver.js.map +1 -1
- package/dist/resolvers/RemoteBrowserActionResolver.d.ts +62 -10
- package/dist/resolvers/RemoteBrowserActionResolver.d.ts.map +1 -1
- package/dist/resolvers/RemoteBrowserActionResolver.js +224 -39
- package/dist/resolvers/RemoteBrowserActionResolver.js.map +1 -1
- package/dist/resolvers/RunAIAgentResolver.d.ts +80 -16
- package/dist/resolvers/RunAIAgentResolver.d.ts.map +1 -1
- package/dist/resolvers/RunAIAgentResolver.js +388 -125
- package/dist/resolvers/RunAIAgentResolver.js.map +1 -1
- package/dist/resolvers/RunAIPromptResolver.d.ts +5 -3
- package/dist/resolvers/RunAIPromptResolver.d.ts.map +1 -1
- package/dist/resolvers/RunAIPromptResolver.js +19 -18
- package/dist/resolvers/RunAIPromptResolver.js.map +1 -1
- package/dist/resolvers/RunTemplateResolver.d.ts.map +1 -1
- package/dist/resolvers/RunTemplateResolver.js +7 -5
- package/dist/resolvers/RunTemplateResolver.js.map +1 -1
- package/dist/resolvers/RunTestResolver.d.ts.map +1 -1
- package/dist/resolvers/RunTestResolver.js +3 -1
- package/dist/resolvers/RunTestResolver.js.map +1 -1
- package/dist/resolvers/SyncDataResolver.d.ts.map +1 -1
- package/dist/resolvers/SyncDataResolver.js +4 -0
- package/dist/resolvers/SyncDataResolver.js.map +1 -1
- package/dist/resolvers/TestQuerySQLResolver.d.ts.map +1 -1
- package/dist/resolvers/TestQuerySQLResolver.js +1 -0
- package/dist/resolvers/TestQuerySQLResolver.js.map +1 -1
- package/dist/resolvers/TransactionGroupResolver.d.ts +17 -2
- package/dist/resolvers/TransactionGroupResolver.d.ts.map +1 -1
- package/dist/resolvers/TransactionGroupResolver.js +60 -15
- package/dist/resolvers/TransactionGroupResolver.js.map +1 -1
- package/dist/resolvers/UserViewResolver.d.ts +1 -1
- package/dist/resolvers/UserViewResolver.d.ts.map +1 -1
- package/dist/resolvers/UserViewResolver.js +2 -1
- package/dist/resolvers/UserViewResolver.js.map +1 -1
- package/dist/resolvers/meetingRecordingRegistration.d.ts.map +1 -1
- package/dist/resolvers/meetingRecordingRegistration.js +2 -0
- package/dist/resolvers/meetingRecordingRegistration.js.map +1 -1
- package/dist/rest/EntityCRUDHandler.d.ts +6 -0
- package/dist/rest/EntityCRUDHandler.d.ts.map +1 -1
- package/dist/rest/EntityCRUDHandler.js +19 -5
- package/dist/rest/EntityCRUDHandler.js.map +1 -1
- package/dist/rest/MediaAccessKeys.d.ts.map +1 -1
- package/dist/rest/MediaAccessKeys.js +6 -2
- package/dist/rest/MediaAccessKeys.js.map +1 -1
- package/dist/rest/OAuthCallbackHandler.d.ts.map +1 -1
- package/dist/rest/OAuthCallbackHandler.js +11 -5
- package/dist/rest/OAuthCallbackHandler.js.map +1 -1
- package/dist/rest/RESTEndpointHandler.d.ts.map +1 -1
- package/dist/rest/RESTEndpointHandler.js +8 -5
- package/dist/rest/RESTEndpointHandler.js.map +1 -1
- package/dist/rest/RealtimeRecordingHandler.d.ts +3 -3
- package/dist/rest/RealtimeRecordingHandler.d.ts.map +1 -1
- package/dist/rest/RealtimeRecordingHandler.js +6 -8
- package/dist/rest/RealtimeRecordingHandler.js.map +1 -1
- package/dist/rest/ViewOperationsHandler.d.ts +6 -0
- package/dist/rest/ViewOperationsHandler.d.ts.map +1 -1
- package/dist/rest/ViewOperationsHandler.js +24 -6
- package/dist/rest/ViewOperationsHandler.js.map +1 -1
- package/dist/rest/setupRESTEndpoints.d.ts +3 -1
- package/dist/rest/setupRESTEndpoints.d.ts.map +1 -1
- package/dist/rest/setupRESTEndpoints.js +11 -2
- package/dist/rest/setupRESTEndpoints.js.map +1 -1
- package/dist/serverRoleConfigUnits.d.ts +29 -0
- package/dist/serverRoleConfigUnits.d.ts.map +1 -0
- package/dist/serverRoleConfigUnits.js +33 -0
- package/dist/serverRoleConfigUnits.js.map +1 -0
- package/dist/services/DurableEntityActionTaskSubmitter.d.ts.map +1 -1
- package/dist/services/DurableEntityActionTaskSubmitter.js +6 -1
- package/dist/services/DurableEntityActionTaskSubmitter.js.map +1 -1
- package/dist/services/TaskGraphActionRunner.d.ts.map +1 -1
- package/dist/services/TaskGraphActionRunner.js +2 -26
- package/dist/services/TaskGraphActionRunner.js.map +1 -1
- package/dist/services/TaskGraphAgentRunner.d.ts +6 -0
- package/dist/services/TaskGraphAgentRunner.d.ts.map +1 -1
- package/dist/services/TaskGraphAgentRunner.js +38 -0
- package/dist/services/TaskGraphAgentRunner.js.map +1 -1
- package/dist/services/TaskGraphContinuationDeliverer.d.ts +5 -0
- package/dist/services/TaskGraphContinuationDeliverer.d.ts.map +1 -1
- package/dist/services/TaskGraphContinuationDeliverer.js +43 -15
- package/dist/services/TaskGraphContinuationDeliverer.js.map +1 -1
- package/dist/services/WorkQueueHostService.d.ts +2 -1
- package/dist/services/WorkQueueHostService.d.ts.map +1 -1
- package/dist/services/WorkQueueHostService.js +19 -4
- package/dist/services/WorkQueueHostService.js.map +1 -1
- package/dist/services/workQueueConfig.d.ts +2 -2
- package/dist/services/workQueueConfig.js +5 -5
- package/dist/services/workQueueConfig.js.map +1 -1
- package/dist/sharedCache.js +1 -1
- package/dist/sharedCache.js.map +1 -1
- package/dist/types.d.ts +40 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +98 -98
- package/src/__tests__/APIKeyScopeAuth.test.ts +4 -8
- package/src/__tests__/ActionResolver.fieldSecurity.test.ts +237 -0
- package/src/__tests__/ActiveOperations.test.ts +68 -0
- package/src/__tests__/AdhocQueryResolver.dialect.test.ts +137 -0
- package/src/__tests__/AgentRunStatusPublisher.test.ts +49 -0
- package/src/__tests__/AgentSessionResolver.ownership.test.ts +150 -0
- package/src/__tests__/AssertTargetConfigs.test.ts +75 -0
- package/src/__tests__/BatchApplyParity.test.ts +109 -0
- package/src/__tests__/BridgeHostInstance.test.ts +42 -0
- package/src/__tests__/CollectInactiveRowWarnings.test.ts +115 -0
- package/src/__tests__/ConnectionPause.test.ts +192 -0
- package/src/__tests__/ConnectionPauseResolver.test.ts +166 -0
- package/src/__tests__/ConnectionPauseSave.test.ts +143 -0
- package/src/__tests__/CustomColumnPromoterCompletion.test.ts +142 -0
- package/src/__tests__/CustomColumnPromoterOnePass.test.ts +15 -1
- package/src/__tests__/DeleteConnectionRemovesPerConnectionCatalog.test.ts +51 -0
- package/src/__tests__/DetachedDiscoveryStart.test.ts +65 -0
- package/src/__tests__/DurableEntityActionTaskSubmitter.test.ts +73 -0
- package/src/__tests__/EntityCommunicationsResolver.actingUser.test.ts +151 -0
- package/src/__tests__/EntityMapLifecycle.rekey.test.ts +252 -0
- package/src/__tests__/EvolutionActsOnWhatItDetects.test.ts +113 -0
- package/src/__tests__/ExecuteRemoteOperationResolver.test.ts +213 -0
- package/src/__tests__/FetchEntityVectorsResolver.test.ts +206 -3
- package/src/__tests__/FileResolver.fieldSecurity.test.ts +82 -0
- package/src/__tests__/HandoffOfferExpiry.test.ts +40 -0
- package/src/__tests__/IntegrationRunArtifactAuthorization.test.ts +126 -0
- package/src/__tests__/MagicLinkKeys.test.ts +102 -0
- package/src/__tests__/MediaAccessKeys.test.ts +57 -10
- package/src/__tests__/NewArrivalsDefaultDisabled.test.ts +50 -0
- package/src/__tests__/ObjectNamesByID.test.ts +176 -0
- package/src/__tests__/PipelineProgressResolver.filter.test.ts +58 -0
- package/src/__tests__/PostRestartMapsInCatalogScope.test.ts +146 -0
- package/src/__tests__/QuerySystemUserResolver.childRows.test.ts +80 -0
- package/src/__tests__/QuerySystemUserResolver.collision.test.ts +200 -0
- package/src/__tests__/QuerySystemUserResolver.fieldSecurity.test.ts +49 -0
- package/src/__tests__/QuerySystemUserResolver.permissions.test.ts +132 -0
- package/src/__tests__/RESTEndpointHandler.test.ts +25 -0
- package/src/__tests__/RSUPostRestartProgress.test.ts +343 -0
- package/src/__tests__/RSUProgressBridge.test.ts +188 -5
- package/src/__tests__/RSUStartupSweepWiring.test.ts +30 -0
- package/src/__tests__/ReactivateRefreshMessage.test.ts +10 -3
- package/src/__tests__/RealtimeClientSessionResolver.configTamper.test.ts +23 -3
- package/src/__tests__/RealtimeClientSessionResolver.test.ts +346 -46
- package/src/__tests__/{RefreshAdoptsNewColumns.test.ts → RefreshReportsNewColumns.test.ts} +25 -16
- package/src/__tests__/RemoteBrowserActionRecovery.test.ts +287 -0
- package/src/__tests__/RemoteBrowserActionResolver.goalRunLink.test.ts +3 -0
- package/src/__tests__/RemoteBrowserActionResolver.ownership.test.ts +100 -0
- package/src/__tests__/RemoteBrowserAudioStream.test.ts +3 -0
- package/src/__tests__/RemoteBrowserSnapshot.test.ts +3 -0
- package/src/__tests__/ResolverBase.clientOldValues.test.ts +344 -14
- package/src/__tests__/ResolverBase.deleteReturnProjection.test.ts +52 -0
- package/src/__tests__/ResolverBase.encryptedApiZeroReencrypt.test.ts +307 -0
- package/src/__tests__/ResolverBase.entityMessageRelay.test.ts +227 -0
- package/src/__tests__/ResolverBase.includeBinaryFields.test.ts +83 -1
- package/src/__tests__/ResolverBase.publishStatusUpdate.test.ts +68 -0
- package/src/__tests__/ResolverBase.userViewCacheAndDedup.test.ts +130 -0
- package/src/__tests__/RunAIAgentResolver.branch.test.ts +72 -13
- package/src/__tests__/RunAIAgentResolver.consultPredecessor.test.ts +289 -0
- package/src/__tests__/RunAIAgentResolver.conversationWriter.test.ts +210 -0
- package/src/__tests__/RunAIAgentResolver.fireAndForgetCompletion.test.ts +209 -0
- package/src/__tests__/RunAIAgentResolver.handoff.test.ts +649 -0
- package/src/__tests__/RunAIAgentResolver.historyFrom.test.ts +19 -27
- package/src/__tests__/RunAIAgentResolver.runDataGuard.test.ts +10 -2
- package/src/__tests__/RunAIAgentResolver.serverReply.test.ts +358 -0
- package/src/__tests__/RunAIAgentResolver.stoppedPredecessor.test.ts +91 -13
- package/src/__tests__/RunTemplateResolver.test.ts +35 -2
- package/src/__tests__/RunViewResolver.cacheCheckForwarding.test.ts +11 -0
- package/src/__tests__/SchemaEvolutionCustomColumns.test.ts +119 -0
- package/src/__tests__/SchemaRefreshLaunch.test.ts +24 -2
- package/src/__tests__/ScopedFieldsForBuild.test.ts +192 -0
- package/src/__tests__/SessionJanitor.test.ts +195 -4
- package/src/__tests__/SessionManager.test.ts +164 -0
- package/src/__tests__/TaskGraphActionRunner.durablePayload.test.ts +2 -2
- package/src/__tests__/TaskGraphAgentRunner.test.ts +272 -16
- package/src/__tests__/TaskGraphContinuationDeliverer.test.ts +114 -3
- package/src/__tests__/TransactionGroupResolver.fieldSecurity.test.ts +199 -0
- package/src/__tests__/UserViewResolver.updateWhereClause.test.ts +15 -0
- package/src/__tests__/ViewOperationsHandler.test.ts +9 -7
- package/src/__tests__/WidgetSessionService.test.ts +583 -4
- package/src/__tests__/WorkQueueHostService.test.ts +25 -7
- package/src/__tests__/apiRootBoot.test.ts +1 -1
- package/src/__tests__/backgroundSweepConfigUnits.test.ts +153 -0
- package/src/__tests__/buildMagicLinkSessionUser.test.ts +96 -0
- package/src/__tests__/cacheBroadcastProviders.test.ts +403 -0
- package/src/__tests__/cacheInvalidationRecordData.test.ts +45 -0
- package/src/__tests__/contextRequestOrigin.test.ts +105 -0
- package/src/__tests__/conversationBrowsers.test.ts +62 -0
- package/src/__tests__/fieldSecurityFixtures.ts +91 -0
- package/src/__tests__/globalCors.test.ts +3 -3
- package/src/__tests__/localDevAuth.test.ts +196 -0
- package/src/__tests__/magicLinkExtensionCapabilities.test.ts +413 -0
- package/src/__tests__/orphanedConversationDetailReconciler.start.test.ts +82 -0
- package/src/__tests__/orphanedConversationDetailReconciler.test.ts +10 -0
- package/src/__tests__/ownedRealtimeSession.test.ts +14 -0
- package/src/__tests__/pushStatusResolver.filter.test.ts +57 -1
- package/src/__tests__/realtimeRecordingHandler.test.ts +24 -2
- package/src/__tests__/realtimeSessions/RealtimeSessionEventsResolver.test.ts +29 -1
- package/src/__tests__/realtimeSessions/ownedRealtimeSession.anonymous.test.ts +31 -0
- package/src/__tests__/realtimeSessions/ownedRealtimeSession.namedScoped.test.ts +37 -0
- package/src/__tests__/realtimeSessions/sessionAccess.test.ts +224 -7
- package/src/__tests__/realtimeSessions/sessionConfigStamps.test.ts +1 -1
- package/src/__tests__/realtimeSessions/verificationWorkflow.test.ts +25 -4
- package/src/__tests__/requestOrigin.test.ts +104 -0
- package/src/__tests__/resolverBase.cloudEventChangedFields.test.ts +157 -0
- package/src/__tests__/resolverBase.fieldSecurityTransport.test.ts +222 -0
- package/src/__tests__/resolverBase.fls.test.ts +146 -97
- package/src/__tests__/restTransport.fieldSecurity.test.ts +148 -0
- package/src/__tests__/runParamsTimeZone.test.ts +179 -0
- package/src/__tests__/runStreams.fieldSecurity.test.ts +100 -0
- package/src/__tests__/runViewProperties.test.ts +114 -0
- package/src/__tests__/scalabilityBenchmarks.test.ts +765 -0
- package/src/__tests__/scalabilityDatabaseIntegration.test.ts +207 -0
- package/src/__tests__/securityHardeningPr6034.test.ts +120 -0
- package/src/__tests__/sessionDeadline.test.ts +51 -0
- package/src/__tests__/sessionUserClone.test.ts +5 -1
- package/src/__tests__/sharedCache.test.ts +11 -0
- package/src/__tests__/startupSweepOrder.test.ts +40 -0
- package/src/__tests__/unifiedAuth.test.ts +101 -1
- package/src/__tests__/widgetGuestElevation.test.ts +2 -0
- package/src/agentSessions/BridgeHostInstance.ts +20 -5
- package/src/agentSessions/HandoffOfferExpiry.ts +18 -0
- package/src/agentSessions/ReturningVisitorRecap.ts +1 -0
- package/src/agentSessions/SessionJanitor.ts +95 -45
- package/src/agentSessions/SessionManager.ts +73 -20
- package/src/agentSessions/conversationBrowsers.ts +143 -0
- package/src/agentSessions/sessionDeadline.ts +81 -0
- package/src/auth/APIKeyScopeAuth.ts +5 -4
- package/src/auth/AuthProviderCatalogRouter.ts +3 -0
- package/src/auth/__tests__/loginEmailResolution.test.ts +67 -0
- package/src/auth/index.ts +56 -12
- package/src/auth/initializeProviders.ts +43 -1
- package/src/auth/localDevAuth.ts +528 -0
- package/src/auth/loginEmailResolution.ts +67 -0
- package/src/auth/magicLink/MagicLinkKeys.ts +147 -15
- package/src/auth/magicLink/MagicLinkRouter.ts +33 -6
- package/src/auth/magicLink/MagicLinkService.ts +250 -10
- package/src/auth/magicLink/index.ts +1 -1
- package/src/auth/magicLink/redeemLanding.ts +7 -4
- package/src/auth/magicLink/types.ts +38 -3
- package/src/auth/newUsers.ts +1 -0
- package/src/auth/sessionUserClone.ts +3 -2
- package/src/backgroundSweepConfigUnits.ts +213 -0
- package/src/broadcast/BaseCacheInvalidationBroadcastProvider.ts +674 -0
- package/src/broadcast/index.ts +5 -0
- package/src/broadcast/providers/AWSIoTCoreBroadcastProvider.ts +180 -0
- package/src/broadcast/providers/AzureWebPubSubBroadcastProvider.ts +182 -0
- package/src/broadcast/providers/GCPPubSubBroadcastProvider.ts +169 -0
- package/src/broadcast/providers/SequencedRoleBucketBroadcastProvider.ts +57 -0
- package/src/cache.ts +2 -1
- package/src/config.ts +138 -0
- package/src/context.ts +71 -14
- package/src/coreRoutes.ts +29 -7
- package/src/generated/graphql-schemas/__mj.ts +4145 -1193
- package/src/generic/CacheInvalidationResolver.ts +135 -78
- package/src/generic/OrphanedConversationDetailReconciler.ts +36 -3
- package/src/generic/PubSubManager.ts +54 -1
- package/src/generic/PushStatusResolver.ts +108 -11
- package/src/generic/ResolverBase.ts +635 -234
- package/src/generic/RunViewResolver.ts +176 -64
- package/src/generic/actionOutputFieldSecurity.ts +75 -0
- package/src/generic/fieldSecurityTransport.ts +62 -0
- package/src/index.ts +310 -85
- package/src/integration/ConnectionPause.ts +222 -0
- package/src/integration/CustomColumnPromoter.ts +129 -54
- package/src/integration/EntityMapLifecycle.ts +229 -6
- package/src/integration/InactiveRowWarnings.ts +50 -0
- package/src/integration/ObjectNamesByID.ts +97 -0
- package/src/integration/PostRestartIntrospect.ts +49 -0
- package/src/integration/RSUPostRestartProgress.ts +359 -0
- package/src/integration/RSUProgressBridge.ts +85 -2
- package/src/integration/RunArtifactAuthorization.ts +65 -0
- package/src/integration/SchemaRefreshLaunch.ts +12 -2
- package/src/integration/ScopedFieldsForBuild.ts +113 -0
- package/src/integration/TargetConfigGuard.ts +71 -0
- package/src/logging/variablesLoggingMiddleware.ts +59 -3
- package/src/realtimeSessions/README.md +7 -3
- package/src/realtimeSessions/SessionVerificationPortsBase.ts +1 -0
- package/src/realtimeSessions/ownedRealtimeSession.ts +16 -6
- package/src/realtimeSessions/sessionAccess.ts +211 -25
- package/src/realtimeSessions/sessionConfigStamps.ts +1 -1
- package/src/realtimeSessions/subscriptionAuthorization.ts +4 -2
- package/src/realtimeSessions/verificationWorkflow.ts +3 -1
- package/src/realtimeWidget/WidgetRouter.ts +22 -4
- package/src/realtimeWidget/WidgetSessionService.ts +254 -17
- package/src/realtimeWidget/host-identity.ts +1 -1
- package/src/realtimeWidget/visitorIdentity.ts +1 -0
- package/src/realtimeWidget/widgetCore.ts +34 -9
- package/src/realtimeWidget/widgetGuestElevation.ts +3 -1
- package/src/requestOrigin.ts +64 -0
- package/src/resolvers/ActionResolver.ts +78 -15
- package/src/resolvers/AdhocQueryResolver.ts +1 -0
- package/src/resolvers/AgentRunStatusPublisher.ts +36 -8
- package/src/resolvers/AgentSessionResolver.ts +50 -18
- package/src/resolvers/AutotagPipelineResolver.ts +2 -1
- package/src/resolvers/ConversationRunEventsResolver.ts +2 -0
- package/src/resolvers/EntityCommunicationsResolver.ts +56 -15
- package/src/resolvers/ExecuteRemoteOperationResolver.ts +41 -9
- package/src/resolvers/FetchEntityVectorsResolver.ts +132 -21
- package/src/resolvers/FileCategoryResolver.ts +1 -0
- package/src/resolvers/FileResolver.ts +14 -4
- package/src/resolvers/GetDataResolver.ts +35 -13
- package/src/resolvers/IntegrationDiscoveryResolver.ts +1570 -209
- package/src/resolvers/MCPResolver.ts +15 -2
- package/src/resolvers/MergeRecordsResolver.ts +23 -2
- package/src/resolvers/PipelineProgressResolver.ts +12 -3
- package/src/resolvers/QueryResolver.ts +20 -6
- package/src/resolvers/QuerySystemUserResolver.ts +207 -99
- package/src/resolvers/RSUResolver.ts +12 -0
- package/src/resolvers/RealtimeBridgeResolver.ts +1 -0
- package/src/resolvers/RealtimeClientSessionResolver.ts +144 -40
- package/src/resolvers/RemoteBrowserActionResolver.ts +252 -37
- package/src/resolvers/RunAIAgentResolver.ts +518 -163
- package/src/resolvers/RunAIPromptResolver.ts +18 -18
- package/src/resolvers/RunTemplateResolver.ts +9 -5
- package/src/resolvers/RunTestResolver.ts +3 -1
- package/src/resolvers/SyncDataResolver.ts +4 -0
- package/src/resolvers/TestQuerySQLResolver.ts +1 -0
- package/src/resolvers/TransactionGroupResolver.ts +66 -15
- package/src/resolvers/UserViewResolver.ts +2 -1
- package/src/resolvers/__tests__/GetDataResolver.tokens.test.ts +52 -0
- package/src/resolvers/__tests__/MergeRecordsResolver.test.ts +43 -0
- package/src/resolvers/meetingRecordingRegistration.ts +2 -0
- package/src/rest/EntityCRUDHandler.ts +22 -5
- package/src/rest/MediaAccessKeys.ts +6 -2
- package/src/rest/OAuthCallbackHandler.ts +13 -5
- package/src/rest/RESTEndpointHandler.ts +8 -5
- package/src/rest/RealtimeRecordingHandler.ts +9 -10
- package/src/rest/ViewOperationsHandler.ts +26 -7
- package/src/rest/setupRESTEndpoints.ts +11 -2
- package/src/serverRoleConfigUnits.ts +48 -0
- package/src/services/DurableEntityActionTaskSubmitter.ts +10 -2
- package/src/services/TaskGraphActionRunner.ts +2 -23
- package/src/services/TaskGraphAgentRunner.ts +43 -0
- package/src/services/TaskGraphContinuationDeliverer.ts +53 -20
- package/src/services/WorkQueueHostService.ts +26 -4
- package/src/services/workQueueConfig.ts +5 -5
- package/src/sharedCache.ts +1 -1
- package/src/types.ts +41 -1
- package/src/services/TaskOrchestration-Integration.md +0 -188
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
CreateRealtimeRecordingRouter, FINAL_TERMINAL_RECHECK_MS, REALTIME_RECORDING_MOUNT_PATH, type RealtimeRecordingRouterDeps,
|
|
26
26
|
} from '../rest/RealtimeRecordingHandler.js';
|
|
27
27
|
import { RealtimeSessionNotFoundError, RealtimeSessionOwnershipError } from '../realtimeSessions/ownedRealtimeSession.js';
|
|
28
|
+
import { AuthorizeSessionAccess } from '../realtimeSessions/sessionAccess.js';
|
|
28
29
|
import { RecordingAssemblyScheduler, type IRecordingAssemblyScheduler } from '../realtimeSessions/RecordingAssemblyScheduler.js';
|
|
29
30
|
|
|
30
31
|
const SESSION = '11111111-1111-4111-8111-111111111111';
|
|
@@ -135,6 +136,10 @@ class FakeLedger implements IRealtimeRecordingLedger {
|
|
|
135
136
|
throw new Error('not used by the routes');
|
|
136
137
|
}
|
|
137
138
|
|
|
139
|
+
public async StampFile(): Promise<{ RecordingStatus: string | null }> {
|
|
140
|
+
throw new Error('not used by the routes');
|
|
141
|
+
}
|
|
142
|
+
|
|
138
143
|
public async LoadShards(sessionID: string): Promise<LedgerShard[]> {
|
|
139
144
|
return [...this.shardsOf(sessionID).values()].sort((a, b) => a.Index - b.Index)
|
|
140
145
|
.map(s => ({ Index: s.Index, StartSample: s.StartSample, SampleCount: s.SampleCount, Data: s.Data }));
|
|
@@ -198,6 +203,7 @@ function callerLedger(inner: FakeLedger): IRealtimeRecordingLedger {
|
|
|
198
203
|
ClaimAssembly: id => inner.ClaimAssembly(id),
|
|
199
204
|
FinishAssembly: input => inner.FinishAssembly(input),
|
|
200
205
|
StampAssemblyGaps: () => inner.StampAssemblyGaps(),
|
|
206
|
+
StampFile: () => inner.StampFile(),
|
|
201
207
|
LoadShards: refuse,
|
|
202
208
|
LoadShardMetadata: refuse,
|
|
203
209
|
CountShardsBelow: refuse,
|
|
@@ -221,7 +227,7 @@ describe('realtime recording REST routes', () => {
|
|
|
221
227
|
const app = express();
|
|
222
228
|
app.use(REALTIME_RECORDING_MOUNT_PATH, CreateRealtimeRecordingRouter(deps));
|
|
223
229
|
server = await new Promise<Server>(resolve => {
|
|
224
|
-
const s = app.listen(0, () => resolve(s));
|
|
230
|
+
const s = app.listen(0, '127.0.0.1', () => resolve(s));
|
|
225
231
|
});
|
|
226
232
|
baseUrl = `http://127.0.0.1:${(server.address() as AddressInfo).port}${REALTIME_RECORDING_MOUNT_PATH}`;
|
|
227
233
|
}
|
|
@@ -264,11 +270,19 @@ describe('realtime recording REST routes', () => {
|
|
|
264
270
|
const user = {
|
|
265
271
|
ID: id,
|
|
266
272
|
IsMagicLinkAnonymous: req.header('x-test-anonymous') === 'true',
|
|
273
|
+
AnonymousVisitorID: scope ?? undefined,
|
|
267
274
|
MagicLinkScope: scope ? { ResourceID: scope } : undefined,
|
|
268
275
|
};
|
|
269
276
|
return id ? { ContextUser: user as unknown as UserInfo, Provider: {} as unknown as DatabaseProviderBase } : null;
|
|
270
277
|
},
|
|
271
|
-
|
|
278
|
+
// The real scope rule over this test's conversation rows (no database behind them).
|
|
279
|
+
AuthorizeSession: async (session, contextUser) => {
|
|
280
|
+
const row = ledger.Sessions.get(session.ID);
|
|
281
|
+
return AuthorizeSessionAccess(
|
|
282
|
+
{ SessionUserID: session.UserID, ConversationExternalID: row?.ConversationExternalID ?? null, ConversationReadable: row?.ConversationExternalID !== undefined },
|
|
283
|
+
contextUser,
|
|
284
|
+
);
|
|
285
|
+
},
|
|
272
286
|
LoadOwnedSession: async (agentSessionId, contextUser) => {
|
|
273
287
|
const row = ledger.Sessions.get(agentSessionId);
|
|
274
288
|
if (!row) {
|
|
@@ -391,6 +405,14 @@ describe('realtime recording REST routes', () => {
|
|
|
391
405
|
expect((await post(`/${SESSION}/end?lastShardIndex=0&capturedSamples=${SHARD_SAMPLES}`, null, OWNER_ID, headers)).status).toBe(200);
|
|
392
406
|
});
|
|
393
407
|
|
|
408
|
+
it('accepts a named owner holding a resource-scoped link on its own unstamped conversation, and refuses another stamp (#4931)', async () => {
|
|
409
|
+
const headers = { 'x-test-scope': 'res-1' };
|
|
410
|
+
addSession(SESSION, { ConversationExternalID: null });
|
|
411
|
+
expect((await post(`/${SESSION}/shard/0`, shardBytes(0), OWNER_ID, headers)).status).toBe(200);
|
|
412
|
+
addSession(SESSION, { ConversationExternalID: 'res-2' });
|
|
413
|
+
expect((await post(`/${SESSION}/shard/1`, shardBytes(1), OWNER_ID, headers)).status).toBe(403);
|
|
414
|
+
});
|
|
415
|
+
|
|
394
416
|
it('leaves a named owner (no scope, not anonymous) unaffected', async () => {
|
|
395
417
|
expect((await postShard(0)).status).toBe(200);
|
|
396
418
|
});
|
|
@@ -27,7 +27,12 @@ function contextFor(user: Partial<UserInfo> & { ID: string }): RealtimeSessionEv
|
|
|
27
27
|
|
|
28
28
|
const named = (id: string) => contextFor({ ID: id });
|
|
29
29
|
const guest = (id: string, scope?: string) =>
|
|
30
|
-
contextFor({
|
|
30
|
+
contextFor({
|
|
31
|
+
ID: id,
|
|
32
|
+
IsMagicLinkAnonymous: true,
|
|
33
|
+
AnonymousVisitorID: scope,
|
|
34
|
+
MagicLinkScope: scope ? { ResourceID: scope } : undefined,
|
|
35
|
+
} as Partial<UserInfo> & { ID: string });
|
|
31
36
|
|
|
32
37
|
function event(over: Partial<RealtimeSessionEventTopicPayload> = {}): RealtimeSessionEventTopicPayload {
|
|
33
38
|
return {
|
|
@@ -75,6 +80,18 @@ describe('RealtimeSessionEventsFilter (per-event gate)', () => {
|
|
|
75
80
|
});
|
|
76
81
|
});
|
|
77
82
|
|
|
83
|
+
describe('a named user holding a resource-scoped magic link (#4931)', () => {
|
|
84
|
+
const namedScoped = (scope: string) => contextFor({ ID: OWNER, MagicLinkScope: { ResourceID: scope } } as Partial<UserInfo> & { ID: string });
|
|
85
|
+
|
|
86
|
+
it('delivers its own session\'s events when the conversation carries no scope stamp', () => {
|
|
87
|
+
expect(filter(event({ ScopeKey: null }), SESSION_ID, namedScoped('res-1'))).toBe(true);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('does not deliver events of a session stamped with its other link\'s scope', () => {
|
|
91
|
+
expect(filter(event({ ScopeKey: 'res-2' }), SESSION_ID, namedScoped('res-1'))).toBe(false);
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
|
|
78
95
|
it('fails closed on a missing connection identity, owner or argument', () => {
|
|
79
96
|
expect(filter(event(), SESSION_ID, undefined)).toBe(false);
|
|
80
97
|
expect(filter(event(), SESSION_ID, { userPayload: undefined })).toBe(false);
|
|
@@ -98,6 +115,17 @@ describe('AuthorizeRealtimeSessionSubscription (subscribe-time gate)', () => {
|
|
|
98
115
|
expect(d.LoadSession).toHaveBeenCalledWith(SESSION_ID, expect.objectContaining({ ID: OWNER }), expect.anything());
|
|
99
116
|
});
|
|
100
117
|
|
|
118
|
+
it('lets a named scoped owner subscribe to its session on a readable, unstamped conversation, and refuses it when unreadable (#4931)', async () => {
|
|
119
|
+
const namedScoped = contextFor({ ID: OWNER, MagicLinkScope: { ResourceID: 'res-1' } } as Partial<UserInfo> & { ID: string });
|
|
120
|
+
const load = (readable: boolean): SubscriptionAuthorizationDeps => ({
|
|
121
|
+
LoadSession: vi.fn(async () =>
|
|
122
|
+
({ Session: { ID: SESSION_ID, UserID: OWNER }, ConversationExternalID: null, ConversationReadable: readable } as unknown as LoadedSessionForAccess)),
|
|
123
|
+
GetProvider: () => ({}) as IMetadataProvider,
|
|
124
|
+
});
|
|
125
|
+
await expect(AuthorizeRealtimeSessionSubscription({ agentSessionId: SESSION_ID }, namedScoped, load(true))).resolves.toBe(SESSION_ID);
|
|
126
|
+
await expect(AuthorizeRealtimeSessionSubscription({ agentSessionId: SESSION_ID }, namedScoped, load(false))).rejects.toThrow('Realtime session not found.');
|
|
127
|
+
});
|
|
128
|
+
|
|
101
129
|
it('refuses a non-owner with the uniform not-found message', async () => {
|
|
102
130
|
await expect(AuthorizeRealtimeSessionSubscription({ agentSessionId: SESSION_ID }, named(STRANGER), deps({ UserID: OWNER, ExternalID: null }))).rejects.toThrow('Realtime session not found.');
|
|
103
131
|
});
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
+
import type { IMetadataProvider, UserInfo } from '@memberjunction/core';
|
|
3
|
+
import { LoadOwnedRealtimeSession, RealtimeSessionOwnershipError } from '../../realtimeSessions/ownedRealtimeSession.js';
|
|
4
|
+
|
|
5
|
+
// Fixture UUIDs are assembled at runtime so the brief itself carries no record id.
|
|
6
|
+
const uuid = (a: string, b: string) => [a.repeat(8), b.repeat(4), '4' + b.repeat(3), '8' + b.repeat(3), b.repeat(12)].join('-');
|
|
7
|
+
const ANON = uuid('A', '0');
|
|
8
|
+
const SESSION = uuid('1', '1');
|
|
9
|
+
const CONVERSATION = uuid('2', '2');
|
|
10
|
+
const guest = (scope: string) =>
|
|
11
|
+
({ ID: ANON, IsMagicLinkAnonymous: true, AnonymousVisitorID: scope, MagicLinkScope: { ResourceID: scope } } as unknown as UserInfo);
|
|
12
|
+
|
|
13
|
+
/** A session owned by the shared Anonymous user; its conversation is stamped with visitor 1's scope. */
|
|
14
|
+
function provider(): IMetadataProvider {
|
|
15
|
+
return {
|
|
16
|
+
GetEntityObject: vi.fn(async (entity: string) =>
|
|
17
|
+
entity === 'MJ: AI Agent Sessions'
|
|
18
|
+
? { UserID: ANON, ConversationID: CONVERSATION, Load: vi.fn(async () => true) }
|
|
19
|
+
: { ExternalID: 'scope-visitor-1', Load: vi.fn(async () => true) }),
|
|
20
|
+
} as unknown as IMetadataProvider;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
describe('LoadOwnedRealtimeSession with two anonymous visitors', () => {
|
|
24
|
+
it('allows the visitor whose scope matches', async () => {
|
|
25
|
+
await expect(LoadOwnedRealtimeSession(SESSION, guest('scope-visitor-1'), provider())).resolves.toBeDefined();
|
|
26
|
+
});
|
|
27
|
+
it('refuses a second anonymous visitor (same Anonymous user id, different scope)', async () => {
|
|
28
|
+
await expect(LoadOwnedRealtimeSession(SESSION, guest('scope-visitor-2'), provider()))
|
|
29
|
+
.rejects.toBeInstanceOf(RealtimeSessionOwnershipError);
|
|
30
|
+
});
|
|
31
|
+
});
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
+
import type { IMetadataProvider, UserInfo } from '@memberjunction/core';
|
|
3
|
+
import { LoadOwnedRealtimeSession, RealtimeSessionOwnershipError } from '../../realtimeSessions/ownedRealtimeSession.js';
|
|
4
|
+
|
|
5
|
+
// Fixture UUIDs are assembled at runtime so no literal record id appears in the source.
|
|
6
|
+
const uuid = (a: string, b: string) => [a.repeat(8), b.repeat(4), '4' + b.repeat(3), '8' + b.repeat(3), b.repeat(12)].join('-');
|
|
7
|
+
const NAMED = uuid('B', '1');
|
|
8
|
+
const SESSION = uuid('1', '1');
|
|
9
|
+
const CONVERSATION = uuid('2', '2');
|
|
10
|
+
|
|
11
|
+
/** A named magic-link user (found by email) holding a link scoped to `scope`. */
|
|
12
|
+
const namedScoped = (scope: string) => ({ ID: NAMED, IsMagicLinkAnonymous: false, MagicLinkScope: { ResourceID: scope } } as unknown as UserInfo);
|
|
13
|
+
|
|
14
|
+
/** The named user's own session; its conversation loads with `externalID`, or not at all when `readable` is false. */
|
|
15
|
+
function provider(externalID: string | null, readable = true): IMetadataProvider {
|
|
16
|
+
return {
|
|
17
|
+
GetEntityObject: vi.fn(async (entity: string) =>
|
|
18
|
+
entity === 'MJ: AI Agent Sessions'
|
|
19
|
+
? { UserID: NAMED, ConversationID: CONVERSATION, Load: vi.fn(async () => true) }
|
|
20
|
+
: { ExternalID: externalID, Load: vi.fn(async () => readable) }),
|
|
21
|
+
} as unknown as IMetadataProvider;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
describe('LoadOwnedRealtimeSession for a named user with a resource-scoped link', () => {
|
|
25
|
+
it('allows its own session on a conversation it can read that carries no scope stamp (one started from the Conversations app)', async () => {
|
|
26
|
+
await expect(LoadOwnedRealtimeSession(SESSION, namedScoped('res-1'), provider(null))).resolves.toBeDefined();
|
|
27
|
+
});
|
|
28
|
+
it('allows its own session on a conversation stamped with the same scope', async () => {
|
|
29
|
+
await expect(LoadOwnedRealtimeSession(SESSION, namedScoped('res-1'), provider('res-1'))).resolves.toBeDefined();
|
|
30
|
+
});
|
|
31
|
+
it('refuses its own session on a conversation stamped with another scope (a session from its other link)', async () => {
|
|
32
|
+
await expect(LoadOwnedRealtimeSession(SESSION, namedScoped('res-2'), provider('res-1'))).rejects.toBeInstanceOf(RealtimeSessionOwnershipError);
|
|
33
|
+
});
|
|
34
|
+
it('refuses when it cannot read the conversation (fail closed)', async () => {
|
|
35
|
+
await expect(LoadOwnedRealtimeSession(SESSION, namedScoped('res-1'), provider(null, false))).rejects.toBeInstanceOf(RealtimeSessionOwnershipError);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { describe, it, expect, vi } from 'vitest';
|
|
2
2
|
import type { IMetadataProvider, UserInfo } from '@memberjunction/core';
|
|
3
|
-
import {
|
|
3
|
+
import type { MJAIAgentSessionEntity } from '@memberjunction/core-entities';
|
|
4
|
+
import { AuthorizeSessionAccess, AuthorizeConversationTurn, AuthorizeAnonymousRoomSessions, LoadSessionForAccess, LoadSessionConversationScope, LoadConversationScope, AuthorizeLoadedSession } from '../../realtimeSessions/sessionAccess.js';
|
|
4
5
|
|
|
5
6
|
const OWNER = 'AAAAAAAA-0000-4000-8000-000000000001';
|
|
6
7
|
const OTHER = 'AAAAAAAA-0000-4000-8000-000000000002';
|
|
@@ -27,27 +28,57 @@ describe('AuthorizeSessionAccess', () => {
|
|
|
27
28
|
expect(AuthorizeSessionAccess({ SessionUserID: OWNER, ConversationExternalID: null }, { ID: '' })).toEqual({ Allowed: false, Reason: 'not_owner' });
|
|
28
29
|
});
|
|
29
30
|
|
|
30
|
-
describe('anonymous
|
|
31
|
-
const guest = (
|
|
31
|
+
describe('anonymous visitors (one shared Anonymous user, per-visitor AnonymousVisitorID)', () => {
|
|
32
|
+
const guest = (visitorId?: string, resourceScope?: string) => ({
|
|
33
|
+
ID: OWNER,
|
|
34
|
+
IsMagicLinkAnonymous: true,
|
|
35
|
+
AnonymousVisitorID: visitorId,
|
|
36
|
+
MagicLinkScope: resourceScope ? { ResourceID: resourceScope } : visitorId ? { ResourceID: visitorId } : undefined,
|
|
37
|
+
});
|
|
32
38
|
|
|
33
|
-
it('allows a
|
|
39
|
+
it('allows a visitor whose AnonymousVisitorID matches the conversation ExternalID', () => {
|
|
34
40
|
expect(AuthorizeSessionAccess({ SessionUserID: OWNER, ConversationExternalID: 'scope-1' }, guest('scope-1'))).toEqual({ Allowed: true });
|
|
35
41
|
});
|
|
36
42
|
|
|
37
|
-
it('refuses a different guest (same Anonymous user id, different
|
|
43
|
+
it('refuses a different widget guest (same Anonymous user id, different visitor id) — the cross-guest leak', () => {
|
|
38
44
|
expect(AuthorizeSessionAccess({ SessionUserID: OWNER, ConversationExternalID: 'scope-1' }, guest('scope-2'))).toEqual({
|
|
39
45
|
Allowed: false,
|
|
40
46
|
Reason: 'scope_mismatch',
|
|
41
47
|
});
|
|
42
48
|
});
|
|
43
49
|
|
|
44
|
-
it('refuses an anonymous principal with
|
|
45
|
-
expect(AuthorizeSessionAccess({ SessionUserID: OWNER, ConversationExternalID: 'scope-1' }, guest())).toEqual({
|
|
50
|
+
it('refuses an anonymous principal with neither a resource scope nor an AnonymousVisitorID', () => {
|
|
51
|
+
expect(AuthorizeSessionAccess({ SessionUserID: OWNER, ConversationExternalID: 'scope-1' }, guest(undefined))).toEqual({
|
|
46
52
|
Allowed: false,
|
|
47
53
|
Reason: 'scope_missing',
|
|
48
54
|
});
|
|
49
55
|
});
|
|
50
56
|
|
|
57
|
+
describe('identity per token kind: MagicLinkScope.ResourceID when the token carries one, else mj_sid', () => {
|
|
58
|
+
it('widget guest (ResourceID == mj_sid): matches its own sessionId', () => {
|
|
59
|
+
expect(AuthorizeSessionAccess({ SessionUserID: OWNER, ConversationExternalID: 'sid-w' }, guest('sid-w', 'sid-w'))).toEqual({ Allowed: true });
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('anonymous invite WITH a ResourceID: identity is the ResourceID, not its per-redemption mj_sid', () => {
|
|
63
|
+
const visitor = guest('sid-redemption-1', 'invite-scope-R');
|
|
64
|
+
expect(AuthorizeSessionAccess({ SessionUserID: OWNER, ConversationExternalID: 'invite-scope-R' }, visitor)).toEqual({ Allowed: true });
|
|
65
|
+
expect(AuthorizeSessionAccess({ SessionUserID: OWNER, ConversationExternalID: 'sid-redemption-1' }, visitor)).toEqual({
|
|
66
|
+
Allowed: false,
|
|
67
|
+
Reason: 'scope_mismatch',
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('anonymous invite WITHOUT a ResourceID: identity is mj_sid, so two redemptions are told apart', () => {
|
|
72
|
+
const first = { ID: OWNER, IsMagicLinkAnonymous: true, AnonymousVisitorID: 'sid-r1' };
|
|
73
|
+
const second = { ID: OWNER, IsMagicLinkAnonymous: true, AnonymousVisitorID: 'sid-r2' };
|
|
74
|
+
expect(AuthorizeSessionAccess({ SessionUserID: OWNER, ConversationExternalID: 'sid-r1' }, first)).toEqual({ Allowed: true });
|
|
75
|
+
expect(AuthorizeSessionAccess({ SessionUserID: OWNER, ConversationExternalID: 'sid-r1' }, second)).toEqual({
|
|
76
|
+
Allowed: false,
|
|
77
|
+
Reason: 'scope_mismatch',
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
|
|
51
82
|
it('refuses when the conversation carries no scope id (unreadable or unscoped)', () => {
|
|
52
83
|
expect(AuthorizeSessionAccess({ SessionUserID: OWNER, ConversationExternalID: null }, guest('scope-1'))).toEqual({ Allowed: false, Reason: 'scope_mismatch' });
|
|
53
84
|
expect(AuthorizeSessionAccess({ SessionUserID: OWNER, ConversationExternalID: undefined }, guest('scope-1'))).toEqual({ Allowed: false, Reason: 'scope_mismatch' });
|
|
@@ -68,6 +99,28 @@ describe('AuthorizeSessionAccess', () => {
|
|
|
68
99
|
expect(AuthorizeSessionAccess({ SessionUserID: OWNER, ConversationExternalID: 'other' }, scoped)).toEqual({ Allowed: false, Reason: 'scope_mismatch' });
|
|
69
100
|
});
|
|
70
101
|
|
|
102
|
+
describe('a NAMED principal with a resource scope on a conversation with no scope stamp', () => {
|
|
103
|
+
const scoped = { ID: OWNER, MagicLinkScope: { ResourceID: 'share-1' } };
|
|
104
|
+
|
|
105
|
+
it('is allowed when it could read the conversation (e.g. one started from the Conversations app)', () => {
|
|
106
|
+
expect(AuthorizeSessionAccess({ SessionUserID: OWNER, ConversationExternalID: null, ConversationReadable: true }, scoped)).toEqual({ Allowed: true });
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it('is refused when it could not read the conversation, or readability is unknown (fail closed)', () => {
|
|
110
|
+
expect(AuthorizeSessionAccess({ SessionUserID: OWNER, ConversationExternalID: null, ConversationReadable: false }, scoped)).toEqual({ Allowed: false, Reason: 'scope_mismatch' });
|
|
111
|
+
expect(AuthorizeSessionAccess({ SessionUserID: OWNER, ConversationExternalID: null }, scoped)).toEqual({ Allowed: false, Reason: 'scope_mismatch' });
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it('still refuses a conversation stamped with another scope, readable or not', () => {
|
|
115
|
+
expect(AuthorizeSessionAccess({ SessionUserID: OWNER, ConversationExternalID: 'share-2', ConversationReadable: true }, scoped)).toEqual({ Allowed: false, Reason: 'scope_mismatch' });
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it('does not extend to an anonymous visitor, which an unstamped conversation cannot identify', () => {
|
|
119
|
+
const visitor = { ID: OWNER, IsMagicLinkAnonymous: true, AnonymousVisitorID: 'sid-1' };
|
|
120
|
+
expect(AuthorizeSessionAccess({ SessionUserID: OWNER, ConversationExternalID: null, ConversationReadable: true }, visitor)).toEqual({ Allowed: false, Reason: 'scope_mismatch' });
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
|
|
71
124
|
it('does not require a scope of a named principal without one, whatever the conversation says', () => {
|
|
72
125
|
expect(AuthorizeSessionAccess({ SessionUserID: OWNER, ConversationExternalID: 'scope-1' }, { ID: OWNER })).toEqual({ Allowed: true });
|
|
73
126
|
});
|
|
@@ -99,6 +152,7 @@ describe('LoadSessionForAccess', () => {
|
|
|
99
152
|
const loaded = await LoadSessionForAccess(SESSION_ID, USER, provider);
|
|
100
153
|
expect(loaded?.Session.ID).toBe(SESSION_ID);
|
|
101
154
|
expect(loaded?.ConversationExternalID).toBe('scope-1');
|
|
155
|
+
expect(loaded?.ConversationReadable).toBe(true);
|
|
102
156
|
});
|
|
103
157
|
|
|
104
158
|
it('returns null for a malformed id without touching the database', async () => {
|
|
@@ -114,16 +168,179 @@ describe('LoadSessionForAccess', () => {
|
|
|
114
168
|
it('reports a null scope id when the session has no conversation', async () => {
|
|
115
169
|
const loaded = await LoadSessionForAccess(SESSION_ID, USER, fakeProvider({ session: { ID: SESSION_ID, UserID: OWNER, ConversationID: null } }));
|
|
116
170
|
expect(loaded?.ConversationExternalID).toBeNull();
|
|
171
|
+
expect(loaded?.ConversationReadable).toBe(false);
|
|
117
172
|
});
|
|
118
173
|
|
|
119
174
|
it('reports a null scope id when the conversation is unreadable, so a scoped caller is refused downstream', async () => {
|
|
120
175
|
const unreadable = await LoadSessionForAccess(SESSION_ID, USER, fakeProvider({ session: { ID: SESSION_ID, UserID: OWNER, ConversationID: CONVERSATION_ID }, conversation: null }));
|
|
121
176
|
expect(unreadable?.ConversationExternalID).toBeNull();
|
|
177
|
+
expect(unreadable?.ConversationReadable).toBe(false);
|
|
122
178
|
const throwing = await LoadSessionForAccess(
|
|
123
179
|
SESSION_ID,
|
|
124
180
|
USER,
|
|
125
181
|
fakeProvider({ session: { ID: SESSION_ID, UserID: OWNER, ConversationID: CONVERSATION_ID }, conversation: {}, conversationThrows: true }),
|
|
126
182
|
);
|
|
127
183
|
expect(throwing?.ConversationExternalID).toBeNull();
|
|
184
|
+
expect(throwing?.ConversationReadable).toBe(false);
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
it('reports a readable conversation that carries no scope stamp', async () => {
|
|
188
|
+
const loaded = await LoadSessionForAccess(SESSION_ID, USER, fakeProvider({ session: { ID: SESSION_ID, UserID: OWNER, ConversationID: CONVERSATION_ID }, conversation: { ExternalID: null } }));
|
|
189
|
+
expect(loaded?.ConversationExternalID).toBeNull();
|
|
190
|
+
expect(loaded?.ConversationReadable).toBe(true);
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
describe('LoadSessionConversationScope', () => {
|
|
195
|
+
const sessionWithConversation = { ID: SESSION_ID, UserID: OWNER, ConversationID: CONVERSATION_ID } as unknown as MJAIAgentSessionEntity;
|
|
196
|
+
|
|
197
|
+
it('reads the conversation for an unscoped named user too, so its result is the conversation as that user sees it', async () => {
|
|
198
|
+
const provider = fakeProvider({ conversation: { ExternalID: 'scope-1' } });
|
|
199
|
+
const scope = await LoadSessionConversationScope(sessionWithConversation, USER, provider);
|
|
200
|
+
expect(scope).toEqual({ ExternalID: 'scope-1', Readable: true });
|
|
201
|
+
expect(provider.GetEntityObject).toHaveBeenCalledTimes(1);
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
it('reads the conversation when the caller carries a scope identity', async () => {
|
|
205
|
+
const scopedUser = { ID: OWNER, MagicLinkScope: { ResourceID: 'scope-1' } } as unknown as UserInfo;
|
|
206
|
+
const provider = fakeProvider({ conversation: { ExternalID: 'scope-1' } });
|
|
207
|
+
const scope = await LoadSessionConversationScope(sessionWithConversation, scopedUser, provider);
|
|
208
|
+
expect(scope).toEqual({ ExternalID: 'scope-1', Readable: true });
|
|
209
|
+
expect(provider.GetEntityObject).toHaveBeenCalledTimes(1);
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
describe('LoadConversationScope (a conversation addressed directly, e.g. by a text agent turn)', () => {
|
|
214
|
+
it('reports the owner and scope id of a readable conversation', async () => {
|
|
215
|
+
const scope = await LoadConversationScope(CONVERSATION_ID, USER, fakeProvider({ conversation: { UserID: OWNER, ExternalID: 'scope-1' } }));
|
|
216
|
+
expect(scope).toEqual({ UserID: OWNER, ExternalID: 'scope-1', Readable: true });
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
it('reports an unreadable conversation (missing, refused by RLS, or a failed read) without an owner', async () => {
|
|
220
|
+
expect(await LoadConversationScope(CONVERSATION_ID, USER, fakeProvider({ conversation: null }))).toEqual({ UserID: null, ExternalID: null, Readable: false });
|
|
221
|
+
expect(await LoadConversationScope(CONVERSATION_ID, USER, fakeProvider({ conversation: {}, conversationThrows: true }))).toEqual({ UserID: null, ExternalID: null, Readable: false });
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
it('reports a null scope id for a readable conversation with no stamp', async () => {
|
|
225
|
+
const scope = await LoadConversationScope(CONVERSATION_ID, USER, fakeProvider({ conversation: { UserID: OWNER, ExternalID: null } }));
|
|
226
|
+
expect(scope).toEqual({ UserID: OWNER, ExternalID: null, Readable: true });
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
it('does not touch the database for an empty id', async () => {
|
|
230
|
+
const provider = fakeProvider({});
|
|
231
|
+
expect(await LoadConversationScope('', USER, provider)).toEqual({ UserID: null, ExternalID: null, Readable: false });
|
|
232
|
+
expect(provider.GetEntityObject).not.toHaveBeenCalled();
|
|
233
|
+
});
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
describe('AuthorizeConversationTurn (a text agent turn addressed by a message in the conversation, MJ#6032)', () => {
|
|
237
|
+
const ANON = 'AAAAAAAA-0000-4000-8000-00000000A0A0';
|
|
238
|
+
const visitor = (sid: string) => ({ ID: ANON, IsMagicLinkAnonymous: true, AnonymousVisitorID: sid, MagicLinkScope: { ResourceID: sid } }) as unknown as UserInfo;
|
|
239
|
+
|
|
240
|
+
it('allows a named principal without reading the conversation (its permissions already decided the turn)', async () => {
|
|
241
|
+
const provider = fakeProvider({});
|
|
242
|
+
expect(await AuthorizeConversationTurn(CONVERSATION_ID, { ID: OWNER } as UserInfo, provider)).toEqual({ Allowed: true });
|
|
243
|
+
expect(provider.GetEntityObject).not.toHaveBeenCalled();
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
it('allows the anonymous visitor whose scope id the conversation carries', async () => {
|
|
247
|
+
const provider = fakeProvider({ conversation: { UserID: ANON, ExternalID: 'sid-1' } });
|
|
248
|
+
expect(await AuthorizeConversationTurn(CONVERSATION_ID, visitor('sid-1'), provider)).toEqual({ Allowed: true });
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
it('refuses a second anonymous visitor — same shared user, different scope id (the UI-guest-role leak)', async () => {
|
|
252
|
+
const provider = fakeProvider({ conversation: { UserID: ANON, ExternalID: 'sid-1' } });
|
|
253
|
+
expect(await AuthorizeConversationTurn(CONVERSATION_ID, visitor('sid-2'), provider)).toEqual({ Allowed: false, Reason: 'scope_mismatch' });
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
it('refuses an anonymous visitor when the conversation cannot be read or carries no scope id', async () => {
|
|
257
|
+
expect(await AuthorizeConversationTurn(CONVERSATION_ID, visitor('sid-1'), fakeProvider({ conversation: null }))).toEqual({ Allowed: false, Reason: 'not_owner' });
|
|
258
|
+
expect(await AuthorizeConversationTurn(CONVERSATION_ID, visitor('sid-1'), fakeProvider({ conversation: { UserID: ANON, ExternalID: null } }))).toEqual({ Allowed: false, Reason: 'scope_mismatch' });
|
|
259
|
+
});
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
describe('AuthorizeAnonymousRoomSessions (who of the anonymous visitors owns a LiveKit room\'s agent session, MJ#6044)', () => {
|
|
263
|
+
const ANON = 'AAAAAAAA-0000-4000-8000-00000000A0A0';
|
|
264
|
+
const visitor = (sid: string) => ({ ID: ANON, IsMagicLinkAnonymous: true, AnonymousVisitorID: sid, MagicLinkScope: { ResourceID: sid } }) as unknown as UserInfo;
|
|
265
|
+
const roomSession = { ID: SESSION_ID, UserID: ANON, ConversationID: CONVERSATION_ID };
|
|
266
|
+
|
|
267
|
+
it("admits the visitor whose scope id the session's conversation carries", async () => {
|
|
268
|
+
const provider = fakeProvider({ session: roomSession, conversation: { UserID: ANON, ExternalID: 'sid-1' } });
|
|
269
|
+
expect(await AuthorizeAnonymousRoomSessions([SESSION_ID], visitor('sid-1'), provider)).toBe(true);
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
it('refuses another visitor — same shared user, different scope id', async () => {
|
|
273
|
+
const provider = fakeProvider({ session: roomSession, conversation: { UserID: ANON, ExternalID: 'sid-1' } });
|
|
274
|
+
expect(await AuthorizeAnonymousRoomSessions([SESSION_ID], visitor('sid-2'), provider)).toBe(false);
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
it('refuses when the session cannot be read as the caller', async () => {
|
|
278
|
+
expect(await AuthorizeAnonymousRoomSessions([SESSION_ID], visitor('sid-1'), fakeProvider({ session: null }))).toBe(false);
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
it('refuses without reading anything when there is no session or no provider', async () => {
|
|
282
|
+
const provider = fakeProvider({});
|
|
283
|
+
expect(await AuthorizeAnonymousRoomSessions([], visitor('sid-1'), provider)).toBe(false);
|
|
284
|
+
expect(await AuthorizeAnonymousRoomSessions([SESSION_ID], visitor('sid-1'), undefined)).toBe(false);
|
|
285
|
+
expect(provider.GetEntityObject).not.toHaveBeenCalled();
|
|
286
|
+
});
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
describe('AuthorizeLoadedSession', () => {
|
|
291
|
+
const principals: Array<[string, UserInfo]> = [
|
|
292
|
+
['named owner, no scope', { ID: OWNER } as UserInfo],
|
|
293
|
+
['named owner, scope-1', { ID: OWNER, MagicLinkScope: { ResourceID: 'scope-1' } } as unknown as UserInfo],
|
|
294
|
+
['named owner, scope-2', { ID: OWNER, MagicLinkScope: { ResourceID: 'scope-2' } } as unknown as UserInfo],
|
|
295
|
+
['anonymous, scope-1', { ID: OWNER, IsMagicLinkAnonymous: true, AnonymousVisitorID: 'scope-1', MagicLinkScope: { ResourceID: 'scope-1' } } as unknown as UserInfo],
|
|
296
|
+
['anonymous, scope-2', { ID: OWNER, IsMagicLinkAnonymous: true, AnonymousVisitorID: 'scope-2', MagicLinkScope: { ResourceID: 'scope-2' } } as unknown as UserInfo],
|
|
297
|
+
['anonymous, visitor id only', { ID: OWNER, IsMagicLinkAnonymous: true, AnonymousVisitorID: 'scope-1' } as unknown as UserInfo],
|
|
298
|
+
['anonymous, no scope', { ID: OWNER, IsMagicLinkAnonymous: true } as unknown as UserInfo],
|
|
299
|
+
['named non-owner', { ID: OTHER } as UserInfo],
|
|
300
|
+
];
|
|
301
|
+
const conversations: Array<[string, { conversationId: string | null; rows: Parameters<typeof fakeProvider>[0] }]> = [
|
|
302
|
+
['no conversation', { conversationId: null, rows: {} }],
|
|
303
|
+
['missing or refused', { conversationId: CONVERSATION_ID, rows: { conversation: null } }],
|
|
304
|
+
['read fails', { conversationId: CONVERSATION_ID, rows: { conversation: {}, conversationThrows: true } }],
|
|
305
|
+
['unstamped', { conversationId: CONVERSATION_ID, rows: { conversation: { ExternalID: null } } }],
|
|
306
|
+
['stamped scope-1', { conversationId: CONVERSATION_ID, rows: { conversation: { ExternalID: 'scope-1' } } }],
|
|
307
|
+
['stamped scope-2', { conversationId: CONVERSATION_ID, rows: { conversation: { ExternalID: 'scope-2' } } }],
|
|
308
|
+
];
|
|
309
|
+
|
|
310
|
+
for (const [principalName, principal] of principals) {
|
|
311
|
+
for (const [conversationName, { conversationId, rows }] of conversations) {
|
|
312
|
+
it(`decides as if it always read the conversation: ${principalName} × ${conversationName}`, async () => {
|
|
313
|
+
const session = { ID: SESSION_ID, UserID: OWNER, ConversationID: conversationId } as unknown as MJAIAgentSessionEntity;
|
|
314
|
+
const scope = await LoadConversationScope(conversationId, principal, fakeProvider(rows));
|
|
315
|
+
const alwaysRead = AuthorizeSessionAccess(
|
|
316
|
+
{ SessionUserID: session.UserID, ConversationExternalID: scope.ExternalID, ConversationReadable: scope.Readable },
|
|
317
|
+
principal,
|
|
318
|
+
);
|
|
319
|
+
expect(await AuthorizeLoadedSession(session, principal, fakeProvider(rows))).toEqual(alwaysRead);
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
const sessionWithConversation = { ID: SESSION_ID, UserID: OWNER, ConversationID: CONVERSATION_ID } as unknown as MJAIAgentSessionEntity;
|
|
325
|
+
const conversationReads = (provider: IMetadataProvider) =>
|
|
326
|
+
vi.mocked(provider.GetEntityObject).mock.calls.filter(([name]) => name === 'MJ: Conversations').length;
|
|
327
|
+
|
|
328
|
+
it('does not read the conversation for a named owner without a scope, the usual signed-in caller', async () => {
|
|
329
|
+
const provider = fakeProvider({ conversation: { ExternalID: 'scope-1' } });
|
|
330
|
+
expect(await AuthorizeLoadedSession(sessionWithConversation, USER, provider)).toEqual({ Allowed: true });
|
|
331
|
+
expect(conversationReads(provider)).toBe(0);
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
it('does not read the conversation for a caller who does not own the session', async () => {
|
|
335
|
+
const provider = fakeProvider({ conversation: { ExternalID: 'scope-1' } });
|
|
336
|
+
expect(await AuthorizeLoadedSession(sessionWithConversation, { ID: OTHER } as UserInfo, provider)).toEqual({ Allowed: false, Reason: 'not_owner' });
|
|
337
|
+
expect(conversationReads(provider)).toBe(0);
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
it('reads the conversation once for a caller with a scope identity', async () => {
|
|
341
|
+
const provider = fakeProvider({ conversation: { ExternalID: 'scope-1' } });
|
|
342
|
+
const guest = { ID: OWNER, IsMagicLinkAnonymous: true, AnonymousVisitorID: 'scope-1', MagicLinkScope: { ResourceID: 'scope-1' } } as unknown as UserInfo;
|
|
343
|
+
expect(await AuthorizeLoadedSession(sessionWithConversation, guest, provider)).toEqual({ Allowed: true });
|
|
344
|
+
expect(conversationReads(provider)).toBe(1);
|
|
128
345
|
});
|
|
129
346
|
});
|
|
@@ -117,7 +117,7 @@ describe('LoadInheritedVerifiedIdentity', () => {
|
|
|
117
117
|
|
|
118
118
|
it('refuses another anonymous guest (same Anonymous user, different scope) and accepts the same guest', async () => {
|
|
119
119
|
const prov = provider({ externalId: 'scope-A' });
|
|
120
|
-
const guest = (scope: string) => user({ IsMagicLinkAnonymous: true, MagicLinkScope: { ResourceID: scope } });
|
|
120
|
+
const guest = (scope: string) => user({ IsMagicLinkAnonymous: true, AnonymousVisitorID: scope, MagicLinkScope: { ResourceID: scope } });
|
|
121
121
|
expect(await LoadInheritedVerifiedIdentity(PRIOR, guest('scope-B'), prov)).toBeUndefined();
|
|
122
122
|
expect(await LoadInheritedVerifiedIdentity(PRIOR, guest('scope-A'), prov)).toEqual(VERIFIED);
|
|
123
123
|
});
|
|
@@ -96,6 +96,7 @@ class FakePorts implements VerificationPorts {
|
|
|
96
96
|
AgentSessionID: SESSION_ID,
|
|
97
97
|
OwnerUserID: OWNER,
|
|
98
98
|
ConversationExternalID: null,
|
|
99
|
+
ConversationReadable: false,
|
|
99
100
|
Status: 'Active',
|
|
100
101
|
ConfigRaw: JSON.stringify({ targetAgentID: 'target-1' }),
|
|
101
102
|
StartedAtMs: T0,
|
|
@@ -219,11 +220,17 @@ describe('RealtimeSessionVerificationWorkflow', () => {
|
|
|
219
220
|
it('refuses another anonymous guest sharing the Anonymous user (scope mismatch) and a scope-less anonymous caller', async () => {
|
|
220
221
|
ports.AddSession({ ConversationExternalID: 'scope-A' });
|
|
221
222
|
expect(
|
|
222
|
-
await workflow.RequestVerification(
|
|
223
|
+
await workflow.RequestVerification(
|
|
224
|
+
REQUEST,
|
|
225
|
+
principal({ IsMagicLinkAnonymous: true, AnonymousVisitorID: 'scope-B', MagicLinkScope: { ResourceID: 'scope-B' } }),
|
|
226
|
+
),
|
|
223
227
|
).toMatchObject({ ErrorCode: 'session_not_found' });
|
|
224
228
|
expect(await workflow.RequestVerification(REQUEST, principal({ IsMagicLinkAnonymous: true }))).toMatchObject({ ErrorCode: 'session_not_found' });
|
|
225
229
|
expect(
|
|
226
|
-
await workflow.RequestVerification(
|
|
230
|
+
await workflow.RequestVerification(
|
|
231
|
+
REQUEST,
|
|
232
|
+
principal({ IsMagicLinkAnonymous: true, AnonymousVisitorID: 'scope-A', MagicLinkScope: { ResourceID: 'scope-A' } }),
|
|
233
|
+
),
|
|
227
234
|
).toMatchObject({ Success: true });
|
|
228
235
|
});
|
|
229
236
|
|
|
@@ -232,6 +239,17 @@ describe('RealtimeSessionVerificationWorkflow', () => {
|
|
|
232
239
|
expect(await workflow.RequestVerification(REQUEST, principal())).toMatchObject({ ErrorCode: 'session_closed' });
|
|
233
240
|
});
|
|
234
241
|
|
|
242
|
+
it("lets a named owner holding a link scope use an unstamped conversation only when it can read that conversation", async () => {
|
|
243
|
+
// A conversation started outside any link carries no ExternalID. The owner's own row-level security
|
|
244
|
+
// decides: readable is allowed, unreadable is refused like a missing session.
|
|
245
|
+
const linkHolder = principal({ MagicLinkScope: { ResourceID: 'invite-scope-1' } });
|
|
246
|
+
ports.AddSession({ ConversationExternalID: null, ConversationReadable: false });
|
|
247
|
+
expect(await workflow.RequestVerification(REQUEST, linkHolder)).toMatchObject({ ErrorCode: 'session_not_found' });
|
|
248
|
+
|
|
249
|
+
ports.AddSession({ ConversationExternalID: null, ConversationReadable: true });
|
|
250
|
+
expect(await workflow.RequestVerification(REQUEST, linkHolder)).toMatchObject({ Success: true });
|
|
251
|
+
});
|
|
252
|
+
|
|
235
253
|
it('treats an already-verified session as success without sending anything', async () => {
|
|
236
254
|
await workflow.RequestVerification(REQUEST, principal());
|
|
237
255
|
const { code } = secretsFrom(ports);
|
|
@@ -362,7 +380,7 @@ describe('RealtimeSessionVerificationWorkflow', () => {
|
|
|
362
380
|
|
|
363
381
|
it('routes the event with the session scope so an anonymous guest\'s event reaches only that guest', async () => {
|
|
364
382
|
ports.AddSession({ ConversationExternalID: 'scope-A' });
|
|
365
|
-
const guest = principal({ IsMagicLinkAnonymous: true, MagicLinkScope: { ResourceID: 'scope-A' } });
|
|
383
|
+
const guest = principal({ IsMagicLinkAnonymous: true, AnonymousVisitorID: 'scope-A', MagicLinkScope: { ResourceID: 'scope-A' } });
|
|
366
384
|
await workflow.RequestVerification(REQUEST, guest);
|
|
367
385
|
await workflow.SubmitCode({ AgentSessionID: SESSION_ID, Code: secretsFrom(ports).code }, guest);
|
|
368
386
|
expect(ports.Published[0].routing.ScopeKey).toBe('scope-A');
|
|
@@ -445,7 +463,10 @@ describe('RealtimeSessionVerificationWorkflow', () => {
|
|
|
445
463
|
expect(await workflow.SubmitCode({ AgentSessionID: SESSION_ID, Code: code }, principal({ ID: STRANGER }))).toMatchObject({ ErrorCode: 'session_not_found' });
|
|
446
464
|
ports.AddSession({ ConversationExternalID: 'scope-A', ConfigRaw: ports.Sessions.get(SESSION_ID.toLowerCase())?.ConfigRaw ?? null });
|
|
447
465
|
expect(
|
|
448
|
-
await workflow.SubmitCode(
|
|
466
|
+
await workflow.SubmitCode(
|
|
467
|
+
{ AgentSessionID: SESSION_ID, Code: code },
|
|
468
|
+
principal({ IsMagicLinkAnonymous: true, AnonymousVisitorID: 'scope-B', MagicLinkScope: { ResourceID: 'scope-B' } }),
|
|
469
|
+
),
|
|
449
470
|
).toMatchObject({ ErrorCode: 'session_not_found' });
|
|
450
471
|
expect(ports.Published).toHaveLength(0);
|
|
451
472
|
});
|