@memberjunction/server 6.2.0-edge.0 → 6.2.0-edge.1
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/ReturningVisitorRecap.d.ts +2 -0
- package/dist/agentSessions/ReturningVisitorRecap.d.ts.map +1 -1
- package/dist/agentSessions/ReturningVisitorRecap.js +5 -1
- package/dist/agentSessions/ReturningVisitorRecap.js.map +1 -1
- package/dist/agentSessions/SessionManager.js +2 -2
- package/dist/agentSessions/remoteBrowserGoalEngine.d.ts +8 -0
- package/dist/agentSessions/remoteBrowserGoalEngine.d.ts.map +1 -1
- package/dist/agentSessions/remoteBrowserGoalEngine.js +21 -5
- package/dist/agentSessions/remoteBrowserGoalEngine.js.map +1 -1
- package/dist/auth/AuthProviderCatalogRouter.d.ts +2 -0
- package/dist/auth/AuthProviderCatalogRouter.d.ts.map +1 -1
- package/dist/auth/AuthProviderCatalogRouter.js +5 -1
- package/dist/auth/AuthProviderCatalogRouter.js.map +1 -1
- package/dist/auth/index.d.ts +20 -1
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +20 -10
- package/dist/auth/index.js.map +1 -1
- package/dist/auth/initializeProviders.d.ts +8 -0
- package/dist/auth/initializeProviders.d.ts.map +1 -1
- package/dist/auth/initializeProviders.js +21 -5
- package/dist/auth/initializeProviders.js.map +1 -1
- package/dist/auth/magicLink/MagicLinkRouter.d.ts +9 -0
- package/dist/auth/magicLink/MagicLinkRouter.d.ts.map +1 -1
- package/dist/auth/magicLink/MagicLinkRouter.js +22 -10
- package/dist/auth/magicLink/MagicLinkRouter.js.map +1 -1
- package/dist/auth/magicLink/MagicLinkService.d.ts +17 -15
- package/dist/auth/magicLink/MagicLinkService.d.ts.map +1 -1
- package/dist/auth/magicLink/MagicLinkService.js +65 -51
- package/dist/auth/magicLink/MagicLinkService.js.map +1 -1
- package/dist/auth/magicLink/index.d.ts +2 -2
- package/dist/auth/magicLink/index.d.ts.map +1 -1
- package/dist/auth/magicLink/index.js +2 -2
- package/dist/auth/magicLink/index.js.map +1 -1
- package/dist/auth/magicLink/magicLinkCore.d.ts +54 -33
- package/dist/auth/magicLink/magicLinkCore.d.ts.map +1 -1
- package/dist/auth/magicLink/magicLinkCore.js +61 -61
- package/dist/auth/magicLink/magicLinkCore.js.map +1 -1
- package/dist/auth/magicLink/redeemLanding.d.ts +4 -0
- package/dist/auth/magicLink/redeemLanding.d.ts.map +1 -1
- package/dist/auth/magicLink/redeemLanding.js +12 -4
- package/dist/auth/magicLink/redeemLanding.js.map +1 -1
- package/dist/auth/magicLink/types.d.ts +4 -4
- package/dist/auth/principals.d.ts +2 -0
- package/dist/auth/principals.d.ts.map +1 -1
- package/dist/auth/principals.js +6 -2
- package/dist/auth/principals.js.map +1 -1
- package/dist/cache.d.ts +2 -0
- package/dist/cache.d.ts.map +1 -1
- package/dist/cache.js +3 -1
- package/dist/cache.js.map +1 -1
- package/dist/config.d.ts +346 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +34 -4
- package/dist/config.js.map +1 -1
- package/dist/context.d.ts +20 -0
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +27 -19
- package/dist/context.js.map +1 -1
- package/dist/directives/Public.d.ts +2 -0
- package/dist/directives/Public.d.ts.map +1 -1
- package/dist/directives/Public.js +3 -1
- package/dist/directives/Public.js.map +1 -1
- package/dist/directives/RequireSystemUser.d.ts +2 -0
- package/dist/directives/RequireSystemUser.d.ts.map +1 -1
- package/dist/directives/RequireSystemUser.js +3 -1
- package/dist/directives/RequireSystemUser.js.map +1 -1
- package/dist/generated/graphql-schemas/__mj.d.ts +11 -0
- package/dist/generated/graphql-schemas/__mj.d.ts.map +1 -1
- package/dist/generated/graphql-schemas/__mj.js +48 -0
- package/dist/generated/graphql-schemas/__mj.js.map +1 -1
- package/dist/generic/CacheInvalidationResolver.d.ts +94 -4
- package/dist/generic/CacheInvalidationResolver.d.ts.map +1 -1
- package/dist/generic/CacheInvalidationResolver.js +122 -3
- package/dist/generic/CacheInvalidationResolver.js.map +1 -1
- package/dist/generic/DeleteOptionsInput.d.ts +8 -1
- package/dist/generic/DeleteOptionsInput.d.ts.map +1 -1
- package/dist/generic/DeleteOptionsInput.js +1 -1
- package/dist/generic/DeleteOptionsInput.js.map +1 -1
- package/dist/generic/FireAndForgetHeartbeat.d.ts +3 -1
- package/dist/generic/FireAndForgetHeartbeat.d.ts.map +1 -1
- package/dist/generic/FireAndForgetHeartbeat.js +8 -4
- package/dist/generic/FireAndForgetHeartbeat.js.map +1 -1
- package/dist/generic/PushStatusResolver.d.ts +10 -1
- package/dist/generic/PushStatusResolver.d.ts.map +1 -1
- package/dist/generic/PushStatusResolver.js +11 -3
- package/dist/generic/PushStatusResolver.js.map +1 -1
- package/dist/generic/ResolverBase.d.ts +5 -1
- package/dist/generic/ResolverBase.d.ts.map +1 -1
- package/dist/generic/ResolverBase.js +15 -8
- package/dist/generic/ResolverBase.js.map +1 -1
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +30 -9
- package/dist/index.js.map +1 -1
- package/dist/integration/CustomColumnPromoter.d.ts +2 -0
- package/dist/integration/CustomColumnPromoter.d.ts.map +1 -1
- package/dist/integration/CustomColumnPromoter.js +5 -1
- package/dist/integration/CustomColumnPromoter.js.map +1 -1
- package/dist/integration/EntityMapLifecycle.d.ts +4 -0
- package/dist/integration/EntityMapLifecycle.d.ts.map +1 -1
- package/dist/integration/EntityMapLifecycle.js +10 -2
- package/dist/integration/EntityMapLifecycle.js.map +1 -1
- package/dist/logging/NoLog.d.ts +4 -0
- package/dist/logging/NoLog.d.ts.map +1 -1
- package/dist/logging/NoLog.js +10 -2
- package/dist/logging/NoLog.js.map +1 -1
- package/dist/logging/StartupLogger.d.ts +2 -0
- package/dist/logging/StartupLogger.d.ts.map +1 -1
- package/dist/logging/StartupLogger.js +5 -1
- package/dist/logging/StartupLogger.js.map +1 -1
- package/dist/logging/bootAudit.d.ts +11 -7
- package/dist/logging/bootAudit.d.ts.map +1 -1
- package/dist/logging/bootAudit.js +15 -7
- package/dist/logging/bootAudit.js.map +1 -1
- package/dist/logging/boundaryLogPayload.d.ts +4 -0
- package/dist/logging/boundaryLogPayload.d.ts.map +1 -1
- package/dist/logging/boundaryLogPayload.js +5 -1
- package/dist/logging/boundaryLogPayload.js.map +1 -1
- package/dist/logging/secretRedactor.d.ts +2 -0
- package/dist/logging/secretRedactor.d.ts.map +1 -1
- package/dist/logging/secretRedactor.js +8 -4
- package/dist/logging/secretRedactor.js.map +1 -1
- package/dist/logging/shortenForLog.d.ts +2 -0
- package/dist/logging/shortenForLog.d.ts.map +1 -1
- package/dist/logging/shortenForLog.js +7 -3
- package/dist/logging/shortenForLog.js.map +1 -1
- package/dist/logging/variablesLoggingMiddleware.d.ts +2 -0
- package/dist/logging/variablesLoggingMiddleware.d.ts.map +1 -1
- package/dist/logging/variablesLoggingMiddleware.js +8 -6
- package/dist/logging/variablesLoggingMiddleware.js.map +1 -1
- package/dist/metadataRefreshSignal.d.ts +19 -0
- package/dist/metadataRefreshSignal.d.ts.map +1 -0
- package/dist/metadataRefreshSignal.js +45 -0
- package/dist/metadataRefreshSignal.js.map +1 -0
- package/dist/middleware/MJTenantFilterMiddleware.js +4 -4
- package/dist/multiTenancy/index.d.ts +8 -0
- package/dist/multiTenancy/index.d.ts.map +1 -1
- package/dist/multiTenancy/index.js +21 -5
- package/dist/multiTenancy/index.js.map +1 -1
- package/dist/realtimeWidget/WidgetRouter.d.ts +5 -0
- package/dist/realtimeWidget/WidgetRouter.d.ts.map +1 -1
- package/dist/realtimeWidget/WidgetRouter.js +14 -10
- package/dist/realtimeWidget/WidgetRouter.js.map +1 -1
- package/dist/realtimeWidget/WidgetSessionService.d.ts +6 -6
- package/dist/realtimeWidget/WidgetSessionService.js +27 -27
- package/dist/realtimeWidget/host-identity.d.ts +5 -1
- package/dist/realtimeWidget/host-identity.d.ts.map +1 -1
- package/dist/realtimeWidget/host-identity.js +11 -3
- package/dist/realtimeWidget/host-identity.js.map +1 -1
- package/dist/realtimeWidget/index.d.ts +2 -2
- package/dist/realtimeWidget/index.d.ts.map +1 -1
- package/dist/realtimeWidget/index.js +2 -2
- package/dist/realtimeWidget/index.js.map +1 -1
- package/dist/realtimeWidget/visitorIdentity.d.ts +21 -1
- package/dist/realtimeWidget/visitorIdentity.d.ts.map +1 -1
- package/dist/realtimeWidget/visitorIdentity.js +16 -4
- package/dist/realtimeWidget/visitorIdentity.js.map +1 -1
- package/dist/realtimeWidget/widgetCore.d.ts +48 -0
- package/dist/realtimeWidget/widgetCore.d.ts.map +1 -1
- package/dist/realtimeWidget/widgetCore.js +38 -10
- package/dist/realtimeWidget/widgetCore.js.map +1 -1
- package/dist/realtimeWidget/widgetGuestElevation.d.ts +10 -6
- package/dist/realtimeWidget/widgetGuestElevation.d.ts.map +1 -1
- package/dist/realtimeWidget/widgetGuestElevation.js +14 -6
- package/dist/realtimeWidget/widgetGuestElevation.js.map +1 -1
- package/dist/resolvers/AdhocQueryResolver.js +3 -3
- package/dist/resolvers/FileResolver.js +3 -3
- package/dist/resolvers/GeoResolver.d.ts +2 -2
- package/dist/resolvers/GeoResolver.js +4 -4
- package/dist/resolvers/GetDataResolver.d.ts +14 -0
- package/dist/resolvers/GetDataResolver.d.ts.map +1 -1
- package/dist/resolvers/GetDataResolver.js +43 -15
- package/dist/resolvers/GetDataResolver.js.map +1 -1
- package/dist/resolvers/IntegrationDiscoveryResolver.js +2 -2
- package/dist/resolvers/ListOperationsResolver.d.ts +20 -0
- package/dist/resolvers/ListOperationsResolver.d.ts.map +1 -1
- package/dist/resolvers/ListOperationsResolver.js +68 -28
- package/dist/resolvers/ListOperationsResolver.js.map +1 -1
- package/dist/resolvers/MCPResolver.d.ts +11 -1
- package/dist/resolvers/MCPResolver.d.ts.map +1 -1
- package/dist/resolvers/MCPResolver.js +7 -3
- package/dist/resolvers/MCPResolver.js.map +1 -1
- package/dist/resolvers/RealtimeBridgeResolver.js +3 -3
- package/dist/resolvers/RealtimeClientSessionResolver.js +3 -3
- package/dist/resolvers/RemoteBrowserActionResolver.js +5 -5
- package/dist/resolvers/RunAIAgentResolver.d.ts +10 -4
- package/dist/resolvers/RunAIAgentResolver.d.ts.map +1 -1
- package/dist/resolvers/RunAIAgentResolver.js +69 -38
- package/dist/resolvers/RunAIAgentResolver.js.map +1 -1
- package/dist/resolvers/RunAIPromptResolver.d.ts +1 -1
- package/dist/resolvers/RunAIPromptResolver.js +2 -2
- package/dist/resolvers/RunTestResolver.js +5 -5
- package/dist/resolvers/SqlLoggingConfigResolver.d.ts +8 -4
- package/dist/resolvers/SqlLoggingConfigResolver.d.ts.map +1 -1
- package/dist/resolvers/SqlLoggingConfigResolver.js +5 -5
- package/dist/resolvers/TaskGraphFrameResolver.d.ts +8 -1
- package/dist/resolvers/TaskGraphFrameResolver.d.ts.map +1 -1
- package/dist/resolvers/TaskGraphFrameResolver.js +6 -2
- package/dist/resolvers/TaskGraphFrameResolver.js.map +1 -1
- package/dist/resolvers/adhoc-query-helpers.d.ts +6 -0
- package/dist/resolvers/adhoc-query-helpers.d.ts.map +1 -1
- package/dist/resolvers/adhoc-query-helpers.js +10 -2
- package/dist/resolvers/adhoc-query-helpers.js.map +1 -1
- package/dist/resolvers/artifact-routing.d.ts +8 -8
- package/dist/resolvers/artifact-routing.js +2 -2
- package/dist/resolvers/artifact-routing.js.map +1 -1
- package/dist/resolvers/meetingRecordingRegistration.d.ts +10 -2
- package/dist/resolvers/meetingRecordingRegistration.d.ts.map +1 -1
- package/dist/resolvers/meetingRecordingRegistration.js +24 -8
- package/dist/resolvers/meetingRecordingRegistration.js.map +1 -1
- package/dist/resolvers/peaksSidecar.d.ts +4 -0
- package/dist/resolvers/peaksSidecar.d.ts.map +1 -1
- package/dist/resolvers/peaksSidecar.js +10 -2
- package/dist/resolvers/peaksSidecar.js.map +1 -1
- package/dist/rest/EntityCRUDHandler.d.ts +28 -0
- package/dist/rest/EntityCRUDHandler.d.ts.map +1 -1
- package/dist/rest/EntityCRUDHandler.js +20 -4
- package/dist/rest/EntityCRUDHandler.js.map +1 -1
- package/dist/rest/MediaStreamHandler.d.ts +2 -0
- package/dist/rest/MediaStreamHandler.d.ts.map +1 -1
- package/dist/rest/MediaStreamHandler.js +10 -6
- package/dist/rest/MediaStreamHandler.js.map +1 -1
- package/dist/rest/OAuthCallbackHandler.d.ts +9 -0
- package/dist/rest/OAuthCallbackHandler.d.ts.map +1 -1
- package/dist/rest/OAuthCallbackHandler.js +15 -3
- package/dist/rest/OAuthCallbackHandler.js.map +1 -1
- package/dist/rest/RESTEndpointHandler.d.ts +6 -4
- package/dist/rest/RESTEndpointHandler.d.ts.map +1 -1
- package/dist/rest/RESTEndpointHandler.js +15 -11
- package/dist/rest/RESTEndpointHandler.js.map +1 -1
- package/dist/rest/RealtimeSdpBrokerHandler.d.ts +5 -1
- package/dist/rest/RealtimeSdpBrokerHandler.d.ts.map +1 -1
- package/dist/rest/RealtimeSdpBrokerHandler.js +12 -4
- package/dist/rest/RealtimeSdpBrokerHandler.js.map +1 -1
- package/dist/rest/SignatureWebhookHandler.d.ts +2 -0
- package/dist/rest/SignatureWebhookHandler.d.ts.map +1 -1
- package/dist/rest/SignatureWebhookHandler.js +5 -1
- package/dist/rest/SignatureWebhookHandler.js.map +1 -1
- package/dist/rest/UploadTokenManager.d.ts +24 -8
- package/dist/rest/UploadTokenManager.d.ts.map +1 -1
- package/dist/rest/UploadTokenManager.js +53 -21
- package/dist/rest/UploadTokenManager.js.map +1 -1
- package/dist/rest/ViewOperationsHandler.d.ts +20 -0
- package/dist/rest/ViewOperationsHandler.d.ts.map +1 -1
- package/dist/rest/ViewOperationsHandler.js +20 -4
- package/dist/rest/ViewOperationsHandler.js.map +1 -1
- package/dist/rest/mediaRange.d.ts +4 -0
- package/dist/rest/mediaRange.d.ts.map +1 -1
- package/dist/rest/mediaRange.js +10 -2
- package/dist/rest/mediaRange.js.map +1 -1
- package/dist/rest/setupRESTEndpoints.d.ts +4 -0
- package/dist/rest/setupRESTEndpoints.d.ts.map +1 -1
- package/dist/rest/setupRESTEndpoints.js +13 -7
- package/dist/rest/setupRESTEndpoints.js.map +1 -1
- package/dist/serverExtensionReservedRoots.d.ts +2 -0
- package/dist/serverExtensionReservedRoots.d.ts.map +1 -1
- package/dist/serverExtensionReservedRoots.js +5 -1
- package/dist/serverExtensionReservedRoots.js.map +1 -1
- package/dist/services/TaskGraphActionRunner.d.ts +13 -8
- package/dist/services/TaskGraphActionRunner.d.ts.map +1 -1
- package/dist/services/TaskGraphActionRunner.js +16 -15
- package/dist/services/TaskGraphActionRunner.js.map +1 -1
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +7 -3
- package/dist/types.js.map +1 -1
- package/dist/util.d.ts +6 -0
- package/dist/util.d.ts.map +1 -1
- package/dist/util.js +13 -5
- package/dist/util.js.map +1 -1
- package/package.json +92 -92
- package/src/__tests__/DeleteOptionsInput.wireShape.test.ts +62 -0
- package/src/__tests__/FileResolverPeaks.test.ts +13 -13
- package/src/__tests__/ListOperationsResolver.test.ts +17 -17
- package/src/__tests__/MediaStreamHandler.test.ts +28 -28
- package/src/__tests__/NoLog.test.ts +11 -11
- package/src/__tests__/PrimaryKeyAlwaysMapped.test.ts +10 -10
- package/src/__tests__/RESTEndpointHandler.test.ts +14 -14
- package/src/__tests__/RealtimeBridgeResolver.test.ts +4 -2
- package/src/__tests__/RealtimeSdpBrokerHandler.test.ts +6 -6
- package/src/__tests__/RefreshAdoptsNewColumns.test.ts +8 -8
- package/src/__tests__/RemoteBrowserGoalEngine.test.ts +18 -18
- package/src/__tests__/RunAIAgentResolver.historyFrom.test.ts +228 -0
- package/src/__tests__/TaskGraphActionRunner.durablePayload.test.ts +129 -0
- package/src/__tests__/TaskGraphFrameResolver.test.ts +2 -2
- package/src/__tests__/WidgetSessionService.test.ts +8 -4
- package/src/__tests__/adhoc-query-helpers.test.ts +21 -21
- package/src/__tests__/bootAudit.test.ts +11 -11
- package/src/__tests__/boundaryLogPayload.test.ts +6 -6
- package/src/__tests__/cacheInvalidationRecordData.test.ts +177 -0
- package/src/__tests__/databaseAbstraction.test.ts +12 -6
- package/src/__tests__/getDataTokenRedaction.test.ts +7 -7
- package/src/__tests__/initializeProviders.refresh.test.ts +4 -4
- package/src/__tests__/magicLink.test.ts +73 -134
- package/src/__tests__/magicLinkService.consume.test.ts +224 -0
- package/src/__tests__/meetingRecordingRegistration.test.ts +12 -12
- package/src/__tests__/metadataRefreshSignal.test.ts +78 -0
- package/src/__tests__/multiTenancy.security.test.ts +40 -40
- package/src/__tests__/multiTenancy.test.ts +18 -18
- package/src/__tests__/newUsers.test.ts +24 -23
- package/src/__tests__/principals.test.ts +22 -22
- package/src/__tests__/pushStatusResolver.filter.test.ts +8 -8
- package/src/__tests__/secretRedactor.failOpen.test.ts +12 -12
- package/src/__tests__/secretRedactor.test.ts +12 -12
- package/src/__tests__/serverExtensionReservedRoots.test.ts +7 -7
- package/src/__tests__/subscriptionRedaction.test.ts +5 -5
- package/src/__tests__/unifiedAuth.test.ts +15 -9
- package/src/__tests__/visitorIdentity.resolve.test.ts +6 -6
- package/src/__tests__/widget.test.ts +45 -45
- package/src/__tests__/widgetGuestElevation.test.ts +7 -7
- package/src/__tests__/widgetHostIdentity.test.ts +14 -14
- package/src/agentSessions/ReturningVisitorRecap.ts +12 -1
- package/src/agentSessions/SessionManager.ts +2 -2
- package/src/agentSessions/remoteBrowserGoalEngine.ts +30 -5
- package/src/auth/AuthProviderCatalogRouter.ts +6 -1
- package/src/auth/__tests__/backward-compatibility.test.ts +3 -3
- package/src/auth/index.ts +43 -28
- package/src/auth/initializeProviders.ts +25 -5
- package/src/auth/magicLink/MagicLinkRouter.ts +28 -10
- package/src/auth/magicLink/MagicLinkService.ts +71 -52
- package/src/auth/magicLink/index.ts +7 -7
- package/src/auth/magicLink/magicLinkCore.ts +96 -64
- package/src/auth/magicLink/redeemLanding.ts +14 -4
- package/src/auth/magicLink/types.ts +54 -54
- package/src/auth/newUsers.ts +1 -1
- package/src/auth/principals.ts +11 -2
- package/src/cache.ts +4 -1
- package/src/config.ts +37 -4
- package/src/context.ts +37 -24
- package/src/directives/Public.ts +4 -1
- package/src/directives/RequireSystemUser.ts +4 -1
- package/src/generated/graphql-schemas/__mj.ts +37 -0
- package/src/generic/CacheInvalidationResolver.ts +148 -4
- package/src/generic/DeleteOptionsInput.ts +9 -2
- package/src/generic/FireAndForgetHeartbeat.ts +19 -14
- package/src/generic/PushStatusResolver.ts +21 -7
- package/src/generic/ResolverBase.ts +16 -8
- package/src/generic/RunViewResolver.ts +22 -22
- package/src/generic/__tests__/FireAndForgetHeartbeat.test.ts +7 -7
- package/src/index.ts +35 -9
- package/src/integration/CustomColumnPromoter.ts +6 -1
- package/src/integration/EntityMapLifecycle.ts +20 -2
- package/src/logging/NoLog.ts +16 -2
- package/src/logging/StartupLogger.ts +6 -1
- package/src/logging/bootAudit.ts +26 -16
- package/src/logging/boundaryLogPayload.ts +8 -1
- package/src/logging/secretRedactor.ts +14 -9
- package/src/logging/shortenForLog.ts +8 -3
- package/src/logging/variablesLoggingMiddleware.ts +9 -6
- package/src/metadataRefreshSignal.ts +45 -0
- package/src/middleware/MJTenantFilterMiddleware.ts +4 -4
- package/src/multiTenancy/index.ts +29 -5
- package/src/realtimeWidget/WidgetRouter.ts +15 -10
- package/src/realtimeWidget/WidgetSessionService.ts +76 -76
- package/src/realtimeWidget/host-identity.ts +24 -10
- package/src/realtimeWidget/index.ts +3 -3
- package/src/realtimeWidget/visitorIdentity.ts +39 -8
- package/src/realtimeWidget/widgetCore.ts +75 -10
- package/src/realtimeWidget/widgetGuestElevation.ts +25 -12
- package/src/resolvers/AdhocQueryResolver.ts +3 -3
- package/src/resolvers/AgentSessionResolver.ts +3 -3
- package/src/resolvers/ColorResolver.ts +6 -6
- package/src/resolvers/ComponentRegistryResolver.ts +36 -36
- package/src/resolvers/EntityCommunicationsResolver.ts +4 -4
- package/src/resolvers/ExecuteRemoteOperationResolver.ts +9 -9
- package/src/resolvers/FileResolver.ts +42 -42
- package/src/resolvers/GeoResolver.ts +4 -4
- package/src/resolvers/GetDataResolver.ts +50 -15
- package/src/resolvers/IntegrationDiscoveryResolver.ts +2 -2
- package/src/resolvers/ListOperationsResolver.ts +78 -28
- package/src/resolvers/MCPResolver.ts +30 -15
- package/src/resolvers/QueryResolver.ts +13 -13
- package/src/resolvers/RealtimeBridgeResolver.ts +3 -3
- package/src/resolvers/RealtimeClientSessionResolver.ts +3 -3
- package/src/resolvers/RemoteBrowserActionResolver.ts +5 -5
- package/src/resolvers/RunAIAgentResolver.ts +113 -72
- package/src/resolvers/RunAIPromptResolver.ts +22 -22
- package/src/resolvers/RunTemplateResolver.ts +4 -4
- package/src/resolvers/RunTestResolver.ts +25 -25
- package/src/resolvers/SqlLoggingConfigResolver.ts +56 -56
- package/src/resolvers/TaskGraphFrameResolver.ts +37 -28
- package/src/resolvers/TelemetryResolver.ts +79 -79
- package/src/resolvers/__tests__/GetDataResolver.tokens.test.ts +40 -38
- package/src/resolvers/__tests__/artifact-routing.test.ts +23 -23
- package/src/resolvers/adhoc-query-helpers.ts +19 -2
- package/src/resolvers/artifact-routing.ts +19 -19
- package/src/resolvers/meetingRecordingRegistration.ts +44 -10
- package/src/resolvers/peaksSidecar.ts +12 -2
- package/src/rest/EntityCRUDHandler.ts +24 -4
- package/src/rest/MediaStreamHandler.ts +11 -6
- package/src/rest/OAuthCallbackHandler.ts +25 -7
- package/src/rest/RESTEndpointHandler.ts +20 -15
- package/src/rest/RealtimeSdpBrokerHandler.ts +14 -4
- package/src/rest/SignatureWebhookHandler.ts +6 -1
- package/src/rest/UploadTokenManager.ts +66 -30
- package/src/rest/ViewOperationsHandler.ts +24 -4
- package/src/rest/mediaRange.ts +16 -6
- package/src/rest/setupRESTEndpoints.ts +24 -12
- package/src/serverExtensionReservedRoots.ts +6 -1
- package/src/services/TaskGraphActionRunner.ts +16 -15
- package/src/types.ts +21 -16
- package/src/util.ts +16 -6
|
@@ -5,11 +5,11 @@ import { MJComputerUseEngine, MJRunComputerUseParams } from '@memberjunction/com
|
|
|
5
5
|
import { CdpRemoteBrowserSession, type ComputerUseGoalRun } from '@memberjunction/remote-browser-cdp';
|
|
6
6
|
import type { MJAIAgentRunStepEntity } from '@memberjunction/core-entities';
|
|
7
7
|
import {
|
|
8
|
-
|
|
8
|
+
BuildMJGoalParams,
|
|
9
9
|
BindRemoteBrowserGoalEngine,
|
|
10
10
|
MJProgressComputerUseEngine,
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
ExtractCoAgentRunID,
|
|
12
|
+
FinalizeBrowserGoalStep,
|
|
13
13
|
} from '../agentSessions/remoteBrowserGoalEngine.js';
|
|
14
14
|
|
|
15
15
|
const USER = { ID: 'u-1', Email: 'amith@bluecypress.io' } as unknown as UserInfo;
|
|
@@ -21,7 +21,7 @@ function baseParams(): RunComputerUseParams {
|
|
|
21
21
|
|
|
22
22
|
describe('buildMJGoalParams', () => {
|
|
23
23
|
it('produces MJ-aware params that carry over the base goal/step/url fields', () => {
|
|
24
|
-
const mj =
|
|
24
|
+
const mj = BuildMJGoalParams(baseParams(), USER);
|
|
25
25
|
expect(mj).toBeInstanceOf(MJRunComputerUseParams);
|
|
26
26
|
expect(mj.Goal).toBe('log in');
|
|
27
27
|
expect(mj.MaxSteps).toBe(7);
|
|
@@ -29,21 +29,21 @@ describe('buildMJGoalParams', () => {
|
|
|
29
29
|
});
|
|
30
30
|
|
|
31
31
|
it('injects the acting ContextUser so MJ prompts run as that user', () => {
|
|
32
|
-
expect(
|
|
32
|
+
expect(BuildMJGoalParams(baseParams(), USER).ContextUser).toBe(USER);
|
|
33
33
|
});
|
|
34
34
|
|
|
35
35
|
it('leaves ContextUser undefined when none is supplied', () => {
|
|
36
|
-
expect(
|
|
36
|
+
expect(BuildMJGoalParams(baseParams()).ContextUser).toBeUndefined();
|
|
37
37
|
});
|
|
38
38
|
|
|
39
39
|
it('threads the parent run + step ids for observability nesting', () => {
|
|
40
|
-
const mj =
|
|
40
|
+
const mj = BuildMJGoalParams(baseParams(), USER, 'coagent-run-1', 'goal-step-1');
|
|
41
41
|
expect(mj.AgentRunId).toBe('coagent-run-1');
|
|
42
42
|
expect(mj.AgentRunStepID).toBe('goal-step-1');
|
|
43
43
|
});
|
|
44
44
|
|
|
45
45
|
it('leaves the run/step ids undefined when not supplied', () => {
|
|
46
|
-
const mj =
|
|
46
|
+
const mj = BuildMJGoalParams(baseParams(), USER);
|
|
47
47
|
expect(mj.AgentRunId).toBeUndefined();
|
|
48
48
|
expect(mj.AgentRunStepID).toBeUndefined();
|
|
49
49
|
});
|
|
@@ -51,17 +51,17 @@ describe('buildMJGoalParams', () => {
|
|
|
51
51
|
|
|
52
52
|
describe('extractCoAgentRunID', () => {
|
|
53
53
|
it('pulls coAgentRunID out of a session Config_ blob', () => {
|
|
54
|
-
expect(
|
|
54
|
+
expect(ExtractCoAgentRunID(JSON.stringify({ coAgentRunID: 'run-9', promptRunID: 'p' }))).toBe('run-9');
|
|
55
55
|
});
|
|
56
56
|
it('returns undefined for a missing key, null/empty config, or non-string value', () => {
|
|
57
|
-
expect(
|
|
58
|
-
expect(
|
|
59
|
-
expect(
|
|
60
|
-
expect(
|
|
61
|
-
expect(
|
|
57
|
+
expect(ExtractCoAgentRunID(JSON.stringify({ promptRunID: 'p' }))).toBeUndefined();
|
|
58
|
+
expect(ExtractCoAgentRunID(null)).toBeUndefined();
|
|
59
|
+
expect(ExtractCoAgentRunID(undefined)).toBeUndefined();
|
|
60
|
+
expect(ExtractCoAgentRunID('')).toBeUndefined();
|
|
61
|
+
expect(ExtractCoAgentRunID(JSON.stringify({ coAgentRunID: 123 }))).toBeUndefined();
|
|
62
62
|
});
|
|
63
63
|
it('returns undefined for malformed JSON (best-effort)', () => {
|
|
64
|
-
expect(
|
|
64
|
+
expect(ExtractCoAgentRunID('{not json')).toBeUndefined();
|
|
65
65
|
});
|
|
66
66
|
});
|
|
67
67
|
|
|
@@ -76,7 +76,7 @@ describe('finalizeBrowserGoalStep', () => {
|
|
|
76
76
|
|
|
77
77
|
it('finalizes the parent step Completed from a successful goal result + saves', async () => {
|
|
78
78
|
const step = fakeStep();
|
|
79
|
-
await
|
|
79
|
+
await FinalizeBrowserGoalStep(step, { Success: true, Strategy: 'ComputerUse', Status: 'Completed', StepCount: 4, CurrentUrl: 'https://done/' });
|
|
80
80
|
expect(step.Status).toBe('Completed');
|
|
81
81
|
expect(step.Success).toBe(true);
|
|
82
82
|
expect((step as unknown as { Save: ReturnType<typeof vi.fn> }).Save).toHaveBeenCalledOnce();
|
|
@@ -87,13 +87,13 @@ describe('finalizeBrowserGoalStep', () => {
|
|
|
87
87
|
|
|
88
88
|
it('finalizes Failed and carries the detail as the error message', async () => {
|
|
89
89
|
const step = fakeStep();
|
|
90
|
-
await
|
|
90
|
+
await FinalizeBrowserGoalStep(step, { Success: false, Status: 'Error', Detail: 'login blocked' });
|
|
91
91
|
expect(step.Status).toBe('Failed');
|
|
92
92
|
expect(step.ErrorMessage).toBe('login blocked');
|
|
93
93
|
});
|
|
94
94
|
|
|
95
95
|
it('is a no-op when the step is null (no co-agent run to nest under)', async () => {
|
|
96
|
-
await expect(
|
|
96
|
+
await expect(FinalizeBrowserGoalStep(null, { Success: true })).resolves.toBeUndefined();
|
|
97
97
|
});
|
|
98
98
|
});
|
|
99
99
|
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview The agent's history floor on `RunAIAgentFromConversationDetail`.
|
|
3
|
+
*
|
|
4
|
+
* `agentHistoryFrom` is the one server change behind the conversations host rules: an optional
|
|
5
|
+
* ISO-8601 timestamp, the first moment of the conversation a run may read. These tests pin that
|
|
6
|
+
* the mutation parses it before anything loads, fails the request on an unreadable value instead
|
|
7
|
+
* of dropping it, loads history from it (in the query AND in the window assembly), and hands it to
|
|
8
|
+
* the agent run as `ConversationHistoryFrom` on both the synchronous and fire-and-forget paths —
|
|
9
|
+
* and that leaving it out changes nothing.
|
|
10
|
+
*/
|
|
11
|
+
import 'reflect-metadata'; // must precede any type-graphql decorator evaluation
|
|
12
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
13
|
+
import type { PubSubEngine } from 'type-graphql';
|
|
14
|
+
|
|
15
|
+
// type-graphql's real decorators need emitDecoratorMetadata, which vitest's esbuild transform
|
|
16
|
+
// does not emit; the schema is irrelevant here, so every decorator is a no-op.
|
|
17
|
+
vi.mock('type-graphql', () => {
|
|
18
|
+
const decoratorFactory = (..._args: unknown[]) => (..._decorated: unknown[]) => undefined;
|
|
19
|
+
const exportNames = [
|
|
20
|
+
'Resolver', 'Query', 'Mutation', 'Subscription', 'Arg', 'Args', 'ArgsType', 'Ctx', 'Root',
|
|
21
|
+
'Info', 'Field', 'FieldResolver', 'ObjectType', 'InputType', 'InterfaceType', 'Authorized',
|
|
22
|
+
'UseMiddleware', 'Extensions', 'Directive', 'ID', 'Int', 'Float', 'GraphQLISODateTime',
|
|
23
|
+
'GraphQLTimestamp', 'registerEnumType', 'createMethodDecorator', 'createParamDecorator',
|
|
24
|
+
'buildSchema', 'buildSchemaSync', 'PubSub',
|
|
25
|
+
];
|
|
26
|
+
return Object.fromEntries(exportNames.map((name) => [name, decoratorFactory]));
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const hoisted = vi.hoisted(() => ({
|
|
30
|
+
runAgentInConversation: vi.fn(),
|
|
31
|
+
}));
|
|
32
|
+
|
|
33
|
+
vi.mock('@memberjunction/ai-agents', () => ({
|
|
34
|
+
AgentRunner: class {
|
|
35
|
+
RunAgentInConversation(...args: unknown[]) {
|
|
36
|
+
return hoisted.runAgentInConversation(...args);
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
ArtifactToolManager: class {},
|
|
40
|
+
}));
|
|
41
|
+
|
|
42
|
+
vi.mock('../realtimeWidget/widgetGuestElevation.js', () => ({
|
|
43
|
+
ResolveWidgetGuestRunContext: vi.fn().mockResolvedValue(null),
|
|
44
|
+
ElevateUserPayload: vi.fn(),
|
|
45
|
+
}));
|
|
46
|
+
|
|
47
|
+
import { ConversationEngine } from '@memberjunction/core-entities';
|
|
48
|
+
import { RunAIAgentResolver } from '../resolvers/RunAIAgentResolver.js';
|
|
49
|
+
import type { AppContext, UserPayload } from '../types.js';
|
|
50
|
+
|
|
51
|
+
const FLOOR_ISO = '2026-09-01T12:00:00.000Z';
|
|
52
|
+
const USER = { ID: 'user-1', Email: 'user@example.com' };
|
|
53
|
+
|
|
54
|
+
type Fn = ReturnType<typeof vi.fn>;
|
|
55
|
+
|
|
56
|
+
/** The private members this test reaches, through an explicit shape (no `any`). */
|
|
57
|
+
interface ResolverSeams {
|
|
58
|
+
CheckAPIKeyScopeAuthorization: Fn;
|
|
59
|
+
GetUserFromPayload: Fn;
|
|
60
|
+
loadConversationHistoryWithAttachments: Fn;
|
|
61
|
+
executeAIAgent: Fn;
|
|
62
|
+
executeAgentInBackground: Fn;
|
|
63
|
+
loadInputArtifactsBatch: Fn;
|
|
64
|
+
validateAgent: Fn;
|
|
65
|
+
persistInFlightAgentFailure: Fn;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function makeResolver(): { resolver: RunAIAgentResolver; seams: ResolverSeams } {
|
|
69
|
+
const resolver = new RunAIAgentResolver();
|
|
70
|
+
const seams = resolver as unknown as ResolverSeams;
|
|
71
|
+
seams.CheckAPIKeyScopeAuthorization = vi.fn().mockResolvedValue(undefined);
|
|
72
|
+
seams.GetUserFromPayload = vi.fn().mockReturnValue(USER);
|
|
73
|
+
return { resolver, seams };
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function makeContext(): AppContext {
|
|
77
|
+
const provider = {
|
|
78
|
+
GetEntityObject: vi.fn().mockResolvedValue({
|
|
79
|
+
ConversationID: 'conv-1',
|
|
80
|
+
Load: vi.fn().mockResolvedValue(true),
|
|
81
|
+
}),
|
|
82
|
+
};
|
|
83
|
+
return {
|
|
84
|
+
userPayload: { sessionId: 'session-1', userRecord: USER } as unknown as UserPayload,
|
|
85
|
+
providers: [{ type: 'Read-Write', provider }],
|
|
86
|
+
dataSource: {},
|
|
87
|
+
} as unknown as AppContext;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const pubSub = { publish: vi.fn() } as unknown as PubSubEngine;
|
|
91
|
+
|
|
92
|
+
async function runMutation(
|
|
93
|
+
resolver: RunAIAgentResolver,
|
|
94
|
+
options: { agentHistoryFrom?: string; fireAndForget?: boolean }
|
|
95
|
+
) {
|
|
96
|
+
return resolver.RunAIAgentFromConversationDetail(
|
|
97
|
+
'detail-1', 'agent-1', makeContext(), 'session-1', pubSub,
|
|
98
|
+
undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined,
|
|
99
|
+
undefined, undefined, options.fireAndForget, undefined, undefined,
|
|
100
|
+
options.agentHistoryFrom
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
afterEach(() => {
|
|
105
|
+
vi.restoreAllMocks();
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
describe('RunAIAgentFromConversationDetail — agentHistoryFrom', () => {
|
|
109
|
+
let resolver: RunAIAgentResolver;
|
|
110
|
+
let seams: ResolverSeams;
|
|
111
|
+
|
|
112
|
+
beforeEach(() => {
|
|
113
|
+
({ resolver, seams } = makeResolver());
|
|
114
|
+
seams.loadConversationHistoryWithAttachments = vi.fn().mockResolvedValue([]);
|
|
115
|
+
seams.executeAIAgent = vi.fn().mockResolvedValue({ success: true, result: '{}' });
|
|
116
|
+
seams.executeAgentInBackground = vi.fn();
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it('loads history from the floor and hands the floor to the run', async () => {
|
|
120
|
+
const result = await runMutation(resolver, { agentHistoryFrom: FLOOR_ISO });
|
|
121
|
+
|
|
122
|
+
expect(result.success).toBe(true);
|
|
123
|
+
const loaderArgs = seams.loadConversationHistoryWithAttachments.mock.calls[0];
|
|
124
|
+
expect(loaderArgs[0]).toBe('conv-1');
|
|
125
|
+
expect(loaderArgs[4]).toEqual(['detail-1']);
|
|
126
|
+
expect((loaderArgs[5] as Date).toISOString()).toBe(FLOOR_ISO);
|
|
127
|
+
const runFloor = seams.executeAIAgent.mock.calls[0].at(-1) as Date;
|
|
128
|
+
expect(runFloor.toISOString()).toBe(FLOOR_ISO);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it('hands the floor to a fire-and-forget run too', async () => {
|
|
132
|
+
const result = await runMutation(resolver, { agentHistoryFrom: FLOOR_ISO, fireAndForget: true });
|
|
133
|
+
|
|
134
|
+
expect(result.success).toBe(true);
|
|
135
|
+
expect(seams.executeAIAgent).not.toHaveBeenCalled();
|
|
136
|
+
const runFloor = seams.executeAgentInBackground.mock.calls[0].at(-1) as Date;
|
|
137
|
+
expect(runFloor.toISOString()).toBe(FLOOR_ISO);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it('left out, reads the whole conversation as before', async () => {
|
|
141
|
+
await runMutation(resolver, {});
|
|
142
|
+
|
|
143
|
+
expect(seams.loadConversationHistoryWithAttachments.mock.calls[0][5]).toBeUndefined();
|
|
144
|
+
expect(seams.executeAIAgent.mock.calls[0].at(-1)).toBeUndefined();
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it('fails the request on an unreadable floor, before loading or running anything', async () => {
|
|
148
|
+
const result = await runMutation(resolver, { agentHistoryFrom: 'last tuesday' });
|
|
149
|
+
|
|
150
|
+
expect(result.success).toBe(false);
|
|
151
|
+
expect(result.errorMessage).toContain('agentHistoryFrom');
|
|
152
|
+
expect(seams.loadConversationHistoryWithAttachments).not.toHaveBeenCalled();
|
|
153
|
+
expect(seams.executeAIAgent).not.toHaveBeenCalled();
|
|
154
|
+
expect(seams.executeAgentInBackground).not.toHaveBeenCalled();
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
it('treats an empty string as unreadable too, never as "no floor"', async () => {
|
|
158
|
+
const result = await runMutation(resolver, { agentHistoryFrom: '' });
|
|
159
|
+
|
|
160
|
+
expect(result.success).toBe(false);
|
|
161
|
+
expect(seams.executeAIAgent).not.toHaveBeenCalled();
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
describe('loadConversationHistoryWithAttachments — history floor', () => {
|
|
166
|
+
it('passes the floor to the fresh loader and to the window assembly', async () => {
|
|
167
|
+
const { resolver, seams } = makeResolver();
|
|
168
|
+
seams.loadInputArtifactsBatch = vi.fn().mockResolvedValue(new Map());
|
|
169
|
+
const loadRows = vi.spyOn(ConversationEngine, 'LoadWindowRowsFresh').mockResolvedValue([]);
|
|
170
|
+
const assemble = vi.spyOn(ConversationEngine, 'AssembleContextWindow');
|
|
171
|
+
const floor = new Date(FLOOR_ISO);
|
|
172
|
+
const provider = {};
|
|
173
|
+
|
|
174
|
+
const load = (resolver as unknown as {
|
|
175
|
+
loadConversationHistoryWithAttachments(
|
|
176
|
+
conversationId: string, user: unknown, max: number, provider: unknown, exclude?: string[], historyFrom?: Date
|
|
177
|
+
): Promise<unknown[]>;
|
|
178
|
+
}).loadConversationHistoryWithAttachments.bind(resolver);
|
|
179
|
+
await load('conv-1', USER, 20, provider, ['detail-1'], floor);
|
|
180
|
+
|
|
181
|
+
expect(loadRows).toHaveBeenCalledWith('conv-1', USER, provider, floor);
|
|
182
|
+
expect(assemble.mock.calls[0][1]).toEqual({ maxTailMessages: 20, excludeDetailIds: ['detail-1'], historyFrom: floor });
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
describe('executeAIAgent — ConversationHistoryFrom', () => {
|
|
187
|
+
function wire() {
|
|
188
|
+
const { resolver, seams } = makeResolver();
|
|
189
|
+
seams.validateAgent = vi.fn().mockResolvedValue({ ID: 'agent-1', Name: 'Test Agent' });
|
|
190
|
+
seams.persistInFlightAgentFailure = vi.fn().mockResolvedValue(undefined);
|
|
191
|
+
// Stop right after the params are captured — the rest of the run is out of scope, and so
|
|
192
|
+
// is the failure it logs.
|
|
193
|
+
hoisted.runAgentInConversation.mockReset().mockRejectedValue(new Error('stop here'));
|
|
194
|
+
vi.spyOn(console, 'error').mockImplementation(() => undefined);
|
|
195
|
+
vi.spyOn(console, 'log').mockImplementation(() => undefined);
|
|
196
|
+
const execute = (resolver as unknown as {
|
|
197
|
+
executeAIAgent(...args: unknown[]): Promise<{ success: boolean }>;
|
|
198
|
+
}).executeAIAgent.bind(resolver);
|
|
199
|
+
return execute;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function positional(conversationHistoryFrom?: Date): unknown[] {
|
|
203
|
+
const userPayload = { sessionId: 'session-1', userRecord: USER };
|
|
204
|
+
return [
|
|
205
|
+
{}, {}, 'agent-1', userPayload, '[{"role":"user","content":"hi"}]', 'session-1', pubSub,
|
|
206
|
+
undefined, undefined, undefined, undefined, undefined, undefined, 'detail-1', false, false,
|
|
207
|
+
undefined, undefined, 'conv-1', undefined, undefined, undefined, undefined,
|
|
208
|
+
conversationHistoryFrom,
|
|
209
|
+
];
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
it('puts the floor on the run\'s params', async () => {
|
|
213
|
+
const execute = wire();
|
|
214
|
+
const floor = new Date(FLOOR_ISO);
|
|
215
|
+
await execute(...positional(floor));
|
|
216
|
+
|
|
217
|
+
const params = hoisted.runAgentInConversation.mock.calls[0][0] as Record<string, unknown>;
|
|
218
|
+
expect(params.ConversationHistoryFrom).toBe(floor);
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
it('leaves it unset without a floor', async () => {
|
|
222
|
+
const execute = wire();
|
|
223
|
+
await execute(...positional());
|
|
224
|
+
|
|
225
|
+
const params = hoisted.runAgentInConversation.mock.calls[0][0] as Record<string, unknown>;
|
|
226
|
+
expect(params.ConversationHistoryFrom).toBeUndefined();
|
|
227
|
+
});
|
|
228
|
+
});
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* End-to-end-in-miniature regression test for #4794.
|
|
3
|
+
*
|
|
4
|
+
* The bug: `BuildDurableDeferral` persisted a durable entity action's redacted params as a
|
|
5
|
+
* `LoggedParam[]` ARRAY (`RedactParamsToJSON`'s shape), while `TaskGraphActionRunner.buildParams`
|
|
6
|
+
* reads `Task.InputPayload` back as a name→value RECORD. Every released build with durable dispatch
|
|
7
|
+
* (v6.1.0 onward, including 6.1.4) hit the same real-world failure: `TaskGraphDispatcher`'s
|
|
8
|
+
* `mergedPayload` only merges plain objects, so it silently dropped the array before `buildParams`
|
|
9
|
+
* ever saw it, and the action ran with NONE of its declared inputs. `buildParams` itself has no such
|
|
10
|
+
* guard — `Object.assign(merged, arrayValue)` treats an array's indices as keys — so params named
|
|
11
|
+
* `'0'`, `'1'`, ... would only appear if the array reached it directly, bypassing the dispatcher's
|
|
12
|
+
* drop. That narrower path is exactly what this test exercises, by calling `RunActionForTask`
|
|
13
|
+
* on its own rather than through the dispatcher.
|
|
14
|
+
*
|
|
15
|
+
* This test proves the whole pipe, not just the writer or the reader in isolation: build the
|
|
16
|
+
* payload exactly as the deferral does (`RedactParamsToRecord`), push it through the same
|
|
17
|
+
* `JSON.stringify` / `JSON.parse` round trip `TaskGraphService` performs to persist and reload
|
|
18
|
+
* `Task.InputPayload`, then run it through the real `TaskGraphActionRunner` and assert the action
|
|
19
|
+
* receives its declared parameters BY NAME.
|
|
20
|
+
*/
|
|
21
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
22
|
+
|
|
23
|
+
vi.mock('@memberjunction/actions', () => ({
|
|
24
|
+
ActionEngineServer: {
|
|
25
|
+
Instance: {
|
|
26
|
+
Config: vi.fn(),
|
|
27
|
+
Actions: [{ ID: 'A1', Name: 'Log Activity' }],
|
|
28
|
+
RunAction: vi.fn(),
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
}));
|
|
32
|
+
|
|
33
|
+
import { ActionEngineServer } from '@memberjunction/actions';
|
|
34
|
+
import { RedactParamsToRecord, ActionParam } from '@memberjunction/actions-base';
|
|
35
|
+
import type { MJActionExecutionLogEntity, MJActionParamEntity, MJEntityActionParamEntity } from '@memberjunction/core-entities';
|
|
36
|
+
import type { IMetadataProvider, UserInfo } from '@memberjunction/core';
|
|
37
|
+
import type { TaskActionRunParams } from '@memberjunction/task-graph';
|
|
38
|
+
import { TaskGraphActionRunner } from '../services/TaskGraphActionRunner';
|
|
39
|
+
|
|
40
|
+
// ── Test fixture builders — same shape as packages/Actions/Base/src/__tests__/ParamRedaction.test.ts ──
|
|
41
|
+
|
|
42
|
+
function actionParam(name: string, value: unknown): ActionParam {
|
|
43
|
+
return { Name: name, Value: value, Type: 'Input' } as ActionParam;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function definition(id: string, name: string, logValue: boolean = true): MJActionParamEntity {
|
|
47
|
+
return { ID: id, Name: name, LogValue: logValue } as MJActionParamEntity;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function binding(actionParamID: string, valueType: string, logValue: boolean | null = null): MJEntityActionParamEntity {
|
|
51
|
+
return { ActionParamID: actionParamID, ValueType: valueType, LogValue: logValue } as MJEntityActionParamEntity;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// The declared parameters for the durable entity action under test: three that log normally, and
|
|
55
|
+
// one ("InternalNotes") whose binding opts out of logging (rule 2 in ParamRedaction.ts).
|
|
56
|
+
const RUNTIME_PARAMS: ActionParam[] = [
|
|
57
|
+
actionParam('TypeCode', 'SystemEvent'),
|
|
58
|
+
actionParam('Title', 'Person created'),
|
|
59
|
+
actionParam('RecordID', 'REC-123'),
|
|
60
|
+
actionParam('InternalNotes', 'do not persist this'),
|
|
61
|
+
];
|
|
62
|
+
const ACTION_PARAMS: MJActionParamEntity[] = [
|
|
63
|
+
definition('p1', 'TypeCode'),
|
|
64
|
+
definition('p2', 'Title'),
|
|
65
|
+
definition('p3', 'RecordID'),
|
|
66
|
+
definition('p4', 'InternalNotes'),
|
|
67
|
+
];
|
|
68
|
+
const ENTITY_ACTION_PARAMS: MJEntityActionParamEntity[] = [binding('p4', 'Static', false)];
|
|
69
|
+
|
|
70
|
+
function baseRunParams(inputPayload: unknown): TaskActionRunParams {
|
|
71
|
+
return {
|
|
72
|
+
TaskID: 'T1',
|
|
73
|
+
ActionID: 'A1',
|
|
74
|
+
InputPayload: inputPayload,
|
|
75
|
+
DependencyOutputs: new Map(),
|
|
76
|
+
Provider: {} as IMetadataProvider,
|
|
77
|
+
ContextUser: {} as UserInfo,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
describe('TaskGraphActionRunner — durable payload round-trips by param name (#4794)', () => {
|
|
82
|
+
beforeEach(() => {
|
|
83
|
+
// vitest's `restoreMocks: true` clears mock implementations before every test, including
|
|
84
|
+
// the ones assigned inside the `vi.mock` factory above — so the return value is (re)armed here.
|
|
85
|
+
vi.mocked(ActionEngineServer.Instance.Config).mockResolvedValue(undefined);
|
|
86
|
+
vi.mocked(ActionEngineServer.Instance.RunAction, { partial: true }).mockResolvedValue({
|
|
87
|
+
Success: true,
|
|
88
|
+
Params: [],
|
|
89
|
+
LogEntry: { ID: 'L1' } as MJActionExecutionLogEntity,
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('delivers RedactParamsToRecord\'s output to the action by name, after a JSON round trip', async () => {
|
|
94
|
+
// Exactly what the deferral writes, then exactly what TaskGraphService's JSON column does to it.
|
|
95
|
+
const stored = JSON.parse(JSON.stringify(RedactParamsToRecord(RUNTIME_PARAMS, ACTION_PARAMS, ENTITY_ACTION_PARAMS)));
|
|
96
|
+
|
|
97
|
+
const result = await new TaskGraphActionRunner().RunActionForTask(baseRunParams(stored));
|
|
98
|
+
|
|
99
|
+
expect(result.Success).toBe(true);
|
|
100
|
+
expect(result.ActionLogID).toBe('L1');
|
|
101
|
+
|
|
102
|
+
const runActionCall = vi.mocked(ActionEngineServer.Instance.RunAction).mock.calls[0][0];
|
|
103
|
+
const sentParams = runActionCall.Params as ActionParam[];
|
|
104
|
+
|
|
105
|
+
// The three logged declared names arrive, order-insensitive, with their values intact.
|
|
106
|
+
expect(sentParams.map((p) => p.Name).sort()).toEqual(['RecordID', 'Title', 'TypeCode']);
|
|
107
|
+
expect(sentParams.find((p) => p.Name === 'TypeCode')?.Value).toBe('SystemEvent');
|
|
108
|
+
expect(sentParams.find((p) => p.Name === 'Title')?.Value).toBe('Person created');
|
|
109
|
+
expect(sentParams.find((p) => p.Name === 'RecordID')?.Value).toBe('REC-123');
|
|
110
|
+
|
|
111
|
+
// The binding-suppressed parameter never reaches the action — absent, not present-with-undefined.
|
|
112
|
+
expect(sentParams.some((p) => p.Name === 'InternalNotes')).toBe(false);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('does not turn dependency outputs into params named by the upstream task ID', async () => {
|
|
116
|
+
// The dispatcher keys DependencyOutputs by the upstream task's ID and has ALREADY merged their
|
|
117
|
+
// values into InputPayload (TaskGraphDispatcher.mergedPayload). A runner that also spread the
|
|
118
|
+
// map handed the action one extra param per dependency, named by a GUID and holding that
|
|
119
|
+
// task's whole output — which then landed, unredacted, in ActionExecutionLog.Params.
|
|
120
|
+
const upstreamID = '20924BD7-5128-4150-8404-FB44A55AEA0F';
|
|
121
|
+
const params = baseRunParams({ EntityName: 'MJ: Entities', Record: { ID: 'R1', Name: 'MJ: Tags' } });
|
|
122
|
+
params.DependencyOutputs = new Map([[upstreamID, { Record: { ID: 'R1', Name: 'MJ: Tags' } }]]);
|
|
123
|
+
|
|
124
|
+
await new TaskGraphActionRunner().RunActionForTask(params);
|
|
125
|
+
|
|
126
|
+
const sentParams = vi.mocked(ActionEngineServer.Instance.RunAction).mock.calls[0][0].Params as ActionParam[];
|
|
127
|
+
expect(sentParams.map((p) => p.Name).sort()).toEqual(['EntityName', 'Record']);
|
|
128
|
+
});
|
|
129
|
+
});
|
|
@@ -19,7 +19,7 @@ vi.mock('@memberjunction/core', () => ({ LogError: vi.fn() }));
|
|
|
19
19
|
import {
|
|
20
20
|
TASK_GRAPH_FRAMES_TOPIC,
|
|
21
21
|
TaskGraphFrameBroadcaster,
|
|
22
|
-
|
|
22
|
+
TaskGraphFrameFilter,
|
|
23
23
|
type TaskGraphFramePayload,
|
|
24
24
|
} from '../resolvers/TaskGraphFrameResolver';
|
|
25
25
|
import type { TaskGraphFrame } from '@memberjunction/task-graph';
|
|
@@ -44,7 +44,7 @@ const payload = (over: Partial<TaskGraphFramePayload> = {}): TaskGraphFramePaylo
|
|
|
44
44
|
const context = (userId: string | null) => (userId ? { userPayload: { userRecord: { ID: userId } } } : {});
|
|
45
45
|
|
|
46
46
|
const check = (over: Partial<TaskGraphFramePayload> = {}, args = GRAPH, userId: string | null = OWNER) =>
|
|
47
|
-
|
|
47
|
+
TaskGraphFrameFilter({ payload: payload(over), args: { parentTaskId: args }, context: context(userId) });
|
|
48
48
|
|
|
49
49
|
describe('taskGraphFrameFilter — the delivery gate', () => {
|
|
50
50
|
it('delivers a frame for the watched graph to its owner', () => {
|
|
@@ -21,12 +21,16 @@ vi.mock('../auth/magicLink/MagicLinkService.js', () => ({
|
|
|
21
21
|
MagicLinkService: class {},
|
|
22
22
|
}));
|
|
23
23
|
vi.mock('../agentSessions/ReturningVisitorRecap.js', () => ({
|
|
24
|
-
|
|
24
|
+
WriteReturningVisitorRecap: async () => undefined,
|
|
25
|
+
get writeReturningVisitorRecap() { return this.WriteReturningVisitorRecap; },
|
|
25
26
|
}));
|
|
26
27
|
vi.mock('../realtimeWidget/visitorIdentity.js', () => ({
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
ResolveIdentityByEmail: async () => null,
|
|
29
|
+
get resolveIdentityByEmail() { return this.ResolveIdentityByEmail; },
|
|
30
|
+
MergeVisitorIdentity: async () => 0,
|
|
31
|
+
get mergeVisitorIdentity() { return this.MergeVisitorIdentity; },
|
|
32
|
+
ForgetVisitor: async () => ({ notesArchived: 0, conversationsCleared: 0 }),
|
|
33
|
+
get forgetVisitor() { return this.ForgetVisitor; },
|
|
30
34
|
}));
|
|
31
35
|
|
|
32
36
|
import { WidgetSessionService } from '../realtimeWidget/WidgetSessionService.js';
|
|
@@ -1,50 +1,50 @@
|
|
|
1
1
|
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import {
|
|
2
|
+
import { ExactTotalFromPage, ResolveAdhocTotalRowCount } from '../resolvers/adhoc-query-helpers';
|
|
3
3
|
|
|
4
4
|
describe('exactTotalFromPage', () => {
|
|
5
5
|
it('returns the row count when not paging (maxRows null) — the query was uncapped', () => {
|
|
6
|
-
expect(
|
|
7
|
-
expect(
|
|
6
|
+
expect(ExactTotalFromPage(0, 47, null)).toBe(47);
|
|
7
|
+
expect(ExactTotalFromPage(0, 0, null)).toBe(0);
|
|
8
8
|
});
|
|
9
9
|
|
|
10
10
|
it('returns startRow + pageLength for a SHORT page (fewer rows than the page size)', () => {
|
|
11
|
-
expect(
|
|
12
|
-
expect(
|
|
13
|
-
expect(
|
|
11
|
+
expect(ExactTotalFromPage(0, 47, 100)).toBe(47); // page 1, short → exact total
|
|
12
|
+
expect(ExactTotalFromPage(200, 30, 100)).toBe(230); // page 3, short last page
|
|
13
|
+
expect(ExactTotalFromPage(100, 0, 100)).toBe(100); // empty page past the end
|
|
14
14
|
});
|
|
15
15
|
|
|
16
16
|
it('returns null for a FULL page — a COUNT is required because more rows may exist', () => {
|
|
17
|
-
expect(
|
|
18
|
-
expect(
|
|
17
|
+
expect(ExactTotalFromPage(0, 100, 100)).toBeNull();
|
|
18
|
+
expect(ExactTotalFromPage(500, 100, 100)).toBeNull();
|
|
19
19
|
});
|
|
20
20
|
|
|
21
21
|
it('treats an over-full page defensively as "needs count" (should not occur with OFFSET/FETCH)', () => {
|
|
22
|
-
expect(
|
|
22
|
+
expect(ExactTotalFromPage(0, 150, 100)).toBeNull();
|
|
23
23
|
});
|
|
24
24
|
});
|
|
25
25
|
|
|
26
26
|
describe('resolveAdhocTotalRowCount', () => {
|
|
27
27
|
it('reads TotalRowCount from the count recordset', () => {
|
|
28
|
-
expect(
|
|
29
|
-
expect(
|
|
28
|
+
expect(ResolveAdhocTotalRowCount([{ TotalRowCount: 2087 }], 100)).toBe(2087);
|
|
29
|
+
expect(ResolveAdhocTotalRowCount([{ TotalRowCount: 0 }], 100)).toBe(0);
|
|
30
30
|
});
|
|
31
31
|
|
|
32
32
|
it('floors a fractional/stringified count', () => {
|
|
33
|
-
expect(
|
|
34
|
-
expect(
|
|
33
|
+
expect(ResolveAdhocTotalRowCount([{ TotalRowCount: 42.9 }], 0)).toBe(42);
|
|
34
|
+
expect(ResolveAdhocTotalRowCount([{ TotalRowCount: '2087' as unknown as number }], 0)).toBe(2087);
|
|
35
35
|
});
|
|
36
36
|
|
|
37
37
|
it('falls back when the count is absent, empty, null, or malformed', () => {
|
|
38
|
-
expect(
|
|
39
|
-
expect(
|
|
40
|
-
expect(
|
|
41
|
-
expect(
|
|
42
|
-
expect(
|
|
38
|
+
expect(ResolveAdhocTotalRowCount(null, 100)).toBe(100);
|
|
39
|
+
expect(ResolveAdhocTotalRowCount(undefined, 100)).toBe(100);
|
|
40
|
+
expect(ResolveAdhocTotalRowCount([], 100)).toBe(100);
|
|
41
|
+
expect(ResolveAdhocTotalRowCount([{}], 100)).toBe(100);
|
|
42
|
+
expect(ResolveAdhocTotalRowCount([{ TotalRowCount: null }], 100)).toBe(100);
|
|
43
43
|
});
|
|
44
44
|
|
|
45
45
|
it('falls back on non-finite or negative counts (never reports a misleading total)', () => {
|
|
46
|
-
expect(
|
|
47
|
-
expect(
|
|
48
|
-
expect(
|
|
46
|
+
expect(ResolveAdhocTotalRowCount([{ TotalRowCount: Number.NaN }], 100)).toBe(100);
|
|
47
|
+
expect(ResolveAdhocTotalRowCount([{ TotalRowCount: -5 }], 100)).toBe(100);
|
|
48
|
+
expect(ResolveAdhocTotalRowCount([{ TotalRowCount: Infinity }], 100)).toBe(100);
|
|
49
49
|
});
|
|
50
50
|
});
|
|
@@ -18,7 +18,7 @@ vi.mock('../config.js', () => ({
|
|
|
18
18
|
},
|
|
19
19
|
}));
|
|
20
20
|
|
|
21
|
-
import {
|
|
21
|
+
import { AuditResolverList } from '../logging/bootAudit.js';
|
|
22
22
|
import type { AuditArgParam, AuditResolver } from '../logging/bootAudit.js';
|
|
23
23
|
import { NoLog } from '../logging/NoLog.js';
|
|
24
24
|
|
|
@@ -37,12 +37,12 @@ function makeArgParam(opts: {
|
|
|
37
37
|
type: Function;
|
|
38
38
|
}): AuditArgParam {
|
|
39
39
|
return {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
Target: opts.target,
|
|
41
|
+
MethodName: opts.methodName,
|
|
42
|
+
Index: opts.index,
|
|
43
43
|
kind: 'arg',
|
|
44
44
|
name: opts.name,
|
|
45
|
-
|
|
45
|
+
GetType: () => opts.type,
|
|
46
46
|
};
|
|
47
47
|
}
|
|
48
48
|
|
|
@@ -52,8 +52,8 @@ function makeResolver(opts: {
|
|
|
52
52
|
params: AuditArgParam[];
|
|
53
53
|
}): AuditResolver {
|
|
54
54
|
return {
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
Target: opts.target,
|
|
56
|
+
MethodName: opts.methodName,
|
|
57
57
|
params: opts.params,
|
|
58
58
|
};
|
|
59
59
|
}
|
|
@@ -93,7 +93,7 @@ describe('auditResolverList', () => {
|
|
|
93
93
|
],
|
|
94
94
|
});
|
|
95
95
|
|
|
96
|
-
|
|
96
|
+
AuditResolverList([resolver]);
|
|
97
97
|
expect(warnSpy).not.toHaveBeenCalled();
|
|
98
98
|
});
|
|
99
99
|
|
|
@@ -117,7 +117,7 @@ describe('auditResolverList', () => {
|
|
|
117
117
|
],
|
|
118
118
|
});
|
|
119
119
|
|
|
120
|
-
|
|
120
|
+
AuditResolverList([resolver]);
|
|
121
121
|
expect(warnSpy).toHaveBeenCalledTimes(1);
|
|
122
122
|
const message = warnSpy.mock.calls[0][0];
|
|
123
123
|
expect(typeof message).toBe('string');
|
|
@@ -148,7 +148,7 @@ describe('auditResolverList', () => {
|
|
|
148
148
|
],
|
|
149
149
|
});
|
|
150
150
|
|
|
151
|
-
|
|
151
|
+
AuditResolverList([resolver]);
|
|
152
152
|
expect(warnSpy).not.toHaveBeenCalled();
|
|
153
153
|
});
|
|
154
154
|
|
|
@@ -179,7 +179,7 @@ describe('auditResolverList', () => {
|
|
|
179
179
|
],
|
|
180
180
|
});
|
|
181
181
|
|
|
182
|
-
|
|
182
|
+
AuditResolverList([resolver]);
|
|
183
183
|
expect(warnSpy).toHaveBeenCalledTimes(1);
|
|
184
184
|
const message = warnSpy.mock.calls[0][0];
|
|
185
185
|
expect(message).toContain("'custom'");
|