@memberjunction/server 6.2.0-edge.3 → 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/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 +2378 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +123 -0
- package/dist/config.js.map +1 -1
- package/dist/context.d.ts +8 -0
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +14 -11
- package/dist/context.js.map +1 -1
- package/dist/generated/graphql-schemas/__mj.d.ts +135 -0
- package/dist/generated/graphql-schemas/__mj.d.ts.map +1 -1
- package/dist/generated/graphql-schemas/__mj.js +706 -0
- 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 +20 -4
- package/dist/generic/ResolverBase.d.ts.map +1 -1
- package/dist/generic/ResolverBase.js +39 -10
- package/dist/generic/ResolverBase.js.map +1 -1
- package/dist/generic/RunViewResolver.d.ts.map +1 -1
- package/dist/generic/RunViewResolver.js +4 -0
- package/dist/generic/RunViewResolver.js.map +1 -1
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +120 -131
- 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/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 +14 -1
- package/dist/resolvers/AdhocQueryResolver.d.ts.map +1 -1
- package/dist/resolvers/AdhocQueryResolver.js +21 -5
- package/dist/resolvers/AdhocQueryResolver.js.map +1 -1
- package/dist/resolvers/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/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/HumanHandoffResolver.d.ts.map +1 -1
- package/dist/resolvers/HumanHandoffResolver.js +7 -1
- package/dist/resolvers/HumanHandoffResolver.js.map +1 -1
- package/dist/resolvers/MCPResolver.d.ts.map +1 -1
- package/dist/resolvers/MCPResolver.js +9 -4
- package/dist/resolvers/MCPResolver.js.map +1 -1
- package/dist/resolvers/RealtimeBridgeResolver.d.ts +54 -2
- package/dist/resolvers/RealtimeBridgeResolver.d.ts.map +1 -1
- package/dist/resolvers/RealtimeBridgeResolver.js +155 -10
- package/dist/resolvers/RealtimeBridgeResolver.js.map +1 -1
- package/dist/resolvers/RealtimeClientSessionResolver.d.ts +155 -25
- package/dist/resolvers/RealtimeClientSessionResolver.d.ts.map +1 -1
- package/dist/resolvers/RealtimeClientSessionResolver.js +394 -90
- 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/agentVisionConsentAudit.d.ts +37 -0
- package/dist/resolvers/agentVisionConsentAudit.d.ts.map +1 -0
- package/dist/resolvers/agentVisionConsentAudit.js +63 -0
- package/dist/resolvers/agentVisionConsentAudit.js.map +1 -0
- package/dist/resolvers/avatarInputValidation.d.ts +40 -0
- package/dist/resolvers/avatarInputValidation.d.ts.map +1 -0
- package/dist/resolvers/avatarInputValidation.js +97 -0
- package/dist/resolvers/avatarInputValidation.js.map +1 -0
- package/dist/resolvers/currentUserRoles.d.ts +29 -0
- package/dist/resolvers/currentUserRoles.d.ts.map +1 -1
- package/dist/resolvers/currentUserRoles.js +30 -0
- package/dist/resolvers/currentUserRoles.js.map +1 -1
- package/dist/resolvers/meetings/meetingMutations.d.ts +6 -0
- package/dist/resolvers/meetings/meetingMutations.d.ts.map +1 -1
- package/dist/resolvers/meetings/meetingMutations.js +21 -0
- package/dist/resolvers/meetings/meetingMutations.js.map +1 -1
- package/dist/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/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 +6 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +97 -95
- package/src/__tests__/ActionResolver.authorization.test.ts +353 -0
- package/src/__tests__/AdhocQueryResolver.sqlAuthorizer.test.ts +104 -0
- package/src/__tests__/BridgeHostInstance.test.ts +232 -0
- package/src/__tests__/ClientToolRequestResolver.test.ts +116 -0
- package/src/__tests__/FetchEntityVectorsResolver.test.ts +285 -0
- package/src/__tests__/HostInstance.test.ts +84 -0
- package/src/__tests__/HumanHandoffResolver.test.ts +17 -0
- package/src/__tests__/MeetingResolver.test.ts +75 -1
- package/src/__tests__/RealtimeBridgeResolver.test.ts +415 -6
- package/src/__tests__/RealtimeClientSessionResolver.configTamper.test.ts +383 -0
- package/src/__tests__/RealtimeClientSessionResolver.test.ts +682 -58
- package/src/__tests__/RealtimeProxyServer.test.ts +16 -1
- package/src/__tests__/RealtimeRelay.test.ts +876 -0
- package/src/__tests__/RemoteBrowserActionResolver.goalRunLink.test.ts +129 -0
- package/src/__tests__/ResolverBase.aggregateScreen.test.ts +174 -0
- package/src/__tests__/ResolverBase.clientOldValues.test.ts +6 -3
- 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__/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__/actionAuthorization.test.ts +130 -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__/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__/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 +125 -0
- package/src/context.ts +15 -10
- package/src/generated/graphql-schemas/__mj.ts +496 -1
- package/src/generic/OrphanedConversationDetailReconciler.ts +3 -3
- package/src/generic/ResolverBase.ts +39 -9
- package/src/generic/RunViewResolver.ts +4 -0
- package/src/index.ts +132 -143
- package/src/isolatedProvider.ts +22 -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 +24 -6
- package/src/resolvers/CacheStatsResolver.ts +89 -2
- package/src/resolvers/ClientToolRequestResolver.ts +25 -7
- package/src/resolvers/FetchEntityVectorsResolver.ts +97 -2
- package/src/resolvers/HumanHandoffResolver.ts +8 -0
- package/src/resolvers/MCPResolver.ts +8 -5
- package/src/resolvers/RealtimeBridgeResolver.ts +163 -11
- package/src/resolvers/RealtimeClientSessionResolver.ts +501 -96
- 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/agentVisionConsentAudit.ts +82 -0
- package/src/resolvers/avatarInputValidation.ts +123 -0
- package/src/resolvers/currentUserRoles.ts +32 -1
- package/src/resolvers/meetings/meetingMutations.ts +21 -0
- package/src/services/TaskGraphContinuationDeliverer.ts +13 -7
- package/src/sharedCache.ts +302 -0
- package/src/types.ts +7 -0
|
@@ -93,8 +93,10 @@ export async function resolveWidgetGuestRunContext(
|
|
|
93
93
|
* A scoped anonymous session (`IsMagicLinkAnonymous` + `MagicLinkScope.ResourceID`) holds only the
|
|
94
94
|
* narrow relay grants its invite's role carries — deliberately NOT the AI run entities, whose rows
|
|
95
95
|
* leak the rendered system prompt. Unlike {@link resolveWidgetGuestRunContext} no widget instance is
|
|
96
|
-
* required:
|
|
97
|
-
*
|
|
96
|
+
* required: the realtime target is the session config's `targetAgentID`, which the owner can edit, so
|
|
97
|
+
* the relay re-checks `CanRun` on it for the CALLER before this elevation. Direct actions are refused
|
|
98
|
+
* for these callers before elevation, so only the delegated agent run and the run-entity writes
|
|
99
|
+
* execute as the system user.
|
|
98
100
|
*
|
|
99
101
|
* PUBLIC WEB-WIDGET guests are deliberately EXCLUDED (returned unchanged): their seeded role writes
|
|
100
102
|
* run rows under the guest principal, which the `Widget Guest: Own Agent Runs` RLS read filter
|
|
@@ -126,6 +128,36 @@ export function ResolveScopedAnonymousRunUser(contextUser: UserInfo): UserInfo {
|
|
|
126
128
|
return systemUser;
|
|
127
129
|
}
|
|
128
130
|
|
|
131
|
+
/**
|
|
132
|
+
* The principal a client-direct call's consolidated RECORDING STORE runs as, once the caller has
|
|
133
|
+
* already passed the session-ownership and consent gates (#5195).
|
|
134
|
+
*
|
|
135
|
+
* The store writes `MJ: Files`, the file↔session link and the session's recording stamp — server
|
|
136
|
+
* plumbing attributed through the session link, never through the caller. A signed-in user whose only
|
|
137
|
+
* role is the stock UI role cannot create `MJ: Files`, so running the store as the caller lost every
|
|
138
|
+
* such user's recording (the object landed in storage, the row never did). It therefore runs as the
|
|
139
|
+
* system user for signed-in owners, and anonymous sessions keep exactly the
|
|
140
|
+
* {@link ResolveScopedAnonymousRunUser} behaviour (PUBLIC WEB-WIDGET guests stay on the caller for the
|
|
141
|
+
* same RLS reason documented there).
|
|
142
|
+
*
|
|
143
|
+
* Fails CLOSED: with no system user available the caller is returned, i.e. today's behaviour.
|
|
144
|
+
* Ownership/consent gates must NEVER use this.
|
|
145
|
+
*/
|
|
146
|
+
export function ResolveRecordingStoreUser(contextUser: UserInfo): UserInfo {
|
|
147
|
+
if (contextUser?.IsMagicLinkAnonymous || contextUser?.WidgetGuestContext?.WidgetID) {
|
|
148
|
+
return ResolveScopedAnonymousRunUser(contextUser);
|
|
149
|
+
}
|
|
150
|
+
const systemUser = UserCache.Instance.GetSystemUser();
|
|
151
|
+
if (!systemUser) {
|
|
152
|
+
LogError(
|
|
153
|
+
`[Realtime] Cannot elevate the recording store for user ${contextUser?.ID}: no system user available; ` +
|
|
154
|
+
'storing as the caller.',
|
|
155
|
+
);
|
|
156
|
+
return contextUser;
|
|
157
|
+
}
|
|
158
|
+
return systemUser;
|
|
159
|
+
}
|
|
160
|
+
|
|
129
161
|
/**
|
|
130
162
|
* Builds an elevated {@link UserPayload} that runs subsequent agent work as `elevatedUser` while
|
|
131
163
|
* preserving the guest's `sessionId` — so progress/streaming PubSub still routes to the guest's
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import { Resolver, Mutation, Arg, Ctx } from "type-graphql";
|
|
2
2
|
import { ActionEngineServer } from "@memberjunction/actions";
|
|
3
3
|
import { EntityActionEngineServer } from "@memberjunction/actions";
|
|
4
|
-
import { Metadata, UserInfo, BaseEntity, CompositeKey, KeyValuePair, LogError } from "@memberjunction/core";
|
|
5
|
-
import { ActionParam, ActionResult } from "@memberjunction/actions-base";
|
|
4
|
+
import { Metadata, UserInfo, BaseEntity, CompositeKey, KeyValuePair, LogError, RunView, DatabaseProviderBase } from "@memberjunction/core";
|
|
5
|
+
import { ActionParam, ActionResult, MJActionEntityExtended } from "@memberjunction/actions-base";
|
|
6
|
+
import { UserCache } from "@memberjunction/generic-database-provider";
|
|
6
7
|
import { Field, InputType, ObjectType } from "type-graphql";
|
|
7
8
|
import { KeyValuePairInput } from "../generic/KeyValuePairInput.js";
|
|
8
9
|
import { AppContext, ProviderInfo } from "../types.js";
|
|
9
|
-
import { CopyScalarsAndArrays, UUIDsEqual } from "@memberjunction/global";
|
|
10
|
+
import { CopyScalarsAndArrays, EscapeSQLString, UUIDsEqual } from "@memberjunction/global";
|
|
10
11
|
import { GetReadOnlyProvider, GetReadWriteProvider } from "../util.js";
|
|
11
12
|
import { ResolverBase } from "../generic/ResolverBase.js";
|
|
13
|
+
import { IsScopeLimitedPrincipal } from "../auth/scopeLimitedPrincipal.js";
|
|
14
|
+
import { EvaluateActionRunAuthorization, IsOwner } from "../auth/actionAuthorization.js";
|
|
12
15
|
|
|
13
16
|
/**
|
|
14
17
|
* Input type for action parameters
|
|
@@ -55,8 +58,8 @@ export class RunActionInput {
|
|
|
55
58
|
Params?: ActionParamInput[];
|
|
56
59
|
|
|
57
60
|
/**
|
|
58
|
-
*
|
|
59
|
-
*
|
|
61
|
+
* Ignored. A run started through this API always writes an action execution log row; the field
|
|
62
|
+
* remains so that clients which send it still validate.
|
|
60
63
|
*/
|
|
61
64
|
@Field(() => Boolean, { nullable: true })
|
|
62
65
|
SkipActionLog?: boolean;
|
|
@@ -174,7 +177,13 @@ export class ActionResultOutput {
|
|
|
174
177
|
@Resolver()
|
|
175
178
|
export class ActionResolver extends ResolverBase {
|
|
176
179
|
/**
|
|
177
|
-
* Mutation for running an action
|
|
180
|
+
* Mutation for running an action.
|
|
181
|
+
*
|
|
182
|
+
* Scope-limited sessions are refused. Any other caller must be authorized for the action — see
|
|
183
|
+
* {@link EvaluateActionRunAuthorization}: an Owner may run any action; anyone else needs a role that
|
|
184
|
+
* holds an authorization linked to the action through `MJ: Action Authorizations`, or, when the
|
|
185
|
+
* action has no such link, an action class that authorizes its caller itself. The run is always
|
|
186
|
+
* logged.
|
|
178
187
|
* @param input The input parameters for running the action
|
|
179
188
|
* @param ctx The GraphQL context containing user authentication information
|
|
180
189
|
* @returns The result of running the action
|
|
@@ -185,20 +194,16 @@ export class ActionResolver extends ResolverBase {
|
|
|
185
194
|
@Ctx() ctx: AppContext
|
|
186
195
|
): Promise<ActionResultOutput> {
|
|
187
196
|
try {
|
|
197
|
+
const user = this.getRunActionPrincipal(ctx);
|
|
198
|
+
|
|
188
199
|
// Check API key scope authorization for action execution
|
|
189
200
|
await this.CheckAPIKeyScopeAuthorization('action:execute', input.ActionID, ctx.userPayload);
|
|
190
201
|
|
|
191
|
-
// Get the user from context
|
|
192
|
-
const user = ctx.userPayload.userRecord;
|
|
193
|
-
if (!user) {
|
|
194
|
-
throw new Error("User is not authenticated");
|
|
195
|
-
}
|
|
196
|
-
|
|
197
202
|
// Initialize the action engine
|
|
198
203
|
await ActionEngineServer.Instance.Config(false, user);
|
|
199
204
|
|
|
200
|
-
// Get the action by ID
|
|
201
205
|
const action = this.findActionById(input.ActionID);
|
|
206
|
+
await this.assertCanRunAction(action, user, ctx.providers);
|
|
202
207
|
|
|
203
208
|
// Parse the parameters
|
|
204
209
|
const params = this.parseActionParameters(input.Params);
|
|
@@ -206,7 +211,7 @@ export class ActionResolver extends ResolverBase {
|
|
|
206
211
|
// Run the action — thread the request-scoped provider so provider-bound
|
|
207
212
|
// actions (e.g. the semantic find-* / Search Entity actions, which call
|
|
208
213
|
// params.Provider.SearchEntity) run against the caller's metadata layer.
|
|
209
|
-
const result = await this.executeAction(action, user, params, ctx.providers
|
|
214
|
+
const result = await this.executeAction(action, user, params, ctx.providers);
|
|
210
215
|
|
|
211
216
|
// Return the result
|
|
212
217
|
return this.createActionResult(result);
|
|
@@ -215,6 +220,66 @@ export class ActionResolver extends ResolverBase {
|
|
|
215
220
|
}
|
|
216
221
|
}
|
|
217
222
|
|
|
223
|
+
/**
|
|
224
|
+
* The authenticated caller of RunAction. A scope-limited session is refused: its confinement exists
|
|
225
|
+
* only as row-level-security filters, and an action can reach data and services those filters never
|
|
226
|
+
* cover.
|
|
227
|
+
* @throws Error when there is no user or the session is scope-limited
|
|
228
|
+
*/
|
|
229
|
+
private getRunActionPrincipal(ctx: AppContext): UserInfo {
|
|
230
|
+
const user = ctx.userPayload?.userRecord;
|
|
231
|
+
if (!user) {
|
|
232
|
+
throw new Error("User is not authenticated");
|
|
233
|
+
}
|
|
234
|
+
if (IsScopeLimitedPrincipal(user)) {
|
|
235
|
+
throw new Error("RunAction is not permitted for scope-limited sessions");
|
|
236
|
+
}
|
|
237
|
+
return user;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Refuses the run unless the caller is authorized for the action — see
|
|
242
|
+
* {@link EvaluateActionRunAuthorization}. The `MJ: Action Authorizations` rows, the authorization
|
|
243
|
+
* tree and the role grants all come from the request's provider, or all from the global provider
|
|
244
|
+
* when the request carries none.
|
|
245
|
+
* @throws Error when the caller may not run the action
|
|
246
|
+
*/
|
|
247
|
+
private async assertCanRunAction(action: MJActionEntityExtended, user: UserInfo, providers: Array<ProviderInfo>): Promise<void> {
|
|
248
|
+
if (IsOwner(user)) {
|
|
249
|
+
return; // an Owner may run any action, so nothing needs to be read
|
|
250
|
+
}
|
|
251
|
+
const provider = GetReadOnlyProvider(providers, { allowFallbackToReadWrite: true });
|
|
252
|
+
const actionAuthorizationIDs = await this.loadActionAuthorizationIDs(action.ID, provider);
|
|
253
|
+
const metadata = provider ?? Metadata.Provider; // global-provider-ok: fallback only when the request carries no provider
|
|
254
|
+
const actionAuthorizesCaller = ActionEngineServer.Instance.ActionAuthorizesCaller(action);
|
|
255
|
+
const decision = EvaluateActionRunAuthorization(user, actionAuthorizationIDs, metadata, actionAuthorizesCaller);
|
|
256
|
+
if (!decision.Allowed) {
|
|
257
|
+
throw new Error(`Not authorized to run action ${action.ID}: ${decision.Reason}`);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* The AuthorizationID of each `MJ: Action Authorizations` row for the action. Read as the system
|
|
263
|
+
* user: this is the server's own authorization decision, so it must not depend on whether the
|
|
264
|
+
* caller can read that entity.
|
|
265
|
+
*/
|
|
266
|
+
private async loadActionAuthorizationIDs(actionID: string, provider: DatabaseProviderBase | null): Promise<string[]> {
|
|
267
|
+
const systemUser = UserCache.Instance.GetSystemUser();
|
|
268
|
+
if (!systemUser) {
|
|
269
|
+
throw new Error("System user not found");
|
|
270
|
+
}
|
|
271
|
+
const result = await new RunView(provider).RunView<{ AuthorizationID: string }>({
|
|
272
|
+
EntityName: 'MJ: Action Authorizations',
|
|
273
|
+
ExtraFilter: `ActionID='${EscapeSQLString(actionID)}'`,
|
|
274
|
+
Fields: ['AuthorizationID'],
|
|
275
|
+
ResultType: 'simple'
|
|
276
|
+
}, systemUser);
|
|
277
|
+
if (!result.Success) {
|
|
278
|
+
throw new Error(`Could not read the authorizations for action ${actionID}: ${result.ErrorMessage}`);
|
|
279
|
+
}
|
|
280
|
+
return result.Results.map(row => row.AuthorizationID);
|
|
281
|
+
}
|
|
282
|
+
|
|
218
283
|
/**
|
|
219
284
|
* Finds an action by its ID
|
|
220
285
|
* @param actionID The ID of the action to find
|
|
@@ -222,7 +287,7 @@ export class ActionResolver extends ResolverBase {
|
|
|
222
287
|
* @throws Error if the action is not found
|
|
223
288
|
* @private
|
|
224
289
|
*/
|
|
225
|
-
private findActionById(actionID: string):
|
|
290
|
+
private findActionById(actionID: string): MJActionEntityExtended {
|
|
226
291
|
const action = ActionEngineServer.Instance.Actions.find(a => UUIDsEqual(a.ID, actionID));
|
|
227
292
|
if (!action) {
|
|
228
293
|
throw new Error(`Action with ID ${actionID} not found`);
|
|
@@ -264,20 +329,18 @@ export class ActionResolver extends ResolverBase {
|
|
|
264
329
|
}
|
|
265
330
|
|
|
266
331
|
/**
|
|
267
|
-
* Executes an action
|
|
332
|
+
* Executes an action. The run is always logged: a client cannot switch off the action execution log.
|
|
268
333
|
* @param action The action to execute
|
|
269
334
|
* @param user The user context
|
|
270
335
|
* @param params The action parameters
|
|
271
|
-
* @param skipActionLog Whether to skip action logging
|
|
272
336
|
* @returns The action result
|
|
273
337
|
* @private
|
|
274
338
|
*/
|
|
275
339
|
private async executeAction(
|
|
276
|
-
action:
|
|
340
|
+
action: MJActionEntityExtended,
|
|
277
341
|
user: UserInfo,
|
|
278
342
|
params: ActionParam[],
|
|
279
|
-
providers: Array<ProviderInfo
|
|
280
|
-
skipActionLog?: boolean
|
|
343
|
+
providers: Array<ProviderInfo>
|
|
281
344
|
): Promise<ActionResult> {
|
|
282
345
|
// Resolve the request-scoped provider. Prefer read-write (actions may mutate);
|
|
283
346
|
// fall back to read-only, then to the engine's global-Metadata default when no
|
|
@@ -287,7 +350,7 @@ export class ActionResolver extends ResolverBase {
|
|
|
287
350
|
Action: action,
|
|
288
351
|
ContextUser: user,
|
|
289
352
|
Params: params,
|
|
290
|
-
SkipActionLog:
|
|
353
|
+
SkipActionLog: false,
|
|
291
354
|
Filters: [],
|
|
292
355
|
Provider: provider
|
|
293
356
|
});
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { Arg, Ctx, Query, Resolver, Field, Int, InputType } from 'type-graphql';
|
|
2
2
|
import { LogError } from '@memberjunction/core';
|
|
3
|
-
import type {
|
|
3
|
+
import type { DatabaseProviderBase, RunQueryResult, UserInfo } from '@memberjunction/core';
|
|
4
4
|
import { RenderPipeline } from '@memberjunction/generic-database-provider';
|
|
5
|
+
import type { AdhocSQLAuthorizer } from '@memberjunction/actions';
|
|
5
6
|
import { AppContext } from '../types.js';
|
|
6
7
|
import { configInfo } from '../config.js';
|
|
7
8
|
import { GetReadOnlyProvider } from '../util.js';
|
|
@@ -73,7 +74,7 @@ export class AdhocQueryResolver extends ResolverBase {
|
|
|
73
74
|
return this.buildErrorResult('No read-only data source available for ad-hoc query execution');
|
|
74
75
|
}
|
|
75
76
|
const contextUser = context.userPayload?.userRecord;
|
|
76
|
-
const refusal = this.
|
|
77
|
+
const refusal = this.AuthorizeRenderedSQL(input.SQL, provider, contextUser);
|
|
77
78
|
if (refusal) {
|
|
78
79
|
return this.buildErrorResult(refusal, Date.now() - startTime);
|
|
79
80
|
}
|
|
@@ -104,12 +105,14 @@ export class AdhocQueryResolver extends ResolverBase {
|
|
|
104
105
|
* because raw SQL applies neither (see assertFullQueryUsesReadableEntityViews). The provider
|
|
105
106
|
* renders the same input the same way and only wraps it in server-built paging and a count,
|
|
106
107
|
* so the rendered SQL is the full set of reads. Returns the refusal message, or null.
|
|
108
|
+
*
|
|
109
|
+
* `provider` is the read-only provider the SQL will run on; it supplies the platform and the
|
|
110
|
+
* entity metadata. {@link CreateAdhocSQLAuthorizer} exposes this check to the action engine.
|
|
107
111
|
*/
|
|
108
|
-
|
|
112
|
+
public AuthorizeRenderedSQL(sqlText: string, provider: DatabaseProviderBase, contextUser: UserInfo | undefined): string | null {
|
|
109
113
|
try {
|
|
110
|
-
const rendered = RenderPipeline.Run(sqlText, { Platform:
|
|
111
|
-
|
|
112
|
-
this.assertFullQueryUsesReadableEntityViews(rendered.Trace.AfterTemplates, mdProvider, contextUser, 'ad-hoc SQL');
|
|
114
|
+
const rendered = RenderPipeline.Run(sqlText, { Platform: provider.PlatformKey, ContextUser: contextUser, RequireReadStatement: true });
|
|
115
|
+
this.assertFullQueryUsesReadableEntityViews(rendered.Trace.AfterTemplates, provider, contextUser, 'ad-hoc SQL');
|
|
113
116
|
return null;
|
|
114
117
|
} catch (err) {
|
|
115
118
|
return err instanceof Error ? err.message : String(err);
|
|
@@ -161,3 +164,18 @@ export class AdhocQueryResolver extends ResolverBase {
|
|
|
161
164
|
};
|
|
162
165
|
}
|
|
163
166
|
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* The ad-hoc SQL checks MJServer registers with the action engine, so that Run Ad-hoc Query applies
|
|
170
|
+
* the same checks as {@link AdhocQueryResolver.ExecuteAdhocQuery}: the rendered SQL must be one read
|
|
171
|
+
* statement that reads only entity views the caller may read in full, and the timeout is limited by
|
|
172
|
+
* the server's request timeout.
|
|
173
|
+
* @param requestTimeoutMs the server's request timeout in milliseconds; 0 or less means no limit
|
|
174
|
+
*/
|
|
175
|
+
export function CreateAdhocSQLAuthorizer(requestTimeoutMs: number): AdhocSQLAuthorizer {
|
|
176
|
+
const resolver = new AdhocQueryResolver();
|
|
177
|
+
return {
|
|
178
|
+
Authorize: (sql, provider, contextUser) => resolver.AuthorizeRenderedSQL(sql, provider, contextUser),
|
|
179
|
+
ClampTimeoutSeconds: (requestedSeconds) => ClampAdhocTimeoutSeconds(requestedSeconds, requestTimeoutMs),
|
|
180
|
+
};
|
|
181
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { Field, Float, Int, ObjectType, Query, Resolver } from 'type-graphql';
|
|
2
|
-
import { LocalCacheManager, CacheStats, CacheEntryType } from '@memberjunction/core';
|
|
1
|
+
import { Arg, Field, Float, Int, ObjectType, Query, Resolver } from 'type-graphql';
|
|
2
|
+
import { BaseEngine, BaseEngineRegistry, LocalCacheManager, CacheStats, CacheEntryType } from '@memberjunction/core';
|
|
3
|
+
import type { EngineStateCensus } from '@memberjunction/core';
|
|
3
4
|
import { RequireSystemUser } from '../directives/index.js';
|
|
4
5
|
|
|
5
6
|
// ============================================================================
|
|
@@ -66,10 +67,83 @@ class CacheStatsDetailGQL extends CacheStatsGQL {
|
|
|
66
67
|
EntityBreakdown: CacheEntityBreakdownGQL[];
|
|
67
68
|
}
|
|
68
69
|
|
|
70
|
+
@ObjectType()
|
|
71
|
+
class EnginePropertyCensusGQL {
|
|
72
|
+
@Field(() => String)
|
|
73
|
+
PropertyName: string;
|
|
74
|
+
|
|
75
|
+
@Field(() => String, { nullable: true })
|
|
76
|
+
EntityName?: string;
|
|
77
|
+
|
|
78
|
+
@Field(() => String, { nullable: true })
|
|
79
|
+
DatasetName?: string;
|
|
80
|
+
|
|
81
|
+
@Field(() => Int)
|
|
82
|
+
RowCount: number;
|
|
83
|
+
|
|
84
|
+
@Field(() => String, { nullable: true })
|
|
85
|
+
MaxUpdatedAt: string | null;
|
|
86
|
+
|
|
87
|
+
@Field(() => String, { nullable: true })
|
|
88
|
+
IdentityHash: string | null;
|
|
89
|
+
|
|
90
|
+
@Field(() => Boolean)
|
|
91
|
+
LoadedSuccessfully: boolean;
|
|
92
|
+
|
|
93
|
+
@Field(() => Boolean)
|
|
94
|
+
PermissionDenied: boolean;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
@ObjectType()
|
|
98
|
+
class EngineDerivedCountGQL {
|
|
99
|
+
@Field(() => String)
|
|
100
|
+
Name: string;
|
|
101
|
+
|
|
102
|
+
@Field(() => Int)
|
|
103
|
+
Value: number;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
@ObjectType()
|
|
107
|
+
class EngineStateCensusGQL {
|
|
108
|
+
@Field(() => String)
|
|
109
|
+
EngineClass: string;
|
|
110
|
+
|
|
111
|
+
@Field(() => Boolean)
|
|
112
|
+
Loaded: boolean;
|
|
113
|
+
|
|
114
|
+
@Field(() => Boolean)
|
|
115
|
+
PermissionConstrained: boolean;
|
|
116
|
+
|
|
117
|
+
@Field(() => [EnginePropertyCensusGQL])
|
|
118
|
+
Properties: EnginePropertyCensusGQL[];
|
|
119
|
+
|
|
120
|
+
@Field(() => [EngineDerivedCountGQL])
|
|
121
|
+
Derived: EngineDerivedCountGQL[];
|
|
122
|
+
}
|
|
123
|
+
|
|
69
124
|
// ============================================================================
|
|
70
125
|
// Helpers (pure core)
|
|
71
126
|
// ============================================================================
|
|
72
127
|
|
|
128
|
+
function censusToGQL(census: EngineStateCensus): EngineStateCensusGQL {
|
|
129
|
+
const gql = new EngineStateCensusGQL();
|
|
130
|
+
gql.EngineClass = census.EngineClass;
|
|
131
|
+
gql.Loaded = census.Loaded;
|
|
132
|
+
gql.PermissionConstrained = census.PermissionConstrained;
|
|
133
|
+
gql.Properties = census.Properties.map(p => Object.assign(new EnginePropertyCensusGQL(), p));
|
|
134
|
+
gql.Derived = Object.entries(census.Derived).map(([Name, Value]) => Object.assign(new EngineDerivedCountGQL(), { Name, Value }));
|
|
135
|
+
return gql;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/** Census of every registered engine in this process, optionally narrowed to one class name. */
|
|
139
|
+
function buildEngineCensus(engineClass?: string): EngineStateCensusGQL[] {
|
|
140
|
+
return BaseEngineRegistry.Instance.GetAllEngines()
|
|
141
|
+
.filter((engine): engine is BaseEngine<unknown> => engine instanceof BaseEngine)
|
|
142
|
+
.filter(engine => !engineClass || engine.constructor.name === engineClass)
|
|
143
|
+
.map(engine => censusToGQL(engine.GetStateCensus()))
|
|
144
|
+
.sort((a, b) => a.EngineClass.localeCompare(b.EngineClass));
|
|
145
|
+
}
|
|
146
|
+
|
|
73
147
|
function toGQL(stats: CacheStats): CacheStatsGQL {
|
|
74
148
|
const gql = new CacheStatsGQL();
|
|
75
149
|
gql.TotalEntries = stats.totalEntries;
|
|
@@ -139,4 +213,17 @@ export class CacheStatsResolver {
|
|
|
139
213
|
result.EntityBreakdown = buildEntityBreakdown();
|
|
140
214
|
return result;
|
|
141
215
|
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* What each engine in this server process holds — row counts, newest timestamps, a row-version
|
|
219
|
+
* hash, and engine-specific derived-state counts. Comparing the hashes across servers shows
|
|
220
|
+
* whether they converged; a derived count of zero next to a full array shows lost derived state.
|
|
221
|
+
*/
|
|
222
|
+
@RequireSystemUser()
|
|
223
|
+
@Query(() => [EngineStateCensusGQL])
|
|
224
|
+
EngineStateCensus(
|
|
225
|
+
@Arg('EngineClass', () => String, { nullable: true }) engineClass?: string
|
|
226
|
+
): EngineStateCensusGQL[] {
|
|
227
|
+
return buildEngineCensus(engineClass);
|
|
228
|
+
}
|
|
142
229
|
}
|
|
@@ -14,6 +14,7 @@ import { AppContext } from '../types.js';
|
|
|
14
14
|
import { LogStatus, LogError } from '@memberjunction/core';
|
|
15
15
|
import { ResolverBase } from '../generic/ResolverBase.js';
|
|
16
16
|
import { ClientToolRequestManager, CLIENT_TOOL_REQUEST_TOPIC, ClientToolRequestNotificationPayload } from '@memberjunction/ai-agents';
|
|
17
|
+
import { ParseClientToolMedia } from '@memberjunction/ai-core-plus';
|
|
17
18
|
|
|
18
19
|
@ObjectType()
|
|
19
20
|
export class ClientToolRequestNotification {
|
|
@@ -71,7 +72,9 @@ export class ClientToolRequestResolver extends ResolverBase {
|
|
|
71
72
|
/**
|
|
72
73
|
* Client sends the result of executing a client tool back to the server.
|
|
73
74
|
* This resolves the pending Promise in ClientToolRequestManager so the
|
|
74
|
-
* agent loop can continue.
|
|
75
|
+
* agent loop can continue. `media` is an optional JSON array of images.
|
|
76
|
+
* When `media` fails validation or `result` is not valid JSON, the request
|
|
77
|
+
* resolves as a failed result.
|
|
75
78
|
*/
|
|
76
79
|
@Mutation(() => Boolean)
|
|
77
80
|
async RespondToClientToolRequest(
|
|
@@ -79,15 +82,25 @@ export class ClientToolRequestResolver extends ResolverBase {
|
|
|
79
82
|
@Arg('success') success: boolean,
|
|
80
83
|
@Arg('result', { nullable: true }) result: string | undefined,
|
|
81
84
|
@Arg('errorMessage', { nullable: true }) errorMessage: string | undefined,
|
|
85
|
+
@Arg('media', { nullable: true }) media: string | undefined,
|
|
82
86
|
@Ctx() _context: AppContext = {} as AppContext
|
|
83
87
|
): Promise<boolean> {
|
|
84
88
|
try {
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
89
|
+
const parsedMedia = ParseClientToolMedia(media);
|
|
90
|
+
// `=== true` narrows the union; this package compiles without strictNullChecks.
|
|
91
|
+
const found = ClientToolRequestManager.Instance.ReceiveResponse(parsedMedia.ok === true
|
|
92
|
+
? {
|
|
93
|
+
RequestID: requestID,
|
|
94
|
+
Success: success,
|
|
95
|
+
Result: result ? JSON.parse(result) : undefined,
|
|
96
|
+
ErrorMessage: errorMessage,
|
|
97
|
+
Media: parsedMedia.media.length ? parsedMedia.media : undefined
|
|
98
|
+
}
|
|
99
|
+
: {
|
|
100
|
+
RequestID: requestID,
|
|
101
|
+
Success: false,
|
|
102
|
+
ErrorMessage: `Client tool media rejected: ${parsedMedia.error}`
|
|
103
|
+
});
|
|
91
104
|
|
|
92
105
|
if (!found) {
|
|
93
106
|
LogError(`RespondToClientToolRequest: no pending request for ${requestID} (may have timed out)`);
|
|
@@ -96,6 +109,11 @@ export class ClientToolRequestResolver extends ResolverBase {
|
|
|
96
109
|
} catch (error) {
|
|
97
110
|
const msg = error instanceof Error ? error.message : String(error);
|
|
98
111
|
LogError(`RespondToClientToolRequest error: ${msg}`);
|
|
112
|
+
ClientToolRequestManager.Instance.ReceiveResponse({
|
|
113
|
+
RequestID: requestID,
|
|
114
|
+
Success: false,
|
|
115
|
+
ErrorMessage: `Client tool response rejected: ${msg}`
|
|
116
|
+
});
|
|
99
117
|
return false;
|
|
100
118
|
}
|
|
101
119
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { Resolver, Query, Arg, Ctx, ObjectType, Field, Float, Int } from 'type-graphql';
|
|
2
2
|
import { AppContext } from '../types.js';
|
|
3
|
-
import { LogError, LogStatus, Metadata, RunView, UserInfo } from '@memberjunction/core';
|
|
3
|
+
import { CompositeKey, EntityInfo, IMetadataProvider, LogError, LogStatus, Metadata, RunView, UserInfo } from '@memberjunction/core';
|
|
4
4
|
import { MJEntityDocumentEntity, MJVectorIndexEntity, MJVectorDatabaseEntity } from '@memberjunction/core-entities';
|
|
5
5
|
import { ResolverBase } from '../generic/ResolverBase.js';
|
|
6
|
+
import { GetReadOnlyProvider } from '../util.js';
|
|
6
7
|
import { GetAIAPIKey } from '@memberjunction/ai';
|
|
7
8
|
import { VectorDBBase } from '@memberjunction/ai-vectordb';
|
|
8
9
|
import { AIEngine } from '@memberjunction/aiengine';
|
|
@@ -50,7 +51,7 @@ export class FetchEntityVectorsResolver extends ResolverBase {
|
|
|
50
51
|
@Arg('entityDocumentID') entityDocumentID: string,
|
|
51
52
|
@Arg('maxRecords', () => Int, { nullable: true }) maxRecords: number | undefined,
|
|
52
53
|
@Arg('filter', { nullable: true }) filter: string | undefined,
|
|
53
|
-
@Ctx() { userPayload }: AppContext = {} as AppContext
|
|
54
|
+
@Ctx() { userPayload, providers }: AppContext = {} as AppContext
|
|
54
55
|
): Promise<FetchEntityVectorsResult> {
|
|
55
56
|
const startTime = Date.now();
|
|
56
57
|
try {
|
|
@@ -85,6 +86,17 @@ export class FetchEntityVectorsResolver extends ResolverBase {
|
|
|
85
86
|
);
|
|
86
87
|
}
|
|
87
88
|
|
|
89
|
+
// Providers that keep their vectors in MJ, keyed by EntityDocumentID (the in-process
|
|
90
|
+
// SimpleVectorServiceProvider), can't be listed through QueryIndex: they key by the
|
|
91
|
+
// document ID rather than the index name, aren't handed the context user, and return
|
|
92
|
+
// matches without vector values. Read the stored Entity Record Document rows instead.
|
|
93
|
+
if (vectorDBInstance.QueryKeyIsEntityDocumentID) {
|
|
94
|
+
const md = GetReadOnlyProvider(providers, { allowFallbackToReadWrite: true }) ?? Metadata.Provider;
|
|
95
|
+
const results = await this.fetchStoredVectors(entityDoc, limit, filter, currentUser, md);
|
|
96
|
+
LogStatus(`FetchEntityVectors: Loaded ${results.length} stored vectors for entity "${entityDoc.Entity}" in ${Date.now() - startTime}ms`);
|
|
97
|
+
return { Success: true, Results: results, TotalCount: results.length, ElapsedMs: Date.now() - startTime };
|
|
98
|
+
}
|
|
99
|
+
|
|
88
100
|
// Step 4: Query with zero vector + Entity metadata filter.
|
|
89
101
|
// Pinecone's list API doesn't support metadata filtering, but query does.
|
|
90
102
|
// A zero vector returns results in arbitrary order (similarity is meaningless),
|
|
@@ -227,6 +239,89 @@ export class FetchEntityVectorsResolver extends ResolverBase {
|
|
|
227
239
|
return instance;
|
|
228
240
|
}
|
|
229
241
|
|
|
242
|
+
/**
|
|
243
|
+
* Load the vectors an EntityDocument stored in MJ (`MJ: Entity Record Documents.VectorJSON`),
|
|
244
|
+
* restricted to the entity records that pass `filter`. Each item's metadata carries the entity
|
|
245
|
+
* name, the record ID and the record's name fields, which is what the cluster view labels from.
|
|
246
|
+
*/
|
|
247
|
+
private async fetchStoredVectors(
|
|
248
|
+
entityDoc: MJEntityDocumentEntity,
|
|
249
|
+
limit: number,
|
|
250
|
+
filter: string | undefined,
|
|
251
|
+
contextUser: UserInfo,
|
|
252
|
+
md: IMetadataProvider
|
|
253
|
+
): Promise<EntityVectorItem[]> {
|
|
254
|
+
const entityInfo = md.EntityByName(entityDoc.Entity);
|
|
255
|
+
if (!entityInfo) {
|
|
256
|
+
throw new Error(`Entity "${entityDoc.Entity}" not found in metadata`);
|
|
257
|
+
}
|
|
258
|
+
const labelsByRecordID = await this.loadRecordLabels(entityInfo, filter, contextUser);
|
|
259
|
+
|
|
260
|
+
const rv = new RunView();
|
|
261
|
+
const docResult = await rv.RunView<{ ID: string; RecordID: string; VectorJSON: string }>({
|
|
262
|
+
EntityName: 'MJ: Entity Record Documents',
|
|
263
|
+
ExtraFilter: `EntityDocumentID='${EscapeSQLString(entityDoc.ID)}' AND VectorJSON IS NOT NULL`,
|
|
264
|
+
Fields: ['ID', 'RecordID', 'VectorJSON'],
|
|
265
|
+
IgnoreMaxRows: true,
|
|
266
|
+
ResultType: 'simple',
|
|
267
|
+
}, contextUser);
|
|
268
|
+
if (!docResult.Success) {
|
|
269
|
+
throw new Error(`Failed to load stored vectors: ${docResult.ErrorMessage}`);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
const results: EntityVectorItem[] = [];
|
|
273
|
+
for (const row of docResult.Results) {
|
|
274
|
+
const labels = labelsByRecordID.get(row.RecordID.toLowerCase());
|
|
275
|
+
if (!labels) continue; // filtered out, not readable by this user, or the record no longer exists
|
|
276
|
+
results.push({
|
|
277
|
+
ID: row.ID,
|
|
278
|
+
Values: JSON.parse(row.VectorJSON) as number[],
|
|
279
|
+
Metadata: JSON.stringify({ Entity: entityDoc.Entity, RecordID: row.RecordID, ...labels }),
|
|
280
|
+
});
|
|
281
|
+
if (results.length >= limit) break;
|
|
282
|
+
}
|
|
283
|
+
return results;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Map each record that passes `filter` to its name-field values, keyed by the same compact
|
|
288
|
+
* record-ID form the vector sync writes to `MJ: Entity Record Documents.RecordID` (lower-cased).
|
|
289
|
+
*/
|
|
290
|
+
private async loadRecordLabels(
|
|
291
|
+
entityInfo: EntityInfo,
|
|
292
|
+
filter: string | undefined,
|
|
293
|
+
contextUser: UserInfo
|
|
294
|
+
): Promise<Map<string, Record<string, string>>> {
|
|
295
|
+
const nameFields = entityInfo.Fields.filter(f => f.IsNameField).map(f => f.Name);
|
|
296
|
+
if (nameFields.length === 0 && entityInfo.NameField) {
|
|
297
|
+
nameFields.push(entityInfo.NameField.Name);
|
|
298
|
+
}
|
|
299
|
+
const keyFields = entityInfo.PrimaryKeys.map(pk => pk.Name);
|
|
300
|
+
|
|
301
|
+
const rv = new RunView();
|
|
302
|
+
const result = await rv.RunView<Record<string, unknown>>({
|
|
303
|
+
EntityName: entityInfo.Name,
|
|
304
|
+
ExtraFilter: filter || undefined,
|
|
305
|
+
Fields: [...new Set([...keyFields, ...nameFields])],
|
|
306
|
+
IgnoreMaxRows: true,
|
|
307
|
+
ResultType: 'simple',
|
|
308
|
+
}, contextUser);
|
|
309
|
+
if (!result.Success) {
|
|
310
|
+
throw new Error(`Failed to load "${entityInfo.Name}" records: ${result.ErrorMessage}`);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
const map = new Map<string, Record<string, string>>();
|
|
314
|
+
for (const row of result.Results) {
|
|
315
|
+
const key = CompositeKey.FromEntityRecord(entityInfo, row).ToCompactURLSegment().toLowerCase();
|
|
316
|
+
const labels: Record<string, string> = {};
|
|
317
|
+
for (const name of nameFields) {
|
|
318
|
+
if (row[name] != null) labels[name] = String(row[name]);
|
|
319
|
+
}
|
|
320
|
+
map.set(key, labels);
|
|
321
|
+
}
|
|
322
|
+
return map;
|
|
323
|
+
}
|
|
324
|
+
|
|
230
325
|
private errorResult(message: string, startTime: number): FetchEntityVectorsResult {
|
|
231
326
|
return {
|
|
232
327
|
Success: false,
|
|
@@ -2,9 +2,11 @@ import { Resolver, Mutation, Query, Subscription, Arg, Ctx, Root, ObjectType, Fi
|
|
|
2
2
|
import { IMetadataProvider, LogError, UserInfo } from '@memberjunction/core';
|
|
3
3
|
import { MJGlobal, UUIDsEqual } from '@memberjunction/global';
|
|
4
4
|
import { NotificationEngine } from '@memberjunction/notifications';
|
|
5
|
+
import { UserCache } from '@memberjunction/generic-database-provider';
|
|
5
6
|
import {
|
|
6
7
|
LiveKitSipService,
|
|
7
8
|
RoomHandoffEngine,
|
|
9
|
+
HandoffOfferRegistry,
|
|
8
10
|
type HandoffOfferEvent,
|
|
9
11
|
type HandoffOfferView,
|
|
10
12
|
type IHandoffNotifier,
|
|
@@ -207,6 +209,12 @@ export class NotificationHandoffNotifier implements IHandoffNotifier {
|
|
|
207
209
|
}
|
|
208
210
|
}
|
|
209
211
|
|
|
212
|
+
// The registry's background sweep and list queries run outside any request, so they need a server identity. Resolve the
|
|
213
|
+
// system user lazily: the user cache may not have loaded when this module does.
|
|
214
|
+
HandoffOfferRegistry.Instance.Configure({
|
|
215
|
+
ResolveContextUser: () => UserCache.Instance.GetSystemUser(),
|
|
216
|
+
});
|
|
217
|
+
|
|
210
218
|
/**
|
|
211
219
|
* Binds the handoff engine's collaborators that only the server host can supply (same module-load rationale as the other
|
|
212
220
|
* realtime bindings): the pub/sub publisher, the notification sender, and a room-presence check over the LiveKit credentials
|
|
@@ -639,11 +639,14 @@ export class MCPResolver extends ResolverBase {
|
|
|
639
639
|
// Publish syncing progress
|
|
640
640
|
this.publishProgress(pubSub, sessionId, user.ID, ConnectionID, 'syncing', 'Synchronizing tools to database...');
|
|
641
641
|
|
|
642
|
-
// Perform the sync
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
642
|
+
// Perform the sync; always detach the listener, even if syncTools throws, so failed
|
|
643
|
+
// syncs don't stack handlers on the shared manager.
|
|
644
|
+
let syncResult: MCPSyncToolsResult;
|
|
645
|
+
try {
|
|
646
|
+
syncResult = await manager.syncTools(ConnectionID, { contextUser: user });
|
|
647
|
+
} finally {
|
|
648
|
+
manager.removeEventListener('toolsSynced', eventHandler);
|
|
649
|
+
}
|
|
647
650
|
|
|
648
651
|
if (!syncResult.success) {
|
|
649
652
|
this.publishProgress(pubSub, sessionId, user.ID, ConnectionID, 'error', `Sync failed: ${syncResult.error}`);
|