@memberjunction/ng-conversations 6.1.2 → 6.2.0-edge.0

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.
Files changed (113) hide show
  1. package/README.md +1 -1
  2. package/dist/lib/components/conversation/conversation-chat-area.component.d.ts.map +1 -1
  3. package/dist/lib/components/conversation/conversation-chat-area.component.js +9 -26
  4. package/dist/lib/components/conversation/conversation-chat-area.component.js.map +1 -1
  5. package/dist/lib/components/realtime/channels/channel-onboarding-panel.component.d.ts +1 -1
  6. package/dist/lib/components/realtime/channels/channel-onboarding-panel.component.d.ts.map +1 -1
  7. package/dist/lib/components/realtime/channels/channel-onboarding-panel.component.js.map +1 -1
  8. package/dist/lib/components/realtime/channels/client-context-channel.d.ts +1 -1
  9. package/dist/lib/components/realtime/channels/client-context-channel.d.ts.map +1 -1
  10. package/dist/lib/components/realtime/channels/client-context-channel.js +1 -1
  11. package/dist/lib/components/realtime/channels/client-context-channel.js.map +1 -1
  12. package/dist/lib/components/realtime/channels/realtime-channel-pane.component.d.ts +1 -1
  13. package/dist/lib/components/realtime/channels/realtime-channel-pane.component.d.ts.map +1 -1
  14. package/dist/lib/components/realtime/channels/realtime-channel-pane.component.js +3 -0
  15. package/dist/lib/components/realtime/channels/realtime-channel-pane.component.js.map +1 -1
  16. package/dist/lib/components/realtime/media/media-channel.d.ts +2 -1
  17. package/dist/lib/components/realtime/media/media-channel.d.ts.map +1 -1
  18. package/dist/lib/components/realtime/media/media-channel.js +1 -1
  19. package/dist/lib/components/realtime/media/media-channel.js.map +1 -1
  20. package/dist/lib/components/realtime/realtime-activity-rail.component.d.ts +1 -1
  21. package/dist/lib/components/realtime/realtime-activity-rail.component.d.ts.map +1 -1
  22. package/dist/lib/components/realtime/realtime-activity-rail.component.js.map +1 -1
  23. package/dist/lib/components/realtime/realtime-agent-banner.component.d.ts +1 -1
  24. package/dist/lib/components/realtime/realtime-agent-banner.component.d.ts.map +1 -1
  25. package/dist/lib/components/realtime/realtime-agent-banner.component.js.map +1 -1
  26. package/dist/lib/components/realtime/realtime-composer.component.d.ts +3 -1
  27. package/dist/lib/components/realtime/realtime-composer.component.d.ts.map +1 -1
  28. package/dist/lib/components/realtime/realtime-composer.component.js +26 -8
  29. package/dist/lib/components/realtime/realtime-composer.component.js.map +1 -1
  30. package/dist/lib/components/realtime/realtime-delegation-card.component.d.ts +1 -1
  31. package/dist/lib/components/realtime/realtime-delegation-card.component.d.ts.map +1 -1
  32. package/dist/lib/components/realtime/realtime-delegation-card.component.js.map +1 -1
  33. package/dist/lib/components/realtime/realtime-session-overlay.component.d.ts +2 -2
  34. package/dist/lib/components/realtime/realtime-session-overlay.component.d.ts.map +1 -1
  35. package/dist/lib/components/realtime/realtime-session-overlay.component.js +1 -1
  36. package/dist/lib/components/realtime/realtime-session-overlay.component.js.map +1 -1
  37. package/dist/lib/components/realtime/realtime-session-state.d.ts +2 -3
  38. package/dist/lib/components/realtime/realtime-session-state.d.ts.map +1 -1
  39. package/dist/lib/components/realtime/realtime-session-state.js +3 -2
  40. package/dist/lib/components/realtime/realtime-session-state.js.map +1 -1
  41. package/dist/lib/components/realtime/realtime-session-thread.component.d.ts +17 -1
  42. package/dist/lib/components/realtime/realtime-session-thread.component.d.ts.map +1 -1
  43. package/dist/lib/components/realtime/realtime-session-thread.component.js +122 -45
  44. package/dist/lib/components/realtime/realtime-session-thread.component.js.map +1 -1
  45. package/dist/lib/components/realtime/realtime-session-timeline-card.component.d.ts +1 -9
  46. package/dist/lib/components/realtime/realtime-session-timeline-card.component.d.ts.map +1 -1
  47. package/dist/lib/components/realtime/realtime-session-timeline-card.component.js +13 -43
  48. package/dist/lib/components/realtime/realtime-session-timeline-card.component.js.map +1 -1
  49. package/dist/lib/components/realtime/realtime-surface-tabs.component.d.ts +2 -2
  50. package/dist/lib/components/realtime/realtime-surface-tabs.component.d.ts.map +1 -1
  51. package/dist/lib/components/realtime/realtime-surface-tabs.component.js.map +1 -1
  52. package/dist/lib/components/realtime/realtime-surface-tabs.model.d.ts +1 -1
  53. package/dist/lib/components/realtime/realtime-surface-tabs.model.d.ts.map +1 -1
  54. package/dist/lib/components/realtime/realtime-surface-tabs.model.js.map +1 -1
  55. package/dist/lib/components/realtime/remote-browser/remote-browser-channel.d.ts +1 -1
  56. package/dist/lib/components/realtime/remote-browser/remote-browser-channel.d.ts.map +1 -1
  57. package/dist/lib/components/realtime/remote-browser/remote-browser-channel.js +1 -1
  58. package/dist/lib/components/realtime/remote-browser/remote-browser-channel.js.map +1 -1
  59. package/dist/lib/components/realtime/whiteboard/whiteboard-channel.d.ts +1 -1
  60. package/dist/lib/components/realtime/whiteboard/whiteboard-channel.d.ts.map +1 -1
  61. package/dist/lib/components/realtime/whiteboard/whiteboard-channel.js +1 -1
  62. package/dist/lib/components/realtime/whiteboard/whiteboard-channel.js.map +1 -1
  63. package/dist/lib/conversations.module.d.ts.map +1 -1
  64. package/dist/lib/conversations.module.js.map +1 -1
  65. package/dist/lib/services/browser-realtime-media-host.d.ts +24 -0
  66. package/dist/lib/services/browser-realtime-media-host.d.ts.map +1 -0
  67. package/dist/lib/services/browser-realtime-media-host.js +95 -0
  68. package/dist/lib/services/browser-realtime-media-host.js.map +1 -0
  69. package/dist/lib/services/conversation-attachment.service.d.ts +24 -2
  70. package/dist/lib/services/conversation-attachment.service.d.ts.map +1 -1
  71. package/dist/lib/services/conversation-attachment.service.js +43 -4
  72. package/dist/lib/services/conversation-attachment.service.js.map +1 -1
  73. package/dist/lib/services/graphql-attachment-blob-store.d.ts +44 -0
  74. package/dist/lib/services/graphql-attachment-blob-store.d.ts.map +1 -0
  75. package/dist/lib/services/graphql-attachment-blob-store.js +113 -0
  76. package/dist/lib/services/graphql-attachment-blob-store.js.map +1 -0
  77. package/dist/lib/services/mention-autocomplete.service.d.ts +17 -141
  78. package/dist/lib/services/mention-autocomplete.service.d.ts.map +1 -1
  79. package/dist/lib/services/mention-autocomplete.service.js +15 -460
  80. package/dist/lib/services/mention-autocomplete.service.js.map +1 -1
  81. package/dist/lib/services/realtime-session-review.service.d.ts +1 -1
  82. package/dist/lib/services/realtime-session-review.service.d.ts.map +1 -1
  83. package/dist/lib/services/realtime-session-review.service.js +1 -1
  84. package/dist/lib/services/realtime-session-review.service.js.map +1 -1
  85. package/dist/lib/services/realtime-session.service.d.ts +16 -1150
  86. package/dist/lib/services/realtime-session.service.d.ts.map +1 -1
  87. package/dist/lib/services/realtime-session.service.js +28 -2430
  88. package/dist/lib/services/realtime-session.service.js.map +1 -1
  89. package/dist/lib/utils/realtime-session-timeline.d.ts +8 -79
  90. package/dist/lib/utils/realtime-session-timeline.d.ts.map +1 -1
  91. package/dist/lib/utils/realtime-session-timeline.js +8 -89
  92. package/dist/lib/utils/realtime-session-timeline.js.map +1 -1
  93. package/dist/public-api.d.ts +2 -2
  94. package/dist/public-api.d.ts.map +1 -1
  95. package/dist/public-api.js +6 -2
  96. package/dist/public-api.js.map +1 -1
  97. package/package.json +33 -32
  98. package/dist/lib/components/realtime/channels/base-realtime-channel-client.d.ts +0 -384
  99. package/dist/lib/components/realtime/channels/base-realtime-channel-client.d.ts.map +0 -1
  100. package/dist/lib/components/realtime/channels/base-realtime-channel-client.js +0 -231
  101. package/dist/lib/components/realtime/channels/base-realtime-channel-client.js.map +0 -1
  102. package/dist/lib/services/delegation-result-parser.d.ts +0 -50
  103. package/dist/lib/services/delegation-result-parser.d.ts.map +0 -1
  104. package/dist/lib/services/delegation-result-parser.js +0 -60
  105. package/dist/lib/services/delegation-result-parser.js.map +0 -1
  106. package/dist/lib/services/narration-template.d.ts +0 -42
  107. package/dist/lib/services/narration-template.d.ts.map +0 -1
  108. package/dist/lib/services/narration-template.js +0 -73
  109. package/dist/lib/services/narration-template.js.map +0 -1
  110. package/dist/lib/services/skill-picker-narrowing.d.ts +0 -13
  111. package/dist/lib/services/skill-picker-narrowing.d.ts.map +0 -1
  112. package/dist/lib/services/skill-picker-narrowing.js +0 -13
  113. package/dist/lib/services/skill-picker-narrowing.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"conversations.module.js","sourceRoot":"","sources":["../../src/lib/conversations.module.ts"],"names":[],"mappings":"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","sourcesContent":["import { NgModule } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { FormsModule, ReactiveFormsModule } from '@angular/forms';\nimport { OverlayModule } from '@angular/cdk/overlay';\n\n// MJ UI Components\nimport { MJButtonDirective, MJDatepickerComponent, MJDialogComponent, MJDialogActionsComponent, MJEmptyStateComponent, MJAlertComponent, MJAccordionModule } from '@memberjunction/ng-ui-components';\n\n// MemberJunction modules\nimport { ContainerDirectivesModule } from '@memberjunction/ng-container-directives';\nimport { CodeEditorModule } from '@memberjunction/ng-code-editor';\nimport { ArtifactsModule } from '@memberjunction/ng-artifacts';\nimport { TestingModule } from '@memberjunction/ng-testing';\nimport { SharedGenericModule } from '@memberjunction/ng-shared-generic';\nimport { UserRoutinesModule } from '@memberjunction/ng-user-routines';\n\n// Markdown module\nimport { MarkdownModule } from '@memberjunction/ng-markdown';\n\n// Resource permissions (generic share dialog)\nimport { ResourcePermissionsModule } from '@memberjunction/ng-resource-permissions';\n\n// Composer (mention editor + dropdown + message input box) — extracted to @memberjunction/ng-composer\nimport { ComposerModule } from '@memberjunction/ng-composer';\n\n// AI-aware composer wrapper (agent/record/skill trigger plugins built in)\nimport { AiComposerComponent } from './components/composer/ai-composer.component';\nimport { LoadComposerPlugins } from './composer-plugins/load-composer-plugins';\n\n// Components\nimport { MessageItemComponent } from './components/message/message-item.component';\nimport { MessageListComponent } from './components/message/message-list.component';\nimport { MessageInputComponent } from './components/message/message-input.component';\nimport { DynamicFormsModule } from '@memberjunction/ng-forms';\nimport { ActionableCommandsComponent } from './components/message/actionable-commands.component';\nimport { WorkflowPlanCardComponent } from './components/message/workflow-plan-card.component';\nimport { TaskGraphEditorModule } from '@memberjunction/ng-task-graph-editor';\nimport { ConversationMessageRatingComponent } from './components/message/conversation-message-rating.component';\nimport { ConversationWorkspaceComponent } from './components/workspace/conversation-workspace.component';\nimport { ConversationNavigationComponent } from './components/navigation/conversation-navigation.component';\nimport { ConversationSidebarComponent } from './components/sidebar/conversation-sidebar.component';\nimport { RoutinesSectionComponent } from './components/sidebar/routines-section.component';\nimport { ConversationListComponent } from './components/conversation/conversation-list.component';\nimport { ConversationChatAreaComponent } from './components/conversation/conversation-chat-area.component';\nimport { ConversationEmptyStateComponent } from './components/conversation/conversation-empty-state.component';\nimport { ConversationAgentPickerComponent } from './components/conversation/conversation-agent-picker.component';\nimport { ConversationModePickerComponent } from './components/conversation/conversation-mode-picker.component';\nimport { ThreadPanelComponent } from './components/thread/thread-panel.component';\nimport { CollectionTreeComponent } from './components/collection/collection-tree.component';\nimport { CollectionViewComponent } from './components/collection/collection-view.component';\nimport { CollectionArtifactCardComponent } from './components/collection/collection-artifact-card.component';\nimport { LibraryFullViewComponent } from './components/library/library-full-view.component';\nimport { CollectionFormModalComponent } from './components/collection/collection-form-modal.component';\nimport { ArtifactCreateModalComponent } from './components/collection/artifact-create-modal.component';\nimport { CollectionsFullViewComponent } from './components/collection/collections-full-view.component';\nimport { ProjectSelectorComponent } from './components/project/project-selector.component';\nimport { ProjectFormModalComponent } from './components/project/project-form-modal.component';\nimport { TasksFullViewComponent } from './components/task/tasks-full-view.component';\nimport { TasksDropdownComponent } from './components/tasks/tasks-dropdown.component';\nimport { TaskWidgetComponent } from './components/tasks/task-widget.component';\nimport { AgentProcessPanelComponent } from './components/agent/agent-process-panel.component';\nimport { ActiveAgentIndicatorComponent } from './components/agent/active-agent-indicator.component';\nimport { ActiveTasksPanelComponent } from './components/active-tasks/active-tasks-panel.component';\nimport { ShareModalComponent } from './components/share/share-modal.component';\nimport { MembersModalComponent } from './components/members/members-modal.component';\nimport { ExportModalComponent } from './components/export/export-modal.component';\nimport { SearchPanelComponent } from './components/search/search-panel.component';\nimport { NotificationBadgeComponent } from './components/notification/notification-badge.component';\nimport { ActivityIndicatorComponent } from './components/notification/activity-indicator.component';\nimport { ToastComponent } from './components/toast/toast.component';\nimport { InputDialogComponent } from './components/dialogs/input-dialog.component';\nimport { RatingDialogComponent } from './components/dialogs/rating-dialog.component';\nimport { CollectionShareModalComponent } from './components/collection/collection-share-modal.component';\nimport { UserPickerComponent } from './components/shared/user-picker.component';\nimport { ArtifactCollectionPickerModalComponent } from './components/collection/artifact-collection-picker-modal.component';\nimport { ArtifactShareModalComponent } from './components/artifact/artifact-share-modal.component';\nimport { GlobalTasksPanelComponent } from './components/global-tasks/global-tasks-panel.component';\nimport { ImageViewerComponent } from './components/attachment/image-viewer.component';\nimport { PinnedMessagesPanelComponent } from './components/conversation/pinned-messages-panel.component';\nimport { ChatAgentsOverlayComponent } from './components/overlay/chat-overlay.component';\nimport { RealtimeAgentPickerComponent } from './components/realtime/realtime-agent-picker.component';\nimport { RealtimeSessionOverlayComponent } from './components/realtime/realtime-session-overlay.component';\nimport { RealtimeWhiteboardHostComponent } from '@memberjunction/ng-whiteboard';\nimport { LoadRealtimeWhiteboardChannel } from './components/realtime/whiteboard/whiteboard-channel';\nimport { LoadWhiteboardArtifactViewer } from './components/realtime/whiteboard/whiteboard-artifact-viewer.component';\nimport { LoadRealtimeRemoteBrowserChannel } from './components/realtime/remote-browser/remote-browser-channel';\nimport { RemoteBrowserSurfaceComponent } from './components/realtime/remote-browser/remote-browser-surface.component';\nimport { LoadRealtimeMediaChannel } from './components/realtime/media/media-channel';\nimport { LoadClientContextChannel } from './components/realtime/channels/client-context-channel';\nimport { RealtimeMediaSurfaceComponent } from './components/realtime/media/realtime-media-surface.component';\nimport { RealtimeEvidencePlaybackComponent } from './components/realtime/evidence-playback/realtime-evidence-playback.component';\n\n// Directives\nimport { SearchShortcutDirective } from './directives/search-shortcut.directive';\n\n// PR 2c — Widget extension surface (standalone)\nimport { ChatSlotDirective } from './directives/chat-slot.directive';\nimport { MJChatEmptyStateDefaultComponent } from './components/slots/mj-chat-empty-state-default.component';\nimport { MJChatAgentPresenceDefaultComponent } from './components/slots/mj-chat-agent-presence-default.component';\nimport { MJChatHeaderDefaultComponent } from './components/slots/mj-chat-header-default.component';\nimport { MJChatMessageExtraDefaultComponent } from './components/slots/mj-chat-message-extra-default.component';\nimport { MJChatDemonstrationSurfaceDefaultComponent } from './components/slots/mj-chat-demonstration-surface-default.component';\nimport { MJChatMessageBubbleDefaultComponent } from './components/slots/mj-chat-message-bubble-default.component';\n\n// Tree-shaking prevention for interactive-channel CLIENT PLUGINS: they are resolved\n// dynamically through the MJ ClassFactory (keyed by the `MJ: AI Agent Channels` registry's\n// ClientPluginClass), so these static calls are what keep their @RegisterClass side effects\n// from being eliminated by the bundler. They live here (not in RealtimeSessionService) because\n// channel plugins carry Angular surface components — the service stays component-free.\nLoadRealtimeWhiteboardChannel();\n// Remote Browser channel plugin — same registry-driven resolution (ClientPluginClass\n// 'RealtimeRemoteBrowserChannel'); the static call defeats tree-shaking of its @RegisterClass.\nLoadRealtimeRemoteBrowserChannel();\n// Media channel plugin — same registry-driven resolution (ClientPluginClass\n// 'RealtimeMediaChannel'); the static call defeats tree-shaking of its @RegisterClass.\nLoadRealtimeMediaChannel();\nLoadClientContextChannel();\n// Whiteboard ARTIFACT VIEWER plugin — resolved by the artifact plugin host via the\n// ClassFactory (keyed by the artifact type's DriverClass), same tree-shaking concern.\nLoadWhiteboardArtifactViewer();\n// Composer trigger-provider PLUGINS ('@' agent mentions, '#' record mentions, '/' skill\n// commands) — resolved via ClassFactory discovery by any mj-mention-editor without an\n// explicit provider list; the static call defeats tree-shaking of their @RegisterClass.\nLoadComposerPlugins();\n\n// Export all components (excluding standalone components)\nconst COMPONENTS = [\n MessageItemComponent,\n MessageListComponent,\n MessageInputComponent,\n AiComposerComponent,\n ActionableCommandsComponent,\n WorkflowPlanCardComponent,\n ConversationMessageRatingComponent,\n ConversationWorkspaceComponent,\n ConversationNavigationComponent,\n ConversationSidebarComponent,\n RoutinesSectionComponent,\n ConversationListComponent,\n ConversationChatAreaComponent,\n ConversationEmptyStateComponent,\n ConversationAgentPickerComponent,\n ConversationModePickerComponent,\n ThreadPanelComponent,\n CollectionTreeComponent,\n CollectionViewComponent,\n CollectionArtifactCardComponent,\n LibraryFullViewComponent,\n CollectionFormModalComponent,\n ArtifactCreateModalComponent,\n CollectionsFullViewComponent,\n ProjectSelectorComponent,\n ProjectFormModalComponent,\n // TasksFullViewComponent - now standalone, imported below\n TasksDropdownComponent,\n TaskWidgetComponent,\n AgentProcessPanelComponent,\n ActiveAgentIndicatorComponent,\n ActiveTasksPanelComponent,\n ShareModalComponent,\n MembersModalComponent,\n ExportModalComponent,\n SearchPanelComponent,\n NotificationBadgeComponent,\n ActivityIndicatorComponent,\n ToastComponent,\n InputDialogComponent,\n RatingDialogComponent,\n GlobalTasksPanelComponent,\n ImageViewerComponent,\n PinnedMessagesPanelComponent,\n ChatAgentsOverlayComponent\n];\n\n@NgModule({\n declarations: [\n ...COMPONENTS,\n SearchShortcutDirective\n ],\n imports: [\n CommonModule,\n FormsModule,\n TaskGraphEditorModule,\n ReactiveFormsModule,\n OverlayModule,\n MJButtonDirective,\n MJDatepickerComponent,\n MJDialogComponent,\n MJDialogActionsComponent,\n MJEmptyStateComponent,\n MJAlertComponent,\n MJAccordionModule,\n ContainerDirectivesModule,\n CodeEditorModule,\n ArtifactsModule,\n TestingModule,\n SharedGenericModule,\n UserRoutinesModule,\n ComposerModule,\n MarkdownModule,\n DynamicFormsModule,\n ResourcePermissionsModule,\n // Standalone components\n TasksFullViewComponent,\n CollectionShareModalComponent,\n UserPickerComponent,\n ArtifactCollectionPickerModalComponent,\n ArtifactShareModalComponent,\n // PR 2c — Widget extension surface (standalone)\n ChatSlotDirective,\n MJChatEmptyStateDefaultComponent,\n MJChatAgentPresenceDefaultComponent,\n MJChatHeaderDefaultComponent,\n MJChatMessageExtraDefaultComponent,\n MJChatDemonstrationSurfaceDefaultComponent,\n MJChatMessageBubbleDefaultComponent,\n // Realtime / voice (PR #2787)\n RealtimeAgentPickerComponent,\n RealtimeSessionOverlayComponent,\n RealtimeWhiteboardHostComponent,\n RemoteBrowserSurfaceComponent,\n RealtimeMediaSurfaceComponent,\n RealtimeEvidencePlaybackComponent\n ],\n exports: [\n ...COMPONENTS,\n SearchShortcutDirective,\n // Composer components (mj-mention-editor / mj-mention-dropdown / mj-message-input-box)\n // remain available to consumers of this module's template surface\n ComposerModule,\n // Standalone components\n TasksFullViewComponent,\n // PR 2c — Widget extension surface\n ChatSlotDirective,\n MJChatEmptyStateDefaultComponent,\n MJChatAgentPresenceDefaultComponent,\n MJChatHeaderDefaultComponent,\n MJChatMessageExtraDefaultComponent,\n MJChatDemonstrationSurfaceDefaultComponent,\n MJChatMessageBubbleDefaultComponent,\n // Realtime / voice (PR #2787)\n RealtimeAgentPickerComponent,\n RealtimeSessionOverlayComponent,\n RealtimeWhiteboardHostComponent,\n RemoteBrowserSurfaceComponent,\n RealtimeMediaSurfaceComponent,\n RealtimeEvidencePlaybackComponent\n ]\n})\nexport class ConversationsModule { }"]}
