@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
|
@@ -11,7 +11,7 @@ import { fileURLToPath } from 'node:url';
|
|
|
11
11
|
import {
|
|
12
12
|
CORE_CONSTANT_RESERVED_SERVER_EXTENSION_ROOTS,
|
|
13
13
|
CORE_STATIC_RESERVED_SERVER_EXTENSION_ROOTS,
|
|
14
|
-
|
|
14
|
+
CoreReservedServerExtensionRoots,
|
|
15
15
|
} from '../serverExtensionReservedRoots.js';
|
|
16
16
|
import { validateServerExtensionRootPath } from '@memberjunction/server-extensions-core';
|
|
17
17
|
|
|
@@ -58,12 +58,12 @@ describe('coreReservedServerExtensionRoots', () => {
|
|
|
58
58
|
|
|
59
59
|
it('structurally guarantees every pre-auth app.use / app.get / app.post mount in index.ts is reserved', () => {
|
|
60
60
|
const indexSrc = readFileSync(join(SRC, 'index.ts'), 'utf8');
|
|
61
|
-
const authMiddlewareIndex = indexSrc.indexOf('app.use(
|
|
61
|
+
const authMiddlewareIndex = indexSrc.indexOf('app.use(CreateUnifiedAuthMiddleware');
|
|
62
62
|
expect(authMiddlewareIndex).toBeGreaterThan(0);
|
|
63
63
|
const preAuthSrc = indexSrc.substring(0, authMiddlewareIndex);
|
|
64
64
|
|
|
65
65
|
const mountRegex = /app\.(?:use|get|post)\s*\(\s*([^,\s)]+)/g;
|
|
66
|
-
const reservedRoots =
|
|
66
|
+
const reservedRoots = CoreReservedServerExtensionRoots('/');
|
|
67
67
|
|
|
68
68
|
// Explicit allowlist of known non-path middleware mounts (e.g. app.use(mw), app.use(cors()), app.use(compression(...)))
|
|
69
69
|
const knownNonPathTokens = [
|
|
@@ -71,7 +71,7 @@ describe('coreReservedServerExtensionRoots', () => {
|
|
|
71
71
|
'express.',
|
|
72
72
|
'compression',
|
|
73
73
|
'cookieParser',
|
|
74
|
-
'
|
|
74
|
+
'CreateUnifiedAuthMiddleware',
|
|
75
75
|
'mw',
|
|
76
76
|
];
|
|
77
77
|
const isKnownNonPath = (t: string): boolean =>
|
|
@@ -120,7 +120,7 @@ describe('coreReservedServerExtensionRoots', () => {
|
|
|
120
120
|
});
|
|
121
121
|
|
|
122
122
|
it('includes graphqlRootPath and every core mount', () => {
|
|
123
|
-
const roots =
|
|
123
|
+
const roots = CoreReservedServerExtensionRoots('/api');
|
|
124
124
|
expect(roots).toEqual(
|
|
125
125
|
expect.arrayContaining([
|
|
126
126
|
'/api',
|
|
@@ -139,7 +139,7 @@ describe('coreReservedServerExtensionRoots', () => {
|
|
|
139
139
|
});
|
|
140
140
|
|
|
141
141
|
it('closes the F-M2 bypasses: cased /auth and sibling /healthcheck', () => {
|
|
142
|
-
const extra =
|
|
142
|
+
const extra = CoreReservedServerExtensionRoots('/');
|
|
143
143
|
expect(validateServerExtensionRootPath('/Auth', extra)).toMatch(/reserved prefix/);
|
|
144
144
|
expect(validateServerExtensionRootPath('/healthcheck', extra)).toMatch(/reserved prefix/);
|
|
145
145
|
expect(validateServerExtensionRootPath('/Healthcheck', extra)).toMatch(/reserved prefix/);
|
|
@@ -156,7 +156,7 @@ describe('coreReservedServerExtensionRoots', () => {
|
|
|
156
156
|
});
|
|
157
157
|
|
|
158
158
|
it('reserves a non-default graphqlRootPath and its nested paths', () => {
|
|
159
|
-
const extra =
|
|
159
|
+
const extra = CoreReservedServerExtensionRoots('/api');
|
|
160
160
|
expect(validateServerExtensionRootPath('/api', extra)).toMatch(/reserved prefix/);
|
|
161
161
|
expect(validateServerExtensionRootPath('/api/graphql', extra)).toMatch(/reserved prefix/);
|
|
162
162
|
expect(validateServerExtensionRootPath('/apiv2', extra)).toBeNull();
|
|
@@ -45,7 +45,7 @@ vi.mock('../config.js', () => ({
|
|
|
45
45
|
},
|
|
46
46
|
}));
|
|
47
47
|
|
|
48
|
-
import {
|
|
48
|
+
import { VariablesLoggingMiddleware } from '../logging/variablesLoggingMiddleware.js';
|
|
49
49
|
|
|
50
50
|
/**
|
|
51
51
|
* Build a synthetic GraphQLResolveInfo-shaped object that matches what type-graphql passes
|
|
@@ -99,7 +99,7 @@ describe('variablesLoggingMiddleware', () => {
|
|
|
99
99
|
|
|
100
100
|
it('skips field resolvers (info.path.prev !== undefined) without logging', async () => {
|
|
101
101
|
const next = vi.fn(async () => 'next-result');
|
|
102
|
-
const result = await
|
|
102
|
+
const result = await VariablesLoggingMiddleware(
|
|
103
103
|
{
|
|
104
104
|
root: undefined,
|
|
105
105
|
args: { x: 1 },
|
|
@@ -126,7 +126,7 @@ describe('variablesLoggingMiddleware', () => {
|
|
|
126
126
|
],
|
|
127
127
|
};
|
|
128
128
|
|
|
129
|
-
await
|
|
129
|
+
await VariablesLoggingMiddleware(
|
|
130
130
|
{
|
|
131
131
|
root: undefined,
|
|
132
132
|
args: { input: { ID: 'abc', Name: 'HubSpot', Values: 'FAKE_SECRET' } },
|
|
@@ -165,7 +165,7 @@ describe('variablesLoggingMiddleware', () => {
|
|
|
165
165
|
Entities: [{ ClassName: 'SomeUnrelatedEntity', EncryptedFields: [] }],
|
|
166
166
|
};
|
|
167
167
|
|
|
168
|
-
await
|
|
168
|
+
await VariablesLoggingMiddleware(
|
|
169
169
|
{
|
|
170
170
|
root: undefined,
|
|
171
171
|
args: { token: 'plaintext-leak' },
|
|
@@ -196,7 +196,7 @@ describe('variablesLoggingMiddleware', () => {
|
|
|
196
196
|
const next = vi.fn(async () => undefined);
|
|
197
197
|
const fakeProvider = { Entities: [] };
|
|
198
198
|
|
|
199
|
-
await
|
|
199
|
+
await VariablesLoggingMiddleware(
|
|
200
200
|
{
|
|
201
201
|
root: undefined,
|
|
202
202
|
args: { input: { Values: 'FAKE_SECRET' } },
|
|
@@ -59,16 +59,22 @@ vi.mock('jsonwebtoken', () => ({
|
|
|
59
59
|
}));
|
|
60
60
|
|
|
61
61
|
vi.mock('../auth/index.js', () => ({
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
62
|
+
GetSigningKeys: mockGetSigningKeys,
|
|
63
|
+
get getSigningKeys() { return this.GetSigningKeys; },
|
|
64
|
+
GetSystemUser: vi.fn(),
|
|
65
|
+
get getSystemUser() { return this.GetSystemUser; },
|
|
66
|
+
GetValidationOptions: mockGetValidationOptions,
|
|
67
|
+
get getValidationOptions() { return this.GetValidationOptions; },
|
|
68
|
+
VerifyUserRecord: mockVerifyUserRecord,
|
|
69
|
+
get verifyUserRecord() { return this.VerifyUserRecord; },
|
|
70
|
+
ExtractUserInfoFromPayload: mockExtractUserInfo,
|
|
71
|
+
get extractUserInfoFromPayload() { return this.ExtractUserInfoFromPayload; },
|
|
67
72
|
}));
|
|
68
73
|
|
|
69
74
|
vi.mock('../cache.js', () => {
|
|
70
75
|
const map = new Map<string, boolean>();
|
|
71
|
-
return {
|
|
76
|
+
return { AuthCache: map,
|
|
77
|
+
get authCache() { return this.AuthCache; } };
|
|
72
78
|
});
|
|
73
79
|
|
|
74
80
|
vi.mock('../config.js', () => ({
|
|
@@ -95,7 +101,7 @@ vi.mock('@memberjunction/api-keys', () => ({
|
|
|
95
101
|
GetAPIKeyEngine: vi.fn(),
|
|
96
102
|
}));
|
|
97
103
|
|
|
98
|
-
import {
|
|
104
|
+
import { CreateUnifiedAuthMiddleware } from '../context.js';
|
|
99
105
|
import type { Request, Response, NextFunction } from 'express';
|
|
100
106
|
import type { DataSourceInfo } from '../types.js';
|
|
101
107
|
|
|
@@ -178,11 +184,11 @@ function setupSuccessfulAuth() {
|
|
|
178
184
|
// ─── Tests ──────────────────────────────────────────────────────────────────
|
|
179
185
|
|
|
180
186
|
describe('createUnifiedAuthMiddleware', () => {
|
|
181
|
-
let middleware: ReturnType<typeof
|
|
187
|
+
let middleware: ReturnType<typeof CreateUnifiedAuthMiddleware>;
|
|
182
188
|
|
|
183
189
|
beforeEach(() => {
|
|
184
190
|
vi.clearAllMocks();
|
|
185
|
-
middleware =
|
|
191
|
+
middleware = CreateUnifiedAuthMiddleware(mockDataSources);
|
|
186
192
|
});
|
|
187
193
|
|
|
188
194
|
describe('OPTIONS passthrough', () => {
|
|
@@ -13,7 +13,7 @@ vi.mock('@memberjunction/core', async (importOriginal) => {
|
|
|
13
13
|
};
|
|
14
14
|
});
|
|
15
15
|
|
|
16
|
-
import {
|
|
16
|
+
import { ResolveIdentityByEmail } from '../realtimeWidget/visitorIdentity.js';
|
|
17
17
|
import type { EntityInfo, IMetadataProvider, UserInfo } from '@memberjunction/core';
|
|
18
18
|
|
|
19
19
|
type LookupParams = { EntityName: string; ExtraFilter: string; Fields: string[] };
|
|
@@ -32,7 +32,7 @@ describe('resolveIdentityByEmail — the configured identity entity can have ANY
|
|
|
32
32
|
it('selects the real key column and returns its bare value for a single non-ID key', async () => {
|
|
33
33
|
runViewMock.mockResolvedValue({ Success: true, Results: [{ individual_id: 4711 }] });
|
|
34
34
|
const provider = makeProvider({ ID: 'ent-persons', PrimaryKeys: [{ Name: 'individual_id' }] });
|
|
35
|
-
const out = await
|
|
35
|
+
const out = await ResolveIdentityByEmail('ada@example.com', user, provider, { entityName: 'Persons', EmailField: 'EmailAddress' });
|
|
36
36
|
expect(lastParams().Fields).toEqual(['individual_id']);
|
|
37
37
|
expect(lastParams().ExtraFilter).toBe("EmailAddress = 'ada@example.com'");
|
|
38
38
|
expect(out).toEqual({ entityId: 'ent-persons', recordId: '4711' });
|
|
@@ -41,7 +41,7 @@ describe('resolveIdentityByEmail — the configured identity entity can have ANY
|
|
|
41
41
|
it('selects EVERY key column and carries a composite key as a full segment, not its first column', async () => {
|
|
42
42
|
runViewMock.mockResolvedValue({ Success: true, Results: [{ OrderID: '11055', LineNo: 3 }] });
|
|
43
43
|
const provider = makeProvider({ ID: 'ent-lines', PrimaryKeys: [{ Name: 'OrderID' }, { Name: 'LineNo' }] });
|
|
44
|
-
const out = await
|
|
44
|
+
const out = await ResolveIdentityByEmail('x@y.com', user, provider, { entityName: 'Order Lines' });
|
|
45
45
|
expect(lastParams().Fields).toEqual(['OrderID', 'LineNo']);
|
|
46
46
|
expect(out).toEqual({ entityId: 'ent-lines', recordId: 'OrderID|11055||LineNo|3' });
|
|
47
47
|
});
|
|
@@ -49,13 +49,13 @@ describe('resolveIdentityByEmail — the configured identity entity can have ANY
|
|
|
49
49
|
it('stays anonymous when no row matches or a key column is null', async () => {
|
|
50
50
|
const provider = makeProvider({ ID: 'ent-users', PrimaryKeys: [{ Name: 'ID' }] });
|
|
51
51
|
runViewMock.mockResolvedValue({ Success: true, Results: [] });
|
|
52
|
-
expect(await
|
|
52
|
+
expect(await ResolveIdentityByEmail('none@y.com', user, provider)).toBeUndefined();
|
|
53
53
|
runViewMock.mockResolvedValue({ Success: true, Results: [{ ID: null }] });
|
|
54
|
-
expect(await
|
|
54
|
+
expect(await ResolveIdentityByEmail('null@y.com', user, provider)).toBeUndefined();
|
|
55
55
|
});
|
|
56
56
|
|
|
57
57
|
it('stays anonymous when the configured entity is not in metadata', async () => {
|
|
58
|
-
expect(await
|
|
58
|
+
expect(await ResolveIdentityByEmail('a@b.com', user, makeProvider(undefined), { entityName: 'Nope' })).toBeUndefined();
|
|
59
59
|
expect(runViewMock).not.toHaveBeenCalled();
|
|
60
60
|
});
|
|
61
61
|
});
|
|
@@ -2,32 +2,32 @@ import { describe, it, expect } from 'vitest';
|
|
|
2
2
|
import jwt from 'jsonwebtoken';
|
|
3
3
|
import { createPublicKey } from 'node:crypto';
|
|
4
4
|
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
5
|
+
ParseAllowedOrigins,
|
|
6
|
+
IsOriginAllowed,
|
|
7
|
+
IsModalityEnabled,
|
|
8
|
+
EvaluateWidgetMint,
|
|
9
|
+
BuildWidgetGuestClaims,
|
|
10
|
+
LooksLikeBot,
|
|
11
11
|
} from '../realtimeWidget/widgetCore.js';
|
|
12
12
|
import { MagicLinkKeyManager } from '../auth/magicLink/MagicLinkKeys.js';
|
|
13
13
|
|
|
14
14
|
describe('widget core — parseAllowedOrigins', () => {
|
|
15
15
|
it('parses a JSON array of origins', () => {
|
|
16
|
-
expect(
|
|
16
|
+
expect(ParseAllowedOrigins('["https://a.com","https://b.com"]')).toEqual(['https://a.com', 'https://b.com']);
|
|
17
17
|
});
|
|
18
18
|
|
|
19
19
|
it('tolerates a comma-separated string', () => {
|
|
20
|
-
expect(
|
|
20
|
+
expect(ParseAllowedOrigins('https://a.com, https://b.com')).toEqual(['https://a.com', 'https://b.com']);
|
|
21
21
|
});
|
|
22
22
|
|
|
23
23
|
it('normalizes case and strips trailing slashes', () => {
|
|
24
|
-
expect(
|
|
24
|
+
expect(ParseAllowedOrigins('["HTTPS://Acme.COM/"]')).toEqual(['https://acme.com']);
|
|
25
25
|
});
|
|
26
26
|
|
|
27
27
|
it('returns empty (fail-closed) for null / blank / non-array JSON', () => {
|
|
28
|
-
expect(
|
|
29
|
-
expect(
|
|
30
|
-
expect(
|
|
28
|
+
expect(ParseAllowedOrigins(null)).toEqual([]);
|
|
29
|
+
expect(ParseAllowedOrigins(' ')).toEqual([]);
|
|
30
|
+
expect(ParseAllowedOrigins('{"not":"an-array"}')).toEqual([]);
|
|
31
31
|
});
|
|
32
32
|
});
|
|
33
33
|
|
|
@@ -35,37 +35,37 @@ describe('widget core — isOriginAllowed (fail-closed)', () => {
|
|
|
35
35
|
const allowed = ['https://acme.com', 'https://www.acme.com'];
|
|
36
36
|
|
|
37
37
|
it('accepts an exact (normalized) match', () => {
|
|
38
|
-
expect(
|
|
39
|
-
expect(
|
|
38
|
+
expect(IsOriginAllowed('https://acme.com', allowed)).toBe(true);
|
|
39
|
+
expect(IsOriginAllowed('HTTPS://ACME.COM/', allowed)).toBe(true);
|
|
40
40
|
});
|
|
41
41
|
|
|
42
42
|
it('rejects a non-listed origin', () => {
|
|
43
|
-
expect(
|
|
44
|
-
expect(
|
|
43
|
+
expect(IsOriginAllowed('https://evil.com', allowed)).toBe(false);
|
|
44
|
+
expect(IsOriginAllowed('https://sub.acme.com', allowed)).toBe(false);
|
|
45
45
|
});
|
|
46
46
|
|
|
47
47
|
it('rejects a missing request origin', () => {
|
|
48
|
-
expect(
|
|
49
|
-
expect(
|
|
48
|
+
expect(IsOriginAllowed(undefined, allowed)).toBe(false);
|
|
49
|
+
expect(IsOriginAllowed('', allowed)).toBe(false);
|
|
50
50
|
});
|
|
51
51
|
|
|
52
52
|
it('rejects everything when the allowlist is empty (never "*")', () => {
|
|
53
|
-
expect(
|
|
53
|
+
expect(IsOriginAllowed('https://acme.com', [])).toBe(false);
|
|
54
54
|
});
|
|
55
55
|
});
|
|
56
56
|
|
|
57
57
|
describe('widget core — isModalityEnabled', () => {
|
|
58
58
|
it('Both enables text and voice', () => {
|
|
59
|
-
expect(
|
|
60
|
-
expect(
|
|
59
|
+
expect(IsModalityEnabled('Both', 'Text')).toBe(true);
|
|
60
|
+
expect(IsModalityEnabled('Both', 'Voice')).toBe(true);
|
|
61
61
|
});
|
|
62
62
|
it('Text enables only text', () => {
|
|
63
|
-
expect(
|
|
64
|
-
expect(
|
|
63
|
+
expect(IsModalityEnabled('Text', 'Text')).toBe(true);
|
|
64
|
+
expect(IsModalityEnabled('Text', 'Voice')).toBe(false);
|
|
65
65
|
});
|
|
66
66
|
it('Voice enables only voice', () => {
|
|
67
|
-
expect(
|
|
68
|
-
expect(
|
|
67
|
+
expect(IsModalityEnabled('Voice', 'Voice')).toBe(true);
|
|
68
|
+
expect(IsModalityEnabled('Voice', 'Text')).toBe(false);
|
|
69
69
|
});
|
|
70
70
|
});
|
|
71
71
|
|
|
@@ -73,22 +73,22 @@ describe('widget core — evaluateWidgetMint', () => {
|
|
|
73
73
|
const base = { Status: 'Active', AllowedOrigins: '["https://acme.com"]', Modality: 'Both' };
|
|
74
74
|
|
|
75
75
|
it('passes for an active widget from an allowed origin', () => {
|
|
76
|
-
expect(
|
|
76
|
+
expect(EvaluateWidgetMint(base, 'https://acme.com')).toEqual({ ok: true });
|
|
77
77
|
});
|
|
78
78
|
|
|
79
79
|
it('rejects a disabled widget', () => {
|
|
80
|
-
expect(
|
|
80
|
+
expect(EvaluateWidgetMint({ ...base, Status: 'Disabled' }, 'https://acme.com')).toEqual({
|
|
81
81
|
ok: false,
|
|
82
82
|
errorCode: 'disabled',
|
|
83
83
|
});
|
|
84
84
|
});
|
|
85
85
|
|
|
86
86
|
it('rejects a disallowed origin', () => {
|
|
87
|
-
expect(
|
|
87
|
+
expect(EvaluateWidgetMint(base, 'https://evil.com')).toEqual({ ok: false, errorCode: 'origin_not_allowed' });
|
|
88
88
|
});
|
|
89
89
|
|
|
90
90
|
it('rejects a missing origin (fail-closed)', () => {
|
|
91
|
-
expect(
|
|
91
|
+
expect(EvaluateWidgetMint(base, undefined)).toEqual({ ok: false, errorCode: 'origin_not_allowed' });
|
|
92
92
|
});
|
|
93
93
|
});
|
|
94
94
|
|
|
@@ -106,14 +106,14 @@ describe('widget core — buildWidgetGuestClaims', () => {
|
|
|
106
106
|
};
|
|
107
107
|
|
|
108
108
|
it('marks the session anonymous + magic-link and binds the widget id', () => {
|
|
109
|
-
const claims =
|
|
109
|
+
const claims = BuildWidgetGuestClaims(args);
|
|
110
110
|
expect(claims.mj_anon).toBe(true);
|
|
111
111
|
expect(claims.mj_magic_link).toBe(true);
|
|
112
112
|
expect(claims.mj_widget_id).toBe('WIDGET-123');
|
|
113
113
|
});
|
|
114
114
|
|
|
115
115
|
it('scopes to the application + guest role and the configured anon email', () => {
|
|
116
|
-
const claims =
|
|
116
|
+
const claims = BuildWidgetGuestClaims(args);
|
|
117
117
|
expect(claims.mj_app_id).toBe('APP-1');
|
|
118
118
|
expect(claims.mj_role).toBe('Widget Guest');
|
|
119
119
|
expect(claims.email).toBe('anonymous@magic-link.local');
|
|
@@ -122,13 +122,13 @@ describe('widget core — buildWidgetGuestClaims', () => {
|
|
|
122
122
|
});
|
|
123
123
|
|
|
124
124
|
it('carries a single scope entry for the guest grant', () => {
|
|
125
|
-
const claims =
|
|
125
|
+
const claims = BuildWidgetGuestClaims(args);
|
|
126
126
|
expect(claims.mj_scopes).toHaveLength(1);
|
|
127
127
|
expect(claims.mj_scopes?.[0]).toMatchObject({ appId: 'APP-1', role: 'Widget Guest' });
|
|
128
128
|
});
|
|
129
129
|
|
|
130
130
|
it('sets exp = iat + ttl', () => {
|
|
131
|
-
const claims =
|
|
131
|
+
const claims = BuildWidgetGuestClaims(args);
|
|
132
132
|
expect(claims.iat).toBe(1_000_000);
|
|
133
133
|
expect(claims.exp).toBe(1_000_900);
|
|
134
134
|
});
|
|
@@ -139,7 +139,7 @@ describe('widget core — RS256 sign + verify roundtrip (reuses MagicLinkKeyMana
|
|
|
139
139
|
const km = MagicLinkKeyManager.Instance;
|
|
140
140
|
km.Initialize(); // ephemeral keypair (idempotent if already initialized in-process)
|
|
141
141
|
|
|
142
|
-
const claims =
|
|
142
|
+
const claims = BuildWidgetGuestClaims({
|
|
143
143
|
issuer: 'https://mj.example.com',
|
|
144
144
|
audience: 'mj-magic-link',
|
|
145
145
|
widgetId: 'WIDGET-XYZ',
|
|
@@ -164,7 +164,7 @@ describe('widget core — RS256 sign + verify roundtrip (reuses MagicLinkKeyMana
|
|
|
164
164
|
it('rejects a tampered widget token', () => {
|
|
165
165
|
const km = MagicLinkKeyManager.Instance;
|
|
166
166
|
km.Initialize();
|
|
167
|
-
const claims =
|
|
167
|
+
const claims = BuildWidgetGuestClaims({
|
|
168
168
|
issuer: 'https://mj.example.com',
|
|
169
169
|
audience: 'mj-magic-link',
|
|
170
170
|
widgetId: 'W',
|
|
@@ -184,21 +184,21 @@ describe('widget core — RS256 sign + verify roundtrip (reuses MagicLinkKeyMana
|
|
|
184
184
|
|
|
185
185
|
describe('widget core — looksLikeBot (W6 mint heuristic)', () => {
|
|
186
186
|
it('flags a missing / blank user-agent as a bot', () => {
|
|
187
|
-
expect(
|
|
188
|
-
expect(
|
|
189
|
-
expect(
|
|
187
|
+
expect(LooksLikeBot(undefined)).toBe(true);
|
|
188
|
+
expect(LooksLikeBot(null)).toBe(true);
|
|
189
|
+
expect(LooksLikeBot(' ')).toBe(true);
|
|
190
190
|
});
|
|
191
191
|
|
|
192
192
|
it('flags known automation user-agents', () => {
|
|
193
|
-
expect(
|
|
194
|
-
expect(
|
|
195
|
-
expect(
|
|
196
|
-
expect(
|
|
197
|
-
expect(
|
|
193
|
+
expect(LooksLikeBot('curl/8.4.0')).toBe(true);
|
|
194
|
+
expect(LooksLikeBot('python-requests/2.31')).toBe(true);
|
|
195
|
+
expect(LooksLikeBot('Googlebot/2.1 (+http://www.google.com/bot.html)')).toBe(true);
|
|
196
|
+
expect(LooksLikeBot('Mozilla/5.0 (compatible; bingbot/2.0)')).toBe(true);
|
|
197
|
+
expect(LooksLikeBot('HeadlessChrome/120.0.0.0')).toBe(true);
|
|
198
198
|
});
|
|
199
199
|
|
|
200
200
|
it('allows real browser user-agents', () => {
|
|
201
|
-
expect(
|
|
202
|
-
expect(
|
|
201
|
+
expect(LooksLikeBot('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0 Safari/537.36')).toBe(false);
|
|
202
|
+
expect(LooksLikeBot('Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 Version/17.0 Mobile/15E148 Safari/604.1')).toBe(false);
|
|
203
203
|
});
|
|
204
204
|
});
|
|
@@ -13,8 +13,8 @@ vi.mock('@memberjunction/generic-database-provider', () => ({
|
|
|
13
13
|
}));
|
|
14
14
|
|
|
15
15
|
import {
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
ResolveWidgetGuestRunContext,
|
|
17
|
+
ElevateUserPayload,
|
|
18
18
|
ResolveScopedAnonymousRunUser,
|
|
19
19
|
} from '../realtimeWidget/widgetGuestElevation.js';
|
|
20
20
|
import type { UserPayload } from '../types.js';
|
|
@@ -29,12 +29,12 @@ function payloadWith(userRecord: Partial<UserInfo>): UserPayload {
|
|
|
29
29
|
|
|
30
30
|
describe('widgetGuestElevation — resolveWidgetGuestRunContext (guard paths, no DB)', () => {
|
|
31
31
|
it('returns null for a normal authenticated user (not anonymous)', async () => {
|
|
32
|
-
const result = await
|
|
32
|
+
const result = await ResolveWidgetGuestRunContext(payloadWith({ IsMagicLinkAnonymous: false }), providerStub);
|
|
33
33
|
expect(result).toBeNull();
|
|
34
34
|
});
|
|
35
35
|
|
|
36
36
|
it('returns null for an anonymous magic-link session that is NOT a widget guest (no WidgetGuestContext)', async () => {
|
|
37
|
-
const result = await
|
|
37
|
+
const result = await ResolveWidgetGuestRunContext(
|
|
38
38
|
payloadWith({ IsMagicLinkAnonymous: true, WidgetGuestContext: undefined }),
|
|
39
39
|
providerStub,
|
|
40
40
|
);
|
|
@@ -42,7 +42,7 @@ describe('widgetGuestElevation — resolveWidgetGuestRunContext (guard paths, no
|
|
|
42
42
|
});
|
|
43
43
|
|
|
44
44
|
it('returns null when userRecord is absent', async () => {
|
|
45
|
-
const result = await
|
|
45
|
+
const result = await ResolveWidgetGuestRunContext({ email: '', userRecord: undefined, sessionId: 's' }, providerStub);
|
|
46
46
|
expect(result).toBeNull();
|
|
47
47
|
});
|
|
48
48
|
});
|
|
@@ -104,7 +104,7 @@ describe('widgetGuestElevation — elevateUserPayload', () => {
|
|
|
104
104
|
const guestPayload = payloadWith({ IsMagicLinkAnonymous: true });
|
|
105
105
|
const systemUser = { Email: 'system@system.org' } as UserInfo;
|
|
106
106
|
|
|
107
|
-
const elevated =
|
|
107
|
+
const elevated = ElevateUserPayload(guestPayload, systemUser);
|
|
108
108
|
|
|
109
109
|
expect(elevated.userRecord).toBe(systemUser);
|
|
110
110
|
expect(elevated.email).toBe('system@system.org');
|
|
@@ -117,7 +117,7 @@ describe('widgetGuestElevation — elevateUserPayload', () => {
|
|
|
117
117
|
const guestPayload = payloadWith({ IsMagicLinkAnonymous: true });
|
|
118
118
|
const systemUser = { Email: 'system@system.org' } as UserInfo;
|
|
119
119
|
|
|
120
|
-
|
|
120
|
+
ElevateUserPayload(guestPayload, systemUser);
|
|
121
121
|
|
|
122
122
|
expect(guestPayload.isSystemUser).toBeUndefined();
|
|
123
123
|
expect(guestPayload.email).toBe('anonymous@magic-link.local');
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { describe, it, expect } from 'vitest';
|
|
2
2
|
import jwt from 'jsonwebtoken';
|
|
3
3
|
import { generateKeyPairSync } from 'node:crypto';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { VerifyHostAssertion, ExtractHostIdentity } from '../realtimeWidget/host-identity.js';
|
|
5
|
+
import { BuildWidgetGuestClaims } from '../realtimeWidget/widgetCore.js';
|
|
6
6
|
|
|
7
7
|
/** A throwaway RSA keypair for signing test host assertions. */
|
|
8
8
|
function keypair(): { privatePem: string; publicPem: string } {
|
|
@@ -23,54 +23,54 @@ describe('verifyHostAssertion', () => {
|
|
|
23
23
|
it('accepts a valid host assertion and extracts the identity', () => {
|
|
24
24
|
const kp = keypair();
|
|
25
25
|
const token = sign(kp.privatePem, { email: 'jane@acme.com', given_name: 'Jane', family_name: 'Doe', sub: 'host-123' });
|
|
26
|
-
const result =
|
|
26
|
+
const result = VerifyHostAssertion(token, kp.publicPem, WIDGET_KEY);
|
|
27
27
|
expect(result.ok).toBe(true);
|
|
28
28
|
if (result.ok) {
|
|
29
|
-
expect(result.
|
|
29
|
+
expect(result.Identity).toMatchObject({ email: 'jane@acme.com', firstName: 'Jane', lastName: 'Doe', hostUserId: 'host-123' });
|
|
30
30
|
}
|
|
31
31
|
});
|
|
32
32
|
|
|
33
33
|
it('rejects a missing assertion', () => {
|
|
34
34
|
const kp = keypair();
|
|
35
|
-
expect(
|
|
35
|
+
expect(VerifyHostAssertion(undefined, kp.publicPem, WIDGET_KEY)).toEqual({ ok: false, errorCode: 'missing' });
|
|
36
36
|
});
|
|
37
37
|
|
|
38
38
|
it('rejects when no host key is configured (fail-closed)', () => {
|
|
39
39
|
const kp = keypair();
|
|
40
40
|
const token = sign(kp.privatePem, { email: 'x@y.com' });
|
|
41
|
-
expect(
|
|
41
|
+
expect(VerifyHostAssertion(token, undefined, WIDGET_KEY)).toEqual({ ok: false, errorCode: 'no_key' });
|
|
42
42
|
});
|
|
43
43
|
|
|
44
44
|
it('rejects a signature from the wrong key', () => {
|
|
45
45
|
const signer = keypair();
|
|
46
46
|
const other = keypair();
|
|
47
47
|
const token = sign(signer.privatePem, { email: 'x@y.com' });
|
|
48
|
-
expect(
|
|
48
|
+
expect(VerifyHostAssertion(token, other.publicPem, WIDGET_KEY)).toEqual({ ok: false, errorCode: 'bad_signature' });
|
|
49
49
|
});
|
|
50
50
|
|
|
51
51
|
it('rejects a wrong-audience assertion', () => {
|
|
52
52
|
const kp = keypair();
|
|
53
53
|
const token = sign(kp.privatePem, { email: 'x@y.com' }, { audience: 'pk_live_someone_else' });
|
|
54
|
-
expect(
|
|
54
|
+
expect(VerifyHostAssertion(token, kp.publicPem, WIDGET_KEY)).toEqual({ ok: false, errorCode: 'bad_signature' });
|
|
55
55
|
});
|
|
56
56
|
|
|
57
57
|
it('rejects an expired assertion', () => {
|
|
58
58
|
const kp = keypair();
|
|
59
59
|
const token = sign(kp.privatePem, { email: 'x@y.com' }, { expiresIn: -10 });
|
|
60
|
-
expect(
|
|
60
|
+
expect(VerifyHostAssertion(token, kp.publicPem, WIDGET_KEY)).toEqual({ ok: false, errorCode: 'expired' });
|
|
61
61
|
});
|
|
62
62
|
|
|
63
63
|
it('rejects an assertion with no email', () => {
|
|
64
64
|
const kp = keypair();
|
|
65
65
|
const token = sign(kp.privatePem, { given_name: 'NoEmail' });
|
|
66
|
-
expect(
|
|
66
|
+
expect(VerifyHostAssertion(token, kp.publicPem, WIDGET_KEY)).toEqual({ ok: false, errorCode: 'no_email' });
|
|
67
67
|
});
|
|
68
68
|
|
|
69
69
|
it('rejects an assertion with no exp (unbounded lifetime)', () => {
|
|
70
70
|
const kp = keypair();
|
|
71
71
|
// Sign directly with no expiresIn so the token carries iat but no exp.
|
|
72
72
|
const token = jwt.sign({ email: 'x@y.com' }, kp.privatePem, { algorithm: 'RS256', audience: WIDGET_KEY });
|
|
73
|
-
expect(
|
|
73
|
+
expect(VerifyHostAssertion(token, kp.publicPem, WIDGET_KEY)).toEqual({ ok: false, errorCode: 'expired' });
|
|
74
74
|
});
|
|
75
75
|
|
|
76
76
|
it('rejects an assertion older than the maxAge cap even when its exp is still in the future', () => {
|
|
@@ -81,13 +81,13 @@ describe('verifyHostAssertion', () => {
|
|
|
81
81
|
algorithm: 'RS256',
|
|
82
82
|
audience: WIDGET_KEY,
|
|
83
83
|
});
|
|
84
|
-
expect(
|
|
84
|
+
expect(VerifyHostAssertion(token, kp.publicPem, WIDGET_KEY)).toEqual({ ok: false, errorCode: 'expired' });
|
|
85
85
|
});
|
|
86
86
|
});
|
|
87
87
|
|
|
88
88
|
describe('buildWidgetGuestClaims with hostIdentity', () => {
|
|
89
89
|
it('carries the host identity as INFORMATIONAL claims but keeps the Anonymous principal email', () => {
|
|
90
|
-
const claims =
|
|
90
|
+
const claims = BuildWidgetGuestClaims({
|
|
91
91
|
issuer: 'iss',
|
|
92
92
|
audience: 'mj-magic-link',
|
|
93
93
|
widgetId: 'W',
|
|
@@ -111,7 +111,7 @@ describe('buildWidgetGuestClaims with hostIdentity', () => {
|
|
|
111
111
|
|
|
112
112
|
describe('extractHostIdentity', () => {
|
|
113
113
|
it('tolerates firstName/lastName fallbacks', () => {
|
|
114
|
-
const id =
|
|
114
|
+
const id = ExtractHostIdentity({ email: 'a@b.com', firstName: 'Al', lastName: 'Bo' });
|
|
115
115
|
expect(id).toMatchObject({ email: 'a@b.com', firstName: 'Al', lastName: 'Bo' });
|
|
116
116
|
});
|
|
117
117
|
});
|
|
@@ -52,7 +52,7 @@ const MAX_TRANSCRIPT_TURNS = 60;
|
|
|
52
52
|
* `ExpiresAt` that many days out (the Memory Manager's decay phase reaps expired notes). Omit/0
|
|
53
53
|
* for no expiry (system default retention applies).
|
|
54
54
|
*/
|
|
55
|
-
export async function
|
|
55
|
+
export async function WriteReturningVisitorRecap(
|
|
56
56
|
conversationId: string | null | undefined,
|
|
57
57
|
agentId: string | null | undefined,
|
|
58
58
|
contextUser: UserInfo,
|
|
@@ -101,6 +101,17 @@ export async function writeReturningVisitorRecap(
|
|
|
101
101
|
}
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
+
/** @deprecated Use {@link WriteReturningVisitorRecap}. */
|
|
105
|
+
export async function writeReturningVisitorRecap(
|
|
106
|
+
conversationId: string | null | undefined,
|
|
107
|
+
agentId: string | null | undefined,
|
|
108
|
+
contextUser: UserInfo,
|
|
109
|
+
provider: IMetadataProvider,
|
|
110
|
+
retentionDays?: number | null,
|
|
111
|
+
): Promise<void> {
|
|
112
|
+
return WriteReturningVisitorRecap(conversationId, agentId, contextUser, provider, retentionDays);
|
|
113
|
+
}
|
|
114
|
+
|
|
104
115
|
/** The polymorphic scope a recap note is filed under. */
|
|
105
116
|
interface RecapScope {
|
|
106
117
|
entityId: string;
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
import { AIAgentPermissionHelper } from '@memberjunction/ai-engine-base';
|
|
9
9
|
import { RealtimeClientSessionService, RealtimeChannelServerHost } from '@memberjunction/ai-agents';
|
|
10
10
|
import { GetHostInstanceID } from './HostInstance.js';
|
|
11
|
-
import {
|
|
11
|
+
import { WriteReturningVisitorRecap } from './ReturningVisitorRecap.js';
|
|
12
12
|
import { ResolveScopedAnonymousRunUser } from '../realtimeWidget/widgetGuestElevation.js';
|
|
13
13
|
|
|
14
14
|
/** Entity names — centralised so the `MJ:`-prefix convention is applied in exactly one place. */
|
|
@@ -207,7 +207,7 @@ export class SessionManager {
|
|
|
207
207
|
// Returning-visitor recap (RV2): if this session's conversation is returning-visitor-enabled,
|
|
208
208
|
// summarize it into an Active memory note so the visitor's next session opens with prior context.
|
|
209
209
|
// Best-effort + no-op for non-returning-visitor conversations; never blocks teardown.
|
|
210
|
-
await
|
|
210
|
+
await WriteReturningVisitorRecap(session.ConversationID, session.AgentID, contextUser, provider);
|
|
211
211
|
return true;
|
|
212
212
|
}
|
|
213
213
|
|