@memberjunction/ng-conversations 6.2.0-edge.2 → 6.2.0-edge.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -7
- package/dist/lib/components/collection/collection-view.component.d.ts.map +1 -1
- package/dist/lib/components/collection/collection-view.component.js +1 -0
- package/dist/lib/components/collection/collection-view.component.js.map +1 -1
- package/dist/lib/components/composer/ai-composer.component.d.ts +14 -2
- package/dist/lib/components/composer/ai-composer.component.d.ts.map +1 -1
- package/dist/lib/components/composer/ai-composer.component.js +35 -4
- package/dist/lib/components/composer/ai-composer.component.js.map +1 -1
- package/dist/lib/components/conversation/conversation-chat-area.component.d.ts +632 -55
- package/dist/lib/components/conversation/conversation-chat-area.component.d.ts.map +1 -1
- package/dist/lib/components/conversation/conversation-chat-area.component.js +2748 -624
- package/dist/lib/components/conversation/conversation-chat-area.component.js.map +1 -1
- package/dist/lib/components/conversation/forks-popover.component.d.ts +37 -0
- package/dist/lib/components/conversation/forks-popover.component.d.ts.map +1 -0
- package/dist/lib/components/conversation/forks-popover.component.js +164 -0
- package/dist/lib/components/conversation/forks-popover.component.js.map +1 -0
- package/dist/lib/components/export/export-modal.component.d.ts +7 -2
- package/dist/lib/components/export/export-modal.component.d.ts.map +1 -1
- package/dist/lib/components/export/export-modal.component.js +16 -3
- package/dist/lib/components/export/export-modal.component.js.map +1 -1
- package/dist/lib/components/message/conversation-message-rating.component.d.ts.map +1 -1
- package/dist/lib/components/message/conversation-message-rating.component.js +11 -9
- package/dist/lib/components/message/conversation-message-rating.component.js.map +1 -1
- package/dist/lib/components/message/message-input.component.d.ts +121 -11
- package/dist/lib/components/message/message-input.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-input.component.js +307 -106
- package/dist/lib/components/message/message-input.component.js.map +1 -1
- package/dist/lib/components/message/message-item.component.d.ts +178 -5
- package/dist/lib/components/message/message-item.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-item.component.js +919 -306
- package/dist/lib/components/message/message-item.component.js.map +1 -1
- package/dist/lib/components/message/message-list.component.d.ts +92 -21
- package/dist/lib/components/message/message-list.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-list.component.js +337 -52
- package/dist/lib/components/message/message-list.component.js.map +1 -1
- package/dist/lib/components/realtime/avatar/realtime-avatar-channel.d.ts +34 -0
- package/dist/lib/components/realtime/avatar/realtime-avatar-channel.d.ts.map +1 -0
- package/dist/lib/components/realtime/avatar/realtime-avatar-channel.js +75 -0
- package/dist/lib/components/realtime/avatar/realtime-avatar-channel.js.map +1 -0
- package/dist/lib/components/realtime/avatar/realtime-avatar-surface.component.d.ts +80 -0
- package/dist/lib/components/realtime/avatar/realtime-avatar-surface.component.d.ts.map +1 -0
- package/dist/lib/components/realtime/avatar/realtime-avatar-surface.component.js +202 -0
- package/dist/lib/components/realtime/avatar/realtime-avatar-surface.component.js.map +1 -0
- package/dist/lib/components/realtime/capture/realtime-camera-check-card.component.d.ts +45 -0
- package/dist/lib/components/realtime/capture/realtime-camera-check-card.component.d.ts.map +1 -0
- package/dist/lib/components/realtime/capture/realtime-camera-check-card.component.js +123 -0
- package/dist/lib/components/realtime/capture/realtime-camera-check-card.component.js.map +1 -0
- package/dist/lib/components/realtime/capture/realtime-capture-channel.d.ts +90 -0
- package/dist/lib/components/realtime/capture/realtime-capture-channel.d.ts.map +1 -0
- package/dist/lib/components/realtime/capture/realtime-capture-channel.js +223 -0
- package/dist/lib/components/realtime/capture/realtime-capture-channel.js.map +1 -0
- package/dist/lib/components/realtime/capture/realtime-capture-model.d.ts +98 -0
- package/dist/lib/components/realtime/capture/realtime-capture-model.d.ts.map +1 -0
- package/dist/lib/components/realtime/capture/realtime-capture-model.js +161 -0
- package/dist/lib/components/realtime/capture/realtime-capture-model.js.map +1 -0
- package/dist/lib/components/realtime/capture/realtime-capture-surface.component.d.ts +48 -0
- package/dist/lib/components/realtime/capture/realtime-capture-surface.component.d.ts.map +1 -0
- package/dist/lib/components/realtime/capture/realtime-capture-surface.component.js +205 -0
- package/dist/lib/components/realtime/capture/realtime-capture-surface.component.js.map +1 -0
- package/dist/lib/components/realtime/channels/client-context-channel.d.ts +19 -2
- package/dist/lib/components/realtime/channels/client-context-channel.d.ts.map +1 -1
- package/dist/lib/components/realtime/channels/client-context-channel.js +83 -9
- package/dist/lib/components/realtime/channels/client-context-channel.js.map +1 -1
- package/dist/lib/components/realtime/channels/realtime-channel-pane.component.d.ts +30 -9
- package/dist/lib/components/realtime/channels/realtime-channel-pane.component.d.ts.map +1 -1
- package/dist/lib/components/realtime/channels/realtime-channel-pane.component.js +78 -14
- package/dist/lib/components/realtime/channels/realtime-channel-pane.component.js.map +1 -1
- package/dist/lib/components/realtime/identity-verification/identity-verification-channel.d.ts +71 -0
- package/dist/lib/components/realtime/identity-verification/identity-verification-channel.d.ts.map +1 -0
- package/dist/lib/components/realtime/identity-verification/identity-verification-channel.js +259 -0
- package/dist/lib/components/realtime/identity-verification/identity-verification-channel.js.map +1 -0
- package/dist/lib/components/realtime/identity-verification/identity-verification-model.d.ts +129 -0
- package/dist/lib/components/realtime/identity-verification/identity-verification-model.d.ts.map +1 -0
- package/dist/lib/components/realtime/identity-verification/identity-verification-model.js +373 -0
- package/dist/lib/components/realtime/identity-verification/identity-verification-model.js.map +1 -0
- package/dist/lib/components/realtime/identity-verification/identity-verification-surface.component.d.ts +77 -0
- package/dist/lib/components/realtime/identity-verification/identity-verification-surface.component.d.ts.map +1 -0
- package/dist/lib/components/realtime/identity-verification/identity-verification-surface.component.js +420 -0
- package/dist/lib/components/realtime/identity-verification/identity-verification-surface.component.js.map +1 -0
- package/dist/lib/components/realtime/interactive-component/component-contract.d.ts +83 -0
- package/dist/lib/components/realtime/interactive-component/component-contract.d.ts.map +1 -0
- package/dist/lib/components/realtime/interactive-component/component-contract.js +292 -0
- package/dist/lib/components/realtime/interactive-component/component-contract.js.map +1 -0
- package/dist/lib/components/realtime/interactive-component/component-data-state.d.ts +39 -0
- package/dist/lib/components/realtime/interactive-component/component-data-state.d.ts.map +1 -0
- package/dist/lib/components/realtime/interactive-component/component-data-state.js +152 -0
- package/dist/lib/components/realtime/interactive-component/component-data-state.js.map +1 -0
- package/dist/lib/components/realtime/interactive-component/component-instance-engine.d.ts +109 -0
- package/dist/lib/components/realtime/interactive-component/component-instance-engine.d.ts.map +1 -0
- package/dist/lib/components/realtime/interactive-component/component-instance-engine.js +146 -0
- package/dist/lib/components/realtime/interactive-component/component-instance-engine.js.map +1 -0
- package/dist/lib/components/realtime/interactive-component/component-spec-content.d.ts +19 -0
- package/dist/lib/components/realtime/interactive-component/component-spec-content.d.ts.map +1 -0
- package/dist/lib/components/realtime/interactive-component/component-spec-content.js +39 -0
- package/dist/lib/components/realtime/interactive-component/component-spec-content.js.map +1 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-channel.d.ts +183 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-channel.d.ts.map +1 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-channel.js +761 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-channel.js.map +1 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-config.d.ts +25 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-config.d.ts.map +1 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-config.js +57 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-config.js.map +1 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-host.component.d.ts +40 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-host.component.d.ts.map +1 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-host.component.js +97 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-host.component.js.map +1 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-types.d.ts +144 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-types.d.ts.map +1 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-types.js +57 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-types.js.map +1 -0
- package/dist/lib/components/realtime/interactive-component/react-component-handle.d.ts +36 -0
- package/dist/lib/components/realtime/interactive-component/react-component-handle.d.ts.map +1 -0
- package/dist/lib/components/realtime/interactive-component/react-component-handle.js +55 -0
- package/dist/lib/components/realtime/interactive-component/react-component-handle.js.map +1 -0
- package/dist/lib/components/realtime/interactive-component/realtime-interactive-component-surface.component.d.ts +55 -0
- package/dist/lib/components/realtime/interactive-component/realtime-interactive-component-surface.component.d.ts.map +1 -0
- package/dist/lib/components/realtime/interactive-component/realtime-interactive-component-surface.component.js +210 -0
- package/dist/lib/components/realtime/interactive-component/realtime-interactive-component-surface.component.js.map +1 -0
- package/dist/lib/components/realtime/interactive-component/run-view-component-artifact-source.d.ts +32 -0
- package/dist/lib/components/realtime/interactive-component/run-view-component-artifact-source.d.ts.map +1 -0
- package/dist/lib/components/realtime/interactive-component/run-view-component-artifact-source.js +90 -0
- package/dist/lib/components/realtime/interactive-component/run-view-component-artifact-source.js.map +1 -0
- package/dist/lib/components/realtime/media/media-channel.d.ts +7 -0
- package/dist/lib/components/realtime/media/media-channel.d.ts.map +1 -1
- package/dist/lib/components/realtime/media/media-channel.js +28 -1
- package/dist/lib/components/realtime/media/media-channel.js.map +1 -1
- package/dist/lib/components/realtime/realtime-agent-banner.component.d.ts +8 -1
- package/dist/lib/components/realtime/realtime-agent-banner.component.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-agent-banner.component.js +89 -71
- package/dist/lib/components/realtime/realtime-agent-banner.component.js.map +1 -1
- package/dist/lib/components/realtime/realtime-agent-orb.component.d.ts +21 -0
- package/dist/lib/components/realtime/realtime-agent-orb.component.d.ts.map +1 -0
- package/dist/lib/components/realtime/realtime-agent-orb.component.js +49 -0
- package/dist/lib/components/realtime/realtime-agent-orb.component.js.map +1 -0
- package/dist/lib/components/realtime/realtime-agent-picker.component.d.ts +44 -11
- package/dist/lib/components/realtime/realtime-agent-picker.component.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-agent-picker.component.js +162 -50
- package/dist/lib/components/realtime/realtime-agent-picker.component.js.map +1 -1
- package/dist/lib/components/realtime/realtime-audio-visuals.d.ts +8 -2
- package/dist/lib/components/realtime/realtime-audio-visuals.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-audio-visuals.js +14 -18
- package/dist/lib/components/realtime/realtime-audio-visuals.js.map +1 -1
- package/dist/lib/components/realtime/realtime-composer.component.d.ts +42 -2
- package/dist/lib/components/realtime/realtime-composer.component.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-composer.component.js +137 -102
- package/dist/lib/components/realtime/realtime-composer.component.js.map +1 -1
- package/dist/lib/components/realtime/realtime-perception-chip.component.d.ts +71 -0
- package/dist/lib/components/realtime/realtime-perception-chip.component.d.ts.map +1 -0
- package/dist/lib/components/realtime/realtime-perception-chip.component.js +221 -0
- package/dist/lib/components/realtime/realtime-perception-chip.component.js.map +1 -0
- package/dist/lib/components/realtime/realtime-session-overlay.component.d.ts +264 -22
- package/dist/lib/components/realtime/realtime-session-overlay.component.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-session-overlay.component.js +851 -135
- package/dist/lib/components/realtime/realtime-session-overlay.component.js.map +1 -1
- package/dist/lib/components/realtime/realtime-surface-placement-prefs.d.ts +14 -0
- package/dist/lib/components/realtime/realtime-surface-placement-prefs.d.ts.map +1 -0
- package/dist/lib/components/realtime/realtime-surface-placement-prefs.js +14 -0
- package/dist/lib/components/realtime/realtime-surface-placement-prefs.js.map +1 -0
- package/dist/lib/components/realtime/realtime-surface-stage.model.d.ts +74 -0
- package/dist/lib/components/realtime/realtime-surface-stage.model.d.ts.map +1 -0
- package/dist/lib/components/realtime/realtime-surface-stage.model.js +171 -0
- package/dist/lib/components/realtime/realtime-surface-stage.model.js.map +1 -0
- package/dist/lib/components/realtime/realtime-surface-tabs.component.d.ts +71 -13
- package/dist/lib/components/realtime/realtime-surface-tabs.component.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-surface-tabs.component.js +232 -73
- package/dist/lib/components/realtime/realtime-surface-tabs.component.js.map +1 -1
- package/dist/lib/components/realtime/realtime-surface-tabs.model.d.ts +5 -0
- package/dist/lib/components/realtime/realtime-surface-tabs.model.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-surface-tabs.model.js +8 -0
- package/dist/lib/components/realtime/realtime-surface-tabs.model.js.map +1 -1
- package/dist/lib/components/realtime/realtime-ui-config.d.ts +12 -2
- package/dist/lib/components/realtime/realtime-ui-config.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-ui-config.js +5 -1
- package/dist/lib/components/realtime/realtime-ui-config.js.map +1 -1
- package/dist/lib/components/realtime/remote-browser/remote-browser-channel.d.ts +10 -1
- package/dist/lib/components/realtime/remote-browser/remote-browser-channel.d.ts.map +1 -1
- package/dist/lib/components/realtime/remote-browser/remote-browser-channel.js +42 -2
- package/dist/lib/components/realtime/remote-browser/remote-browser-channel.js.map +1 -1
- package/dist/lib/components/realtime/remote-browser/remote-browser-surface.component.d.ts +20 -3
- package/dist/lib/components/realtime/remote-browser/remote-browser-surface.component.d.ts.map +1 -1
- package/dist/lib/components/realtime/remote-browser/remote-browser-surface.component.js +44 -10
- package/dist/lib/components/realtime/remote-browser/remote-browser-surface.component.js.map +1 -1
- package/dist/lib/components/realtime/whiteboard/whiteboard-channel.d.ts +28 -44
- package/dist/lib/components/realtime/whiteboard/whiteboard-channel.d.ts.map +1 -1
- package/dist/lib/components/realtime/whiteboard/whiteboard-channel.js +76 -162
- package/dist/lib/components/realtime/whiteboard/whiteboard-channel.js.map +1 -1
- package/dist/lib/components/search/search-panel.component.d.ts +2 -0
- package/dist/lib/components/search/search-panel.component.d.ts.map +1 -1
- package/dist/lib/components/search/search-panel.component.js +25 -12
- package/dist/lib/components/search/search-panel.component.js.map +1 -1
- package/dist/lib/components/workspace/conversation-workspace.component.d.ts +22 -31
- package/dist/lib/components/workspace/conversation-workspace.component.d.ts.map +1 -1
- package/dist/lib/components/workspace/conversation-workspace.component.js +50 -63
- package/dist/lib/components/workspace/conversation-workspace.component.js.map +1 -1
- package/dist/lib/conversations.module.d.ts +30 -29
- package/dist/lib/conversations.module.d.ts.map +1 -1
- package/dist/lib/conversations.module.js +27 -5
- package/dist/lib/conversations.module.js.map +1 -1
- package/dist/lib/events/chat-events.d.ts +25 -0
- package/dist/lib/events/chat-events.d.ts.map +1 -1
- package/dist/lib/events/chat-events.js +36 -0
- package/dist/lib/events/chat-events.js.map +1 -1
- package/dist/lib/models/agent-turn.model.d.ts +5 -0
- package/dist/lib/models/agent-turn.model.d.ts.map +1 -1
- package/dist/lib/models/agent-turn.model.js.map +1 -1
- package/dist/lib/services/agent-state.service.d.ts +34 -8
- package/dist/lib/services/agent-state.service.d.ts.map +1 -1
- package/dist/lib/services/agent-state.service.js +82 -29
- package/dist/lib/services/agent-state.service.js.map +1 -1
- package/dist/lib/services/artifact-state.service.d.ts +0 -9
- package/dist/lib/services/artifact-state.service.d.ts.map +1 -1
- package/dist/lib/services/artifact-state.service.js +1 -32
- package/dist/lib/services/artifact-state.service.js.map +1 -1
- package/dist/lib/services/browser-realtime-media-host.d.ts +12 -0
- package/dist/lib/services/browser-realtime-media-host.d.ts.map +1 -1
- package/dist/lib/services/browser-realtime-media-host.js +19 -0
- package/dist/lib/services/browser-realtime-media-host.js.map +1 -1
- package/dist/lib/services/browser-recording-unload-guard.d.ts +30 -0
- package/dist/lib/services/browser-recording-unload-guard.d.ts.map +1 -0
- package/dist/lib/services/browser-recording-unload-guard.js +43 -0
- package/dist/lib/services/browser-recording-unload-guard.js.map +1 -0
- package/dist/lib/services/conversation-agent.service.d.ts +35 -11
- package/dist/lib/services/conversation-agent.service.d.ts.map +1 -1
- package/dist/lib/services/conversation-agent.service.js +65 -20
- package/dist/lib/services/conversation-agent.service.js.map +1 -1
- package/dist/lib/services/conversation-detail-window.store.d.ts +22 -4
- package/dist/lib/services/conversation-detail-window.store.d.ts.map +1 -1
- package/dist/lib/services/conversation-detail-window.store.js +50 -9
- package/dist/lib/services/conversation-detail-window.store.js.map +1 -1
- package/dist/lib/services/conversation-naming.d.ts +72 -22
- package/dist/lib/services/conversation-naming.d.ts.map +1 -1
- package/dist/lib/services/conversation-naming.js +84 -10
- package/dist/lib/services/conversation-naming.js.map +1 -1
- package/dist/lib/services/data-cache.service.d.ts +13 -5
- package/dist/lib/services/data-cache.service.d.ts.map +1 -1
- package/dist/lib/services/data-cache.service.js +39 -19
- package/dist/lib/services/data-cache.service.js.map +1 -1
- package/dist/lib/services/export.service.d.ts +26 -9
- package/dist/lib/services/export.service.d.ts.map +1 -1
- package/dist/lib/services/export.service.js +61 -18
- package/dist/lib/services/export.service.js.map +1 -1
- package/dist/lib/services/realtime-audio-recorder.d.ts +33 -5
- package/dist/lib/services/realtime-audio-recorder.d.ts.map +1 -1
- package/dist/lib/services/realtime-audio-recorder.js +71 -11
- package/dist/lib/services/realtime-audio-recorder.js.map +1 -1
- package/dist/lib/services/realtime-pairing.d.ts +10 -5
- package/dist/lib/services/realtime-pairing.d.ts.map +1 -1
- package/dist/lib/services/realtime-pairing.js +15 -6
- package/dist/lib/services/realtime-pairing.js.map +1 -1
- package/dist/lib/services/realtime-session.service.d.ts +3 -2
- package/dist/lib/services/realtime-session.service.d.ts.map +1 -1
- package/dist/lib/services/realtime-session.service.js +7 -2
- package/dist/lib/services/realtime-session.service.js.map +1 -1
- package/dist/lib/services/search.service.d.ts +7 -2
- package/dist/lib/services/search.service.d.ts.map +1 -1
- package/dist/lib/services/search.service.js +13 -4
- package/dist/lib/services/search.service.js.map +1 -1
- package/dist/lib/util/frame-zone.d.ts +10 -0
- package/dist/lib/util/frame-zone.d.ts.map +1 -0
- package/dist/lib/util/frame-zone.js +10 -0
- package/dist/lib/util/frame-zone.js.map +1 -0
- package/dist/lib/utils/conversation-branching.d.ts +4 -0
- package/dist/lib/utils/conversation-branching.d.ts.map +1 -0
- package/dist/lib/utils/conversation-branching.js +5 -0
- package/dist/lib/utils/conversation-branching.js.map +1 -0
- package/dist/lib/utils/conversation-forks.d.ts +315 -0
- package/dist/lib/utils/conversation-forks.d.ts.map +1 -0
- package/dist/lib/utils/conversation-forks.js +456 -0
- package/dist/lib/utils/conversation-forks.js.map +1 -0
- package/dist/public-api.d.ts +23 -1
- package/dist/public-api.d.ts.map +1 -1
- package/dist/public-api.js +30 -1
- package/dist/public-api.js.map +1 -1
- package/package.json +37 -32
- package/dist/lib/components/thread/thread-panel.component.d.ts +0 -126
- package/dist/lib/components/thread/thread-panel.component.d.ts.map +0 -1
- package/dist/lib/components/thread/thread-panel.component.js +0 -440
- package/dist/lib/components/thread/thread-panel.component.js.map +0 -1
|
@@ -1,35 +1,56 @@
|
|
|
1
1
|
import { OnDestroy, OnInit } from '@angular/core';
|
|
2
|
+
import type { MediaPlacement } from '@memberjunction/ai-realtime-client/media';
|
|
2
3
|
import { BaseRealtimeChannelClient } from '@memberjunction/realtime-runtime';
|
|
3
4
|
import * as i0 from "@angular/core";
|
|
4
5
|
/**
|
|
5
|
-
* Generic
|
|
6
|
-
*
|
|
6
|
+
* Generic host for an interactive channel's surface on the call overlay's stage. Given the per-session channel
|
|
7
|
+
* {@link Plugin}, it:
|
|
7
8
|
*
|
|
8
9
|
* 1. dynamically creates the plugin's surface component
|
|
9
10
|
* ({@link BaseRealtimeChannelClient.GetSurfaceComponent}) into its own view container;
|
|
10
11
|
* 2. immediately hands the created instance to
|
|
11
12
|
* {@link BaseRealtimeChannelClient.BindSurface} — synchronously, BEFORE the surface's
|
|
12
13
|
* first change detection, so inputs the plugin sets are visible in its `ngOnInit`;
|
|
13
|
-
* 3.
|
|
14
|
-
* (
|
|
15
|
-
*
|
|
14
|
+
* 3. tells the plugin whether the surface is on screen
|
|
15
|
+
* ({@link BaseRealtimeChannelClient.OnSurfaceVisibilityChange}) and where it is placed
|
|
16
|
+
* ({@link BaseRealtimeChannelClient.OnSurfacePlacementChange}) right after binding and whenever
|
|
17
|
+
* {@link Visible} or {@link Placement} changes;
|
|
18
|
+
* 4. notifies {@link BaseRealtimeChannelClient.UnbindSurface} when the pane is destroyed
|
|
19
|
+
* (the channel left the session / the overlay was torn down) or handed another plugin,
|
|
20
|
+
* flipping the plugin back into its no-surface tool-execution mode.
|
|
16
21
|
*
|
|
17
22
|
* This is how channel surfaces render with ZERO channel-specific wiring in the overlay:
|
|
18
23
|
* the host never knows the surface component's type or API — the plugin wires its own
|
|
19
24
|
* inputs/outputs in `BindSurface`.
|
|
20
25
|
*
|
|
21
26
|
* The created component is inserted as a SIBLING of this host element (standard
|
|
22
|
-
* `ViewContainerRef` semantics), so it participates directly in
|
|
27
|
+
* `ViewContainerRef` semantics), so it participates directly in its container's layout;
|
|
23
28
|
* the host element itself renders nothing (`display: none`).
|
|
24
29
|
*/
|
|
25
30
|
export declare class RealtimeChannelPaneComponent implements OnInit, OnDestroy {
|
|
26
|
-
/** The per-session channel plugin whose surface this pane hosts. */
|
|
27
|
-
Plugin: BaseRealtimeChannelClient;
|
|
28
31
|
private viewContainer;
|
|
29
32
|
private surfaceRef;
|
|
33
|
+
private plugin;
|
|
34
|
+
private initialized;
|
|
35
|
+
private visible;
|
|
36
|
+
private placement;
|
|
37
|
+
/**
|
|
38
|
+
* The per-session channel plugin whose surface this pane hosts. Handing the pane another plugin (the same channel
|
|
39
|
+
* in a new session) releases the old plugin's surface and creates the new one's.
|
|
40
|
+
*/
|
|
41
|
+
set Plugin(value: BaseRealtimeChannelClient);
|
|
42
|
+
get Plugin(): BaseRealtimeChannelClient;
|
|
43
|
+
/** Whether the surface is on screen. The plugin hears of every change while its surface is bound. */
|
|
44
|
+
set Visible(value: boolean);
|
|
45
|
+
get Visible(): boolean;
|
|
46
|
+
/** Where the surface is placed. The plugin hears of every move while its surface is bound. */
|
|
47
|
+
set Placement(value: MediaPlacement);
|
|
48
|
+
get Placement(): MediaPlacement;
|
|
30
49
|
ngOnInit(): void;
|
|
31
50
|
ngOnDestroy(): void;
|
|
51
|
+
private createSurface;
|
|
52
|
+
private releaseSurface;
|
|
32
53
|
static ɵfac: i0.ɵɵFactoryDeclaration<RealtimeChannelPaneComponent, never>;
|
|
33
|
-
static ɵcmp: i0.ɵɵComponentDeclaration<RealtimeChannelPaneComponent, "mj-realtime-channel-pane", never, { "Plugin": { "alias": "Plugin"; "required": true; }; }, {}, never, never, true, never>;
|
|
54
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<RealtimeChannelPaneComponent, "mj-realtime-channel-pane", never, { "Plugin": { "alias": "Plugin"; "required": true; }; "Visible": { "alias": "Visible"; "required": false; }; "Placement": { "alias": "Placement"; "required": false; }; }, {}, never, never, true, never>;
|
|
34
55
|
}
|
|
35
56
|
//# sourceMappingURL=realtime-channel-pane.component.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"realtime-channel-pane.component.d.ts","sourceRoot":"","sources":["../../../../../src/lib/components/realtime/channels/realtime-channel-pane.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkC,SAAS,EAAE,MAAM,EAAkC,MAAM,eAAe,CAAC;AAClH,OAAO,EAAE,yBAAyB,EAAE,MAAM,kCAAkC,CAAC;;AAE7E
|
|
1
|
+
{"version":3,"file":"realtime-channel-pane.component.d.ts","sourceRoot":"","sources":["../../../../../src/lib/components/realtime/channels/realtime-channel-pane.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkC,SAAS,EAAE,MAAM,EAAkC,MAAM,eAAe,CAAC;AAClH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0CAA0C,CAAC;AAC/E,OAAO,EAAE,yBAAyB,EAAE,MAAM,kCAAkC,CAAC;;AAE7E;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,qBAMa,4BAA6B,YAAW,MAAM,EAAE,SAAS;IACpE,OAAO,CAAC,aAAa,CAA4B;IACjD,OAAO,CAAC,UAAU,CAAqC;IACvD,OAAO,CAAC,MAAM,CAA6B;IAC3C,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,OAAO,CAAQ;IACvB,OAAO,CAAC,SAAS,CAAyB;IAE1C;;;OAGG;IACH,IACI,MAAM,CAAC,KAAK,EAAE,yBAAyB,EAW1C;IACD,IAAI,MAAM,IAAI,yBAAyB,CAEtC;IAED,qGAAqG;IACrG,IACI,OAAO,CAAC,KAAK,EAAE,OAAO,EAQzB;IACD,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,8FAA8F;IAC9F,IACI,SAAS,CAAC,KAAK,EAAE,cAAc,EAQlC;IACD,IAAI,SAAS,IAAI,cAAc,CAE9B;IAED,QAAQ,IAAI,IAAI;IAKhB,WAAW,IAAI,IAAI;IAInB,OAAO,CAAC,aAAa;IAmBrB,OAAO,CAAC,cAAc;yCAvFX,4BAA4B;2CAA5B,4BAA4B;CA4FxC"}
|
|
@@ -1,35 +1,93 @@
|
|
|
1
1
|
import { Component, Input, ViewContainerRef, inject } from '@angular/core';
|
|
2
2
|
import * as i0 from "@angular/core";
|
|
3
3
|
/**
|
|
4
|
-
* Generic
|
|
5
|
-
*
|
|
4
|
+
* Generic host for an interactive channel's surface on the call overlay's stage. Given the per-session channel
|
|
5
|
+
* {@link Plugin}, it:
|
|
6
6
|
*
|
|
7
7
|
* 1. dynamically creates the plugin's surface component
|
|
8
8
|
* ({@link BaseRealtimeChannelClient.GetSurfaceComponent}) into its own view container;
|
|
9
9
|
* 2. immediately hands the created instance to
|
|
10
10
|
* {@link BaseRealtimeChannelClient.BindSurface} — synchronously, BEFORE the surface's
|
|
11
11
|
* first change detection, so inputs the plugin sets are visible in its `ngOnInit`;
|
|
12
|
-
* 3.
|
|
13
|
-
* (
|
|
14
|
-
*
|
|
12
|
+
* 3. tells the plugin whether the surface is on screen
|
|
13
|
+
* ({@link BaseRealtimeChannelClient.OnSurfaceVisibilityChange}) and where it is placed
|
|
14
|
+
* ({@link BaseRealtimeChannelClient.OnSurfacePlacementChange}) right after binding and whenever
|
|
15
|
+
* {@link Visible} or {@link Placement} changes;
|
|
16
|
+
* 4. notifies {@link BaseRealtimeChannelClient.UnbindSurface} when the pane is destroyed
|
|
17
|
+
* (the channel left the session / the overlay was torn down) or handed another plugin,
|
|
18
|
+
* flipping the plugin back into its no-surface tool-execution mode.
|
|
15
19
|
*
|
|
16
20
|
* This is how channel surfaces render with ZERO channel-specific wiring in the overlay:
|
|
17
21
|
* the host never knows the surface component's type or API — the plugin wires its own
|
|
18
22
|
* inputs/outputs in `BindSurface`.
|
|
19
23
|
*
|
|
20
24
|
* The created component is inserted as a SIBLING of this host element (standard
|
|
21
|
-
* `ViewContainerRef` semantics), so it participates directly in
|
|
25
|
+
* `ViewContainerRef` semantics), so it participates directly in its container's layout;
|
|
22
26
|
* the host element itself renders nothing (`display: none`).
|
|
23
27
|
*/
|
|
24
28
|
export class RealtimeChannelPaneComponent {
|
|
25
|
-
/** The per-session channel plugin whose surface this pane hosts. */
|
|
26
|
-
Plugin;
|
|
27
29
|
viewContainer = inject(ViewContainerRef);
|
|
28
30
|
surfaceRef = null;
|
|
31
|
+
plugin;
|
|
32
|
+
initialized = false;
|
|
33
|
+
visible = true;
|
|
34
|
+
placement = 'tab';
|
|
35
|
+
/**
|
|
36
|
+
* The per-session channel plugin whose surface this pane hosts. Handing the pane another plugin (the same channel
|
|
37
|
+
* in a new session) releases the old plugin's surface and creates the new one's.
|
|
38
|
+
*/
|
|
39
|
+
set Plugin(value) {
|
|
40
|
+
if (value === this.plugin) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
if (this.initialized) {
|
|
44
|
+
this.releaseSurface();
|
|
45
|
+
}
|
|
46
|
+
this.plugin = value;
|
|
47
|
+
if (this.initialized) {
|
|
48
|
+
this.createSurface();
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
get Plugin() {
|
|
52
|
+
return this.plugin;
|
|
53
|
+
}
|
|
54
|
+
/** Whether the surface is on screen. The plugin hears of every change while its surface is bound. */
|
|
55
|
+
set Visible(value) {
|
|
56
|
+
if (value === this.visible) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
this.visible = value;
|
|
60
|
+
if (this.surfaceRef) {
|
|
61
|
+
this.plugin.OnSurfaceVisibilityChange(value);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
get Visible() {
|
|
65
|
+
return this.visible;
|
|
66
|
+
}
|
|
67
|
+
/** Where the surface is placed. The plugin hears of every move while its surface is bound. */
|
|
68
|
+
set Placement(value) {
|
|
69
|
+
if (value === this.placement) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
this.placement = value;
|
|
73
|
+
if (this.surfaceRef) {
|
|
74
|
+
this.plugin.OnSurfacePlacementChange(value);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
get Placement() {
|
|
78
|
+
return this.placement;
|
|
79
|
+
}
|
|
29
80
|
ngOnInit() {
|
|
81
|
+
this.initialized = true;
|
|
82
|
+
this.createSurface();
|
|
83
|
+
}
|
|
84
|
+
ngOnDestroy() {
|
|
85
|
+
this.releaseSurface();
|
|
86
|
+
}
|
|
87
|
+
createSurface() {
|
|
30
88
|
// Server-only channels have no surface (GetSurfaceComponent === null). The overlay should not
|
|
31
89
|
// register a pane for them, but guard here too so a stray registration never crashes the panel.
|
|
32
|
-
const surface = this.
|
|
90
|
+
const surface = this.plugin.GetSurfaceComponent();
|
|
33
91
|
if (!surface) {
|
|
34
92
|
return;
|
|
35
93
|
}
|
|
@@ -39,16 +97,18 @@ export class RealtimeChannelPaneComponent {
|
|
|
39
97
|
this.surfaceRef = this.viewContainer.createComponent(surface);
|
|
40
98
|
// Bind BEFORE the created component's first change detection — inputs the plugin sets
|
|
41
99
|
// here are in place when the surface's ngOnInit runs.
|
|
42
|
-
this.
|
|
100
|
+
this.plugin.BindSurface(this.surfaceRef.instance);
|
|
101
|
+
this.plugin.OnSurfaceVisibilityChange(this.visible);
|
|
102
|
+
this.plugin.OnSurfacePlacementChange(this.placement);
|
|
43
103
|
this.surfaceRef.changeDetectorRef.markForCheck();
|
|
44
104
|
}
|
|
45
|
-
|
|
46
|
-
this.
|
|
105
|
+
releaseSurface() {
|
|
106
|
+
this.plugin.UnbindSurface();
|
|
47
107
|
this.surfaceRef?.destroy();
|
|
48
108
|
this.surfaceRef = null;
|
|
49
109
|
}
|
|
50
110
|
static ɵfac = function RealtimeChannelPaneComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || RealtimeChannelPaneComponent)(); };
|
|
51
|
-
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: RealtimeChannelPaneComponent, selectors: [["mj-realtime-channel-pane"]], inputs: { Plugin: "Plugin" }, decls: 0, vars: 0, template: function RealtimeChannelPaneComponent_Template(rf, ctx) { }, styles: ["[_nghost-%COMP%] { display: none; }"] });
|
|
111
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: RealtimeChannelPaneComponent, selectors: [["mj-realtime-channel-pane"]], inputs: { Plugin: "Plugin", Visible: "Visible", Placement: "Placement" }, decls: 0, vars: 0, template: function RealtimeChannelPaneComponent_Template(rf, ctx) { }, styles: ["[_nghost-%COMP%] { display: none; }"] });
|
|
52
112
|
}
|
|
53
113
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(RealtimeChannelPaneComponent, [{
|
|
54
114
|
type: Component,
|
|
@@ -56,6 +116,10 @@ export class RealtimeChannelPaneComponent {
|
|
|
56
116
|
}], null, { Plugin: [{
|
|
57
117
|
type: Input,
|
|
58
118
|
args: [{ required: true }]
|
|
119
|
+
}], Visible: [{
|
|
120
|
+
type: Input
|
|
121
|
+
}], Placement: [{
|
|
122
|
+
type: Input
|
|
59
123
|
}] }); })();
|
|
60
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(RealtimeChannelPaneComponent, { className: "RealtimeChannelPaneComponent", filePath: "src/lib/components/realtime/channels/realtime-channel-pane.component.ts", lineNumber:
|
|
124
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(RealtimeChannelPaneComponent, { className: "RealtimeChannelPaneComponent", filePath: "src/lib/components/realtime/channels/realtime-channel-pane.component.ts", lineNumber: 36 }); })();
|
|
61
125
|
//# sourceMappingURL=realtime-channel-pane.component.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"realtime-channel-pane.component.js","sourceRoot":"","sources":["../../../../../src/lib/components/realtime/channels/realtime-channel-pane.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAgB,KAAK,EAA2B,gBAAgB,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;;
|
|
1
|
+
{"version":3,"file":"realtime-channel-pane.component.js","sourceRoot":"","sources":["../../../../../src/lib/components/realtime/channels/realtime-channel-pane.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component, ComponentRef, Input, OnDestroy, OnInit, Type, ViewContainerRef, inject } from '@angular/core';\nimport type { MediaPlacement } from '@memberjunction/ai-realtime-client/media';\nimport { BaseRealtimeChannelClient } from '@memberjunction/realtime-runtime';\n\n/**\n * Generic host for an interactive channel's surface on the call overlay's stage. Given the per-session channel\n * {@link Plugin}, it:\n *\n * 1. dynamically creates the plugin's surface component\n * ({@link BaseRealtimeChannelClient.GetSurfaceComponent}) into its own view container;\n * 2. immediately hands the created instance to\n * {@link BaseRealtimeChannelClient.BindSurface} — synchronously, BEFORE the surface's\n * first change detection, so inputs the plugin sets are visible in its `ngOnInit`;\n * 3. tells the plugin whether the surface is on screen\n * ({@link BaseRealtimeChannelClient.OnSurfaceVisibilityChange}) and where it is placed\n * ({@link BaseRealtimeChannelClient.OnSurfacePlacementChange}) right after binding and whenever\n * {@link Visible} or {@link Placement} changes;\n * 4. notifies {@link BaseRealtimeChannelClient.UnbindSurface} when the pane is destroyed\n * (the channel left the session / the overlay was torn down) or handed another plugin,\n * flipping the plugin back into its no-surface tool-execution mode.\n *\n * This is how channel surfaces render with ZERO channel-specific wiring in the overlay:\n * the host never knows the surface component's type or API — the plugin wires its own\n * inputs/outputs in `BindSurface`.\n *\n * The created component is inserted as a SIBLING of this host element (standard\n * `ViewContainerRef` semantics), so it participates directly in its container's layout;\n * the host element itself renders nothing (`display: none`).\n */\n@Component({\n standalone: true,\n selector: 'mj-realtime-channel-pane',\n template: '',\n styles: [':host { display: none; }']\n})\nexport class RealtimeChannelPaneComponent implements OnInit, OnDestroy {\n private viewContainer = inject(ViewContainerRef);\n private surfaceRef: ComponentRef<object> | null = null;\n private plugin!: BaseRealtimeChannelClient;\n private initialized = false;\n private visible = true;\n private placement: MediaPlacement = 'tab';\n\n /**\n * The per-session channel plugin whose surface this pane hosts. Handing the pane another plugin (the same channel\n * in a new session) releases the old plugin's surface and creates the new one's.\n */\n @Input({ required: true })\n set Plugin(value: BaseRealtimeChannelClient) {\n if (value === this.plugin) {\n return;\n }\n if (this.initialized) {\n this.releaseSurface();\n }\n this.plugin = value;\n if (this.initialized) {\n this.createSurface();\n }\n }\n get Plugin(): BaseRealtimeChannelClient {\n return this.plugin;\n }\n\n /** Whether the surface is on screen. The plugin hears of every change while its surface is bound. */\n @Input()\n set Visible(value: boolean) {\n if (value === this.visible) {\n return;\n }\n this.visible = value;\n if (this.surfaceRef) {\n this.plugin.OnSurfaceVisibilityChange(value);\n }\n }\n get Visible(): boolean {\n return this.visible;\n }\n\n /** Where the surface is placed. The plugin hears of every move while its surface is bound. */\n @Input()\n set Placement(value: MediaPlacement) {\n if (value === this.placement) {\n return;\n }\n this.placement = value;\n if (this.surfaceRef) {\n this.plugin.OnSurfacePlacementChange(value);\n }\n }\n get Placement(): MediaPlacement {\n return this.placement;\n }\n\n ngOnInit(): void {\n this.initialized = true;\n this.createSurface();\n }\n\n ngOnDestroy(): void {\n this.releaseSurface();\n }\n\n private createSurface(): void {\n // Server-only channels have no surface (GetSurfaceComponent === null). The overlay should not\n // register a pane for them, but guard here too so a stray registration never crashes the panel.\n const surface = this.plugin.GetSurfaceComponent();\n if (!surface) {\n return;\n }\n // The runtime carries the surface as an opaque component class — it has no business knowing\n // what a component is in any given framework. This is the single point that does, so the\n // Angular narrowing belongs here rather than as a structural claim in the shared contract.\n this.surfaceRef = this.viewContainer.createComponent(surface as Type<object>);\n // Bind BEFORE the created component's first change detection — inputs the plugin sets\n // here are in place when the surface's ngOnInit runs.\n this.plugin.BindSurface(this.surfaceRef.instance);\n this.plugin.OnSurfaceVisibilityChange(this.visible);\n this.plugin.OnSurfacePlacementChange(this.placement);\n this.surfaceRef.changeDetectorRef.markForCheck();\n }\n\n private releaseSurface(): void {\n this.plugin.UnbindSurface();\n this.surfaceRef?.destroy();\n this.surfaceRef = null;\n }\n}\n"]}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { Type } from '@angular/core';
|
|
2
|
+
import type { JSONObject } from '@memberjunction/ai';
|
|
3
|
+
import { type RealtimeChannelActor, type RealtimeChannelDescriptor } from '@memberjunction/ai-core-plus';
|
|
4
|
+
import { GraphQLDataProvider, GraphQLRealtimeSessionClient } from '@memberjunction/graphql-dataprovider';
|
|
5
|
+
import { BaseRealtimeChannelClient, type ChannelOnboardingDetails, type RealtimeChannelVerbResult } from '@memberjunction/realtime-runtime';
|
|
6
|
+
import { IdentityVerificationModel } from './identity-verification-model';
|
|
7
|
+
import { IdentityVerificationSurfaceComponent } from './identity-verification-surface.component';
|
|
8
|
+
/** The registry key (`MJ: AI Agent Channels` → `ClientPluginClass`) and the channel's name. */
|
|
9
|
+
export declare const IDENTITY_VERIFICATION_CHANNEL_NAME = "IdentityVerification";
|
|
10
|
+
/** The verbs, by name — the vocabulary the agent, the surface and the tests share. */
|
|
11
|
+
export declare const IDENTITY_VERIFICATION_VERBS: {
|
|
12
|
+
readonly Fill: "fill";
|
|
13
|
+
readonly Confirm: "confirm";
|
|
14
|
+
readonly Submit: "submit";
|
|
15
|
+
readonly Resend: "resend";
|
|
16
|
+
readonly EnterCode: "enter_code";
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* IDENTITY VERIFICATION as a generic, opt-in interactive channel: the way an agent helps a person —
|
|
20
|
+
* typically an anonymous visitor — prove they control an email address without leaving the call.
|
|
21
|
+
*
|
|
22
|
+
* What it models: three nouns (name, email, status), five verbs. The agent can `fill` what it heard, but
|
|
23
|
+
* only the USER can `confirm` it (enforced twice: `InvokableBy: 'user'`, which the runtime checks before
|
|
24
|
+
* dispatch, and again inside the verb). `submit` then asks the server to email a one-time code and link;
|
|
25
|
+
* `enter_code` hands the typed code back; `resend` asks for a fresh one. The channel never decides whether
|
|
26
|
+
* a person IS verified — the server's `identity.verified` session event does, and the channel follows it.
|
|
27
|
+
*
|
|
28
|
+
* The server half is a thin plugin that validates nothing beyond scope (see `IdentityVerificationChannelServer`);
|
|
29
|
+
* the real checks — domain policy, rate limits, hashing, expiry — live in the verification service.
|
|
30
|
+
*
|
|
31
|
+
* Opt in per agent or app with `channels.config.IdentityVerification`; open it from the host with
|
|
32
|
+
* `openChannel('IdentityVerification', { name, email })` or let the agent open it on demand.
|
|
33
|
+
*/
|
|
34
|
+
export declare class IdentityVerificationChannel extends BaseRealtimeChannelClient<IdentityVerificationSurfaceComponent> {
|
|
35
|
+
/** The state machine. Public so the surface and tests share the one instance. */
|
|
36
|
+
readonly Model: IdentityVerificationModel;
|
|
37
|
+
private surface;
|
|
38
|
+
private eventsSub;
|
|
39
|
+
get ChannelName(): string;
|
|
40
|
+
get TabTitle(): string;
|
|
41
|
+
get TabIcon(): string;
|
|
42
|
+
/** Clock hook for tests. */
|
|
43
|
+
protected now(): number;
|
|
44
|
+
GetDescriptor(): RealtimeChannelDescriptor;
|
|
45
|
+
GetState(): JSONObject;
|
|
46
|
+
GetSurfaceComponent(): Type<IdentityVerificationSurfaceComponent>;
|
|
47
|
+
GetOnboardingDetails(): ChannelOnboardingDetails;
|
|
48
|
+
protected OnInitialize(): void;
|
|
49
|
+
protected OnOpen(inputs: JSONObject): void;
|
|
50
|
+
BindSurface(instance: IdentityVerificationSurfaceComponent): void;
|
|
51
|
+
UnbindSurface(): void;
|
|
52
|
+
/** Runs one verb. The runtime already validated the call against the descriptor; confirm is guarded again here. */
|
|
53
|
+
ApplyVerb(verb: string, args: JSONObject, actor: RealtimeChannelActor, _instanceId?: string): Promise<RealtimeChannelVerbResult>;
|
|
54
|
+
Dispose(): void;
|
|
55
|
+
/** Records every change (events immediately, one coalesced note to the model) and completes on verification. */
|
|
56
|
+
private onModelChange;
|
|
57
|
+
/**
|
|
58
|
+
* The server calls, riding the session's own provider and live session id. `null` when the session has
|
|
59
|
+
* no GraphQL provider — the channel then refuses to send rather than pretending.
|
|
60
|
+
*/
|
|
61
|
+
private createService;
|
|
62
|
+
private withClient;
|
|
63
|
+
/** Builds the transport; protected so a test (or a host on another transport) can substitute it. */
|
|
64
|
+
protected createVerificationClient(provider: GraphQLDataProvider): GraphQLRealtimeSessionClient;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Tree-shaking prevention: the channel is resolved through the ClassFactory by the registry row's
|
|
68
|
+
* `ClientPluginClass` key, so this static call keeps its `@RegisterClass` side effect alive.
|
|
69
|
+
*/
|
|
70
|
+
export declare function LoadIdentityVerificationChannel(): void;
|
|
71
|
+
//# sourceMappingURL=identity-verification-channel.d.ts.map
|
package/dist/lib/components/realtime/identity-verification/identity-verification-channel.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"identity-verification-channel.d.ts","sourceRoot":"","sources":["../../../../../src/lib/components/realtime/identity-verification/identity-verification-channel.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAG1C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAGL,KAAK,oBAAoB,EACzB,KAAK,yBAAyB,EAC/B,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,mBAAmB,EAAE,4BAA4B,EAAE,MAAM,sCAAsC,CAAC;AACzG,OAAO,EACL,yBAAyB,EACzB,KAAK,wBAAwB,EAC7B,KAAK,yBAAyB,EAC/B,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAAE,yBAAyB,EAAqE,MAAM,+BAA+B,CAAC;AAC7I,OAAO,EAAE,oCAAoC,EAAE,MAAM,2CAA2C,CAAC;AAEjG,+FAA+F;AAC/F,eAAO,MAAM,kCAAkC,yBAAyB,CAAC;AAEzE,sFAAsF;AACtF,eAAO,MAAM,2BAA2B;;;;;;CAM9B,CAAC;AAIX;;;;;;;;;;;;;;;GAeG;AACH,qBACa,2BAA4B,SAAQ,yBAAyB,CAAC,oCAAoC,CAAC;IAC9G,iFAAiF;IACjF,SAAgB,KAAK,EAAE,yBAAyB,CAAyE;IAEzH,OAAO,CAAC,OAAO,CAAqD;IACpE,OAAO,CAAC,SAAS,CAA6B;IAE9C,IAAW,WAAW,IAAI,MAAM,CAE/B;IAED,IAAoB,QAAQ,IAAI,MAAM,CAErC;IAED,IAAoB,OAAO,IAAI,MAAM,CAEpC;IAED,4BAA4B;IAC5B,SAAS,CAAC,GAAG,IAAI,MAAM;IAIP,aAAa,IAAI,yBAAyB;IAoG1C,QAAQ,IAAI,UAAU;IAItB,mBAAmB,IAAI,IAAI,CAAC,oCAAoC,CAAC;IAIjE,oBAAoB,IAAI,wBAAwB;cAU7C,YAAY,IAAI,IAAI;cASpB,MAAM,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI;IAI5C,WAAW,CAAC,QAAQ,EAAE,oCAAoC,GAAG,IAAI;IAOxD,aAAa,IAAI,IAAI;IAIrC,mHAAmH;IAC7F,SAAS,CAC7B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,UAAU,EAChB,KAAK,EAAE,oBAAoB,EAC3B,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,yBAAyB,CAAC;IAiBrB,OAAO,IAAI,IAAI;IAQ/B,gHAAgH;IAChH,OAAO,CAAC,aAAa;IAWrB;;;OAGG;IACH,OAAO,CAAC,aAAa;YAOP,UAAU;IAWxB,oGAAoG;IACpG,SAAS,CAAC,wBAAwB,CAAC,QAAQ,EAAE,mBAAmB,GAAG,4BAA4B;CAGhG;AASD;;;GAGG;AACH,wBAAgB,+BAA+B,IAAI,IAAI,CAEtD"}
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { RegisterClass } from '@memberjunction/global';
|
|
8
|
+
import { IsIdentityVerifiedEventPayload, REALTIME_CHANNEL_CONTRACT_VERSION } from '@memberjunction/ai-core-plus';
|
|
9
|
+
import { GraphQLRealtimeSessionClient } from '@memberjunction/graphql-dataprovider';
|
|
10
|
+
import { BaseRealtimeChannelClient } from '@memberjunction/realtime-runtime';
|
|
11
|
+
import { IdentityVerificationModel } from './identity-verification-model';
|
|
12
|
+
import { IdentityVerificationSurfaceComponent } from './identity-verification-surface.component';
|
|
13
|
+
/** The registry key (`MJ: AI Agent Channels` → `ClientPluginClass`) and the channel's name. */
|
|
14
|
+
export const IDENTITY_VERIFICATION_CHANNEL_NAME = 'IdentityVerification';
|
|
15
|
+
/** The verbs, by name — the vocabulary the agent, the surface and the tests share. */
|
|
16
|
+
export const IDENTITY_VERIFICATION_VERBS = {
|
|
17
|
+
Fill: 'fill',
|
|
18
|
+
Confirm: 'confirm',
|
|
19
|
+
Submit: 'submit',
|
|
20
|
+
Resend: 'resend',
|
|
21
|
+
EnterCode: 'enter_code'
|
|
22
|
+
};
|
|
23
|
+
const FIELD_PARAM = { type: 'string', enum: ['name', 'email'], description: 'Which detail: "name" or "email".' };
|
|
24
|
+
/**
|
|
25
|
+
* IDENTITY VERIFICATION as a generic, opt-in interactive channel: the way an agent helps a person —
|
|
26
|
+
* typically an anonymous visitor — prove they control an email address without leaving the call.
|
|
27
|
+
*
|
|
28
|
+
* What it models: three nouns (name, email, status), five verbs. The agent can `fill` what it heard, but
|
|
29
|
+
* only the USER can `confirm` it (enforced twice: `InvokableBy: 'user'`, which the runtime checks before
|
|
30
|
+
* dispatch, and again inside the verb). `submit` then asks the server to email a one-time code and link;
|
|
31
|
+
* `enter_code` hands the typed code back; `resend` asks for a fresh one. The channel never decides whether
|
|
32
|
+
* a person IS verified — the server's `identity.verified` session event does, and the channel follows it.
|
|
33
|
+
*
|
|
34
|
+
* The server half is a thin plugin that validates nothing beyond scope (see `IdentityVerificationChannelServer`);
|
|
35
|
+
* the real checks — domain policy, rate limits, hashing, expiry — live in the verification service.
|
|
36
|
+
*
|
|
37
|
+
* Opt in per agent or app with `channels.config.IdentityVerification`; open it from the host with
|
|
38
|
+
* `openChannel('IdentityVerification', { name, email })` or let the agent open it on demand.
|
|
39
|
+
*/
|
|
40
|
+
let IdentityVerificationChannel = class IdentityVerificationChannel extends BaseRealtimeChannelClient {
|
|
41
|
+
/** The state machine. Public so the surface and tests share the one instance. */
|
|
42
|
+
Model = new IdentityVerificationModel(this.createService(), () => this.now());
|
|
43
|
+
surface = null;
|
|
44
|
+
eventsSub = null;
|
|
45
|
+
get ChannelName() {
|
|
46
|
+
return IDENTITY_VERIFICATION_CHANNEL_NAME;
|
|
47
|
+
}
|
|
48
|
+
get TabTitle() {
|
|
49
|
+
return 'Verify your identity';
|
|
50
|
+
}
|
|
51
|
+
get TabIcon() {
|
|
52
|
+
return 'fa-solid fa-user-shield';
|
|
53
|
+
}
|
|
54
|
+
/** Clock hook for tests. */
|
|
55
|
+
now() {
|
|
56
|
+
return Date.now();
|
|
57
|
+
}
|
|
58
|
+
GetDescriptor() {
|
|
59
|
+
return {
|
|
60
|
+
Key: this.ChannelName,
|
|
61
|
+
Version: REALTIME_CHANNEL_CONTRACT_VERSION,
|
|
62
|
+
DisplayName: 'Identity verification',
|
|
63
|
+
OwningPackage: '@memberjunction/ng-conversations',
|
|
64
|
+
Instructions: 'Helps the user prove who they are by email, during this call. Ask for their name and email, `fill` what you hear, ' +
|
|
65
|
+
'then ask the user to check the form and press Confirm — only they can confirm, so never claim you did. ' +
|
|
66
|
+
'Once both are confirmed, `submit` emails them a code and a link. They can type the code in themselves, or you can ' +
|
|
67
|
+
'`enter_code` if they read it to you; or they can open the link, which completes it on its own. ' +
|
|
68
|
+
'Never repeat a code or an email back unprompted. Check `status`: it becomes "verified" when the server confirms it — ' +
|
|
69
|
+
'do not treat the person as verified before that.',
|
|
70
|
+
Nouns: [
|
|
71
|
+
{ Name: 'name', Description: "The person's name, as entered.", Schema: { type: 'string' } },
|
|
72
|
+
{ Name: 'email', Description: "The person's email address, as entered.", Schema: { type: 'string' } },
|
|
73
|
+
{
|
|
74
|
+
Name: 'status',
|
|
75
|
+
Description: 'Where verification stands: collecting (getting details, or ready to send), sending, code_sent, verifying, verified.',
|
|
76
|
+
Schema: { type: 'string', enum: ['collecting', 'sending', 'code_sent', 'verifying', 'verified'] }
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
Name: 'confirmed',
|
|
80
|
+
Description: 'Whether the USER has confirmed each detail. Only confirmed details can be sent.',
|
|
81
|
+
Schema: { type: 'object', properties: { name: { type: 'boolean' }, email: { type: 'boolean' } } }
|
|
82
|
+
},
|
|
83
|
+
{ Name: 'problem', Description: 'The latest problem in plain words, or empty.', Schema: { type: 'string' } }
|
|
84
|
+
],
|
|
85
|
+
Verbs: [
|
|
86
|
+
{
|
|
87
|
+
Name: IDENTITY_VERIFICATION_VERBS.Fill,
|
|
88
|
+
Description: 'Set the name or the email. What you fill is shown to the user marked as suggested until they confirm it.',
|
|
89
|
+
ParametersSchema: {
|
|
90
|
+
type: 'object',
|
|
91
|
+
properties: { field: FIELD_PARAM, value: { type: 'string', description: 'The value to set.', maxLength: 200 } },
|
|
92
|
+
required: ['field', 'value'],
|
|
93
|
+
additionalProperties: false
|
|
94
|
+
},
|
|
95
|
+
InvokableBy: 'both'
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
Name: IDENTITY_VERIFICATION_VERBS.Confirm,
|
|
99
|
+
Description: 'Confirm the details shown. Only the user can do this.',
|
|
100
|
+
ParametersSchema: { type: 'object', properties: { field: FIELD_PARAM }, additionalProperties: false },
|
|
101
|
+
InvokableBy: 'user'
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
Name: IDENTITY_VERIFICATION_VERBS.Submit,
|
|
105
|
+
Description: 'Email the user a one-time code and link. Needs both details filled and confirmed by the user.',
|
|
106
|
+
ParametersSchema: { type: 'object', additionalProperties: false },
|
|
107
|
+
InvokableBy: 'both',
|
|
108
|
+
Preconditions: ['name and email are filled', 'the user has confirmed both']
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
Name: IDENTITY_VERIFICATION_VERBS.Resend,
|
|
112
|
+
Description: 'Email a fresh code to the same address. Only after a code was sent, and subject to a short wait.',
|
|
113
|
+
ParametersSchema: { type: 'object', additionalProperties: false },
|
|
114
|
+
InvokableBy: 'both',
|
|
115
|
+
Preconditions: ['a code was already sent']
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
Name: IDENTITY_VERIFICATION_VERBS.EnterCode,
|
|
119
|
+
Description: 'Submit the code the user received (digits as they gave them).',
|
|
120
|
+
ParametersSchema: {
|
|
121
|
+
type: 'object',
|
|
122
|
+
properties: { code: { type: 'string', description: 'The code from the email.', maxLength: 16 } },
|
|
123
|
+
required: ['code'],
|
|
124
|
+
additionalProperties: false
|
|
125
|
+
},
|
|
126
|
+
InvokableBy: 'both',
|
|
127
|
+
Preconditions: ['a code was sent']
|
|
128
|
+
}
|
|
129
|
+
],
|
|
130
|
+
Inputs: {
|
|
131
|
+
type: 'object',
|
|
132
|
+
properties: {
|
|
133
|
+
name: { type: 'string', description: 'A name the host already knows, to pre-fill (the user still confirms it).' },
|
|
134
|
+
email: { type: 'string', description: 'An email the host already knows, to pre-fill (the user still confirms it).' }
|
|
135
|
+
},
|
|
136
|
+
additionalProperties: false
|
|
137
|
+
},
|
|
138
|
+
Events: [
|
|
139
|
+
{ Name: 'field_filled', Description: 'A detail was filled in, by the agent or the user.' },
|
|
140
|
+
{ Name: 'confirmed', Description: 'The user confirmed one or both details.' },
|
|
141
|
+
{ Name: 'code_sent', Description: 'The server emailed a code and link.' },
|
|
142
|
+
{ Name: 'code_entered', Description: 'A code was submitted for checking (the code itself is never included).' },
|
|
143
|
+
{ Name: 'verified', Description: 'The server confirmed the person is verified.' },
|
|
144
|
+
{ Name: 'error', Description: 'A step failed; the payload carries the error code and the stage.' }
|
|
145
|
+
],
|
|
146
|
+
Output: {
|
|
147
|
+
type: 'object',
|
|
148
|
+
properties: { verified: { type: 'boolean' }, email: { type: 'string' }, name: { type: 'string' } },
|
|
149
|
+
required: ['verified', 'email', 'name']
|
|
150
|
+
},
|
|
151
|
+
DisplayPolicy: 'on-demand',
|
|
152
|
+
DefaultAvailability: 'opt-in',
|
|
153
|
+
MaxExposure: 'state'
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
GetState() {
|
|
157
|
+
return this.Model.ToState();
|
|
158
|
+
}
|
|
159
|
+
GetSurfaceComponent() {
|
|
160
|
+
return IdentityVerificationSurfaceComponent;
|
|
161
|
+
}
|
|
162
|
+
GetOnboardingDetails() {
|
|
163
|
+
return {
|
|
164
|
+
Heading: 'Verify your identity',
|
|
165
|
+
Description: 'Confirm your name and email so we can recognise you. We email you a code and a link; either one completes it.',
|
|
166
|
+
Tips: ['Check the details the assistant filled in, then press Confirm.', 'You can type the code here, or just open the link in the email.'],
|
|
167
|
+
IconClass: 'fa-solid fa-user-shield'
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
OnInitialize() {
|
|
171
|
+
this.Model.OnChange((change) => this.onModelChange(change));
|
|
172
|
+
this.eventsSub = this.Context?.SessionEvents$?.subscribe((event) => {
|
|
173
|
+
if (event.Type === 'identity.verified' && IsIdentityVerifiedEventPayload(event.Payload)) {
|
|
174
|
+
this.Model.MarkVerified(event.Payload);
|
|
175
|
+
}
|
|
176
|
+
}) ?? null;
|
|
177
|
+
}
|
|
178
|
+
OnOpen(inputs) {
|
|
179
|
+
this.Model.Seed(inputs);
|
|
180
|
+
}
|
|
181
|
+
BindSurface(instance) {
|
|
182
|
+
this.surface = instance;
|
|
183
|
+
instance.Model = this.Model;
|
|
184
|
+
instance.AgentName = this.Context?.AgentName ?? 'The assistant';
|
|
185
|
+
instance.Dispatch = (verb, args) => this.ApplyVerb(verb, args, 'user');
|
|
186
|
+
}
|
|
187
|
+
UnbindSurface() {
|
|
188
|
+
this.surface = null;
|
|
189
|
+
}
|
|
190
|
+
/** Runs one verb. The runtime already validated the call against the descriptor; confirm is guarded again here. */
|
|
191
|
+
async ApplyVerb(verb, args, actor, _instanceId) {
|
|
192
|
+
switch (verb) {
|
|
193
|
+
case IDENTITY_VERIFICATION_VERBS.Fill:
|
|
194
|
+
return this.Model.Fill(args, actor);
|
|
195
|
+
case IDENTITY_VERIFICATION_VERBS.Confirm:
|
|
196
|
+
return this.Model.Confirm(args, actor);
|
|
197
|
+
case IDENTITY_VERIFICATION_VERBS.Submit:
|
|
198
|
+
return this.Model.Submit();
|
|
199
|
+
case IDENTITY_VERIFICATION_VERBS.Resend:
|
|
200
|
+
return this.Model.Resend();
|
|
201
|
+
case IDENTITY_VERIFICATION_VERBS.EnterCode:
|
|
202
|
+
return this.Model.EnterCode(args);
|
|
203
|
+
default:
|
|
204
|
+
return { Success: false, ErrorCode: 'unknown_verb', Error: `${this.ChannelName} has no verb "${verb}".` };
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
Dispose() {
|
|
208
|
+
this.eventsSub?.unsubscribe();
|
|
209
|
+
this.eventsSub = null;
|
|
210
|
+
this.Model.OnChange(null);
|
|
211
|
+
this.surface = null;
|
|
212
|
+
super.Dispose();
|
|
213
|
+
}
|
|
214
|
+
/** Records every change (events immediately, one coalesced note to the model) and completes on verification. */
|
|
215
|
+
onModelChange(change) {
|
|
216
|
+
if (change.Event) {
|
|
217
|
+
this.EmitChannelEvent(change.Event.Name, change.Event.Payload);
|
|
218
|
+
}
|
|
219
|
+
this.RecordChange({ Author: change.Author });
|
|
220
|
+
if (change.Event?.Name === 'verified') {
|
|
221
|
+
const view = this.Model.View;
|
|
222
|
+
this.Complete({ verified: true, email: view.Email.Value, name: view.Name.Value });
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* The server calls, riding the session's own provider and live session id. `null` when the session has
|
|
227
|
+
* no GraphQL provider — the channel then refuses to send rather than pretending.
|
|
228
|
+
*/
|
|
229
|
+
createService() {
|
|
230
|
+
return {
|
|
231
|
+
Request: (input) => this.withClient((client, id) => client.RequestVerification({ AgentSessionID: id, Name: input.Name, Email: input.Email })),
|
|
232
|
+
SubmitCode: (code) => this.withClient((client, id) => client.SubmitVerificationCode({ AgentSessionID: id, Code: code }))
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
async withClient(run) {
|
|
236
|
+
const provider = this.Context?.Provider;
|
|
237
|
+
const sessionId = this.Context?.AgentSessionID ?? null;
|
|
238
|
+
if (!provider || !sessionId) {
|
|
239
|
+
return { Success: false, VerificationState: 'unverified', ErrorCode: 'session_not_found' };
|
|
240
|
+
}
|
|
241
|
+
return run(this.createVerificationClient(provider), sessionId);
|
|
242
|
+
}
|
|
243
|
+
/** Builds the transport; protected so a test (or a host on another transport) can substitute it. */
|
|
244
|
+
createVerificationClient(provider) {
|
|
245
|
+
return new GraphQLRealtimeSessionClient(provider);
|
|
246
|
+
}
|
|
247
|
+
};
|
|
248
|
+
IdentityVerificationChannel = __decorate([
|
|
249
|
+
RegisterClass(BaseRealtimeChannelClient, 'IdentityVerificationChannel')
|
|
250
|
+
], IdentityVerificationChannel);
|
|
251
|
+
export { IdentityVerificationChannel };
|
|
252
|
+
/**
|
|
253
|
+
* Tree-shaking prevention: the channel is resolved through the ClassFactory by the registry row's
|
|
254
|
+
* `ClientPluginClass` key, so this static call keeps its `@RegisterClass` side effect alive.
|
|
255
|
+
*/
|
|
256
|
+
export function LoadIdentityVerificationChannel() {
|
|
257
|
+
// intentional no-op — the import side effect performs the registration
|
|
258
|
+
}
|
|
259
|
+
//# sourceMappingURL=identity-verification-channel.js.map
|
package/dist/lib/components/realtime/identity-verification/identity-verification-channel.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"identity-verification-channel.js","sourceRoot":"","sources":["../../../../../src/lib/components/realtime/identity-verification/identity-verification-channel.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Type } from '@angular/core';\nimport type { Subscription } from 'rxjs';\nimport { RegisterClass } from '@memberjunction/global';\nimport type { JSONObject } from '@memberjunction/ai';\nimport {\n IsIdentityVerifiedEventPayload,\n REALTIME_CHANNEL_CONTRACT_VERSION,\n type RealtimeChannelActor,\n type RealtimeChannelDescriptor\n} from '@memberjunction/ai-core-plus';\nimport { GraphQLDataProvider, GraphQLRealtimeSessionClient } from '@memberjunction/graphql-dataprovider';\nimport {\n BaseRealtimeChannelClient,\n type ChannelOnboardingDetails,\n type RealtimeChannelVerbResult\n} from '@memberjunction/realtime-runtime';\nimport { IdentityVerificationModel, type IdentityVerificationChange, type IdentityVerificationService } from './identity-verification-model';\nimport { IdentityVerificationSurfaceComponent } from './identity-verification-surface.component';\n\n/** The registry key (`MJ: AI Agent Channels` → `ClientPluginClass`) and the channel's name. */\nexport const IDENTITY_VERIFICATION_CHANNEL_NAME = 'IdentityVerification';\n\n/** The verbs, by name — the vocabulary the agent, the surface and the tests share. */\nexport const IDENTITY_VERIFICATION_VERBS = {\n Fill: 'fill',\n Confirm: 'confirm',\n Submit: 'submit',\n Resend: 'resend',\n EnterCode: 'enter_code'\n} as const;\n\nconst FIELD_PARAM = { type: 'string', enum: ['name', 'email'], description: 'Which detail: \"name\" or \"email\".' };\n\n/**\n * IDENTITY VERIFICATION as a generic, opt-in interactive channel: the way an agent helps a person —\n * typically an anonymous visitor — prove they control an email address without leaving the call.\n *\n * What it models: three nouns (name, email, status), five verbs. The agent can `fill` what it heard, but\n * only the USER can `confirm` it (enforced twice: `InvokableBy: 'user'`, which the runtime checks before\n * dispatch, and again inside the verb). `submit` then asks the server to email a one-time code and link;\n * `enter_code` hands the typed code back; `resend` asks for a fresh one. The channel never decides whether\n * a person IS verified — the server's `identity.verified` session event does, and the channel follows it.\n *\n * The server half is a thin plugin that validates nothing beyond scope (see `IdentityVerificationChannelServer`);\n * the real checks — domain policy, rate limits, hashing, expiry — live in the verification service.\n *\n * Opt in per agent or app with `channels.config.IdentityVerification`; open it from the host with\n * `openChannel('IdentityVerification', { name, email })` or let the agent open it on demand.\n */\n@RegisterClass(BaseRealtimeChannelClient, 'IdentityVerificationChannel')\nexport class IdentityVerificationChannel extends BaseRealtimeChannelClient<IdentityVerificationSurfaceComponent> {\n /** The state machine. Public so the surface and tests share the one instance. */\n public readonly Model: IdentityVerificationModel = new IdentityVerificationModel(this.createService(), () => this.now());\n\n private surface: IdentityVerificationSurfaceComponent | null = null;\n private eventsSub: Subscription | null = null;\n\n public get ChannelName(): string {\n return IDENTITY_VERIFICATION_CHANNEL_NAME;\n }\n\n public override get TabTitle(): string {\n return 'Verify your identity';\n }\n\n public override get TabIcon(): string {\n return 'fa-solid fa-user-shield';\n }\n\n /** Clock hook for tests. */\n protected now(): number {\n return Date.now();\n }\n\n public override GetDescriptor(): RealtimeChannelDescriptor {\n return {\n Key: this.ChannelName,\n Version: REALTIME_CHANNEL_CONTRACT_VERSION,\n DisplayName: 'Identity verification',\n OwningPackage: '@memberjunction/ng-conversations',\n Instructions:\n 'Helps the user prove who they are by email, during this call. Ask for their name and email, `fill` what you hear, ' +\n 'then ask the user to check the form and press Confirm — only they can confirm, so never claim you did. ' +\n 'Once both are confirmed, `submit` emails them a code and a link. They can type the code in themselves, or you can ' +\n '`enter_code` if they read it to you; or they can open the link, which completes it on its own. ' +\n 'Never repeat a code or an email back unprompted. Check `status`: it becomes \"verified\" when the server confirms it — ' +\n 'do not treat the person as verified before that.',\n Nouns: [\n { Name: 'name', Description: \"The person's name, as entered.\", Schema: { type: 'string' } },\n { Name: 'email', Description: \"The person's email address, as entered.\", Schema: { type: 'string' } },\n {\n Name: 'status',\n Description: 'Where verification stands: collecting (getting details, or ready to send), sending, code_sent, verifying, verified.',\n Schema: { type: 'string', enum: ['collecting', 'sending', 'code_sent', 'verifying', 'verified'] }\n },\n {\n Name: 'confirmed',\n Description: 'Whether the USER has confirmed each detail. Only confirmed details can be sent.',\n Schema: { type: 'object', properties: { name: { type: 'boolean' }, email: { type: 'boolean' } } }\n },\n { Name: 'problem', Description: 'The latest problem in plain words, or empty.', Schema: { type: 'string' } }\n ],\n Verbs: [\n {\n Name: IDENTITY_VERIFICATION_VERBS.Fill,\n Description: 'Set the name or the email. What you fill is shown to the user marked as suggested until they confirm it.',\n ParametersSchema: {\n type: 'object',\n properties: { field: FIELD_PARAM, value: { type: 'string', description: 'The value to set.', maxLength: 200 } },\n required: ['field', 'value'],\n additionalProperties: false\n },\n InvokableBy: 'both'\n },\n {\n Name: IDENTITY_VERIFICATION_VERBS.Confirm,\n Description: 'Confirm the details shown. Only the user can do this.',\n ParametersSchema: { type: 'object', properties: { field: FIELD_PARAM }, additionalProperties: false },\n InvokableBy: 'user'\n },\n {\n Name: IDENTITY_VERIFICATION_VERBS.Submit,\n Description: 'Email the user a one-time code and link. Needs both details filled and confirmed by the user.',\n ParametersSchema: { type: 'object', additionalProperties: false },\n InvokableBy: 'both',\n Preconditions: ['name and email are filled', 'the user has confirmed both']\n },\n {\n Name: IDENTITY_VERIFICATION_VERBS.Resend,\n Description: 'Email a fresh code to the same address. Only after a code was sent, and subject to a short wait.',\n ParametersSchema: { type: 'object', additionalProperties: false },\n InvokableBy: 'both',\n Preconditions: ['a code was already sent']\n },\n {\n Name: IDENTITY_VERIFICATION_VERBS.EnterCode,\n Description: 'Submit the code the user received (digits as they gave them).',\n ParametersSchema: {\n type: 'object',\n properties: { code: { type: 'string', description: 'The code from the email.', maxLength: 16 } },\n required: ['code'],\n additionalProperties: false\n },\n InvokableBy: 'both',\n Preconditions: ['a code was sent']\n }\n ],\n Inputs: {\n type: 'object',\n properties: {\n name: { type: 'string', description: 'A name the host already knows, to pre-fill (the user still confirms it).' },\n email: { type: 'string', description: 'An email the host already knows, to pre-fill (the user still confirms it).' }\n },\n additionalProperties: false\n },\n Events: [\n { Name: 'field_filled', Description: 'A detail was filled in, by the agent or the user.' },\n { Name: 'confirmed', Description: 'The user confirmed one or both details.' },\n { Name: 'code_sent', Description: 'The server emailed a code and link.' },\n { Name: 'code_entered', Description: 'A code was submitted for checking (the code itself is never included).' },\n { Name: 'verified', Description: 'The server confirmed the person is verified.' },\n { Name: 'error', Description: 'A step failed; the payload carries the error code and the stage.' }\n ],\n Output: {\n type: 'object',\n properties: { verified: { type: 'boolean' }, email: { type: 'string' }, name: { type: 'string' } },\n required: ['verified', 'email', 'name']\n },\n DisplayPolicy: 'on-demand',\n DefaultAvailability: 'opt-in',\n MaxExposure: 'state'\n };\n }\n\n public override GetState(): JSONObject {\n return this.Model.ToState();\n }\n\n public override GetSurfaceComponent(): Type<IdentityVerificationSurfaceComponent> {\n return IdentityVerificationSurfaceComponent;\n }\n\n public override GetOnboardingDetails(): ChannelOnboardingDetails {\n return {\n Heading: 'Verify your identity',\n Description:\n 'Confirm your name and email so we can recognise you. We email you a code and a link; either one completes it.',\n Tips: ['Check the details the assistant filled in, then press Confirm.', 'You can type the code here, or just open the link in the email.'],\n IconClass: 'fa-solid fa-user-shield'\n };\n }\n\n protected override OnInitialize(): void {\n this.Model.OnChange((change) => this.onModelChange(change));\n this.eventsSub = this.Context?.SessionEvents$?.subscribe((event) => {\n if (event.Type === 'identity.verified' && IsIdentityVerifiedEventPayload(event.Payload)) {\n this.Model.MarkVerified(event.Payload);\n }\n }) ?? null;\n }\n\n protected override OnOpen(inputs: JSONObject): void {\n this.Model.Seed(inputs);\n }\n\n public BindSurface(instance: IdentityVerificationSurfaceComponent): void {\n this.surface = instance;\n instance.Model = this.Model;\n instance.AgentName = this.Context?.AgentName ?? 'The assistant';\n instance.Dispatch = (verb, args) => this.ApplyVerb(verb, args, 'user');\n }\n\n public override UnbindSurface(): void {\n this.surface = null;\n }\n\n /** Runs one verb. The runtime already validated the call against the descriptor; confirm is guarded again here. */\n public override async ApplyVerb(\n verb: string,\n args: JSONObject,\n actor: RealtimeChannelActor,\n _instanceId?: string\n ): Promise<RealtimeChannelVerbResult> {\n switch (verb) {\n case IDENTITY_VERIFICATION_VERBS.Fill:\n return this.Model.Fill(args, actor);\n case IDENTITY_VERIFICATION_VERBS.Confirm:\n return this.Model.Confirm(args, actor);\n case IDENTITY_VERIFICATION_VERBS.Submit:\n return this.Model.Submit();\n case IDENTITY_VERIFICATION_VERBS.Resend:\n return this.Model.Resend();\n case IDENTITY_VERIFICATION_VERBS.EnterCode:\n return this.Model.EnterCode(args);\n default:\n return { Success: false, ErrorCode: 'unknown_verb', Error: `${this.ChannelName} has no verb \"${verb}\".` };\n }\n }\n\n public override Dispose(): void {\n this.eventsSub?.unsubscribe();\n this.eventsSub = null;\n this.Model.OnChange(null);\n this.surface = null;\n super.Dispose();\n }\n\n /** Records every change (events immediately, one coalesced note to the model) and completes on verification. */\n private onModelChange(change: IdentityVerificationChange): void {\n if (change.Event) {\n this.EmitChannelEvent(change.Event.Name, change.Event.Payload);\n }\n this.RecordChange({ Author: change.Author });\n if (change.Event?.Name === 'verified') {\n const view = this.Model.View;\n this.Complete({ verified: true, email: view.Email.Value, name: view.Name.Value });\n }\n }\n\n /**\n * The server calls, riding the session's own provider and live session id. `null` when the session has\n * no GraphQL provider — the channel then refuses to send rather than pretending.\n */\n private createService(): IdentityVerificationService | null {\n return {\n Request: (input) => this.withClient((client, id) => client.RequestVerification({ AgentSessionID: id, Name: input.Name, Email: input.Email })),\n SubmitCode: (code) => this.withClient((client, id) => client.SubmitVerificationCode({ AgentSessionID: id, Code: code }))\n };\n }\n\n private async withClient<T extends { Success: boolean }>(\n run: (client: GraphQLRealtimeSessionClient, agentSessionId: string) => Promise<T>\n ): Promise<T | NoSessionResult> {\n const provider = this.Context?.Provider as GraphQLDataProvider | null | undefined;\n const sessionId = this.Context?.AgentSessionID ?? null;\n if (!provider || !sessionId) {\n return { Success: false, VerificationState: 'unverified', ErrorCode: 'session_not_found' };\n }\n return run(this.createVerificationClient(provider), sessionId);\n }\n\n /** Builds the transport; protected so a test (or a host on another transport) can substitute it. */\n protected createVerificationClient(provider: GraphQLDataProvider): GraphQLRealtimeSessionClient {\n return new GraphQLRealtimeSessionClient(provider);\n }\n}\n\n/** The shape returned when there is no live session to talk to (mirrors the client's own failure results). */\ninterface NoSessionResult {\n Success: false;\n VerificationState: 'unverified';\n ErrorCode: 'session_not_found';\n}\n\n/**\n * Tree-shaking prevention: the channel is resolved through the ClassFactory by the registry row's\n * `ClientPluginClass` key, so this static call keeps its `@RegisterClass` side effect alive.\n */\nexport function LoadIdentityVerificationChannel(): void {\n // intentional no-op — the import side effect performs the registration\n}\n"]}
|