1
+ {"version":3,"file":"conversations.module.js","sourceRoot":"","sources":["../../src/lib/conversations.module.ts"],"names":[],"mappings":"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","sourcesContent":["import { NgModule } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { FormsModule, ReactiveFormsModule } from '@angular/forms';\nimport { OverlayModule } from '@angular/cdk/overlay';\n\n// MJ UI Components\nimport { MJButtonDirective, MJDatepickerComponent, MJDialogComponent, MJDialogActionsComponent, MJEmptyStateComponent, MJAlertComponent, MJAccordionModule } from '@memberjunction/ng-ui-components';\n\n// MemberJunction modules\nimport { ContainerDirectivesModule } from '@memberjunction/ng-container-directives';\nimport { CodeEditorModule } from '@memberjunction/ng-code-editor';\nimport { ArtifactsModule } from '@memberjunction/ng-artifacts';\nimport { TestingModule } from '@memberjunction/ng-testing';\nimport { SharedGenericModule } from '@memberjunction/ng-shared-generic';\nimport { UserRoutinesModule } from '@memberjunction/ng-user-routines';\n\n// Markdown module\nimport { MarkdownModule } from '@memberjunction/ng-markdown';\n\n// Resource permissions (generic share dialog)\nimport { ResourcePermissionsModule } from '@memberjunction/ng-resource-permissions';\n\n// Composer (mention editor + dropdown + message input box) — extracted to @memberjunction/ng-composer\nimport { ComposerModule } from '@memberjunction/ng-composer';\n\n// AI-aware composer wrapper (agent/record/skill trigger plugins built in)\nimport { AiComposerComponent } from './components/composer/ai-composer.component';\nimport { LoadComposerPlugins } from './composer-plugins/load-composer-plugins';\n\n// Components\nimport { MessageItemComponent } from './components/message/message-item.component';\nimport { MessageListComponent } from './components/message/message-list.component';\nimport { MessageInputComponent } from './components/message/message-input.component';\nimport { DynamicFormsModule } from '@memberjunction/ng-forms';\nimport { ActionableCommandsComponent } from './components/message/actionable-commands.component';\nimport { WorkflowPlanCardComponent } from './components/message/workflow-plan-card.component';\nimport { TaskGraphEditorModule } from '@memberjunction/ng-task-graph-editor';\nimport { ConversationMessageRatingComponent } from './components/message/conversation-message-rating.component';\nimport { ConversationWorkspaceComponent } from './components/workspace/conversation-workspace.component';\nimport { ConversationNavigationComponent } from './components/navigation/conversation-navigation.component';\nimport { ConversationSidebarComponent } from './components/sidebar/conversation-sidebar.component';\nimport { RoutinesSectionComponent } from './components/sidebar/routines-section.component';\nimport { ConversationListComponent } from './components/conversation/conversation-list.component';\nimport { ConversationChatAreaComponent } from './components/conversation/conversation-chat-area.component';\nimport { ConversationEmptyStateComponent } from './components/conversation/conversation-empty-state.component';\nimport { ConversationAgentPickerComponent } from './components/conversation/conversation-agent-picker.component';\nimport { ConversationModePickerComponent } from './components/conversation/conversation-mode-picker.component';\nimport { ThreadPanelComponent } from './components/thread/thread-panel.component';\nimport { CollectionTreeComponent } from './components/collection/collection-tree.component';\nimport { CollectionViewComponent } from './components/collection/collection-view.component';\nimport { CollectionArtifactCardComponent } from './components/collection/collection-artifact-card.component';\nimport { LibraryFullViewComponent } from './components/library/library-full-view.component';\nimport { CollectionFormModalComponent } from './components/collection/collection-form-modal.component';\nimport { ArtifactCreateModalComponent } from './components/collection/artifact-create-modal.component';\nimport { CollectionsFullViewComponent } from './components/collection/collections-full-view.component';\nimport { ProjectSelectorComponent } from './components/project/project-selector.component';\nimport { ProjectFormModalComponent } from './components/project/project-form-modal.component';\nimport { TasksFullViewComponent } from './components/task/tasks-full-view.component';\nimport { TasksDropdownComponent } from './components/tasks/tasks-dropdown.component';\nimport { TaskWidgetComponent } from './components/tasks/task-widget.component';\nimport { AgentProcessPanelComponent } from './components/agent/agent-process-panel.component';\nimport { ActiveAgentIndicatorComponent } from './components/agent/active-agent-indicator.component';\nimport { ActiveTasksPanelComponent } from './components/active-tasks/active-tasks-panel.component';\nimport { ShareModalComponent } from './components/share/share-modal.component';\nimport { MembersModalComponent } from './components/members/members-modal.component';\nimport { ExportModalComponent } from './components/export/export-modal.component';\nimport { SearchPanelComponent } from './components/search/search-panel.component';\nimport { NotificationBadgeComponent } from './components/notification/notification-badge.component';\nimport { ActivityIndicatorComponent } from './components/notification/activity-indicator.component';\nimport { ToastComponent } from './components/toast/toast.component';\nimport { InputDialogComponent } from './components/dialogs/input-dialog.component';\nimport { RatingDialogComponent } from './components/dialogs/rating-dialog.component';\nimport { CollectionShareModalComponent } from './components/collection/collection-share-modal.component';\nimport { UserPickerComponent } from './components/shared/user-picker.component';\nimport { ArtifactCollectionPickerModalComponent } from './components/collection/artifact-collection-picker-modal.component';\nimport { ArtifactShareModalComponent } from './components/artifact/artifact-share-modal.component';\nimport { GlobalTasksPanelComponent } from './components/global-tasks/global-tasks-panel.component';\nimport { ImageViewerComponent } from './components/attachment/image-viewer.component';\nimport { PinnedMessagesPanelComponent } from './components/conversation/pinned-messages-panel.component';\nimport { ChatAgentsOverlayComponent } from './components/overlay/chat-overlay.component';\nimport { RealtimeAgentPickerComponent } from './components/realtime/realtime-agent-picker.component';\nimport { RealtimeSessionOverlayComponent } from './components/realtime/realtime-session-overlay.component';\nimport { RealtimeWhiteboardHostComponent } from '@memberjunction/ng-whiteboard';\nimport { LoadRealtimeWhiteboardChannel } from './components/realtime/whiteboard/whiteboard-channel';\nimport { LoadWhiteboardArtifactViewer } from './components/realtime/whiteboard/whiteboard-artifact-viewer.component';\nimport { LoadRealtimeRemoteBrowserChannel } from './components/realtime/remote-browser/remote-browser-channel';\nimport { RemoteBrowserSurfaceComponent } from './components/realtime/remote-browser/remote-browser-surface.component';\nimport { LoadRealtimeMediaChannel } from './components/realtime/media/media-channel';\nimport { LoadClientContextChannel } from './components/realtime/channels/client-context-channel';\nimport { RealtimeMediaSurfaceComponent } from './components/realtime/media/realtime-media-surface.component';\nimport { RealtimeEvidencePlaybackComponent } from './components/realtime/evidence-playback/realtime-evidence-playback.component';\n\n// Directives\nimport { SearchShortcutDirective } from './directives/search-shortcut.directive';\n\n// PR 2c — Widget extension surface (standalone)\nimport { ChatSlotDirective } from './directives/chat-slot.directive';\nimport { MJChatEmptyStateDefaultComponent } from './components/slots/mj-chat-empty-state-default.component';\nimport { MJChatAgentPresenceDefaultComponent } from './components/slots/mj-chat-agent-presence-default.component';\nimport { MJChatHeaderDefaultComponent } from './components/slots/mj-chat-header-default.component';\nimport { MJChatMessageExtraDefaultComponent } from './components/slots/mj-chat-message-extra-default.component';\nimport { MJChatDemonstrationSurfaceDefaultComponent } from './components/slots/mj-chat-demonstration-surface-default.component';\nimport { MJChatMessageBubbleDefaultComponent } from './components/slots/mj-chat-message-bubble-default.component';\n\n// Tree-shaking prevention for interactive-channel CLIENT PLUGINS: they are resolved\n// dynamically through the MJ ClassFactory (keyed by the `MJ: AI Agent Channels` registry's\n// ClientPluginClass), so these static calls are what keep their @RegisterClass side effects\n// from being eliminated by the bundler. They live here (not in RealtimeSessionService) because\n// channel plugins carry Angular surface components — the service stays component-free.\nLoadRealtimeWhiteboardChannel();\n// Remote Browser channel plugin — same registry-driven resolution (ClientPluginClass\n// 'RealtimeRemoteBrowserChannel'); the static call defeats tree-shaking of its @RegisterClass.\nLoadRealtimeRemoteBrowserChannel();\n// Media channel plugin — same registry-driven resolution (ClientPluginClass\n// 'RealtimeMediaChannel'); the static call defeats tree-shaking of its @RegisterClass.\nLoadRealtimeMediaChannel();\nLoadClientContextChannel();\n// Whiteboard ARTIFACT VIEWER plugin — resolved by the artifact plugin host via the\n// ClassFactory (keyed by the artifact type's DriverClass), same tree-shaking concern.\nLoadWhiteboardArtifactViewer();\n// Composer trigger-provider PLUGINS ('@' agent mentions, '#' record mentions, '/' skill\n// commands) — resolved via ClassFactory discovery by any mj-mention-editor without an\n// explicit provider list; the static call defeats tree-shaking of their @RegisterClass.\nLoadComposerPlugins();\n\n// Export all components (excluding standalone components)\nconst COMPONENTS = [\n MessageItemComponent,\n MessageListComponent,\n MessageInputComponent,\n AiComposerComponent,\n ActionableCommandsComponent,\n WorkflowPlanCardComponent,\n ConversationMessageRatingComponent,\n ConversationWorkspaceComponent,\n ConversationNavigationComponent,\n ConversationSidebarComponent,\n RoutinesSectionComponent,\n ConversationListComponent,\n ConversationChatAreaComponent,\n ConversationEmptyStateComponent,\n ConversationAgentPickerComponent,\n ConversationModePickerComponent,\n ThreadPanelComponent,\n CollectionTreeComponent,\n CollectionViewComponent,\n CollectionArtifactCardComponent,\n LibraryFullViewComponent,\n CollectionFormModalComponent,\n ArtifactCreateModalComponent,\n CollectionsFullViewComponent,\n ProjectSelectorComponent,\n ProjectFormModalComponent,\n // TasksFullViewComponent - now standalone, imported below\n TasksDropdownComponent,\n TaskWidgetComponent,\n AgentProcessPanelComponent,\n ActiveAgentIndicatorComponent,\n ActiveTasksPanelComponent,\n ShareModalComponent,\n MembersModalComponent,\n ExportModalComponent,\n SearchPanelComponent,\n NotificationBadgeComponent,\n ActivityIndicatorComponent,\n ToastComponent,\n InputDialogComponent,\n RatingDialogComponent,\n GlobalTasksPanelComponent,\n ImageViewerComponent,\n PinnedMessagesPanelComponent,\n ChatAgentsOverlayComponent\n];\n\n@NgModule({\n declarations: [\n ...COMPONENTS,\n SearchShortcutDirective\n ],\n imports: [\n CommonModule,\n FormsModule,\n TaskGraphEditorModule,\n ReactiveFormsModule,\n OverlayModule,\n MJButtonDirective,\n MJDatepickerComponent,\n MJDialogComponent,\n MJDialogActionsComponent,\n MJEmptyStateComponent,\n MJAlertComponent,\n MJAccordionModule,\n ContainerDirectivesModule,\n CodeEditorModule,\n ArtifactsModule,\n TestingModule,\n SharedGenericModule,\n UserRoutinesModule,\n ComposerModule,\n MarkdownModule,\n DynamicFormsModule,\n ResourcePermissionsModule,\n // Standalone components\n TasksFullViewComponent,\n CollectionShareModalComponent,\n UserPickerComponent,\n ArtifactCollectionPickerModalComponent,\n ArtifactShareModalComponent,\n // PR 2c — Widget extension surface (standalone)\n ChatSlotDirective,\n MJChatEmptyStateDefaultComponent,\n MJChatAgentPresenceDefaultComponent,\n MJChatHeaderDefaultComponent,\n MJChatMessageExtraDefaultComponent,\n MJChatDemonstrationSurfaceDefaultComponent,\n MJChatMessageBubbleDefaultComponent,\n // Realtime / voice (PR #2787)\n RealtimeAgentPickerComponent,\n RealtimeSessionOverlayComponent,\n RealtimeWhiteboardHostComponent,\n RemoteBrowserSurfaceComponent,\n RealtimeMediaSurfaceComponent,\n RealtimeEvidencePlaybackComponent\n ],\n exports: [\n ...COMPONENTS,\n SearchShortcutDirective,\n // Composer components (mj-mention-editor / mj-mention-dropdown / mj-message-input-box)\n // remain available to consumers of this module's template surface\n ComposerModule,\n // Standalone components\n TasksFullViewComponent,\n // PR 2c — Widget extension surface\n ChatSlotDirective,\n MJChatEmptyStateDefaultComponent,\n MJChatAgentPresenceDefaultComponent,\n MJChatHeaderDefaultComponent,\n MJChatMessageExtraDefaultComponent,\n MJChatDemonstrationSurfaceDefaultComponent,\n MJChatMessageBubbleDefaultComponent,\n // Realtime / voice (PR #2787)\n RealtimeAgentPickerComponent,\n RealtimeSessionOverlayComponent,\n RealtimeWhiteboardHostComponent,\n RemoteBrowserSurfaceComponent,\n RealtimeMediaSurfaceComponent,\n RealtimeEvidencePlaybackComponent\n ]\n})\nexport class ConversationsModule {}"]}
@@ -0,0 +1,24 @@
1
+ import { IRealtimeMediaHost, IRealtimeSessionRecorder } from '@memberjunction/realtime-runtime';
2
+ /**
3
+ * The browser's implementation of the realtime runtime's media seam.
4
+ *
5
+ * Everything here is the half of a realtime session that genuinely *is* platform-specific:
6
+ * how the microphone is requested, and how captured audio becomes bytes we can upload. The
7
+ * orchestration around it — mint, connect, transcripts, tools, narration, channels, teardown —
8
+ * lives in `@memberjunction/realtime-runtime` and is identical on every host.
9
+ */
10
+ export declare class BrowserRealtimeMediaHost implements IRealtimeMediaHost {
11
+ /**
12
+ * Requests the microphone through the standard Web API, which surfaces the browser's own
13
+ * permission prompt. A denial rejects, and the runtime treats that as a failed session start.
14
+ */
15
+ AcquireMicrophone(): Promise<MediaStream>;
16
+ /**
17
+ * Wraps the browser recorder so the runtime never sees a `Blob`.
18
+ *
19
+ * Returns `null` when the platform cannot record, which the runtime treats as "recording is
20
+ * simply off" rather than an error — recording is consent-gated and optional by design.
21
+ */
22
+ CreateRecorder(): IRealtimeSessionRecorder | null;
23
+ }
24
+ //# sourceMappingURL=browser-realtime-media-host.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-realtime-media-host.d.ts","sourceRoot":"","sources":["../../../src/lib/services/browser-realtime-media-host.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,kBAAkB,EAClB,wBAAwB,EAC3B,MAAM,kCAAkC,CAAC;AAG1C;;;;;;;GAOG;AACH,qBAAa,wBAAyB,YAAW,kBAAkB;IAC/D;;;OAGG;IACU,iBAAiB,IAAI,OAAO,CAAC,WAAW,CAAC;IAItD;;;;;OAKG;IACI,cAAc,IAAI,wBAAwB,GAAG,IAAI;CAG3D"}
@@ -0,0 +1,95 @@
1
+ import { RealtimeAudioRecorder } from './realtime-audio-recorder';
2
+ /**
3
+ * The browser's implementation of the realtime runtime's media seam.
4
+ *
5
+ * Everything here is the half of a realtime session that genuinely *is* platform-specific:
6
+ * how the microphone is requested, and how captured audio becomes bytes we can upload. The
7
+ * orchestration around it — mint, connect, transcripts, tools, narration, channels, teardown —
8
+ * lives in `@memberjunction/realtime-runtime` and is identical on every host.
9
+ */
10
+ export class BrowserRealtimeMediaHost {
11
+ /**
12
+ * Requests the microphone through the standard Web API, which surfaces the browser's own
13
+ * permission prompt. A denial rejects, and the runtime treats that as a failed session start.
14
+ */
15
+ async AcquireMicrophone() {
16
+ return navigator.mediaDevices.getUserMedia({ audio: true });
17
+ }
18
+ /**
19
+ * Wraps the browser recorder so the runtime never sees a `Blob`.
20
+ *
21
+ * Returns `null` when the platform cannot record, which the runtime treats as "recording is
22
+ * simply off" rather than an error — recording is consent-gated and optional by design.
23
+ */
24
+ CreateRecorder() {
25
+ return new BrowserRealtimeSessionRecorder(new RealtimeAudioRecorder());
26
+ }
27
+ }
28
+ /**
29
+ * Adapts {@link RealtimeAudioRecorder} (which speaks `Blob`, because that is what `MediaRecorder`
30
+ * and the Web Audio API hand you) to the runtime's byte-agnostic recorder contract.
31
+ *
32
+ * The base64 encoding that used to sit in the session service lives here now. That is the correct
33
+ * home for it: a browser reaches for `FileReader`, React Native reads a file off disk, and a test
34
+ * harness holds bytes in memory — three different answers to a question the orchestration layer
35
+ * should never have been asking.
36
+ */
37
+ class BrowserRealtimeSessionRecorder {
38
+ recorder;
39
+ constructor(recorder) {
40
+ this.recorder = recorder;
41
+ }
42
+ get IsRecording() {
43
+ return this.recorder.IsRecording;
44
+ }
45
+ get SampleRate() {
46
+ return this.recorder.SampleRate;
47
+ }
48
+ get MimeType() {
49
+ return this.recorder.MimeType;
50
+ }
51
+ Start(micStream, remoteStream) {
52
+ this.recorder.Start(micStream, remoteStream);
53
+ }
54
+ AttachRemoteStream(stream) {
55
+ this.recorder.AttachRemoteStream(stream);
56
+ }
57
+ NowOffsetMs() {
58
+ return this.recorder.NowOffsetMs();
59
+ }
60
+ GetPeaks() {
61
+ return this.recorder.GetPeaks();
62
+ }
63
+ async SnapshotNewSegmentBase64() {
64
+ const segment = this.recorder.SnapshotNewSegment();
65
+ if (!segment || segment.size === 0) {
66
+ return null;
67
+ }
68
+ return this.blobToBase64(segment);
69
+ }
70
+ async StopAndEncode() {
71
+ const blob = await this.recorder.Stop();
72
+ if (!blob || blob.size === 0) {
73
+ return null;
74
+ }
75
+ return this.blobToBase64(blob);
76
+ }
77
+ /**
78
+ * Encodes a {@link Blob} as base64 with the `data:` prefix stripped, via {@link FileReader}.
79
+ * Resolves to `null` rather than rejecting — a failed encode costs us the recording, never
80
+ * the live call.
81
+ */
82
+ blobToBase64(blob) {
83
+ return new Promise((resolve) => {
84
+ const reader = new FileReader();
85
+ reader.onloadend = () => {
86
+ const result = typeof reader.result === 'string' ? reader.result : '';
87
+ const comma = result.indexOf(',');
88
+ resolve(comma >= 0 ? result.slice(comma + 1) : null);
89
+ };
90
+ reader.onerror = () => resolve(null);
91
+ reader.readAsDataURL(blob);
92
+ });
93
+ }
94
+ }
95
+ //# sourceMappingURL=browser-realtime-media-host.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-realtime-media-host.js","sourceRoot":"","sources":["../../../src/lib/services/browser-realtime-media-host.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAElE;;;;;;;GAOG;AACH,MAAM,OAAO,wBAAwB;IACjC;;;OAGG;IACI,KAAK,CAAC,iBAAiB;QAC1B,OAAO,SAAS,CAAC,YAAY,CAAC,YAAY,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAChE,CAAC;IAED;;;;;OAKG;IACI,cAAc;QACjB,OAAO,IAAI,8BAA8B,CAAC,IAAI,qBAAqB,EAAE,CAAC,CAAC;IAC3E,CAAC;CACJ;AAED;;;;;;;;GAQG;AACH,MAAM,8BAA8B;IACH;IAA7B,YAA6B,QAA+B;QAA/B,aAAQ,GAAR,QAAQ,CAAuB;IAAG,CAAC;IAEhE,IAAW,WAAW;QAClB,OAAO,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC;IACrC,CAAC;IAED,IAAW,UAAU;QACjB,OAAO,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC;IACpC,CAAC;IAED,IAAW,QAAQ;QACf,OAAO,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC;IAClC,CAAC;IAEM,KAAK,CAAC,SAAsB,EAAE,YAAgC;QACjE,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;IACjD,CAAC;IAEM,kBAAkB,CAAC,MAAmB;QACzC,IAAI,CAAC,QAAQ,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC;IAC7C,CAAC;IAEM,WAAW;QACd,OAAO,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC;IACvC,CAAC;IAEM,QAAQ;QACX,OAAO,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC;IACpC,CAAC;IAEM,KAAK,CAAC,wBAAwB;QACjC,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,kBAAkB,EAAE,CAAC;QACnD,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YACjC,OAAO,IAAI,CAAC;QAChB,CAAC;QACD,OAAO,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;IACtC,CAAC;IAEM,KAAK,CAAC,aAAa;QACtB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;QACxC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YAC3B,OAAO,IAAI,CAAC;QAChB,CAAC;QACD,OAAO,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;IACnC,CAAC;IAED;;;;OAIG;IACK,YAAY,CAAC,IAAU;QAC3B,OAAO,IAAI,OAAO,CAAgB,CAAC,OAAO,EAAE,EAAE;YAC1C,MAAM,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;YAChC,MAAM,CAAC,SAAS,GAAG,GAAG,EAAE;gBACpB,MAAM,MAAM,GAAG,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;gBACtE,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;gBAClC,OAAO,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YACzD,CAAC,CAAC;YACF,MAAM,CAAC,OAAO,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YACrC,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;QAC/B,CAAC,CAAC,CAAC;IACP,CAAC;CACJ","sourcesContent":["import {\n IRealtimeMediaHost,\n IRealtimeSessionRecorder,\n} from '@memberjunction/realtime-runtime';\nimport { RealtimeAudioRecorder } from './realtime-audio-recorder';\n\n/**\n * The browser's implementation of the realtime runtime's media seam.\n *\n * Everything here is the half of a realtime session that genuinely *is* platform-specific:\n * how the microphone is requested, and how captured audio becomes bytes we can upload. The\n * orchestration around it — mint, connect, transcripts, tools, narration, channels, teardown —\n * lives in `@memberjunction/realtime-runtime` and is identical on every host.\n */\nexport class BrowserRealtimeMediaHost implements IRealtimeMediaHost {\n /**\n * Requests the microphone through the standard Web API, which surfaces the browser's own\n * permission prompt. A denial rejects, and the runtime treats that as a failed session start.\n */\n public async AcquireMicrophone(): Promise<MediaStream> {\n return navigator.mediaDevices.getUserMedia({ audio: true });\n }\n\n /**\n * Wraps the browser recorder so the runtime never sees a `Blob`.\n *\n * Returns `null` when the platform cannot record, which the runtime treats as \"recording is\n * simply off\" rather than an error — recording is consent-gated and optional by design.\n */\n public CreateRecorder(): IRealtimeSessionRecorder | null {\n return new BrowserRealtimeSessionRecorder(new RealtimeAudioRecorder());\n }\n}\n\n/**\n * Adapts {@link RealtimeAudioRecorder} (which speaks `Blob`, because that is what `MediaRecorder`\n * and the Web Audio API hand you) to the runtime's byte-agnostic recorder contract.\n *\n * The base64 encoding that used to sit in the session service lives here now. That is the correct\n * home for it: a browser reaches for `FileReader`, React Native reads a file off disk, and a test\n * harness holds bytes in memory — three different answers to a question the orchestration layer\n * should never have been asking.\n */\nclass BrowserRealtimeSessionRecorder implements IRealtimeSessionRecorder {\n constructor(private readonly recorder: RealtimeAudioRecorder) {}\n\n public get IsRecording(): boolean {\n return this.recorder.IsRecording;\n }\n\n public get SampleRate(): number {\n return this.recorder.SampleRate;\n }\n\n public get MimeType(): string {\n return this.recorder.MimeType;\n }\n\n public Start(micStream: MediaStream, remoteStream: MediaStream | null): void {\n this.recorder.Start(micStream, remoteStream);\n }\n\n public AttachRemoteStream(stream: MediaStream): void {\n this.recorder.AttachRemoteStream(stream);\n }\n\n public NowOffsetMs(): number {\n return this.recorder.NowOffsetMs();\n }\n\n public GetPeaks(): number[] {\n return this.recorder.GetPeaks();\n }\n\n public async SnapshotNewSegmentBase64(): Promise<string | null> {\n const segment = this.recorder.SnapshotNewSegment();\n if (!segment || segment.size === 0) {\n return null;\n }\n return this.blobToBase64(segment);\n }\n\n public async StopAndEncode(): Promise<string | null> {\n const blob = await this.recorder.Stop();\n if (!blob || blob.size === 0) {\n return null;\n }\n return this.blobToBase64(blob);\n }\n\n /**\n * Encodes a {@link Blob} as base64 with the `data:` prefix stripped, via {@link FileReader}.\n * Resolves to `null` rather than rejecting — a failed encode costs us the recording, never\n * the live call.\n */\n private blobToBase64(blob: Blob): Promise<string | null> {\n return new Promise<string | null>((resolve) => {\n const reader = new FileReader();\n reader.onloadend = () => {\n const result = typeof reader.result === 'string' ? reader.result : '';\n const comma = result.indexOf(',');\n resolve(comma >= 0 ? result.slice(comma + 1) : null);\n };\n reader.onerror = () => resolve(null);\n reader.readAsDataURL(blob);\n });\n }\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  import { UserInfo, IMetadataProvider } from '@memberjunction/core';
2
- import { MJConversationDetailAttachmentEntity } from '@memberjunction/core-entities';
2
+ import { MJConversationDetailAttachmentEntity, MJAIAgentEntity } from '@memberjunction/core-entities';
3
3
  import { MessageAttachment } from '../components/message/message-item.component';
