@memberjunction/ng-conversations 6.2.0-edge.3 → 6.2.0-edge.5
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 +33 -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-agent-picker.component.d.ts +1 -1
- package/dist/lib/components/conversation/conversation-agent-picker.component.js +3 -3
- package/dist/lib/components/conversation/conversation-agent-picker.component.js.map +1 -1
- package/dist/lib/components/conversation/conversation-chat-area.component.d.ts +651 -53
- package/dist/lib/components/conversation/conversation-chat-area.component.d.ts.map +1 -1
- package/dist/lib/components/conversation/conversation-chat-area.component.js +3002 -661
- 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 +96 -11
- package/dist/lib/components/message/message-input.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-input.component.js +253 -112
- package/dist/lib/components/message/message-input.component.js.map +1 -1
- package/dist/lib/components/message/message-item.component.d.ts +304 -16
- package/dist/lib/components/message/message-item.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-item.component.js +2029 -363
- package/dist/lib/components/message/message-item.component.js.map +1 -1
- package/dist/lib/components/message/message-list.component.d.ts +101 -22
- package/dist/lib/components/message/message-list.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-list.component.js +326 -55
- 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/sidebar/routines-section.component.js +1 -1
- package/dist/lib/components/sidebar/routines-section.component.js.map +1 -1
- package/dist/lib/components/task/tasks-full-view.component.d.ts +152 -31
- package/dist/lib/components/task/tasks-full-view.component.d.ts.map +1 -1
- package/dist/lib/components/task/tasks-full-view.component.js +2227 -214
- package/dist/lib/components/task/tasks-full-view.component.js.map +1 -1
- package/dist/lib/components/tasks/tasks-dropdown.component.js +4 -4
- package/dist/lib/components/tasks/tasks-dropdown.component.js.map +1 -1
- package/dist/lib/components/workspace/conversation-workspace.component.d.ts +33 -32
- package/dist/lib/components/workspace/conversation-workspace.component.d.ts.map +1 -1
- package/dist/lib/components/workspace/conversation-workspace.component.js +72 -88
- 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 +90 -37
- 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 +19 -7
- package/dist/lib/services/browser-realtime-media-host.d.ts.map +1 -1
- package/dist/lib/services/browser-realtime-media-host.js +21 -72
- package/dist/lib/services/browser-realtime-media-host.js.map +1 -1
- package/dist/lib/services/conversation-agent.service.d.ts +48 -16
- package/dist/lib/services/conversation-agent.service.d.ts.map +1 -1
- package/dist/lib/services/conversation-agent.service.js +110 -35
- 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 +93 -12
- package/dist/lib/services/conversation-naming.js.map +1 -1
- package/dist/lib/services/conversation-tasks-filter.d.ts +15 -0
- package/dist/lib/services/conversation-tasks-filter.d.ts.map +1 -0
- package/dist/lib/services/conversation-tasks-filter.js +69 -0
- package/dist/lib/services/conversation-tasks-filter.js.map +1 -0
- 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 +115 -79
- package/dist/lib/services/realtime-audio-recorder.d.ts.map +1 -1
- package/dist/lib/services/realtime-audio-recorder.js +273 -186
- 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 +31 -2
- package/dist/lib/services/realtime-session.service.d.ts.map +1 -1
- package/dist/lib/services/realtime-session.service.js +34 -2
- package/dist/lib/services/realtime-session.service.js.map +1 -1
- package/dist/lib/services/recording/libopus-wasm-binary.d.ts +3 -0
- package/dist/lib/services/recording/libopus-wasm-binary.d.ts.map +1 -0
- package/dist/lib/services/recording/libopus-wasm-binary.js +489 -0
- package/dist/lib/services/recording/libopus-wasm-binary.js.map +1 -0
- package/dist/lib/services/recording/libopus-worker-source.d.ts +48 -0
- package/dist/lib/services/recording/libopus-worker-source.d.ts.map +1 -0
- package/dist/lib/services/recording/libopus-worker-source.js +170 -0
- package/dist/lib/services/recording/libopus-worker-source.js.map +1 -0
- package/dist/lib/services/recording/linear-resampler.d.ts +45 -0
- package/dist/lib/services/recording/linear-resampler.d.ts.map +1 -0
- package/dist/lib/services/recording/linear-resampler.js +85 -0
- package/dist/lib/services/recording/linear-resampler.js.map +1 -0
- package/dist/lib/services/recording/opus-packet-encoder.d.ts +50 -0
- package/dist/lib/services/recording/opus-packet-encoder.d.ts.map +1 -0
- package/dist/lib/services/recording/opus-packet-encoder.js +41 -0
- package/dist/lib/services/recording/opus-packet-encoder.js.map +1 -0
- package/dist/lib/services/recording/wasm-opus-encoder.d.ts +86 -0
- package/dist/lib/services/recording/wasm-opus-encoder.d.ts.map +1 -0
- package/dist/lib/services/recording/wasm-opus-encoder.js +232 -0
- package/dist/lib/services/recording/wasm-opus-encoder.js.map +1 -0
- package/dist/lib/services/recording/webcodecs-opus-encoder.d.ts +39 -0
- package/dist/lib/services/recording/webcodecs-opus-encoder.d.ts.map +1 -0
- package/dist/lib/services/recording/webcodecs-opus-encoder.js +101 -0
- package/dist/lib/services/recording/webcodecs-opus-encoder.js.map +1 -0
- 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 +16 -20
- package/dist/lib/services/search.service.js.map +1 -1
- 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/lib/utils/distinct-artifacts.d.ts +9 -3
- package/dist/lib/utils/distinct-artifacts.d.ts.map +1 -1
- package/dist/lib/utils/distinct-artifacts.js +24 -5
- package/dist/lib/utils/distinct-artifacts.js.map +1 -1
- 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 -33
- 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
- package/dist/lib/services/realtime-pcm-wav.d.ts +0 -79
- package/dist/lib/services/realtime-pcm-wav.d.ts.map +0 -1
- package/dist/lib/services/realtime-pcm-wav.js +0 -213
- package/dist/lib/services/realtime-pcm-wav.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"export.service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/export.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,0BAA0B,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"export.service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/export.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { Injectable } from '@angular/core';
|
|
2
|
+
import { ConversationEngine } from '@memberjunction/core-entities';
|
|
2
3
|
import { RunView, Metadata } from '@memberjunction/core';
|
|
4
|
+
import { UUIDsEqual } from '@memberjunction/global';
|
|
3
5
|
import * as i0 from "@angular/core";
|
|
4
6
|
/**
|
|
5
7
|
* Tokens captured by the theme auto-snapshot — exactly the custom properties the
|
|
@@ -29,18 +31,26 @@ export class ExportService {
|
|
|
29
31
|
get Provider() {
|
|
30
32
|
return this._provider ?? Metadata.Provider;
|
|
31
33
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
+
/**
|
|
35
|
+
* Exports the messages of one scope of a conversation (Main, or one fork's path) and
|
|
36
|
+
* downloads the file. In a fork the export header names the fork.
|
|
37
|
+
* @throws when the scope belongs to another conversation, or the conversation is not found.
|
|
38
|
+
*/
|
|
39
|
+
async ExportConversation(conversationId, scope, format, currentUser, options = {}) {
|
|
40
|
+
const conversation = await this.loadConversationData(conversationId, scope, currentUser);
|
|
34
41
|
const { content, filename, mimeType } = await this.BuildExportContent(conversation, format, options);
|
|
35
42
|
this.downloadFile(content, filename, mimeType);
|
|
36
43
|
}
|
|
37
|
-
/**
|
|
38
|
-
|
|
39
|
-
|
|
44
|
+
/**
|
|
45
|
+
* @deprecated Use {@link ExportConversation}. Without `scope`, exports Main.
|
|
46
|
+
*/
|
|
47
|
+
async exportConversation(conversationId, format, currentUser, options = {}, scope) {
|
|
48
|
+
const resolved = scope ?? ConversationEngine.TrunkScope(conversationId);
|
|
49
|
+
return this.ExportConversation(conversationId, resolved, format, currentUser, options);
|
|
40
50
|
}
|
|
41
51
|
/**
|
|
42
52
|
* Build the export document for already-loaded conversation data — the
|
|
43
|
-
* download-free seam of {@link
|
|
53
|
+
* download-free seam of {@link ExportConversation}. Async because HTML-format
|
|
44
54
|
* branding may inline a logo. Exposed publicly so hosts (and tests) can build
|
|
45
55
|
* export content without triggering a browser download.
|
|
46
56
|
*/
|
|
@@ -249,7 +259,11 @@ export class ExportService {
|
|
|
249
259
|
return url;
|
|
250
260
|
}
|
|
251
261
|
}
|
|
252
|
-
|
|
262
|
+
/** Loads the conversation and the messages in the scope that no rerun replaced, in Sequence order. */
|
|
263
|
+
async loadConversationData(conversationId, scope, currentUser) {
|
|
264
|
+
if (!UUIDsEqual(scope.ConversationID, conversationId)) {
|
|
265
|
+
throw new Error(`Conversation ${conversationId} cannot be exported with the scope of conversation ${scope.ConversationID}`);
|
|
266
|
+
}
|
|
253
267
|
const rv = RunView.FromMetadataProvider(this.Provider);
|
|
254
268
|
// Load conversation and details in parallel
|
|
255
269
|
const [conversationResult, detailsResult] = await rv.RunViews([
|
|
@@ -260,7 +274,7 @@ export class ExportService {
|
|
|
260
274
|
},
|
|
261
275
|
{
|
|
262
276
|
EntityName: 'MJ: Conversation Details',
|
|
263
|
-
ExtraFilter:
|
|
277
|
+
ExtraFilter: ConversationEngine.LiveRowsFilter(ConversationEngine.ScopeFilter(scope)),
|
|
264
278
|
OrderBy: 'Sequence ASC',
|
|
265
279
|
ResultType: 'entity_object'
|
|
266
280
|
}
|
|
@@ -268,28 +282,44 @@ export class ExportService {
|
|
|
268
282
|
if (!conversationResult.Success || !conversationResult.Results?.length) {
|
|
269
283
|
throw new Error('Conversation not found');
|
|
270
284
|
}
|
|
285
|
+
const details = (detailsResult.Results || []);
|
|
271
286
|
return {
|
|
272
287
|
conversation: conversationResult.Results[0],
|
|
273
|
-
details
|
|
288
|
+
details,
|
|
289
|
+
fork: this.forkLabel(scope, details)
|
|
274
290
|
};
|
|
275
291
|
}
|
|
292
|
+
/** The header name of the scope's fork: its display name; null in Main. */
|
|
293
|
+
forkLabel(scope, details) {
|
|
294
|
+
if (scope.BranchID == null) {
|
|
295
|
+
return null;
|
|
296
|
+
}
|
|
297
|
+
const fork = scope.Branches.find(b => UUIDsEqual(b.ID, scope.BranchID));
|
|
298
|
+
if (!fork) {
|
|
299
|
+
return scope.BranchID;
|
|
300
|
+
}
|
|
301
|
+
const first = [...details]
|
|
302
|
+
.filter(d => UUIDsEqual(d.BranchID ?? null, scope.BranchID))
|
|
303
|
+
.sort((a, b) => a.Sequence - b.Sequence)
|
|
304
|
+
.find(d => ConversationEngine.ForkPlainText(d.Message) != null);
|
|
305
|
+
return ConversationEngine.ForkDisplayName(fork, first?.Message ?? null);
|
|
306
|
+
}
|
|
276
307
|
exportAsJSON(data, options) {
|
|
277
308
|
const exportData = {};
|
|
278
309
|
// Add metadata if requested
|
|
279
|
-
|
|
280
|
-
|
|
310
|
+
const conversationBlock = options.includeMetadata
|
|
311
|
+
? {
|
|
281
312
|
id: data.conversation.ID,
|
|
282
313
|
name: data.conversation.Name,
|
|
283
314
|
description: data.conversation.Description,
|
|
284
315
|
createdAt: data.conversation.__mj_CreatedAt,
|
|
285
316
|
updatedAt: data.conversation.__mj_UpdatedAt
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
name: data.conversation.Name
|
|
291
|
-
};
|
|
317
|
+
}
|
|
318
|
+
: { name: data.conversation.Name };
|
|
319
|
+
if (data.fork) {
|
|
320
|
+
conversationBlock.fork = data.fork;
|
|
292
321
|
}
|
|
322
|
+
exportData.conversation = conversationBlock;
|
|
293
323
|
// Branding block (title / trademark / logo) when the host supplied branding —
|
|
294
324
|
// the data-format analogue of the HTML header + trademark footer.
|
|
295
325
|
const branding = this.buildBrandingBlock(options);
|
|
@@ -331,6 +361,9 @@ export class ExportService {
|
|
|
331
361
|
if (options.includeMetadata) {
|
|
332
362
|
md += `**Created:** ${this.formatDate(data.conversation.__mj_CreatedAt)}\n\n`;
|
|
333
363
|
}
|
|
364
|
+
if (data.fork) {
|
|
365
|
+
md += `**Fork:** ${data.fork}\n\n`;
|
|
366
|
+
}
|
|
334
367
|
md += `---\n\n`;
|
|
335
368
|
if (options.includeMessages) {
|
|
336
369
|
for (const detail of data.details) {
|
|
@@ -378,11 +411,18 @@ export class ExportService {
|
|
|
378
411
|
<body>
|
|
379
412
|
${theme.logoDataUri ? `<img class="brand-logo" src="${this.escapeAttr(theme.logoDataUri)}" alt="" />
|
|
380
413
|
` : ''}<h1>${this.escapeHtml(title)}</h1>`;
|
|
414
|
+
const forkLine = data.fork ? `
|
|
415
|
+
<p>Fork: ${this.escapeHtml(data.fork)}</p>` : '';
|
|
381
416
|
if (options.includeMetadata) {
|
|
382
417
|
html += `
|
|
383
418
|
<div class="meta">
|
|
384
419
|
${data.conversation.Description ? `<p>${this.escapeHtml(data.conversation.Description)}</p>` : ''}
|
|
385
|
-
<p>Created: ${this.formatDate(data.conversation.__mj_CreatedAt)}</p
|
|
420
|
+
<p>Created: ${this.formatDate(data.conversation.__mj_CreatedAt)}</p>${forkLine}
|
|
421
|
+
</div>`;
|
|
422
|
+
}
|
|
423
|
+
else if (forkLine) {
|
|
424
|
+
html += `
|
|
425
|
+
<div class="meta">${forkLine}
|
|
386
426
|
</div>`;
|
|
387
427
|
}
|
|
388
428
|
if (options.includeMessages) {
|
|
@@ -419,6 +459,9 @@ export class ExportService {
|
|
|
419
459
|
if (options.includeMetadata) {
|
|
420
460
|
text += `Created: ${this.formatDate(data.conversation.__mj_CreatedAt)}\n\n`;
|
|
421
461
|
}
|
|
462
|
+
if (data.fork) {
|
|
463
|
+
text += `Fork: ${data.fork}\n\n`;
|
|
464
|
+
}
|
|
422
465
|
text += '-'.repeat(80) + '\n\n';
|
|
423
466
|
if (options.includeMessages) {
|
|
424
467
|
for (const detail of data.details) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"export.service.js","sourceRoot":"","sources":["../../../src/lib/services/export.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { Injectable } from '@angular/core';\nimport { MJConversationEntity, MJConversationDetailEntity } from '@memberjunction/core-entities';\nimport { RunView, UserInfo, Metadata, IMetadataProvider } from '@memberjunction/core';\n\nexport type ExportFormat = 'json' | 'markdown' | 'html' | 'text';\n\n/**\n * Branding applied to exported files, across EVERY format. HTML gets the full\n * treatment (theme colors, an inlined logo, the title, and a trademark footer);\n * JSON/markdown/text carry the title and trademark (markdown also references the\n * logo). Hosts supply this via `mj-conversation-chat-area`'s `exportBranding`\n * input. Color theming (`brandTokens`) is HTML-only — it has no meaning in the\n * data/plain-text formats.\n */\nexport interface ExportBranding {\n /**\n * CSS custom-property snapshot emitted as a `:root{}` block in the exported\n * document, so the export's stylesheet (which reads `var(--mj-…, fallback)`)\n * renders in the app's theme. HTML export only. Keys must be valid\n * custom-property names (`--like-this`). Entries are DROPPED when the key is\n * invalid or the value carries declaration-escape / network-call characters\n * (`<>{};@\\`, `url(`, `expression(`) — plain colors, `var()`, and\n * `color-mix()` pass. When omitted and `ExportOptions.includeTheme` is true,\n * the current theme is auto-snapshotted from `document.documentElement` (see\n * {@link DEFAULT_EXPORT_THEME_TOKENS}).\n */\n brandTokens?: Record<string, string>;\n /**\n * Logo URL. In HTML it is fetched and inlined as a data URI (so the file stays\n * self-contained) and rendered above the title — requires\n * `ExportOptions.includeCSS`, since it needs its stylesheet rule. In markdown it is\n * referenced by URL. JSON carries it as a string; plain text omits it.\n *\n * If the fetch fails, or the response isn't `content-type: image/*`, the raw URL is\n * emitted instead — so the exported file will reach out to that URL when opened.\n * There is no size or timeout guard on the fetch: a very large logo inflates the\n * export.\n */\n logoUrl?: string;\n /** Overrides the exported document's title (defaults to the conversation name). */\n title?: string;\n /**\n * A short trademark / attribution line (e.g. `© 2026 Acme Association ·\n * Powered by Betty`) rendered at the FOOT of the exported document: a styled HTML\n * footer, a markdown/text trailer, and a field in the JSON `branding` block.\n *\n * In HTML it needs its stylesheet rule, so — like the logo — it is emitted only when\n * `ExportOptions.includeCSS` is true. The markdown/text/JSON trailers have no such\n * dependency and always emit.\n *\n * NOT escaped for markdown: a value containing `_`, `]`, `)`, or a newline can break\n * the surrounding markdown. Supply plain text (HTML and JSON are escaped).\n */\n trademark?: string;\n}\n\nexport interface ExportOptions {\n includeMessages?: boolean;\n includeMetadata?: boolean;\n prettyPrint?: boolean;\n includeCSS?: boolean;\n /**\n * Emit the current app theme into the HTML export. When true and\n * `branding.brandTokens` is absent, the {@link DEFAULT_EXPORT_THEME_TOKENS}\n * are auto-snapshotted from the live document at export time. Default false —\n * an unthemed export renders exactly as before (the stylesheet's `var()`\n * fallbacks carry the legacy palette).\n *\n * Gates only the TOKEN auto-snapshot: a supplied `branding`'s `logoUrl`,\n * `title`, and `trademark` apply whenever `branding` is present — in HTML AND\n * in the JSON/markdown/text formats. (The export modal passes `branding`\n * through only while its \"Include branding\" checkbox is on, so in the UI flow\n * everything travels together.)\n */\n includeTheme?: boolean;\n /**\n * Which theme mode the snapshot captures — NOT whichever mode the app happens to be\n * in when the user clicks Export. Defaults to `'light'`: an export taken during a\n * dark session would otherwise bake dark text onto the page's white background and\n * come out unreadable. `'dark'` pairs the dark palette with the dark\n * `--mj-bg-page` the body rule applies, so the file is coherent either way.\n * HTML only — the data formats carry no colors.\n */\n themeMode?: 'light' | 'dark';\n /** Branding (tokens / logo / title) applied to the export — see {@link ExportBranding}. */\n branding?: ExportBranding;\n}\n\n/**\n * Tokens captured by the theme auto-snapshot — exactly the custom properties the\n * HTML export's stylesheet consumes. Hosts wanting more control supply their own\n * map via {@link ExportBranding.brandTokens} instead.\n */\nexport const DEFAULT_EXPORT_THEME_TOKENS: readonly string[] = [\n '--mj-bg-page',\n '--mj-text-primary',\n '--mj-text-secondary',\n '--mj-text-disabled',\n '--mj-border-default',\n '--mj-brand-primary',\n '--mj-brand-accent-subtle',\n '--mj-bg-surface-card',\n '--mj-font-family',\n '--mj-radius-md',\n];\n\n/** Internal: options with defaults applied (branding stays optional). */\ntype ResolvedExportOptions = Required<Omit<ExportOptions, 'branding'>> & Pick<ExportOptions, 'branding'>;\n\n/** Internal: the theme pieces resolved once per HTML export. */\ninterface ResolvedExportTheme {\n /** `<style>:root{…}</style>` block (empty string when no tokens resolved). */\n rootBlock: string;\n /** Inlined logo (data URI, or the raw URL on fetch failure); null = no logo. */\n logoDataUri: string | null;\n /** Document-title override; null = use the conversation name. */\n title: string | null;\n}\n\n@Injectable({\n providedIn: 'root'\n})\nexport class ExportService {\n private _provider: IMetadataProvider | null = null;\n\n /**\n * Set the metadata provider this service should use. When unset, falls back to Metadata.Provider.\n */\n public set Provider(value: IMetadataProvider | null) {\n this._provider = value;\n }\n\n public get Provider(): IMetadataProvider {\n return this._provider ?? Metadata.Provider;\n }\n\n async ExportConversation(\n conversationId: string,\n format: ExportFormat,\n currentUser: UserInfo,\n options: ExportOptions = {}\n ): Promise<void> {\n const conversation = await this.loadConversationData(conversationId, currentUser);\n const { content, filename, mimeType } = await this.BuildExportContent(conversation, format, options);\n this.downloadFile(content, filename, mimeType);\n }\n\n /** @deprecated Use {@link ExportConversation}. */\n async exportConversation(\n conversationId: string,\n format: ExportFormat,\n currentUser: UserInfo,\n options: ExportOptions = {}\n ): Promise<void> {\n return this.ExportConversation(conversationId, format, currentUser, options);\n }\n\n /**\n * Build the export document for already-loaded conversation data — the\n * download-free seam of {@link exportConversation}. Async because HTML-format\n * branding may inline a logo. Exposed publicly so hosts (and tests) can build\n * export content without triggering a browser download.\n */\n public async BuildExportContent(\n data: { conversation: MJConversationEntity; details: MJConversationDetailEntity[] },\n format: ExportFormat,\n options: ExportOptions = {}\n ): Promise<{ content: string; filename: string; mimeType: string }> {\n const exportOptions: ResolvedExportOptions = {\n includeMessages: options.includeMessages ?? true,\n includeMetadata: options.includeMetadata ?? true,\n prettyPrint: options.prettyPrint ?? true,\n includeCSS: options.includeCSS ?? true,\n includeTheme: options.includeTheme ?? false,\n themeMode: options.themeMode ?? 'light',\n branding: options.branding\n };\n const baseName = `conversation-${data.conversation.Name}-${this.getTimestamp()}`;\n\n switch (format) {\n case 'json':\n return { content: this.exportAsJSON(data, exportOptions), filename: `${baseName}.json`, mimeType: 'application/json' };\n case 'markdown':\n return { content: this.exportAsMarkdown(data, exportOptions), filename: `${baseName}.md`, mimeType: 'text/markdown' };\n case 'html':\n return {\n content: this.exportAsHTML(data, exportOptions, await this.resolveTheme(exportOptions)),\n filename: `${baseName}.html`,\n mimeType: 'text/html'\n };\n case 'text':\n return { content: this.exportAsText(data, exportOptions), filename: `${baseName}.txt`, mimeType: 'text/plain' };\n default:\n throw new Error(`Unsupported export format: ${format}`);\n }\n }\n\n /**\n * Snapshot the given theme tokens from the live document. Empty/unset tokens are\n * skipped.\n *\n * `mode` captures a SPECIFIC palette rather than whatever the app is rendering right\n * now. Without it, exporting from a dark session bakes dark text onto the export's\n * white page and the file is unreadable. When the requested mode isn't the active one,\n * `data-theme` is flipped on `documentElement`, read, and restored — all synchronous\n * within one task, so the browser never paints the intermediate state. Omit `mode`\n * to read the live values as-is.\n */\n public SnapshotBrandTokens(\n tokens: readonly string[] = DEFAULT_EXPORT_THEME_TOKENS,\n mode?: 'light' | 'dark'\n ): Record<string, string> {\n const root = document.documentElement;\n const previous = root.getAttribute('data-theme');\n // The app's two real states are `data-theme=\"dark\"` and NO attribute at all —\n // `MJExplorerAppComponent` removes it for light rather than writing \"light\"\n // (explorer-app.component.ts). Reproduce those exactly rather than inventing a\n // third state, so the transient DOM is one the stylesheet has actually seen.\n const wantDark = mode === 'dark';\n const isDark = previous === 'dark';\n const mustSwap = mode != null && wantDark !== isDark;\n\n if (mustSwap) {\n if (wantDark) {\n root.setAttribute('data-theme', 'dark');\n } else {\n root.removeAttribute('data-theme');\n }\n }\n try {\n const style = getComputedStyle(root);\n const out: Record<string, string> = {};\n for (const token of tokens) {\n const value = style.getPropertyValue(token).trim();\n if (value) {\n out[token] = value;\n }\n }\n return out;\n } finally {\n // Restore even if reading throws — never strand the app in the other theme.\n if (mustSwap) {\n if (previous === null) {\n root.removeAttribute('data-theme');\n } else {\n root.setAttribute('data-theme', previous);\n }\n }\n }\n }\n\n /** Resolve the HTML export's theme pieces once: tokens (explicit > snapshot), logo, title. */\n private async resolveTheme(options: ResolvedExportOptions): Promise<ResolvedExportTheme> {\n const tokens = this.resolveBrandTokens(options);\n const rootBlock = tokens ? this.buildRootBlock(tokens) : '';\n const logoUrl = options.branding?.logoUrl?.trim();\n return {\n rootBlock,\n // The logo needs its `.brand-logo` rule (as the trademark footer needs its own),\n // so both are gated on includeCSS — a CSS-less export must never carry a\n // full-size unstyled logo. The modal enforces this too, but the public\n // BuildExportContent seam has to hold the line on its own.\n logoDataUri: options.includeCSS && logoUrl ? await this.inlineLogo(logoUrl) : null,\n // The title is deliberately NOT includeCSS-gated: it lands in <title>/<h1>, needs\n // no stylesheet, and is the one branding field every format carries unconditionally.\n title: options.branding?.title?.trim() || null\n };\n }\n\n /** Explicit host tokens win; `includeTheme` falls back to a live snapshot; else no theme. */\n private resolveBrandTokens(options: ResolvedExportOptions): Record<string, string> | null {\n const explicit = options.branding?.brandTokens;\n if (explicit && Object.keys(explicit).length > 0) {\n return explicit;\n }\n return options.includeTheme ? this.SnapshotBrandTokens(DEFAULT_EXPORT_THEME_TOKENS, options.themeMode) : null;\n }\n\n /** Document title used by every format: branding override → conversation name → generic. */\n private resolveTitle(\n data: { conversation: MJConversationEntity; details: MJConversationDetailEntity[] },\n options: ResolvedExportOptions\n ): string {\n return options.branding?.title?.trim() || data.conversation.Name || 'Conversation';\n }\n\n /**\n * The JSON `branding` block — the data-format analogue of the HTML header +\n * trademark footer. Carries the title, trademark, and logo URL the host set;\n * null when no branding (or none of those fields) is present. Theme color\n * tokens are HTML-only and never included here.\n */\n private buildBrandingBlock(options: ResolvedExportOptions): Record<string, string> | null {\n const b = options.branding;\n if (!b) {\n return null;\n }\n const block: Record<string, string> = {};\n const title = b.title?.trim();\n const trademark = b.trademark?.trim();\n const logoUrl = b.logoUrl?.trim();\n if (title) block.title = title;\n if (trademark) block.trademark = trademark;\n if (logoUrl) block.logoUrl = logoUrl;\n return Object.keys(block).length > 0 ? block : null;\n }\n\n /**\n * CSS functions permitted inside an exported token value. This is an ALLOWLIST\n * (not a blocklist) so no network-capable function can slip through: blocking\n * only `url(`/`expression(` let `image-set()`, `-webkit-image-set()`,\n * `cross-fade()`, `image()`, and `src()` fetch a beacon URL without ever\n * writing the literal `url(`. Anything not on this list drops the whole entry.\n * The set is the safe value/color-math functions the export could legitimately\n * carry; extend it only with functions that CANNOT load an external resource.\n */\n private static readonly SAFE_CSS_FUNCTIONS = new Set([\n 'var', 'calc', 'min', 'max', 'clamp',\n 'rgb', 'rgba', 'hsl', 'hsla', 'hwb', 'lab', 'lch', 'oklab', 'oklch',\n 'color', 'color-mix',\n ]);\n\n /**\n * Emit the sanitized `:root{}` style block. Keys must be custom-property names.\n * A value is REJECTED (the entry is dropped, not stripped) when it carries any\n * declaration/tag-escape or network-reach vector: `<>{}` (tag/rule breakout),\n * `;` (declaration breakout — e.g. `; background: url(beacon)`), `\\` (CSS\n * escapes), `@` (at-rules), OR any CSS function not in\n * {@link SAFE_CSS_FUNCTIONS} (which excludes every resource-loading function —\n * url/image-set/cross-fade/image/src/expression/…). Plain colors, `var()`, and\n * `color-mix()` pass untouched.\n */\n private buildRootBlock(tokens: Record<string, string>): string {\n const rules: string[] = [];\n for (const [key, rawValue] of Object.entries(tokens)) {\n if (!/^--[A-Za-z0-9_-]+$/.test(key)) {\n continue;\n }\n const value = String(rawValue).trim();\n if (!value || /[<>{};@\\\\]/.test(value) || this.hasUnsafeCssFunction(value)) {\n continue;\n }\n rules.push(`${key}: ${value};`);\n }\n return rules.length > 0 ? `\n <style>:root { ${rules.join(' ')} }</style>` : '';\n }\n\n /** True if the value calls any CSS function outside {@link SAFE_CSS_FUNCTIONS}. */\n private hasUnsafeCssFunction(value: string): boolean {\n // Every `name(` occurrence — the identifier immediately before a '('.\n const calls = value.match(/([a-zA-Z][a-zA-Z-]*)\\s*\\(/g) ?? [];\n return calls.some((c) => {\n const name = c.replace(/\\s*\\($/, '').toLowerCase();\n return !ExportService.SAFE_CSS_FUNCTIONS.has(name);\n });\n }\n\n /** Fetch → data URI so the export stays self-contained; raw URL on any failure\n * (or when the response isn't actually an image — don't inline HTML/other as\n * a bogus `data:` image). */\n private async inlineLogo(url: string): Promise<string> {\n try {\n const response = await fetch(url);\n if (!response.ok) {\n return url;\n }\n const contentType = response.headers.get('content-type') ?? '';\n if (!/^image\\//i.test(contentType)) {\n return url;\n }\n const blob = await response.blob();\n return await new Promise<string>((resolve, reject) => {\n const reader = new FileReader();\n reader.onloadend = () => resolve(String(reader.result));\n reader.onerror = () => reject(reader.error);\n reader.readAsDataURL(blob);\n });\n } catch {\n return url;\n }\n }\n\n private async loadConversationData(\n conversationId: string,\n currentUser: UserInfo\n ): Promise<{ conversation: MJConversationEntity; details: MJConversationDetailEntity[] }> {\n const rv = RunView.FromMetadataProvider(this.Provider);\n\n // Load conversation and details in parallel\n const [conversationResult, detailsResult] = await rv.RunViews([\n {\n EntityName: 'MJ: Conversations',\n ExtraFilter: `ID='${conversationId}'`,\n ResultType: 'entity_object'\n },\n {\n EntityName: 'MJ: Conversation Details',\n ExtraFilter: `ConversationID='${conversationId}'`,\n OrderBy: 'Sequence ASC',\n ResultType: 'entity_object'\n }\n ], currentUser);\n\n if (!conversationResult.Success || !conversationResult.Results?.length) {\n throw new Error('Conversation not found');\n }\n\n return {\n conversation: conversationResult.Results[0] as MJConversationEntity,\n details: (detailsResult.Results || []) as MJConversationDetailEntity[]\n };\n }\n\n private exportAsJSON(\n data: {\n conversation: MJConversationEntity;\n details: MJConversationDetailEntity[];\n },\n options: ResolvedExportOptions\n ): string {\n const exportData: Record<string, unknown> = {};\n\n // Add metadata if requested\n if (options.includeMetadata) {\n exportData.conversation = {\n id: data.conversation.ID,\n name: data.conversation.Name,\n description: data.conversation.Description,\n createdAt: data.conversation.__mj_CreatedAt,\n updatedAt: data.conversation.__mj_UpdatedAt\n };\n } else {\n exportData.conversation = {\n name: data.conversation.Name\n };\n }\n\n // Branding block (title / trademark / logo) when the host supplied branding —\n // the data-format analogue of the HTML header + trademark footer.\n const branding = this.buildBrandingBlock(options);\n if (branding) {\n exportData.branding = branding;\n }\n\n // Add messages if requested\n if (options.includeMessages) {\n exportData.messages = data.details.map((detail, index) => {\n const message: Record<string, unknown> = {\n role: detail.Role,\n message: detail.Message\n };\n\n if (options.includeMetadata) {\n message.id = detail.ID;\n message.sequence = index + 1;\n message.timestamp = detail.__mj_CreatedAt;\n }\n\n return message;\n });\n }\n\n // Use pretty print option\n return JSON.stringify(exportData, null, options.prettyPrint ? 2 : 0);\n }\n\n private exportAsMarkdown(\n data: {\n conversation: MJConversationEntity;\n details: MJConversationDetailEntity[];\n },\n options: ResolvedExportOptions\n ): string {\n const logoUrl = options.branding?.logoUrl?.trim();\n // Unbranded markdown must stay byte-identical to before (`# <Name>`), so DON'T\n // route through resolveTitle's 'Conversation' fallback here — only a supplied\n // branding title overrides the raw conversation name.\n const title = options.branding?.title?.trim() || data.conversation.Name;\n let md = '';\n if (logoUrl) {\n md += `\\n\\n`;\n }\n md += `# ${title}\\n\\n`;\n\n if (data.conversation.Description) {\n md += `${data.conversation.Description}\\n\\n`;\n }\n\n if (options.includeMetadata) {\n md += `**Created:** ${this.formatDate(data.conversation.__mj_CreatedAt)}\\n\\n`;\n }\n\n md += `---\\n\\n`;\n\n if (options.includeMessages) {\n for (const detail of data.details) {\n md += `## ${this.capitalizeRole(detail.Role || 'Unknown')}\\n\\n`;\n md += `${detail.Message}\\n\\n`;\n\n if (options.includeMetadata) {\n md += `*${this.formatDate(detail.__mj_CreatedAt)}*\\n\\n`;\n }\n\n md += `---\\n\\n`;\n }\n }\n\n const trademark = options.branding?.trademark?.trim();\n if (trademark) {\n md += `_${trademark}_\\n`;\n }\n\n return md;\n }\n\n private exportAsHTML(\n data: {\n conversation: MJConversationEntity;\n details: MJConversationDetailEntity[];\n },\n options: ResolvedExportOptions,\n theme: ResolvedExportTheme\n ): string {\n const trademark = options.branding?.trademark?.trim();\n // Every color reads a theme token with the legacy hex as its fallback, so an\n // unthemed export (no :root block emitted) renders exactly as it always has,\n // while a themed one follows the app's palette.\n const styles = options.includeCSS ? `\n <style>\n body { font-family: var(--mj-font-family, system-ui, -apple-system, sans-serif); background: var(--mj-bg-page, #fff); color: var(--mj-text-primary, #333); max-width: 800px; margin: 40px auto; padding: 0 20px; line-height: 1.6; }\n h1 { color: var(--mj-text-primary, #333); border-bottom: 2px solid var(--mj-brand-primary, #007bff); padding-bottom: 10px; }\n .meta { color: var(--mj-text-secondary, #666); font-size: 14px; margin-bottom: 30px; }\n .message { margin-bottom: 30px; padding: 20px; border-radius: var(--mj-radius-md, 8px); background: var(--mj-bg-surface-card, #f5f5f5); }\n .message.user { background: var(--mj-brand-accent-subtle, #e3f2fd); }\n .message.assistant { background: var(--mj-bg-surface-card, #f5f5f5); }\n .role { font-weight: 600; color: var(--mj-brand-primary, #007bff); margin-bottom: 10px; }\n .content { white-space: pre-wrap; }\n .timestamp { color: var(--mj-text-disabled, #999); font-size: 12px; margin-top: 10px; }${theme.logoDataUri ? `\n .brand-logo { display: block; max-height: 48px; margin-bottom: 12px; }` : ''}${trademark ? `\n .brand-trademark { margin-top: 40px; padding-top: 16px; border-top: 1px solid var(--mj-border-default, #ddd); color: var(--mj-text-secondary, #666); font-size: 12px; text-align: center; }` : ''}\n </style>${theme.rootBlock}` : '';\n\n const title = theme.title ?? (data.conversation.Name || 'Conversation');\n let html = `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>${this.escapeHtml(title)}</title>${styles}\n</head>\n<body>\n ${theme.logoDataUri ? `<img class=\"brand-logo\" src=\"${this.escapeAttr(theme.logoDataUri)}\" alt=\"\" />\n ` : ''}<h1>${this.escapeHtml(title)}</h1>`;\n\n if (options.includeMetadata) {\n html += `\n <div class=\"meta\">\n ${data.conversation.Description ? `<p>${this.escapeHtml(data.conversation.Description)}</p>` : ''}\n <p>Created: ${this.formatDate(data.conversation.__mj_CreatedAt)}</p>\n </div>`;\n }\n\n if (options.includeMessages) {\n for (const detail of data.details) {\n const roleClass = detail.Role?.toLowerCase() || 'unknown';\n html += `\n <div class=\"message ${roleClass}\">\n <div class=\"role\">${this.capitalizeRole(detail.Role || 'Unknown')}</div>\n <div class=\"content\">${this.escapeHtml(detail.Message || '')}</div>`;\n\n if (options.includeMetadata) {\n html += `\n <div class=\"timestamp\">${this.formatDate(detail.__mj_CreatedAt)}</div>`;\n }\n\n html += `\n </div>`;\n }\n }\n\n if (options.includeCSS && trademark) {\n html += `\n <footer class=\"brand-trademark\">${this.escapeHtml(trademark)}</footer>`;\n }\n\n html += `\n</body>\n</html>`;\n\n return html;\n }\n\n private exportAsText(\n data: {\n conversation: MJConversationEntity;\n details: MJConversationDetailEntity[];\n },\n options: ResolvedExportOptions\n ): string {\n const name = this.resolveTitle(data, options) || 'Conversation';\n let text = `${name}\\n`;\n text += '='.repeat(name.length) + '\\n\\n';\n\n if (data.conversation.Description) {\n text += `${data.conversation.Description}\\n\\n`;\n }\n\n if (options.includeMetadata) {\n text += `Created: ${this.formatDate(data.conversation.__mj_CreatedAt)}\\n\\n`;\n }\n\n text += '-'.repeat(80) + '\\n\\n';\n\n if (options.includeMessages) {\n for (const detail of data.details) {\n text += `[${this.capitalizeRole(detail.Role || 'Unknown')}]\\n`;\n text += `${detail.Message}\\n`;\n\n if (options.includeMetadata) {\n text += `(${this.formatDate(detail.__mj_CreatedAt)})\\n`;\n }\n\n text += '\\n' + '-'.repeat(80) + '\\n\\n';\n }\n }\n\n const trademark = options.branding?.trademark?.trim();\n if (trademark) {\n text += `${trademark}\\n`;\n }\n\n return text;\n }\n\n private downloadFile(content: string, filename: string, mimeType: string): void {\n const blob = new Blob([content], { type: mimeType });\n const url = URL.createObjectURL(blob);\n const link = document.createElement('a');\n link.href = url;\n link.download = filename;\n document.body.appendChild(link);\n link.click();\n document.body.removeChild(link);\n URL.revokeObjectURL(url);\n }\n\n private formatDate(date: Date | string): string {\n const d = new Date(date);\n return d.toLocaleString('en-US', {\n year: 'numeric',\n month: 'long',\n day: 'numeric',\n hour: '2-digit',\n minute: '2-digit'\n });\n }\n\n private capitalizeRole(role: string): string {\n return role.charAt(0).toUpperCase() + role.slice(1).toLowerCase();\n }\n\n private escapeHtml(text: string): string {\n const div = document.createElement('div');\n div.textContent = text;\n return div.innerHTML;\n }\n\n /** escapeHtml + quote escaping — for values interpolated into HTML attributes. */\n private escapeAttr(text: string): string {\n return this.escapeHtml(text).replace(/\"/g, '"');\n }\n\n private getTimestamp(): string {\n const now = new Date();\n return now.toISOString().replace(/[:.]/g, '-').slice(0, -5);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"export.service.js","sourceRoot":"","sources":["../../../src/lib/services/export.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { Injectable } from '@angular/core';\nimport { ConversationEngine, ConversationScope, MJConversationEntity, MJConversationDetailEntity } from '@memberjunction/core-entities';\nimport { RunView, UserInfo, Metadata, IMetadataProvider } from '@memberjunction/core';\nimport { UUIDsEqual } from '@memberjunction/global';\n\nexport type ExportFormat = 'json' | 'markdown' | 'html' | 'text';\n\n/**\n * Branding applied to exported files, across EVERY format. HTML gets the full\n * treatment (theme colors, an inlined logo, the title, and a trademark footer);\n * JSON/markdown/text carry the title and trademark (markdown also references the\n * logo). Hosts supply this via `mj-conversation-chat-area`'s `exportBranding`\n * input. Color theming (`brandTokens`) is HTML-only — it has no meaning in the\n * data/plain-text formats.\n */\nexport interface ExportBranding {\n /**\n * CSS custom-property snapshot emitted as a `:root{}` block in the exported\n * document, so the export's stylesheet (which reads `var(--mj-…, fallback)`)\n * renders in the app's theme. HTML export only. Keys must be valid\n * custom-property names (`--like-this`). Entries are DROPPED when the key is\n * invalid or the value carries declaration-escape / network-call characters\n * (`<>{};@\\`, `url(`, `expression(`) — plain colors, `var()`, and\n * `color-mix()` pass. When omitted and `ExportOptions.includeTheme` is true,\n * the current theme is auto-snapshotted from `document.documentElement` (see\n * {@link DEFAULT_EXPORT_THEME_TOKENS}).\n */\n brandTokens?: Record<string, string>;\n /**\n * Logo URL. In HTML it is fetched and inlined as a data URI (so the file stays\n * self-contained) and rendered above the title — requires\n * `ExportOptions.includeCSS`, since it needs its stylesheet rule. In markdown it is\n * referenced by URL. JSON carries it as a string; plain text omits it.\n *\n * If the fetch fails, or the response isn't `content-type: image/*`, the raw URL is\n * emitted instead — so the exported file will reach out to that URL when opened.\n * There is no size or timeout guard on the fetch: a very large logo inflates the\n * export.\n */\n logoUrl?: string;\n /** Overrides the exported document's title (defaults to the conversation name). */\n title?: string;\n /**\n * A short trademark / attribution line (e.g. `© 2026 Acme Association ·\n * Powered by Betty`) rendered at the FOOT of the exported document: a styled HTML\n * footer, a markdown/text trailer, and a field in the JSON `branding` block.\n *\n * In HTML it needs its stylesheet rule, so — like the logo — it is emitted only when\n * `ExportOptions.includeCSS` is true. The markdown/text/JSON trailers have no such\n * dependency and always emit.\n *\n * NOT escaped for markdown: a value containing `_`, `]`, `)`, or a newline can break\n * the surrounding markdown. Supply plain text (HTML and JSON are escaped).\n */\n trademark?: string;\n}\n\nexport interface ExportOptions {\n includeMessages?: boolean;\n includeMetadata?: boolean;\n prettyPrint?: boolean;\n includeCSS?: boolean;\n /**\n * Emit the current app theme into the HTML export. When true and\n * `branding.brandTokens` is absent, the {@link DEFAULT_EXPORT_THEME_TOKENS}\n * are auto-snapshotted from the live document at export time. Default false —\n * an unthemed export renders exactly as before (the stylesheet's `var()`\n * fallbacks carry the legacy palette).\n *\n * Gates only the TOKEN auto-snapshot: a supplied `branding`'s `logoUrl`,\n * `title`, and `trademark` apply whenever `branding` is present — in HTML AND\n * in the JSON/markdown/text formats. (The export modal passes `branding`\n * through only while its \"Include branding\" checkbox is on, so in the UI flow\n * everything travels together.)\n */\n includeTheme?: boolean;\n /**\n * Which theme mode the snapshot captures — NOT whichever mode the app happens to be\n * in when the user clicks Export. Defaults to `'light'`: an export taken during a\n * dark session would otherwise bake dark text onto the page's white background and\n * come out unreadable. `'dark'` pairs the dark palette with the dark\n * `--mj-bg-page` the body rule applies, so the file is coherent either way.\n * HTML only — the data formats carry no colors.\n */\n themeMode?: 'light' | 'dark';\n /** Branding (tokens / logo / title) applied to the export — see {@link ExportBranding}. */\n branding?: ExportBranding;\n}\n\n/**\n * Tokens captured by the theme auto-snapshot — exactly the custom properties the\n * HTML export's stylesheet consumes. Hosts wanting more control supply their own\n * map via {@link ExportBranding.brandTokens} instead.\n */\nexport const DEFAULT_EXPORT_THEME_TOKENS: readonly string[] = [\n '--mj-bg-page',\n '--mj-text-primary',\n '--mj-text-secondary',\n '--mj-text-disabled',\n '--mj-border-default',\n '--mj-brand-primary',\n '--mj-brand-accent-subtle',\n '--mj-bg-surface-card',\n '--mj-font-family',\n '--mj-radius-md',\n];\n\n/** The conversation and the messages one export writes. */\nexport interface ExportConversationData {\n conversation: MJConversationEntity;\n details: MJConversationDetailEntity[];\n /**\n * The fork the messages come from, as the header names it (its display name). Absent or null\n * in Main.\n */\n fork?: string | null;\n}\n\n/** Internal: options with defaults applied (branding stays optional). */\ntype ResolvedExportOptions = Required<Omit<ExportOptions, 'branding'>> & Pick<ExportOptions, 'branding'>;\n\n/** Internal: the theme pieces resolved once per HTML export. */\ninterface ResolvedExportTheme {\n /** `<style>:root{…}</style>` block (empty string when no tokens resolved). */\n rootBlock: string;\n /** Inlined logo (data URI, or the raw URL on fetch failure); null = no logo. */\n logoDataUri: string | null;\n /** Document-title override; null = use the conversation name. */\n title: string | null;\n}\n\n@Injectable({\n providedIn: 'root'\n})\nexport class ExportService {\n private _provider: IMetadataProvider | null = null;\n\n /**\n * Set the metadata provider this service should use. When unset, falls back to Metadata.Provider.\n */\n public set Provider(value: IMetadataProvider | null) {\n this._provider = value;\n }\n\n public get Provider(): IMetadataProvider {\n return this._provider ?? Metadata.Provider;\n }\n\n /**\n * Exports the messages of one scope of a conversation (Main, or one fork's path) and\n * downloads the file. In a fork the export header names the fork.\n * @throws when the scope belongs to another conversation, or the conversation is not found.\n */\n async ExportConversation(\n conversationId: string,\n scope: ConversationScope,\n format: ExportFormat,\n currentUser: UserInfo,\n options: ExportOptions = {}\n ): Promise<void> {\n const conversation = await this.loadConversationData(conversationId, scope, currentUser);\n const { content, filename, mimeType } = await this.BuildExportContent(conversation, format, options);\n this.downloadFile(content, filename, mimeType);\n }\n\n /**\n * @deprecated Use {@link ExportConversation}. Without `scope`, exports Main.\n */\n async exportConversation(\n conversationId: string,\n format: ExportFormat,\n currentUser: UserInfo,\n options: ExportOptions = {},\n scope?: ConversationScope\n ): Promise<void> {\n const resolved = scope ?? ConversationEngine.TrunkScope(conversationId);\n return this.ExportConversation(conversationId, resolved, format, currentUser, options);\n }\n\n /**\n * Build the export document for already-loaded conversation data — the\n * download-free seam of {@link ExportConversation}. Async because HTML-format\n * branding may inline a logo. Exposed publicly so hosts (and tests) can build\n * export content without triggering a browser download.\n */\n public async BuildExportContent(\n data: ExportConversationData,\n format: ExportFormat,\n options: ExportOptions = {}\n ): Promise<{ content: string; filename: string; mimeType: string }> {\n const exportOptions: ResolvedExportOptions = {\n includeMessages: options.includeMessages ?? true,\n includeMetadata: options.includeMetadata ?? true,\n prettyPrint: options.prettyPrint ?? true,\n includeCSS: options.includeCSS ?? true,\n includeTheme: options.includeTheme ?? false,\n themeMode: options.themeMode ?? 'light',\n branding: options.branding\n };\n const baseName = `conversation-${data.conversation.Name}-${this.getTimestamp()}`;\n\n switch (format) {\n case 'json':\n return { content: this.exportAsJSON(data, exportOptions), filename: `${baseName}.json`, mimeType: 'application/json' };\n case 'markdown':\n return { content: this.exportAsMarkdown(data, exportOptions), filename: `${baseName}.md`, mimeType: 'text/markdown' };\n case 'html':\n return {\n content: this.exportAsHTML(data, exportOptions, await this.resolveTheme(exportOptions)),\n filename: `${baseName}.html`,\n mimeType: 'text/html'\n };\n case 'text':\n return { content: this.exportAsText(data, exportOptions), filename: `${baseName}.txt`, mimeType: 'text/plain' };\n default:\n throw new Error(`Unsupported export format: ${format}`);\n }\n }\n\n /**\n * Snapshot the given theme tokens from the live document. Empty/unset tokens are\n * skipped.\n *\n * `mode` captures a SPECIFIC palette rather than whatever the app is rendering right\n * now. Without it, exporting from a dark session bakes dark text onto the export's\n * white page and the file is unreadable. When the requested mode isn't the active one,\n * `data-theme` is flipped on `documentElement`, read, and restored — all synchronous\n * within one task, so the browser never paints the intermediate state. Omit `mode`\n * to read the live values as-is.\n */\n public SnapshotBrandTokens(\n tokens: readonly string[] = DEFAULT_EXPORT_THEME_TOKENS,\n mode?: 'light' | 'dark'\n ): Record<string, string> {\n const root = document.documentElement;\n const previous = root.getAttribute('data-theme');\n // The app's two real states are `data-theme=\"dark\"` and NO attribute at all —\n // `MJExplorerAppComponent` removes it for light rather than writing \"light\"\n // (explorer-app.component.ts). Reproduce those exactly rather than inventing a\n // third state, so the transient DOM is one the stylesheet has actually seen.\n const wantDark = mode === 'dark';\n const isDark = previous === 'dark';\n const mustSwap = mode != null && wantDark !== isDark;\n\n if (mustSwap) {\n if (wantDark) {\n root.setAttribute('data-theme', 'dark');\n } else {\n root.removeAttribute('data-theme');\n }\n }\n try {\n const style = getComputedStyle(root);\n const out: Record<string, string> = {};\n for (const token of tokens) {\n const value = style.getPropertyValue(token).trim();\n if (value) {\n out[token] = value;\n }\n }\n return out;\n } finally {\n // Restore even if reading throws — never strand the app in the other theme.\n if (mustSwap) {\n if (previous === null) {\n root.removeAttribute('data-theme');\n } else {\n root.setAttribute('data-theme', previous);\n }\n }\n }\n }\n\n /** Resolve the HTML export's theme pieces once: tokens (explicit > snapshot), logo, title. */\n private async resolveTheme(options: ResolvedExportOptions): Promise<ResolvedExportTheme> {\n const tokens = this.resolveBrandTokens(options);\n const rootBlock = tokens ? this.buildRootBlock(tokens) : '';\n const logoUrl = options.branding?.logoUrl?.trim();\n return {\n rootBlock,\n // The logo needs its `.brand-logo` rule (as the trademark footer needs its own),\n // so both are gated on includeCSS — a CSS-less export must never carry a\n // full-size unstyled logo. The modal enforces this too, but the public\n // BuildExportContent seam has to hold the line on its own.\n logoDataUri: options.includeCSS && logoUrl ? await this.inlineLogo(logoUrl) : null,\n // The title is deliberately NOT includeCSS-gated: it lands in <title>/<h1>, needs\n // no stylesheet, and is the one branding field every format carries unconditionally.\n title: options.branding?.title?.trim() || null\n };\n }\n\n /** Explicit host tokens win; `includeTheme` falls back to a live snapshot; else no theme. */\n private resolveBrandTokens(options: ResolvedExportOptions): Record<string, string> | null {\n const explicit = options.branding?.brandTokens;\n if (explicit && Object.keys(explicit).length > 0) {\n return explicit;\n }\n return options.includeTheme ? this.SnapshotBrandTokens(DEFAULT_EXPORT_THEME_TOKENS, options.themeMode) : null;\n }\n\n /** Document title used by every format: branding override → conversation name → generic. */\n private resolveTitle(\n data: ExportConversationData,\n options: ResolvedExportOptions\n ): string {\n return options.branding?.title?.trim() || data.conversation.Name || 'Conversation';\n }\n\n /**\n * The JSON `branding` block — the data-format analogue of the HTML header +\n * trademark footer. Carries the title, trademark, and logo URL the host set;\n * null when no branding (or none of those fields) is present. Theme color\n * tokens are HTML-only and never included here.\n */\n private buildBrandingBlock(options: ResolvedExportOptions): Record<string, string> | null {\n const b = options.branding;\n if (!b) {\n return null;\n }\n const block: Record<string, string> = {};\n const title = b.title?.trim();\n const trademark = b.trademark?.trim();\n const logoUrl = b.logoUrl?.trim();\n if (title) block.title = title;\n if (trademark) block.trademark = trademark;\n if (logoUrl) block.logoUrl = logoUrl;\n return Object.keys(block).length > 0 ? block : null;\n }\n\n /**\n * CSS functions permitted inside an exported token value. This is an ALLOWLIST\n * (not a blocklist) so no network-capable function can slip through: blocking\n * only `url(`/`expression(` let `image-set()`, `-webkit-image-set()`,\n * `cross-fade()`, `image()`, and `src()` fetch a beacon URL without ever\n * writing the literal `url(`. Anything not on this list drops the whole entry.\n * The set is the safe value/color-math functions the export could legitimately\n * carry; extend it only with functions that CANNOT load an external resource.\n */\n private static readonly SAFE_CSS_FUNCTIONS = new Set([\n 'var', 'calc', 'min', 'max', 'clamp',\n 'rgb', 'rgba', 'hsl', 'hsla', 'hwb', 'lab', 'lch', 'oklab', 'oklch',\n 'color', 'color-mix',\n ]);\n\n /**\n * Emit the sanitized `:root{}` style block. Keys must be custom-property names.\n * A value is REJECTED (the entry is dropped, not stripped) when it carries any\n * declaration/tag-escape or network-reach vector: `<>{}` (tag/rule breakout),\n * `;` (declaration breakout — e.g. `; background: url(beacon)`), `\\` (CSS\n * escapes), `@` (at-rules), OR any CSS function not in\n * {@link SAFE_CSS_FUNCTIONS} (which excludes every resource-loading function —\n * url/image-set/cross-fade/image/src/expression/…). Plain colors, `var()`, and\n * `color-mix()` pass untouched.\n */\n private buildRootBlock(tokens: Record<string, string>): string {\n const rules: string[] = [];\n for (const [key, rawValue] of Object.entries(tokens)) {\n if (!/^--[A-Za-z0-9_-]+$/.test(key)) {\n continue;\n }\n const value = String(rawValue).trim();\n if (!value || /[<>{};@\\\\]/.test(value) || this.hasUnsafeCssFunction(value)) {\n continue;\n }\n rules.push(`${key}: ${value};`);\n }\n return rules.length > 0 ? `\n <style>:root { ${rules.join(' ')} }</style>` : '';\n }\n\n /** True if the value calls any CSS function outside {@link SAFE_CSS_FUNCTIONS}. */\n private hasUnsafeCssFunction(value: string): boolean {\n // Every `name(` occurrence — the identifier immediately before a '('.\n const calls = value.match(/([a-zA-Z][a-zA-Z-]*)\\s*\\(/g) ?? [];\n return calls.some((c) => {\n const name = c.replace(/\\s*\\($/, '').toLowerCase();\n return !ExportService.SAFE_CSS_FUNCTIONS.has(name);\n });\n }\n\n /** Fetch → data URI so the export stays self-contained; raw URL on any failure\n * (or when the response isn't actually an image — don't inline HTML/other as\n * a bogus `data:` image). */\n private async inlineLogo(url: string): Promise<string> {\n try {\n const response = await fetch(url);\n if (!response.ok) {\n return url;\n }\n const contentType = response.headers.get('content-type') ?? '';\n if (!/^image\\//i.test(contentType)) {\n return url;\n }\n const blob = await response.blob();\n return await new Promise<string>((resolve, reject) => {\n const reader = new FileReader();\n reader.onloadend = () => resolve(String(reader.result));\n reader.onerror = () => reject(reader.error);\n reader.readAsDataURL(blob);\n });\n } catch {\n return url;\n }\n }\n\n /** Loads the conversation and the messages in the scope that no rerun replaced, in Sequence order. */\n private async loadConversationData(\n conversationId: string,\n scope: ConversationScope,\n currentUser: UserInfo\n ): Promise<ExportConversationData> {\n if (!UUIDsEqual(scope.ConversationID, conversationId)) {\n throw new Error(`Conversation ${conversationId} cannot be exported with the scope of conversation ${scope.ConversationID}`);\n }\n const rv = RunView.FromMetadataProvider(this.Provider);\n\n // Load conversation and details in parallel\n const [conversationResult, detailsResult] = await rv.RunViews([\n {\n EntityName: 'MJ: Conversations',\n ExtraFilter: `ID='${conversationId}'`,\n ResultType: 'entity_object'\n },\n {\n EntityName: 'MJ: Conversation Details',\n ExtraFilter: ConversationEngine.LiveRowsFilter(ConversationEngine.ScopeFilter(scope)),\n OrderBy: 'Sequence ASC',\n ResultType: 'entity_object'\n }\n ], currentUser);\n\n if (!conversationResult.Success || !conversationResult.Results?.length) {\n throw new Error('Conversation not found');\n }\n\n const details = (detailsResult.Results || []) as MJConversationDetailEntity[];\n return {\n conversation: conversationResult.Results[0] as MJConversationEntity,\n details,\n fork: this.forkLabel(scope, details)\n };\n }\n\n /** The header name of the scope's fork: its display name; null in Main. */\n private forkLabel(scope: ConversationScope, details: ReadonlyArray<MJConversationDetailEntity>): string | null {\n if (scope.BranchID == null) {\n return null;\n }\n const fork = scope.Branches.find(b => UUIDsEqual(b.ID, scope.BranchID));\n if (!fork) {\n return scope.BranchID;\n }\n const first = [...details]\n .filter(d => UUIDsEqual(d.BranchID ?? null, scope.BranchID))\n .sort((a, b) => a.Sequence - b.Sequence)\n .find(d => ConversationEngine.ForkPlainText(d.Message) != null);\n return ConversationEngine.ForkDisplayName(fork, first?.Message ?? null);\n }\n\n private exportAsJSON(\n data: ExportConversationData,\n options: ResolvedExportOptions\n ): string {\n const exportData: Record<string, unknown> = {};\n\n // Add metadata if requested\n const conversationBlock: Record<string, unknown> = options.includeMetadata\n ? {\n id: data.conversation.ID,\n name: data.conversation.Name,\n description: data.conversation.Description,\n createdAt: data.conversation.__mj_CreatedAt,\n updatedAt: data.conversation.__mj_UpdatedAt\n }\n : { name: data.conversation.Name };\n if (data.fork) {\n conversationBlock.fork = data.fork;\n }\n exportData.conversation = conversationBlock;\n\n // Branding block (title / trademark / logo) when the host supplied branding —\n // the data-format analogue of the HTML header + trademark footer.\n const branding = this.buildBrandingBlock(options);\n if (branding) {\n exportData.branding = branding;\n }\n\n // Add messages if requested\n if (options.includeMessages) {\n exportData.messages = data.details.map((detail, index) => {\n const message: Record<string, unknown> = {\n role: detail.Role,\n message: detail.Message\n };\n\n if (options.includeMetadata) {\n message.id = detail.ID;\n message.sequence = index + 1;\n message.timestamp = detail.__mj_CreatedAt;\n }\n\n return message;\n });\n }\n\n // Use pretty print option\n return JSON.stringify(exportData, null, options.prettyPrint ? 2 : 0);\n }\n\n private exportAsMarkdown(\n data: ExportConversationData,\n options: ResolvedExportOptions\n ): string {\n const logoUrl = options.branding?.logoUrl?.trim();\n // Unbranded markdown must stay byte-identical to before (`# <Name>`), so DON'T\n // route through resolveTitle's 'Conversation' fallback here — only a supplied\n // branding title overrides the raw conversation name.\n const title = options.branding?.title?.trim() || data.conversation.Name;\n let md = '';\n if (logoUrl) {\n md += `\\n\\n`;\n }\n md += `# ${title}\\n\\n`;\n\n if (data.conversation.Description) {\n md += `${data.conversation.Description}\\n\\n`;\n }\n\n if (options.includeMetadata) {\n md += `**Created:** ${this.formatDate(data.conversation.__mj_CreatedAt)}\\n\\n`;\n }\n\n if (data.fork) {\n md += `**Fork:** ${data.fork}\\n\\n`;\n }\n\n md += `---\\n\\n`;\n\n if (options.includeMessages) {\n for (const detail of data.details) {\n md += `## ${this.capitalizeRole(detail.Role || 'Unknown')}\\n\\n`;\n md += `${detail.Message}\\n\\n`;\n\n if (options.includeMetadata) {\n md += `*${this.formatDate(detail.__mj_CreatedAt)}*\\n\\n`;\n }\n\n md += `---\\n\\n`;\n }\n }\n\n const trademark = options.branding?.trademark?.trim();\n if (trademark) {\n md += `_${trademark}_\\n`;\n }\n\n return md;\n }\n\n private exportAsHTML(\n data: ExportConversationData,\n options: ResolvedExportOptions,\n theme: ResolvedExportTheme\n ): string {\n const trademark = options.branding?.trademark?.trim();\n // Every color reads a theme token with the legacy hex as its fallback, so an\n // unthemed export (no :root block emitted) renders exactly as it always has,\n // while a themed one follows the app's palette.\n const styles = options.includeCSS ? `\n <style>\n body { font-family: var(--mj-font-family, system-ui, -apple-system, sans-serif); background: var(--mj-bg-page, #fff); color: var(--mj-text-primary, #333); max-width: 800px; margin: 40px auto; padding: 0 20px; line-height: 1.6; }\n h1 { color: var(--mj-text-primary, #333); border-bottom: 2px solid var(--mj-brand-primary, #007bff); padding-bottom: 10px; }\n .meta { color: var(--mj-text-secondary, #666); font-size: 14px; margin-bottom: 30px; }\n .message { margin-bottom: 30px; padding: 20px; border-radius: var(--mj-radius-md, 8px); background: var(--mj-bg-surface-card, #f5f5f5); }\n .message.user { background: var(--mj-brand-accent-subtle, #e3f2fd); }\n .message.assistant { background: var(--mj-bg-surface-card, #f5f5f5); }\n .role { font-weight: 600; color: var(--mj-brand-primary, #007bff); margin-bottom: 10px; }\n .content { white-space: pre-wrap; }\n .timestamp { color: var(--mj-text-disabled, #999); font-size: 12px; margin-top: 10px; }${theme.logoDataUri ? `\n .brand-logo { display: block; max-height: 48px; margin-bottom: 12px; }` : ''}${trademark ? `\n .brand-trademark { margin-top: 40px; padding-top: 16px; border-top: 1px solid var(--mj-border-default, #ddd); color: var(--mj-text-secondary, #666); font-size: 12px; text-align: center; }` : ''}\n </style>${theme.rootBlock}` : '';\n\n const title = theme.title ?? (data.conversation.Name || 'Conversation');\n let html = `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>${this.escapeHtml(title)}</title>${styles}\n</head>\n<body>\n ${theme.logoDataUri ? `<img class=\"brand-logo\" src=\"${this.escapeAttr(theme.logoDataUri)}\" alt=\"\" />\n ` : ''}<h1>${this.escapeHtml(title)}</h1>`;\n\n const forkLine = data.fork ? `\n <p>Fork: ${this.escapeHtml(data.fork)}</p>` : '';\n if (options.includeMetadata) {\n html += `\n <div class=\"meta\">\n ${data.conversation.Description ? `<p>${this.escapeHtml(data.conversation.Description)}</p>` : ''}\n <p>Created: ${this.formatDate(data.conversation.__mj_CreatedAt)}</p>${forkLine}\n </div>`;\n } else if (forkLine) {\n html += `\n <div class=\"meta\">${forkLine}\n </div>`;\n }\n\n if (options.includeMessages) {\n for (const detail of data.details) {\n const roleClass = detail.Role?.toLowerCase() || 'unknown';\n html += `\n <div class=\"message ${roleClass}\">\n <div class=\"role\">${this.capitalizeRole(detail.Role || 'Unknown')}</div>\n <div class=\"content\">${this.escapeHtml(detail.Message || '')}</div>`;\n\n if (options.includeMetadata) {\n html += `\n <div class=\"timestamp\">${this.formatDate(detail.__mj_CreatedAt)}</div>`;\n }\n\n html += `\n </div>`;\n }\n }\n\n if (options.includeCSS && trademark) {\n html += `\n <footer class=\"brand-trademark\">${this.escapeHtml(trademark)}</footer>`;\n }\n\n html += `\n</body>\n</html>`;\n\n return html;\n }\n\n private exportAsText(\n data: ExportConversationData,\n options: ResolvedExportOptions\n ): string {\n const name = this.resolveTitle(data, options) || 'Conversation';\n let text = `${name}\\n`;\n text += '='.repeat(name.length) + '\\n\\n';\n\n if (data.conversation.Description) {\n text += `${data.conversation.Description}\\n\\n`;\n }\n\n if (options.includeMetadata) {\n text += `Created: ${this.formatDate(data.conversation.__mj_CreatedAt)}\\n\\n`;\n }\n\n if (data.fork) {\n text += `Fork: ${data.fork}\\n\\n`;\n }\n\n text += '-'.repeat(80) + '\\n\\n';\n\n if (options.includeMessages) {\n for (const detail of data.details) {\n text += `[${this.capitalizeRole(detail.Role || 'Unknown')}]\\n`;\n text += `${detail.Message}\\n`;\n\n if (options.includeMetadata) {\n text += `(${this.formatDate(detail.__mj_CreatedAt)})\\n`;\n }\n\n text += '\\n' + '-'.repeat(80) + '\\n\\n';\n }\n }\n\n const trademark = options.branding?.trademark?.trim();\n if (trademark) {\n text += `${trademark}\\n`;\n }\n\n return text;\n }\n\n private downloadFile(content: string, filename: string, mimeType: string): void {\n const blob = new Blob([content], { type: mimeType });\n const url = URL.createObjectURL(blob);\n const link = document.createElement('a');\n link.href = url;\n link.download = filename;\n document.body.appendChild(link);\n link.click();\n document.body.removeChild(link);\n URL.revokeObjectURL(url);\n }\n\n private formatDate(date: Date | string): string {\n const d = new Date(date);\n return d.toLocaleString('en-US', {\n year: 'numeric',\n month: 'long',\n day: 'numeric',\n hour: '2-digit',\n minute: '2-digit'\n });\n }\n\n private capitalizeRole(role: string): string {\n return role.charAt(0).toUpperCase() + role.slice(1).toLowerCase();\n }\n\n private escapeHtml(text: string): string {\n const div = document.createElement('div');\n div.textContent = text;\n return div.innerHTML;\n }\n\n /** escapeHtml + quote escaping — for values interpolated into HTML attributes. */\n private escapeAttr(text: string): string {\n return this.escapeHtml(text).replace(/\"/g, '"');\n }\n\n private getTimestamp(): string {\n const now = new Date();\n return now.toISOString().replace(/[:.]/g, '-').slice(0, -5);\n }\n}\n"]}
|