@memberjunction/server 6.2.0-edge.5 → 6.2.0-edge.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +96 -1
- package/dist/.tsbuildinfo +1 -1
- package/dist/agentSessions/BridgeHostInstance.d.ts +8 -3
- package/dist/agentSessions/BridgeHostInstance.d.ts.map +1 -1
- package/dist/agentSessions/BridgeHostInstance.js +14 -4
- package/dist/agentSessions/BridgeHostInstance.js.map +1 -1
- package/dist/agentSessions/HandoffOfferExpiry.d.ts +10 -0
- package/dist/agentSessions/HandoffOfferExpiry.d.ts.map +1 -0
- package/dist/agentSessions/HandoffOfferExpiry.js +18 -0
- package/dist/agentSessions/HandoffOfferExpiry.js.map +1 -0
- package/dist/agentSessions/ReturningVisitorRecap.js +1 -0
- package/dist/agentSessions/ReturningVisitorRecap.js.map +1 -1
- package/dist/agentSessions/SessionJanitor.d.ts +34 -11
- package/dist/agentSessions/SessionJanitor.d.ts.map +1 -1
- package/dist/agentSessions/SessionJanitor.js +88 -44
- package/dist/agentSessions/SessionJanitor.js.map +1 -1
- package/dist/agentSessions/SessionManager.d.ts +29 -9
- package/dist/agentSessions/SessionManager.d.ts.map +1 -1
- package/dist/agentSessions/SessionManager.js +62 -16
- package/dist/agentSessions/SessionManager.js.map +1 -1
- package/dist/agentSessions/conversationBrowsers.d.ts +61 -0
- package/dist/agentSessions/conversationBrowsers.d.ts.map +1 -0
- package/dist/agentSessions/conversationBrowsers.js +118 -0
- package/dist/agentSessions/conversationBrowsers.js.map +1 -0
- package/dist/agentSessions/sessionDeadline.d.ts +43 -0
- package/dist/agentSessions/sessionDeadline.d.ts.map +1 -0
- package/dist/agentSessions/sessionDeadline.js +68 -0
- package/dist/agentSessions/sessionDeadline.js.map +1 -0
- package/dist/auth/APIKeyScopeAuth.d.ts.map +1 -1
- package/dist/auth/APIKeyScopeAuth.js +5 -4
- package/dist/auth/APIKeyScopeAuth.js.map +1 -1
- package/dist/auth/AuthProviderCatalogRouter.d.ts.map +1 -1
- package/dist/auth/AuthProviderCatalogRouter.js +2 -0
- package/dist/auth/AuthProviderCatalogRouter.js.map +1 -1
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +51 -10
- package/dist/auth/index.js.map +1 -1
- package/dist/auth/initializeProviders.d.ts +10 -0
- package/dist/auth/initializeProviders.d.ts.map +1 -1
- package/dist/auth/initializeProviders.js +37 -1
- package/dist/auth/initializeProviders.js.map +1 -1
- package/dist/auth/localDevAuth.d.ts +79 -0
- package/dist/auth/localDevAuth.d.ts.map +1 -0
- package/dist/auth/localDevAuth.js +439 -0
- package/dist/auth/localDevAuth.js.map +1 -0
- package/dist/auth/loginEmailResolution.d.ts +41 -0
- package/dist/auth/loginEmailResolution.d.ts.map +1 -0
- package/dist/auth/loginEmailResolution.js +47 -0
- package/dist/auth/loginEmailResolution.js.map +1 -0
- package/dist/auth/magicLink/MagicLinkKeys.d.ts +51 -3
- package/dist/auth/magicLink/MagicLinkKeys.d.ts.map +1 -1
- package/dist/auth/magicLink/MagicLinkKeys.js +130 -13
- package/dist/auth/magicLink/MagicLinkKeys.js.map +1 -1
- package/dist/auth/magicLink/MagicLinkRouter.d.ts +3 -0
- package/dist/auth/magicLink/MagicLinkRouter.d.ts.map +1 -1
- package/dist/auth/magicLink/MagicLinkRouter.js +23 -5
- package/dist/auth/magicLink/MagicLinkRouter.js.map +1 -1
- package/dist/auth/magicLink/MagicLinkService.d.ts +39 -5
- package/dist/auth/magicLink/MagicLinkService.d.ts.map +1 -1
- package/dist/auth/magicLink/MagicLinkService.js +221 -9
- package/dist/auth/magicLink/MagicLinkService.js.map +1 -1
- package/dist/auth/magicLink/index.d.ts +1 -1
- package/dist/auth/magicLink/index.d.ts.map +1 -1
- package/dist/auth/magicLink/index.js +1 -1
- package/dist/auth/magicLink/index.js.map +1 -1
- package/dist/auth/magicLink/redeemLanding.d.ts +2 -2
- package/dist/auth/magicLink/redeemLanding.d.ts.map +1 -1
- package/dist/auth/magicLink/redeemLanding.js +7 -4
- package/dist/auth/magicLink/redeemLanding.js.map +1 -1
- package/dist/auth/magicLink/types.d.ts +39 -3
- package/dist/auth/magicLink/types.d.ts.map +1 -1
- package/dist/auth/magicLink/types.js +0 -4
- package/dist/auth/magicLink/types.js.map +1 -1
- package/dist/auth/newUsers.d.ts.map +1 -1
- package/dist/auth/newUsers.js +1 -0
- package/dist/auth/newUsers.js.map +1 -1
- package/dist/auth/sessionUserClone.d.ts +1 -1
- package/dist/auth/sessionUserClone.d.ts.map +1 -1
- package/dist/auth/sessionUserClone.js +3 -2
- package/dist/auth/sessionUserClone.js.map +1 -1
- package/dist/backgroundSweepConfigUnits.d.ts +231 -0
- package/dist/backgroundSweepConfigUnits.d.ts.map +1 -0
- package/dist/backgroundSweepConfigUnits.js +180 -0
- package/dist/backgroundSweepConfigUnits.js.map +1 -0
- package/dist/broadcast/BaseCacheInvalidationBroadcastProvider.d.ts +292 -0
- package/dist/broadcast/BaseCacheInvalidationBroadcastProvider.d.ts.map +1 -0
- package/dist/broadcast/BaseCacheInvalidationBroadcastProvider.js +442 -0
- package/dist/broadcast/BaseCacheInvalidationBroadcastProvider.js.map +1 -0
- package/dist/broadcast/index.d.ts +6 -0
- package/dist/broadcast/index.d.ts.map +1 -0
- package/dist/broadcast/index.js +6 -0
- package/dist/broadcast/index.js.map +1 -0
- package/dist/broadcast/providers/AWSIoTCoreBroadcastProvider.d.ts +43 -0
- package/dist/broadcast/providers/AWSIoTCoreBroadcastProvider.d.ts.map +1 -0
- package/dist/broadcast/providers/AWSIoTCoreBroadcastProvider.js +144 -0
- package/dist/broadcast/providers/AWSIoTCoreBroadcastProvider.js.map +1 -0
- package/dist/broadcast/providers/AzureWebPubSubBroadcastProvider.d.ts +46 -0
- package/dist/broadcast/providers/AzureWebPubSubBroadcastProvider.d.ts.map +1 -0
- package/dist/broadcast/providers/AzureWebPubSubBroadcastProvider.js +149 -0
- package/dist/broadcast/providers/AzureWebPubSubBroadcastProvider.js.map +1 -0
- package/dist/broadcast/providers/GCPPubSubBroadcastProvider.d.ts +49 -0
- package/dist/broadcast/providers/GCPPubSubBroadcastProvider.d.ts.map +1 -0
- package/dist/broadcast/providers/GCPPubSubBroadcastProvider.js +131 -0
- package/dist/broadcast/providers/GCPPubSubBroadcastProvider.js.map +1 -0
- package/dist/broadcast/providers/SequencedRoleBucketBroadcastProvider.d.ts +24 -0
- package/dist/broadcast/providers/SequencedRoleBucketBroadcastProvider.d.ts.map +1 -0
- package/dist/broadcast/providers/SequencedRoleBucketBroadcastProvider.js +51 -0
- package/dist/broadcast/providers/SequencedRoleBucketBroadcastProvider.js.map +1 -0
- package/dist/cache.d.ts +3 -2
- package/dist/cache.d.ts.map +1 -1
- package/dist/cache.js.map +1 -1
- package/dist/config.d.ts +1402 -8
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +120 -0
- package/dist/config.js.map +1 -1
- package/dist/context.d.ts +5 -1
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +64 -12
- package/dist/context.js.map +1 -1
- package/dist/coreRoutes.d.ts +3 -1
- package/dist/coreRoutes.d.ts.map +1 -1
- package/dist/coreRoutes.js +20 -4
- package/dist/coreRoutes.js.map +1 -1
- package/dist/generated/graphql-schemas/__mj.d.ts +863 -14
- package/dist/generated/graphql-schemas/__mj.d.ts.map +1 -1
- package/dist/generated/graphql-schemas/__mj.js +4167 -62
- package/dist/generated/graphql-schemas/__mj.js.map +1 -1
- package/dist/generic/CacheInvalidationResolver.d.ts +50 -30
- package/dist/generic/CacheInvalidationResolver.d.ts.map +1 -1
- package/dist/generic/CacheInvalidationResolver.js +154 -79
- package/dist/generic/CacheInvalidationResolver.js.map +1 -1
- package/dist/generic/OrphanedConversationDetailReconciler.d.ts +11 -0
- package/dist/generic/OrphanedConversationDetailReconciler.d.ts.map +1 -1
- package/dist/generic/OrphanedConversationDetailReconciler.js +29 -1
- package/dist/generic/OrphanedConversationDetailReconciler.js.map +1 -1
- package/dist/generic/PubSubManager.d.ts +10 -0
- package/dist/generic/PubSubManager.d.ts.map +1 -1
- package/dist/generic/PubSubManager.js +44 -1
- package/dist/generic/PubSubManager.js.map +1 -1
- package/dist/generic/PushStatusResolver.d.ts +39 -6
- package/dist/generic/PushStatusResolver.d.ts.map +1 -1
- package/dist/generic/PushStatusResolver.js +93 -11
- package/dist/generic/PushStatusResolver.js.map +1 -1
- package/dist/generic/ResolverBase.d.ts +114 -29
- package/dist/generic/ResolverBase.d.ts.map +1 -1
- package/dist/generic/ResolverBase.js +509 -220
- package/dist/generic/ResolverBase.js.map +1 -1
- package/dist/generic/RunViewResolver.d.ts +15 -3
- package/dist/generic/RunViewResolver.d.ts.map +1 -1
- package/dist/generic/RunViewResolver.js +126 -20
- package/dist/generic/RunViewResolver.js.map +1 -1
- package/dist/generic/actionOutputFieldSecurity.d.ts +26 -0
- package/dist/generic/actionOutputFieldSecurity.d.ts.map +1 -0
- package/dist/generic/actionOutputFieldSecurity.js +47 -0
- package/dist/generic/actionOutputFieldSecurity.js.map +1 -0
- package/dist/generic/fieldSecurityTransport.d.ts +30 -0
- package/dist/generic/fieldSecurityTransport.d.ts.map +1 -0
- package/dist/generic/fieldSecurityTransport.js +30 -0
- package/dist/generic/fieldSecurityTransport.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +262 -84
- package/dist/index.js.map +1 -1
- package/dist/integration/ConnectionPause.d.ts +121 -0
- package/dist/integration/ConnectionPause.d.ts.map +1 -0
- package/dist/integration/ConnectionPause.js +183 -0
- package/dist/integration/ConnectionPause.js.map +1 -0
- package/dist/integration/CustomColumnPromoter.d.ts +72 -6
- package/dist/integration/CustomColumnPromoter.d.ts.map +1 -1
- package/dist/integration/CustomColumnPromoter.js +93 -47
- package/dist/integration/CustomColumnPromoter.js.map +1 -1
- package/dist/integration/EntityMapLifecycle.d.ts +78 -4
- package/dist/integration/EntityMapLifecycle.d.ts.map +1 -1
- package/dist/integration/EntityMapLifecycle.js +199 -5
- package/dist/integration/EntityMapLifecycle.js.map +1 -1
- package/dist/integration/InactiveRowWarnings.d.ts +31 -0
- package/dist/integration/InactiveRowWarnings.d.ts.map +1 -1
- package/dist/integration/InactiveRowWarnings.js +29 -0
- package/dist/integration/InactiveRowWarnings.js.map +1 -1
- package/dist/integration/ObjectNamesByID.d.ts +28 -0
- package/dist/integration/ObjectNamesByID.d.ts.map +1 -0
- package/dist/integration/ObjectNamesByID.js +87 -0
- package/dist/integration/ObjectNamesByID.js.map +1 -0
- package/dist/integration/PostRestartIntrospect.d.ts +26 -0
- package/dist/integration/PostRestartIntrospect.d.ts.map +1 -0
- package/dist/integration/PostRestartIntrospect.js +27 -0
- package/dist/integration/PostRestartIntrospect.js.map +1 -0
- package/dist/integration/RSUPostRestartProgress.d.ts +176 -0
- package/dist/integration/RSUPostRestartProgress.d.ts.map +1 -0
- package/dist/integration/RSUPostRestartProgress.js +323 -0
- package/dist/integration/RSUPostRestartProgress.js.map +1 -0
- package/dist/integration/RSUProgressBridge.d.ts +41 -2
- package/dist/integration/RSUProgressBridge.d.ts.map +1 -1
- package/dist/integration/RSUProgressBridge.js +84 -1
- package/dist/integration/RSUProgressBridge.js.map +1 -1
- package/dist/integration/RunArtifactAuthorization.d.ts +39 -0
- package/dist/integration/RunArtifactAuthorization.d.ts.map +1 -0
- package/dist/integration/RunArtifactAuthorization.js +45 -0
- package/dist/integration/RunArtifactAuthorization.js.map +1 -0
- package/dist/integration/SchemaRefreshLaunch.d.ts +9 -0
- package/dist/integration/SchemaRefreshLaunch.d.ts.map +1 -1
- package/dist/integration/SchemaRefreshLaunch.js +3 -2
- package/dist/integration/SchemaRefreshLaunch.js.map +1 -1
- package/dist/integration/ScopedFieldsForBuild.d.ts +46 -0
- package/dist/integration/ScopedFieldsForBuild.d.ts.map +1 -0
- package/dist/integration/ScopedFieldsForBuild.js +91 -0
- package/dist/integration/ScopedFieldsForBuild.js.map +1 -0
- package/dist/integration/TargetConfigGuard.d.ts +40 -0
- package/dist/integration/TargetConfigGuard.d.ts.map +1 -0
- package/dist/integration/TargetConfigGuard.js +40 -0
- package/dist/integration/TargetConfigGuard.js.map +1 -0
- package/dist/logging/variablesLoggingMiddleware.d.ts +12 -0
- package/dist/logging/variablesLoggingMiddleware.d.ts.map +1 -1
- package/dist/logging/variablesLoggingMiddleware.js +50 -1
- package/dist/logging/variablesLoggingMiddleware.js.map +1 -1
- package/dist/realtimeSessions/SessionVerificationPortsBase.d.ts.map +1 -1
- package/dist/realtimeSessions/SessionVerificationPortsBase.js +1 -0
- package/dist/realtimeSessions/SessionVerificationPortsBase.js.map +1 -1
- package/dist/realtimeSessions/ownedRealtimeSession.d.ts +8 -6
- package/dist/realtimeSessions/ownedRealtimeSession.d.ts.map +1 -1
- package/dist/realtimeSessions/ownedRealtimeSession.js +14 -6
- package/dist/realtimeSessions/ownedRealtimeSession.js.map +1 -1
- package/dist/realtimeSessions/sessionAccess.d.ts +103 -11
- package/dist/realtimeSessions/sessionAccess.d.ts.map +1 -1
- package/dist/realtimeSessions/sessionAccess.js +147 -22
- package/dist/realtimeSessions/sessionAccess.js.map +1 -1
- package/dist/realtimeSessions/sessionConfigStamps.js +1 -1
- package/dist/realtimeSessions/sessionConfigStamps.js.map +1 -1
- package/dist/realtimeSessions/subscriptionAuthorization.d.ts.map +1 -1
- package/dist/realtimeSessions/subscriptionAuthorization.js +5 -2
- package/dist/realtimeSessions/subscriptionAuthorization.js.map +1 -1
- package/dist/realtimeSessions/verificationWorkflow.d.ts +2 -0
- package/dist/realtimeSessions/verificationWorkflow.d.ts.map +1 -1
- package/dist/realtimeSessions/verificationWorkflow.js +1 -1
- package/dist/realtimeSessions/verificationWorkflow.js.map +1 -1
- package/dist/realtimeWidget/WidgetRouter.d.ts.map +1 -1
- package/dist/realtimeWidget/WidgetRouter.js +19 -3
- package/dist/realtimeWidget/WidgetRouter.js.map +1 -1
- package/dist/realtimeWidget/WidgetSessionService.d.ts +67 -7
- package/dist/realtimeWidget/WidgetSessionService.d.ts.map +1 -1
- package/dist/realtimeWidget/WidgetSessionService.js +203 -19
- package/dist/realtimeWidget/WidgetSessionService.js.map +1 -1
- package/dist/realtimeWidget/host-identity.d.ts +1 -1
- package/dist/realtimeWidget/host-identity.js +1 -1
- package/dist/realtimeWidget/visitorIdentity.d.ts.map +1 -1
- package/dist/realtimeWidget/visitorIdentity.js +1 -0
- package/dist/realtimeWidget/visitorIdentity.js.map +1 -1
- package/dist/realtimeWidget/widgetCore.d.ts +20 -1
- package/dist/realtimeWidget/widgetCore.d.ts.map +1 -1
- package/dist/realtimeWidget/widgetCore.js +21 -8
- package/dist/realtimeWidget/widgetCore.js.map +1 -1
- package/dist/realtimeWidget/widgetGuestElevation.d.ts +1 -1
- package/dist/realtimeWidget/widgetGuestElevation.d.ts.map +1 -1
- package/dist/realtimeWidget/widgetGuestElevation.js +3 -1
- package/dist/realtimeWidget/widgetGuestElevation.js.map +1 -1
- package/dist/requestOrigin.d.ts +22 -0
- package/dist/requestOrigin.d.ts.map +1 -0
- package/dist/requestOrigin.js +60 -0
- package/dist/requestOrigin.js.map +1 -0
- package/dist/resolvers/ActionResolver.d.ts +19 -1
- package/dist/resolvers/ActionResolver.d.ts.map +1 -1
- package/dist/resolvers/ActionResolver.js +63 -12
- package/dist/resolvers/ActionResolver.js.map +1 -1
- package/dist/resolvers/AdhocQueryResolver.d.ts.map +1 -1
- package/dist/resolvers/AdhocQueryResolver.js +1 -0
- package/dist/resolvers/AdhocQueryResolver.js.map +1 -1
- package/dist/resolvers/AgentRunStatusPublisher.d.ts +18 -4
- package/dist/resolvers/AgentRunStatusPublisher.d.ts.map +1 -1
- package/dist/resolvers/AgentRunStatusPublisher.js +32 -8
- package/dist/resolvers/AgentRunStatusPublisher.js.map +1 -1
- package/dist/resolvers/AgentSessionResolver.d.ts +10 -4
- package/dist/resolvers/AgentSessionResolver.d.ts.map +1 -1
- package/dist/resolvers/AgentSessionResolver.js +44 -17
- package/dist/resolvers/AgentSessionResolver.js.map +1 -1
- package/dist/resolvers/AutotagPipelineResolver.d.ts.map +1 -1
- package/dist/resolvers/AutotagPipelineResolver.js +2 -1
- package/dist/resolvers/AutotagPipelineResolver.js.map +1 -1
- package/dist/resolvers/ConversationRunEventsResolver.d.ts.map +1 -1
- package/dist/resolvers/ConversationRunEventsResolver.js +2 -0
- package/dist/resolvers/ConversationRunEventsResolver.js.map +1 -1
- package/dist/resolvers/EntityCommunicationsResolver.d.ts +13 -1
- package/dist/resolvers/EntityCommunicationsResolver.d.ts.map +1 -1
- package/dist/resolvers/EntityCommunicationsResolver.js +50 -14
- package/dist/resolvers/EntityCommunicationsResolver.js.map +1 -1
- package/dist/resolvers/ExecuteRemoteOperationResolver.d.ts +6 -0
- package/dist/resolvers/ExecuteRemoteOperationResolver.d.ts.map +1 -1
- package/dist/resolvers/ExecuteRemoteOperationResolver.js +30 -7
- package/dist/resolvers/ExecuteRemoteOperationResolver.js.map +1 -1
- package/dist/resolvers/FetchEntityVectorsResolver.d.ts +28 -0
- package/dist/resolvers/FetchEntityVectorsResolver.d.ts.map +1 -1
- package/dist/resolvers/FetchEntityVectorsResolver.js +117 -21
- package/dist/resolvers/FetchEntityVectorsResolver.js.map +1 -1
- package/dist/resolvers/FileCategoryResolver.d.ts.map +1 -1
- package/dist/resolvers/FileCategoryResolver.js +1 -0
- package/dist/resolvers/FileCategoryResolver.js.map +1 -1
- package/dist/resolvers/FileResolver.d.ts +5 -0
- package/dist/resolvers/FileResolver.d.ts.map +1 -1
- package/dist/resolvers/FileResolver.js +13 -4
- package/dist/resolvers/FileResolver.js.map +1 -1
- package/dist/resolvers/GetDataResolver.d.ts.map +1 -1
- package/dist/resolvers/GetDataResolver.js +34 -13
- package/dist/resolvers/GetDataResolver.js.map +1 -1
- package/dist/resolvers/IntegrationDiscoveryResolver.d.ts +401 -11
- package/dist/resolvers/IntegrationDiscoveryResolver.d.ts.map +1 -1
- package/dist/resolvers/IntegrationDiscoveryResolver.js +2713 -1290
- package/dist/resolvers/IntegrationDiscoveryResolver.js.map +1 -1
- package/dist/resolvers/MCPResolver.d.ts.map +1 -1
- package/dist/resolvers/MCPResolver.js +13 -2
- package/dist/resolvers/MCPResolver.js.map +1 -1
- package/dist/resolvers/MergeRecordsResolver.d.ts +8 -1
- package/dist/resolvers/MergeRecordsResolver.d.ts.map +1 -1
- package/dist/resolvers/MergeRecordsResolver.js +31 -3
- package/dist/resolvers/MergeRecordsResolver.js.map +1 -1
- package/dist/resolvers/PipelineProgressResolver.d.ts +6 -0
- package/dist/resolvers/PipelineProgressResolver.d.ts.map +1 -1
- package/dist/resolvers/PipelineProgressResolver.js +5 -3
- package/dist/resolvers/PipelineProgressResolver.js.map +1 -1
- package/dist/resolvers/QueryResolver.d.ts.map +1 -1
- package/dist/resolvers/QueryResolver.js +20 -6
- package/dist/resolvers/QueryResolver.js.map +1 -1
- package/dist/resolvers/QuerySystemUserResolver.d.ts +38 -0
- package/dist/resolvers/QuerySystemUserResolver.d.ts.map +1 -1
- package/dist/resolvers/QuerySystemUserResolver.js +184 -88
- package/dist/resolvers/QuerySystemUserResolver.js.map +1 -1
- package/dist/resolvers/RSUResolver.d.ts.map +1 -1
- package/dist/resolvers/RSUResolver.js +12 -0
- package/dist/resolvers/RSUResolver.js.map +1 -1
- package/dist/resolvers/RealtimeBridgeResolver.d.ts.map +1 -1
- package/dist/resolvers/RealtimeBridgeResolver.js +1 -0
- package/dist/resolvers/RealtimeBridgeResolver.js.map +1 -1
- package/dist/resolvers/RealtimeClientSessionResolver.d.ts +22 -2
- package/dist/resolvers/RealtimeClientSessionResolver.d.ts.map +1 -1
- package/dist/resolvers/RealtimeClientSessionResolver.js +118 -33
- package/dist/resolvers/RealtimeClientSessionResolver.js.map +1 -1
- package/dist/resolvers/RemoteBrowserActionResolver.d.ts +62 -10
- package/dist/resolvers/RemoteBrowserActionResolver.d.ts.map +1 -1
- package/dist/resolvers/RemoteBrowserActionResolver.js +224 -39
- package/dist/resolvers/RemoteBrowserActionResolver.js.map +1 -1
- package/dist/resolvers/RunAIAgentResolver.d.ts +80 -16
- package/dist/resolvers/RunAIAgentResolver.d.ts.map +1 -1
- package/dist/resolvers/RunAIAgentResolver.js +388 -125
- package/dist/resolvers/RunAIAgentResolver.js.map +1 -1
- package/dist/resolvers/RunAIPromptResolver.d.ts +5 -3
- package/dist/resolvers/RunAIPromptResolver.d.ts.map +1 -1
- package/dist/resolvers/RunAIPromptResolver.js +19 -18
- package/dist/resolvers/RunAIPromptResolver.js.map +1 -1
- package/dist/resolvers/RunTemplateResolver.d.ts.map +1 -1
- package/dist/resolvers/RunTemplateResolver.js +7 -5
- package/dist/resolvers/RunTemplateResolver.js.map +1 -1
- package/dist/resolvers/RunTestResolver.d.ts.map +1 -1
- package/dist/resolvers/RunTestResolver.js +3 -1
- package/dist/resolvers/RunTestResolver.js.map +1 -1
- package/dist/resolvers/SyncDataResolver.d.ts.map +1 -1
- package/dist/resolvers/SyncDataResolver.js +4 -0
- package/dist/resolvers/SyncDataResolver.js.map +1 -1
- package/dist/resolvers/TestQuerySQLResolver.d.ts.map +1 -1
- package/dist/resolvers/TestQuerySQLResolver.js +1 -0
- package/dist/resolvers/TestQuerySQLResolver.js.map +1 -1
- package/dist/resolvers/TransactionGroupResolver.d.ts +17 -2
- package/dist/resolvers/TransactionGroupResolver.d.ts.map +1 -1
- package/dist/resolvers/TransactionGroupResolver.js +60 -15
- package/dist/resolvers/TransactionGroupResolver.js.map +1 -1
- package/dist/resolvers/UserViewResolver.d.ts +1 -1
- package/dist/resolvers/UserViewResolver.d.ts.map +1 -1
- package/dist/resolvers/UserViewResolver.js +2 -1
- package/dist/resolvers/UserViewResolver.js.map +1 -1
- package/dist/resolvers/meetingRecordingRegistration.d.ts.map +1 -1
- package/dist/resolvers/meetingRecordingRegistration.js +2 -0
- package/dist/resolvers/meetingRecordingRegistration.js.map +1 -1
- package/dist/rest/EntityCRUDHandler.d.ts +6 -0
- package/dist/rest/EntityCRUDHandler.d.ts.map +1 -1
- package/dist/rest/EntityCRUDHandler.js +19 -5
- package/dist/rest/EntityCRUDHandler.js.map +1 -1
- package/dist/rest/MediaAccessKeys.d.ts.map +1 -1
- package/dist/rest/MediaAccessKeys.js +6 -2
- package/dist/rest/MediaAccessKeys.js.map +1 -1
- package/dist/rest/OAuthCallbackHandler.d.ts.map +1 -1
- package/dist/rest/OAuthCallbackHandler.js +11 -5
- package/dist/rest/OAuthCallbackHandler.js.map +1 -1
- package/dist/rest/RESTEndpointHandler.d.ts.map +1 -1
- package/dist/rest/RESTEndpointHandler.js +8 -5
- package/dist/rest/RESTEndpointHandler.js.map +1 -1
- package/dist/rest/RealtimeRecordingHandler.d.ts +3 -3
- package/dist/rest/RealtimeRecordingHandler.d.ts.map +1 -1
- package/dist/rest/RealtimeRecordingHandler.js +6 -8
- package/dist/rest/RealtimeRecordingHandler.js.map +1 -1
- package/dist/rest/ViewOperationsHandler.d.ts +6 -0
- package/dist/rest/ViewOperationsHandler.d.ts.map +1 -1
- package/dist/rest/ViewOperationsHandler.js +24 -6
- package/dist/rest/ViewOperationsHandler.js.map +1 -1
- package/dist/rest/setupRESTEndpoints.d.ts +3 -1
- package/dist/rest/setupRESTEndpoints.d.ts.map +1 -1
- package/dist/rest/setupRESTEndpoints.js +11 -2
- package/dist/rest/setupRESTEndpoints.js.map +1 -1
- package/dist/serverRoleConfigUnits.d.ts +29 -0
- package/dist/serverRoleConfigUnits.d.ts.map +1 -0
- package/dist/serverRoleConfigUnits.js +33 -0
- package/dist/serverRoleConfigUnits.js.map +1 -0
- package/dist/services/DurableEntityActionTaskSubmitter.d.ts.map +1 -1
- package/dist/services/DurableEntityActionTaskSubmitter.js +6 -1
- package/dist/services/DurableEntityActionTaskSubmitter.js.map +1 -1
- package/dist/services/TaskGraphActionRunner.d.ts.map +1 -1
- package/dist/services/TaskGraphActionRunner.js +2 -26
- package/dist/services/TaskGraphActionRunner.js.map +1 -1
- package/dist/services/TaskGraphAgentRunner.d.ts +6 -0
- package/dist/services/TaskGraphAgentRunner.d.ts.map +1 -1
- package/dist/services/TaskGraphAgentRunner.js +38 -0
- package/dist/services/TaskGraphAgentRunner.js.map +1 -1
- package/dist/services/TaskGraphContinuationDeliverer.d.ts +5 -0
- package/dist/services/TaskGraphContinuationDeliverer.d.ts.map +1 -1
- package/dist/services/TaskGraphContinuationDeliverer.js +43 -15
- package/dist/services/TaskGraphContinuationDeliverer.js.map +1 -1
- package/dist/services/WorkQueueHostService.d.ts +2 -1
- package/dist/services/WorkQueueHostService.d.ts.map +1 -1
- package/dist/services/WorkQueueHostService.js +19 -4
- package/dist/services/WorkQueueHostService.js.map +1 -1
- package/dist/services/workQueueConfig.d.ts +2 -2
- package/dist/services/workQueueConfig.js +5 -5
- package/dist/services/workQueueConfig.js.map +1 -1
- package/dist/sharedCache.js +1 -1
- package/dist/sharedCache.js.map +1 -1
- package/dist/types.d.ts +40 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +98 -98
- package/src/__tests__/APIKeyScopeAuth.test.ts +4 -8
- package/src/__tests__/ActionResolver.fieldSecurity.test.ts +237 -0
- package/src/__tests__/ActiveOperations.test.ts +68 -0
- package/src/__tests__/AdhocQueryResolver.dialect.test.ts +137 -0
- package/src/__tests__/AgentRunStatusPublisher.test.ts +49 -0
- package/src/__tests__/AgentSessionResolver.ownership.test.ts +150 -0
- package/src/__tests__/AssertTargetConfigs.test.ts +75 -0
- package/src/__tests__/BatchApplyParity.test.ts +109 -0
- package/src/__tests__/BridgeHostInstance.test.ts +42 -0
- package/src/__tests__/CollectInactiveRowWarnings.test.ts +115 -0
- package/src/__tests__/ConnectionPause.test.ts +192 -0
- package/src/__tests__/ConnectionPauseResolver.test.ts +166 -0
- package/src/__tests__/ConnectionPauseSave.test.ts +143 -0
- package/src/__tests__/CustomColumnPromoterCompletion.test.ts +142 -0
- package/src/__tests__/CustomColumnPromoterOnePass.test.ts +15 -1
- package/src/__tests__/DeleteConnectionRemovesPerConnectionCatalog.test.ts +51 -0
- package/src/__tests__/DetachedDiscoveryStart.test.ts +65 -0
- package/src/__tests__/DurableEntityActionTaskSubmitter.test.ts +73 -0
- package/src/__tests__/EntityCommunicationsResolver.actingUser.test.ts +151 -0
- package/src/__tests__/EntityMapLifecycle.rekey.test.ts +252 -0
- package/src/__tests__/EvolutionActsOnWhatItDetects.test.ts +113 -0
- package/src/__tests__/ExecuteRemoteOperationResolver.test.ts +213 -0
- package/src/__tests__/FetchEntityVectorsResolver.test.ts +206 -3
- package/src/__tests__/FileResolver.fieldSecurity.test.ts +82 -0
- package/src/__tests__/HandoffOfferExpiry.test.ts +40 -0
- package/src/__tests__/IntegrationRunArtifactAuthorization.test.ts +126 -0
- package/src/__tests__/MagicLinkKeys.test.ts +102 -0
- package/src/__tests__/MediaAccessKeys.test.ts +57 -10
- package/src/__tests__/NewArrivalsDefaultDisabled.test.ts +50 -0
- package/src/__tests__/ObjectNamesByID.test.ts +176 -0
- package/src/__tests__/PipelineProgressResolver.filter.test.ts +58 -0
- package/src/__tests__/PostRestartMapsInCatalogScope.test.ts +146 -0
- package/src/__tests__/QuerySystemUserResolver.childRows.test.ts +80 -0
- package/src/__tests__/QuerySystemUserResolver.collision.test.ts +200 -0
- package/src/__tests__/QuerySystemUserResolver.fieldSecurity.test.ts +49 -0
- package/src/__tests__/QuerySystemUserResolver.permissions.test.ts +132 -0
- package/src/__tests__/RESTEndpointHandler.test.ts +25 -0
- package/src/__tests__/RSUPostRestartProgress.test.ts +343 -0
- package/src/__tests__/RSUProgressBridge.test.ts +188 -5
- package/src/__tests__/RSUStartupSweepWiring.test.ts +30 -0
- package/src/__tests__/ReactivateRefreshMessage.test.ts +10 -3
- package/src/__tests__/RealtimeClientSessionResolver.configTamper.test.ts +23 -3
- package/src/__tests__/RealtimeClientSessionResolver.test.ts +346 -46
- package/src/__tests__/{RefreshAdoptsNewColumns.test.ts → RefreshReportsNewColumns.test.ts} +25 -16
- package/src/__tests__/RemoteBrowserActionRecovery.test.ts +287 -0
- package/src/__tests__/RemoteBrowserActionResolver.goalRunLink.test.ts +3 -0
- package/src/__tests__/RemoteBrowserActionResolver.ownership.test.ts +100 -0
- package/src/__tests__/RemoteBrowserAudioStream.test.ts +3 -0
- package/src/__tests__/RemoteBrowserSnapshot.test.ts +3 -0
- package/src/__tests__/ResolverBase.clientOldValues.test.ts +344 -14
- package/src/__tests__/ResolverBase.deleteReturnProjection.test.ts +52 -0
- package/src/__tests__/ResolverBase.encryptedApiZeroReencrypt.test.ts +307 -0
- package/src/__tests__/ResolverBase.entityMessageRelay.test.ts +227 -0
- package/src/__tests__/ResolverBase.includeBinaryFields.test.ts +83 -1
- package/src/__tests__/ResolverBase.publishStatusUpdate.test.ts +68 -0
- package/src/__tests__/ResolverBase.userViewCacheAndDedup.test.ts +130 -0
- package/src/__tests__/RunAIAgentResolver.branch.test.ts +72 -13
- package/src/__tests__/RunAIAgentResolver.consultPredecessor.test.ts +289 -0
- package/src/__tests__/RunAIAgentResolver.conversationWriter.test.ts +210 -0
- package/src/__tests__/RunAIAgentResolver.fireAndForgetCompletion.test.ts +209 -0
- package/src/__tests__/RunAIAgentResolver.handoff.test.ts +649 -0
- package/src/__tests__/RunAIAgentResolver.historyFrom.test.ts +19 -27
- package/src/__tests__/RunAIAgentResolver.runDataGuard.test.ts +10 -2
- package/src/__tests__/RunAIAgentResolver.serverReply.test.ts +358 -0
- package/src/__tests__/RunAIAgentResolver.stoppedPredecessor.test.ts +91 -13
- package/src/__tests__/RunTemplateResolver.test.ts +35 -2
- package/src/__tests__/RunViewResolver.cacheCheckForwarding.test.ts +11 -0
- package/src/__tests__/SchemaEvolutionCustomColumns.test.ts +119 -0
- package/src/__tests__/SchemaRefreshLaunch.test.ts +24 -2
- package/src/__tests__/ScopedFieldsForBuild.test.ts +192 -0
- package/src/__tests__/SessionJanitor.test.ts +195 -4
- package/src/__tests__/SessionManager.test.ts +164 -0
- package/src/__tests__/TaskGraphActionRunner.durablePayload.test.ts +2 -2
- package/src/__tests__/TaskGraphAgentRunner.test.ts +272 -16
- package/src/__tests__/TaskGraphContinuationDeliverer.test.ts +114 -3
- package/src/__tests__/TransactionGroupResolver.fieldSecurity.test.ts +199 -0
- package/src/__tests__/UserViewResolver.updateWhereClause.test.ts +15 -0
- package/src/__tests__/ViewOperationsHandler.test.ts +9 -7
- package/src/__tests__/WidgetSessionService.test.ts +583 -4
- package/src/__tests__/WorkQueueHostService.test.ts +25 -7
- package/src/__tests__/apiRootBoot.test.ts +1 -1
- package/src/__tests__/backgroundSweepConfigUnits.test.ts +153 -0
- package/src/__tests__/buildMagicLinkSessionUser.test.ts +96 -0
- package/src/__tests__/cacheBroadcastProviders.test.ts +403 -0
- package/src/__tests__/cacheInvalidationRecordData.test.ts +45 -0
- package/src/__tests__/contextRequestOrigin.test.ts +105 -0
- package/src/__tests__/conversationBrowsers.test.ts +62 -0
- package/src/__tests__/fieldSecurityFixtures.ts +91 -0
- package/src/__tests__/globalCors.test.ts +3 -3
- package/src/__tests__/localDevAuth.test.ts +196 -0
- package/src/__tests__/magicLinkExtensionCapabilities.test.ts +413 -0
- package/src/__tests__/orphanedConversationDetailReconciler.start.test.ts +82 -0
- package/src/__tests__/orphanedConversationDetailReconciler.test.ts +10 -0
- package/src/__tests__/ownedRealtimeSession.test.ts +14 -0
- package/src/__tests__/pushStatusResolver.filter.test.ts +57 -1
- package/src/__tests__/realtimeRecordingHandler.test.ts +24 -2
- package/src/__tests__/realtimeSessions/RealtimeSessionEventsResolver.test.ts +29 -1
- package/src/__tests__/realtimeSessions/ownedRealtimeSession.anonymous.test.ts +31 -0
- package/src/__tests__/realtimeSessions/ownedRealtimeSession.namedScoped.test.ts +37 -0
- package/src/__tests__/realtimeSessions/sessionAccess.test.ts +224 -7
- package/src/__tests__/realtimeSessions/sessionConfigStamps.test.ts +1 -1
- package/src/__tests__/realtimeSessions/verificationWorkflow.test.ts +25 -4
- package/src/__tests__/requestOrigin.test.ts +104 -0
- package/src/__tests__/resolverBase.cloudEventChangedFields.test.ts +157 -0
- package/src/__tests__/resolverBase.fieldSecurityTransport.test.ts +222 -0
- package/src/__tests__/resolverBase.fls.test.ts +146 -97
- package/src/__tests__/restTransport.fieldSecurity.test.ts +148 -0
- package/src/__tests__/runParamsTimeZone.test.ts +179 -0
- package/src/__tests__/runStreams.fieldSecurity.test.ts +100 -0
- package/src/__tests__/runViewProperties.test.ts +114 -0
- package/src/__tests__/scalabilityBenchmarks.test.ts +765 -0
- package/src/__tests__/scalabilityDatabaseIntegration.test.ts +207 -0
- package/src/__tests__/securityHardeningPr6034.test.ts +120 -0
- package/src/__tests__/sessionDeadline.test.ts +51 -0
- package/src/__tests__/sessionUserClone.test.ts +5 -1
- package/src/__tests__/sharedCache.test.ts +11 -0
- package/src/__tests__/startupSweepOrder.test.ts +40 -0
- package/src/__tests__/unifiedAuth.test.ts +101 -1
- package/src/__tests__/widgetGuestElevation.test.ts +2 -0
- package/src/agentSessions/BridgeHostInstance.ts +20 -5
- package/src/agentSessions/HandoffOfferExpiry.ts +18 -0
- package/src/agentSessions/ReturningVisitorRecap.ts +1 -0
- package/src/agentSessions/SessionJanitor.ts +95 -45
- package/src/agentSessions/SessionManager.ts +73 -20
- package/src/agentSessions/conversationBrowsers.ts +143 -0
- package/src/agentSessions/sessionDeadline.ts +81 -0
- package/src/auth/APIKeyScopeAuth.ts +5 -4
- package/src/auth/AuthProviderCatalogRouter.ts +3 -0
- package/src/auth/__tests__/loginEmailResolution.test.ts +67 -0
- package/src/auth/index.ts +56 -12
- package/src/auth/initializeProviders.ts +43 -1
- package/src/auth/localDevAuth.ts +528 -0
- package/src/auth/loginEmailResolution.ts +67 -0
- package/src/auth/magicLink/MagicLinkKeys.ts +147 -15
- package/src/auth/magicLink/MagicLinkRouter.ts +33 -6
- package/src/auth/magicLink/MagicLinkService.ts +250 -10
- package/src/auth/magicLink/index.ts +1 -1
- package/src/auth/magicLink/redeemLanding.ts +7 -4
- package/src/auth/magicLink/types.ts +38 -3
- package/src/auth/newUsers.ts +1 -0
- package/src/auth/sessionUserClone.ts +3 -2
- package/src/backgroundSweepConfigUnits.ts +213 -0
- package/src/broadcast/BaseCacheInvalidationBroadcastProvider.ts +674 -0
- package/src/broadcast/index.ts +5 -0
- package/src/broadcast/providers/AWSIoTCoreBroadcastProvider.ts +180 -0
- package/src/broadcast/providers/AzureWebPubSubBroadcastProvider.ts +182 -0
- package/src/broadcast/providers/GCPPubSubBroadcastProvider.ts +169 -0
- package/src/broadcast/providers/SequencedRoleBucketBroadcastProvider.ts +57 -0
- package/src/cache.ts +2 -1
- package/src/config.ts +138 -0
- package/src/context.ts +71 -14
- package/src/coreRoutes.ts +29 -7
- package/src/generated/graphql-schemas/__mj.ts +4145 -1193
- package/src/generic/CacheInvalidationResolver.ts +135 -78
- package/src/generic/OrphanedConversationDetailReconciler.ts +36 -3
- package/src/generic/PubSubManager.ts +54 -1
- package/src/generic/PushStatusResolver.ts +108 -11
- package/src/generic/ResolverBase.ts +635 -234
- package/src/generic/RunViewResolver.ts +176 -64
- package/src/generic/actionOutputFieldSecurity.ts +75 -0
- package/src/generic/fieldSecurityTransport.ts +62 -0
- package/src/index.ts +310 -85
- package/src/integration/ConnectionPause.ts +222 -0
- package/src/integration/CustomColumnPromoter.ts +129 -54
- package/src/integration/EntityMapLifecycle.ts +229 -6
- package/src/integration/InactiveRowWarnings.ts +50 -0
- package/src/integration/ObjectNamesByID.ts +97 -0
- package/src/integration/PostRestartIntrospect.ts +49 -0
- package/src/integration/RSUPostRestartProgress.ts +359 -0
- package/src/integration/RSUProgressBridge.ts +85 -2
- package/src/integration/RunArtifactAuthorization.ts +65 -0
- package/src/integration/SchemaRefreshLaunch.ts +12 -2
- package/src/integration/ScopedFieldsForBuild.ts +113 -0
- package/src/integration/TargetConfigGuard.ts +71 -0
- package/src/logging/variablesLoggingMiddleware.ts +59 -3
- package/src/realtimeSessions/README.md +7 -3
- package/src/realtimeSessions/SessionVerificationPortsBase.ts +1 -0
- package/src/realtimeSessions/ownedRealtimeSession.ts +16 -6
- package/src/realtimeSessions/sessionAccess.ts +211 -25
- package/src/realtimeSessions/sessionConfigStamps.ts +1 -1
- package/src/realtimeSessions/subscriptionAuthorization.ts +4 -2
- package/src/realtimeSessions/verificationWorkflow.ts +3 -1
- package/src/realtimeWidget/WidgetRouter.ts +22 -4
- package/src/realtimeWidget/WidgetSessionService.ts +254 -17
- package/src/realtimeWidget/host-identity.ts +1 -1
- package/src/realtimeWidget/visitorIdentity.ts +1 -0
- package/src/realtimeWidget/widgetCore.ts +34 -9
- package/src/realtimeWidget/widgetGuestElevation.ts +3 -1
- package/src/requestOrigin.ts +64 -0
- package/src/resolvers/ActionResolver.ts +78 -15
- package/src/resolvers/AdhocQueryResolver.ts +1 -0
- package/src/resolvers/AgentRunStatusPublisher.ts +36 -8
- package/src/resolvers/AgentSessionResolver.ts +50 -18
- package/src/resolvers/AutotagPipelineResolver.ts +2 -1
- package/src/resolvers/ConversationRunEventsResolver.ts +2 -0
- package/src/resolvers/EntityCommunicationsResolver.ts +56 -15
- package/src/resolvers/ExecuteRemoteOperationResolver.ts +41 -9
- package/src/resolvers/FetchEntityVectorsResolver.ts +132 -21
- package/src/resolvers/FileCategoryResolver.ts +1 -0
- package/src/resolvers/FileResolver.ts +14 -4
- package/src/resolvers/GetDataResolver.ts +35 -13
- package/src/resolvers/IntegrationDiscoveryResolver.ts +1570 -209
- package/src/resolvers/MCPResolver.ts +15 -2
- package/src/resolvers/MergeRecordsResolver.ts +23 -2
- package/src/resolvers/PipelineProgressResolver.ts +12 -3
- package/src/resolvers/QueryResolver.ts +20 -6
- package/src/resolvers/QuerySystemUserResolver.ts +207 -99
- package/src/resolvers/RSUResolver.ts +12 -0
- package/src/resolvers/RealtimeBridgeResolver.ts +1 -0
- package/src/resolvers/RealtimeClientSessionResolver.ts +144 -40
- package/src/resolvers/RemoteBrowserActionResolver.ts +252 -37
- package/src/resolvers/RunAIAgentResolver.ts +518 -163
- package/src/resolvers/RunAIPromptResolver.ts +18 -18
- package/src/resolvers/RunTemplateResolver.ts +9 -5
- package/src/resolvers/RunTestResolver.ts +3 -1
- package/src/resolvers/SyncDataResolver.ts +4 -0
- package/src/resolvers/TestQuerySQLResolver.ts +1 -0
- package/src/resolvers/TransactionGroupResolver.ts +66 -15
- package/src/resolvers/UserViewResolver.ts +2 -1
- package/src/resolvers/__tests__/GetDataResolver.tokens.test.ts +52 -0
- package/src/resolvers/__tests__/MergeRecordsResolver.test.ts +43 -0
- package/src/resolvers/meetingRecordingRegistration.ts +2 -0
- package/src/rest/EntityCRUDHandler.ts +22 -5
- package/src/rest/MediaAccessKeys.ts +6 -2
- package/src/rest/OAuthCallbackHandler.ts +13 -5
- package/src/rest/RESTEndpointHandler.ts +8 -5
- package/src/rest/RealtimeRecordingHandler.ts +9 -10
- package/src/rest/ViewOperationsHandler.ts +26 -7
- package/src/rest/setupRESTEndpoints.ts +11 -2
- package/src/serverRoleConfigUnits.ts +48 -0
- package/src/services/DurableEntityActionTaskSubmitter.ts +10 -2
- package/src/services/TaskGraphActionRunner.ts +2 -23
- package/src/services/TaskGraphAgentRunner.ts +43 -0
- package/src/services/TaskGraphContinuationDeliverer.ts +53 -20
- package/src/services/WorkQueueHostService.ts +26 -4
- package/src/services/workQueueConfig.ts +5 -5
- package/src/sharedCache.ts +1 -1
- package/src/types.ts +41 -1
- package/src/services/TaskOrchestration-Integration.md +0 -188
|
@@ -10,11 +10,28 @@
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import { BaseSingleton } from '@memberjunction/global';
|
|
13
|
-
import { LogStatusEx } from '@memberjunction/core';
|
|
13
|
+
import { LogStatusEx, LogWarning } from '@memberjunction/core';
|
|
14
14
|
import { createPrivateKey, createPublicKey, generateKeyPairSync, createHash, type KeyObject } from 'node:crypto';
|
|
15
15
|
import jwt from 'jsonwebtoken';
|
|
16
16
|
import type { MagicLinkJWTClaims } from './types.js';
|
|
17
17
|
|
|
18
|
+
/**
|
|
19
|
+
* True when the process is NOT running with `NODE_ENV=production`. This is the same
|
|
20
|
+
* production/local-dev line MJServer already uses to forbid local dev auth in production.
|
|
21
|
+
*/
|
|
22
|
+
export function IsMagicLinkLocalDevEnvironment(env: NodeJS.ProcessEnv = process.env): boolean {
|
|
23
|
+
return env.NODE_ENV?.trim().toLowerCase() !== 'production';
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Warning logged when a non-local-dev server falls back to an ephemeral keypair. */
|
|
27
|
+
export const EPHEMERAL_MAGIC_LINK_KEY_WARNING =
|
|
28
|
+
'[MagicLink] No rsaPrivateKey configured and NODE_ENV=production — generated an EPHEMERAL RS256 keypair. ' +
|
|
29
|
+
'Magic-link session tokens signed with it will stop validating when this process restarts, and they will not ' +
|
|
30
|
+
'validate on any other MJAPI instance behind the same load balancer, because each process generates its own key. ' +
|
|
31
|
+
'To fix, generate one RSA private key (e.g. `openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048`) and set it ' +
|
|
32
|
+
'as magicLink.rsaPrivateKey in mj.config.cjs or as MJ_MAGIC_LINK_PRIVATE_KEY (raw or base64-encoded PEM), ' +
|
|
33
|
+
'using the same key on every instance.';
|
|
34
|
+
|
|
18
35
|
/** A single JSON Web Key plus the metadata jwks-rsa needs to match it. */
|
|
19
36
|
interface PublishedJWK extends JsonWebKey {
|
|
20
37
|
kid: string;
|
|
@@ -34,6 +51,7 @@ export class MagicLinkKeyManager extends BaseSingleton<MagicLinkKeyManager> {
|
|
|
34
51
|
private publicKey?: KeyObject;
|
|
35
52
|
private _kid = '';
|
|
36
53
|
private _initialized = false;
|
|
54
|
+
private _isEphemeral = false;
|
|
37
55
|
|
|
38
56
|
// Public to satisfy BaseSingleton.getInstance's `this: new () => T` constraint
|
|
39
57
|
// (matches the AuthProviderFactory singleton pattern).
|
|
@@ -49,6 +67,15 @@ export class MagicLinkKeyManager extends BaseSingleton<MagicLinkKeyManager> {
|
|
|
49
67
|
return this._initialized;
|
|
50
68
|
}
|
|
51
69
|
|
|
70
|
+
/**
|
|
71
|
+
* True when no private key was configured and the keypair was generated for this process
|
|
72
|
+
* only. Tokens signed with an ephemeral key do not survive a restart and do not validate on
|
|
73
|
+
* other instances. Downstream code should ask this rather than reading the raw config value.
|
|
74
|
+
*/
|
|
75
|
+
public get IsEphemeral(): boolean {
|
|
76
|
+
return this._isEphemeral;
|
|
77
|
+
}
|
|
78
|
+
|
|
52
79
|
public get Kid(): string {
|
|
53
80
|
return this._kid;
|
|
54
81
|
}
|
|
@@ -56,8 +83,11 @@ export class MagicLinkKeyManager extends BaseSingleton<MagicLinkKeyManager> {
|
|
|
56
83
|
/**
|
|
57
84
|
* Initializes the keypair from a provided PEM (raw or base64-encoded) or, if
|
|
58
85
|
* none is supplied, generates an ephemeral 2048-bit RSA keypair. Idempotent.
|
|
86
|
+
*
|
|
87
|
+
* @param env - process environment used to decide whether the ephemeral fallback is a local-dev
|
|
88
|
+
* default (verbose-only notice) or a production misconfiguration (warning). Defaults to `process.env`.
|
|
59
89
|
*/
|
|
60
|
-
public Initialize(privateKeyPem?: string): void {
|
|
90
|
+
public Initialize(privateKeyPem?: string, env: NodeJS.ProcessEnv = process.env): void {
|
|
61
91
|
if (this._initialized) {
|
|
62
92
|
return;
|
|
63
93
|
}
|
|
@@ -69,17 +99,8 @@ export class MagicLinkKeyManager extends BaseSingleton<MagicLinkKeyManager> {
|
|
|
69
99
|
} else {
|
|
70
100
|
const { privateKey } = generateKeyPairSync('rsa', { modulusLength: 2048 });
|
|
71
101
|
priv = privateKey;
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
// the default startup output. Deployments that care set the key; operators diagnosing
|
|
75
|
-
// magic-link session loss can re-run with verbose logging.
|
|
76
|
-
LogStatusEx({
|
|
77
|
-
message:
|
|
78
|
-
'[MagicLink] No rsaPrivateKey configured — generated an EPHEMERAL RS256 keypair. ' +
|
|
79
|
-
'Outstanding magic-link sessions will be invalidated on restart. Set magicLink.rsaPrivateKey ' +
|
|
80
|
-
'(or MJ_MAGIC_LINK_PRIVATE_KEY) for stable production keys.',
|
|
81
|
-
verboseOnly: true
|
|
82
|
-
});
|
|
102
|
+
this._isEphemeral = true;
|
|
103
|
+
this.reportEphemeralKey(env);
|
|
83
104
|
}
|
|
84
105
|
|
|
85
106
|
this.privateKeyPem = priv.export({ type: 'pkcs8', format: 'pem' }) as string;
|
|
@@ -89,14 +110,106 @@ export class MagicLinkKeyManager extends BaseSingleton<MagicLinkKeyManager> {
|
|
|
89
110
|
}
|
|
90
111
|
|
|
91
112
|
/**
|
|
92
|
-
* Signs a set of magic-link claims and returns the compact JWT.
|
|
113
|
+
* Signs a set of magic-link (or local-dev) claims and returns the compact JWT.
|
|
93
114
|
* `iat`/`exp` are expected to already be set on the claims.
|
|
94
115
|
*/
|
|
95
|
-
public Sign(claims:
|
|
116
|
+
public Sign<T extends object>(claims: T): string {
|
|
96
117
|
this.ensureInitialized();
|
|
97
118
|
return jwt.sign(claims, this.privateKeyPem, { algorithm: 'RS256', keyid: this._kid });
|
|
98
119
|
}
|
|
99
120
|
|
|
121
|
+
/**
|
|
122
|
+
* Verifies a magic-link session JWT signed by this key manager (`RS256`, `mj_magic_link === true`).
|
|
123
|
+
* Returns `null` if invalid, expired, or forged.
|
|
124
|
+
*/
|
|
125
|
+
public VerifySessionToken(
|
|
126
|
+
token: string,
|
|
127
|
+
options?: { issuer?: string; audience?: string },
|
|
128
|
+
): MagicLinkJWTClaims | null {
|
|
129
|
+
this.ensureInitialized();
|
|
130
|
+
try {
|
|
131
|
+
const publicPem = this.publicKey!.export({ type: 'spki', format: 'pem' }) as string;
|
|
132
|
+
const verifyOptions: jwt.VerifyOptions = { algorithms: ['RS256'] };
|
|
133
|
+
if (options?.issuer) {
|
|
134
|
+
verifyOptions.issuer = options.issuer;
|
|
135
|
+
}
|
|
136
|
+
if (options?.audience) {
|
|
137
|
+
verifyOptions.audience = options.audience;
|
|
138
|
+
}
|
|
139
|
+
const decoded = jwt.verify(token, publicPem, verifyOptions);
|
|
140
|
+
if (!decoded || typeof decoded !== 'object') {
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
143
|
+
const claims = decoded as MagicLinkJWTClaims;
|
|
144
|
+
if (claims.mj_magic_link !== true || typeof claims.sub !== 'string') {
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
return claims;
|
|
148
|
+
} catch {
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Signs a redirect binding JWT (`mj_purpose = 'magic-link-redirect'`) that cryptographically
|
|
155
|
+
* binds a validated `redirectUrl` to a specific invite's `tokenHash`.
|
|
156
|
+
*
|
|
157
|
+
* Note: Expiration is intentionally omitted from the redirect binding JWT because the database
|
|
158
|
+
* invite row's `ExpiresAt` (enforced atomically during `RedeemInvite`) is the authoritative,
|
|
159
|
+
* mutable expiration — allowing `UpdateInviteExpiry()` to extend an invite without invalidating
|
|
160
|
+
* an already-delivered `&rt=` parameter.
|
|
161
|
+
*/
|
|
162
|
+
public SignRedirectBinding(tokenHash: string, redirectUrl: string, _expiresAtEpochSeconds?: number): string {
|
|
163
|
+
this.ensureInitialized();
|
|
164
|
+
const nowSeconds = Math.floor(Date.now() / 1000);
|
|
165
|
+
return jwt.sign(
|
|
166
|
+
{
|
|
167
|
+
mj_purpose: 'magic-link-redirect',
|
|
168
|
+
mj_th: tokenHash,
|
|
169
|
+
mj_redirect: redirectUrl,
|
|
170
|
+
iat: nowSeconds,
|
|
171
|
+
},
|
|
172
|
+
this.privateKeyPem,
|
|
173
|
+
{ algorithm: 'RS256', keyid: this._kid },
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Verifies a redirect binding JWT produced by {@link SignRedirectBinding} and ensures it matches
|
|
179
|
+
* `expectedTokenHash` (preventing cross-invite substitution) and carries a valid `http(s)` URL.
|
|
180
|
+
* Ignores JWT `exp` so bindings minted before an `UpdateInviteExpiry()` extension remain valid
|
|
181
|
+
* while the underlying invite row is valid. Returns the bound URL or `null`.
|
|
182
|
+
*/
|
|
183
|
+
public VerifyRedirectBinding(bindingToken: string, expectedTokenHash: string): string | null {
|
|
184
|
+
this.ensureInitialized();
|
|
185
|
+
try {
|
|
186
|
+
const publicPem = this.publicKey!.export({ type: 'spki', format: 'pem' }) as string;
|
|
187
|
+
const decoded = jwt.verify(bindingToken, publicPem, {
|
|
188
|
+
algorithms: ['RS256'],
|
|
189
|
+
ignoreExpiration: true,
|
|
190
|
+
});
|
|
191
|
+
if (!decoded || typeof decoded !== 'object') {
|
|
192
|
+
return null;
|
|
193
|
+
}
|
|
194
|
+
const record = decoded as { mj_purpose?: string; mj_th?: string; mj_redirect?: string };
|
|
195
|
+
if (
|
|
196
|
+
record.mj_purpose !== 'magic-link-redirect' ||
|
|
197
|
+
record.mj_th !== expectedTokenHash ||
|
|
198
|
+
typeof record.mj_redirect !== 'string' ||
|
|
199
|
+
!record.mj_redirect
|
|
200
|
+
) {
|
|
201
|
+
return null;
|
|
202
|
+
}
|
|
203
|
+
const parsed = new URL(record.mj_redirect);
|
|
204
|
+
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
|
|
205
|
+
return null;
|
|
206
|
+
}
|
|
207
|
+
return record.mj_redirect;
|
|
208
|
+
} catch {
|
|
209
|
+
return null;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
100
213
|
/**
|
|
101
214
|
* Returns the JWKS document (public key set) for the JWKS endpoint.
|
|
102
215
|
*/
|
|
@@ -106,6 +219,25 @@ export class MagicLinkKeyManager extends BaseSingleton<MagicLinkKeyManager> {
|
|
|
106
219
|
return { keys: [{ ...jwk, kid: this._kid, use: 'sig', alg: 'RS256' }] };
|
|
107
220
|
}
|
|
108
221
|
|
|
222
|
+
/**
|
|
223
|
+
* Local dev (NODE_ENV not 'production'): the ephemeral fallback is the designed behavior and
|
|
224
|
+
* fires on every boot, so the notice stays verbose-only. Otherwise it is a data-loss-on-restart
|
|
225
|
+
* misconfiguration, so it is a warning in the default output.
|
|
226
|
+
*/
|
|
227
|
+
private reportEphemeralKey(env: NodeJS.ProcessEnv): void {
|
|
228
|
+
if (!IsMagicLinkLocalDevEnvironment(env)) {
|
|
229
|
+
LogWarning(EPHEMERAL_MAGIC_LINK_KEY_WARNING);
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
LogStatusEx({
|
|
233
|
+
message:
|
|
234
|
+
'[MagicLink] No rsaPrivateKey configured — generated an EPHEMERAL RS256 keypair. ' +
|
|
235
|
+
'Outstanding magic-link sessions will be invalidated on restart. Set magicLink.rsaPrivateKey ' +
|
|
236
|
+
'(or MJ_MAGIC_LINK_PRIVATE_KEY) for stable production keys.',
|
|
237
|
+
verboseOnly: true
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
|
|
109
241
|
private ensureInitialized(): void {
|
|
110
242
|
if (!this._initialized) {
|
|
111
243
|
throw new Error('MagicLinkKeyManager not initialized — call Initialize() during server startup.');
|
|
@@ -32,6 +32,7 @@ export const MAGIC_LINK_JWKS_PATH = `${MAGIC_LINK_MOUNT_PATH}/jwks.json`;
|
|
|
32
32
|
export function CreateMagicLinkHandler(publicUrl: string, config: MagicLinkConfig): {
|
|
33
33
|
publicRouter: Router;
|
|
34
34
|
authenticatedRouter: Router;
|
|
35
|
+
service: MagicLinkService;
|
|
35
36
|
} {
|
|
36
37
|
// Initialize the signing keypair once.
|
|
37
38
|
MagicLinkKeyManager.Instance.Initialize(config.rsaPrivateKey);
|
|
@@ -64,10 +65,27 @@ export function CreateMagicLinkHandler(publicUrl: string, config: MagicLinkConfi
|
|
|
64
65
|
res.status(200).json(MagicLinkKeyManager.Instance.GetJWKS());
|
|
65
66
|
});
|
|
66
67
|
|
|
67
|
-
// Sends a completed redemption result: browser flow → 302 into
|
|
68
|
+
// Sends a completed redemption result: browser flow → 302 into a verified per-invite
|
|
69
|
+
// RedirectUrl (when cryptographically bound + origin-allowed) or Explorer with
|
|
68
70
|
// the session token in the URL fragment (never sent to a server, so it stays
|
|
69
71
|
// out of access/proxy logs); API flow → JSON with an appropriate status.
|
|
70
|
-
const sendRedeemResult = (
|
|
72
|
+
const sendRedeemResult = (
|
|
73
|
+
res: Response,
|
|
74
|
+
result: RedeemMagicLinkResult,
|
|
75
|
+
wantsJson: boolean,
|
|
76
|
+
verifiedRedirectUrl?: string,
|
|
77
|
+
): void => {
|
|
78
|
+
if (verifiedRedirectUrl && !wantsJson) {
|
|
79
|
+
const baseWithoutHash = verifiedRedirectUrl.split('#')[0];
|
|
80
|
+
if (result.success && result.token) {
|
|
81
|
+
res.redirect(302, `${baseWithoutHash}#token=${encodeURIComponent(result.token)}`);
|
|
82
|
+
} else {
|
|
83
|
+
const sep = baseWithoutHash.includes('?') ? '&' : '?';
|
|
84
|
+
res.redirect(302, `${baseWithoutHash}${sep}mlError=${encodeURIComponent(result.errorCode ?? 'invalid')}`);
|
|
85
|
+
}
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
|
|
71
89
|
const explorerUrl = config.explorerUrl?.replace(/\/$/, '');
|
|
72
90
|
if (explorerUrl && !wantsJson) {
|
|
73
91
|
if (result.success && result.token) {
|
|
@@ -102,6 +120,7 @@ export function CreateMagicLinkHandler(publicUrl: string, config: MagicLinkConfi
|
|
|
102
120
|
// the actual redemption happens only on POST (below), gated by a user click.
|
|
103
121
|
publicRouter.get('/redeem', redeemLimiter, (req: Request, res: Response) => {
|
|
104
122
|
const token = typeof req.query.token === 'string' ? req.query.token : '';
|
|
123
|
+
const rt = typeof req.query.rt === 'string' ? req.query.rt : undefined;
|
|
105
124
|
if (!token) {
|
|
106
125
|
res.status(400).json({ success: false, error: 'Missing token.' });
|
|
107
126
|
return;
|
|
@@ -114,16 +133,19 @@ export function CreateMagicLinkHandler(publicUrl: string, config: MagicLinkConfi
|
|
|
114
133
|
res
|
|
115
134
|
.status(200)
|
|
116
135
|
.type('html')
|
|
117
|
-
.send(BuildRedeemLandingHtml(token, ApiRoute(`${MAGIC_LINK_MOUNT_PATH}/redeem`)));
|
|
136
|
+
.send(BuildRedeemLandingHtml(token, ApiRoute(`${MAGIC_LINK_MOUNT_PATH}/redeem`), rt));
|
|
118
137
|
});
|
|
119
138
|
|
|
120
139
|
// POST /redeem performs the actual (side-effectful) redemption. Token arrives
|
|
121
140
|
// from the interstitial form body, an API client's JSON body, or the query.
|
|
122
141
|
publicRouter.post('/redeem', redeemLimiter, urlencoded({ extended: false }), json(), async (req: Request, res: Response) => {
|
|
123
|
-
const body = (req.body ?? {}) as { token?: string };
|
|
142
|
+
const body = (req.body ?? {}) as { token?: string; rt?: string };
|
|
124
143
|
const token =
|
|
125
144
|
(typeof body.token === 'string' && body.token) ||
|
|
126
145
|
(typeof req.query.token === 'string' ? req.query.token : '');
|
|
146
|
+
const rt =
|
|
147
|
+
(typeof body.rt === 'string' && body.rt) ||
|
|
148
|
+
(typeof req.query.rt === 'string' ? req.query.rt : undefined);
|
|
127
149
|
const wantsJson = req.query.format === 'json' || req.is('application/json') === 'application/json';
|
|
128
150
|
|
|
129
151
|
if (!token) {
|
|
@@ -131,6 +153,8 @@ export function CreateMagicLinkHandler(publicUrl: string, config: MagicLinkConfi
|
|
|
131
153
|
return;
|
|
132
154
|
}
|
|
133
155
|
|
|
156
|
+
const verifiedRedirectUrl = service.ResolveVerifiedRedirectUrl(token, rt);
|
|
157
|
+
|
|
134
158
|
// Forensic context for the redemption audit trail. `req.ip` honors the app's
|
|
135
159
|
// trust-proxy setting; headers are best-effort and may be absent for API clients.
|
|
136
160
|
const result = await service.RedeemInvite(token, {
|
|
@@ -138,7 +162,7 @@ export function CreateMagicLinkHandler(publicUrl: string, config: MagicLinkConfi
|
|
|
138
162
|
userAgent: req.get('user-agent') ?? undefined,
|
|
139
163
|
origin: req.get('origin') ?? undefined,
|
|
140
164
|
});
|
|
141
|
-
sendRedeemResult(res, result, wantsJson);
|
|
165
|
+
sendRedeemResult(res, result, wantsJson, verifiedRedirectUrl);
|
|
142
166
|
});
|
|
143
167
|
|
|
144
168
|
// ── Authenticated (invite creation) ───────────────────────────────────────
|
|
@@ -166,6 +190,8 @@ export function CreateMagicLinkHandler(publicUrl: string, config: MagicLinkConfi
|
|
|
166
190
|
MaxUses: body.MaxUses,
|
|
167
191
|
firstName: body.firstName,
|
|
168
192
|
lastName: body.lastName,
|
|
193
|
+
RedirectUrl: body.RedirectUrl,
|
|
194
|
+
SendEmail: body.SendEmail,
|
|
169
195
|
},
|
|
170
196
|
creatingUser,
|
|
171
197
|
);
|
|
@@ -175,13 +201,14 @@ export function CreateMagicLinkHandler(publicUrl: string, config: MagicLinkConfi
|
|
|
175
201
|
res.status(status).json(result);
|
|
176
202
|
});
|
|
177
203
|
|
|
178
|
-
return { publicRouter, authenticatedRouter };
|
|
204
|
+
return { publicRouter, authenticatedRouter, service };
|
|
179
205
|
}
|
|
180
206
|
|
|
181
207
|
/** @deprecated Use {@link CreateMagicLinkHandler}. */
|
|
182
208
|
export function createMagicLinkHandler(publicUrl: string, config: MagicLinkConfig): {
|
|
183
209
|
publicRouter: Router;
|
|
184
210
|
authenticatedRouter: Router;
|
|
211
|
+
service: MagicLinkService;
|
|
185
212
|
} {
|
|
186
213
|
return CreateMagicLinkHandler(publicUrl, config);
|
|
187
214
|
}
|
|
@@ -37,9 +37,12 @@ import { configInfo, type MagicLinkConfig } from '../../config.js';
|
|
|
37
37
|
import { CreateIsolatedProvider } from '../../isolatedProvider.js';
|
|
38
38
|
import { MagicLinkKeyManager } from './MagicLinkKeys.js';
|
|
39
39
|
import { GenerateRawToken, GenerateSessionId, HashToken, EvaluateInvite, BuildSessionClaims, BuildConsumeInvitePostgresSQL, CanIssueInvites, IsRoleGrantable, MAGIC_LINK_TOKEN_PREFIX } from './magicLinkCore.js';
|
|
40
|
+
import type { IServerExtensionMagicLinkService } from '@memberjunction/server-extensions-core';
|
|
40
41
|
import type {
|
|
41
42
|
CreateMagicLinkInviteParams,
|
|
42
43
|
CreateMagicLinkInviteResult,
|
|
44
|
+
ManageMagicLinkInviteResult,
|
|
45
|
+
MagicLinkJWTClaims,
|
|
43
46
|
RedeemMagicLinkResult,
|
|
44
47
|
RedeemAuditContext,
|
|
45
48
|
} from './types.js';
|
|
@@ -75,11 +78,53 @@ interface ProvisionResult {
|
|
|
75
78
|
error?: string;
|
|
76
79
|
}
|
|
77
80
|
|
|
81
|
+
/**
|
|
82
|
+
* Validates that a candidate `redirectUrl` is a well-formed `http:` or `https:` URL whose
|
|
83
|
+
* origin matches at least one concrete normalized entry in `allowedOrigins`.
|
|
84
|
+
* Wildcard `'*'` entries are explicitly ignored/rejected so session tokens can never be
|
|
85
|
+
* redirected to unvalidated origins.
|
|
86
|
+
*/
|
|
87
|
+
export function IsMagicLinkRedirectUrlAllowed(redirectUrl: string, allowedOrigins: readonly string[]): boolean {
|
|
88
|
+
const trimmed = redirectUrl.trim();
|
|
89
|
+
if (!trimmed) {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
let parsed: URL;
|
|
93
|
+
try {
|
|
94
|
+
parsed = new URL(trimmed);
|
|
95
|
+
} catch {
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
const normalizedTargetOrigin = parsed.origin.toLowerCase();
|
|
102
|
+
for (const rawAllowed of allowedOrigins) {
|
|
103
|
+
const candidate = (rawAllowed ?? '').trim();
|
|
104
|
+
if (!candidate || candidate === '*') {
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
try {
|
|
108
|
+
const allowedUrl = new URL(candidate);
|
|
109
|
+
if (allowedUrl.origin.toLowerCase() === normalizedTargetOrigin) {
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
} catch {
|
|
113
|
+
if (candidate.replace(/\/$/, '').toLowerCase() === normalizedTargetOrigin) {
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
|
|
78
121
|
/**
|
|
79
122
|
* Magic-link service. One instance per server, constructed with the resolved
|
|
80
|
-
* public URL and the validated config.
|
|
123
|
+
* public URL and the validated config. Implements {@link IServerExtensionMagicLinkService}
|
|
124
|
+
* so `BaseServerExtension` implementations can mint, revoke, extend, and verify invites
|
|
125
|
+
* via `context.services.GetMagicLinkService?.()`.
|
|
81
126
|
*/
|
|
82
|
-
export class MagicLinkService {
|
|
127
|
+
export class MagicLinkService implements IServerExtensionMagicLinkService {
|
|
83
128
|
constructor(
|
|
84
129
|
private readonly publicUrl: string,
|
|
85
130
|
private readonly config: MagicLinkConfig,
|
|
@@ -87,7 +132,7 @@ export class MagicLinkService {
|
|
|
87
132
|
|
|
88
133
|
/**
|
|
89
134
|
* Creates a single-use, app-scoped invite, persists its hashed token, and
|
|
90
|
-
* (when a communication provider is configured) emails the link.
|
|
135
|
+
* (when a communication provider is configured and `params.SendEmail !== false`) emails the link.
|
|
91
136
|
*
|
|
92
137
|
* @param params invite parameters
|
|
93
138
|
* @param creatingUser the authenticated internal user issuing the invite
|
|
@@ -110,6 +155,15 @@ export class MagicLinkService {
|
|
|
110
155
|
return { success: false, errorCode: 'forbidden', error: 'Not authorized to issue magic-link invites.' };
|
|
111
156
|
}
|
|
112
157
|
|
|
158
|
+
const validatedRedirectUrl = params.RedirectUrl?.trim() ? params.RedirectUrl.trim() : undefined;
|
|
159
|
+
if (validatedRedirectUrl && !IsMagicLinkRedirectUrlAllowed(validatedRedirectUrl, this.allowedRedirectOrigins())) {
|
|
160
|
+
return {
|
|
161
|
+
success: false,
|
|
162
|
+
errorCode: 'invalid_redirect_url',
|
|
163
|
+
error: `RedirectUrl '${validatedRedirectUrl}' is not permitted by the server's allowed frontend origins.`,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
|
|
113
167
|
const roleId = params.RoleId ?? this.resolveRestrictedRoleId(md);
|
|
114
168
|
if (!roleId) {
|
|
115
169
|
return { success: false, error: `Restricted role '${this.config.restrictedRoleName}' not found and no roleId supplied.` };
|
|
@@ -136,12 +190,13 @@ export class MagicLinkService {
|
|
|
136
190
|
}
|
|
137
191
|
|
|
138
192
|
const rawToken = GenerateRawToken();
|
|
193
|
+
const tokenHash = HashToken(rawToken);
|
|
139
194
|
const expiresInHours = params.ExpiresInHours ?? this.config.defaultExpiresInHours;
|
|
140
195
|
const expiresAt = new Date(Date.now() + expiresInHours * 3600 * 1000);
|
|
141
196
|
|
|
142
197
|
const invite = await md.GetEntityObject<MJMagicLinkInviteEntity>(INVITE_ENTITY, creatingUser);
|
|
143
198
|
invite.NewRecord();
|
|
144
|
-
invite.TokenHash =
|
|
199
|
+
invite.TokenHash = tokenHash;
|
|
145
200
|
invite.Email = params.email;
|
|
146
201
|
invite.ApplicationID = params.ApplicationId;
|
|
147
202
|
invite.RoleID = roleId;
|
|
@@ -161,10 +216,22 @@ export class MagicLinkService {
|
|
|
161
216
|
// multi-scope reads. Best-effort so a child-row hiccup never fails issuance.
|
|
162
217
|
await this.writeInviteScopeChildRows(invite.ID, params.ApplicationId, roleId, creatingUser, md);
|
|
163
218
|
|
|
164
|
-
|
|
219
|
+
let redirectBindingToken: string | undefined;
|
|
220
|
+
if (validatedRedirectUrl) {
|
|
221
|
+
if (!MagicLinkKeyManager.Instance.IsInitialized) {
|
|
222
|
+
MagicLinkKeyManager.Instance.Initialize(this.config.rsaPrivateKey);
|
|
223
|
+
}
|
|
224
|
+
redirectBindingToken = MagicLinkKeyManager.Instance.SignRedirectBinding(
|
|
225
|
+
tokenHash,
|
|
226
|
+
validatedRedirectUrl,
|
|
227
|
+
Math.floor(expiresAt.getTime() / 1000),
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const redemptionUrl = this.buildRedemptionUrl(rawToken, redirectBindingToken);
|
|
165
232
|
|
|
166
233
|
let emailSent = false;
|
|
167
|
-
if (this.config.communicationProvider) {
|
|
234
|
+
if (params.SendEmail !== false && this.config.communicationProvider) {
|
|
168
235
|
emailSent = await this.sendInviteEmail(params.email, redemptionUrl, app.Name, creatingUser);
|
|
169
236
|
}
|
|
170
237
|
|
|
@@ -172,7 +239,7 @@ export class MagicLinkService {
|
|
|
172
239
|
success: true,
|
|
173
240
|
inviteId: invite.ID,
|
|
174
241
|
redemptionUrl,
|
|
175
|
-
// Surface the raw token only when we couldn't deliver it ourselves.
|
|
242
|
+
// Surface the raw token only when we couldn't (or were asked not to) deliver it ourselves.
|
|
176
243
|
rawToken: emailSent ? undefined : rawToken,
|
|
177
244
|
emailSent,
|
|
178
245
|
expiresAt: expiresAt.toISOString(),
|
|
@@ -183,6 +250,158 @@ export class MagicLinkService {
|
|
|
183
250
|
}
|
|
184
251
|
}
|
|
185
252
|
|
|
253
|
+
/**
|
|
254
|
+
* Revokes an existing invite so subsequent redemptions fail with `'revoked'`.
|
|
255
|
+
* Requires the acting user to hold invite-issuance authority (`CanIssueInvites`).
|
|
256
|
+
*/
|
|
257
|
+
public async RevokeInvite(
|
|
258
|
+
inviteId: string,
|
|
259
|
+
actingUser: UserInfo,
|
|
260
|
+
provider?: IMetadataProvider,
|
|
261
|
+
): Promise<ManageMagicLinkInviteResult> {
|
|
262
|
+
try {
|
|
263
|
+
const callerRoleNames = (actingUser.UserRoles ?? []).map((r) => r.Role).filter((n): n is string => !!n);
|
|
264
|
+
if (!CanIssueInvites(actingUser.Type, callerRoleNames, this.config.inviteIssuerRoleNames)) {
|
|
265
|
+
return { success: false, errorCode: 'forbidden', error: 'Not authorized to revoke magic-link invites.' };
|
|
266
|
+
}
|
|
267
|
+
if (!inviteId?.trim()) {
|
|
268
|
+
return { success: false, errorCode: 'not_found', error: 'Invite ID is required.' };
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
const md = provider ?? Metadata.Provider;
|
|
272
|
+
const invite = await md.GetEntityObject<MJMagicLinkInviteEntity>(INVITE_ENTITY, actingUser);
|
|
273
|
+
const loaded = await invite.Load(inviteId.trim());
|
|
274
|
+
if (!loaded) {
|
|
275
|
+
return { success: false, errorCode: 'not_found', error: `Invite '${inviteId}' not found.` };
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
if (invite.Status === 'Revoked') {
|
|
279
|
+
return {
|
|
280
|
+
success: true,
|
|
281
|
+
inviteId: invite.ID,
|
|
282
|
+
status: invite.Status,
|
|
283
|
+
expiresAt: invite.ExpiresAt.toISOString(),
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
invite.Status = 'Revoked';
|
|
288
|
+
if (!(await invite.Save())) {
|
|
289
|
+
return {
|
|
290
|
+
success: false,
|
|
291
|
+
errorCode: 'server_error',
|
|
292
|
+
error: `Failed to revoke invite: ${invite.LatestResult?.CompleteMessage ?? 'unknown error'}`,
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
return {
|
|
297
|
+
success: true,
|
|
298
|
+
inviteId: invite.ID,
|
|
299
|
+
status: invite.Status,
|
|
300
|
+
expiresAt: invite.ExpiresAt.toISOString(),
|
|
301
|
+
};
|
|
302
|
+
} catch (e) {
|
|
303
|
+
LogError(e);
|
|
304
|
+
return { success: false, errorCode: 'server_error', error: e instanceof Error ? e.message : String(e) };
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Updates the expiration timestamp of an existing non-revoked, non-consumed invite.
|
|
310
|
+
* Requires the acting user to hold invite-issuance authority (`CanIssueInvites`).
|
|
311
|
+
*/
|
|
312
|
+
public async UpdateInviteExpiry(
|
|
313
|
+
inviteId: string,
|
|
314
|
+
expiresAt: Date,
|
|
315
|
+
actingUser: UserInfo,
|
|
316
|
+
provider?: IMetadataProvider,
|
|
317
|
+
): Promise<ManageMagicLinkInviteResult> {
|
|
318
|
+
try {
|
|
319
|
+
const callerRoleNames = (actingUser.UserRoles ?? []).map((r) => r.Role).filter((n): n is string => !!n);
|
|
320
|
+
if (!CanIssueInvites(actingUser.Type, callerRoleNames, this.config.inviteIssuerRoleNames)) {
|
|
321
|
+
return { success: false, errorCode: 'forbidden', error: 'Not authorized to update magic-link invites.' };
|
|
322
|
+
}
|
|
323
|
+
if (!(expiresAt instanceof Date) || Number.isNaN(expiresAt.getTime())) {
|
|
324
|
+
return { success: false, errorCode: 'invalid_expiry', error: 'expiresAt must be a valid Date.' };
|
|
325
|
+
}
|
|
326
|
+
if (!inviteId?.trim()) {
|
|
327
|
+
return { success: false, errorCode: 'not_found', error: 'Invite ID is required.' };
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
const md = provider ?? Metadata.Provider;
|
|
331
|
+
const invite = await md.GetEntityObject<MJMagicLinkInviteEntity>(INVITE_ENTITY, actingUser);
|
|
332
|
+
const loaded = await invite.Load(inviteId.trim());
|
|
333
|
+
if (!loaded) {
|
|
334
|
+
return { success: false, errorCode: 'not_found', error: `Invite '${inviteId}' not found.` };
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
if (invite.Status === 'Revoked' || invite.Status === 'Consumed') {
|
|
338
|
+
return {
|
|
339
|
+
success: false,
|
|
340
|
+
errorCode: 'invalid_state',
|
|
341
|
+
error: `Cannot update expiry on invite '${invite.ID}' because its status is '${invite.Status}'.`,
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
const nowMs = Date.now();
|
|
346
|
+
invite.ExpiresAt = expiresAt;
|
|
347
|
+
if (invite.Status === 'Expired' && expiresAt.getTime() > nowMs && invite.UseCount < invite.MaxUses) {
|
|
348
|
+
invite.Status = 'Active';
|
|
349
|
+
} else if (invite.Status === 'Active' && expiresAt.getTime() <= nowMs) {
|
|
350
|
+
invite.Status = 'Expired';
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
if (!(await invite.Save())) {
|
|
354
|
+
return {
|
|
355
|
+
success: false,
|
|
356
|
+
errorCode: 'server_error',
|
|
357
|
+
error: `Failed to update invite expiry: ${invite.LatestResult?.CompleteMessage ?? 'unknown error'}`,
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
return {
|
|
362
|
+
success: true,
|
|
363
|
+
inviteId: invite.ID,
|
|
364
|
+
status: invite.Status,
|
|
365
|
+
expiresAt: invite.ExpiresAt.toISOString(),
|
|
366
|
+
};
|
|
367
|
+
} catch (e) {
|
|
368
|
+
LogError(e);
|
|
369
|
+
return { success: false, errorCode: 'server_error', error: e instanceof Error ? e.message : String(e) };
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* Verifies a magic-link session JWT against this service's configured issuer and audience.
|
|
375
|
+
*/
|
|
376
|
+
public VerifySessionToken(token: string): MagicLinkJWTClaims | null {
|
|
377
|
+
if (!token || !MagicLinkKeyManager.Instance.IsInitialized) {
|
|
378
|
+
return null;
|
|
379
|
+
}
|
|
380
|
+
return MagicLinkKeyManager.Instance.VerifySessionToken(token, {
|
|
381
|
+
issuer: this.publicUrl,
|
|
382
|
+
audience: this.config.audience,
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* Verifies a signed redirect binding (`rt`) against the raw invite token's hash AND the host's
|
|
388
|
+
* allowed frontend origins. Returns the verified redirect URL, or `undefined` if absent/invalid.
|
|
389
|
+
*/
|
|
390
|
+
public ResolveVerifiedRedirectUrl(rawToken: string, redirectBindingToken: string | undefined): string | undefined {
|
|
391
|
+
if (!rawToken || !redirectBindingToken || !MagicLinkKeyManager.Instance.IsInitialized) {
|
|
392
|
+
return undefined;
|
|
393
|
+
}
|
|
394
|
+
const tokenHash = HashToken(rawToken);
|
|
395
|
+
const boundUrl = MagicLinkKeyManager.Instance.VerifyRedirectBinding(redirectBindingToken, tokenHash);
|
|
396
|
+
if (!boundUrl) {
|
|
397
|
+
return undefined;
|
|
398
|
+
}
|
|
399
|
+
if (!IsMagicLinkRedirectUrlAllowed(boundUrl, this.allowedRedirectOrigins())) {
|
|
400
|
+
return undefined;
|
|
401
|
+
}
|
|
402
|
+
return boundUrl;
|
|
403
|
+
}
|
|
404
|
+
|
|
186
405
|
/**
|
|
187
406
|
* Redeems a raw token: validates the invite, atomically consumes one use,
|
|
188
407
|
* provisions/links the user with the restricted role + app, and mints a
|
|
@@ -420,10 +639,31 @@ export class MagicLinkService {
|
|
|
420
639
|
return role?.ID;
|
|
421
640
|
}
|
|
422
641
|
|
|
423
|
-
/** Builds the shareable redemption URL. */
|
|
424
|
-
private buildRedemptionUrl(rawToken: string): string {
|
|
642
|
+
/** Builds the shareable redemption URL (including `&rt=...` when a per-invite RedirectUrl was signed). */
|
|
643
|
+
private buildRedemptionUrl(rawToken: string, redirectBindingToken?: string): string {
|
|
425
644
|
const base = this.publicUrl.replace(/\/$/, '');
|
|
426
|
-
|
|
645
|
+
const rtParam = redirectBindingToken ? `&rt=${encodeURIComponent(redirectBindingToken)}` : '';
|
|
646
|
+
return `${base}/magic-link/redeem?token=${encodeURIComponent(rawToken)}${rtParam}`;
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
/**
|
|
650
|
+
* Collects concrete frontend origins a caller-supplied per-invite `RedirectUrl` is permitted
|
|
651
|
+
* to target (`explorerUrl`, `magicLink.allowedRedirectOrigins`, and non-wildcard `cors.allowedOrigins`).
|
|
652
|
+
*/
|
|
653
|
+
private allowedRedirectOrigins(): string[] {
|
|
654
|
+
const origins: string[] = [];
|
|
655
|
+
const candidates: readonly (string | undefined)[] = [
|
|
656
|
+
this.config.explorerUrl ?? configInfo.magicLink?.explorerUrl,
|
|
657
|
+
...(this.config.allowedRedirectOrigins ?? configInfo.magicLink?.allowedRedirectOrigins ?? []),
|
|
658
|
+
...(configInfo.cors?.allowedOrigins ?? []),
|
|
659
|
+
];
|
|
660
|
+
for (const raw of candidates) {
|
|
661
|
+
const trimmed = raw?.trim();
|
|
662
|
+
if (trimmed && trimmed !== '*') {
|
|
663
|
+
origins.push(trimmed);
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
return origins;
|
|
427
667
|
}
|
|
428
668
|
|
|
429
669
|
/**
|
|
@@ -8,7 +8,7 @@ export {
|
|
|
8
8
|
type InviteEvaluationInput,
|
|
9
9
|
} from './magicLinkCore.js';
|
|
10
10
|
export { MagicLinkKeyManager } from './MagicLinkKeys.js';
|
|
11
|
-
export { MagicLinkService } from './MagicLinkService.js';
|
|
11
|
+
export { MagicLinkService, IsMagicLinkRedirectUrlAllowed } from './MagicLinkService.js';
|
|
12
12
|
export {
|
|
13
13
|
CreateMagicLinkHandler, createMagicLinkHandler,
|
|
14
14
|
CreateMagicLinkJwksRouter, createMagicLinkJwksRouter,
|