4
4
  import { PendingAttachment } from '@memberjunction/ng-composer';
5
5
  import * as i0 from "@angular/core";
@@ -8,6 +8,23 @@ import * as i0 from "@angular/core";
8
8
  * Handles loading, saving, and converting attachments between different formats.
9
9
  */
10
10
  export declare class ConversationAttachmentService {
11
+ /**
12
+ * Where attachment bytes go when they are too large to store inline.
13
+ *
14
+ * Held directly rather than read off the shared `ConversationAttachmentService` in
15
+ * `@memberjunction/aiengine`. That package's entry point imports Node's `crypto`
16
+ * (`AIEngine.ts`, for an embedding-cache key), so a runtime import of it from here pulls the
17
+ * whole server AI engine into Explorer's browser bundle and the build fails to resolve `crypto`.
18
+ * The shared service is a server-side consumer of the same seam, not a dependency of this one.
19
+ *
20
+ * The seam's *type* used to be imported from there with `import type`, on the reasoning that an
21
+ * erased import costs nothing. It does at runtime — but the class-registration manifest generator
22
+ * walks **package.json**, so the declared dependency was a live edge regardless, and it later
23
+ * carried `@memberjunction/storage`'s drivers into the browser manifest. Both the contract and
24
+ * the placement policy (`ConversationUtility`) now come from `@memberjunction/ai-core-plus`, and
25
+ * this package does not declare `aiengine` at all.
26
+ */
27
+ private readonly blobStore;
11
28
  private _provider;
12
29
  constructor();
13
30
  /**
@@ -31,8 +48,13 @@ export declare class ConversationAttachmentService {
31
48
  * @param conversationDetailId - ID of the conversation detail to attach to
32
49
  * @param pendingAttachments - Array of pending attachments from the mention editor
33
50
  * @param contextUser - User context for the operation
51
+ * @param agent - The agent this turn is addressed to, when the caller has resolved one. Only its
52
+ * `InlineStorageThresholdBytes` is read, and only to make the inline-vs-storage decision match
53
+ * what the server would decide for the same file. Omitting it falls back to the system default,
54
+ * which is correct for a turn with no agent — but a caller that HAS an agent and does not pass
55
+ * it produces the cross-surface drift this shared policy exists to remove.
34
56
  */
35
- saveAttachments(conversationDetailId: string, pendingAttachments: PendingAttachment[], contextUser?: UserInfo): Promise<MJConversationDetailAttachmentEntity[]>;
57
+ saveAttachments(conversationDetailId: string, pendingAttachments: PendingAttachment[], contextUser?: UserInfo, agent?: MJAIAgentEntity | null): Promise<MJConversationDetailAttachmentEntity[]>;
36
58
  /**
37
59
  * Create attachment reference tokens for message text.
38
60
  * These tokens are stored in the Message field to reference attachments.
@@ -1 +1 @@
1
- {"version":3,"file":"conversation-attachment.service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/conversation-attachment.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAqB,QAAQ,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACtF,OAAO,EACL,oCAAoC,EAMrC,MAAM,+BAA+B,CAAC;AAMvC,OAAO,EAAE,iBAAiB,EAAE,MAAM,8CAA8C,CAAC;AACjF,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;;AAIhE;;;GAGG;AACH,qBAGa,6BAA6B;IACxC,OAAO,CAAC,SAAS,CAAkC;;IAInD;;OAEG;IACH,IAAW,QAAQ,CAAC,KAAK,EAAE,iBAAiB,GAAG,IAAI,EAElD;IAED,IAAW,QAAQ,IAAI,iBAAiB,CAEvC;IAED;;;OAGG;IACG,0BAA0B,CAC9B,qBAAqB,EAAE,MAAM,EAAE,EAC/B,WAAW,CAAC,EAAE,QAAQ,GACrB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,iBAAiB,EAAE,CAAC,CAAC;IA0F5C;;OAEG;IACG,yBAAyB,CAC7B,oBAAoB,EAAE,MAAM,EAC5B,WAAW,CAAC,EAAE,QAAQ,GACrB,OAAO,CAAC,iBAAiB,EAAE,CAAC;IAK/B;;;;;;;OAOG;IACG,eAAe,CACnB,oBAAoB,EAAE,MAAM,EAC5B,kBAAkB,EAAE,iBAAiB,EAAE,EACvC,WAAW,CAAC,EAAE,QAAQ,GACrB,OAAO,CAAC,oCAAoC,EAAE,CAAC;IA8ElD;;;OAGG;IACH,0BAA0B,CAAC,WAAW,EAAE,oCAAoC,EAAE,GAAG,MAAM;IAoBvF;;OAEG;IACH,OAAO,CAAC,0BAA0B;IAiClC;;OAEG;IACH,OAAO,CAAC,6BAA6B;IAYrC;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAO7B;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAyB5B;;OAEG;IACH,OAAO,CAAC,wBAAwB;IAKhC;;;OAGG;IACG,eAAe,CACnB,IAAI,EAAE,IAAI,EACV,OAAO,GAAE,MAAY,GACpB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IA+CzB;;OAEG;IACG,kBAAkB,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAqBvF;;;OAGG;IACG,WAAW,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,iBAAiB,CAAC;IA+BzD;;OAEG;IACH,OAAO,CAAC,aAAa;IASrB;;OAEG;IACH,OAAO,CAAC,cAAc;yCA/cX,6BAA6B;6CAA7B,6BAA6B;CAkdzC"}
1
+ {"version":3,"file":"conversation-attachment.service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/conversation-attachment.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAqB,QAAQ,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACtF,OAAO,EACL,oCAAoC,EAKpC,eAAe,EAEhB,MAAM,+BAA+B,CAAC;AASvC,OAAO,EAAE,iBAAiB,EAAE,MAAM,8CAA8C,CAAC;AACjF,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;;AAIhE;;;GAGG;AACH,qBAGa,6BAA6B;IACxC;;;;;;;;;;;;;;;OAeG;IACH,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA0D;IAEpF,OAAO,CAAC,SAAS,CAAkC;;IAInD;;OAEG;IACH,IAAW,QAAQ,CAAC,KAAK,EAAE,iBAAiB,GAAG,IAAI,EAElD;IAED,IAAW,QAAQ,IAAI,iBAAiB,CAEvC;IAED;;;OAGG;IACG,0BAA0B,CAC9B,qBAAqB,EAAE,MAAM,EAAE,EAC/B,WAAW,CAAC,EAAE,QAAQ,GACrB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,iBAAiB,EAAE,CAAC,CAAC;IA0F5C;;OAEG;IACG,yBAAyB,CAC7B,oBAAoB,EAAE,MAAM,EAC5B,WAAW,CAAC,EAAE,QAAQ,GACrB,OAAO,CAAC,iBAAiB,EAAE,CAAC;IAK/B;;;;;;;;;;;;OAYG;IACG,eAAe,CACnB,oBAAoB,EAAE,MAAM,EAC5B,kBAAkB,EAAE,iBAAiB,EAAE,EACvC,WAAW,CAAC,EAAE,QAAQ,EACtB,KAAK,CAAC,EAAE,eAAe,GAAG,IAAI,GAC7B,OAAO,CAAC,oCAAoC,EAAE,CAAC;IAwGlD;;;OAGG;IACH,0BAA0B,CAAC,WAAW,EAAE,oCAAoC,EAAE,GAAG,MAAM;IAoBvF;;OAEG;IACH,OAAO,CAAC,0BAA0B;IAiClC;;OAEG;IACH,OAAO,CAAC,6BAA6B;IAYrC;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAO7B;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAyB5B;;OAEG;IACH,OAAO,CAAC,wBAAwB;IAKhC;;;OAGG;IACG,eAAe,CACnB,IAAI,EAAE,IAAI,EACV,OAAO,GAAE,MAAY,GACpB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IA+CzB;;OAEG;IACG,kBAAkB,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAqBvF;;;OAGG;IACG,WAAW,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,iBAAiB,CAAC;IA+BzD;;OAEG;IACH,OAAO,CAAC,aAAa;IASrB;;OAEG;IACH,OAAO,CAAC,cAAc;yCAjgBX,6BAA6B;6CAA7B,6BAA6B;CAogBzC"}
@@ -1,7 +1,8 @@
1
1
  import { Injectable } from '@angular/core';
2
2
  import { RunView, Metadata } from '@memberjunction/core';
3
3
  import { ArtifactMetadataEngine } from '@memberjunction/core-entities';
4
- import { ConversationUtility } from '@memberjunction/ai-core-plus';
4
+ import { ConversationUtility, DEFAULT_INLINE_STORAGE_THRESHOLD_BYTES } from '@memberjunction/ai-core-plus';
5
+ import { GraphQLAttachmentBlobStore } from './graphql-attachment-blob-store';
5
6
  import { AIEngineBase } from '@memberjunction/ai-engine-base';
6
7
  import { UUIDsEqual } from '@memberjunction/global';
7
8
  import * as i0 from "@angular/core";
@@ -10,6 +11,23 @@ import * as i0 from "@angular/core";
10
11
  * Handles loading, saving, and converting attachments between different formats.
11
12
  */
12
13
  export class ConversationAttachmentService {
14
+ /**
15
+ * Where attachment bytes go when they are too large to store inline.
16
+ *
17
+ * Held directly rather than read off the shared `ConversationAttachmentService` in
18
+ * `@memberjunction/aiengine`. That package's entry point imports Node's `crypto`
19
+ * (`AIEngine.ts`, for an embedding-cache key), so a runtime import of it from here pulls the
20
+ * whole server AI engine into Explorer's browser bundle and the build fails to resolve `crypto`.
21
+ * The shared service is a server-side consumer of the same seam, not a dependency of this one.
22
+ *
23
+ * The seam's *type* used to be imported from there with `import type`, on the reasoning that an
24
+ * erased import costs nothing. It does at runtime — but the class-registration manifest generator
25
+ * walks **package.json**, so the declared dependency was a live edge regardless, and it later
26
+ * carried `@memberjunction/storage`'s drivers into the browser manifest. Both the contract and
27
+ * the placement policy (`ConversationUtility`) now come from `@memberjunction/ai-core-plus`, and
28
+ * this package does not declare `aiengine` at all.
29
+ */
30
+ blobStore = new GraphQLAttachmentBlobStore();
13
31
  _provider = null;
14
32
  constructor() { }
15
33
  /**
@@ -121,8 +139,13 @@ export class ConversationAttachmentService {
121
139
  * @param conversationDetailId - ID of the conversation detail to attach to
122
140
  * @param pendingAttachments - Array of pending attachments from the mention editor
123
141
  * @param contextUser - User context for the operation
142
+ * @param agent - The agent this turn is addressed to, when the caller has resolved one. Only its
143
+ * `InlineStorageThresholdBytes` is read, and only to make the inline-vs-storage decision match
144
+ * what the server would decide for the same file. Omitting it falls back to the system default,
145
+ * which is correct for a turn with no agent — but a caller that HAS an agent and does not pass
146
+ * it produces the cross-surface drift this shared policy exists to remove.
124
147
  */
125
- async saveAttachments(conversationDetailId, pendingAttachments, contextUser) {
148
+ async saveAttachments(conversationDetailId, pendingAttachments, contextUser, agent) {
126
149
  const savedAttachments = [];
127
150
  const rejectionMessages = [];
128
151
  const md = this.Provider;
@@ -155,10 +178,26 @@ export class ConversationAttachmentService {
155
178
  }
156
179
  continue; // Skip creating a ConversationDetailAttachment for artifacts
157
180
  }
158
- // Store inline data for uploaded files
181
+ // Storage placement is NOT this service's decision. `ConversationUtility.ShouldStoreInline`
182
+ // owns it — honouring an agent's `InlineStorageThresholdBytes` before the system default —
183
+ // and it is the same call the server and the mobile app make. This service previously set
184
+ // `InlineData` unconditionally, so a large image went into a database column instead of
185
+ // MJStorage, contradicting the entity's own contract that the two are mutually exclusive
186
+ // and sized.
159
187
  if (pending.dataUrl) {
160
188
  const base64Data = this.extractBase64FromDataUrl(pending.dataUrl);
161
- attachment.InlineData = base64Data;
189
+ const storeInline = ConversationUtility.ShouldStoreInline(pending.sizeBytes, agent?.InlineStorageThresholdBytes ?? null, DEFAULT_INLINE_STORAGE_THRESHOLD_BYTES);
190
+ if (storeInline) {
191
+ attachment.InlineData = base64Data;
192
+ }
193
+ else {
194
+ const stored = await this.blobStore.Upload({ FileName: pending.fileName, MimeType: pending.mimeType, Base64Data: base64Data }, contextUser ?? md.CurrentUser, md);
195
+ if (!stored?.Success || !stored.FileID) {
196
+ rejectionMessages.push(`Attachment "${pending.fileName}" is too large to store inline and could not be uploaded: ${stored?.Error ?? 'storage is not available.'}`);
197
+ continue;
198
+ }
199
+ attachment.FileID = stored.FileID;
200
+ }
162
201
  }
163
202
  const saved = await attachment.Save();
164
203
  if (saved) {
@@ -1 +1 @@
1
- {"version":3,"file":"conversation-attachment.service.js","sourceRoot":"","sources":["../../../src/lib/services/conversation-attachment.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { Injectable } from '@angular/core';\nimport { RunView, Metadata, UserInfo, IMetadataProvider } from '@memberjunction/core';\nimport {\n MJConversationDetailAttachmentEntity,\n MJConversationDetailArtifactEntity,\n MJArtifactVersionEntity,\n MJArtifactEntity,\n MJAIModalityEntity,\n ArtifactMetadataEngine\n} from '@memberjunction/core-entities';\nimport {\n ConversationUtility,\n AttachmentContent,\n AttachmentType\n} from '@memberjunction/ai-core-plus';\nimport { MessageAttachment } from '../components/message/message-item.component';\nimport { PendingAttachment } from '@memberjunction/ng-composer';\nimport { AIEngineBase } from '@memberjunction/ai-engine-base';\nimport { UUIDsEqual } from '@memberjunction/global';\n\n/**\n * Service for managing conversation attachments.\n * Handles loading, saving, and converting attachments between different formats.\n */\n@Injectable({\n providedIn: 'root'\n})\nexport class ConversationAttachmentService {\n private _provider: IMetadataProvider | null = null;\n\n constructor() {}\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 * Load all attachments for a list of conversation detail IDs.\n * Returns a map of ConversationDetailID -> MessageAttachment[]\n */\n async loadAttachmentsForMessages(\n conversationDetailIds: string[],\n contextUser?: UserInfo\n ): Promise<Map<string, MessageAttachment[]>> {\n const result = new Map<string, MessageAttachment[]>();\n\n if (!conversationDetailIds || conversationDetailIds.length === 0) {\n return result;\n }\n\n try {\n const rv = RunView.FromMetadataProvider(this.Provider);\n const idList = conversationDetailIds.map(id => `'${id}'`).join(',');\n\n // Load input artifacts (ConversationDetailArtifact with Direction='Input').\n // Since the backfill migration (V202605271400__Backfill_Attachment_Artifacts)\n // converted all legacy ConversationDetailAttachment rows to artifact pairs,\n // the artifact junction is the single source of truth — no separate attachment\n // query needed.\n const artifactLinksResult = await rv.RunView<MJConversationDetailArtifactEntity>({\n EntityName: 'MJ: Conversation Detail Artifacts',\n ExtraFilter: `ConversationDetailID IN (${idList}) AND Direction = 'Input'`,\n ResultType: 'entity_object'\n }, contextUser);\n\n if (artifactLinksResult.Success && artifactLinksResult.Results && artifactLinksResult.Results.length > 0) {\n // Load the referenced artifact versions AND their parent artifacts in parallel\n // so we can resolve the semantic artifact-type name for the tile badge.\n const versionIds = artifactLinksResult.Results.map(l => `'${l.ArtifactVersionID}'`).join(',');\n const versionsResult = await rv.RunView<MJArtifactVersionEntity>({\n EntityName: 'MJ: Artifact Versions',\n ExtraFilter: `ID IN (${versionIds})`,\n ResultType: 'entity_object'\n }, contextUser);\n\n if (versionsResult.Success && versionsResult.Results) {\n const versionMap = new Map<string, MJArtifactVersionEntity>();\n for (const v of versionsResult.Results) {\n versionMap.set(v.ID, v);\n }\n\n // Bulk-load parent artifacts to get TypeID, then resolve type names via cached engine.\n const artifactIds = Array.from(new Set(versionsResult.Results.map(v => v.ArtifactID).filter(Boolean)));\n const artifactMap = new Map<string, MJArtifactEntity>();\n if (artifactIds.length > 0) {\n const artifactIdList = artifactIds.map(id => `'${id}'`).join(',');\n const artifactsResult = await rv.RunView<MJArtifactEntity>({\n EntityName: 'MJ: Artifacts',\n ExtraFilter: `ID IN (${artifactIdList})`,\n ResultType: 'entity_object'\n }, contextUser);\n if (artifactsResult.Success && artifactsResult.Results) {\n for (const a of artifactsResult.Results) {\n artifactMap.set(a.ID, a);\n }\n }\n // Ensure the artifact-type cache is populated so FindArtifactTypeByID resolves.\n await ArtifactMetadataEngine.Instance.Config(false, contextUser);\n }\n\n for (const link of artifactLinksResult.Results) {\n const version = versionMap.get(link.ArtifactVersionID);\n if (version) {\n const parentArtifact = artifactMap.get(version.ArtifactID);\n const artifactType = parentArtifact\n ? ArtifactMetadataEngine.Instance.FindArtifactTypeByID(parentArtifact.TypeID)\n : undefined;\n const detailId = link.ConversationDetailID;\n if (!result.has(detailId)) {\n result.set(detailId, []);\n }\n result.get(detailId)!.push({\n id: link.ID,\n type: version.ContentMode === 'File' ? this.getMimeAttachmentType(version.MimeType || '') : 'Document',\n mimeType: version.MimeType || 'text/plain',\n fileName: version.FileName || version.Name || 'Artifact',\n sizeBytes: version.ContentSizeBytes || 0,\n source: 'artifact',\n artifactId: version.ArtifactID || undefined,\n artifactVersionId: version.ID,\n artifactTypeName: artifactType?.Name || undefined\n } as MessageAttachment);\n }\n }\n }\n }\n } catch (error) {\n console.error('Error loading attachments:', error);\n }\n\n return result;\n }\n\n /**\n * Load attachments for a single message\n */\n async loadAttachmentsForMessage(\n conversationDetailId: string,\n contextUser?: UserInfo\n ): Promise<MessageAttachment[]> {\n const map = await this.loadAttachmentsForMessages([conversationDetailId], contextUser);\n return map.get(conversationDetailId) || [];\n }\n\n /**\n * Save pending attachments to the database.\n * Returns the saved attachment entities.\n *\n * @param conversationDetailId - ID of the conversation detail to attach to\n * @param pendingAttachments - Array of pending attachments from the mention editor\n * @param contextUser - User context for the operation\n */\n async saveAttachments(\n conversationDetailId: string,\n pendingAttachments: PendingAttachment[],\n contextUser?: UserInfo\n ): Promise<MJConversationDetailAttachmentEntity[]> {\n const savedAttachments: MJConversationDetailAttachmentEntity[] = [];\n const rejectionMessages: string[] = [];\n const md = this.Provider;\n\n for (let i = 0; i < pendingAttachments.length; i++) {\n const pending = pendingAttachments[i];\n\n try {\n const attachment = await md.GetEntityObject<MJConversationDetailAttachmentEntity>(\n 'MJ: Conversation Detail Attachments',\n contextUser\n );\n\n // Determine attachment type from MIME type\n const attachmentType = ConversationUtility.GetAttachmentTypeFromMime(pending.mimeType);\n\n attachment.ConversationDetailID = conversationDetailId;\n attachment.ModalityID = this.getModalityIdForType(attachmentType);\n attachment.MimeType = pending.mimeType;\n attachment.FileName = pending.fileName;\n attachment.FileSizeBytes = pending.sizeBytes;\n attachment.Width = pending.width ?? null;\n attachment.Height = pending.height ?? null;\n attachment.DurationSeconds = null; // PendingAttachment doesn't have duration\n attachment.DisplayOrder = i;\n attachment.ThumbnailBase64 = pending.thumbnailUrl ?? null;\n\n // For artifact references, create a ConversationDetailArtifact with Direction='Input'\n // instead of a ConversationDetailAttachment\n if (pending.source === 'artifact' && pending.artifactVersionId) {\n const artifactLink = await md.GetEntityObject<MJConversationDetailArtifactEntity>(\n 'MJ: Conversation Detail Artifacts',\n contextUser\n );\n artifactLink.ConversationDetailID = conversationDetailId;\n artifactLink.ArtifactVersionID = pending.artifactVersionId;\n artifactLink.Direction = 'Input';\n const artifactSaved = await artifactLink.Save();\n if (!artifactSaved) {\n console.error('Failed to save artifact input link:', artifactLink.LatestResult);\n }\n continue; // Skip creating a ConversationDetailAttachment for artifacts\n }\n\n // Store inline data for uploaded files\n if (pending.dataUrl) {\n const base64Data = this.extractBase64FromDataUrl(pending.dataUrl);\n attachment.InlineData = base64Data;\n }\n\n const saved = await attachment.Save();\n if (saved) {\n savedAttachments.push(attachment);\n } else {\n const message = attachment.LatestResult?.CompleteMessage\n ?? `Attachment \"${pending.fileName}\" was rejected by the server.`;\n console.error('Failed to save attachment:', attachment.LatestResult);\n rejectionMessages.push(message);\n }\n } catch (error) {\n console.error('Error saving attachment:', error);\n rejectionMessages.push(\n `Attachment \"${pending.fileName}\" failed to upload: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n\n // Surface server-side rejections (e.g. unregistered MIME types) to the\n // caller — throwing here lets the message-input toast pipeline display\n // the actual server message rather than silently dropping the file.\n if (rejectionMessages.length > 0) {\n throw new Error(rejectionMessages.join('\\n'));\n }\n\n return savedAttachments;\n }\n\n /**\n * Create attachment reference tokens for message text.\n * These tokens are stored in the Message field to reference attachments.\n */\n createAttachmentReferences(attachments: MJConversationDetailAttachmentEntity[]): string {\n return attachments\n .map(att => {\n const content: AttachmentContent = {\n _mode: 'attachment',\n id: att.ID,\n type: this.getAttachmentTypeFromModality(att.ModalityID),\n mimeType: att.MimeType,\n fileName: att.FileName ?? undefined,\n sizeBytes: att.FileSizeBytes,\n width: att.Width ?? undefined,\n height: att.Height ?? undefined,\n durationSeconds: att.DurationSeconds ?? undefined,\n thumbnailBase64: att.ThumbnailBase64 ?? undefined\n };\n return ConversationUtility.CreateAttachmentReference(content);\n })\n .join(' ');\n }\n\n /**\n * Convert a database entity to a MessageAttachment for display\n */\n private convertToMessageAttachment(entity: MJConversationDetailAttachmentEntity): MessageAttachment {\n // Determine content URL\n let contentUrl: string | undefined;\n let thumbnailUrl: string | undefined;\n\n if (entity.InlineData) {\n // Create data URL from inline data\n contentUrl = `data:${entity.MimeType};base64,${entity.InlineData}`;\n } else if (entity.FileID) {\n // TODO: Integrate with MJStorage to get pre-authenticated URL\n contentUrl = undefined; // Will need to be loaded separately\n }\n\n // Use thumbnail if available\n if (entity.ThumbnailBase64) {\n thumbnailUrl = entity.ThumbnailBase64.startsWith('data:')\n ? entity.ThumbnailBase64\n : `data:image/jpeg;base64,${entity.ThumbnailBase64}`;\n }\n\n return {\n id: entity.ID,\n type: this.getAttachmentTypeFromModality(entity.ModalityID),\n mimeType: entity.MimeType,\n fileName: entity.FileName,\n sizeBytes: entity.FileSizeBytes,\n width: entity.Width ?? undefined,\n height: entity.Height ?? undefined,\n thumbnailUrl: thumbnailUrl,\n contentUrl: contentUrl\n };\n }\n\n /**\n * Get the AttachmentType from a modality ID\n */\n private getAttachmentTypeFromModality(modalityId: string): AttachmentType {\n const modality = AIEngineBase.Instance.Modalities.find(m => UUIDsEqual(m.ID, modalityId))\n\n const name = modality?.Name?.toLowerCase() || '';\n\n if (name === 'image') return 'Image';\n if (name === 'video') return 'Video';\n if (name === 'audio') return 'Audio';\n\n return 'Document';\n }\n\n /**\n * Get the AttachmentType from a MIME type string\n */\n private getMimeAttachmentType(mimeType: string): 'Image' | 'Video' | 'Audio' | 'Document' {\n if (mimeType.startsWith('image/')) return 'Image';\n if (mimeType.startsWith('video/')) return 'Video';\n if (mimeType.startsWith('audio/')) return 'Audio';\n return 'Document';\n }\n\n /**\n * Get the modality ID for an attachment type\n */\n private getModalityIdForType(type: AttachmentType): string {\n // Map AttachmentType to modality name\n // AttachmentType is 'Image' | 'Video' | 'Audio' | 'Document'\n // Modality names are 'Image', 'Audio', 'Video', 'File'\n let modalityName = type.toLowerCase().trim();\n if (modalityName === 'document') {\n modalityName = 'file';\n }\n\n const modality = AIEngineBase.Instance.Modalities.find(m => m.Name?.trim().toLowerCase() === modalityName);\n if (modality) {\n return modality.ID;\n }\n\n // Fallback to 'file' modality if specific type not found\n // recursive call, so long as the current modality isn't file as that\n // would cause infinite recursion/stack overflow\n if (modalityName !== 'file') {\n return this.getModalityIdForType('Document');\n }\n else {\n return '';\n }\n }\n \n /**\n * Extract base64 data from a data URL\n */\n private extractBase64FromDataUrl(dataUrl: string): string {\n const matches = dataUrl.match(/^data:[^;]+;base64,(.+)$/);\n return matches ? matches[1] : dataUrl;\n }\n\n /**\n * Create a thumbnail from an image file.\n * Returns a base64 data URL of the thumbnail.\n */\n async createThumbnail(\n file: File,\n maxSize: number = 200\n ): Promise<string | null> {\n return new Promise((resolve) => {\n if (!file.type.startsWith('image/')) {\n resolve(null);\n return;\n }\n\n const reader = new FileReader();\n reader.onload = (e) => {\n const img = new Image();\n img.onload = () => {\n const canvas = document.createElement('canvas');\n let width = img.width;\n let height = img.height;\n\n // Scale down to maxSize\n if (width > height) {\n if (width > maxSize) {\n height = Math.round((height * maxSize) / width);\n width = maxSize;\n }\n } else {\n if (height > maxSize) {\n width = Math.round((width * maxSize) / height);\n height = maxSize;\n }\n }\n\n canvas.width = width;\n canvas.height = height;\n\n const ctx = canvas.getContext('2d');\n if (ctx) {\n ctx.drawImage(img, 0, 0, width, height);\n resolve(canvas.toDataURL('image/jpeg', 0.7));\n } else {\n resolve(null);\n }\n };\n img.onerror = () => resolve(null);\n img.src = e.target?.result as string;\n };\n reader.onerror = () => resolve(null);\n reader.readAsDataURL(file);\n });\n }\n\n /**\n * Get image dimensions from a file\n */\n async getImageDimensions(file: File): Promise<{ width: number; height: number } | null> {\n return new Promise((resolve) => {\n if (!file.type.startsWith('image/')) {\n resolve(null);\n return;\n }\n\n const reader = new FileReader();\n reader.onload = (e) => {\n const img = new Image();\n img.onload = () => {\n resolve({ width: img.width, height: img.height });\n };\n img.onerror = () => resolve(null);\n img.src = e.target?.result as string;\n };\n reader.onerror = () => resolve(null);\n reader.readAsDataURL(file);\n });\n }\n\n /**\n * Process a file and create a PendingAttachment.\n * This creates the data structure needed for the mention editor component.\n */\n async processFile(file: File): Promise<PendingAttachment> {\n // Read file data URL\n const dataUrl = await this.fileToDataUrl(file);\n\n const pending: PendingAttachment = {\n id: this.generateTempId(),\n file: file,\n dataUrl: dataUrl,\n mimeType: file.type,\n fileName: file.name,\n sizeBytes: file.size\n };\n\n // Get image dimensions and create thumbnail\n const type = ConversationUtility.GetAttachmentTypeFromMime(file.type);\n if (type === 'Image') {\n const dimensions = await this.getImageDimensions(file);\n if (dimensions) {\n pending.width = dimensions.width;\n pending.height = dimensions.height;\n }\n\n const thumbnail = await this.createThumbnail(file);\n if (thumbnail) {\n pending.thumbnailUrl = thumbnail;\n }\n }\n\n return pending;\n }\n\n /**\n * Convert a file to a data URL\n */\n private fileToDataUrl(file: File): Promise<string> {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => resolve(reader.result as string);\n reader.onerror = () => reject(reader.error);\n reader.readAsDataURL(file);\n });\n }\n\n /**\n * Generate a temporary ID for pending attachments\n */\n private generateTempId(): string {\n return `temp-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;\n }\n}\n"]}
1
+ {"version":3,"file":"conversation-attachment.service.js","sourceRoot":"","sources":["../../../src/lib/services/conversation-attachment.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { Injectable } from '@angular/core';\nimport { RunView, Metadata, UserInfo, IMetadataProvider } from '@memberjunction/core';\nimport {\n MJConversationDetailAttachmentEntity,\n MJConversationDetailArtifactEntity,\n MJArtifactVersionEntity,\n MJArtifactEntity,\n MJAIModalityEntity,\n MJAIAgentEntity,\n ArtifactMetadataEngine\n} from '@memberjunction/core-entities';\nimport {\n ConversationUtility,\n DEFAULT_INLINE_STORAGE_THRESHOLD_BYTES,\n AttachmentContent,\n AttachmentType\n} from '@memberjunction/ai-core-plus';\nimport type { IAttachmentBlobStore } from '@memberjunction/ai-core-plus';\nimport { GraphQLAttachmentBlobStore } from './graphql-attachment-blob-store';\nimport { MessageAttachment } from '../components/message/message-item.component';\nimport { PendingAttachment } from '@memberjunction/ng-composer';\nimport { AIEngineBase } from '@memberjunction/ai-engine-base';\nimport { UUIDsEqual } from '@memberjunction/global';\n\n/**\n * Service for managing conversation attachments.\n * Handles loading, saving, and converting attachments between different formats.\n */\n@Injectable({\n providedIn: 'root'\n})\nexport class ConversationAttachmentService {\n /**\n * Where attachment bytes go when they are too large to store inline.\n *\n * Held directly rather than read off the shared `ConversationAttachmentService` in\n * `@memberjunction/aiengine`. That package's entry point imports Node's `crypto`\n * (`AIEngine.ts`, for an embedding-cache key), so a runtime import of it from here pulls the\n * whole server AI engine into Explorer's browser bundle and the build fails to resolve `crypto`.\n * The shared service is a server-side consumer of the same seam, not a dependency of this one.\n *\n * The seam's *type* used to be imported from there with `import type`, on the reasoning that an\n * erased import costs nothing. It does at runtime — but the class-registration manifest generator\n * walks **package.json**, so the declared dependency was a live edge regardless, and it later\n * carried `@memberjunction/storage`'s drivers into the browser manifest. Both the contract and\n * the placement policy (`ConversationUtility`) now come from `@memberjunction/ai-core-plus`, and\n * this package does not declare `aiengine` at all.\n */\n private readonly blobStore: IAttachmentBlobStore = new GraphQLAttachmentBlobStore();\n\n private _provider: IMetadataProvider | null = null;\n\n constructor() {}\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 * Load all attachments for a list of conversation detail IDs.\n * Returns a map of ConversationDetailID -> MessageAttachment[]\n */\n async loadAttachmentsForMessages(\n conversationDetailIds: string[],\n contextUser?: UserInfo\n ): Promise<Map<string, MessageAttachment[]>> {\n const result = new Map<string, MessageAttachment[]>();\n\n if (!conversationDetailIds || conversationDetailIds.length === 0) {\n return result;\n }\n\n try {\n const rv = RunView.FromMetadataProvider(this.Provider);\n const idList = conversationDetailIds.map(id => `'${id}'`).join(',');\n\n // Load input artifacts (ConversationDetailArtifact with Direction='Input').\n // Since the backfill migration (V202605271400__Backfill_Attachment_Artifacts)\n // converted all legacy ConversationDetailAttachment rows to artifact pairs,\n // the artifact junction is the single source of truth — no separate attachment\n // query needed.\n const artifactLinksResult = await rv.RunView<MJConversationDetailArtifactEntity>({\n EntityName: 'MJ: Conversation Detail Artifacts',\n ExtraFilter: `ConversationDetailID IN (${idList}) AND Direction = 'Input'`,\n ResultType: 'entity_object'\n }, contextUser);\n\n if (artifactLinksResult.Success && artifactLinksResult.Results && artifactLinksResult.Results.length > 0) {\n // Load the referenced artifact versions AND their parent artifacts in parallel\n // so we can resolve the semantic artifact-type name for the tile badge.\n const versionIds = artifactLinksResult.Results.map(l => `'${l.ArtifactVersionID}'`).join(',');\n const versionsResult = await rv.RunView<MJArtifactVersionEntity>({\n EntityName: 'MJ: Artifact Versions',\n ExtraFilter: `ID IN (${versionIds})`,\n ResultType: 'entity_object'\n }, contextUser);\n\n if (versionsResult.Success && versionsResult.Results) {\n const versionMap = new Map<string, MJArtifactVersionEntity>();\n for (const v of versionsResult.Results) {\n versionMap.set(v.ID, v);\n }\n\n // Bulk-load parent artifacts to get TypeID, then resolve type names via cached engine.\n const artifactIds = Array.from(new Set(versionsResult.Results.map(v => v.ArtifactID).filter(Boolean)));\n const artifactMap = new Map<string, MJArtifactEntity>();\n if (artifactIds.length > 0) {\n const artifactIdList = artifactIds.map(id => `'${id}'`).join(',');\n const artifactsResult = await rv.RunView<MJArtifactEntity>({\n EntityName: 'MJ: Artifacts',\n ExtraFilter: `ID IN (${artifactIdList})`,\n ResultType: 'entity_object'\n }, contextUser);\n if (artifactsResult.Success && artifactsResult.Results) {\n for (const a of artifactsResult.Results) {\n artifactMap.set(a.ID, a);\n }\n }\n // Ensure the artifact-type cache is populated so FindArtifactTypeByID resolves.\n await ArtifactMetadataEngine.Instance.Config(false, contextUser);\n }\n\n for (const link of artifactLinksResult.Results) {\n const version = versionMap.get(link.ArtifactVersionID);\n if (version) {\n const parentArtifact = artifactMap.get(version.ArtifactID);\n const artifactType = parentArtifact\n ? ArtifactMetadataEngine.Instance.FindArtifactTypeByID(parentArtifact.TypeID)\n : undefined;\n const detailId = link.ConversationDetailID;\n if (!result.has(detailId)) {\n result.set(detailId, []);\n }\n result.get(detailId)!.push({\n id: link.ID,\n type: version.ContentMode === 'File' ? this.getMimeAttachmentType(version.MimeType || '') : 'Document',\n mimeType: version.MimeType || 'text/plain',\n fileName: version.FileName || version.Name || 'Artifact',\n sizeBytes: version.ContentSizeBytes || 0,\n source: 'artifact',\n artifactId: version.ArtifactID || undefined,\n artifactVersionId: version.ID,\n artifactTypeName: artifactType?.Name || undefined\n } as MessageAttachment);\n }\n }\n }\n }\n } catch (error) {\n console.error('Error loading attachments:', error);\n }\n\n return result;\n }\n\n /**\n * Load attachments for a single message\n */\n async loadAttachmentsForMessage(\n conversationDetailId: string,\n contextUser?: UserInfo\n ): Promise<MessageAttachment[]> {\n const map = await this.loadAttachmentsForMessages([conversationDetailId], contextUser);\n return map.get(conversationDetailId) || [];\n }\n\n /**\n * Save pending attachments to the database.\n * Returns the saved attachment entities.\n *\n * @param conversationDetailId - ID of the conversation detail to attach to\n * @param pendingAttachments - Array of pending attachments from the mention editor\n * @param contextUser - User context for the operation\n * @param agent - The agent this turn is addressed to, when the caller has resolved one. Only its\n * `InlineStorageThresholdBytes` is read, and only to make the inline-vs-storage decision match\n * what the server would decide for the same file. Omitting it falls back to the system default,\n * which is correct for a turn with no agent — but a caller that HAS an agent and does not pass\n * it produces the cross-surface drift this shared policy exists to remove.\n */\n async saveAttachments(\n conversationDetailId: string,\n pendingAttachments: PendingAttachment[],\n contextUser?: UserInfo,\n agent?: MJAIAgentEntity | null\n ): Promise<MJConversationDetailAttachmentEntity[]> {\n const savedAttachments: MJConversationDetailAttachmentEntity[] = [];\n const rejectionMessages: string[] = [];\n const md = this.Provider;\n\n for (let i = 0; i < pendingAttachments.length; i++) {\n const pending = pendingAttachments[i];\n\n try {\n const attachment = await md.GetEntityObject<MJConversationDetailAttachmentEntity>(\n 'MJ: Conversation Detail Attachments',\n contextUser\n );\n\n // Determine attachment type from MIME type\n const attachmentType = ConversationUtility.GetAttachmentTypeFromMime(pending.mimeType);\n\n attachment.ConversationDetailID = conversationDetailId;\n attachment.ModalityID = this.getModalityIdForType(attachmentType);\n attachment.MimeType = pending.mimeType;\n attachment.FileName = pending.fileName;\n attachment.FileSizeBytes = pending.sizeBytes;\n attachment.Width = pending.width ?? null;\n attachment.Height = pending.height ?? null;\n attachment.DurationSeconds = null; // PendingAttachment doesn't have duration\n attachment.DisplayOrder = i;\n attachment.ThumbnailBase64 = pending.thumbnailUrl ?? null;\n\n // For artifact references, create a ConversationDetailArtifact with Direction='Input'\n // instead of a ConversationDetailAttachment\n if (pending.source === 'artifact' && pending.artifactVersionId) {\n const artifactLink = await md.GetEntityObject<MJConversationDetailArtifactEntity>(\n 'MJ: Conversation Detail Artifacts',\n contextUser\n );\n artifactLink.ConversationDetailID = conversationDetailId;\n artifactLink.ArtifactVersionID = pending.artifactVersionId;\n artifactLink.Direction = 'Input';\n const artifactSaved = await artifactLink.Save();\n if (!artifactSaved) {\n console.error('Failed to save artifact input link:', artifactLink.LatestResult);\n }\n continue; // Skip creating a ConversationDetailAttachment for artifacts\n }\n\n // Storage placement is NOT this service's decision. `ConversationUtility.ShouldStoreInline`\n // owns it — honouring an agent's `InlineStorageThresholdBytes` before the system default —\n // and it is the same call the server and the mobile app make. This service previously set\n // `InlineData` unconditionally, so a large image went into a database column instead of\n // MJStorage, contradicting the entity's own contract that the two are mutually exclusive\n // and sized.\n if (pending.dataUrl) {\n const base64Data = this.extractBase64FromDataUrl(pending.dataUrl);\n const storeInline = ConversationUtility.ShouldStoreInline(\n pending.sizeBytes,\n agent?.InlineStorageThresholdBytes ?? null,\n DEFAULT_INLINE_STORAGE_THRESHOLD_BYTES,\n );\n\n if (storeInline) {\n attachment.InlineData = base64Data;\n } else {\n const stored = await this.blobStore.Upload(\n { FileName: pending.fileName, MimeType: pending.mimeType, Base64Data: base64Data },\n contextUser ?? md.CurrentUser,\n md,\n );\n if (!stored?.Success || !stored.FileID) {\n rejectionMessages.push(\n `Attachment \"${pending.fileName}\" is too large to store inline and could not be uploaded: ${stored?.Error ?? 'storage is not available.'}`,\n );\n continue;\n }\n attachment.FileID = stored.FileID;\n }\n }\n\n const saved = await attachment.Save();\n if (saved) {\n savedAttachments.push(attachment);\n } else {\n const message = attachment.LatestResult?.CompleteMessage\n ?? `Attachment \"${pending.fileName}\" was rejected by the server.`;\n console.error('Failed to save attachment:', attachment.LatestResult);\n rejectionMessages.push(message);\n }\n } catch (error) {\n console.error('Error saving attachment:', error);\n rejectionMessages.push(\n `Attachment \"${pending.fileName}\" failed to upload: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n\n // Surface server-side rejections (e.g. unregistered MIME types) to the\n // caller — throwing here lets the message-input toast pipeline display\n // the actual server message rather than silently dropping the file.\n if (rejectionMessages.length > 0) {\n throw new Error(rejectionMessages.join('\\n'));\n }\n\n return savedAttachments;\n }\n\n /**\n * Create attachment reference tokens for message text.\n * These tokens are stored in the Message field to reference attachments.\n */\n createAttachmentReferences(attachments: MJConversationDetailAttachmentEntity[]): string {\n return attachments\n .map(att => {\n const content: AttachmentContent = {\n _mode: 'attachment',\n id: att.ID,\n type: this.getAttachmentTypeFromModality(att.ModalityID),\n mimeType: att.MimeType,\n fileName: att.FileName ?? undefined,\n sizeBytes: att.FileSizeBytes,\n width: att.Width ?? undefined,\n height: att.Height ?? undefined,\n durationSeconds: att.DurationSeconds ?? undefined,\n thumbnailBase64: att.ThumbnailBase64 ?? undefined\n };\n return ConversationUtility.CreateAttachmentReference(content);\n })\n .join(' ');\n }\n\n /**\n * Convert a database entity to a MessageAttachment for display\n */\n private convertToMessageAttachment(entity: MJConversationDetailAttachmentEntity): MessageAttachment {\n // Determine content URL\n let contentUrl: string | undefined;\n let thumbnailUrl: string | undefined;\n\n if (entity.InlineData) {\n // Create data URL from inline data\n contentUrl = `data:${entity.MimeType};base64,${entity.InlineData}`;\n } else if (entity.FileID) {\n // TODO: Integrate with MJStorage to get pre-authenticated URL\n contentUrl = undefined; // Will need to be loaded separately\n }\n\n // Use thumbnail if available\n if (entity.ThumbnailBase64) {\n thumbnailUrl = entity.ThumbnailBase64.startsWith('data:')\n ? entity.ThumbnailBase64\n : `data:image/jpeg;base64,${entity.ThumbnailBase64}`;\n }\n\n return {\n id: entity.ID,\n type: this.getAttachmentTypeFromModality(entity.ModalityID),\n mimeType: entity.MimeType,\n fileName: entity.FileName,\n sizeBytes: entity.FileSizeBytes,\n width: entity.Width ?? undefined,\n height: entity.Height ?? undefined,\n thumbnailUrl: thumbnailUrl,\n contentUrl: contentUrl\n };\n }\n\n /**\n * Get the AttachmentType from a modality ID\n */\n private getAttachmentTypeFromModality(modalityId: string): AttachmentType {\n const modality = AIEngineBase.Instance.Modalities.find(m => UUIDsEqual(m.ID, modalityId))\n\n const name = modality?.Name?.toLowerCase() || '';\n\n if (name === 'image') return 'Image';\n if (name === 'video') return 'Video';\n if (name === 'audio') return 'Audio';\n\n return 'Document';\n }\n\n /**\n * Get the AttachmentType from a MIME type string\n */\n private getMimeAttachmentType(mimeType: string): 'Image' | 'Video' | 'Audio' | 'Document' {\n if (mimeType.startsWith('image/')) return 'Image';\n if (mimeType.startsWith('video/')) return 'Video';\n if (mimeType.startsWith('audio/')) return 'Audio';\n return 'Document';\n }\n\n /**\n * Get the modality ID for an attachment type\n */\n private getModalityIdForType(type: AttachmentType): string {\n // Map AttachmentType to modality name\n // AttachmentType is 'Image' | 'Video' | 'Audio' | 'Document'\n // Modality names are 'Image', 'Audio', 'Video', 'File'\n let modalityName = type.toLowerCase().trim();\n if (modalityName === 'document') {\n modalityName = 'file';\n }\n\n const modality = AIEngineBase.Instance.Modalities.find(m => m.Name?.trim().toLowerCase() === modalityName);\n if (modality) {\n return modality.ID;\n }\n\n // Fallback to 'file' modality if specific type not found\n // recursive call, so long as the current modality isn't file as that\n // would cause infinite recursion/stack overflow\n if (modalityName !== 'file') {\n return this.getModalityIdForType('Document');\n }\n else {\n return '';\n }\n }\n \n /**\n * Extract base64 data from a data URL\n */\n private extractBase64FromDataUrl(dataUrl: string): string {\n const matches = dataUrl.match(/^data:[^;]+;base64,(.+)$/);\n return matches ? matches[1] : dataUrl;\n }\n\n /**\n * Create a thumbnail from an image file.\n * Returns a base64 data URL of the thumbnail.\n */\n async createThumbnail(\n file: File,\n maxSize: number = 200\n ): Promise<string | null> {\n return new Promise((resolve) => {\n if (!file.type.startsWith('image/')) {\n resolve(null);\n return;\n }\n\n const reader = new FileReader();\n reader.onload = (e) => {\n const img = new Image();\n img.onload = () => {\n const canvas = document.createElement('canvas');\n let width = img.width;\n let height = img.height;\n\n // Scale down to maxSize\n if (width > height) {\n if (width > maxSize) {\n height = Math.round((height * maxSize) / width);\n width = maxSize;\n }\n } else {\n if (height > maxSize) {\n width = Math.round((width * maxSize) / height);\n height = maxSize;\n }\n }\n\n canvas.width = width;\n canvas.height = height;\n\n const ctx = canvas.getContext('2d');\n if (ctx) {\n ctx.drawImage(img, 0, 0, width, height);\n resolve(canvas.toDataURL('image/jpeg', 0.7));\n } else {\n resolve(null);\n }\n };\n img.onerror = () => resolve(null);\n img.src = e.target?.result as string;\n };\n reader.onerror = () => resolve(null);\n reader.readAsDataURL(file);\n });\n }\n\n /**\n * Get image dimensions from a file\n */\n async getImageDimensions(file: File): Promise<{ width: number; height: number } | null> {\n return new Promise((resolve) => {\n if (!file.type.startsWith('image/')) {\n resolve(null);\n return;\n }\n\n const reader = new FileReader();\n reader.onload = (e) => {\n const img = new Image();\n img.onload = () => {\n resolve({ width: img.width, height: img.height });\n };\n img.onerror = () => resolve(null);\n img.src = e.target?.result as string;\n };\n reader.onerror = () => resolve(null);\n reader.readAsDataURL(file);\n });\n }\n\n /**\n * Process a file and create a PendingAttachment.\n * This creates the data structure needed for the mention editor component.\n */\n async processFile(file: File): Promise<PendingAttachment> {\n // Read file data URL\n const dataUrl = await this.fileToDataUrl(file);\n\n const pending: PendingAttachment = {\n id: this.generateTempId(),\n file: file,\n dataUrl: dataUrl,\n mimeType: file.type,\n fileName: file.name,\n sizeBytes: file.size\n };\n\n // Get image dimensions and create thumbnail\n const type = ConversationUtility.GetAttachmentTypeFromMime(file.type);\n if (type === 'Image') {\n const dimensions = await this.getImageDimensions(file);\n if (dimensions) {\n pending.width = dimensions.width;\n pending.height = dimensions.height;\n }\n\n const thumbnail = await this.createThumbnail(file);\n if (thumbnail) {\n pending.thumbnailUrl = thumbnail;\n }\n }\n\n return pending;\n }\n\n /**\n * Convert a file to a data URL\n */\n private fileToDataUrl(file: File): Promise<string> {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => resolve(reader.result as string);\n reader.onerror = () => reject(reader.error);\n reader.readAsDataURL(file);\n });\n }\n\n /**\n * Generate a temporary ID for pending attachments\n */\n private generateTempId(): string {\n return `temp-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;\n }\n}\n"]}
@@ -0,0 +1,44 @@
1
+ import { UserInfo, IMetadataProvider } from '@memberjunction/core';
2
+ import type { AttachmentBlobUploadInput, AttachmentBlobUploadResult, IAttachmentBlobStore } from '@memberjunction/ai-core-plus';
3
+ export declare class GraphQLAttachmentBlobStore implements IAttachmentBlobStore {
4
+ /**
5
+ * Uploads bytes through MJAPI's storage subsystem, which creates the `MJ: Files` record.
6
+ *
7
+ * Storage account selection is the server's decision here: a browser has no business choosing
8
+ * a storage backend, and `UploadFile` resolves a default when none is named.
9
+ */
10
+ Upload(input: AttachmentBlobUploadInput, _contextUser: UserInfo, _provider?: IMetadataProvider): Promise<AttachmentBlobUploadResult>;
11
+ /**
12
+ * Not supported from the browser, deliberately.
13
+ *
14
+ * Pulling file bytes through JavaScript only to re-encode them as base64 wastes memory and
15
+ * bandwidth for no benefit — {@link GetDownloadUrl} gives the browser something it can hand
16
+ * straight to an `<img>`, a download, or a fetch, and the service falls back to exactly that
17
+ * when this returns `null`. This is the one operation where "not supported" is the better
18
+ * answer rather than a gap.
19
+ */
20
+ Download(_fileId: string, _contextUser: UserInfo, _provider?: IMetadataProvider): Promise<string | null>;
21
+ /**
22
+ * Mints a permission-gated, time-limited URL for a stored file.
23
+ *
24
+ * Goes through `CreateMediaAccessToken` rather than `CreatePreAuthDownloadUrl`: the latter is
25
+ * keyed by storage account + object name, so using it would mean the client resolving storage
26
+ * internals it has no business knowing. The media route is keyed by `MJ: Files` id, checks the
27
+ * caller's permissions server-side, and Range-streams — it is the same path
28
+ * `mj-storage-media-player` already uses, so this adds a caller rather than a second mechanism.
29
+ *
30
+ * This is what makes the write path readable. Explorer only started producing storage-backed
31
+ * attachments when this seam was bound; without a URL here, every attachment over the inline
32
+ * threshold would upload successfully and then be permanently undisplayable.
33
+ */
34
+ GetDownloadUrl(fileId: string, _contextUser: UserInfo, _provider?: IMetadataProvider): Promise<string | null>;
35
+ /**
36
+ * Not supported from the browser.
37
+ *
38
+ * Deleting stored bytes is a server-side concern with its own permission and retention rules;
39
+ * a client requesting it directly would bypass them. Returning `false` leaves the attachment
40
+ * row intact rather than orphaning it against content the client could not remove.
41
+ */
42
+ Delete(_fileId: string, _contextUser: UserInfo, _provider?: IMetadataProvider): Promise<boolean>;
43
+ }
44
+ //# sourceMappingURL=graphql-attachment-blob-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graphql-attachment-blob-store.d.ts","sourceRoot":"","sources":["../../../src/lib/services/graphql-attachment-blob-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAY,MAAM,sBAAsB,CAAC;AAE7E,OAAO,KAAK,EACR,yBAAyB,EACzB,0BAA0B,EAC1B,oBAAoB,EACvB,MAAM,8BAA8B,CAAC;AA4CtC,qBAAa,0BAA2B,YAAW,oBAAoB;IACnE;;;;;OAKG;IACU,MAAM,CACf,KAAK,EAAE,yBAAyB,EAChC,YAAY,EAAE,QAAQ,EACtB,SAAS,CAAC,EAAE,iBAAiB,GAC9B,OAAO,CAAC,0BAA0B,CAAC;IAkBtC;;;;;;;;OAQG;IACU,QAAQ,CACjB,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,QAAQ,EACtB,SAAS,CAAC,EAAE,iBAAiB,GAC9B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAIzB;;;;;;;;;;;;OAYG;IACU,cAAc,CACvB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,QAAQ,EACtB,SAAS,CAAC,EAAE,iBAAiB,GAC9B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAoBzB;;;;;;OAMG;IACU,MAAM,CACf,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,QAAQ,EACtB,SAAS,CAAC,EAAE,iBAAiB,GAC9B,OAAO,CAAC,OAAO,CAAC;CAGtB"}